diff --git a/src/components/alert-dialog.stories.tsx b/src/components/alert-dialog.stories.tsx index 9742f39..70a70fa 100644 --- a/src/components/alert-dialog.stories.tsx +++ b/src/components/alert-dialog.stories.tsx @@ -11,6 +11,7 @@ import { AlertDialogTrigger, Button, } from "@hm-design/ui" +import { StateBoard, type BoardState } from "@/components/story-board" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" // Alert Dialog is a modal Radix overlay (Portal) for a decision that must be confirmed or cancelled: no Close (X), no outside @@ -68,17 +69,34 @@ export default meta type Story = StoryObj // Representative Story: the common Story page; each trigger opens the real dialog. +// Representative-page layout (Storybook presentation only): equal columns on PC (iframe width 1000px and up), fewer below that +// (200px minimum). Each specimen sits in its own single-column StateBoard (min larger than any column), so every subtitle and divider +// has the width of its column; a section with fewer specimens than columns leaves the remaining columns empty. The trigger keeps its +// own size (the wrapper div stretches, the inline-flex trigger does not). Overlays open in a portal, so this layout never affects them. +function SpecimenGrid({ states, columns = 4 }: { states: BoardState[]; columns?: 4 | 5 }) { + return ( +
+ {states.map((state) => ( + {state.children}
}]} /> + ))} + + ) +} + +// Representative Story: Overview and Variants are merged into one Variants section. export const All: Story = { name: "Alert Dialog", parameters: { layout: "fullscreen", controls: { disable: true } }, render: () => ( - - - - + }, + { id: "destructive", label: "Destructive", children: }, + ]} + /> ), diff --git a/src/components/context-menu.stories.tsx b/src/components/context-menu.stories.tsx index 39c8b8d..7d73b46 100644 --- a/src/components/context-menu.stories.tsx +++ b/src/components/context-menu.stories.tsx @@ -83,7 +83,7 @@ export const All: Story = { render: () => ( - + diff --git a/src/components/dialog.stories.tsx b/src/components/dialog.stories.tsx index 26a2ba4..ac1e896 100644 --- a/src/components/dialog.stories.tsx +++ b/src/components/dialog.stories.tsx @@ -4,6 +4,7 @@ import { Button } from "@hm-design/ui" import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@hm-design/ui" import { Input } from "@hm-design/ui" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@hm-design/ui" +import { StateBoard, type BoardState } from "@/components/story-board" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" // Dialog is an overlay (Radix Portal), so it does not fit the StateBoard. The representative Story is a row of triggers that open @@ -161,7 +162,7 @@ function FormContent({ defaultOpen }: { defaultOpen?: boolean }) { return (
-
+ ) +} + +// Representative Story: the common Story page. Overview is merged into Variants (Basic is its first item). export const All: Story = { name: "Dialog", parameters: { layout: "fullscreen", controls: { disable: true } }, render: () => ( - - - - + -
- - - -
+ }, + { id: "long-content", label: "Long Content", children: }, + { id: "wide-content", label: "Wide Content", children: }, + { id: "body-scroll", label: "Body Scroll", children: }, + ]} + />
-
- - -
+ }, + { id: "form", label: "Form", children: }, + ]} + />
), diff --git a/src/components/drawer.stories.tsx b/src/components/drawer.stories.tsx index 16024ab..e0c32df 100644 --- a/src/components/drawer.stories.tsx +++ b/src/components/drawer.stories.tsx @@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react-vite" // Usage: preserved native label fixtures do not define a new-screen exception. Use public Label // for supported fields (docs/components/label.md §5); copy only actions requested by the screen. import { Button, Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger, Input } from "@hm-design/ui" +import { StateBoard, type BoardState } from "@/components/story-board" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" // Drawer is a modal vaul overlay (Portal). The representative Story opens the real Drawer from its triggers; drag the handle or @@ -70,7 +71,7 @@ function FormCase({ defaultOpen }: { defaultOpen?: boolean }) { return (
-
+ ) +} + +// Representative Story: Overview and Usage are merged into one Usage section (Basic, Form, Long Content). export const All: Story = { name: "Drawer", parameters: { layout: "fullscreen", controls: { disable: true } }, render: () => ( - - - -
- - -
+ }, + { id: "form", label: "Form", children: }, + { id: "long-content", label: "Long Content", children: }, + ]} + />
), diff --git a/src/components/dropdown-menu.stories.tsx b/src/components/dropdown-menu.stories.tsx index abee707..51e37d4 100644 --- a/src/components/dropdown-menu.stories.tsx +++ b/src/components/dropdown-menu.stories.tsx @@ -87,7 +87,7 @@ export const All: Story = { - + diff --git a/src/components/hover-card.stories.tsx b/src/components/hover-card.stories.tsx index 981243a..50ae7ca 100644 --- a/src/components/hover-card.stories.tsx +++ b/src/components/hover-card.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite" import { HoverCard, HoverCardContent, HoverCardTrigger } from "@hm-design/ui" +import { StateBoard, type BoardState } from "@/components/story-board" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" // Hover Card is a Radix overlay (Portal) for a richer preview than Tooltip. The representative Story shows real triggers @@ -48,17 +49,34 @@ const meta = { title: "Components/Overlay/Hover Card", component: HoverCard, par export default meta type Story = StoryObj +// Representative-page layout (Storybook presentation only): equal columns on PC (iframe width 1000px and up), fewer below that +// (200px minimum). Each specimen sits in its own single-column StateBoard (min larger than any column), so every subtitle and divider +// has the width of its column; a section with fewer specimens than columns leaves the remaining columns empty. The trigger keeps its +// own size (the wrapper div stretches, the inline-flex trigger does not). Overlays open in a portal, so this layout never affects them. +function SpecimenGrid({ states, columns = 4 }: { states: BoardState[]; columns?: 4 | 5 }) { + return ( +
+ {states.map((state) => ( + {state.children}
}]} /> + ))} + + ) +} + +// Representative Story: Overview and Usage are merged into one Variants section (Basic, Long Content). export const All: Story = { name: "Hover Card", parameters: { layout: "fullscreen", controls: { disable: true } }, render: () => ( - - - - - + + }, + { id: "long-content", label: "Long Content", children: }, + ]} + /> ), diff --git a/src/components/popover.stories.tsx b/src/components/popover.stories.tsx index d4e9a58..2184eee 100644 --- a/src/components/popover.stories.tsx +++ b/src/components/popover.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite" import { Button, Input, Popover, PopoverClose, PopoverContent, PopoverTrigger } from "@hm-design/ui" +import { StateBoard, type BoardState } from "@/components/story-board" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" // Popover is a non-modal Radix overlay (Portal). The representative Story opens the real panels from their triggers; @@ -33,7 +34,7 @@ function FormPanel() {
-
+ ) +} + +// Representative Story: Overview is merged into Variants (Basic is its first item); each align trigger sits in its own column. export const All: Story = { name: "Popover", parameters: { layout: "fullscreen", controls: { disable: true } }, render: () => ( - - - - + }, + { id: "align-start", label: "Align Start", children: }, + { id: "align-center", label: "Align Center", children: }, + { id: "align-end", label: "Align End", children: }, + ]} + /> - + }]} /> ), diff --git a/src/components/sheet.stories.tsx b/src/components/sheet.stories.tsx index eedb18b..22a3a3e 100644 --- a/src/components/sheet.stories.tsx +++ b/src/components/sheet.stories.tsx @@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react-vite" // Usage: preserved native label fixtures do not define a new-screen exception. Use public Label // for supported fields (docs/components/label.md §5); copy only actions requested by the screen. import { Button, Input, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from "@hm-design/ui" +import { StateBoard, type BoardState } from "@/components/story-board" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" // Sheet is a modal Radix overlay (Portal), so the representative Story is a row of triggers that open the real Sheet for each @@ -68,7 +69,7 @@ function FormCase({ defaultOpen }: { defaultOpen?: boolean }) { return (
-
+ ) +} + +// Representative Story: the common Story page. Overview is merged into Variants (Right is its first item). export const All: Story = { name: "Sheet", parameters: { layout: "fullscreen", controls: { disable: true } }, render: () => ( - - - - + -
- - - -
+ }, + { id: "left", label: "Left", children: }, + { id: "top", label: "Top", children: }, + { id: "bottom", label: "Bottom", children: }, + ]} + />
-
- - -
+ }, + { id: "long-content", label: "Long Content", children: }, + ]} + />
), diff --git a/src/components/tooltip.stories.tsx b/src/components/tooltip.stories.tsx index d841187..e01ed61 100644 --- a/src/components/tooltip.stories.tsx +++ b/src/components/tooltip.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite" import { Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@hm-design/ui" +import { StateBoard, type BoardState } from "@/components/story-board" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" // Tooltip is a Radix overlay (Portal) with short, non-interactive text. The representative Story shows real triggers @@ -20,20 +21,16 @@ function Basic({ defaultOpen }: { defaultOpen?: boolean }) { ) } -function Placements() { +function Placement({ side }: { side: "top" | "right" | "bottom" | "left" }) { return ( -
- {(["top", "right", "bottom", "left"] as const).map((side) => ( - - - - - {`side="${side}"`} - - ))} -
+ + + + + {`side="${side}"`} + ) } @@ -70,6 +67,21 @@ const meta = { title: "Components/Overlay/Tooltip", component: Tooltip, paramete export default meta type Story = StoryObj +// Representative-page layout (Storybook presentation only): equal columns on PC (iframe width 1000px and up), fewer below that +// (200px minimum). Each specimen sits in its own single-column StateBoard (min larger than any column), so every subtitle and divider +// has the width of its column; a section with fewer specimens than columns leaves the remaining columns empty. The trigger keeps its +// own size (the wrapper div stretches, the inline-flex trigger does not). Overlays open in a portal, so this layout never affects them. +function SpecimenGrid({ states, columns = 4 }: { states: BoardState[]; columns?: 4 | 5 }) { + return ( +
+ {states.map((state) => ( + {state.children}
}]} /> + ))} + + ) +} + +// Representative Story: Overview is merged into Variants (Basic is its first item, then the four sides): 5 columns on PC. export const All: Story = { name: "Tooltip", parameters: { layout: "fullscreen", controls: { disable: true } }, @@ -77,17 +89,26 @@ export const All: Story = { - - - - + }, + { id: "top", label: "Top", children: }, + { id: "right", label: "Right", children: }, + { id: "bottom", label: "Bottom", children: }, + { id: "left", label: "Left", children: }, + ]} + /> -
- - -
+ }, + { id: "disabled", label: "Disabled", children: }, + ]} + />