import {
CodeBlock,
FlexContainer,
Tag,
} from '@pantheon-systems/pds-toolkit-react';
import { Meta, StoryObj } from '@storybook/react-vite';
import { TimelineItem } from '../Timeline/TimelineItem';
import { SlotPlaceholder } from '../_story-helpers/SlotPlaceholder';
import { ChainOfThought } from './ChainOfThought';
const meta: Meta<typeof ChainOfThought> = {
tags: ['new-pattern', 'ready-for-dev'],
title: 'Component Proposals/Chain of Thought',
component: ChainOfThought,
parameters: {
docs: {
description: {
component:
'**New pattern:** not in PDS v2 today. A collapsible record of what an agent did. The summary line is a Thinking State rendered from `label`, `isActive` and `time`; the body depends on the variant: plain steps, reasoning text, a web search, or coding tool calls. Rows are Timeline Item.',
},
},
},
argTypes: {
className: { table: { category: 'Base attributes' } },
isOpen: { control: 'boolean', table: { category: 'State' } },
expandWhenActive: {
control: 'boolean',
table: { category: 'Component configuration' },
},
iconName: {
control: 'select',
options: ['zappy', 'sparklesSolid'],
table: { category: 'Content' },
},
isActive: { control: 'boolean', table: { category: 'State' } },
label: { control: 'text', table: { category: 'Content' } },
size: {
control: 'select',
options: ['s', 'm'],
table: { category: 'Component configuration' },
},
variant: {
control: 'select',
options: ['steps', 'reasoning', 'search', 'coding'],
table: { category: 'Component configuration' },
},
},
args: {
isOpen: true,
label: 'Thought for',
showTimer: true,
size: 's',
time: '4s',
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Steps: Story = {
render: (args) => (
<ChainOfThought {...args}>
<TimelineItem label='Confirmed edit permission' status='done' />
<TimelineItem label='Read the page' secondaryText='home' status='done' />
<TimelineItem label='Reserved the page for editing' status='done' />
<TimelineItem
detail='Updated the heading, two paragraphs and two links.'
label='Applied changes'
secondaryText='5 edits'
status='done'
/>
<TimelineItem label='Saved changes' status='done' />
</ChainOfThought>
),
};
export const Working: Story = {
args: {
expandWhenActive: true,
isActive: true,
isOpen: false,
showTimer: false,
},
render: (args) => (
<ChainOfThought {...args} label='Working...'>
<TimelineItem label='Confirmed edit permission' status='done' />
<TimelineItem label='Read the page' secondaryText='home' status='done' />
<TimelineItem label='Reserved the page for editing' status='active' />
<TimelineItem label='Applied changes' status='pending' />
<TimelineItem label='Saved changes' status='pending' />
</ChainOfThought>
),
};
export const Reasoning: Story = {
args: { variant: 'reasoning' },
render: (args) => (
<ChainOfThought {...args}>
<p>
Summer demand spikes for stone-fruit flavors — peach and apricot lead.
</p>
<p>
I should check cone inventory before promoting a waffle-bowl special.
</p>
</ChainOfThought>
),
};
export const Search: Story = {
args: { variant: 'search' },
render: (args) => (
<ChainOfThought {...args} label='Searched the web'>
<TimelineItem
iconName='magnifyingGlass'
isQuiet
label='best waffle cone supplier'
/>
<TimelineItem
iconName='globe'
label='Joy Cone'
secondaryText='joycone.com'
/>
<TimelineItem
iconName='globe'
label='WebstaurantStore'
secondaryText='webstaurantstore.com'
/>
<TimelineItem
iconName='globe'
label='The Konery'
secondaryText='thekonery.com'
/>
<TimelineItem isQuiet label='+7 more' />
</ChainOfThought>
),
};
export const Coding: Story = {
args: { variant: 'coding' },
render: (args) => (
<ChainOfThought {...args} label='Ran 3 tools'>
<TimelineItem label='Read' secondaryText={<code>flavors.ts</code>} />
<TimelineItem
label='Edit'
secondaryText={
<>
<code>ChurnSchedule.tsx</code>{' '}
<span className='pds-timeline-item__added'>+74</span>{' '}
<span className='pds-timeline-item__removed'>-41</span>
</>
}
/>
<TimelineItem label='Run' secondaryText={<code>npm run freeze</code>} />
</ChainOfThought>
),
};
export const Slot: Story = {
args: { isActive: true, label: 'Zappy is investigating errors' },
parameters: {
docs: {
description: {
story:
'Each `TimelineItem` has a `children` slot under it, always visible. What goes in it is up to the screen. The first list shows the slots. The second is an example: the finished step keeps its output in `detail`, collapsed, and the active step shows its content open.',
},
},
},
render: (args) => (
<FlexContainer flexDirection='column' gap='xl'>
<ChainOfThought {...args}>
<TimelineItem label='Reading the failed build logs' status='done'>
<SlotPlaceholder label='children' style={{ minHeight: '5rem' }} />
</TimelineItem>
<TimelineItem label='Comparing composer.json' status='active'>
<SlotPlaceholder label='children' style={{ minHeight: '5rem' }} />
</TimelineItem>
</ChainOfThought>
<ChainOfThought {...args}>
<TimelineItem
detail={
<FlexContainer flexDirection='column' gap='xs'>
<CodeBlock
code={
'ERROR: Your requirements could not be resolved to an installable set of packages.\n drupal/pathauto is locked to ^1.11 and an update was not requested.'
}
hasCopyButton={false}
language='bash'
/>
<FlexContainer gap='xs'>
<Tag size='xs' tagColor='slate' tagLabel='composer.json' />
<Tag size='xs' tagColor='slate' tagLabel='composer.lock' />
</FlexContainer>
</FlexContainer>
}
label='Reading the failed build logs and error trace'
status='done'
/>
<TimelineItem
label='Comparing composer.json against the last known-good commit'
status='active'
>
<CodeBlock
code={
'- "drupal/pathauto": "^1.11"\n+ "drupal/pathauto": "^1.13"'
}
hasCopyButton={false}
language='diff'
/>
</TimelineItem>
</ChainOfThought>
</FlexContainer>
),
};
Chain of Thought
A collapsible list.
Net-new componentOpen in Storybook