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: () => {},
},
};