import { useState, type ReactNode } from "react" import type { Meta, StoryObj } from "@storybook/react-vite" import { AlignCenterIcon, AlignLeftIcon, AlignRightIcon, BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react" import { ToggleGroup, ToggleGroupItem } from "@hm-design/ui" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" // Toggle Group is a group of pressed-state items (toolbar-style), not a content switcher (that is Tabs). The representative Story // shows single / multiple / icon-only / disabled / vertical / spaced groups with real controls; the same specimens also exist as // Stories tagged `verification` (hidden from the sidebar). Icon-only items carry an `aria-label`. // `showValue={false}` hides the selected-value readout on the representative page; the verification Stories keep it. function Single({ showValue = true }: { showValue?: boolean }) { const [value, setValue] = useState("left") return (
v && setValue(v)} aria-label="정렬"> 왼쪽 가운데 오른쪽 {showValue ? {`value = ${value}`} : null}
) } function Multiple({ showValue = true }: { showValue?: boolean }) { const [value, setValue] = useState(["bold"]) return (
{showValue ? {`value = [${value.join(", ")}]`} : null}
) } function DisabledGroup() { return ( A B ) } function DisabledItem() { return ( A B (비활성) C ) } function Vertical() { return ( ) } function Spaced() { return ( 첫째 둘째 셋째 ) } function Many() { return ( {Array.from({ length: 10 }, (_, i) => ( {`옵션 ${i + 1}`} ))} ) } function Sizes() { return ( // 3 equal columns on PC (iframe width 1000px and up): sm / default / lg; fewer columns below that (240px minimum).
{(["sm", "default", "lg"] as const).map((size) => ( 굵게 {size} ))}
) } // No `component`: ToggleGroup props are a union (single | multiple), so Stories without args would not type-check. // `internal` keeps it out of the sidebar by default; Story IDs and direct URLs stay valid. const meta = { title: "Components/Form/Toggle Group", tags: ["internal"], parameters: { layout: "padded" } } satisfies Meta export default meta type Story = StoryObj // 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 (
{nodes.map((node, i) => (
{node}
))}
) } // 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: () => ( , , , ]} /> {/* First two columns of a 3-column grid; the third stays empty. */} , ]} /> ), } export const SingleSelection: Story = { tags: ["verification"], name: "Single", render: () => } export const MultipleSelection: Story = { tags: ["verification"], name: "Multiple", render: () => } export const VerticalGroup: Story = { tags: ["verification"], name: "Vertical", render: () => } // 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: () =>
} export const ContentNodes: Story = { tags: ["verification"], render: () => ( {[]} <> <>굵게 굵게 ), }