import type { Meta, StoryObj } from '@storybook/nextjs-vite' import type { ReactNode } from 'react' import { toast, ToastHost } from '.' const buttonClassName = 'rounded-lg border border-divider-subtle bg-components-button-secondary-bg px-3 py-2 text-sm text-text-secondary shadow-xs transition-colors hover:bg-state-base-hover' const cardClassName = 'flex min-h-[220px] flex-col gap-4 rounded-2xl border border-divider-subtle bg-components-panel-bg p-6 shadow-sm shadow-shadow-shadow-3' const ExampleCard = ({ eyebrow, title, description, children, }: { eyebrow: string title: string description: string children: ReactNode }) => { return (
{eyebrow}

{title}

{description}

{children}
) } const VariantExamples = () => { const createVariantToast = (type: 'success' | 'error' | 'warning' | 'info') => { const copy = { success: { title: 'Changes saved', description: 'Your draft is available to collaborators.', }, error: { title: 'Sync failed', description: 'Check your network connection and try again.', }, warning: { title: 'Storage almost full', description: 'You have less than 10% of workspace quota remaining.', }, info: { title: 'Invitation sent', description: 'An email has been sent to the new teammate.', }, } as const toast[type](copy[type].title, { description: copy[type].description, }) } return ( ) } const StackExamples = () => { const createStack = () => { ;[ { type: 'info' as const, title: 'Generating preview', description: 'The first toast compresses behind the newest notification.', }, { type: 'warning' as const, title: 'Review required', description: 'A second toast should deepen the stack without breaking spacing.', }, { type: 'success' as const, title: 'Ready to publish', description: 'The newest toast stays frontmost while older items tuck behind it.', }, ].forEach((item) => { toast[item.type](item.title, { description: item.description, }) }) } const createBurst = () => { Array.from({ length: 5 }).forEach((_, index) => { toast[index % 2 === 0 ? 'info' : 'success'](`Background task ${index + 1}`, { description: 'Use this to inspect how the stack behaves near the host limit.', }) }) } return ( ) } const PromiseExamples = () => { const createPromiseToast = () => { const request = new Promise((resolve) => { window.setTimeout(() => resolve('The deployment is now available in production.'), 1400) }) void toast.promise(request, { loading: { type: 'info', title: 'Deploying workflow', description: 'Provisioning runtime and publishing the latest version.', }, success: result => ({ type: 'success', title: 'Deployment complete', description: result, }), error: () => ({ type: 'error', title: 'Deployment failed', description: 'The release could not be completed.', }), }) } const createRejectingPromiseToast = () => { const request = new Promise((_, reject) => { window.setTimeout(() => reject(new Error('intentional story failure')), 1200) }) void toast.promise(request, { loading: 'Validating model credentials…', success: 'Credentials verified', error: () => ({ type: 'error', title: 'Credentials rejected', description: 'The model provider returned an authentication error.', }), }) } return ( ) } const ActionExamples = () => { const createActionToast = () => { toast.warning('Project archived', { description: 'You can restore it from workspace settings for the next 30 days.', actionProps: { children: 'Undo', onClick: () => { toast.success('Project restored', { description: 'The workspace is active again.', }) }, }, }) } const createLongCopyToast = () => { toast.info('Knowledge ingestion in progress', { description: 'This longer example helps validate line wrapping, close button alignment, and action button placement when the content spans multiple rows.', actionProps: { children: 'View details', onClick: () => { toast.info('Job details opened') }, }, }) } return ( ) } const UpdateExamples = () => { const createUpdatableToast = () => { const toastId = toast.info('Import started', { description: 'Preparing assets and metadata for processing.', timeout: 0, }) window.setTimeout(() => { toast.update(toastId, { type: 'success', title: 'Import finished', description: '128 records were imported successfully.', timeout: 5000, }) }, 1400) } const clearAll = () => { toast.dismiss() } return ( ) } const ToastDocsDemo = () => { return ( <>
Base UI toast docs

Shared stacked toast examples

Each example card below triggers the same shared toast viewport in the top-right corner, so you can review stacking, state transitions, actions, and tone variants the same way the official Base UI documentation demonstrates toast behavior.

) } const meta = { title: 'Base/Feedback/UI Toast', component: ToastHost, parameters: { layout: 'fullscreen', docs: { description: { component: 'Dify toast host built on Base UI Toast. The story is organized as multiple example panels that all feed the same shared toast viewport, matching the way the Base UI documentation showcases toast behavior.', }, }, }, tags: ['autodocs'], } satisfies Meta export default meta type Story = StoryObj export const DocsPattern: Story = { render: () => , }