← All proposals

Select

An extension of the PDS Select: one new prop, variant, with bare next to default.

Extends a PDS componentOpen in Storybook

proposals/Select/Select.stories.tsx97 lines · View on GitHub
import { Meta, StoryObj } from '@storybook/react-vite';

import { Select, SelectProps } from './Select';

import './select-story.css';

// Sample models: Zappy first, then other agents.
const MODELS = [
	{ label: 'Zappy', value: 'zappy' },
	{ label: 'Claude Haiku 5.5', value: 'haiku' },
	{ label: 'Claude Sonnet 5.5', value: 'sonnet' },
	{ disabled: true, label: 'Claude Opus 5.5', value: 'opus' },
];

const meta: Meta<typeof Select> = {
	tags: ['ready-for-dev'],
	title: 'Component Proposals/Select',
	component: Select,
	parameters: {
		docs: {
			description: {
				component:
					'Proposal, based on the PDS Select, with a `bare` variant: no border, fill or container, for a picker that sits inline in a toolbar (for example the model picker in a chat input). The stories show the bare variant only; `default` is the unchanged PDS Select.',
			},
		},
	},
	argTypes: {
		autoWidth: { table: { category: 'Component configuration' } },
		className: { table: { category: 'Base attributes' } },
		disabled: { table: { category: 'Base attributes' } },
		id: { table: { category: 'Base attributes' } },
		label: { control: 'text', table: { category: 'Content' } },
		options: { control: 'object', table: { category: 'Content' } },
		showLabel: { table: { category: 'Component configuration' } },
		size: {
			control: 'inline-radio',
			options: ['s', 'm'],
			table: { category: 'Component configuration' },
		},
		variant: {
			control: 'inline-radio',
			options: ['default', 'bare'],
			table: { category: 'Component configuration' },
		},
	},
	args: {
		defaultValue: 'zappy',
		id: 'select-default',
		label: 'Model',
		options: MODELS,
		size: 's',
		variant: 'bare',
	},
};

export default meta;

type Story = StoryObj<typeof meta>;

export const Bare: Story = {
	args: { id: 'select-bare' },
	parameters: {
		docs: {
			description: {
				story:
					"No border, fill or container. The label is hidden (still read by screen readers) and the trigger hugs the selected value; the list is as wide as its longest option. The value is secondary text at rest and default text on hover and while open; the focus ring is the Select's own.",
			},
		},
	},
};

const ROWS: Array<{ caption: string; props: Partial<SelectProps> }> = [
	{ caption: 'Size s', props: {} },
	{ caption: 'Size m', props: { size: 'm' } },
	{ caption: 'Disabled', props: { disabled: true } },
];

export const AllSizesAndStates: Story = {
	parameters: {
		docs: {
			description: {
				story: 'The bare variant in each size and the disabled state.',
			},
		},
	},
	render: (args) => (
		<div className='select-story__stack'>
			{ROWS.map(({ caption, props }) => (
				<div className='select-story__example' key={caption}>
					<p className='pds-copy-xs select-story__caption'>{caption}</p>
					<Select {...args} id={`select-${caption}`} {...props} />
				</div>
			))}
		</div>
	),
};