From 0c13a3cdf5f481f4b1a6a90f9e8bd930e85fcb68 Mon Sep 17 00:00:00 2001 From: Bartosz Dotryw Date: Thu, 5 Apr 2018 18:39:37 +0200 Subject: [PATCH 1/5] New props: * renderSystem * renderContainer * renderItem * className * containerClassName * itemClassName --- src/NotificationContainer.jsx | 26 +++++++++++++++++++------- src/NotificationItem.jsx | 13 ++++++++++--- src/NotificationSystem.jsx | 35 +++++++++++++++++++++++++++-------- 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/NotificationContainer.jsx b/src/NotificationContainer.jsx index 0b6e044..16186f2 100644 --- a/src/NotificationContainer.jsx +++ b/src/NotificationContainer.jsx @@ -9,13 +9,19 @@ var NotificationContainer = createReactClass({ propTypes: { position: PropTypes.string.isRequired, notifications: PropTypes.array.isRequired, - getStyles: PropTypes.object + getStyles: PropTypes.object, + + renderContainer: PropTypes.func, + renderItem: PropTypes.func, + + className: PropTypes.string, + itemClassName: PropTypes.string }, _style: {}, componentWillMount: function() { - // Fix position if width is overrided + // Fix position if width is overridden this._style = this.props.getStyles.container(this.props.position); if (this.props.getStyles.overrideWidth && (this.props.position === Constants.positions.tc || this.props.position === Constants.positions.bc)) { @@ -23,6 +29,14 @@ var NotificationContainer = createReactClass({ } }, + _renderDefault: function(notifications) { + return ( +
+ { notifications } +
+ ) + }, + render: function() { var self = this; var notifications; @@ -42,15 +56,13 @@ var NotificationContainer = createReactClass({ noAnimation={ self.props.noAnimation } allowHTML={ self.props.allowHTML } children={ self.props.children } + renderItem={ self.props.renderItem } + className={ self.props.itemClassName } /> ); }); - return ( -
- { notifications } -
- ); + return (this.props.renderContainer || this._renderDefault)(notifications); } }); diff --git a/src/NotificationItem.jsx b/src/NotificationItem.jsx index d578382..2aeae46 100644 --- a/src/NotificationItem.jsx +++ b/src/NotificationItem.jsx @@ -36,7 +36,10 @@ var NotificationItem = createReactClass({ children: PropTypes.oneOfType([ PropTypes.string, PropTypes.element - ]) + ]), + + renderItem: PropTypes.func, + className: PropTypes.string, }, getDefaultProps: function() { @@ -247,7 +250,7 @@ var NotificationItem = createReactClass({ return { __html: string }; }, - render: function() { + _renderDefault: function() { var notification = this.props.notification; var className = 'notification notification-' + notification.level; var notificationStyle = merge({}, this._styles.notification); @@ -323,13 +326,17 @@ var NotificationItem = createReactClass({ } return ( -
+
{ title } { message } { dismiss } { actionButton }
); + }, + + render: function() { + return (this.props.renderItem || this._renderDefault)(this.props.notification); } }); diff --git a/src/NotificationSystem.jsx b/src/NotificationSystem.jsx index b661a7d..b957275 100644 --- a/src/NotificationSystem.jsx +++ b/src/NotificationSystem.jsx @@ -94,14 +94,26 @@ var NotificationSystem = createReactClass({ PropTypes.object ]), noAnimation: PropTypes.bool, - allowHTML: PropTypes.bool + allowHTML: PropTypes.bool, + + renderSystem: PropTypes.func, + renderContainer: PropTypes.func, + renderItem: PropTypes.func, + + className: PropTypes.string, + containerClassName: PropTypes.string, + itemClassName: PropTypes.string }, getDefaultProps: function() { return { style: {}, noAnimation: false, - allowHTML: false + allowHTML: false, + + className: '', + containerClassName: '', + itemClassName: '' }; }, @@ -232,6 +244,14 @@ var NotificationSystem = createReactClass({ this._isMounted = false; }, + _renderDefault: function(containers) { + return ( +
+ { containers } +
+ ); + }, + render: function() { var self = this; var containers = null; @@ -257,17 +277,16 @@ var NotificationSystem = createReactClass({ onRemove={ self._didNotificationRemoved } noAnimation={ self.props.noAnimation } allowHTML={ self.props.allowHTML } + renderContainer={ self.props.renderContainer } + renderItem={ self.props.renderItem } + className={ self.props.containerClassName } + itemClassName={ self.props.itemClassName } /> ); }); } - - return ( -
- { containers } -
- ); + return (this.props.renderSystem || this._renderDefault)(containers); } }); From 80be2daee994b611ef3ec578e935944df6d31be1 Mon Sep 17 00:00:00 2001 From: Bartosz Dotryw Date: Fri, 6 Apr 2018 11:31:38 +0200 Subject: [PATCH 2/5] Tests --- src/NotificationContainer.jsx | 6 +- src/NotificationItem.jsx | 4 +- src/NotificationSystem.jsx | 8 +-- test/notification-system.test.js | 114 ++++++++++++++++++++++++++++++- 4 files changed, 122 insertions(+), 10 deletions(-) diff --git a/src/NotificationContainer.jsx b/src/NotificationContainer.jsx index 16186f2..4b41653 100644 --- a/src/NotificationContainer.jsx +++ b/src/NotificationContainer.jsx @@ -14,7 +14,7 @@ var NotificationContainer = createReactClass({ renderContainer: PropTypes.func, renderItem: PropTypes.func, - className: PropTypes.string, + containerClassName: PropTypes.string, itemClassName: PropTypes.string }, @@ -31,7 +31,7 @@ var NotificationContainer = createReactClass({ _renderDefault: function(notifications) { return ( -
+
{ notifications }
) @@ -57,7 +57,7 @@ var NotificationContainer = createReactClass({ allowHTML={ self.props.allowHTML } children={ self.props.children } renderItem={ self.props.renderItem } - className={ self.props.itemClassName } + itemClassName={ self.props.itemClassName } /> ); }); diff --git a/src/NotificationItem.jsx b/src/NotificationItem.jsx index 2aeae46..774276a 100644 --- a/src/NotificationItem.jsx +++ b/src/NotificationItem.jsx @@ -39,7 +39,7 @@ var NotificationItem = createReactClass({ ]), renderItem: PropTypes.func, - className: PropTypes.string, + itemClassName: PropTypes.string, }, getDefaultProps: function() { @@ -326,7 +326,7 @@ var NotificationItem = createReactClass({ } return ( -
+
{ title } { message } { dismiss } diff --git a/src/NotificationSystem.jsx b/src/NotificationSystem.jsx index b957275..35cde98 100644 --- a/src/NotificationSystem.jsx +++ b/src/NotificationSystem.jsx @@ -100,7 +100,7 @@ var NotificationSystem = createReactClass({ renderContainer: PropTypes.func, renderItem: PropTypes.func, - className: PropTypes.string, + systemClassName: PropTypes.string, containerClassName: PropTypes.string, itemClassName: PropTypes.string }, @@ -111,7 +111,7 @@ var NotificationSystem = createReactClass({ noAnimation: false, allowHTML: false, - className: '', + systemClassName: '', containerClassName: '', itemClassName: '' }; @@ -246,7 +246,7 @@ var NotificationSystem = createReactClass({ _renderDefault: function(containers) { return ( -
+
{ containers }
); @@ -279,7 +279,7 @@ var NotificationSystem = createReactClass({ allowHTML={ self.props.allowHTML } renderContainer={ self.props.renderContainer } renderItem={ self.props.renderItem } - className={ self.props.containerClassName } + containerClassName={ self.props.containerClassName } itemClassName={ self.props.itemClassName } /> ); diff --git a/test/notification-system.test.js b/test/notification-system.test.js index 44b17a7..712d390 100644 --- a/test/notification-system.test.js +++ b/test/notification-system.test.js @@ -392,7 +392,7 @@ describe('Notification Component', function() { done(); }); - it('should render containers with a overrided width', done => { + it('should render containers with a overridden width', done => { notificationObj.position = 'tc'; component.addNotification(notificationObj); let notification = TestUtils.findRenderedDOMComponentWithClass(instance, 'notifications-tc'); @@ -443,3 +443,115 @@ describe('Notification Component', function() { done(); }); }); + +describe('Notification Component with custom render functions', function() { + let node; + let instance; + let component; + let clock; + let notificationObj; + const ref = 'notificationSystem'; + let customComponents; + + this.timeout(10000); + + function renderSystem(children) { + return ; + } + function renderContainer(children) { + return ; + } + function renderItem(_params) { + return ; + } + + beforeEach(() => { + // We need to create this wrapper so we can use refs + class ElementWrapper extends Component { + render() { + return ; + } + } + node = window.document.createElement('div'); + instance = TestUtils.renderIntoDocument(React.createElement(ElementWrapper), node); + component = instance.refs[ref]; + notificationObj = merge({}, defaultNotification); + + clock = sinon.useFakeTimers(); + + component.addNotification(defaultNotification); + }); + + afterEach(() => { + clock.restore(); + }); + + it('should have custom wrapper rendered', done => { + customComponents = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'custom-system'); + expect(customComponents.length).to.equal(1); + done(); + }); + + it('should have custom container rendered', done => { + customComponents = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'custom-container'); + expect(customComponents.length).to.equal(1); + done(); + }); + + it('should have custom items rendered', done => { + customComponents = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'custom-item'); + expect(customComponents.length).to.equal(1); + done(); + }); +}); + +describe('Notification Component with custom classNames', function() { + let node; + let instance; + let component; + let clock; + let notificationObj; + const ref = 'notificationSystem'; + let customComponent; + + this.timeout(10000); + + beforeEach(() => { + // We need to create this wrapper so we can use refs + class ElementWrapper extends Component { + render() { + return ; + } + } + node = window.document.createElement('div'); + instance = TestUtils.renderIntoDocument(React.createElement(ElementWrapper), node); + component = instance.refs[ref]; + notificationObj = merge({}, defaultNotification); + + clock = sinon.useFakeTimers(); + + component.addNotification(defaultNotification); + }); + + afterEach(() => { + clock.restore(); + }); + + it('should have custom wrapper rendered', done => { + customComponent = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'customsystem'); + expect(customComponent.length).to.equal(1); + done(); + }); + + it('should have custom container rendered', done => { + customComponent = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'customcontainer'); + expect(customComponent.length).to.equal(1); + done(); + }); + + it('should have custom items rendered', done => { + customComponent = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'customitem'); + expect(customComponent.length).to.equal(1); + done(); + }); +}); From 8c0aa245be6bcb8782a76d4d9f97bf625baf178a Mon Sep 17 00:00:00 2001 From: Bartosz Dotryw Date: Fri, 6 Apr 2018 11:48:12 +0200 Subject: [PATCH 3/5] Updates README --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 464f1b6..90b238e 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,12 @@ The notification object has the following properties: | onAdd | function | null | A callback function that will be called when the notification is successfully added. The first argument is the original notification e.g. `function (notification) { console.log(notification.title + 'was added'); }` | | onRemove | function | null | A callback function that will be called when the notification is about to be removed. The first argument is the original notification e.g. `function (notification) { console.log(notification.title + 'was removed'); }` | | uid | integer/string | null | Overrides the internal `uid`. Useful if you are managing your notifications id. Notifications with same `uid` won't be displayed. | - +| systemClassName | string | "" | Additional CSS class(es) to add to `` (see HTML template below) | +| containerClassName | string | "" | Additional CSS class(es) to add to `` (see HTML template below) | +| itemClassName | string | "" | Additional CSS class(es) to add to `` (see HTML template below) | +| renderSystem | function | *built-in render function* | Custom render function for notification system, receives ``s as param (this allows to use other component rather than `div.notifications-wrapper`). Overrides `systemClassName` | +| renderContainer | function | *built-in render function* | Custom render function for notification container, receives ``s as param (this allows to use other component rather than `div.notifications-{position}`). Overrides `containerClassName` | +| renderItem | function | *built-in render function* | Custom render function for notification, receives notification object as param (this allows to use other component rather than `div.notification` with it's children). Overrides `itemClassName` | ### Dismissible @@ -190,12 +195,12 @@ To disable all inline styles, just pass `false` to the prop `style`. ``` -Here is the notification HTML: +Here is the notification HTML (if not using custom render functions): ```html -
-
-
+
+
+

Default title

Default message
× From 4120fb83691a68e04f4b2c0185be9aeb39ca90b4 Mon Sep 17 00:00:00 2001 From: Bartosz Dotryw Date: Fri, 6 Apr 2018 15:03:15 +0200 Subject: [PATCH 4/5] dismiss fix --- README.md | 2 +- src/NotificationItem.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 90b238e..4847c77 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ The notification object has the following properties: | itemClassName | string | "" | Additional CSS class(es) to add to `` (see HTML template below) | | renderSystem | function | *built-in render function* | Custom render function for notification system, receives ``s as param (this allows to use other component rather than `div.notifications-wrapper`). Overrides `systemClassName` | | renderContainer | function | *built-in render function* | Custom render function for notification container, receives ``s as param (this allows to use other component rather than `div.notifications-{position}`). Overrides `containerClassName` | -| renderItem | function | *built-in render function* | Custom render function for notification, receives notification object as param (this allows to use other component rather than `div.notification` with it's children). Overrides `itemClassName` | +| renderItem | function | *built-in render function* | Custom render function for notification, receives notification object and dismiss callback as params (this allows to use other component rather than `div.notification` with it's children). Overrides `itemClassName` | ### Dismissible diff --git a/src/NotificationItem.jsx b/src/NotificationItem.jsx index 774276a..66d8657 100644 --- a/src/NotificationItem.jsx +++ b/src/NotificationItem.jsx @@ -336,7 +336,7 @@ var NotificationItem = createReactClass({ }, render: function() { - return (this.props.renderItem || this._renderDefault)(this.props.notification); + return (this.props.renderItem || this._renderDefault)(this.props.notification, this._dismiss); } }); From 74d4c79b43ec7c3937dc6ab135337c02f96cefc7 Mon Sep 17 00:00:00 2001 From: Bartosz Dotryw Date: Mon, 9 Apr 2018 10:42:40 +0200 Subject: [PATCH 5/5] Added visible prop --- README.md | 2 +- src/NotificationItem.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4847c77..f4397fe 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ The notification object has the following properties: | itemClassName | string | "" | Additional CSS class(es) to add to `` (see HTML template below) | | renderSystem | function | *built-in render function* | Custom render function for notification system, receives ``s as param (this allows to use other component rather than `div.notifications-wrapper`). Overrides `systemClassName` | | renderContainer | function | *built-in render function* | Custom render function for notification container, receives ``s as param (this allows to use other component rather than `div.notifications-{position}`). Overrides `containerClassName` | -| renderItem | function | *built-in render function* | Custom render function for notification, receives notification object and dismiss callback as params (this allows to use other component rather than `div.notification` with it's children). Overrides `itemClassName` | +| renderItem | function | *built-in render function* | Custom render function for notification, receives *notification object*, *dismiss callback* and *`visible` state* as params (this allows to use other component rather than `div.notification` with it's children). Overrides `itemClassName` | ### Dismissible diff --git a/src/NotificationItem.jsx b/src/NotificationItem.jsx index 66d8657..9d53022 100644 --- a/src/NotificationItem.jsx +++ b/src/NotificationItem.jsx @@ -336,7 +336,7 @@ var NotificationItem = createReactClass({ }, render: function() { - return (this.props.renderItem || this._renderDefault)(this.props.notification, this._dismiss); + return (this.props.renderItem || this._renderDefault)(this.props.notification, this._dismiss, this.state.visible); } });