Build four form primitives from Figma references with brand-aligned creative decisions: restrained press states (scale-95 instead of highlight splashes), clean iconless Switch, and consistent error states with inline warning icons. Introduce form-control semantic tokens (--color-control-*) in tokens.css so all form components share a single source for borders, checked states, focus rings, labels, and errors. Retrofit Input to use these tokens instead of direct palette references. Update CLAUDE.md and ARCHITECTURE.md with token layer documentation, token discipline rule (no palette references in components), and component tier decision criteria. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
86 lines
2.2 KiB
TypeScript
86 lines
2.2 KiB
TypeScript
import { useState } from 'react'
|
|
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
import { Switch } from './Switch'
|
|
|
|
const meta: Meta<typeof Switch> = {
|
|
title: 'UI/Switch',
|
|
component: Switch,
|
|
tags: ['autodocs'],
|
|
argTypes: {
|
|
label: { control: 'text' },
|
|
description: { control: 'text' },
|
|
checked: { control: 'boolean' },
|
|
disabled: { control: 'boolean' },
|
|
},
|
|
parameters: {
|
|
design: {
|
|
type: 'figma',
|
|
url: 'https://www.figma.com/design/mrabO6AtxN3ektGiTk0I9c/ResearchInsights?node-id=33-5337',
|
|
},
|
|
},
|
|
}
|
|
|
|
export default meta
|
|
type Story = StoryObj<typeof meta>
|
|
|
|
const ControlledSwitch = (props: React.ComponentProps<typeof Switch>) => {
|
|
const [checked, setChecked] = useState(props.checked ?? false)
|
|
return <Switch {...props} checked={checked} onChange={setChecked} />
|
|
}
|
|
|
|
export const Default: Story = {
|
|
render: () => <ControlledSwitch label="Enable notifications" />,
|
|
}
|
|
|
|
export const On: Story = {
|
|
render: () => <ControlledSwitch label="Enable notifications" checked />,
|
|
}
|
|
|
|
export const WithDescription: Story = {
|
|
render: () => (
|
|
<ControlledSwitch
|
|
label="Auto-save responses"
|
|
description="Automatically save participant responses as they are entered."
|
|
checked
|
|
/>
|
|
),
|
|
}
|
|
|
|
export const Disabled: Story = {
|
|
render: () => (
|
|
<div className="flex flex-col gap-4">
|
|
<Switch label="Disabled off" disabled />
|
|
<Switch label="Disabled on" disabled checked />
|
|
</div>
|
|
),
|
|
}
|
|
|
|
export const Standalone: Story = {
|
|
render: () => (
|
|
<div className="flex items-center gap-4">
|
|
<span className="text-body text-grey-01">Dark mode</span>
|
|
<ControlledSwitch aria-label="Toggle dark mode" />
|
|
</div>
|
|
),
|
|
}
|
|
|
|
export const AllStates: Story = {
|
|
render: () => (
|
|
<div className="flex flex-col gap-4">
|
|
<ControlledSwitch label="Off" />
|
|
<ControlledSwitch label="On" checked />
|
|
<ControlledSwitch
|
|
label="With description"
|
|
description="Additional context about this setting."
|
|
/>
|
|
<ControlledSwitch
|
|
label="On with description"
|
|
description="This feature is currently enabled."
|
|
checked
|
|
/>
|
|
<Switch label="Disabled off" disabled />
|
|
<Switch label="Disabled on" disabled checked />
|
|
</div>
|
|
),
|
|
}
|