diff --git a/apps/website/src/content/docs/toast.mdx b/apps/website/src/content/docs/toast.mdx index 4c94060a39d..d8f1c4da3bd 100644 --- a/apps/website/src/content/docs/toast.mdx +++ b/apps/website/src/content/docs/toast.mdx @@ -1,18 +1,102 @@ --- title: Toast -description: A Toast is a non modal, unobtrusive window element used to display small amount of information to a user. +description: A toast is a non-disruptive message that provides feedback based on a user action. thumbnail: Toast ---

{frontmatter.description}

- +## Usage + +Before triggering a toast, you need to call the `useToaster` hook, which returns an object containing various methods for triggering the toast and changing the toaster settings. -A toast notification provides a brief message about app processes at the top of the screen. Because these messages are so prominent, we need to be careful not to overuse or misuse them. +**Note**: `useToaster` must be called from the top level of a component which is rendered as a descendant of [`ThemeProvider`](/docs/themeprovider). + +### Status + +Toasts can be triggered using the status methods provided by the toaster object. The status method takes in a toast message and an `options` object for further customization. Four available statuses are: + +- `positive()` +- `negative()` +- `warning()` +- `informational()` + + + + + +For further customization with `options`, you can utilize `link`, which allows taking further actions directly from the toast, such as navigating to another page or triggering a specific function. + + + + + +### Settings + +The object returned by `useToaster` also provides a `setSettings` method, which can be used to customize the `placement` and `order` of toasts. + +`placement` supports the following values: + +- `"top"` (default) +- `"top-start"` +- `"top-end"` +- `"bottom"` +- `"bottom-start"` +- `"bottom-end"` + +`"start"` indicates the left side of viewport, while `"end"` represents the right side. + + + + + +`order` supports the following values: + +- `"auto"` (default) +- `"descending"` +- `"ascending"` + +When set to `"descending"`, the most recent toasts are on top. When set to `"ascending"`, the most recent toasts are on bottom. When set to `"auto"`, it will behave like `"descending"` when `placement` is set to a value beginning with `"top"`, otherwise it will behave like `"ascending"`. + + + + + +### Closing toasts + +When setting the `hasCloseButton` option available in the status method to `true`, each toast will be displayed with a close button, which allows the end user to close the toast manually. + + + + + +Additionally, to implement further actions upon the closing of each toast or to chain one toast after another, you can call the `close()` function returned from the status method. + + + + + +Closing also depends on the type of toast when used without `hasCloseButton`. By default, persisting toasts will not be closed automatically and will contain a close button while temporary toasts will automatically close after 7 seconds and will not contain a close button. The type of toasts can be specified by passing either `"persisting"` or `"temporary"` into the `type` option. + + + + + +To close all currently open toasts at once, use the `closeAll()` method offered by the toaster object. + + + + + +The `animateOutTo` prop allows you to control the direction to which the toast animates out when closing. Specifically, it helps determine an "anchor" element that the toast will go towards when it is dismissed. This can be useful, for example, when you want to indicate to the user that the toasts are being saved into a "notifications" panel. + + + + ## Props diff --git a/examples/Toast.anchorToButton.css b/examples/Toast.anchorToButton.css new file mode 100644 index 00000000000..e059575c674 --- /dev/null +++ b/examples/Toast.anchorToButton.css @@ -0,0 +1,5 @@ +.demo-container { + display: flex; + align-items: center; + flex-direction: column; +} diff --git a/examples/Toast.anchorToButton.jsx b/examples/Toast.anchorToButton.jsx new file mode 100644 index 00000000000..737a79be04c --- /dev/null +++ b/examples/Toast.anchorToButton.jsx @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { useToaster, Button } from '@itwin/itwinui-react'; + +export default () => { + const toaster = useToaster(); + const buttonRef = React.useRef(null); + + React.useEffect(() => { + toaster.setSettings({ + placement: 'top-end', + }); + }, []); + + return ( +
+ +
+ ); +}; diff --git a/examples/Toast.close.jsx b/examples/Toast.close.jsx new file mode 100644 index 00000000000..2d9d00934bf --- /dev/null +++ b/examples/Toast.close.jsx @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { useToaster, Button, Flex, ProgressRadial } from '@itwin/itwinui-react'; + +export default () => { + const toaster = useToaster(); + + const displayProcessToast = () => { + const { close } = toaster.informational( + + + Your process is running... + , + ); + + setTimeout(() => { + close(); + toaster.positive('Process completed', { + hasCloseButton: true, + }); + }, 1000); + }; + + return ; +}; diff --git a/examples/Toast.closeAll.css b/examples/Toast.closeAll.css new file mode 100644 index 00000000000..a94f5c6e618 --- /dev/null +++ b/examples/Toast.closeAll.css @@ -0,0 +1,6 @@ +.demo-container { + display: flex; + align-items: center; + flex-direction: column; + gap: var(--iui-size-xs); +} diff --git a/examples/Toast.closeAll.jsx b/examples/Toast.closeAll.jsx new file mode 100644 index 00000000000..4ee411d7740 --- /dev/null +++ b/examples/Toast.closeAll.jsx @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { useToaster, Button } from '@itwin/itwinui-react'; + +export default () => { + const toaster = useToaster(); + + return ( +
+ + + +
+ ); +}; diff --git a/examples/Toast.hasCloseButton.jsx b/examples/Toast.hasCloseButton.jsx new file mode 100644 index 00000000000..38c2044c20d --- /dev/null +++ b/examples/Toast.hasCloseButton.jsx @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { useToaster, Button } from '@itwin/itwinui-react'; + +export default () => { + const toaster = useToaster(); + + return ( +
+ +
+ ); +}; diff --git a/examples/Toast.link.jsx b/examples/Toast.link.jsx new file mode 100644 index 00000000000..e250a91e304 --- /dev/null +++ b/examples/Toast.link.jsx @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { useToaster, Button } from '@itwin/itwinui-react'; + +export default () => { + const toaster = useToaster(); + + const displayToast = () => { + toaster.positive('Job processing completed.', { + link: { + title: 'Link', + onClick: () => { + alert('Link was clicked!'); + }, + }, + }); + }; + + return ( +
+ +
+ ); +}; diff --git a/examples/Toast.main.css b/examples/Toast.main.css new file mode 100644 index 00000000000..e059575c674 --- /dev/null +++ b/examples/Toast.main.css @@ -0,0 +1,5 @@ +.demo-container { + display: flex; + align-items: center; + flex-direction: column; +} diff --git a/examples/Toast.main.jsx b/examples/Toast.main.jsx index 2b587847d0c..d2a092824c5 100644 --- a/examples/Toast.main.jsx +++ b/examples/Toast.main.jsx @@ -9,22 +9,10 @@ export default () => { const toaster = useToaster(); return ( - +
+ +
); }; diff --git a/examples/Toast.order.css b/examples/Toast.order.css new file mode 100644 index 00000000000..a94f5c6e618 --- /dev/null +++ b/examples/Toast.order.css @@ -0,0 +1,6 @@ +.demo-container { + display: flex; + align-items: center; + flex-direction: column; + gap: var(--iui-size-xs); +} diff --git a/examples/Toast.order.jsx b/examples/Toast.order.jsx new file mode 100644 index 00000000000..033e321cf13 --- /dev/null +++ b/examples/Toast.order.jsx @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { useToaster, Button, Select } from '@itwin/itwinui-react'; + +export default () => { + const toaster = useToaster(); + + return ( +
+ + toaster.setSettings({ + placement: value, + }) + } + /> + +
+ ); +}; diff --git a/examples/Toast.status.css b/examples/Toast.status.css new file mode 100644 index 00000000000..56c654d5310 --- /dev/null +++ b/examples/Toast.status.css @@ -0,0 +1,4 @@ +.demo-container { + display: flex; + gap: var(--iui-size-xs); +} diff --git a/examples/Toast.status.jsx b/examples/Toast.status.jsx new file mode 100644 index 00000000000..c38a4407d08 --- /dev/null +++ b/examples/Toast.status.jsx @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { useToaster, Button } from '@itwin/itwinui-react'; + +export default () => { + const toaster = useToaster(); + + return ( +
+ + + + +
+ ); +}; diff --git a/examples/Toast.type.css b/examples/Toast.type.css new file mode 100644 index 00000000000..56c654d5310 --- /dev/null +++ b/examples/Toast.type.css @@ -0,0 +1,4 @@ +.demo-container { + display: flex; + gap: var(--iui-size-xs); +} diff --git a/examples/Toast.type.jsx b/examples/Toast.type.jsx new file mode 100644 index 00000000000..eed4558a33e --- /dev/null +++ b/examples/Toast.type.jsx @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ +import * as React from 'react'; +import { useToaster, Button } from '@itwin/itwinui-react'; + +export default () => { + const toaster = useToaster(); + + return ( +
+ + +
+ ); +}; diff --git a/examples/index.tsx b/examples/index.tsx index e720659fa62..d9871e09243 100644 --- a/examples/index.tsx +++ b/examples/index.tsx @@ -1279,6 +1279,46 @@ import { default as ToastMainExampleRaw } from './Toast.main'; const ToastMainExample = withThemeProvider(ToastMainExampleRaw); export { ToastMainExample }; +import { default as ToastStatusExampleRaw } from './Toast.status'; +const ToastStatusExample = withThemeProvider(ToastStatusExampleRaw); +export { ToastStatusExample }; + +import { default as ToastLinkExampleRaw } from './Toast.link'; +const ToastLinkExample = withThemeProvider(ToastLinkExampleRaw); +export { ToastLinkExample }; + +import { default as ToastPlacementExampleRaw } from './Toast.placement'; +const ToastPlacementExample = withThemeProvider(ToastPlacementExampleRaw); +export { ToastPlacementExample }; + +import { default as ToastOrderExampleRaw } from './Toast.order'; +const ToastOrderExample = withThemeProvider(ToastOrderExampleRaw); +export { ToastOrderExample }; + +import { default as ToastAnchorToButtonExampleRaw } from './Toast.anchorToButton'; +const ToastAnchorToButtonExample = withThemeProvider( + ToastAnchorToButtonExampleRaw, +); +export { ToastAnchorToButtonExample }; + +import { default as ToastHasCloseButtonExampleRaw } from './Toast.hasCloseButton'; +const ToastHasCloseButtonExample = withThemeProvider( + ToastHasCloseButtonExampleRaw, +); +export { ToastHasCloseButtonExample }; + +import { default as ToastCloseExampleRaw } from './Toast.close'; +const ToastCloseExample = withThemeProvider(ToastCloseExampleRaw); +export { ToastCloseExample }; + +import { default as ToastTypeExampleRaw } from './Toast.type'; +const ToastTypeExample = withThemeProvider(ToastTypeExampleRaw); +export { ToastTypeExample }; + +import { default as ToastCloseAllExampleRaw } from './Toast.closeAll'; +const ToastCloseAllExample = withThemeProvider(ToastCloseAllExampleRaw); +export { ToastCloseAllExample }; + // ---------------------------------------------------------------------------- import { default as ToggleSwitchMainExampleRaw } from './ToggleSwitch.main';