open-ds 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -2
  3. package/assets/schemes/accessible-first.json +3093 -0
  4. package/assets/schemes/brand-expressive.json +3124 -0
  5. package/assets/schemes/content-first.json +3110 -0
  6. package/assets/schemes/dense-data.json +3489 -0
  7. package/assets/schemes/grammar.json +3903 -0
  8. package/assets/schemes/multi-brand.json +4359 -0
  9. package/assets/skills/open-ds/SKILL.md +50 -0
  10. package/assets/skills/open-ds-build/SKILL.md +19 -0
  11. package/assets/skills/open-ds-change/SKILL.md +19 -0
  12. package/assets/skills/open-ds-choose/SKILL.md +18 -0
  13. package/assets/skills/open-ds-review/SKILL.md +22 -0
  14. package/assets/skills/open-ds-write/SKILL.md +13 -0
  15. package/assets/stories/accordion.stories.tsx +46 -0
  16. package/assets/stories/alert-dialog.stories.tsx +65 -0
  17. package/assets/stories/alert.stories.tsx +44 -0
  18. package/assets/stories/aspect-ratio.stories.tsx +37 -0
  19. package/assets/stories/avatar.stories.tsx +42 -0
  20. package/assets/stories/badge.stories.tsx +39 -0
  21. package/assets/stories/breadcrumb.stories.tsx +54 -0
  22. package/assets/stories/button.stories.tsx +46 -0
  23. package/assets/stories/calendar.stories.tsx +30 -0
  24. package/assets/stories/card.stories.tsx +50 -0
  25. package/assets/stories/carousel.stories.tsx +64 -0
  26. package/assets/stories/chart.stories.tsx +61 -0
  27. package/assets/stories/checkbox.stories.tsx +29 -0
  28. package/assets/stories/collapsible.stories.tsx +39 -0
  29. package/assets/stories/combobox.stories.tsx +57 -0
  30. package/assets/stories/command.stories.tsx +60 -0
  31. package/assets/stories/context-menu.stories.tsx +55 -0
  32. package/assets/stories/data-table.stories.tsx +93 -0
  33. package/assets/stories/date-picker.stories.tsx +27 -0
  34. package/assets/stories/dialog.stories.tsx +70 -0
  35. package/assets/stories/drawer.stories.tsx +62 -0
  36. package/assets/stories/dropdown-menu.stories.tsx +65 -0
  37. package/assets/stories/empty.stories.tsx +39 -0
  38. package/assets/stories/field.stories.tsx +42 -0
  39. package/assets/stories/form.stories.tsx +56 -0
  40. package/assets/stories/input-group.stories.tsx +41 -0
  41. package/assets/stories/input-otp.stories.tsx +48 -0
  42. package/assets/stories/input.stories.tsx +32 -0
  43. package/assets/stories/kbd.stories.tsx +30 -0
  44. package/assets/stories/label.stories.tsx +26 -0
  45. package/assets/stories/native-select.stories.tsx +39 -0
  46. package/assets/stories/navigation-menu.stories.tsx +41 -0
  47. package/assets/stories/pagination.stories.tsx +61 -0
  48. package/assets/stories/popover.stories.tsx +37 -0
  49. package/assets/stories/progress.stories.tsx +30 -0
  50. package/assets/stories/radio-group.stories.tsx +45 -0
  51. package/assets/stories/resizable.stories.tsx +54 -0
  52. package/assets/stories/scroll-area.stories.tsx +47 -0
  53. package/assets/stories/select.stories.tsx +57 -0
  54. package/assets/stories/separator.stories.tsx +28 -0
  55. package/assets/stories/sheet.stories.tsx +46 -0
  56. package/assets/stories/sidebar.stories.tsx +62 -0
  57. package/assets/stories/skeleton.stories.tsx +27 -0
  58. package/assets/stories/slider.stories.tsx +44 -0
  59. package/assets/stories/spinner.stories.tsx +25 -0
  60. package/assets/stories/switch.stories.tsx +29 -0
  61. package/assets/stories/table.stories.tsx +97 -0
  62. package/assets/stories/tabs.stories.tsx +55 -0
  63. package/assets/stories/textarea.stories.tsx +28 -0
  64. package/assets/stories/toast.stories.tsx +30 -0
  65. package/assets/stories/toggle-group.stories.tsx +41 -0
  66. package/assets/stories/toggle.stories.tsx +20 -0
  67. package/assets/stories/tooltip.stories.tsx +49 -0
  68. package/assets/tokens/accessible-first/content.json +32 -0
  69. package/assets/tokens/accessible-first/dark.tokens.json +581 -0
  70. package/assets/tokens/accessible-first/light.tokens.json +581 -0
  71. package/assets/tokens/accessible-first/shadcn.css +21 -0
  72. package/assets/tokens/accessible-first/theme.css +101 -0
  73. package/assets/tokens/accessible-first/tokens.css +331 -0
  74. package/assets/tokens/accessible-first/tokens.json +1616 -0
  75. package/assets/tokens/accessible-first/tokens.scoped.css +333 -0
  76. package/assets/tokens/brand-expressive/content.json +32 -0
  77. package/assets/tokens/brand-expressive/dark.tokens.json +585 -0
  78. package/assets/tokens/brand-expressive/light.tokens.json +585 -0
  79. package/assets/tokens/brand-expressive/shadcn.css +21 -0
  80. package/assets/tokens/brand-expressive/theme.css +101 -0
  81. package/assets/tokens/brand-expressive/tokens.css +331 -0
  82. package/assets/tokens/brand-expressive/tokens.json +1651 -0
  83. package/assets/tokens/brand-expressive/tokens.scoped.css +333 -0
  84. package/assets/tokens/content-first/content.json +32 -0
  85. package/assets/tokens/content-first/dark.tokens.json +582 -0
  86. package/assets/tokens/content-first/light.tokens.json +582 -0
  87. package/assets/tokens/content-first/shadcn.css +21 -0
  88. package/assets/tokens/content-first/theme.css +101 -0
  89. package/assets/tokens/content-first/tokens.css +331 -0
  90. package/assets/tokens/content-first/tokens.json +1631 -0
  91. package/assets/tokens/content-first/tokens.scoped.css +333 -0
  92. package/assets/tokens/dense-data/content.json +32 -0
  93. package/assets/tokens/dense-data/dark.tokens.json +580 -0
  94. package/assets/tokens/dense-data/light.tokens.json +580 -0
  95. package/assets/tokens/dense-data/shadcn.css +21 -0
  96. package/assets/tokens/dense-data/theme.css +101 -0
  97. package/assets/tokens/dense-data/tokens.css +331 -0
  98. package/assets/tokens/dense-data/tokens.json +1623 -0
  99. package/assets/tokens/dense-data/tokens.scoped.css +333 -0
  100. package/assets/tokens/index.json +143 -0
  101. package/assets/tokens/multi-brand/aster-dark.tokens.json +625 -0
  102. package/assets/tokens/multi-brand/aster-light.tokens.json +625 -0
  103. package/assets/tokens/multi-brand/birch-dark.tokens.json +625 -0
  104. package/assets/tokens/multi-brand/birch-light.tokens.json +625 -0
  105. package/assets/tokens/multi-brand/content.json +32 -0
  106. package/assets/tokens/multi-brand/coral-dark.tokens.json +625 -0
  107. package/assets/tokens/multi-brand/coral-light.tokens.json +625 -0
  108. package/assets/tokens/multi-brand/shadcn.css +21 -0
  109. package/assets/tokens/multi-brand/theme.css +101 -0
  110. package/assets/tokens/multi-brand/tokens.css +1002 -0
  111. package/assets/tokens/multi-brand/tokens.json +1754 -0
  112. package/assets/tokens/multi-brand/tokens.scoped.css +1022 -0
  113. package/assets/tokens/shadcn-map.json +34 -0
  114. package/assets/ui/components/accordion.tsx +60 -0
  115. package/assets/ui/components/alert-dialog.tsx +171 -0
  116. package/assets/ui/components/alert.tsx +56 -0
  117. package/assets/ui/components/aspect-ratio.tsx +17 -0
  118. package/assets/ui/components/avatar.tsx +96 -0
  119. package/assets/ui/components/badge.tsx +36 -0
  120. package/assets/ui/components/breadcrumb.tsx +99 -0
  121. package/assets/ui/components/button.tsx +53 -0
  122. package/assets/ui/components/calendar.tsx +169 -0
  123. package/assets/ui/components/card.tsx +72 -0
  124. package/assets/ui/components/carousel.tsx +224 -0
  125. package/assets/ui/components/chart.tsx +315 -0
  126. package/assets/ui/components/checkbox.tsx +29 -0
  127. package/assets/ui/components/collapsible.tsx +25 -0
  128. package/assets/ui/components/combobox.tsx +275 -0
  129. package/assets/ui/components/command.tsx +145 -0
  130. package/assets/ui/components/context-menu.tsx +218 -0
  131. package/assets/ui/components/data-table.tsx +307 -0
  132. package/assets/ui/components/date-picker.tsx +79 -0
  133. package/assets/ui/components/dialog.tsx +68 -0
  134. package/assets/ui/components/drawer.tsx +115 -0
  135. package/assets/ui/components/dropdown-menu.tsx +58 -0
  136. package/assets/ui/components/empty.tsx +92 -0
  137. package/assets/ui/components/field.tsx +234 -0
  138. package/assets/ui/components/form.tsx +146 -0
  139. package/assets/ui/components/input-group.tsx +154 -0
  140. package/assets/ui/components/input-otp.tsx +75 -0
  141. package/assets/ui/components/input.tsx +25 -0
  142. package/assets/ui/components/kbd.tsx +30 -0
  143. package/assets/ui/components/label.tsx +22 -0
  144. package/assets/ui/components/native-select.tsx +59 -0
  145. package/assets/ui/components/navigation-menu.tsx +149 -0
  146. package/assets/ui/components/pagination.tsx +108 -0
  147. package/assets/ui/components/popover.tsx +61 -0
  148. package/assets/ui/components/progress.tsx +31 -0
  149. package/assets/ui/components/radio-group.tsx +40 -0
  150. package/assets/ui/components/resizable.tsx +54 -0
  151. package/assets/ui/components/scroll-area.tsx +55 -0
  152. package/assets/ui/components/select.tsx +81 -0
  153. package/assets/ui/components/separator.tsx +35 -0
  154. package/assets/ui/components/sheet.tsx +114 -0
  155. package/assets/ui/components/sidebar.tsx +685 -0
  156. package/assets/ui/components/skeleton.tsx +15 -0
  157. package/assets/ui/components/slider.tsx +70 -0
  158. package/assets/ui/components/spinner.tsx +16 -0
  159. package/assets/ui/components/switch.tsx +32 -0
  160. package/assets/ui/components/table.tsx +78 -0
  161. package/assets/ui/components/tabs.tsx +49 -0
  162. package/assets/ui/components/textarea.tsx +25 -0
  163. package/assets/ui/components/toast.tsx +54 -0
  164. package/assets/ui/components/toggle-group.tsx +88 -0
  165. package/assets/ui/components/toggle.tsx +48 -0
  166. package/assets/ui/components/tooltip.tsx +34 -0
  167. package/assets/ui/lib/use-mobile.ts +20 -0
  168. package/assets/ui/lib/utils.ts +7 -0
  169. package/assets/ui/styles.css +27 -0
  170. package/bin/open-ds.js +6 -0
  171. package/package.json +56 -4
  172. package/src/agents.mjs +150 -0
  173. package/src/cli.mjs +445 -0
  174. package/src/components.mjs +69 -0
  175. package/src/context.mjs +143 -0
  176. package/src/create.mjs +377 -0
  177. package/src/docs.mjs +570 -0
  178. package/src/guidance.mjs +63 -0
  179. package/src/index.mjs +20 -0
  180. package/src/mcp.mjs +660 -0
  181. package/src/readmes.mjs +106 -0
  182. package/src/schemes.mjs +188 -0
  183. package/src/tokens.mjs +127 -0
  184. package/templates/project/.github/workflows/ci.yml +15 -0
  185. package/templates/project/.storybook/component-docs.mdx +26 -0
  186. package/templates/project/.storybook/main.ts +17 -0
  187. package/templates/project/.storybook/manager-head.html +3 -0
  188. package/templates/project/.storybook/manager.ts +37 -0
  189. package/templates/project/.storybook/preview-head.html +3 -0
  190. package/templates/project/.storybook/preview.tsx +82 -0
  191. package/templates/project/docs/docusaurus.config.ts +64 -0
  192. package/templates/project/docs/sidebars.ts +8 -0
  193. package/templates/project/docs/src/css/custom.css +275 -0
  194. package/templates/project/gitignore +6 -0
  195. package/templates/project/src/styles/index.css +16 -0
  196. package/templates/project/src/vite-env.d.ts +7 -0
  197. package/templates/project/stories/docs-blocks.tsx +190 -0
  198. package/templates/project/stories/samples.tsx +102 -0
  199. package/templates/project/stories/usage.tsx +31 -0
  200. package/templates/project/tokens/build.mjs +468 -0
  201. package/templates/project/tsconfig.json +15 -0
