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.
95 lines
4.1 KiB
TypeScript
95 lines
4.1 KiB
TypeScript
import { useState, type ReactNode } from "react"
|
|
import type { Meta, StoryObj } from "@storybook/react-vite"
|
|
import { ChevronDownIcon } from "lucide-react"
|
|
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from "@hm-design/ui"
|
|
import { StateBoard } from "@/components/story-board"
|
|
import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
|
|
|
|
// The representative "Collapsible" Story shows one independent disclosure per state with real, clickable triggers. The same
|
|
// sections also exist as Stories tagged `verification` (hidden from the sidebar). Collapsible is a single disclosure: no divider
|
|
// system and no animation.
|
|
|
|
const longText = "긴 텍스트는 줄바꿈으로 전체를 표시합니다. 공백 없는 긴 문자열도 너비를 밀어내지 않고 줄바꿈합니다. ".repeat(6)
|
|
|
|
const narrow = (children: ReactNode) => <div className="w-full max-w-md">{children}</div>
|
|
|
|
function Frame({ label, defaultOpen, disabled, children }: { label: string; defaultOpen?: boolean; disabled?: boolean; children: ReactNode }) {
|
|
return narrow(
|
|
<Collapsible defaultOpen={defaultOpen} disabled={disabled}>
|
|
<CollapsibleTrigger>
|
|
{label}
|
|
<ChevronDownIcon aria-hidden />
|
|
</CollapsibleTrigger>
|
|
<CollapsibleContent>{children}</CollapsibleContent>
|
|
</Collapsible>
|
|
)
|
|
}
|
|
|
|
const ClosedSpecimen = () => <Frame label="고급 설정 보기">추가 옵션이 여기에 표시됩니다.</Frame>
|
|
const OpenSpecimen = () => (
|
|
<Frame label="고급 설정 보기" defaultOpen>
|
|
처음부터 열려 있는 영역입니다.
|
|
</Frame>
|
|
)
|
|
const DisabledSpecimen = () => (
|
|
<Frame label="비활성 영역" disabled>
|
|
열 수 없습니다.
|
|
</Frame>
|
|
)
|
|
const LongSpecimen = () => (
|
|
<Frame label="긴 콘텐츠" defaultOpen>
|
|
<p>{longText}</p>
|
|
<p className="mt-2">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</p>
|
|
</Frame>
|
|
)
|
|
|
|
// Controlled: the parent owns `open`; an HM Button is the trigger through asChild and keeps its style.
|
|
function ControlledSpecimen() {
|
|
const [open, setOpen] = useState(false)
|
|
return narrow(
|
|
<Collapsible open={open} onOpenChange={setOpen}>
|
|
<CollapsibleTrigger asChild>
|
|
<Button variant="primary" appearance="outline">
|
|
{open ? "접기" : "펼치기"}
|
|
</Button>
|
|
</CollapsibleTrigger>
|
|
<CollapsibleContent>{`controlled: open = ${String(open)}`}</CollapsibleContent>
|
|
</Collapsible>
|
|
)
|
|
}
|
|
|
|
const sections = [
|
|
{ id: "closed", label: "Closed", node: <ClosedSpecimen /> },
|
|
{ id: "open", label: "Open", node: <OpenSpecimen /> },
|
|
{ id: "disabled", label: "Disabled", node: <DisabledSpecimen /> },
|
|
{ id: "long", label: "Long Content", node: <LongSpecimen /> },
|
|
{ id: "controlled", label: "Button trigger", node: <ControlledSpecimen /> },
|
|
]
|
|
|
|
const meta = { title: "Components/Disclosure/Collapsible", component: Collapsible, parameters: { layout: "padded" } } satisfies Meta<typeof Collapsible>
|
|
export default meta
|
|
type Story = StoryObj<typeof meta>
|
|
|
|
const board = (...ids: string[]) => (
|
|
<StateBoard min={360} states={sections.filter((s) => ids.includes(s.id)).map((s) => ({ id: s.id, label: s.label, children: s.node }))} />
|
|
)
|
|
|
|
// Representative Story: the common Story page; the sections group the same specimens.
|
|
export const All: Story = {
|
|
name: "Collapsible",
|
|
parameters: { layout: "fullscreen", controls: { disable: true } },
|
|
render: () => (
|
|
<StoryPage>
|
|
<StoryPageHeader title="Collapsible" />
|
|
<StorySection title="Overview">{board("closed")}</StorySection>
|
|
<StorySection title="States">{board("open", "disabled")}</StorySection>
|
|
<StorySection title="Usage">{board("long", "controlled")}</StorySection>
|
|
</StoryPage>
|
|
),
|
|
}
|
|
|
|
export const Closed: Story = { tags: ["verification"], render: () => <ClosedSpecimen /> }
|
|
export const Open: Story = { tags: ["verification"], render: () => <OpenSpecimen /> }
|
|
export const Disabled: Story = { tags: ["verification"], render: () => <DisabledSpecimen /> }
|
|
export const LongContent: Story = { tags: ["verification"], name: "Long Content", render: () => <LongSpecimen /> }
|