Skip to content

Commit

Permalink
Merge 319a0c5 into 1991ed2
Browse files Browse the repository at this point in the history
  • Loading branch information
mudafar committed Apr 15, 2019
2 parents 1991ed2 + 319a0c5 commit e4ba23d
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 12 deletions.
16 changes: 8 additions & 8 deletions .size-snapshot.json
Expand Up @@ -5,9 +5,9 @@
"gzipped": 5540
},
"cjs/react-toastify.min.js": {
"bundled": 29343,
"minified": 16443,
"gzipped": 5216
"bundled": 29632,
"minified": 16597,
"gzipped": 5262
},
"./esm/index.esm.js": {
"bundled": 32847,
Expand All @@ -24,16 +24,16 @@
}
},
"esm/react-toastify.js": {
"bundled": 32948,
"minified": 18322,
"gzipped": 5466,
"bundled": 33577,
"minified": 18650,
"gzipped": 5525,
"treeshaked": {
"rollup": {
"code": 16013,
"code": 16285,
"import_statements": 442
},
"webpack": {
"code": 17592
"code": 17878
}
}
}
Expand Down
51 changes: 50 additions & 1 deletion README.md
Expand Up @@ -17,6 +17,7 @@
- [One component to rule them all](#one-component-to-rule-them-all)
- [One ToastContainer to render them](#one-toastcontainer-to-render-them)
- [What if I told you that the ToastContainer is optional](#what-if-i-told-you-that-the-toastcontainer-is-optional)
- [Multi container support](#multi-container-support)
- [Positioning toast](#positioning-toast)
- [Set autoclose delay or disable it](#set-autoclose-delay-or-disable-it)
- [Render a component](#render-a-component)
Expand Down Expand Up @@ -158,6 +159,50 @@ toast.configure({
});
```


#### Multi container support

To enable multiple container support, you have to pass `enableMultiContainer` and specify a `containerId` and use it in
each toast, to do so add `containerId` to the toast's options object.



Note: adding `enableMultiContainer` prop to the `<ToastContainer/ >` will:
- Check each toast to verify if its `containerId` match the container `containerId` so it can be rendered.
- Ensure not to render any `toast` that has `containerId`.
- Render any toast if both the `toast` and `<ToastContainer/ >` does not include `containerId` and `containerId` respectively.

A simple example to demonstrate multi toast container capability.

- Notify A button will show a toast on the bottom left.
- Notify B button will show a toast on the top right.

```javascript
import React, { Component } from 'react';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';


class App extends Component {
notifyA = () => toast('Wow so easy !', {containerId: 'A'});
notifyB = () => toast('Wow so easy !', {containerId: 'B'});

render(){
return (
<div>
<ToastContainer enableMultiContainer containerId={'A'} position={toast.POSITION.BOTTOM_LEFT} />
<ToastContainer enableMultiContainer containerId={'B'} position={toast.POSITION.TOP_RIGHT} />

<button onClick={this.notifyA}>Notify A !</button>
<button onClick={this.notifyB}>Notify B !</button>
</div>
);
}
}

```


### Positioning toast

By default, all the toasts will be positioned on the top right of your browser. If a position is set on a `toast`, the one defined on ToastContainer will be replaced.
Expand Down Expand Up @@ -1152,9 +1197,12 @@ On mobile the toast will take all the available width.
| toastClassName | string\|object | - | Add optional classes to the toast |
| bodyClassName | string\|object | - | Add optional classes to the toast body |
| progressClassName | string\|object | - | Add optional classes to the progress bar |
| progressStyle | object | - | Add optional inline style to the progress bar |
| progressStyle | object | - | Add optional inline style to the progress bar |
| draggable | bool | true | Allow toast to be draggable |
| draggablePercent | number | 80 | The percentage of the toast's width it takes for a drag to dismiss a toast(value between 0 and 100) |
| enableMultiContainer | bool | - | Enable multi toast container support |
| containerId | string\number | - | Container id used to match toast with the same containerId |



### toast
Expand Down Expand Up @@ -1189,6 +1237,7 @@ The **toastId** can be used to remove a toast programmatically or to check if th
- `progress`: a value between 0..1 to control the progress bar
- `render`: string or React Element, only available when calling update
- `delay`: a number to let you delay the toast appearance
- `containerId`: string or number to match a specific Toast container

:warning:*Toast options supersede ToastContainer props* :warning:

Expand Down
65 changes: 65 additions & 0 deletions src/__tests__/components/ToastContainer.js
Expand Up @@ -282,6 +282,71 @@ describe('ToastContainer', () => {
});
});

describe('Multiple container support', ()=> {
describe('Disabled', ()=> {
it('Should render toasts in all container', () => {
const toastContainerComponent1 = mount(<ToastContainer enableMultiContainer={false} />);
const toastContainerComponent2 = mount(<ToastContainer />);
const toastContainerComponent3 = mount(<ToastContainer containerId={1}/>);

toast('Toast 1');
toast('Toast 2', {containerId: 1});
jest.runAllTimers();

expect(toastContainerComponent1.state().toast).toHaveLength(2);
expect(toastContainerComponent2.state().toast).toHaveLength(2);
expect(toastContainerComponent3.state().toast).toHaveLength(2);
});
});

describe('Enabled', () => {
describe('With containerId', () => {
it('Should show only related toasts aka- same containerId and containerId', () => {
const toastContainerComponent1 = mount(<ToastContainer containerId={1} enableMultiContainer/>);
const toastContainerComponent2 = mount(<ToastContainer containerId={2} enableMultiContainer/>);

toast('Toast with containerId 1', {containerId: 1});
toast('Toast with containerId 2', {containerId: 2});
toast('Another toast with containerId 2', {containerId: 2});
jest.runAllTimers();

expect(toastContainerComponent1.state().toast).toHaveLength(1);
expect(toastContainerComponent2.state().toast).toHaveLength(2);
});

it('Should not display unrelated toasts', () => {
const toastContainerComponent = mount(<ToastContainer containerId={1} enableMultiContainer/>);

toast('Toast with containerId 1', {containerId: 2});
toast('Toast with containerId 2', {containerId: 2});
jest.runAllTimers();

expect(toastContainerComponent.state().toast).toHaveLength(0);
});
});

describe('Has no containerId', () => {
it('Should display toasts with no containerId', () => {
const toastContainerComponent = mount(<ToastContainer enableMultiContainer />);

toast('Toast');
jest.runAllTimers();

expect(toastContainerComponent.state().toast).toHaveLength(1);
});

it('Should not display any toasts with containerId', () => {
const toastContainerComponent = mount(<ToastContainer enableMultiContainer />);

toast('Toast', {containerId: 1});
jest.runAllTimers();

expect(toastContainerComponent.state().toast).toHaveLength(0);
});
});
});
});

it("Should throw an error if can't render a toast", () => {
expect(() => {
mount(<ToastContainer />);
Expand Down
3 changes: 2 additions & 1 deletion src/components/Toast.js
Expand Up @@ -56,7 +56,8 @@ class Toast extends Component {
progress: PropTypes.number,
isProgressDone: PropTypes.bool,
updateId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
ariaLabel: PropTypes.string
ariaLabel: PropTypes.string,
containerId: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
};

static defaultProps = {
Expand Down
23 changes: 21 additions & 2 deletions src/components/ToastContainer.js
Expand Up @@ -107,7 +107,17 @@ class ToastContainer extends Component {
/**
* Pause the toast on focus loss
*/
pauseOnFocusLoss: PropTypes.bool
pauseOnFocusLoss: PropTypes.bool,

/**
* Show the toast only if it includes containerId and it's the same as containerId
*/
enableMultiContainer: PropTypes.bool,

/**
* Set id to handle multiple container
*/
containerId: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
};

static defaultProps = {
Expand Down Expand Up @@ -229,12 +239,21 @@ class ToastContainer extends Component {
return null;
}

belongToContainer({containerId}) {
return containerId === this.props.containerId;
}

buildToast(content, { delay, ...options }) {
if (!this.canBeRendered(content)) {
throw new Error(
`The element you provided cannot be rendered. You provided an element of type ${typeof content}`
`The element you provided cannot be rendered. You provided an element of type ${typeof content}`
);
}
if (this.props.enableMultiContainer) {
if (!this.belongToContainer(options)) {
return null;
}
}
const toastId = options.toastId;
const closeToast = () => this.removeToast(toastId);
const toastOptions = {
Expand Down

0 comments on commit e4ba23d

Please sign in to comment.