Skip to content

Commit

Permalink
feat: update ToastManager to support custom container and transitio…
Browse files Browse the repository at this point in the history
…n components
  • Loading branch information
cheton committed Dec 29, 2023
1 parent 8505c42 commit e65ee26
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Box, Button, Toast, ToastContainer, ToastManager, useToastManager } from '@tonic-ui/react';
import React from 'react';

const MyContainerComponent = ({
placement,
...rest
}) => {
const verticalMargin = '6x'; // 24px
const horizontalMargin = '4x'; // 16px
const styleProps = {};

if (placement.includes('top')) {
styleProps.top = verticalMargin;
}
if (placement.includes('bottom')) {
styleProps.bottom = verticalMargin;
}
if (placement.includes('left')) {
styleProps.left = horizontalMargin;
}
if (placement.includes('right')) {
styleProps.right = horizontalMargin;
}

return (
<ToastContainer
placement={placement}
{...styleProps}
{...rest}
/>
);
};

const MyApp = () => {
const toast = useToastManager();

return (
<Button
onClick={() => {
const render = ({ onClose, placement }) => (
<Box my="2x">
<Toast appearance="info" isClosable onClose={onClose} minWidth={320}>
Hello world!
</Toast>
</Box>
);

const placement = 'bottom-right';
if (toast.state[placement].length >= 3) {
toast.close(toast.state[placement][0].id, placement);
}

const options = {
placement: placement,
duration: 30 * 1000,
};
toast(render, options);
}}
>
Notify
</Button>
);
};

const App = () => (
<ToastManager
ContainerComponent={MyContainerComponent}
placement="bottom-right"
>
<MyApp />
</ToastManager>
);

export default App;
12 changes: 12 additions & 0 deletions packages/react-docs/pages/components/toast-manager/index.page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,24 @@ toast.remove(id);

See the [useToastManager](./toast-manager/useToastManager) Hook for detailed usage.

## Commonly Asked Questions

### How to customize the toast container?

`ToastManager` renders a `ToastContainer` component by default. You can customize the container component by passing a `ContainerComponent` prop to `ToastManager`.

{render('./custom-toast-container')}

## Props

### ToastManager

| Name | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
| ContainerComponent | ElementType | ToastContainer | The component used for the container. |
| ContainerProps | object | | Props applied to the container component. |
| TransitionComponent | ElementType | ToastTransition | The component used for the transition. |
| TransitionProps | object | | Props applied to the [Transition](http://reactcommunity.org/react-transition-group/transition#Transition-props) element. |
| children | ReactNode \| `(context) => ReactNode` | | A function child can be used intead of a React element. This function is called with the context object. |
| containerRef | RefObject | | A `ref` to the component where the toasts will be rendered. |
| placement | string | 'bottom-right' | The default placement to place toasts. One of: 'top', 'top-right', 'top-left', 'bottom', 'bottom-left', 'bottom-right' |
19 changes: 11 additions & 8 deletions packages/react/src/toast/ToastManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ const getToastPlacementByState = (state, id) => {

const ToastManager = ({
container: DEPRECATED_container, // deprecated (remove in next major version)

ContainerComponent = ToastContainer,
ContainerProps,
TransitionComponent = ToastTransition,
TransitionProps,
children,
containerRef,
placement: placementProp = defaultPlacement,
Expand Down Expand Up @@ -155,8 +158,7 @@ const ToastManager = ({
* Create a toast at the specified placement and return the id
*/
const notify = useCallback((message, options) => {
const { id, duration, placement } = options;
const toast = createToast(message, { id, duration, placement });
const toast = createToast(message, options);

if (!placements.includes(toast.placement)) {
console.error(`[ToastManager] Error: Invalid toast placement "${toast.placement}". Please provide a valid placement from the following options: ${placements.join(', ')}.`);
Expand Down Expand Up @@ -250,16 +252,17 @@ const ToastManager = ({
{Object.keys(state).map((placement) => {
const toasts = ensureArray(state[placement]);
return (
<ToastContainer
<ContainerComponent
{...ContainerProps}
key={placement}
placement={placement}
>
<TransitionGroup component={null}>
{toasts.map((toast) => (
<ToastTransition
<TransitionComponent
{...TransitionProps}
key={toast.id}
in={true}
collapsedHeight={0}
unmountOnExit
>
<ToastController
Expand All @@ -282,10 +285,10 @@ const ToastManager = ({
return null;
})()}
</ToastController>
</ToastTransition>
</TransitionComponent>
))}
</TransitionGroup>
</ToastContainer>
</ContainerComponent>
);
})}
</Portal>
Expand Down

0 comments on commit e65ee26

Please sign in to comment.