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.
- package/LICENSE +21 -0
- package/README.md +66 -2
- package/assets/schemes/accessible-first.json +3093 -0
- package/assets/schemes/brand-expressive.json +3124 -0
- package/assets/schemes/content-first.json +3110 -0
- package/assets/schemes/dense-data.json +3489 -0
- package/assets/schemes/grammar.json +3903 -0
- package/assets/schemes/multi-brand.json +4359 -0
- package/assets/skills/open-ds/SKILL.md +50 -0
- package/assets/skills/open-ds-build/SKILL.md +19 -0
- package/assets/skills/open-ds-change/SKILL.md +19 -0
- package/assets/skills/open-ds-choose/SKILL.md +18 -0
- package/assets/skills/open-ds-review/SKILL.md +22 -0
- package/assets/skills/open-ds-write/SKILL.md +13 -0
- package/assets/stories/accordion.stories.tsx +46 -0
- package/assets/stories/alert-dialog.stories.tsx +65 -0
- package/assets/stories/alert.stories.tsx +44 -0
- package/assets/stories/aspect-ratio.stories.tsx +37 -0
- package/assets/stories/avatar.stories.tsx +42 -0
- package/assets/stories/badge.stories.tsx +39 -0
- package/assets/stories/breadcrumb.stories.tsx +54 -0
- package/assets/stories/button.stories.tsx +46 -0
- package/assets/stories/calendar.stories.tsx +30 -0
- package/assets/stories/card.stories.tsx +50 -0
- package/assets/stories/carousel.stories.tsx +64 -0
- package/assets/stories/chart.stories.tsx +61 -0
- package/assets/stories/checkbox.stories.tsx +29 -0
- package/assets/stories/collapsible.stories.tsx +39 -0
- package/assets/stories/combobox.stories.tsx +57 -0
- package/assets/stories/command.stories.tsx +60 -0
- package/assets/stories/context-menu.stories.tsx +55 -0
- package/assets/stories/data-table.stories.tsx +93 -0
- package/assets/stories/date-picker.stories.tsx +27 -0
- package/assets/stories/dialog.stories.tsx +70 -0
- package/assets/stories/drawer.stories.tsx +62 -0
- package/assets/stories/dropdown-menu.stories.tsx +65 -0
- package/assets/stories/empty.stories.tsx +39 -0
- package/assets/stories/field.stories.tsx +42 -0
- package/assets/stories/form.stories.tsx +56 -0
- package/assets/stories/input-group.stories.tsx +41 -0
- package/assets/stories/input-otp.stories.tsx +48 -0
- package/assets/stories/input.stories.tsx +32 -0
- package/assets/stories/kbd.stories.tsx +30 -0
- package/assets/stories/label.stories.tsx +26 -0
- package/assets/stories/native-select.stories.tsx +39 -0
- package/assets/stories/navigation-menu.stories.tsx +41 -0
- package/assets/stories/pagination.stories.tsx +61 -0
- package/assets/stories/popover.stories.tsx +37 -0
- package/assets/stories/progress.stories.tsx +30 -0
- package/assets/stories/radio-group.stories.tsx +45 -0
- package/assets/stories/resizable.stories.tsx +54 -0
- package/assets/stories/scroll-area.stories.tsx +47 -0
- package/assets/stories/select.stories.tsx +57 -0
- package/assets/stories/separator.stories.tsx +28 -0
- package/assets/stories/sheet.stories.tsx +46 -0
- package/assets/stories/sidebar.stories.tsx +62 -0
- package/assets/stories/skeleton.stories.tsx +27 -0
- package/assets/stories/slider.stories.tsx +44 -0
- package/assets/stories/spinner.stories.tsx +25 -0
- package/assets/stories/switch.stories.tsx +29 -0
- package/assets/stories/table.stories.tsx +97 -0
- package/assets/stories/tabs.stories.tsx +55 -0
- package/assets/stories/textarea.stories.tsx +28 -0
- package/assets/stories/toast.stories.tsx +30 -0
- package/assets/stories/toggle-group.stories.tsx +41 -0
- package/assets/stories/toggle.stories.tsx +20 -0
- package/assets/stories/tooltip.stories.tsx +49 -0
- package/assets/tokens/accessible-first/content.json +32 -0
- package/assets/tokens/accessible-first/dark.tokens.json +581 -0
- package/assets/tokens/accessible-first/light.tokens.json +581 -0
- package/assets/tokens/accessible-first/shadcn.css +21 -0
- package/assets/tokens/accessible-first/theme.css +101 -0
- package/assets/tokens/accessible-first/tokens.css +331 -0
- package/assets/tokens/accessible-first/tokens.json +1616 -0
- package/assets/tokens/accessible-first/tokens.scoped.css +333 -0
- package/assets/tokens/brand-expressive/content.json +32 -0
- package/assets/tokens/brand-expressive/dark.tokens.json +585 -0
- package/assets/tokens/brand-expressive/light.tokens.json +585 -0
- package/assets/tokens/brand-expressive/shadcn.css +21 -0
- package/assets/tokens/brand-expressive/theme.css +101 -0
- package/assets/tokens/brand-expressive/tokens.css +331 -0
- package/assets/tokens/brand-expressive/tokens.json +1651 -0
- package/assets/tokens/brand-expressive/tokens.scoped.css +333 -0
- package/assets/tokens/content-first/content.json +32 -0
- package/assets/tokens/content-first/dark.tokens.json +582 -0
- package/assets/tokens/content-first/light.tokens.json +582 -0
- package/assets/tokens/content-first/shadcn.css +21 -0
- package/assets/tokens/content-first/theme.css +101 -0
- package/assets/tokens/content-first/tokens.css +331 -0
- package/assets/tokens/content-first/tokens.json +1631 -0
- package/assets/tokens/content-first/tokens.scoped.css +333 -0
- package/assets/tokens/dense-data/content.json +32 -0
- package/assets/tokens/dense-data/dark.tokens.json +580 -0
- package/assets/tokens/dense-data/light.tokens.json +580 -0
- package/assets/tokens/dense-data/shadcn.css +21 -0
- package/assets/tokens/dense-data/theme.css +101 -0
- package/assets/tokens/dense-data/tokens.css +331 -0
- package/assets/tokens/dense-data/tokens.json +1623 -0
- package/assets/tokens/dense-data/tokens.scoped.css +333 -0
- package/assets/tokens/index.json +143 -0
- package/assets/tokens/multi-brand/aster-dark.tokens.json +625 -0
- package/assets/tokens/multi-brand/aster-light.tokens.json +625 -0
- package/assets/tokens/multi-brand/birch-dark.tokens.json +625 -0
- package/assets/tokens/multi-brand/birch-light.tokens.json +625 -0
- package/assets/tokens/multi-brand/content.json +32 -0
- package/assets/tokens/multi-brand/coral-dark.tokens.json +625 -0
- package/assets/tokens/multi-brand/coral-light.tokens.json +625 -0
- package/assets/tokens/multi-brand/shadcn.css +21 -0
- package/assets/tokens/multi-brand/theme.css +101 -0
- package/assets/tokens/multi-brand/tokens.css +1002 -0
- package/assets/tokens/multi-brand/tokens.json +1754 -0
- package/assets/tokens/multi-brand/tokens.scoped.css +1022 -0
- package/assets/tokens/shadcn-map.json +34 -0
- package/assets/ui/components/accordion.tsx +60 -0
- package/assets/ui/components/alert-dialog.tsx +171 -0
- package/assets/ui/components/alert.tsx +56 -0
- package/assets/ui/components/aspect-ratio.tsx +17 -0
- package/assets/ui/components/avatar.tsx +96 -0
- package/assets/ui/components/badge.tsx +36 -0
- package/assets/ui/components/breadcrumb.tsx +99 -0
- package/assets/ui/components/button.tsx +53 -0
- package/assets/ui/components/calendar.tsx +169 -0
- package/assets/ui/components/card.tsx +72 -0
- package/assets/ui/components/carousel.tsx +224 -0
- package/assets/ui/components/chart.tsx +315 -0
- package/assets/ui/components/checkbox.tsx +29 -0
- package/assets/ui/components/collapsible.tsx +25 -0
- package/assets/ui/components/combobox.tsx +275 -0
- package/assets/ui/components/command.tsx +145 -0
- package/assets/ui/components/context-menu.tsx +218 -0
- package/assets/ui/components/data-table.tsx +307 -0
- package/assets/ui/components/date-picker.tsx +79 -0
- package/assets/ui/components/dialog.tsx +68 -0
- package/assets/ui/components/drawer.tsx +115 -0
- package/assets/ui/components/dropdown-menu.tsx +58 -0
- package/assets/ui/components/empty.tsx +92 -0
- package/assets/ui/components/field.tsx +234 -0
- package/assets/ui/components/form.tsx +146 -0
- package/assets/ui/components/input-group.tsx +154 -0
- package/assets/ui/components/input-otp.tsx +75 -0
- package/assets/ui/components/input.tsx +25 -0
- package/assets/ui/components/kbd.tsx +30 -0
- package/assets/ui/components/label.tsx +22 -0
- package/assets/ui/components/native-select.tsx +59 -0
- package/assets/ui/components/navigation-menu.tsx +149 -0
- package/assets/ui/components/pagination.tsx +108 -0
- package/assets/ui/components/popover.tsx +61 -0
- package/assets/ui/components/progress.tsx +31 -0
- package/assets/ui/components/radio-group.tsx +40 -0
- package/assets/ui/components/resizable.tsx +54 -0
- package/assets/ui/components/scroll-area.tsx +55 -0
- package/assets/ui/components/select.tsx +81 -0
- package/assets/ui/components/separator.tsx +35 -0
- package/assets/ui/components/sheet.tsx +114 -0
- package/assets/ui/components/sidebar.tsx +685 -0
- package/assets/ui/components/skeleton.tsx +15 -0
- package/assets/ui/components/slider.tsx +70 -0
- package/assets/ui/components/spinner.tsx +16 -0
- package/assets/ui/components/switch.tsx +32 -0
- package/assets/ui/components/table.tsx +78 -0
- package/assets/ui/components/tabs.tsx +49 -0
- package/assets/ui/components/textarea.tsx +25 -0
- package/assets/ui/components/toast.tsx +54 -0
- package/assets/ui/components/toggle-group.tsx +88 -0
- package/assets/ui/components/toggle.tsx +48 -0
- package/assets/ui/components/tooltip.tsx +34 -0
- package/assets/ui/lib/use-mobile.ts +20 -0
- package/assets/ui/lib/utils.ts +7 -0
- package/assets/ui/styles.css +27 -0
- package/bin/open-ds.js +6 -0
- package/package.json +56 -4
- package/src/agents.mjs +150 -0
- package/src/cli.mjs +445 -0
- package/src/components.mjs +69 -0
- package/src/context.mjs +143 -0
- package/src/create.mjs +377 -0
- package/src/docs.mjs +570 -0
- package/src/guidance.mjs +63 -0
- package/src/index.mjs +20 -0
- package/src/mcp.mjs +660 -0
- package/src/readmes.mjs +106 -0
- package/src/schemes.mjs +188 -0
- package/src/tokens.mjs +127 -0
- package/templates/project/.github/workflows/ci.yml +15 -0
- package/templates/project/.storybook/component-docs.mdx +26 -0
- package/templates/project/.storybook/main.ts +17 -0
- package/templates/project/.storybook/manager-head.html +3 -0
- package/templates/project/.storybook/manager.ts +37 -0
- package/templates/project/.storybook/preview-head.html +3 -0
- package/templates/project/.storybook/preview.tsx +82 -0
- package/templates/project/docs/docusaurus.config.ts +64 -0
- package/templates/project/docs/sidebars.ts +8 -0
- package/templates/project/docs/src/css/custom.css +275 -0
- package/templates/project/gitignore +6 -0
- package/templates/project/src/styles/index.css +16 -0
- package/templates/project/src/vite-env.d.ts +7 -0
- package/templates/project/stories/docs-blocks.tsx +190 -0
- package/templates/project/stories/samples.tsx +102 -0
- package/templates/project/stories/usage.tsx +31 -0
- package/templates/project/tokens/build.mjs +468 -0
- package/templates/project/tsconfig.json +15 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: open-ds
|
|
3
|
+
description: Build UI with an Open DS scheme. Use when you pick a design system, deploy one into a project, or write UI in a project that has open-ds.json.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Open DS
|
|
7
|
+
|
|
8
|
+
An Open DS scheme is a full design system as data. It answers a fixed set of questions (the grammar) and gives the reason for each answer. Tokens, components, usage rules and voice follow from those answers.
|
|
9
|
+
|
|
10
|
+
## Focused skills
|
|
11
|
+
|
|
12
|
+
This skill is the overview. For each job there is a focused skill next to it:
|
|
13
|
+
|
|
14
|
+
| Skill | When |
|
|
15
|
+
| ---------------- | ----------------------------------------- |
|
|
16
|
+
| `open-ds-choose` | Pick a scheme and take it into a project. |
|
|
17
|
+
| `open-ds-build` | Build UI in a project that uses a scheme. |
|
|
18
|
+
| `open-ds-write` | Write copy in the scheme's voice. |
|
|
19
|
+
| `open-ds-change` | Change a token, a component or an answer. |
|
|
20
|
+
| `open-ds-review` | Review UI against the scheme. |
|
|
21
|
+
|
|
22
|
+
The MCP server serves the same five as prompts.
|
|
23
|
+
|
|
24
|
+
## Pick a scheme
|
|
25
|
+
|
|
26
|
+
1. Run `open-ds list`, or call the MCP tool `list_schemes`.
|
|
27
|
+
2. Read `ai.use_when` and `ai.avoid_when` of each scheme. Pick the one that fits the product.
|
|
28
|
+
3. If two fit, read `scenarios` in each scheme. Pick the closest one.
|
|
29
|
+
|
|
30
|
+
## Deploy it
|
|
31
|
+
|
|
32
|
+
- CLI: `open-ds init <scheme> --dir <project>`. Add `--brand <id>` for a multi-brand scheme.
|
|
33
|
+
- MCP: call `plan_init` (or `plan_create` for a new project). It returns the exact command and the files it writes; run the command. The server never writes to your disk.
|
|
34
|
+
- Then install the packages that the command prints. Import `src/styles/open-ds.css` after Tailwind.
|
|
35
|
+
|
|
36
|
+
## Build UI in a project that uses a scheme
|
|
37
|
+
|
|
38
|
+
1. Read `AGENTS.md`. It holds the usage rules and the voice.
|
|
39
|
+
2. Before you choose a token, a component or a variant, find the situation: `open-ds when <scheme> <words>` or the MCP tool `when_to_use`. Do what the rule says. Do not do what its "not" says.
|
|
40
|
+
3. Use only the components in `src/components/ui` and the CSS variables in `src/styles/open-ds.css`. Do not write raw colors, sizes or spacing.
|
|
41
|
+
4. To change how a component looks, change a component key (for example `--button-radius`). Do not edit the component.
|
|
42
|
+
5. Write copy in the scheme's voice. Read the usage rules of the voice situations (button-label, error-words, success-words, empty-words, confirm-words, first-visit): each gives the tone, a rule and an example.
|
|
43
|
+
6. To explain a decision, run `open-ds why <scheme> <question-id>` or call `why`. Quote the answer and its reasons.
|
|
44
|
+
7. Before you use a colour, read its guidance: `open-ds context <scheme> <token>` or `get_context`. Never use it for a case in its `not_for`, and put text only on the fills it lists. Status goes by real risk: info, then warning, then danger.
|
|
45
|
+
|
|
46
|
+
## Do not
|
|
47
|
+
|
|
48
|
+
- Do not mix two schemes in one product.
|
|
49
|
+
- Do not use color alone to show meaning.
|
|
50
|
+
- Do not remove focus rings.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: open-ds-build
|
|
3
|
+
description: Build UI in a project that uses an Open DS scheme. Use whenever you write or edit screens, components or styles in a project with open-ds.json.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build UI with the scheme
|
|
7
|
+
|
|
8
|
+
Before you start, call `get_context build` (or `open-ds context <scheme> build`). Before you use a colour, read its guidance with `get_context <token>`: its intent, what not to use it for and the fills it may sit on.
|
|
9
|
+
|
|
10
|
+
1. Read `AGENTS.md` first. It holds the usage rules and the voice for this scheme.
|
|
11
|
+
2. Before you pick a component, a variant or a token, find the situation: `npx open-ds when <scheme> <words>` or the MCP tool `when_to_use`. Do what its rule says, never what its "not" says.
|
|
12
|
+
3. Use only the components in `src/components/ui` and the scheme's CSS variables. No raw colours, sizes or spacing.
|
|
13
|
+
4. Use only components in the scheme's inventory (`get_inventory`). If you need one that is missing, say so and add it with `npx open-ds add <component>` (`plan_add`), or ask; do not build a look-alike.
|
|
14
|
+
5. To change how a component looks, change its component key (for example `--button-radius`), not the component file.
|
|
15
|
+
6. Light first: build and check the light theme, then dark.
|
|
16
|
+
7. Write the words with open-ds-write.
|
|
17
|
+
8. Before you finish, check the screen with open-ds-review.
|
|
18
|
+
|
|
19
|
+
To explain a decision, call `why` with the question id or the component key, and quote the answer and its reasons.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: open-ds-change
|
|
3
|
+
description: Change an Open DS design system: a token, a component or an answer. Use when the product differs from the scheme, or a value, colour, size or rule needs to change.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Change the design system
|
|
7
|
+
|
|
8
|
+
Pick the smallest layer that does the job:
|
|
9
|
+
|
|
10
|
+
1. **A look on one component:** change its component key in the project's tokens (for example `button/radius`). The component reads it.
|
|
11
|
+
2. **A value everywhere:** change the semantic token it comes from. Find it with `why <scheme> <component-key>` or `get_key`.
|
|
12
|
+
3. **A raw option:** change the primitive the semantic points at (a palette step, a size, a corner). The primitives page on open-ds.dev shows what uses each one.
|
|
13
|
+
4. **A decision:** when the product is different, change the answer itself. Call `what_moves` first: it lists the answers and tokens that follow from it. Write the new reason.
|
|
14
|
+
|
|
15
|
+
Then:
|
|
16
|
+
|
|
17
|
+
- Rebuild the tokens: `npm run tokens` in a created project.
|
|
18
|
+
- Keep light and dark working, and keep contrast at WCAG AA.
|
|
19
|
+
- Say what you changed, at which layer, and why. Quote the old answer if you changed one.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: open-ds-choose
|
|
3
|
+
description: Pick an Open DS scheme for a product and take it into a project. Use before a project has a design system, or when someone asks which design system fits.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Choose and take a scheme
|
|
7
|
+
|
|
8
|
+
1. List the schemes: `npx open-ds list`, or the MCP tool `list_schemes`.
|
|
9
|
+
2. Read each scheme's `use_when` and `avoid_when`. Pick the one that fits the product: its people, content and main task.
|
|
10
|
+
3. If two fit, compare them: the MCP tool `compare_schemes`, or open both on open-ds.dev. Read the reasons, not only the looks.
|
|
11
|
+
4. Take it:
|
|
12
|
+
- A new design system project: `npx open-ds create <dir> --scheme <id>` (the MCP tool `plan_create` returns the exact command and the files it writes).
|
|
13
|
+
- An existing app: `npx open-ds init <id> --dir .` (`plan_init`).
|
|
14
|
+
- A multi-brand scheme needs `--brand <id>`.
|
|
15
|
+
5. Run the command yourself. The MCP server never writes to your disk.
|
|
16
|
+
6. Tell the person which scheme you picked and quote the reasons that made it fit.
|
|
17
|
+
|
|
18
|
+
The questions and answers are a starting point, not a standard. If one answer is wrong for the product, say which, and change it later with open-ds-change.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: open-ds-review
|
|
3
|
+
description: Review UI against an Open DS scheme. Use before you finish a screen, or when someone asks whether UI follows the design system.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review UI against the scheme
|
|
7
|
+
|
|
8
|
+
Check each point and report what fails, with the rule it breaks:
|
|
9
|
+
|
|
10
|
+
1. **Components:** only components from `src/components/ui`, and only ones in the inventory (`get_inventory`). No look-alikes.
|
|
11
|
+
2. **Tokens:** no raw colours, sizes, spacing, radii or shadows. Only the scheme's variables and component keys.
|
|
12
|
+
3. **Usage rules:** each choice matches its situation (`when_to_use`): number in a table, status label, destructive action, field label, focus.
|
|
13
|
+
4. **Voice:** labels, errors, empty and success messages follow the voice (open-ds-write).
|
|
14
|
+
5. **Meaning:** colour is never the only signal. Check every colour against its guidance (`get_context <token>` or `open-ds context <scheme> <token>`): it is used for what its intent says, and never for a case in its `not_for`. Use what `not_for` names instead.
|
|
15
|
+
6. **Urgency:** a status matches the real risk: info, then warning, then danger. Never a higher level to get attention. Success sits outside the order.
|
|
16
|
+
7. **Pairs:** text and icons sit only on the fills their guidance lists (`sits_on`). Tag text is `color.text.primary` on a category fill. Disabled controls use the disabled set, not opacity.
|
|
17
|
+
8. **Access:** visible focus, labels on every control, targets the scheme's size, WCAG AA contrast.
|
|
18
|
+
9. **Themes:** light first, and dark works too.
|
|
19
|
+
|
|
20
|
+
Start with `get_context review` (or `open-ds context <scheme> review`): it returns every rule, every colour's guidance and the urgency order in one call.
|
|
21
|
+
|
|
22
|
+
For each failure, give the fix and quote the scheme's reason with `why`.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: open-ds-write
|
|
3
|
+
description: Write interface copy in the voice of an Open DS scheme. Use for button labels, errors, success and empty messages, confirmations and first-visit hints.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Write in the scheme's voice
|
|
7
|
+
|
|
8
|
+
1. Read the voice: `npx open-ds show <scheme>` or `get_scheme` with part `voice`. Note its summary, principles and the words to use and avoid.
|
|
9
|
+
2. For each message, find its situation with `when_to_use`: button-label, error-words, success-words, empty-words, confirm-words or first-visit. Each rule gives the tone, a rule and an example.
|
|
10
|
+
3. Match the example's shape, not its words. Use the product's own objects and numbers.
|
|
11
|
+
4. Buttons: one verb, the action itself. Errors: what happened, then what to do. Empty states: why it is empty, then the next step. Confirmations: name the object and the consequence.
|
|
12
|
+
5. Never use the words the voice says to avoid.
|
|
13
|
+
6. Keep it short. If a message needs two sentences, the first says what happened.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@open-ds/ui";
|
|
3
|
+
import { Show } from "../src/samples";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
parameters: { openDs: { component: "accordion", situations: [] } },
|
|
7
|
+
title: "Components/Accordion",
|
|
8
|
+
component: Accordion,
|
|
9
|
+
args: { type: "single", collapsible: true },
|
|
10
|
+
} satisfies Meta<typeof Accordion>;
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof meta>;
|
|
13
|
+
|
|
14
|
+
export const Playground: Story = {
|
|
15
|
+
render: (args) => (
|
|
16
|
+
<Show component="accordion">
|
|
17
|
+
{(s) => (
|
|
18
|
+
<Accordion {...args} className="max-w-lg">
|
|
19
|
+
{s.metrics.map((m) => (
|
|
20
|
+
<AccordionItem key={m.label} value={m.label}>
|
|
21
|
+
<AccordionTrigger>{m.label}</AccordionTrigger>
|
|
22
|
+
<AccordionContent>{m.value}</AccordionContent>
|
|
23
|
+
</AccordionItem>
|
|
24
|
+
))}
|
|
25
|
+
</Accordion>
|
|
26
|
+
)}
|
|
27
|
+
</Show>
|
|
28
|
+
),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const Examples: Story = {
|
|
32
|
+
render: () => (
|
|
33
|
+
<Show component="accordion">
|
|
34
|
+
{(s) => (
|
|
35
|
+
<Accordion type="single" collapsible defaultValue={s.metrics[0].label} className="max-w-lg">
|
|
36
|
+
{s.metrics.map((m) => (
|
|
37
|
+
<AccordionItem key={m.label} value={m.label}>
|
|
38
|
+
<AccordionTrigger>{m.label}</AccordionTrigger>
|
|
39
|
+
<AccordionContent>{m.value}</AccordionContent>
|
|
40
|
+
</AccordionItem>
|
|
41
|
+
))}
|
|
42
|
+
</Accordion>
|
|
43
|
+
)}
|
|
44
|
+
</Show>
|
|
45
|
+
),
|
|
46
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import {
|
|
3
|
+
AlertDialog,
|
|
4
|
+
AlertDialogTrigger,
|
|
5
|
+
AlertDialogContent,
|
|
6
|
+
AlertDialogHeader,
|
|
7
|
+
AlertDialogFooter,
|
|
8
|
+
AlertDialogTitle,
|
|
9
|
+
AlertDialogDescription,
|
|
10
|
+
AlertDialogAction,
|
|
11
|
+
AlertDialogCancel,
|
|
12
|
+
Button,
|
|
13
|
+
} from "@open-ds/ui";
|
|
14
|
+
import { Show } from "../src/samples";
|
|
15
|
+
|
|
16
|
+
const meta = {
|
|
17
|
+
parameters: { openDs: { component: "alert-dialog", situations: ["destructive-action", "confirm-words"] } },
|
|
18
|
+
title: "Components/Alert dialog",
|
|
19
|
+
component: AlertDialog,
|
|
20
|
+
} satisfies Meta<typeof AlertDialog>;
|
|
21
|
+
export default meta;
|
|
22
|
+
type Story = StoryObj<typeof meta>;
|
|
23
|
+
|
|
24
|
+
export const Playground: Story = {
|
|
25
|
+
render: (args) => (
|
|
26
|
+
<Show component="alert-dialog">
|
|
27
|
+
{(s) => (
|
|
28
|
+
<AlertDialog {...args}>
|
|
29
|
+
<AlertDialogTrigger asChild>
|
|
30
|
+
<Button variant="secondary">{s.confirm?.trigger ?? s.actions.secondary}</Button>
|
|
31
|
+
</AlertDialogTrigger>
|
|
32
|
+
<AlertDialogContent>
|
|
33
|
+
<AlertDialogHeader>
|
|
34
|
+
<AlertDialogTitle>{s.confirm?.title ?? s.actions.secondary}</AlertDialogTitle>
|
|
35
|
+
</AlertDialogHeader>
|
|
36
|
+
</AlertDialogContent>
|
|
37
|
+
</AlertDialog>
|
|
38
|
+
)}
|
|
39
|
+
</Show>
|
|
40
|
+
),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Examples: Story = {
|
|
44
|
+
render: () => (
|
|
45
|
+
<Show component="alert-dialog">
|
|
46
|
+
{(s) => (
|
|
47
|
+
<AlertDialog>
|
|
48
|
+
<AlertDialogTrigger asChild>
|
|
49
|
+
<Button variant="secondary">{s.confirm?.trigger ?? s.actions.secondary}</Button>
|
|
50
|
+
</AlertDialogTrigger>
|
|
51
|
+
<AlertDialogContent>
|
|
52
|
+
<AlertDialogHeader>
|
|
53
|
+
<AlertDialogTitle>{s.confirm?.title ?? s.actions.secondary}</AlertDialogTitle>
|
|
54
|
+
<AlertDialogDescription>{s.confirm?.body ?? ""}</AlertDialogDescription>
|
|
55
|
+
</AlertDialogHeader>
|
|
56
|
+
<AlertDialogFooter>
|
|
57
|
+
<AlertDialogCancel>{s.confirm?.cancel ?? "Cancel"}</AlertDialogCancel>
|
|
58
|
+
<AlertDialogAction>{s.confirm?.confirm ?? s.actions.primary}</AlertDialogAction>
|
|
59
|
+
</AlertDialogFooter>
|
|
60
|
+
</AlertDialogContent>
|
|
61
|
+
</AlertDialog>
|
|
62
|
+
)}
|
|
63
|
+
</Show>
|
|
64
|
+
),
|
|
65
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Alert, AlertTitle, AlertDescription } from "@open-ds/ui";
|
|
3
|
+
import { AlertTriangle } from "lucide-react";
|
|
4
|
+
import { Show } from "../src/samples";
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
parameters: { openDs: { component: "alert", situations: ["error-message", "status-label"] } },
|
|
8
|
+
title: "Components/Alert",
|
|
9
|
+
component: Alert,
|
|
10
|
+
args: { variant: "default" },
|
|
11
|
+
} satisfies Meta<typeof Alert>;
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof meta>;
|
|
14
|
+
|
|
15
|
+
export const Playground: Story = {
|
|
16
|
+
render: (args) => (
|
|
17
|
+
<Alert {...args} className="max-w-lg">
|
|
18
|
+
<AlertTriangle />
|
|
19
|
+
<AlertTitle>Alert</AlertTitle>
|
|
20
|
+
<AlertDescription>Stays on the page until the cause is fixed.</AlertDescription>
|
|
21
|
+
</Alert>
|
|
22
|
+
),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const Examples: Story = {
|
|
26
|
+
render: () => (
|
|
27
|
+
<Show component="alert">
|
|
28
|
+
{(s) => (
|
|
29
|
+
<div className="grid max-w-lg gap-[var(--space-gap-default)]">
|
|
30
|
+
{/* Warning and danger statuses, each in the tone its meaning picks. */}
|
|
31
|
+
{s.statuses
|
|
32
|
+
.filter((x) => x.meaning === "warning" || x.meaning === "danger")
|
|
33
|
+
.map((x) => (
|
|
34
|
+
<Alert key={x.label} variant={x.meaning === "danger" ? "destructive" : "default"}>
|
|
35
|
+
<AlertTriangle />
|
|
36
|
+
<AlertTitle>{x.label}</AlertTitle>
|
|
37
|
+
<AlertDescription>{x.why}</AlertDescription>
|
|
38
|
+
</Alert>
|
|
39
|
+
))}
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
</Show>
|
|
43
|
+
),
|
|
44
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { AspectRatio } from "@open-ds/ui";
|
|
3
|
+
import { Show } from "../src/samples";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
parameters: { openDs: { component: "aspect-ratio", situations: [] } },
|
|
7
|
+
title: "Components/Aspect ratio",
|
|
8
|
+
component: AspectRatio,
|
|
9
|
+
args: { ratio: 16 / 9 },
|
|
10
|
+
} satisfies Meta<typeof AspectRatio>;
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof meta>;
|
|
13
|
+
|
|
14
|
+
export const Playground: Story = {
|
|
15
|
+
render: (args) => (
|
|
16
|
+
<div className="max-w-md">
|
|
17
|
+
<AspectRatio {...args} className="rounded-[var(--radius-container)] bg-[var(--color-surface-sunken)]" />
|
|
18
|
+
</div>
|
|
19
|
+
),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const Examples: Story = {
|
|
23
|
+
render: () => (
|
|
24
|
+
<Show component="aspect-ratio">
|
|
25
|
+
{(s) => (
|
|
26
|
+
<div className="max-w-md">
|
|
27
|
+
<AspectRatio
|
|
28
|
+
ratio={16 / 9}
|
|
29
|
+
className="flex items-end rounded-[var(--radius-container)] bg-[var(--color-surface-sunken)] p-[var(--space-inset-container)]"
|
|
30
|
+
>
|
|
31
|
+
<span className="[font-weight:var(--type-heading-font-weight)]">{s.screen}</span>
|
|
32
|
+
</AspectRatio>
|
|
33
|
+
</div>
|
|
34
|
+
)}
|
|
35
|
+
</Show>
|
|
36
|
+
),
|
|
37
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Avatar, AvatarFallback } from "@open-ds/ui";
|
|
3
|
+
import { Show } from "../src/samples";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
parameters: { openDs: { component: "avatar", situations: [] } },
|
|
7
|
+
title: "Components/Avatar",
|
|
8
|
+
component: Avatar,
|
|
9
|
+
} satisfies Meta<typeof Avatar>;
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof meta>;
|
|
12
|
+
|
|
13
|
+
export const Playground: Story = {
|
|
14
|
+
render: (args) => (
|
|
15
|
+
<Avatar {...args}>
|
|
16
|
+
<AvatarFallback>AB</AvatarFallback>
|
|
17
|
+
</Avatar>
|
|
18
|
+
),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Examples: Story = {
|
|
22
|
+
render: () => (
|
|
23
|
+
<Show component="avatar">
|
|
24
|
+
{(s) => (
|
|
25
|
+
<div className="flex gap-[var(--space-gap-default)]">
|
|
26
|
+
{s.metrics.slice(0, 3).map((m) => (
|
|
27
|
+
<Avatar key={m.label} title={m.label}>
|
|
28
|
+
<AvatarFallback>
|
|
29
|
+
{m.label
|
|
30
|
+
.split(" ")
|
|
31
|
+
.slice(0, 2)
|
|
32
|
+
.map((w) => w[0])
|
|
33
|
+
.join("")
|
|
34
|
+
.toUpperCase()}
|
|
35
|
+
</AvatarFallback>
|
|
36
|
+
</Avatar>
|
|
37
|
+
))}
|
|
38
|
+
</div>
|
|
39
|
+
)}
|
|
40
|
+
</Show>
|
|
41
|
+
),
|
|
42
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Badge } from "@open-ds/ui";
|
|
3
|
+
import { Show, toneOf } from "../src/samples";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
parameters: { openDs: { component: "badge", situations: ["status-label", "status-shape"] } },
|
|
7
|
+
title: "Components/Badge",
|
|
8
|
+
component: Badge,
|
|
9
|
+
args: { children: "Status", tone: "neutral" },
|
|
10
|
+
argTypes: { tone: { control: "inline-radio", options: ["neutral", "info", "success", "warning", "danger"] } },
|
|
11
|
+
} satisfies Meta<typeof Badge>;
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof meta>;
|
|
14
|
+
|
|
15
|
+
export const Playground: Story = {};
|
|
16
|
+
|
|
17
|
+
// Each status shows in the tone its meaning picks. Danger appears only where the scheme says something failed.
|
|
18
|
+
export const Examples: Story = {
|
|
19
|
+
render: () => (
|
|
20
|
+
<Show component="badge">
|
|
21
|
+
{(s) => (
|
|
22
|
+
<div>
|
|
23
|
+
<dl className="grid max-w-2xl grid-cols-[auto_1fr] items-center gap-x-[var(--space-gap-group)] gap-y-[var(--space-gap-default)]">
|
|
24
|
+
{s.statuses.map((x) => (
|
|
25
|
+
<div key={x.label} className="contents">
|
|
26
|
+
<dt>
|
|
27
|
+
<Badge tone={x.meaning}>{x.label}</Badge>
|
|
28
|
+
</dt>
|
|
29
|
+
<dd className="text-[var(--color-text-secondary)]">
|
|
30
|
+
{x.meaning}: {x.why}
|
|
31
|
+
</dd>
|
|
32
|
+
</div>
|
|
33
|
+
))}
|
|
34
|
+
</dl>
|
|
35
|
+
</div>
|
|
36
|
+
)}
|
|
37
|
+
</Show>
|
|
38
|
+
),
|
|
39
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import {
|
|
3
|
+
Breadcrumb,
|
|
4
|
+
BreadcrumbList,
|
|
5
|
+
BreadcrumbItem,
|
|
6
|
+
BreadcrumbLink,
|
|
7
|
+
BreadcrumbPage,
|
|
8
|
+
BreadcrumbSeparator,
|
|
9
|
+
} from "@open-ds/ui";
|
|
10
|
+
import { Show } from "../src/samples";
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
parameters: { openDs: { component: "breadcrumb", situations: ["link", "keyboard-focus"] } },
|
|
14
|
+
title: "Components/Breadcrumb",
|
|
15
|
+
component: Breadcrumb,
|
|
16
|
+
} satisfies Meta<typeof Breadcrumb>;
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
|
|
20
|
+
export const Playground: Story = {
|
|
21
|
+
render: (args) => (
|
|
22
|
+
<Breadcrumb {...args}>
|
|
23
|
+
<BreadcrumbList>
|
|
24
|
+
<BreadcrumbItem>
|
|
25
|
+
<BreadcrumbLink href="#">Home</BreadcrumbLink>
|
|
26
|
+
</BreadcrumbItem>
|
|
27
|
+
<BreadcrumbSeparator />
|
|
28
|
+
<BreadcrumbItem>
|
|
29
|
+
<BreadcrumbPage>Page</BreadcrumbPage>
|
|
30
|
+
</BreadcrumbItem>
|
|
31
|
+
</BreadcrumbList>
|
|
32
|
+
</Breadcrumb>
|
|
33
|
+
),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const Examples: Story = {
|
|
37
|
+
render: () => (
|
|
38
|
+
<Show component="breadcrumb">
|
|
39
|
+
{(s) => (
|
|
40
|
+
<Breadcrumb>
|
|
41
|
+
<BreadcrumbList>
|
|
42
|
+
<BreadcrumbItem>
|
|
43
|
+
<BreadcrumbLink href="#">{s.screen}</BreadcrumbLink>
|
|
44
|
+
</BreadcrumbItem>
|
|
45
|
+
<BreadcrumbSeparator />
|
|
46
|
+
<BreadcrumbItem>
|
|
47
|
+
<BreadcrumbPage>{s.card?.title ?? s.metrics[0].label}</BreadcrumbPage>
|
|
48
|
+
</BreadcrumbItem>
|
|
49
|
+
</BreadcrumbList>
|
|
50
|
+
</Breadcrumb>
|
|
51
|
+
)}
|
|
52
|
+
</Show>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Button } from "@open-ds/ui";
|
|
3
|
+
import { Download, MoreHorizontal } from "lucide-react";
|
|
4
|
+
import { Show, toneOf } from "../src/samples";
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
parameters: {
|
|
8
|
+
openDs: {
|
|
9
|
+
component: "button",
|
|
10
|
+
situations: ["commit-action", "alternative-action", "destructive-action", "row-action"],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
title: "Components/Button",
|
|
14
|
+
component: Button,
|
|
15
|
+
args: { children: "Continue", variant: "primary", size: "default" },
|
|
16
|
+
argTypes: {
|
|
17
|
+
variant: { control: "inline-radio", options: ["primary", "secondary", "ghost"] },
|
|
18
|
+
size: { control: "inline-radio", options: ["default", "compact", "icon"] },
|
|
19
|
+
},
|
|
20
|
+
} satisfies Meta<typeof Button>;
|
|
21
|
+
export default meta;
|
|
22
|
+
type Story = StoryObj<typeof meta>;
|
|
23
|
+
|
|
24
|
+
export const Playground: Story = {};
|
|
25
|
+
|
|
26
|
+
export const Examples: Story = {
|
|
27
|
+
render: () => (
|
|
28
|
+
<Show component="button">
|
|
29
|
+
{(s) => (
|
|
30
|
+
<div>
|
|
31
|
+
<div className="flex flex-wrap items-center gap-[var(--space-gap-default)]">
|
|
32
|
+
<Button>{s.actions.primary}</Button>
|
|
33
|
+
<Button variant="secondary">
|
|
34
|
+
<Download /> {s.actions.secondary}
|
|
35
|
+
</Button>
|
|
36
|
+
{s.confirm && <Button variant="ghost">{s.confirm.cancel}</Button>}
|
|
37
|
+
<Button variant="ghost" size="icon" aria-label={s.menu?.trigger ?? "More actions"}>
|
|
38
|
+
<MoreHorizontal />
|
|
39
|
+
</Button>
|
|
40
|
+
<Button disabled>{s.actions.primary}</Button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
44
|
+
</Show>
|
|
45
|
+
),
|
|
46
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Calendar } from "@open-ds/ui";
|
|
3
|
+
import { Show } from "../src/samples";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
parameters: { openDs: { component: "calendar", situations: ["keyboard-focus"] } },
|
|
7
|
+
title: "Components/Calendar",
|
|
8
|
+
component: Calendar,
|
|
9
|
+
args: { mode: "single" },
|
|
10
|
+
} satisfies Meta<typeof Calendar>;
|
|
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="calendar">
|
|
19
|
+
{(s) => (
|
|
20
|
+
<div className="flex flex-col gap-[var(--space-gap-default)]">
|
|
21
|
+
<p className="text-[var(--color-text-secondary)]">{s.field.label}</p>
|
|
22
|
+
<Calendar
|
|
23
|
+
mode="single"
|
|
24
|
+
className="rounded-[var(--radius-container)] border border-[var(--color-border-default)]"
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
)}
|
|
28
|
+
</Show>
|
|
29
|
+
),
|
|
30
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@open-ds/ui";
|
|
3
|
+
import { Show, toneOf } from "../src/samples";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
parameters: { openDs: { component: "card", situations: ["card", "related-items", "between-sections"] } },
|
|
7
|
+
title: "Components/Card",
|
|
8
|
+
component: Card,
|
|
9
|
+
} satisfies Meta<typeof Card>;
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof meta>;
|
|
12
|
+
|
|
13
|
+
export const Playground: Story = {
|
|
14
|
+
render: (args) => (
|
|
15
|
+
<Show component="card">
|
|
16
|
+
{(s) => (
|
|
17
|
+
<Card {...args} className="max-w-md">
|
|
18
|
+
<CardHeader>
|
|
19
|
+
<CardTitle>{s.card!.title}</CardTitle>
|
|
20
|
+
<CardDescription>{s.card!.description}</CardDescription>
|
|
21
|
+
</CardHeader>
|
|
22
|
+
</Card>
|
|
23
|
+
)}
|
|
24
|
+
</Show>
|
|
25
|
+
),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const Examples: Story = {
|
|
29
|
+
render: () => (
|
|
30
|
+
<Show component="card">
|
|
31
|
+
{(s) => (
|
|
32
|
+
<div className="max-w-md">
|
|
33
|
+
<Card>
|
|
34
|
+
<CardHeader>
|
|
35
|
+
<CardTitle>{s.card!.title}</CardTitle>
|
|
36
|
+
<CardDescription>{s.card!.description}</CardDescription>
|
|
37
|
+
</CardHeader>
|
|
38
|
+
<CardContent>
|
|
39
|
+
<Badge tone={toneOf(s, s.card!.status)}>{s.card!.status}</Badge>
|
|
40
|
+
</CardContent>
|
|
41
|
+
<CardFooter>
|
|
42
|
+
<Button>{s.card!.primary}</Button>
|
|
43
|
+
<Button variant="ghost">{s.card!.secondary}</Button>
|
|
44
|
+
</CardFooter>
|
|
45
|
+
</Card>
|
|
46
|
+
</div>
|
|
47
|
+
)}
|
|
48
|
+
</Show>
|
|
49
|
+
),
|
|
50
|
+
};
|