Skip to content

Commit

Permalink
docs: update toast examples
Browse files Browse the repository at this point in the history
  • Loading branch information
cheton committed Oct 29, 2024
1 parent dce24b6 commit faf14d3
Show file tree
Hide file tree
Showing 3 changed files with 261 additions and 216 deletions.
193 changes: 88 additions & 105 deletions packages/react-docs/pages/components/toast/drawer-toast.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@ import {
Stack,
Text,
Toast,
ToastController,
ToastTransition,
ToastGroup,
useColorStyle,
} from '@tonic-ui/react';
import { CloseSIcon } from '@tonic-ui/react-icons';
import React, { useState } from 'react';
import { TransitionGroup } from 'react-transition-group';

const MAX_TOASTS = 1;

const CustomToastContainer = (props) => (
const InlineToastContainer = (props) => (
<Flex
flexDirection="column"
alignItems="center"
Expand All @@ -32,7 +30,7 @@ const CustomToastContainer = (props) => (
left="50%"
transform="translateX(-50%)"
width="max-content"
maxWidth="80%" // up to 80% of the modal or drawer width
maxWidth="80%" // up to 80% of the drawer width
zIndex="toast"
{...props}
/>
Expand All @@ -46,39 +44,35 @@ const App = () => {

const notify = (options) => {
const {
appearance,
content,
duration = null,
isClosable = true,
duration,
} = { ...options };

setToasts(prevState => {
const id = ++autoIncrementIndex;
const onClose = () => {
setToasts(toasts => toasts.filter(x => x.id !== id));
};
// You can decide how many toasts you want to show at the same time depending on your use case
const nextState = [
...prevState.slice(MAX_TOASTS > 1 ? -(MAX_TOASTS - 1) : prevState.length),
{
id,
appearance,
content,
duration,
isClosable,
onClose,
},
];
return nextState;
});
};

const closeToast = (id) => {
setToasts(toasts => toasts.filter(x => x.id !== id));
};

const closeAll = () => {
setToasts([]);
};

const handleClickAddToastByAppearance = (appearance) => (event) => {
const content = {
const toastMessage = {
success: (
<>
<Text>This is a success message.</Text>
Expand All @@ -88,7 +82,7 @@ const App = () => {
info: (
<>
<Text>This is an info message.</Text>
<Text>The toast will remain visible until the user dismisses it.</Text>
<Text>The toast will be automatically dismissed after 5 seconds.</Text>
</>
),
warning: (
Expand All @@ -106,103 +100,92 @@ const App = () => {
}[appearance];

notify({
appearance,
content,
duration: (appearance === 'success') ? 5000 : undefined,
content: ({ onClose }) => (
<Toast
appearance={appearance}
isClosable={true}
onClose={onClose}
sx={{
mb: '2x',
minWidth: 280, // The toast has a minimum width of 280 pixels
width: 'fit-content',
boxShadow: colorStyle.shadow.thin,
}}
>
{toastMessage}
</Toast>
),
duration: (appearance === 'success' || appearance === 'info') ? 5000 : undefined,
});
};

const handleClickCloseToasts = () => {
closeAll();
};

return (<>
<Flex justifyContent="space-between" columnGap="4x">
<Flex flexWrap="wrap" columnGap="2x" rowGap="2x">
<Button variant="secondary" onClick={handleClickAddToastByAppearance('success')}>
Show Success Message
</Button>
<Button variant="secondary" onClick={handleClickAddToastByAppearance('info')}>
Show Info Message
</Button>
<Button variant="secondary" onClick={handleClickAddToastByAppearance('warning')}>
Show Warning Message
</Button>
<Button variant="secondary" onClick={handleClickAddToastByAppearance('error')}>
Show Error Message
</Button>
return (
<>
<Flex justifyContent="space-between" columnGap="4x">
<Flex flexWrap="wrap" columnGap="2x" rowGap="2x">
<Button variant="secondary" onClick={handleClickAddToastByAppearance('success')}>
Show Success Message
</Button>
<Button variant="secondary" onClick={handleClickAddToastByAppearance('info')}>
Show Info Message
</Button>
<Button variant="secondary" onClick={handleClickAddToastByAppearance('warning')}>
Show Warning Message
</Button>
<Button variant="secondary" onClick={handleClickAddToastByAppearance('error')}>
Show Error Message
</Button>
</Flex>
<Box>
<Button variant="secondary" onClick={handleClickCloseToasts}>
<CloseSIcon />
<Space width="2x" />
Close
</Button>
</Box>
</Flex>
<Divider my="4x" />
<Flex columnGap="4x">
<DrawerContent
margin={0}
minHeight={400}
minWidth={320}
width="50%"
>
<InlineToastContainer>
<ToastGroup
onClose={closeToast}
toasts={toasts}
/>
</InlineToastContainer>
<DrawerHeader>
Drawer
</DrawerHeader>
<DrawerBody>
<Stack direction="column" spacing="4x">
<Skeleton width={160} />
<Skeleton width={240} />
<Skeleton width={240} />
</Stack>
</DrawerBody>
<DrawerFooter>
<Grid templateColumns="repeat(2, 1fr)" columnGap="2x">
<Button variant="primary">
OK
</Button>
<Button>
Cancel
</Button>
</Grid>
</DrawerFooter>
</DrawerContent>
</Flex>
<Box>
<Button variant="secondary" onClick={handleClickCloseToasts}>
<CloseSIcon />
<Space width="2x" />
Close
</Button>
</Box>
</Flex>
<Divider my="4x" />
<Flex columnGap="4x">
<DrawerContent
margin={0}
minHeight={400}
minWidth={320}
width="50%"
>
<CustomToastContainer>
<TransitionGroup
component={null} // Pass in `component={null}` to avoid a wrapping `<div>` element
>
{toasts.map(toast => (
<ToastTransition
key={toast?.id}
in={true}
unmountOnExit
>
<ToastController
duration={toast?.duration}
onClose={toast?.onClose}
>
<Toast
appearance={toast?.appearance}
isClosable={toast?.isClosable}
onClose={toast?.onClose}
sx={{
mb: '2x',
minWidth: 280, // The toast has a minimum width of 280 pixels
width: 'fit-content',
boxShadow: colorStyle.shadow.thin,
}}
>
{toast?.content}
</Toast>
</ToastController>
</ToastTransition>
))}
</TransitionGroup>
</CustomToastContainer>
<DrawerHeader>
Drawer
</DrawerHeader>
<DrawerBody>
<Stack direction="column" spacing="4x">
<Skeleton width={160} />
<Skeleton width={240} />
<Skeleton width={240} />
</Stack>
</DrawerBody>
<DrawerFooter>
<Grid templateColumns="repeat(2, 1fr)" columnGap="2x">
<Button variant="primary">
OK
</Button>
<Button>
Cancel
</Button>
</Grid>
</DrawerFooter>
</DrawerContent>
</Flex>
</>);
</>
);
};

export default App;
91 changes: 85 additions & 6 deletions packages/react-docs/pages/components/toast/index.page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ A toast notification is a small popup that appears at either side of the screen,
import {
Toast,
ToastCloseButton,
ToastController,
ToastGroup,
ToastTransition,
} from '@tonic-ui/react';
```
Expand Down Expand Up @@ -78,10 +78,90 @@ The placement and size of toasts are typically determined by the design of the a

In this example, the toast will be positioned 48 pixels from the top of the modal or drawer, and has a minimum width of 280 pixels. If the content of the toast message is wider than 280 pixels, the toast will expand to fit the content without exceeding 80% of the width of the modal or drawer in which it is being displayed.

To animate the toast when it is displayed or dismissed, you can use the `ToastTransition` component. The `ToastController` component can also be used to control the duration for which the toast will be displayed before it is automatically dismissed. This allows you to set a specific amount of time for the toast to be visible, ensuring that it does not interrupt the user's workflow for too long.
```jsx
const InlineToastContainer = (props) => (
<Flex
flexDirection="column"
alignItems="center"
position="absolute"
top="12x"
left="50%"
transform="translateX(-50%)"
width="max-content"
maxWidth="80%" // up to 80% of the drawer width
zIndex="toast"
{...props}
/>
);
```

```jsx
<Toast
appearance="success"
isClosable={true}
onClose={onClose}
sx={{
mb: '2x',
minWidth: 280, // minimum width of 280 pixels
width: 'fit-content',
boxShadow: colorStyle.shadow.thin,
}}
>
<Text>This is a success message.</Text>
</Toast>
```

To control the display of toasts, you can pass an array of toast objects to the `ToastGroup` component. Each toast object should include the following properties:

| Name | Type | Description |
| :--- | :--- | :---------- |
| id | string \| number | A unique identifier for the toast. |
| content | function | A function that renders the toast's content and accepts `{ onClose }` as a parameter to handle closing the toast. |
| duration | number | (Optional) Defines how long (in milliseconds) the toast should remain visible before automatically dismissing. Use `undefined` to keep the toast visible indefinitely. |

Here is an example:

```jsx
[
{
id: 1000,
content: ({ onClose }) => (
<Toast
appearance="success"
isClosable
onClose={onClose}
sx={{
mb: '2x',
minWidth: 280, // minimum width of 280 pixels
width: 'fit-content',
boxShadow: colorStyle.shadow.thin,
}}
>
<Text>This is a success message.</Text>
</Toast>
),
duration: 5000, // auto dismiss after 5 seconds
},
];
```

```jsx
<InlineToastContainer>
<ToastGroup
onClose={(id) => {
setToasts(toasts => toasts.filter(x => x.id !== id));
}}
toasts={toasts}
/>
</InlineToastContainer>
```

#### Modal

{render('./modal-toast')}

#### Drawer

{render('./drawer-toast')}

## Props
Expand All @@ -102,13 +182,12 @@ To animate the toast when it is displayed or dismissed, you can use the `ToastTr
| :--- | :--- | :------ | :---------- |
| children | ReactNode | | |

### ToastController
### ToastGroup

| Name | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
| children | ReactNode | | |
| duration | number | null | The duration in milliseconds after which the toast will be automatically closed. Set to `null` to disable auto-closing. |
| onClose | function | | A callback called when the toast is being closed. |
| onClose | function | | A callback called when a toast is being closed. |
| toasts | array | | An array of toasts, each containg `id`, `content`, and an optional `duration` property.<br /><pre>type Toast = {'{'}<br /> id: string \| number;<br /> content: ({'{'} onClose {'}'}) => JSX.Element;<br /> duration?: number;<br />{'}'};</pre> |

### ToastTransition

Expand Down
Loading

0 comments on commit faf14d3

Please sign in to comment.