import { useState } from 'react';
import { FlexContainer } from '@pantheon-systems/pds-toolkit-react';
import { Meta, StoryObj } from '@storybook/react-vite';
import { SlotPlaceholder } from '../_story-helpers/SlotPlaceholder';
import { Button } from '../Button/Button';
import { ChatMessage } from '../ChatMessage/ChatMessage';
import {
SuggestionCard,
SuggestionCardState,
SuggestionChange,
} from './SuggestionCard';
const CHANGE_ROWS = (
<>
<SuggestionChange
after='The 2026 Championship'
afterLabel='After'
before='—'
beforeLabel='Before'
label='Eyebrow'
/>
<SuggestionChange
after='Experience two weeks of elite tennis, electrifying fan moments, and championship glory. Be part of the 2026 Grand Slam Open.'
afterLabel='After'
before='—'
beforeLabel='Before'
label='Description'
/>
</>
);
const CONTENT = (
<SlotPlaceholder label='children' style={{ minHeight: '6rem' }} />
);
const ACTIONS = (
<>
<Button label='Accept' variant='primary' />
<Button label='Refine' variant='secondary' />
<Button label='Dismiss' variant='subtle' />
</>
);
const meta: Meta<typeof SuggestionCard> = {
tags: ['new-pattern'],
title: 'Proposals/Suggestion Card',
component: SuggestionCard,
parameters: {
docs: {
description: {
component:
'**New pattern:** not in PDS v2 today. An agent’s proposed changes in a conversation, with the buttons to decide. Built on `Panel`, with a title, a description, a list of before/after changes and an actions slot. It has a pending state and an accepted state.',
},
},
},
argTypes: {
actions: { table: { category: 'Content' } },
buttonSize: {
control: 'select',
options: ['xs', 's'],
table: { category: 'Component configuration' },
},
children: { table: { category: 'Content' } },
className: { table: { category: 'Base attributes' } },
description: { control: 'text', table: { category: 'Content' } },
headingLevel: {
control: 'select',
options: ['h2', 'h3', 'h4', 'h5', 'h6'],
table: { category: 'Component configuration' },
},
headingSize: {
control: 'select',
options: ['m', 'l'],
table: { category: 'Component configuration' },
},
padding: {
control: 'select',
options: ['none', 'condensed', 'standard', 'spacious'],
table: { category: 'Component configuration' },
},
state: {
control: 'select',
options: ['pending', 'accepted'],
table: { category: 'State' },
},
statusLabel: { control: 'text', table: { category: 'Content' } },
title: { control: 'text', table: { category: 'Content' } },
},
args: {
actions: ACTIONS,
buttonSize: 'xs',
children: CONTENT,
description: 'Tighten and energize the hero copy for stronger impact.',
headingLevel: 'h3',
headingSize: 'm',
padding: 'condensed',
state: 'pending',
statusLabel: 'Changes applied',
title: 'Heading',
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};
export const WithChanges: Story = {
args: { children: CHANGE_ROWS },
parameters: {
docs: {
description: {
story:
'A worked example of the content area: `SuggestionChange` rows, each a field name with its before and after values. What goes in the content area is up to the screen.',
},
},
},
};
export const Accepted: Story = {
args: { state: 'accepted' },
parameters: {
docs: {
description: {
story:
'Once the user accepts, set `state` to `accepted`. The actions are replaced by `statusLabel` (announced to screen readers), so the card in the history can’t be accepted twice. The changes stay visible. The final look of this state is still to be refined.',
},
},
},
};
export const Interactive: Story = {
parameters: {
docs: {
description: {
story:
'Accept switches the card to `accepted`. Story-only wiring: the consumer owns the state.',
},
},
},
render: (args) => {
const [state, setState] = useState<SuggestionCardState>('pending');
return (
<SuggestionCard
{...args}
actions={
<>
<Button
label='Accept'
onClick={() => setState('accepted')}
variant='primary'
/>
<Button label='Refine' variant='secondary' />
<Button label='Dismiss' variant='subtle' />
</>
}
state={state}
/>
);
},
};
export const InChat: Story = {
parameters: {
docs: {
description: {
story:
'The card as agent content inside a `ChatMessage`, after the agent’s text.',
},
},
},
render: (args) => (
<div style={{ maxWidth: '22rem' }}>
<ChatMessage label='Zappy'>
<FlexContainer flexDirection='column' gap='l'>
<p>Here are two changes to tighten the hero copy:</p>
<SuggestionCard {...args} />
</FlexContainer>
</ChatMessage>
</div>
),
};
Suggestion Card
A card for use inside an agent `ChatMessage`:
Net-new componentOpen in Storybook