import type { ReactElement } from 'react'; import { useState } from 'react'; import type { Meta, StoryObj } from '@storybook/react-webpack5'; import { action } from 'storybook/actions'; import { Confetti, GiftBox, Star, Travel, Briefcase, Plane } from '@transferwise/icons'; import { lorem10, lorem20 } from '../../test-utils'; import Button from '../../button'; import Title from '../../title'; import { InfoPrompt, InfoPromptProps, InfoPromptMedia } from './InfoPrompt'; const withComponentGrid = ({ maxWidth = 'auto', gap = '1rem' } = {}) => (Story: () => ReactElement) => (
); export default { title: 'Prompts/InfoPrompt', component: InfoPrompt, tags: ['new'], decorators: [withComponentGrid()], args: { description: 'Your payment is being processed.', }, argTypes: { sentiment: { control: 'select', options: ['success', 'negative', 'neutral', 'warning', 'proposition'], }, title: { control: 'text', table: { type: { summary: 'ReactNode' }, }, }, description: { control: 'text', table: { type: { summary: 'ReactNode' }, }, }, media: { table: { type: { summary: 'InfoPromptMedia', detail: '{ asset: ReactNode }' }, }, }, action: { table: { type: { summary: 'InfoPromptAction', detail: '{ label: string; href?: string; target?: string; onClick?: () => void }', }, }, }, }, } satisfies Meta; /** * Convenience controls for previewing rich markup, * not otherwise possible via Storybook */ type PreviewStoryArgs = InfoPromptProps & { previewMedia: InfoPromptMedia | undefined; previewOnDismiss: boolean; previewAction: boolean; }; const previewArgGroup = { category: 'Storybook Preview options', type: { summary: undefined, }, }; const MEDIA_OPTIONS: Record = { undefined, star: { asset: }, confetti: { asset: }, giftbox: { asset: }, travel: { asset: }, briefcase: { asset: }, plane: { asset: }, }; const previewArgTypes = { previewMedia: { name: 'Preview with `media`', control: 'select', options: ['undefined', 'star', 'confetti', 'giftbox', 'travel', 'briefcase', 'plane'], mapping: MEDIA_OPTIONS, table: previewArgGroup, }, previewOnDismiss: { name: 'Preview with `onDismiss`', control: 'boolean', table: previewArgGroup, }, previewAction: { name: 'Preview with `action`', control: 'boolean', table: previewArgGroup, }, } as const; const getPropsForPreview = ( args: PreviewStoryArgs, ): [InfoPromptProps, Partial] => { const { previewMedia, previewOnDismiss, previewAction, ...props } = args; return [ props, { media: previewMedia, onDismiss: previewOnDismiss ? action('onDismiss') : undefined, action: previewAction ? { label: 'Learn more', onClick: action('action.onClick') } : undefined, }, ]; }; export const Playground: StoryObj = { argTypes: { sentiment: { control: 'radio', options: ['success', 'negative', 'neutral', 'warning', 'proposition'], }, ...previewArgTypes, }, args: { title: 'Payment successful', description: 'Your payment is being processed.', previewMedia: { asset: }, previewOnDismiss: true, previewAction: true, }, render: (args: PreviewStoryArgs) => { const [props, previewProps] = getPropsForPreview(args); return ; }, }; /** * InfoPrompt supports multiple sentiments to communicate different types of messages: * - `neutral` (default): General information * - `success`: Success messages * - `negative`: Error messages * - `warning`: Warning messages * - `proposition`: Promotional content (uses GiftBox icon by default) */ export const Sentiments: StoryObj = { render: (args: InfoPromptProps) => ( <> ), }; /** * InfoPrompt can include both a title and description for more detailed messaging. */ export const WithTitle: StoryObj = { render: (args: InfoPromptProps) => ( <> ), }; /** * Use the `action` prop to add a clickable link below the message. * Actions can have an `href` for navigation or an `onClick` for custom behavior. */ export const WithAction: StoryObj = { render: (args: InfoPromptProps) => ( <> ), }; /** * When `onDismiss` is provided, a close button appears allowing users to dismiss the prompt. * Note: The component itself is not automatically removed - you must handle state management. */ export const Dismissible: StoryObj = { render: function Render() { const [showPrompt, setShowPrompt] = useState(true); return ( <> {showPrompt ? ( setShowPrompt(false)} /> ) : ( )} ); }, }; /** * InfoPrompt supports various media types to enhance visual communication. * * **Default**: Each sentiment has a default status icon that appears when no media is provided. * * **Icon Overrides**: Replace default icons with custom icons to match the prompt's visual language to its content. * Success and proposition sentiments support both standard checkmark and confetti variations. */ export const MediaTypes: StoryObj = { render: (args) => ( <> Default Icon Overrides }} /> }} /> }} /> }} /> }} /> }} /> ), }; /** * While the component itself will stretch to the full available width, the text container will be * capped at `480px` to ensure optimal readability. * * [Visit wise.design](https://wise.design/components/info-prompt#writing-an-info-prompt) for guidance on writing effective prompt messages that are concise and easy to understand. */ export const ParagraphWidth: StoryObj = { parameters: { docs: { canvas: { sourceState: 'hidden', }, }, }, args: { title: lorem10, description: lorem20, sentiment: 'success', onDismiss: () => {}, }, };