diff --git a/packages/react-components/react-toast/etc/react-toast.api.md b/packages/react-components/react-toast/etc/react-toast.api.md index 9c055682fb71dc..4b5fbce3c0cc4d 100644 --- a/packages/react-components/react-toast/etc/react-toast.api.md +++ b/packages/react-components/react-toast/etc/react-toast.api.md @@ -101,6 +101,9 @@ export type ToastId = string; // @public (undocumented) export type ToastOffset = Partial> | ToastOffsetObject; +// @public (undocumented) +export type ToastPoliteness = 'assertive' | 'polite'; + // @public (undocumented) export type ToastPosition = 'top-end' | 'top-start' | 'bottom-end' | 'bottom-start'; diff --git a/packages/react-components/react-toast/src/index.ts b/packages/react-components/react-toast/src/index.ts index b72bb14ab99da0..2e0316bd0d1239 100644 --- a/packages/react-components/react-toast/src/index.ts +++ b/packages/react-components/react-toast/src/index.ts @@ -1,5 +1,5 @@ export { useToastController } from './state'; -export type { ToastPosition, ToastId, ToastOffset } from './state'; +export type { ToastPosition, ToastId, ToastOffset, ToastPoliteness } from './state'; export { ToastTrigger } from './ToastTrigger'; export type { ToastTriggerChildProps, ToastTriggerProps, ToastTriggerState } from './ToastTrigger'; diff --git a/packages/react-components/react-toast/src/state/types.ts b/packages/react-components/react-toast/src/state/types.ts index 7e4f6867661813..676d35e2c49202 100644 --- a/packages/react-components/react-toast/src/state/types.ts +++ b/packages/react-components/react-toast/src/state/types.ts @@ -5,17 +5,51 @@ export type ToastId = string; export type ToasterId = string; export type ToastPosition = 'top-end' | 'top-start' | 'bottom-end' | 'bottom-start'; +export type ToastPoliteness = 'assertive' | 'polite'; export interface ToastOptions { + /** + * Uniquely identifies a toast, used for update and dismiss operations + */ toastId: ToastId; + /** + * The position the toast should render to + */ position: ToastPosition; + /** + * Toast content + */ content: unknown; + /** + * Auto dismiss timeout in milliseconds + * @default 3000 + */ timeout: number; + /** + * Toast timeout pauses while focus is on another window + * @default false + */ pauseOnWindowBlur: boolean; + /** + * Toast timeout pauses while user cursor is on the toast + * @default false + */ pauseOnHover: boolean; + /** + * Toast belongs to a specific toaster + */ toasterId: ToasterId | undefined; + /** + * Higher priority toasts will be rendered before lower priority toasts + */ priority: number; - politeness: 'assertive' | 'polite'; + /** + * Used to determine [aria-live](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions) narration + */ + politeness: ToastPoliteness; + /** + * Additional data that needs to be passed to the toast + */ data: TData; } @@ -34,9 +68,21 @@ export interface ToasterOptions } export interface Toast extends ToastOptions { + /** + * Determines the visiblity of a toast + */ close: () => void; + /** + * Removes a toast completely + */ remove: () => void; + /** + * A number used to track updates immutably + */ updateId: number; + /** + * Used to determine default priority when the user does not set one + */ dispatchedAt: number; } diff --git a/packages/react-components/react-toast/src/state/useToastController.ts b/packages/react-components/react-toast/src/state/useToastController.ts index f290ea7cc26826..5bb4d68cd24311 100644 --- a/packages/react-components/react-toast/src/state/useToastController.ts +++ b/packages/react-components/react-toast/src/state/useToastController.ts @@ -10,6 +10,10 @@ import { DispatchToastOptions, ToastId, ToasterId, UpdateToastOptions } from './ const noop = () => undefined; +/** + * @param toasterId - If an id is provided all imperative methods control that specific toaster + * @returns Imperative methods to control toasts + */ export function useToastController(toasterId?: ToasterId) { const { targetDocument } = useFluent(); diff --git a/packages/react-components/react-toast/src/state/vanilla/toaster.ts b/packages/react-components/react-toast/src/state/vanilla/toaster.ts index 8b672247188d63..184ef5989c8519 100644 --- a/packages/react-components/react-toast/src/state/vanilla/toaster.ts +++ b/packages/react-components/react-toast/src/state/vanilla/toaster.ts @@ -160,7 +160,7 @@ export class Toaster { const remove = () => { this.toasts.delete(toastId); - if (this.queue.peek()) { + if (this.visibleToasts.size < this.limit && this.queue.peek()) { const nextToast = this.queue.dequeue(); this.toasts.set(nextToast.toastId, nextToast); this.visibleToasts.add(nextToast.toastId); diff --git a/packages/react-components/react-toast/stories/Toast/CustomAnnounce.stories.tsx b/packages/react-components/react-toast/stories/Toast/CustomAnnounce.stories.tsx index f9e93cf785f8cc..47c052d69953f2 100644 --- a/packages/react-components/react-toast/stories/Toast/CustomAnnounce.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/CustomAnnounce.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { Toaster, useToastController, Toast, ToastTitle, ToasterProps } from '@fluentui/react-toast'; -import { useId, Link, makeStyles, shorthands } from '@fluentui/react-components'; +import { Toaster, useToastController, Toast, ToastTitle, ToasterProps, ToastPoliteness } from '@fluentui/react-toast'; +import { useId, makeStyles, shorthands, Button, Field, RadioGroup, Radio } from '@fluentui/react-components'; const useStyles = makeStyles({ visuallyHidden: { @@ -20,26 +20,17 @@ export const CustomAnnounce = () => { const styles = useStyles(); const [alert, setAlert] = React.useState(''); const [status, setStatus] = React.useState(''); + const [politeness, setPoliteness] = React.useState('polite'); const toasterId = useId('toaster'); const { dispatchToast } = useToastController(toasterId); - const dispatchAlert = () => + const notify = () => dispatchToast( - Undo}> - Assertive toast {counter++} + + {politeness === 'polite' ? 'Polite' : 'Assertive'} toast {counter++} , - { politeness: 'assertive' }, - ); - - const dispatchStatus = () => - dispatchToast( - - Undo}> - Polite toast {counter++} - - , - { politeness: 'polite' }, + { politeness }, ); const announce: ToasterProps['announce'] = (msg, options) => { @@ -54,9 +45,27 @@ export const CustomAnnounce = () => {
{alert}
+ + setPoliteness(data.value as ToastPoliteness)}> + + + + +
- - + ); }; + +CustomAnnounce.parameters = { + docs: { + description: { + story: [ + 'The `Toaster` manages an [aria-live region](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions)', + "internally so that toasts are announced to screen readers on render. It's possible to opt-out of this default", + 'behaviour by providing a custom `announce` callback.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/CustomTimeout.stories.tsx b/packages/react-components/react-toast/stories/Toast/CustomTimeout.stories.tsx index 9504287e88e721..fa289fe118ee6c 100644 --- a/packages/react-components/react-toast/stories/Toast/CustomTimeout.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/CustomTimeout.stories.tsx @@ -1,22 +1,59 @@ import * as React from 'react'; -import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { Toaster, useToastController, ToastTitle, Toast, ToastTrigger } from '@fluentui/react-toast'; +import { useId, Button, Link, SpinButton, Field } from '@fluentui/react-components'; export const CustomTimeout = () => { + const [timeout, setDismissTimeout] = React.useState(1000); const toasterId = useId('toaster'); const { dispatchToast } = useToastController(toasterId); const notify = () => dispatchToast( - Custom timeout 1000ms + + Dismiss + + } + intent="info" + > + {timeout >= 0 ? `Custom timeout ${timeout}ms` : `Dismiss manually`} + , - { timeout: 1000 }, + { timeout }, ); return ( <> + + { + if (data.value) { + setDismissTimeout(data.value); + } else if (data.displayValue !== undefined) { + const newValue = parseFloat(data.displayValue); + if (!Number.isNaN(newValue)) { + setDismissTimeout(newValue); + } + } + }} + /> + +
- + ); }; + +CustomTimeout.parameters = { + docs: { + description: { + story: [ + 'The timeout of toasts can be customized in milliseconds. Using a negative timeout value results in the toast', + 'never being auto-dismissed.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/Default.stories.tsx b/packages/react-components/react-toast/stories/Toast/Default.stories.tsx index 7f7ecf3cd34018..8b9f29825af982 100644 --- a/packages/react-components/react-toast/stories/Toast/Default.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/Default.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Toaster, useToastController, Toast, ToastTitle, ToastBody, ToastFooter } from '@fluentui/react-toast'; -import { useId, Link } from '@fluentui/react-components'; +import { useId, Link, Button } from '@fluentui/react-components'; export const Default = () => { const toasterId = useId('toaster'); @@ -22,7 +22,7 @@ export const Default = () => { return ( <> - + ); }; diff --git a/packages/react-components/react-toast/stories/Toast/DefaultToastOptions.stories.tsx b/packages/react-components/react-toast/stories/Toast/DefaultToastOptions.stories.tsx index 62584c9bb68366..32d10ea99273b9 100644 --- a/packages/react-components/react-toast/stories/Toast/DefaultToastOptions.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/DefaultToastOptions.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button } from '@fluentui/react-components'; export const DefaultToastOptions = () => { const toasterId = useId('toaster'); @@ -15,7 +15,18 @@ export const DefaultToastOptions = () => { return ( <> - + ); }; + +DefaultToastOptions.parameters = { + docs: { + description: { + story: [ + 'Default options for all toasts can be configured on the `Toaster`.', + 'These options are only defaults and can be overriden using `dispatchToast', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/DismissAll.stories.tsx b/packages/react-components/react-toast/stories/Toast/DismissAll.stories.tsx index af71e386da1fc7..a11e8f9fdf3dfc 100644 --- a/packages/react-components/react-toast/stories/Toast/DismissAll.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/DismissAll.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button } from '@fluentui/react-components'; export const DismissAll = () => { const toasterId = useId('toaster'); @@ -16,8 +16,16 @@ export const DismissAll = () => { return ( <> - - + + ); }; + +DismissAll.parameters = { + docs: { + description: { + story: ['The `dismissAllToasts imperative API will dismiss all rendered Toasts.'].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/DismissToast.stories.tsx b/packages/react-components/react-toast/stories/Toast/DismissToast.stories.tsx index 24185f579b2519..b408cda15374ff 100644 --- a/packages/react-components/react-toast/stories/Toast/DismissToast.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/DismissToast.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button } from '@fluentui/react-components'; export const DismissToast = () => { const toasterId = useId('toaster'); @@ -18,8 +18,21 @@ export const DismissToast = () => { return ( <> - - + + ); }; + +DismissToast.parameters = { + docs: { + description: { + story: [ + 'Toasts can be dismissed imperatively using the `dismissToast` API. In order to imperatively dismiss a ', + "Toast, it's necessary to dispatch it with a user provided id. You can use the id to dismiss the toast.", + "**Don't** use this API to dismiss toats when clicking on an action inside the toast, use the `ToastTrigger`", + 'instead.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/DismissToastWithAction.stories.tsx b/packages/react-components/react-toast/stories/Toast/DismissToastWithAction.stories.tsx index 7b1f5c773d2575..83c3cc75791eb8 100644 --- a/packages/react-components/react-toast/stories/Toast/DismissToastWithAction.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/DismissToastWithAction.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, ToastTrigger, Toast } from '@fluentui/react-toast'; -import { useId, Link } from '@fluentui/react-components'; +import { useId, Link, Button } from '@fluentui/react-components'; export const DismissToastWithAction = () => { const toasterId = useId('toaster'); @@ -25,7 +25,18 @@ export const DismissToastWithAction = () => { return ( <> - + ); }; + +DismissToastWithAction.parameters = { + docs: { + description: { + story: [ + "By wrapping a button or link with a `ToastTrigger`, it's possible to make that actionable", + 'element dismiss the toast with a click.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/MultipleToasters.stories.tsx b/packages/react-components/react-toast/stories/Toast/MultipleToasters.stories.tsx index 921cc2b7d2f4af..7ab0f0b7ff73d2 100644 --- a/packages/react-components/react-toast/stories/Toast/MultipleToasters.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/MultipleToasters.stories.tsx @@ -1,31 +1,52 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button, Field, RadioGroup, Radio } from '@fluentui/react-components'; -export const MultipeToasters = () => { +export const MultipleToasters = () => { const first = useId('toaster-1'); const second = useId('toaster-2'); + const [toaster, setToaster] = React.useState(first); const { dispatchToast: dispatchFirstToast } = useToastController(first); const { dispatchToast: dispatchSecondToast } = useToastController(second); - const notifyFirst = () => - dispatchFirstToast( - - First toaster - , - ); - const notifySecond = () => - dispatchSecondToast( - - Second toaster - , - ); + const notify = () => { + if (toaster === first) { + dispatchFirstToast( + + First toaster + , + ); + } else { + dispatchSecondToast( + + Second toaster + , + ); + } + }; return ( <> + + setToaster(data.value)}> + + + + - - + ); }; + +MultipleToasters.parameters = { + docs: { + description: { + story: [ + '> ⚠️ This use case is **not recommended**', + '', + 'Toasters support a `toasterId` prop to support multiple Toasters in an app.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/Offset.stories.tsx b/packages/react-components/react-toast/stories/Toast/Offset.stories.tsx index d7bded2be7e0e6..9d151fe74ac8bf 100644 --- a/packages/react-components/react-toast/stories/Toast/Offset.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/Offset.stories.tsx @@ -1,11 +1,40 @@ import * as React from 'react'; import { ToastPosition, Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button, Field, SpinButton, RadioGroup, Radio, makeStyles } from '@fluentui/react-components'; + +const useStyles = makeStyles({ + playground: { + display: 'grid', + gridTemplateColumns: '25% 75%', + columnGap: '20px', + rowGap: '20px', + }, + + horizontal: { + gridColumnEnd: 2, + }, + + vertical: { + gridRowStart: 2, + gridColumnEnd: 2, + }, + + positions: { + gridRowStart: 1, + gridRowEnd: 3, + gridColumnStart: 2, + }, +}); export const Offset = () => { + const styles = useStyles(); const toasterId = useId('toaster'); const { dispatchToast } = useToastController(toasterId); - const notify = (position: ToastPosition) => + const [horizontal, setHorizontal] = React.useState(10); + const [vertical, setVertical] = React.useState(10); + const [position, setPosition] = React.useState('bottom-end'); + + const notify = () => dispatchToast( @@ -14,24 +43,64 @@ export const Offset = () => { , { position }, ); - const [horizontal, setHorizontal] = React.useState(10); - const [vertical, setVertical] = React.useState(10); return ( <> - - - - - -
- - setHorizontal(Number(e.target.value))} /> -
-
- - setVertical(Number(e.target.value))} /> +
+ + { + if (data.value) { + setHorizontal(data.value); + } else if (data.displayValue !== undefined) { + const newValue = parseFloat(data.displayValue); + if (!Number.isNaN(newValue)) { + setHorizontal(newValue); + } + } + }} + /> + + + { + if (data.value) { + setVertical(data.value); + } else if (data.displayValue !== undefined) { + const newValue = parseFloat(data.displayValue); + if (!Number.isNaN(newValue)) { + setVertical(newValue); + } + } + }} + /> + + + setPosition(data.value as ToastPosition)}> + + + + + +
+
+ + ); }; + +Offset.parameters = { + docs: { + description: { + story: [ + 'You can declare a static offset for toasts relative to the viewport. This offset can only be set on the', + "`Toaster` component, because it wouldn't make sense to have separate toast offsets for a toasts in a", + 'single position.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/PauseOnHover.stories.tsx b/packages/react-components/react-toast/stories/Toast/PauseOnHover.stories.tsx index d56a06b87e6071..f0e3b09ab57fe1 100644 --- a/packages/react-components/react-toast/stories/Toast/PauseOnHover.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/PauseOnHover.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button } from '@fluentui/react-components'; export const PauseOnHover = () => { const toasterId = useId('toaster'); @@ -16,7 +16,18 @@ export const PauseOnHover = () => { return ( <> - + ); }; + +PauseOnHover.parameters = { + docs: { + description: { + story: [ + 'The `pauseOnHover` option will enable users to pause the timeout of a toast while the mouse cursor', + 'is inside the toast. This option can also be set on the Toaster as a default.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/PauseOnWindowBlur.stories.tsx b/packages/react-components/react-toast/stories/Toast/PauseOnWindowBlur.stories.tsx index 6ddfd6a3dff7a3..448ab308dec9cc 100644 --- a/packages/react-components/react-toast/stories/Toast/PauseOnWindowBlur.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/PauseOnWindowBlur.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button } from '@fluentui/react-components'; export const PauseOnWindowBlur = () => { const toasterId = useId('toaster'); @@ -16,7 +16,18 @@ export const PauseOnWindowBlur = () => { return ( <> - + ); }; + +PauseOnWindowBlur.parameters = { + docs: { + description: { + story: [ + 'Use `pauseOnWindowBlur` option to pause the dismiss timeout of a Toast when the user moves focus', + 'to another window. This option can also be set on the Toaster as a default.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/ToastDescription.md b/packages/react-components/react-toast/stories/Toast/ToastDescription.md new file mode 100644 index 00000000000000..d8ca87dc8a90c4 --- /dev/null +++ b/packages/react-components/react-toast/stories/Toast/ToastDescription.md @@ -0,0 +1,42 @@ + + +> **⚠️ Preview components are considered unstable:** +> +> ```jsx +> +> import { Toast } from '@fluentui/react-components/unstable'; +> +> ``` +> +> - Features and APIs may change before final release +> - Please contact us if you intend to use this in your product + +A Toasts displays temporary content to the user. Toasts are rendered as a separate surface that can be dismissed by +user action or a application timeout. Toasts are typically used in the following situations: + +- Update the user on the status of a task +- Display the progress of a task +- Notify the user to take an action +- Notify the user of an application update +- Warn the user of an error + +The Fluent UI Toast component uses an **imperative** API. Once a Toaster has been rendered, you can use the +`useToastController` hook to get access to imperative methods to dispatch a Toast. The Toast component itself +is simply a layout component. + +## Best practices + +### Do + +- Configure defaults on the Toaster +- Use the toast for non-critical messages +- Let the user view the toast content in the application after the toast dismissed +- Create a keyboard shortcut to move focus to actionable toasts +- Use `politeness` setting to differentiate urgent and non-urgent messages + +### Don't + +- Render too many toasts at once +- Use different positions for toasts +- Use more than one Toaster in an application +- Make every toast have `assertive` politeness diff --git a/packages/react-components/react-toast/stories/Toast/ToastPositions.stories.tsx b/packages/react-components/react-toast/stories/Toast/ToastPositions.stories.tsx index 7f4d6d06c791af..b3272836d5ca04 100644 --- a/packages/react-components/react-toast/stories/Toast/ToastPositions.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/ToastPositions.stories.tsx @@ -1,11 +1,12 @@ import * as React from 'react'; import { Toaster, useToastController, ToastPosition, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button, Field, RadioGroup, Radio } from '@fluentui/react-components'; export const ToastPositions = () => { const toasterId = useId('toaster'); const { dispatchToast } = useToastController(toasterId); - const notify = (position: ToastPosition) => + const [position, setPosition] = React.useState('bottom-end'); + const notify = () => dispatchToast( This toast is {position} @@ -15,11 +16,28 @@ export const ToastPositions = () => { return ( <> + + setPosition(data.value as ToastPosition)}> + + + + + + - - - - + ); }; + +ToastPositions.parameters = { + docs: { + description: { + story: [ + 'Toasts can be dispatched to all four corners of a page. We do not recommend to use more than one', + 'position for toasts in an application because that could be disorienting for users. Pick', + 'one desired position and configure it in the `Toaster`.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/ToasterLimit.stories.tsx b/packages/react-components/react-toast/stories/Toast/ToasterLimit.stories.tsx index 0c20ea998408b7..c8938752966a1c 100644 --- a/packages/react-components/react-toast/stories/Toast/ToasterLimit.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/ToasterLimit.stories.tsx @@ -1,10 +1,11 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button, Field, SpinButton } from '@fluentui/react-components'; export const ToasterLimit = () => { const toasterId = useId('toaster'); const { dispatchToast } = useToastController(toasterId); + const [limit, setLimit] = React.useState(3); const notify = () => dispatchToast( @@ -14,8 +15,35 @@ export const ToasterLimit = () => { return ( <> - - + + { + if (data.value) { + setLimit(data.value); + } else if (data.displayValue !== undefined) { + const newValue = parseFloat(data.displayValue); + if (!Number.isNaN(newValue)) { + setLimit(newValue); + } + } + }} + /> + +
+ + ); }; + +ToasterLimit.parameters = { + docs: { + description: { + story: [ + 'Use the `limit` prop on the `Toaster` to define the maximum number of toasts that can be rendered', + 'at any one time. Any extra toasts will be queued and rendered when a toast has been dismissed.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/UpdateToast.stories.tsx b/packages/react-components/react-toast/stories/Toast/UpdateToast.stories.tsx index 9bd15047953b16..cc1ca025be73aa 100644 --- a/packages/react-components/react-toast/stories/Toast/UpdateToast.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/UpdateToast.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Toaster, useToastController, ToastTitle, Toast } from '@fluentui/react-toast'; -import { useId } from '@fluentui/react-components'; +import { useId, Button } from '@fluentui/react-components'; export const UpdateToast = () => { const toastId = useId('toast'); @@ -39,7 +39,18 @@ export const UpdateToast = () => { return ( <> - + ); }; + +UpdateToast.parameters = { + docs: { + description: { + story: [ + 'Use the `updateToast` imperative API to make changes to a Toast that is already visible. To do this', + 'you **must** provide an id when dispatching the toast. Almost all options of a Toast can be updated.', + ].join('\n'), + }, + }, +}; diff --git a/packages/react-components/react-toast/stories/Toast/index.stories.tsx b/packages/react-components/react-toast/stories/Toast/index.stories.tsx index b384afafdea0f8..b2459ee2fcce8e 100644 --- a/packages/react-components/react-toast/stories/Toast/index.stories.tsx +++ b/packages/react-components/react-toast/stories/Toast/index.stories.tsx @@ -1,3 +1,4 @@ +import { Toast, ToastTitle, ToastBody, ToastFooter, Toaster } from '@fluentui/react-toast'; export { Default } from './Default.stories'; export { DefaultToastOptions } from './DefaultToastOptions.stories'; export { CustomTimeout } from './CustomTimeout.stories'; @@ -9,10 +10,26 @@ export { DismissAll } from './DismissAll.stories'; export { PauseOnWindowBlur } from './PauseOnWindowBlur.stories'; export { PauseOnHover } from './PauseOnHover.stories'; export { UpdateToast } from './UpdateToast.stories'; -export { MultipeToasters } from './MultipleToasters.stories'; +export { MultipleToasters } from './MultipleToasters.stories'; export { ToasterLimit } from './ToasterLimit.stories'; export { CustomAnnounce } from './CustomAnnounce.stories'; +import descriptionMd from './ToastDescription.md'; + export default { title: 'Preview Components/Toast', + component: Toast, + subcomponents: { + ToastTitle, + ToastBody, + ToastFooter, + Toaster, + }, + parameters: { + docs: { + description: { + component: [descriptionMd].join('\n'), + }, + }, + }, };