diff --git a/README.md b/README.md index 88e9b4f..f29b8a4 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ render () { } ``` -See the [examples](/examples/notification-tree) for more context on how to use a notification stack. +See the [examples](examples/notification-tree) for more context on how to use a notification stack. ### Props @@ -101,9 +101,11 @@ The `style` prop useful if you are not using React inline styles and would like For NotificationStack component: -| Name | Type | Description | Required | Default | -|----------------|-------|----------------------------------------------|---------- |----------| -| notifications | array | Array of notifications to render | true | | +| Name | Type | Description | Required | Default | +|-----------------------|-------|----------------------------------------------|---------- |----------| +| notifications | array | Array of notifications to render | true | | +| barStyleFactory | func | create the style of the notification | false | fn | +| activeBarStyleFactory | func | create the style of the active notification | false | fn | **Update** `v5.0.3`: Now notifications used in a stack _can_ have all properties included in the regular notification component. @@ -144,6 +146,31 @@ To use additional inline styles, return two objects. The `bar` object applies st I would highly suggest using this method since the styles included in the component by default handle the visibility of the notification. If you remove these styles, the component won't actually show or hide itself. +### barStyleFactory and activeBarStyleFactory NotificationStack props + +These two function have the following signature: + +```js +(index: Number, style: Object|Void) => Object +``` + +Where `index` is the index of the notification in the notifications array and +`style` is the style property of the individual notification. + +This function is used to dynamically set the style of each notification in the +stack. The default function adds the `bottom` style property to correctly +position of the notification in a stack. + +```js +function defaultStyleFactory(index, style) { + return Object.assign( + {}, + style, + { bottom: `${2 + index * 4}rem` } + ); +} +``` + --- Built with care in New Orleans by [Patrick Burtchaell](http://twitter.com/pburtchaell). diff --git a/package.json b/package.json index 0be5c66..1af8b8f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "react-notification", "version": "5.0.7", + "version": "6.0.0", "description": "Snackbar style notification component for React.", "main": "dist/index.js", "scripts": { diff --git a/src/notification.js b/src/notification.js index 68708b5..b21bd1e 100644 --- a/src/notification.js +++ b/src/notification.js @@ -10,10 +10,10 @@ class Notification extends Component { this.getTitleStyle = this.getTitleStyle.bind(this); this.handleClick = this.handleClick.bind(this); - if (this.props.onDismiss && this.props.isActive) { + if (props.onDismiss && props.isActive) { this.dismissTimeout = setTimeout( - this.props.onDismiss, - this.props.dismissAfter + props.onDismiss, + props.dismissAfter ); } } diff --git a/src/notificationStack.js b/src/notificationStack.js index 8b15541..c3accf1 100644 --- a/src/notificationStack.js +++ b/src/notificationStack.js @@ -2,6 +2,14 @@ import React, { PropTypes } from 'react'; import defaultPropTypes from './defaultPropTypes'; import StackedNotification from './stackedNotification'; +function defaultStyleFactory(index, style) { + return Object.assign( + {}, + style, + { bottom: `${2 + index * 4}rem` } + ); +} + /** * The notification list does not have any state, so use a * pure function here. It just needs to return the stacked array @@ -13,6 +21,11 @@ const NotificationStack = props => { {props.notifications.map((notification, index) => { const dismissAfter = notification.dismissAfter || props.dismissAfter; const isLast = index === 0 && props.notifications.length === 1; + const barStyle = props.barStyleFactory(index, notification.barStyle); + const activeBarStyle = props.activeBarStyleFactory( + index, + notification.activeBarStyle + ); return ( { action={notification.action || props.action} dismissAfter={isLast ? dismissAfter : dismissAfter + (index * 1000)} onDismiss={props.onDismiss.bind(this, notification)} - index={index} + activeBarStyle={activeBarStyle} + barStyle={barStyle} /> ); })} @@ -31,12 +45,16 @@ const NotificationStack = props => { }; NotificationStack.propTypes = { + activeBarStyleFactory: PropTypes.func, + barStyleFactory: PropTypes.func, notifications: PropTypes.array.isRequired, onDismiss: PropTypes.func.isRequired }; NotificationStack.defaultProps = { - dismissAfter: 1000 + dismissAfter: 1000, + activeBarStyleFactory: defaultStyleFactory, + barStyleFactory: defaultStyleFactory } export default NotificationStack; diff --git a/src/stackedNotification.js b/src/stackedNotification.js index 6795a06..cb8a4d3 100644 --- a/src/stackedNotification.js +++ b/src/stackedNotification.js @@ -26,19 +26,11 @@ class StackedNotification extends Component { } render() { - const bottomPosition = `${2 + this.props.index * 4}rem`; - return ( setTimeout(this.props.onDismiss, 300)} isActive={this.state.isActive} - barStyle={Object.assign({}, { - bottom: bottomPosition - }, this.props.barStyle)} - activeBarStyle={Object.assign({}, { - bottom: bottomPosition - }, this.props.activeBarStyle)} /> ); } diff --git a/test/notification.js b/test/notification.js index c71956a..3e0b807 100644 --- a/test/notification.js +++ b/test/notification.js @@ -7,6 +7,9 @@ describe('', () => { const actionClassName = '.notification-bar-action'; const titleClassName = '.notification-bar-title'; + const customClassName = 'foo'; + const customActiveClassName = 'bar'; + let component = shallow( ', () => { expect(component).to.have.className('notification-bar'); }); + it('has custom class name', () => { + let classNameComponent = shallow( + + ); + + expect(classNameComponent).to.have.className(customClassName); + }); + + it('has custom active class name', () => { + let classNameComponent = shallow( + + ); + + expect(classNameComponent).to.have.className(customClassName); + + classNameComponent.setProps({ isActive: true }); + + expect(classNameComponent).to.have.className(customActiveClassName); + }); + + it('should render message element', () => { expect(wrapper).to.have.descendants(messageClassName); }); diff --git a/test/notificationStack.js b/test/notificationStack.js index 9c70fa0..104e0da 100644 --- a/test/notificationStack.js +++ b/test/notificationStack.js @@ -67,4 +67,72 @@ describe('', () => { expect(handleDismiss.calledOnce).to.equal(false); }); + + it('barStyleFactory should set correct style on notification', () => { + const styleFactory = (index, style) => Object.assign( + {}, + style, + { bottom: `${index}px` } + ); + const stack = mount( + {}} + /> + ); + const notification = stack.find(Notification); + expect(notification.prop('barStyle').bottom).to.equal('0px'); + }); + + it('barStyleFactory should respect notification barStyle', () => { + const styleFactory = (index, style) => Object.assign( + {}, + style, + { bottom: `${index}px` } + ); + const stack = mount( + {}} + /> + ); + const notification = stack.find(Notification); + expect(notification.prop('barStyle').background).to.equal('rgb(2, 2, 2)'); + }); + + it('activeBarStyleFactory should set correct style on notification', () => { + const styleFactory = (index, style) => Object.assign( + {}, + style, + { bottom: `${index + 2}px` } + ); + const stack = mount( + {}} + /> + ); + const notification = stack.find(Notification); + expect(notification.prop('activeBarStyle').bottom).to.equal('2px'); + }); + + it('activeBarStyleFactory should respect notification actionBarStyle', () => { + const styleFactory = (index, style) => Object.assign( + {}, + style, + { bottom: `${index}px` } + ); + const stack = mount( + {}} + /> + ); + const notification = stack.find(Notification); + expect(notification.prop('activeBarStyle').left).to.equal('4rem'); + }) });