import { Meta, StoryObj } from '@storybook/react-vite';
import './chat-attachment-story.css';
import { SAMPLE_IMAGE } from '../_story-helpers/sample-image';
import { ChatAttachment, ChatAttachmentProps } from './ChatAttachment';
const meta: Meta<typeof ChatAttachment> = {
tags: ['new-pattern', 'ready-for-dev'],
title: 'Component Proposals/AI Chat/Chat Attachment',
component: ChatAttachment,
parameters: {
docs: {
description: {
component:
'**New pattern:** not in PDS v2 today. One attached file or image in a chat, for the `fieldHeader` slot of `ChatInput`. File chips are a fixed width and shorten long names in the middle; hover or focus shows the full name. The remove button shows on hover and focus (always on touch). `status="error"` marks a failed attachment.',
},
},
},
argTypes: {
className: { table: { category: 'Base attributes' } },
errorMessage: { control: 'text', table: { category: 'Content' } },
fileName: { control: 'text', table: { category: 'Content' } },
fileType: {
control: 'select',
options: ['file', 'image'],
table: { category: 'Component configuration' },
},
onRemove: { table: { category: 'Events' } },
previewUrl: { control: 'text', table: { category: 'Content' } },
removeLabel: { control: 'text', table: { category: 'Content' } },
status: {
control: 'select',
options: ['default', 'error'],
table: { category: 'Component configuration' },
},
},
args: {
fileName: 'notes.md',
fileType: 'file',
onRemove: () => {},
removeLabel: 'Remove notes.md',
},
};
export default meta;
type Story = StoryObj<typeof meta>;
const LONG_NAME =
'verylong-filename-example-when-you-hover-you-see-the-full123.md';
interface StateProps {
args: ChatAttachmentProps;
label: string;
showRemove?: boolean;
}
// One state with its caption. `showRemove` holds the hover-only remove button
// open so the state can be seen without a pointer.
const State = ({ args, label, showRemove = false }: StateProps) => (
<div className='chat-attachment-story__state'>
<ChatAttachment
{...args}
className={showRemove ? 'chat-attachment-story--hover' : undefined}
onRemove={showRemove ? (args.onRemove ?? (() => {})) : undefined}
/>
<span className='chat-attachment-story__label'>{label}</span>
</div>
);
export const Default: Story = {
parameters: {
docs: {
description: {
story:
'A generic file (documents, text and other files). Hover, or tab to the chip, to see the full name and the remove button.',
},
},
},
render: (args) => (
<div className='chat-attachment-story__states'>
<State args={args} label='Default' />
<State args={args} label='Hover or focus' showRemove />
<State
args={{
...args,
errorMessage: 'Upload failed',
status: 'error',
}}
label='Error'
/>
<State
args={{
...args,
errorMessage: 'Upload failed',
status: 'error',
}}
label='Error, hover or focus'
showRemove
/>
<State
args={{ ...args, fileName: LONG_NAME }}
label='Long name'
showRemove
/>
</div>
),
};
export const Image: Story = {
args: {
fileName: 'skyline.jpg',
fileType: 'image',
previewUrl: SAMPLE_IMAGE,
removeLabel: 'Remove skyline.jpg',
},
parameters: {
docs: {
description: {
story:
'An image. It shows a thumbnail from `previewUrl`, or an image icon when there is no preview.',
},
},
},
render: (args) => (
<div className='chat-attachment-story__states'>
<State args={args} label='Default' />
<State args={args} label='Hover or focus' showRemove />
<State args={{ ...args, previewUrl: undefined }} label='No preview' />
<State
args={{ ...args, previewUrl: undefined }}
label='No preview, hover or focus'
showRemove
/>
</div>
),
};
Chat Attachment
Net-new component: one attached item for chat.
Net-new componentOpen in Storybook