style(storybook): group form, selection and date picker story pages
- Button page shows Toggle; new Selection Controls page compares Checkbox, Radio Group and Switch states (specimens moved to *-examples.tsx) - Date Picker page includes Calendar; Combobox, Input and Slider layouts (Korean slider labels) tidied - Absorbed representative Stories keep their IDs as verification Stories - Component docs updated to the new representative pages
This commit is contained in:
1 parent
fe9c115cf9
commit
71d504407d
28 files changed
+1251
-621
No files matched your search
@@ -1,66 +1,11 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite"
|
||||
import { Label, RadioGroup, RadioGroupItem } from "@hm-design/ui"
|
||||
import type { CSSProperties } from "react"
|
||||
import { StateBoard, type BoardState } from "@/components/story-board"
|
||||
import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
|
||||
import { RadioGroup } from "@hm-design/ui"
|
||||
import { StoryPage, StoryPageHeader } from "@/components/story-page"
|
||||
import { Group, RadioGroupSections } from "./radio-group-examples"
|
||||
|
||||
// Current HM Radio Group. ui-viz has no Radio spec, so it was reference only.
|
||||
|
||||
// Story-only Label color. The shared Label sets `color: var(--hm-label-text)` from an unlayered theme rule, so a utility
|
||||
// like `text-foreground` loses to it; overriding the Label's own token on the element works. Option labels use the default
|
||||
// text color; a Label next to a disabled item (`peer-disabled`) keeps the secondary color. State titles are untouched.
|
||||
const optionLabel = "[--hm-label-text:var(--foreground)] peer-disabled:[--hm-label-text:var(--hm-sem-fg-secondary)]"
|
||||
|
||||
// Representative-page layout (Storybook presentation only): equal columns on PC (iframe width 1000px and up), shrinking to
|
||||
// fit below that (`min` is the narrowest column). Each specimen sits in its own single-column StateBoard (min larger than
|
||||
// any column), so StateBoard's auto-fill grid cannot leave an empty track. Full class names are listed so Tailwind sees them.
|
||||
const specimenColumns = {
|
||||
2: "min-[1000px]:grid-cols-2",
|
||||
4: "min-[1000px]:grid-cols-4",
|
||||
} as const
|
||||
|
||||
function SpecimenGrid({ states, columns, min = 220 }: { states: BoardState[]; columns: keyof typeof specimenColumns; min?: number }) {
|
||||
return (
|
||||
<div
|
||||
className={`grid items-start gap-6 [grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--sb-col-min)),1fr))] ${specimenColumns[columns]}`}
|
||||
style={{ "--sb-col-min": `${min}px` } as CSSProperties}
|
||||
>
|
||||
{states.map((state) => (
|
||||
<StateBoard key={state.id} min={10000} states={[state]} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Group({
|
||||
prefix,
|
||||
defaultValue = "a",
|
||||
disabled,
|
||||
disabledItem,
|
||||
invalid,
|
||||
orientation,
|
||||
hoverItem,
|
||||
}: {
|
||||
prefix: string
|
||||
defaultValue?: string
|
||||
disabled?: boolean
|
||||
disabledItem?: string
|
||||
invalid?: boolean
|
||||
orientation?: "horizontal" | "vertical"
|
||||
// Pins :hover on one item with the Storybook-only data-sb-hover attribute (.storybook/pseudo-states.ts).
|
||||
hoverItem?: string
|
||||
}) {
|
||||
return (
|
||||
<RadioGroup defaultValue={defaultValue} disabled={disabled} orientation={orientation} aria-label={prefix}>
|
||||
{["a", "b", "c"].map((v) => (
|
||||
<div key={v} className="flex items-center gap-2">
|
||||
<RadioGroupItem value={v} id={`${prefix}-${v}`} disabled={disabledItem === v} aria-invalid={invalid ? true : undefined} data-sb-hover={hoverItem === v ? "" : undefined} />
|
||||
<Label htmlFor={`${prefix}-${v}`} className={optionLabel}>Option {v.toUpperCase()}</Label>
|
||||
</div>
|
||||
))}
|
||||
</RadioGroup>
|
||||
)
|
||||
}
|
||||
// Current HM Radio Group. The specimens live in ./radio-group-examples and are also shown on the Selection Controls
|
||||
// representative page ("선택 컨트롤", Checkbox / Radio Group / Switch), the single sidebar item for the three. Every Story here
|
||||
// keeps its ID and direct URL but is hidden from the sidebar (tag `verification`).
|
||||
|
||||
const meta = {
|
||||
title: "Components/Form/Radio Group",
|
||||
@@ -78,38 +23,16 @@ const meta = {
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
// Former representative Story: kept for its ID and direct URL; hidden from the sidebar (tag `verification`) since the Selection
|
||||
// Controls page shows the same sections.
|
||||
export const All: Story = {
|
||||
tags: ["verification"],
|
||||
name: "Radio Group",
|
||||
parameters: { layout: "fullscreen", controls: { disable: true } },
|
||||
render: () => (
|
||||
<StoryPage>
|
||||
<StoryPageHeader title="Radio Group" />
|
||||
{/* Overview is merged into Variants: its Vertical example is the first Variants item. */}
|
||||
<StorySection title="Variants">
|
||||
<SpecimenGrid
|
||||
columns={2}
|
||||
min={320}
|
||||
states={[
|
||||
{ id: "vertical", label: "Vertical", children: <Group prefix="v" defaultValue="b" /> },
|
||||
{ id: "horizontal", label: "Horizontal", children: <Group prefix="h" orientation="horizontal" /> },
|
||||
]}
|
||||
/>
|
||||
</StorySection>
|
||||
<StorySection title="States">
|
||||
<SpecimenGrid
|
||||
columns={4}
|
||||
states={[
|
||||
{ id: "hover", label: "Hover", children: <Group prefix="hv" defaultValue="" hoverItem="a" /> },
|
||||
{ id: "focus", label: "Focus", children: <Group prefix="f" /> },
|
||||
{ id: "disabled-item", label: "Disabled · 항목", children: <Group prefix="di" disabledItem="b" /> },
|
||||
{ id: "disabled-group", label: "Disabled · 그룹", children: <Group prefix="dg" disabled /> },
|
||||
]}
|
||||
/>
|
||||
</StorySection>
|
||||
<StorySection title="Validation">
|
||||
{/* Same 4-column track as States, so the Error example keeps the width of one States column. */}
|
||||
<SpecimenGrid columns={4} states={[{ id: "error", label: "Error", children: <Group prefix="e" invalid /> }]} />
|
||||
</StorySection>
|
||||
<RadioGroupSections />
|
||||
</StoryPage>
|
||||
),
|
||||
play: async ({ canvasElement }) => {
|
||||
|
||||
Reference in new issue
Block a user