@@ -0,0 +1,64 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import {
3
+ Carousel,
4
+ CarouselContent,
5
+ CarouselItem,
6
+ CarouselPrevious,
7
+ CarouselNext,
8
+ Card,
9
+ CardContent,
10
+ } from "@open-ds/ui";
11
+ import { Show } from "../src/samples";
12
+
13
+ const meta = {
14
+ parameters: { openDs: { component: "carousel", situations: [] } },
15
+ title: "Components/Carousel",
16
+ component: Carousel,
17
+ } satisfies Meta<typeof Carousel>;
18
+ export default meta;
19
+ type Story = StoryObj<typeof meta>;
20
+
21
+ export const Playground: Story = {
22
+ render: (args) => (
23
+ <Show component="carousel">
24
+ {(s) => (
25
+ <Carousel {...args} className="mx-12 max-w-sm">
26
+ <CarouselContent>
27
+ {s.metrics.map((m) => (
28
+ <CarouselItem key={m.label}>{m.label}</CarouselItem>
29
+ ))}
30
+ </CarouselContent>
31
+ <CarouselPrevious />
32
+ <CarouselNext />
33
+ </Carousel>
34
+ )}
35
+ </Show>
36
+ ),
37
+ };
38
+
39
+ export const Examples: Story = {
40
+ render: () => (
41
+ <Show component="carousel">
42
+ {(s) => (
43
+ <Carousel className="mx-12 max-w-sm">
44
+ <CarouselContent>
45
+ {s.metrics.map((m) => (
46
+ <CarouselItem key={m.label}>
47
+ <Card>
48
+ <CardContent className="flex flex-col gap-[var(--space-gap-tight)] p-[var(--card-padding)]">
49
+ <span className="text-[var(--color-text-secondary)]">{m.label}</span>
50
+ <span className="[font-family:var(--type-display-font-family)] text-[length:var(--type-display-font-size)]">
51
+ {m.value}
52
+ </span>
53
+ </CardContent>
54
+ </Card>
55
+ </CarouselItem>
56
+ ))}
57
+ </CarouselContent>
58
+ <CarouselPrevious />
59
+ <CarouselNext />
60
+ </Carousel>
61
+ )}
62
+ </Show>
63
+ ),
64
+ };
@@ -0,0 +1,61 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@open-ds/ui";
3
+ import { Bar, BarChart, XAxis } from "recharts";
4
+ import type { Samples } from "../src/samples";
5
+ import { Show } from "../src/samples";
6
+
7
+ const meta = {
8
+ parameters: { openDs: { component: "chart", situations: ["number-in-table"] } },
9
+ title: "Components/Chart",
10
+ component: ChartContainer,
11
+ args: { config: { value: { label: "Value", color: "var(--chart-1)" } }, children: <></> },
12
+ } satisfies Meta<typeof ChartContainer>;
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Playground: Story = {
17
+ render: (args) => (
18
+ <ChartContainer {...args} className="h-48 max-w-lg">
19
+ <BarChart
20
+ data={[
21
+ { name: "A", value: 3 },
22
+ { name: "B", value: 5 },
23
+ { name: "C", value: 2 },
24
+ ]}
25
+ >
26
+ <XAxis dataKey="name" />
27
+ <Bar dataKey="value" fill="var(--color-value)" />
28
+ </BarChart>
29
+ </ChartContainer>
30
+ ),
31
+ };
32
+
33
+ export const Examples: Story = {
34
+ render: () => (
35
+ <Show component="chart">
36
+ {(s) => (
37
+ <ChartContainer config={{ value: { label: valueLabel(s), color: "var(--chart-1)" } }} className="h-56 max-w-lg">
38
+ <BarChart data={chartRows(s)}>
39
+ <XAxis dataKey="name" tickLine={false} axisLine={false} />
40
+ <ChartTooltip content={<ChartTooltipContent />} />
41
+ <Bar dataKey="value" fill="var(--color-value)" radius={2} />
42
+ </BarChart>
43
+ </ChartContainer>
44
+ )}
45
+ </Show>
46
+ ),
47
+ };
48
+
49
+ // Rows of the scheme's own figures: the table's number column when it has one, otherwise its figures.
50
+ function chartRows(s: Samples) {
51
+ const t = s.table;
52
+ const col = t ? t.columns.findIndex((c) => c.numeric) : -1;
53
+ const toNumber = (v: string) => Number.parseFloat(v.replace(/[^0-9.]/g, "")) || 0;
54
+ return t && col >= 0
55
+ ? t.rows.slice(0, 8).map((r) => ({ name: r.cells[0], value: toNumber(r.cells[col]) }))
56
+ : s.metrics.map((m) => ({ name: m.label, value: toNumber(m.value) }));
57
+ }
58
+ function valueLabel(s: Samples) {
59
+ const col = s.table?.columns.find((c) => c.numeric);
60
+ return col?.label ?? s.screen;
61
+ }
@@ -0,0 +1,29 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { Checkbox, Label } from "@open-ds/ui";
3
+ import { Show, toneOf } from "../src/samples";
4
+
5
+ const meta = {
6
+ parameters: { openDs: { component: "checkbox", situations: ["smallest-target", "keyboard-focus"] } },
7
+ title: "Components/Checkbox",
8
+ component: Checkbox,
9
+ } satisfies Meta<typeof Checkbox>;
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Playground: Story = { args: { defaultChecked: true, disabled: false } };
14
+
15
+ export const Examples: Story = {
16
+ render: () => (
17
+ <Show component="checkbox">
18
+ {(s) => (
19
+ <div className="grid gap-[var(--space-gap-default)]">
20
+ {s.checkbox!.map((label, i) => (
21
+ <Label key={label}>
22
+ <Checkbox defaultChecked={i === 0} disabled={i === 2} /> {label}
23
+ </Label>
24
+ ))}
25
+ </div>
26
+ )}
27
+ </Show>
28
+ ),
29
+ };
@@ -0,0 +1,39 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { Collapsible, CollapsibleTrigger, CollapsibleContent, Button } from "@open-ds/ui";
3
+ import { Show } from "../src/samples";
4
+
5
+ const meta = {
6
+ parameters: { openDs: { component: "collapsible", situations: [] } },
7
+ title: "Components/Collapsible",
8
+ component: Collapsible,
9
+ } satisfies Meta<typeof Collapsible>;
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Playground: Story = {
14
+ render: (args) => (
15
+ <Collapsible {...args}>
16
+ <CollapsibleTrigger asChild>
17
+ <Button variant="ghost">Show more</Button>
18
+ </CollapsibleTrigger>
19
+ <CollapsibleContent>More detail.</CollapsibleContent>
20
+ </Collapsible>
21
+ ),
22
+ };
23
+
24
+ export const Examples: Story = {
25
+ render: () => (
26
+ <Show component="collapsible">
27
+ {(s) => (
28
+ <Collapsible defaultOpen className="max-w-md">
29
+ <CollapsibleTrigger asChild>
30
+ <Button variant="ghost">{s.card?.title ?? s.screen}</Button>
31
+ </CollapsibleTrigger>
32
+ <CollapsibleContent className="px-[var(--space-inset-control-x)] text-[var(--color-text-secondary)]">
33
+ {s.card?.description ?? s.field.hint}
34
+ </CollapsibleContent>
35
+ </Collapsible>
36
+ )}
37
+ </Show>
38
+ ),
39
+ };
@@ -0,0 +1,57 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { Combobox, ComboboxInput, ComboboxContent, ComboboxEmpty, ComboboxList, ComboboxItem } from "@open-ds/ui";
3
+ import { Show } from "../src/samples";
4
+
5
+ const meta = {
6
+ parameters: { openDs: { component: "combobox", situations: ["field-label", "error-message"] } },
7
+ title: "Components/Combobox",
8
+ component: Combobox,
9
+ } satisfies Meta<typeof Combobox>;
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Playground: Story = {
14
+ render: () => (
15
+ <Show component="combobox">
16
+ {(s) => (
17
+ <Combobox items={s.table?.rows.map((r) => r.cells[0]) ?? s.metrics.map((m) => m.label)}>
18
+ <ComboboxInput placeholder={s.field.label} />
19
+ <ComboboxContent>
20
+ <ComboboxEmpty>No match.</ComboboxEmpty>
21
+ <ComboboxList>
22
+ {(item: string) => (
23
+ <ComboboxItem key={item} value={item}>
24
+ {item}
25
+ </ComboboxItem>
26
+ )}
27
+ </ComboboxList>
28
+ </ComboboxContent>
29
+ </Combobox>
30
+ )}
31
+ </Show>
32
+ ),
33
+ };
34
+
35
+ export const Examples: Story = {
36
+ render: () => (
37
+ <Show component="combobox">
38
+ {(s) => (
39
+ <div className="max-w-sm">
40
+ <Combobox items={s.table?.rows.map((r) => r.cells[0]) ?? s.metrics.map((m) => m.label)}>
41
+ <ComboboxInput placeholder={s.table?.columns[0].label ?? s.field.label} />
42
+ <ComboboxContent>
43
+ <ComboboxEmpty>No match.</ComboboxEmpty>
44
+ <ComboboxList>
45
+ {(item: string) => (
46
+ <ComboboxItem key={item} value={item}>
47
+ {item}
48
+ </ComboboxItem>
49
+ )}
50
+ </ComboboxList>
51
+ </ComboboxContent>
52
+ </Combobox>
53
+ </div>
54
+ )}
55
+ </Show>
56
+ ),
57
+ };
@@ -0,0 +1,60 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import {
3
+ Command,
4
+ CommandInput,
5
+ CommandList,
6
+ CommandEmpty,
7
+ CommandGroup,
8
+ CommandItem,
9
+ CommandShortcut,
10
+ } from "@open-ds/ui";
11
+ import { Show } from "../src/samples";
12
+
13
+ const meta = {
14
+ parameters: { openDs: { component: "command", situations: ["menu-or-dialog", "keyboard-focus"] } },
15
+ title: "Components/Command",
16
+ component: Command,
17
+ } satisfies Meta<typeof Command>;
18
+ export default meta;
19
+ type Story = StoryObj<typeof meta>;
20
+
21
+ export const Playground: Story = {
22
+ render: (args) => (
23
+ <Command
24
+ {...args}
25
+ className="max-w-md rounded-[var(--radius-container)] border border-[var(--color-border-default)]"
26
+ >
27
+ <CommandInput placeholder="Search" />
28
+ <CommandList>
29
+ <CommandEmpty>No match.</CommandEmpty>
30
+ </CommandList>
31
+ </Command>
32
+ ),
33
+ };
34
+
35
+ export const Examples: Story = {
36
+ render: () => (
37
+ <Show component="command">
38
+ {(s) => (
39
+ <Command className="max-w-md rounded-[var(--radius-container)] border border-[var(--color-border-default)]">
40
+ <CommandInput placeholder={s.icon_action ?? s.field.label} />
41
+ <CommandList>
42
+ <CommandEmpty>No match.</CommandEmpty>
43
+ <CommandGroup heading={s.screen}>
44
+ <CommandItem>
45
+ {s.actions.primary}
46
+ <CommandShortcut>Enter</CommandShortcut>
47
+ </CommandItem>
48
+ <CommandItem>{s.actions.secondary}</CommandItem>
49
+ </CommandGroup>
50
+ <CommandGroup heading={s.table?.caption ?? s.metrics[0].label}>
51
+ {(s.table?.rows.map((r) => r.cells[0]) ?? s.metrics.map((m) => m.label)).slice(0, 6).map((x) => (
52
+ <CommandItem key={x}>{x}</CommandItem>
53
+ ))}
54
+ </CommandGroup>
55
+ </CommandList>
56
+ </Command>
57
+ )}
58
+ </Show>
59
+ ),
60
+ };
@@ -0,0 +1,55 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import {
3
+ ContextMenu,
4
+ ContextMenuTrigger,
5
+ ContextMenuContent,
6
+ ContextMenuItem,
7
+ ContextMenuSeparator,
8
+ } from "@open-ds/ui";
9
+ import { Show } from "../src/samples";
10
+
11
+ const meta = {
12
+ parameters: { openDs: { component: "context-menu", situations: ["row-action", "menu-or-dialog"] } },
13
+ title: "Components/Context menu",
14
+ component: ContextMenu,
15
+ } satisfies Meta<typeof ContextMenu>;
16
+ export default meta;
17
+ type Story = StoryObj<typeof meta>;
18
+
19
+ export const Playground: Story = {
20
+ render: (args) => (
21
+ <ContextMenu {...args}>
22
+ <ContextMenuTrigger className="flex h-24 max-w-sm items-center justify-center rounded-[var(--radius-container)] border border-dashed border-[var(--color-border-strong)]">
23
+ Right-click here
24
+ </ContextMenuTrigger>
25
+ <ContextMenuContent>
26
+ <ContextMenuItem>Item</ContextMenuItem>
27
+ </ContextMenuContent>
28
+ </ContextMenu>
29
+ ),
30
+ };
31
+
32
+ export const Examples: Story = {
33
+ render: () => (
34
+ <Show component="context-menu">
35
+ {(s) => (
36
+ <ContextMenu>
37
+ <ContextMenuTrigger className="flex h-24 max-w-sm items-center justify-center rounded-[var(--radius-container)] border border-dashed border-[var(--color-border-strong)]">
38
+ {s.table?.rows[0].cells.join(" · ") ?? s.screen}
39
+ </ContextMenuTrigger>
40
+ <ContextMenuContent>
41
+ {(s.menu?.items ?? [s.actions.primary, s.actions.secondary]).map((x) => (
42
+ <ContextMenuItem key={x}>{x}</ContextMenuItem>
43
+ ))}
44
+ {s.menu && (
45
+ <>
46
+ <ContextMenuSeparator />
47
+ <ContextMenuItem variant="destructive">{s.menu.destructive}</ContextMenuItem>
48
+ </>
49
+ )}
50
+ </ContextMenuContent>
51
+ </ContextMenu>
52
+ )}
53
+ </Show>
54
+ ),
55
+ };
@@ -0,0 +1,93 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { Badge, Button, DataTable, dataTableSelectColumn } from "@open-ds/ui";
3
+ import type { ColumnDef } from "@tanstack/react-table";
4
+ import { Show, toneOf } from "../src/samples";
5
+ import type { Samples } from "../src/samples";
6
+
7
+ const meta = {
8
+ parameters: {
9
+ openDs: { component: "data-table", situations: ["number-in-table", "table-row", "selected-row", "row-action"] },
10
+ },
11
+ title: "Components/Data table",
12
+ component: DataTable,
13
+ args: { columns: [], data: [] },
14
+ } satisfies Meta<typeof DataTable>;
15
+ export default meta;
16
+ type Story = StoryObj<typeof meta>;
17
+
18
+ type Row = Record<string, string>;
19
+
20
+ // The scheme's own rows: its table columns, then the status column, all sortable; status and the
21
+ // second column are filters.
22
+ function tableOf(s: Samples) {
23
+ const t = s.table!;
24
+ const keys = t.columns.map((c) => c.label);
25
+ const data: Row[] = t.rows.map((r) => ({
26
+ ...Object.fromEntries(keys.slice(0, -1).map((k, i) => [k, r.cells[i]])),
27
+ [keys.at(-1)!]: r.status,
28
+ }));
29
+ const status = keys.at(-1)!;
30
+ const columns: ColumnDef<Row, unknown>[] = [
31
+ dataTableSelectColumn<Row>(),
32
+ ...keys.map((k, i) => ({
33
+ accessorKey: k,
34
+ header: k,
35
+ meta: { label: k, numeric: t.columns[i].numeric },
36
+ cell: ({ getValue }: { getValue: () => unknown }) =>
37
+ k === status ? <Badge tone={toneOf(s, String(getValue()))}>{String(getValue())}</Badge> : String(getValue()),
38
+ })),
39
+ ];
40
+ return {
41
+ data,
42
+ columns,
43
+ facets: [
44
+ { column: status, title: status },
45
+ { column: keys[1], title: keys[1] },
46
+ ],
47
+ };
48
+ }
49
+
50
+ export const Playground: Story = {
51
+ render: (args) => (
52
+ <Show component="data-table">
53
+ {(s) => {
54
+ const t = tableOf(s);
55
+ return <DataTable {...args} columns={t.columns} data={t.data} facets={t.facets} pageSize={5} />;
56
+ }}
57
+ </Show>
58
+ ),
59
+ };
60
+
61
+ export const Examples: Story = {
62
+ render: () => (
63
+ <Show component="data-table">
64
+ {(s) => {
65
+ const t = tableOf(s);
66
+ return (
67
+ <div className="flex flex-col gap-[var(--space-gap-default)]">
68
+ <p className="[font-weight:var(--type-heading-font-weight)]">{s.table!.caption}</p>
69
+ <DataTable
70
+ columns={t.columns}
71
+ data={t.data}
72
+ facets={t.facets}
73
+ pageSize={8}
74
+ labels={{ search: s.icon_action ?? "Search" }}
75
+ bulkActions={() => (
76
+ <>
77
+ <Button variant="secondary" size="compact">
78
+ {s.actions.secondary}
79
+ </Button>
80
+ {s.confirm && (
81
+ <Button variant="ghost" size="compact">
82
+ {s.confirm.confirm}
83
+ </Button>
84
+ )}
85
+ </>
86
+ )}
87
+ />
88
+ </div>
89
+ );
90
+ }}
91
+ </Show>
92
+ ),
93
+ };
@@ -0,0 +1,27 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { DatePicker, Label } from "@open-ds/ui";
3
+ import { Show } from "../src/samples";
4
+
5
+ const meta = {
6
+ parameters: { openDs: { component: "date-picker", situations: ["field-label", "keyboard-focus"] } },
7
+ title: "Components/Date picker",
8
+ component: DatePicker,
9
+ args: { mode: "single", placeholder: "Pick a date" },
10
+ } satisfies Meta<typeof DatePicker>;
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Playground: Story = {};
15
+
16
+ export const Examples: Story = {
17
+ render: () => (
18
+ <Show component="date-picker">
19
+ {(s) => (
20
+ <div className="grid max-w-sm gap-[var(--space-gap-tight)]">
21
+ <Label>{s.table?.caption ?? s.screen}</Label>
22
+ <DatePicker mode="range" defaultValue={{ from: new Date(2026, 9, 5), to: new Date(2026, 9, 11) }} />
23
+ </div>
24
+ )}
25
+ </Show>
26
+ ),
27
+ };
@@ -0,0 +1,70 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import {
3
+ Button,
4
+ Dialog,
5
+ DialogClose,
6
+ DialogContent,
7
+ DialogDescription,
8
+ DialogFooter,
9
+ DialogHeader,
10
+ DialogTitle,
11
+ DialogTrigger,
12
+ } from "@open-ds/ui";
13
+ import { Show, toneOf } from "../src/samples";
14
+
15
+ const meta = {
16
+ parameters: { openDs: { component: "dialog", situations: ["destructive-action", "menu-or-dialog"] } },
17
+ title: "Components/Dialog",
18
+ component: Dialog,
19
+ } satisfies Meta<typeof Dialog>;
20
+ export default meta;
21
+ type Story = StoryObj<typeof meta>;
22
+
23
+ export const Playground: Story = {
24
+ args: { modal: true },
25
+ render: (args) => (
26
+ <Show component="dialog">
27
+ {(s) => (
28
+ <Dialog {...args}>
29
+ <DialogTrigger asChild>
30
+ <Button variant="secondary">{s.confirm!.trigger}</Button>
31
+ </DialogTrigger>
32
+ <DialogContent>
33
+ <DialogHeader>
34
+ <DialogTitle>{s.confirm!.title}</DialogTitle>
35
+ <DialogDescription>{s.confirm!.body}</DialogDescription>
36
+ </DialogHeader>
37
+ </DialogContent>
38
+ </Dialog>
39
+ )}
40
+ </Show>
41
+ ),
42
+ };
43
+
44
+ export const Examples: Story = {
45
+ render: () => (
46
+ <Show component="dialog">
47
+ {(s) => (
48
+ <div>
49
+ <Dialog>
50
+ <DialogTrigger asChild>
51
+ <Button variant="secondary">{s.confirm!.trigger}</Button>
52
+ </DialogTrigger>
53
+ <DialogContent>
54
+ <DialogHeader>
55
+ <DialogTitle>{s.confirm!.title}</DialogTitle>
56
+ <DialogDescription>{s.confirm!.body}</DialogDescription>
57
+ </DialogHeader>
58
+ <DialogFooter>
59
+ <DialogClose asChild>
60
+ <Button variant="secondary">{s.confirm!.cancel}</Button>
61
+ </DialogClose>
62
+ <Button>{s.confirm!.confirm}</Button>
63
+ </DialogFooter>
64
+ </DialogContent>
65
+ </Dialog>
66
+ </div>
67
+ )}
68
+ </Show>
69
+ ),
70
+ };
@@ -0,0 +1,62 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import {
3
+ Drawer,
4
+ DrawerTrigger,
5
+ DrawerContent,
6
+ DrawerHeader,
7
+ DrawerTitle,
8
+ DrawerDescription,
9
+ DrawerFooter,
10
+ DrawerClose,
11
+ Button,
12
+ } from "@open-ds/ui";
13
+ import { Show } from "../src/samples";
14
+
15
+ const meta = {
16
+ parameters: { openDs: { component: "drawer", situations: ["menu-or-dialog"] } },
17
+ title: "Components/Drawer",
18
+ component: Drawer,
19
+ } satisfies Meta<typeof Drawer>;
20
+ export default meta;
21
+ type Story = StoryObj<typeof meta>;
22
+
23
+ export const Playground: Story = {
24
+ render: (args) => (
25
+ <Drawer {...args}>
26
+ <DrawerTrigger asChild>
27
+ <Button variant="secondary">Open</Button>
28
+ </DrawerTrigger>
29
+ <DrawerContent>
30
+ <DrawerHeader>
31
+ <DrawerTitle>Drawer</DrawerTitle>
32
+ </DrawerHeader>
33
+ </DrawerContent>
34
+ </Drawer>
35
+ ),
36
+ };
37
+
38
+ export const Examples: Story = {
39
+ render: () => (
40
+ <Show component="drawer">
41
+ {(s) => (
42
+ <Drawer>
43
+ <DrawerTrigger asChild>
44
+ <Button variant="secondary">{s.actions.secondary}</Button>
45
+ </DrawerTrigger>
46
+ <DrawerContent>
47
+ <DrawerHeader>
48
+ <DrawerTitle>{s.screen}</DrawerTitle>
49
+ <DrawerDescription>{s.card?.description ?? s.field.hint}</DrawerDescription>
50
+ </DrawerHeader>
51
+ <DrawerFooter>
52
+ <Button>{s.actions.primary}</Button>
53
+ <DrawerClose asChild>
54
+ <Button variant="ghost">{s.confirm?.cancel ?? "Close"}</Button>
55
+ </DrawerClose>
56
+ </DrawerFooter>
57
+ </DrawerContent>
58
+ </Drawer>
59
+ )}
60
+ </Show>
61
+ ),
62
+ };