Drop page / section descriptions, state notes and repeated captions from the representative Stories of 44 components, the Patterns, Center Graphic and OrgChart pages. Value readouts, spec lists and captions hide only on the representative page; hidden verification Stories keep them. Tabs Default API and the Filter Bar draft / applied counts move to the hidden DefaultApi and DraftApplied Stories; Center Overview is hidden with its direct URL kept. Story IDs are unchanged. Align the component, pattern and OrgChart docs with the pages, point the quality reference check at the DraftApplied Story, and make the P8 styles check expect no section header on the preview-only Expanded page.
84 lines
3.7 KiB
TypeScript
84 lines
3.7 KiB
TypeScript
import { useState, type ReactNode } from "react"
|
|
import type { Meta, StoryObj } from "@storybook/react-vite"
|
|
import type { DateRange } from "react-day-picker"
|
|
import { Calendar } from "@hm-design/ui"
|
|
import { StateBoard } from "@/components/story-board"
|
|
import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
|
|
|
|
// The representative "Calendar" Story shows each mode with real, clickable calendars; the same specimens also exist as Stories
|
|
// tagged `verification` (hidden from the sidebar). `today` is pinned to 2026-10-02 so the Story looks the same on any day; this
|
|
// uses react-day-picker's own `today` prop, not an HM state. Korean is the Calendar default locale.
|
|
|
|
const today = new Date(2026, 9, 2)
|
|
const month = new Date(2026, 9, 1)
|
|
|
|
const box = (node: ReactNode) => <div className="rounded-md border bg-card w-fit">{node}</div>
|
|
|
|
// `showValue={false}` hides the value readout on the representative page; the verification Stories keep it.
|
|
function Single({ showValue = true }: { showValue?: boolean }) {
|
|
const [date, setDate] = useState<Date | undefined>(new Date(2026, 9, 15))
|
|
return (
|
|
<div className="grid gap-2">
|
|
{box(<Calendar mode="single" selected={date} onSelect={setDate} defaultMonth={month} today={today} />)}
|
|
{showValue ? <span className="text-sm text-muted-foreground" data-testid="single">{`선택: ${date ? date.toLocaleDateString("ko-KR") : "없음"}`}</span> : null}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function DisabledDates() {
|
|
const [date, setDate] = useState<Date | undefined>()
|
|
return box(
|
|
<Calendar
|
|
mode="single"
|
|
selected={date}
|
|
onSelect={setDate}
|
|
defaultMonth={month}
|
|
today={today}
|
|
disabled={[{ before: new Date(2026, 9, 5) }, { dayOfWeek: [0] }]}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function Range() {
|
|
const [range, setRange] = useState<DateRange | undefined>({ from: new Date(2026, 9, 8), to: new Date(2026, 9, 14) })
|
|
return box(<Calendar mode="range" selected={range} onSelect={setRange} defaultMonth={month} today={today} />)
|
|
}
|
|
|
|
function TwoMonths() {
|
|
return box(<Calendar mode="single" numberOfMonths={2} defaultMonth={month} today={today} />)
|
|
}
|
|
|
|
const sections = [
|
|
{ id: "single", label: "Single", node: <Single showValue={false} /> },
|
|
{ id: "disabled", label: "Disabled dates", node: <DisabledDates /> },
|
|
{ id: "range", label: "Range", node: <Range /> },
|
|
{ id: "months", label: "Two months", node: <TwoMonths /> },
|
|
]
|
|
|
|
// No `component`: Calendar props are a union of selection modes, so Stories without args would not type-check.
|
|
const meta = { title: "Components/Search & Date/Calendar", parameters: { layout: "padded" } } satisfies Meta
|
|
export default meta
|
|
type Story = StoryObj<typeof meta>
|
|
|
|
const board = (...ids: string[]) => (
|
|
<StateBoard min={300} states={sections.filter((s) => ids.includes(s.id)).map((s) => ({ id: s.id, label: s.label, wide: s.id === "months", children: s.node }))} />
|
|
)
|
|
|
|
// Representative Story: the common Story page; the sections group the same specimens.
|
|
export const All: Story = {
|
|
name: "Calendar",
|
|
parameters: { layout: "fullscreen", controls: { disable: true } },
|
|
render: () => (
|
|
<StoryPage>
|
|
<StoryPageHeader title="Calendar" />
|
|
<StorySection title="Overview">{board("single")}</StorySection>
|
|
<StorySection title="Variants">{board("range", "months")}</StorySection>
|
|
<StorySection title="States">{board("disabled")}</StorySection>
|
|
</StoryPage>
|
|
),
|
|
}
|
|
|
|
export const SingleSelection: Story = { tags: ["verification"], name: "Single", render: () => <Single /> }
|
|
export const DisabledSelection: Story = { tags: ["verification"], name: "Disabled Dates", render: () => <DisabledDates /> }
|
|
export const RangeSelection: Story = { tags: ["verification"], name: "Range", render: () => <Range /> }
|