Files
HMDesign/src/components/switch.stories.tsx
T
shkim4 da0e647b49 docs(storybook): simplify sidebar Story pages around the UI
Drop the category kicker from the 83 sidebar Stories (kicker is now optional;
hidden verification Stories keep it) and shorten or remove repeated, obvious
or internal page/section descriptions. Required specs, limits, virtual-data
and undecided-value notices stay. Story IDs, exports, fixtures, shared state
notes and package code are unchanged. Record: docs/reports/storybook-ui-simplification-2026-10-22.md
2026-10-22 16:13:58 +09:00

87 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useId, useState, type ReactNode } from "react"
import type { Meta, StoryObj } from "@storybook/react-vite"
import { Label, Switch } from "@hm-design/ui"
import { StateBoard } from "@/components/story-board"
import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
function Option({ label, children }: { label: string; children: (id: string) => ReactNode }) {
const id = useId()
return (
<div className="flex items-center gap-2">
{children(id)}
<Label htmlFor={id}>{label}</Label>
</div>
)
}
function Controlled() {
const [on, setOn] = useState(false)
return <Option label={`Notifications (${on ? "on" : "off"})`}>{(id) => <Switch id={id} checked={on} onCheckedChange={setOn} />}</Option>
}
const meta = {
title: "Components/Form/Switch",
component: Switch,
parameters: {
layout: "padded",
docs: {
description: {
component:
"현재 HM 규격: 트랙 36×20, 썸 16, On은 state-active, Off는 stroke 색. ui-viz에는 Switch 규격이 없어 참고만 했습니다. Radix Switch의 role=switch, 키보드, 접근성과 shadcn 기본 transition을 유지합니다.",
},
},
},
} satisfies Meta<typeof Switch>
export default meta
type Story = StoryObj<typeof meta>
export const All: Story = {
name: "Switch",
parameters: { layout: "fullscreen", controls: { disable: true } },
render: () => (
<StoryPage>
<StoryPageHeader
title="Switch"
description="트랙 36×20 · 썸 16 · On은 state-active 색"
/>
<StorySection title="Overview">
<StateBoard
min={240}
states={[
{ id: "off", label: "Off", children: <Option label="Option">{(id) => <Switch id={id} />}</Option> },
{ id: "on", label: "On", children: <Option label="Option">{(id) => <Switch id={id} defaultChecked />}</Option> },
{ id: "interactive", label: "Controlled · click toggles", children: <Controlled /> },
]}
/>
</StorySection>
<StorySection title="States">
<StateBoard
min={240}
states={[
{ id: "hover", label: "Hover", noteAfter: true, note: "Black 20% overlay. 포인터를 올려 확인합니다.", children: <Option label="Option">{(id) => <Switch id={id} />}</Option> },
{ id: "focus", label: "Focus", children: <Option label="Option">{(id) => <Switch id={id} />}</Option> },
{
id: "disabled",
label: "Disabled",
children: (
<div className="grid gap-3">
<Option label="Off">{(id) => <Switch id={id} disabled />}</Option>
<Option label="On">{(id) => <Switch id={id} disabled defaultChecked />}</Option>
</div>
),
},
]}
/>
</StorySection>
</StoryPage>
),
play: async ({ canvasElement }) => {
// preventScroll: the page opens at its header, not at the States section.
canvasElement.querySelector<HTMLButtonElement>('[data-overview-state="focus"] [role="switch"]')?.focus({ preventScroll: true })
},
}
export const Off: Story = { tags: ["verification"], render: () => <Option label="Option">{(id) => <Switch id={id} />}</Option> }
export const On: Story = { tags: ["verification"], render: () => <Option label="Option">{(id) => <Switch id={id} defaultChecked />}</Option> }
export const Disabled: Story = { tags: ["verification"], render: () => <Option label="Option">{(id) => <Switch id={id} disabled defaultChecked />}</Option> }