style(storybook): refine form component stories

This commit is contained in:
shkim4 committed 2026-11-09 15:33:23 +09:00
1 parent e47eb040f2
commit f6b92d781a
23 files changed
+471 -182

No files matched your search

+46 -27
View File
@@ -43,21 +43,24 @@ function Multiple({ showValue = true }: { showValue?: boolean }) {
)
}
function Disabled() {
function DisabledGroup() {
return (
<div className="grid gap-3">
<ToggleGroup type="single" variant="outline" defaultValue="a" disabled aria-label="비활성 그룹">
<ToggleGroupItem value="a">A</ToggleGroupItem>
<ToggleGroupItem value="b">B</ToggleGroupItem>
</ToggleGroup>
<ToggleGroup type="single" variant="outline" defaultValue="a" aria-label="비활성 항목">
<ToggleGroupItem value="a">A</ToggleGroupItem>
<ToggleGroupItem value="b" disabled>
B (비활성)
</ToggleGroupItem>
<ToggleGroupItem value="c">C</ToggleGroupItem>
</ToggleGroup>
</div>
<ToggleGroup type="single" variant="outline" defaultValue="a" disabled aria-label="비활성 그룹">
<ToggleGroupItem value="a">A</ToggleGroupItem>
<ToggleGroupItem value="b">B</ToggleGroupItem>
</ToggleGroup>
)
}
function DisabledItem() {
return (
<ToggleGroup type="single" variant="outline" defaultValue="a" aria-label="비활성 항목">
<ToggleGroupItem value="a">A</ToggleGroupItem>
<ToggleGroupItem value="b" disabled>
B (비활성)
</ToggleGroupItem>
<ToggleGroupItem value="c">C</ToggleGroupItem>
</ToggleGroup>
)
}
@@ -99,7 +102,8 @@ function Many() {
function Sizes() {
return (
<div className="grid gap-3">
// 3 equal columns on PC (iframe width 1000px and up): sm / default / lg; fewer columns below that (240px minimum).
<div className="grid items-start justify-items-start gap-6 [grid-template-columns:repeat(auto-fill,minmax(min(100%,240px),1fr))] min-[1000px]:grid-cols-3">
{(["sm", "default", "lg"] as const).map((size) => (
<ToggleGroup key={size} type="multiple" size={size} variant="outline" aria-label={`${size} content kinds`}>
<ToggleGroupItem value="icon" aria-label={`${size} icon-only`}><BoldIcon /></ToggleGroupItem>
@@ -116,29 +120,42 @@ const meta = { title: "Components/Form/Toggle Group", parameters: { layout: "pad
export default meta
type Story = StoryObj<typeof meta>
// The representative page shows the groups without example titles: the section title names them.
const examples = (...nodes: ReactNode[]) => (
<div className="flex flex-wrap items-start gap-x-10 gap-y-6">
{nodes.map((node, i) => (
<div key={i}>{node}</div>
))}
</div>
)
// The representative page shows the groups without example titles: the section title names them. Equal columns on PC
// (iframe width 1000px and up), fewer below that (200px minimum); the groups keep their own size (they are not stretched to the
// column). Full class names are listed so Tailwind can see them.
const specimenColumns = {
3: "min-[1000px]:grid-cols-3",
4: "min-[1000px]:grid-cols-4",
} as const
function Examples({ columns, nodes }: { columns: keyof typeof specimenColumns; nodes: ReactNode[] }) {
return (
<div className={`grid items-start justify-items-start gap-6 [grid-template-columns:repeat(auto-fill,minmax(min(100%,200px),1fr))] ${specimenColumns[columns]}`}>
{nodes.map((node, i) => (
<div key={i}>{node}</div>
))}
</div>
)
}
// Representative Story: the common Story page; the sections group the same specimens.
// Overview is merged into Variants (the default group is its first item). The 10-option Usage example is the hidden `ManyOptions` Story.
export const All: Story = {
name: "Toggle Group",
parameters: { layout: "fullscreen", controls: { disable: true } },
render: () => (
<StoryPage>
<StoryPageHeader title="Toggle Group" />
<StorySection title="Overview">{examples(<Single showValue={false} />)}</StorySection>
<StorySection title="Variants">
<Examples columns={4} nodes={[<Single key="single" showValue={false} />, <Multiple key="multiple" showValue={false} />, <Vertical key="vertical" />, <Spaced key="spaced" />]} />
</StorySection>
<StorySection title="Sizes">
<Sizes />
</StorySection>
<StorySection title="Variants">{examples(<Multiple showValue={false} />, <Vertical />, <Spaced />)}</StorySection>
<StorySection title="States">{examples(<Disabled />)}</StorySection>
<StorySection title="Usage">{examples(<div className="max-w-sm"><Many /></div>)}</StorySection>
<StorySection title="States">
{/* First two columns of a 3-column grid; the third stays empty. */}
<Examples columns={3} nodes={[<DisabledGroup key="group" />, <DisabledItem key="item" />]} />
</StorySection>
</StoryPage>
),
}
@@ -146,6 +163,8 @@ export const All: Story = {
export const SingleSelection: Story = { tags: ["verification"], name: "Single", render: () => <Single /> }
export const MultipleSelection: Story = { tags: ["verification"], name: "Multiple", render: () => <Multiple /> }
export const VerticalGroup: Story = { tags: ["verification"], name: "Vertical", render: () => <Vertical /> }
// Former Usage section of the representative page (10 options that wrap), kept as its own Story.
export const ManyOptions: Story = { tags: ["verification"], name: "Many Options", render: () => <div className="max-w-sm"><Many /></div> }
export const ContentNodes: Story = {
tags: ["verification"],