@hirobius/design-system 0.20.0 → 0.21.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/AGENTS.md +123 -0
- package/CONSUMING.md +4 -2
- package/DESIGN.md +28 -17
- package/NOTICE.md +1 -1
- package/README.md +37 -5
- package/dist/chunks/empty-state-DNoThgfV.js +1227 -0
- package/dist/chunks/form-By82qZcC.js +66 -0
- package/dist/fonts/geist-mono-400.woff2 +0 -0
- package/dist/fonts/satoshi-400.woff2 +0 -0
- package/dist/fonts/satoshi-500.woff2 +0 -0
- package/dist/fonts/satoshi-700.woff2 +0 -0
- package/dist/fonts.css +53 -0
- package/dist/form.js +1 -1
- package/dist/hirobius-ui.js +876 -877
- package/dist/manifest.js +1 -1
- package/dist/patterns.js +189 -170
- package/dist/styles.css +2 -2
- package/dist/tokens.css +1 -1
- package/dist/tokens.js +136 -57
- package/dist/types/src/app/components/alert-dialog.d.ts +5 -0
- package/dist/types/src/app/components/asset-img.d.ts +1 -0
- package/dist/types/src/app/components/avatar-group.d.ts +1 -0
- package/dist/types/src/app/components/badge.d.ts +1 -1
- package/dist/types/src/app/components/blockquote.d.ts +1 -0
- package/dist/types/src/app/components/button.d.ts +2 -0
- package/dist/types/src/app/components/card.d.ts +3 -2
- package/dist/types/src/app/components/data-table-section.d.ts +1 -0
- package/dist/types/src/app/components/destructive-section.d.ts +1 -0
- package/dist/types/src/app/components/dialog.d.ts +1 -0
- package/dist/types/src/app/components/error-pattern.d.ts +6 -1
- package/dist/types/src/app/components/form-actions.d.ts +1 -0
- package/dist/types/src/app/components/form-control.d.ts +10 -0
- package/dist/types/src/app/components/grid.d.ts +5 -0
- package/dist/types/src/app/components/icon.d.ts +1 -0
- package/dist/types/src/app/components/kbd.d.ts +1 -0
- package/dist/types/src/app/components/metadata-list.d.ts +1 -0
- package/dist/types/src/app/components/metric-tiles.d.ts +1 -0
- package/dist/types/src/app/components/progress.d.ts +1 -1
- package/dist/types/src/app/components/skeleton.d.ts +1 -1
- package/dist/types/src/app/components/stat.d.ts +4 -3
- package/dist/types/src/app/components/status-tile.d.ts +3 -2
- package/dist/types/src/app/components/table.d.ts +5 -0
- package/dist/types/src/app/components/text.d.ts +53 -6
- package/dist/types/src/app/components/timestamp.d.ts +1 -0
- package/dist/types/src/app/data/manifest-types.d.ts +4 -0
- package/dist/types/src/app/design-system/generated-token-refs.d.ts +37 -28
- package/dist/types/src/app/design-system/generated-token-values.d.ts +3 -0
- package/dist/types/src/app/design-system/tokens.d.ts +117 -15
- package/dist/types/src/index.d.ts +43 -40
- package/dist/variables.css +41 -33
- package/docs/CONSUMING.md +63 -39
- package/hirobius.tokens.json +77 -73
- package/llms.txt +158 -50
- package/mcp/catalog.mjs +366 -0
- package/mcp/guide.mjs +315 -0
- package/mcp/hds-mcp.mjs +49 -0
- package/mcp/server.mjs +94 -0
- package/package.json +35 -9
- package/public/hds-manifest.json +348 -254
- package/public/llms/components.txt +4 -3
- package/public/llms/layout.txt +1 -1
- package/public/llms-full.txt +190 -70
- package/public/llms.txt +158 -50
- package/scripts/eslint-plugin-hds/index.d.mts +29 -0
- package/scripts/eslint-plugin-hds/index.mjs +55 -0
- package/scripts/eslint-plugin-hds/package.json +30 -0
- package/scripts/eslint-plugin-hds/rules/no-raw-controls.mjs +47 -0
- package/scripts/eslint-plugin-hds/rules/no-raw-hex.mjs +70 -0
- package/scripts/eslint-plugin-hds/rules/no-raw-px-spacing.mjs +125 -0
- package/scripts/eslint-plugin-hds/rules/prefer-hds-layout-primitive.mjs +54 -0
- package/scripts/eslint-plugin-hds/rules/sx-token-first.mjs +111 -0
- package/scripts/eslint-plugin-hds/rules/utils.mjs +66 -0
- package/src/app/data/component-api.json +114 -53
- package/dist/chunks/empty-state-BBqhCx0S.js +0 -1217
- package/dist/chunks/form-COP3vK9_.js +0 -66
- package/dist/types/src/app/components/status-dot.d.ts +0 -39
package/AGENTS.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# AGENTS.md — @hirobius/design-system
|
|
2
|
+
|
|
3
|
+
<!-- Generated by scripts/generate-agents-md.mjs from mcp/guide.mjs and src/app/data/component-api.json. Do not hand-edit above the repo-notes marker: pnpm agents:generate -->
|
|
4
|
+
|
|
5
|
+
For agents building UI with `@hirobius/design-system`. Read this first. It settles the choices the rest of the docs leave open, so two agents given the same screen build it the same way.
|
|
6
|
+
|
|
7
|
+
## Look things up, do not guess
|
|
8
|
+
|
|
9
|
+
- **MCP server `hds`** (stdio, ships in this package, no network): `npx hds-mcp` from an app that has the package installed. Client config:
|
|
10
|
+
`{ "mcpServers": { "hds": { "command": "npx", "args": ["hds-mcp"] } } }`
|
|
11
|
+
- Tools: `list_core` (call first), `search_components` (by name or need), `get_component` (props, usage contract, compound parts), `search_tokens` (by path, prefix or words). Each answer is under 2 KB.
|
|
12
|
+
- Without the server, the same data is in `src/app/data/component-api.json` (props, `usage`), `public/hds-manifest.json` (tokens, compound parts), `llms.txt` and `DESIGN.md` in this package.
|
|
13
|
+
|
|
14
|
+
## Imports
|
|
15
|
+
|
|
16
|
+
- `@hirobius/design-system`: `Alert`, `AlertDialog`, `Avatar`, `AvatarGroup`, `Badge`, `Blockquote`, `Box`, `Breadcrumb`, `Button`, `Card`, `Checkbox`, `Combobox`, `Container`, `Dialog`, `Disclosure`, `Divider`, `EmptyState`, `Field`, `Grid`, `HdsRouterProvider`, `HdsThemeProvider`, `Icon`, `InlineLink`, `Input`, `Kbd`, `Menu`, `MetadataList`, `Pagination`, `Pin`, `Popover`, `Progress`, `Radio`, `SegmentedControl`, `Select`, `Sidebar`, `Skeleton`, `Slider`, `Spinner`, `Stack`, `Surface`, `Switcher`, `Table`, `Tabs`, `TabsContent`, `TabsList`, `TabsTrigger`, `Tag`, `Text`, `Textarea`, `Timestamp`, `ToastProvider`, `Toggle`, `Tooltip`, `VisuallyHidden`, `useToast`.
|
|
17
|
+
- `@hirobius/design-system/patterns`: `DataTableSection`, `DestructiveSection`, `Form`, `FormActions`, `MetricTile`, `MetricTiles`, `Page`, `PageHeader`. These are not in the root barrel.
|
|
18
|
+
- Load one stylesheet once at the app root and put `data-hds` on the root element (`CONSUMING.md`).
|
|
19
|
+
|
|
20
|
+
## Pick by need
|
|
21
|
+
|
|
22
|
+
One answer per need. Use the components after the arrow; what follows "Not:" is what agents reached for instead, which is the wrong answer for that need even where it has a purpose of its own.
|
|
23
|
+
|
|
24
|
+
- **Outermost wrapper of a screen** → `Page`, `Stack`. Not: `Container`, `Box`, a bare Stack as the root.
|
|
25
|
+
`<Page><Stack gap="spacious">…one child per section…</Stack></Page>`. `Container` is for a full-bleed surface that is not a page.
|
|
26
|
+
- **Screen title with breadcrumb, status and actions** → `PageHeader`, `Breadcrumb`, `Badge`. Not: Text as the page title, a Stack row of Text and Badge.
|
|
27
|
+
Exactly one per screen: `<PageHeader breadcrumb={<Breadcrumb items={[{ label, href }, { label }]} />} title="…" status={<Badge tone="success">Active</Badge>} />`.
|
|
28
|
+
- **Row of headline numbers (stats, KPIs, counts, totals)** → `MetricTiles`, `MetricTile`. Not: `Stat`, `StatusTile`, `CardMetric`, Card with Text.
|
|
29
|
+
`<MetricTiles><MetricTile label="Open projects" value="5" />…</MetricTiles>`; one MetricTile per number. `Stat` is for a number inside prose or a dense list, `Card.Metric` for one inside an existing `Card`, `StatusTile` for a state with notes (never a number).
|
|
30
|
+
- **Table of records with row actions** → `DataTableSection`, `Badge`, `Button`. Not: Table on its own, Card around a Table.
|
|
31
|
+
`<DataTableSection title="Projects" columns={[{ key, label }]} rows={[{ key, cells: [...], actions: <Stack direction="row" gap="tight">…</Stack> }]} />`; leave the actions column out of `columns`.
|
|
32
|
+
- **Switch between panels of related content** → `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`. Not: `SegmentedControl`, Button rows.
|
|
33
|
+
`<Tabs defaultValue="a"><TabsList><TabsTrigger value="a">A</TabsTrigger></TabsList><TabsContent value="a">…</TabsContent></Tabs>`.
|
|
34
|
+
- **Status label in a header or table cell** → `Badge`. Not: `Tag`, `Text`.
|
|
35
|
+
`<Badge tone="success|info|warning|danger|neutral|inProgress">…</Badge>`; tone is the only styling input.
|
|
36
|
+
- **Form with fields and a submit button** → `Form`, `Textarea`, `Input`, `FormActions`, `Button`. Not: a raw `<form>`, a Stack of Buttons as the footer.
|
|
37
|
+
`<Form onSubmit={…}><Textarea label="Notes" … /><FormActions primary={<Button type="submit">Save note</Button>} /></Form>`; every field takes its own `label`.
|
|
38
|
+
- **Confirm a destructive or irreversible action (delete, archive, remove)** → `AlertDialog`, `Button`. Not: `Dialog`, `window.confirm`.
|
|
39
|
+
Trigger, title, description, Cancel and Action parts: `<AlertDialog><AlertDialog.Trigger asChild><Button …>Archive</Button></AlertDialog.Trigger><AlertDialog.Content><AlertDialog.Header><AlertDialog.Title>…</AlertDialog.Title><AlertDialog.Description>…</AlertDialog.Description></AlertDialog.Header><AlertDialog.Footer><AlertDialog.Cancel asChild><Button variant="secondary">Cancel</Button></AlertDialog.Cancel><AlertDialog.Action asChild><Button tone="danger" onClick={…}>Archive</Button></AlertDialog.Action></AlertDialog.Footer></AlertDialog.Content></AlertDialog>`. Focus moves in and returns to the trigger for you.
|
|
40
|
+
- **Brief confirmation after an action (saved, archived, sent)** → `ToastProvider`, `useToast`. Not: `Badge`, `Alert`, `Text`.
|
|
41
|
+
Wrap the app root once in `<ToastProvider>`, then `toast({ title: "Note saved", tone: "success" })` from `useToast()`.
|
|
42
|
+
- **Message that stays next to its content (error, warning, info)** → `Alert`. Not: Text in a coloured Surface.
|
|
43
|
+
`<Alert tone="warning">…</Alert>`.
|
|
44
|
+
- **Button or row action** → `Button`. Not: a raw `<button>`, InlineLink for an action.
|
|
45
|
+
Row actions: `<Button variant="tertiary" size="sm" aria-label="View Brand refresh">View</Button>`; the destructive one adds `tone="danger"`.
|
|
46
|
+
- **Space between sections or items** → `Stack`, `Grid`. Not: margins on children, raw px gaps such as px8.
|
|
47
|
+
Stack `gap`: `spacious` between page sections, `normal` inside a section, `tight` between buttons. `Grid` for two-dimensional layout.
|
|
48
|
+
- **Padded background or a titled content object** → `Surface`, `Card`. Not: a Box with background and padding.
|
|
49
|
+
`Surface` for a plain padded background; `Card` only when the content has a title or can be pressed.
|
|
50
|
+
- **Progress bar or ring** → `Progress`. Not: a hand-built bar.
|
|
51
|
+
`<Progress value={60} label="Upload" />`; inside an existing `Card`, `CardProgress`.
|
|
52
|
+
- **Body copy** → `Text`. Not: Text as a section heading.
|
|
53
|
+
Section headings come from the pattern that owns the section (`PageHeader` `title`, `DataTableSection` `title`), not from extra Text.
|
|
54
|
+
- **Empty state for a list or section** → `EmptyState`. Not: Text saying "No items".
|
|
55
|
+
`DataTableSection` shows its own through `emptyTitle`; use `EmptyState` elsewhere.
|
|
56
|
+
- **The one irreversible action of a screen (delete the client, close the account)** → `DestructiveSection`. Not: a danger Button that acts without a confirm.
|
|
57
|
+
Last on the screen: `<DestructiveSection title="Delete client" description="…" actionLabel="Delete" onConfirm={…} />`; it opens its own AlertDialog. A per-row destructive action uses AlertDialog directly.
|
|
58
|
+
- **Read-only details as label and value pairs** → `MetadataList`, `Field`. Not: a Table with two columns, Text pairs in a Stack.
|
|
59
|
+
`<MetadataList items={[{ term: "Owner", description: "Ada" }]} />` for a set; `Field` for one pair.
|
|
60
|
+
- **A person, or a group of people** → `Avatar`, `AvatarGroup`. Not: an image in a rounded Box.
|
|
61
|
+
`<Avatar src alt initials />`; several in a row: `<AvatarGroup max={3}>…Avatars…</AvatarGroup>`.
|
|
62
|
+
- **A date or time** → `Timestamp`. Not: a formatted string in Text.
|
|
63
|
+
`<Timestamp date="2026-10-14" />` renders a `<time dateTime>`; a date in a table cell may stay plain text.
|
|
64
|
+
- **A keyboard key or shortcut hint** → `Kbd`. Not: `InlineCode`, Text in a Box.
|
|
65
|
+
`<Kbd>⌘K</Kbd>`.
|
|
66
|
+
- **A quotation with attribution** → `Blockquote`. Not: Callout for a quote, italic Text.
|
|
67
|
+
`<Blockquote attribution="Ada Lovelace">…</Blockquote>`.
|
|
68
|
+
- **A fixed-width side rail beside fluid content, or a row that stacks when narrow** → `Sidebar`, `Switcher`. Not: a Grid with media queries.
|
|
69
|
+
`Sidebar` (`side`, `sideWidth`) for rail + content; `Switcher` (`threshold`) for a row that flips to a column. Neither needs a media query.
|
|
70
|
+
- **Keep an element stuck while its region scrolls** → `Pin`. Not: position: sticky in style.
|
|
71
|
+
`<Pin top="…">…</Pin>` inside the scrolling region.
|
|
72
|
+
|
|
73
|
+
## Rules
|
|
74
|
+
|
|
75
|
+
- Tokens only: no raw hex or rgb, no raw `px`, no Tailwind classes, no custom CSS files. Spacing comes from component props (`Stack` `gap`), colour from component `tone` props or `semantic.*` tokens (`search_tokens`).
|
|
76
|
+
- No raw `<button>`, `<input>`, `<select>`, `<textarea>` or `<form>`: use `Button`, `Input`, `Select`, `Textarea`, `Form`.
|
|
77
|
+
- Every control has an accessible name: fields take `label`, a repeated row action takes an `aria-label` naming its row.
|
|
78
|
+
- Section headings come from the pattern that owns the section (`title` props). Do not add a `Text` heading the screen does not ask for.
|
|
79
|
+
|
|
80
|
+
## Finish with the lint plugin
|
|
81
|
+
|
|
82
|
+
The ESLint plugin ships in this package. Pass its `recommended` rules before you report done:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
// eslint.config.mjs
|
|
86
|
+
import hds from '@hirobius/design-system/eslint-plugin';
|
|
87
|
+
|
|
88
|
+
export default [...hds.configs.recommended];
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
<!-- hds:repo-notes — everything below is hand-written, for agents working in the hds repo itself; consumers can stop here. -->
|
|
92
|
+
|
|
93
|
+
## Working in the hds repo
|
|
94
|
+
|
|
95
|
+
Notes for agents working on this repository, not with the package. Read `CLAUDE.md` for
|
|
96
|
+
the full engineering protocol; this section is the home for autonomous-loop rules.
|
|
97
|
+
|
|
98
|
+
## Ralph quality bar
|
|
99
|
+
|
|
100
|
+
REPO_TYPE: library
|
|
101
|
+
QUALITY BAR: Public npm package. Backward compatibility matters. Tests + Storybook stories required.
|
|
102
|
+
|
|
103
|
+
Rules for any autonomous loop in this repo:
|
|
104
|
+
|
|
105
|
+
- One issue per PR. Small steps. Never push to main.
|
|
106
|
+
- The gate (ralph/gate.sh) must pass before any PR. No exceptions.
|
|
107
|
+
- Fight entropy: leave the code better than you found it.
|
|
108
|
+
- No shortcut that creates debt someone else pays for.
|
|
109
|
+
- Merges are HUMAN-approved: `ralph-approved` on the PR, or the issue
|
|
110
|
+
pre-tagged `ralph-auto` (batch approval). Never merge yourself.
|
|
111
|
+
|
|
112
|
+
Loop mechanics (see `ralph/README.md` for the full contract):
|
|
113
|
+
|
|
114
|
+
- Labels: `ralph-ready` (queue, human) · `p0`–`p3` (priority, human) ·
|
|
115
|
+
`ralph-auto`/`ralph-approved` (merge approval, human) · `ralph-wip`
|
|
116
|
+
(claimed, loop) · `ralph-parked`/`needs-adrian` (parked with reason, loop) ·
|
|
117
|
+
`ralph-selfheal-attempted` (gate's one bounded repair, spent).
|
|
118
|
+
- Selection is deterministic (`ralph/next.sh`: priority label, then issue #);
|
|
119
|
+
claims are atomic (`refs/heads/ralph/claim-<n>`); the loop's exit codes are
|
|
120
|
+
a contract (`ralph/run.sh` header). Agents never touch `ralph-*` labels,
|
|
121
|
+
claim refs, or `ralph/{.lock,runs.jsonl,logs/}` — the harness owns those.
|
|
122
|
+
- The engine is org-level: workflows are thin callers into
|
|
123
|
+
`hirobius/ralph/.github/workflows/ralph-{run,gate}-reusable.yml@v1`.
|
package/CONSUMING.md
CHANGED
|
@@ -29,6 +29,7 @@ version keeps the `LucideIcon` type identical).
|
|
|
29
29
|
```tsx
|
|
30
30
|
import { Button, Card, Dialog } from '@hirobius/design-system';
|
|
31
31
|
import '@hirobius/design-system/tokens.css'; // required — design tokens as CSS vars
|
|
32
|
+
import '@hirobius/design-system/fonts.css'; // optional — the HDS brand fonts (Satoshi, Geist Mono)
|
|
32
33
|
|
|
33
34
|
export function Example() {
|
|
34
35
|
return (
|
|
@@ -43,7 +44,8 @@ Available subpaths:
|
|
|
43
44
|
|
|
44
45
|
| Import | What |
|
|
45
46
|
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
46
|
-
| `@hirobius/design-system` | The core
|
|
47
|
+
| `@hirobius/design-system` | The 43-component core set ([README → What belongs in the system](README.md#what-belongs-in-the-system)), the rest of the allow-list and the templates; the `pattern` tier is only in `/patterns` |
|
|
48
|
+
| `@hirobius/design-system/fonts.css` | Optional brand fonts (Satoshi, Geist Mono); woff2 files ship in the package, relative URLs, `font-display: swap` |
|
|
47
49
|
| `@hirobius/design-system/tokens.css` | Token CSS variables (import once at app root) |
|
|
48
50
|
| `@hirobius/design-system/tokens` | Token values as TS constants |
|
|
49
51
|
| `@hirobius/design-system/cn` | `cn()` class-merge helper |
|
|
@@ -51,7 +53,7 @@ Available subpaths:
|
|
|
51
53
|
| `@hirobius/design-system/contexts` | Theme / language / tenant / font providers |
|
|
52
54
|
| `@hirobius/design-system/brand` | Palette → HDS-semantic overlay bridge (static / SSR / Astro; see [`docs/CONSUMING.md` §12](docs/CONSUMING.md#12-static-astro-sites--the-brand-overlay-bridge)) |
|
|
53
55
|
| `@hirobius/design-system/scroll` | Opt-in scroll-motion primitives — `SmoothScroll` (Lenis), `useScrollProgress` (Motion). Requires the optional peer `lenis`. See [`docs/CONSUMING.md` §13](docs/CONSUMING.md#13-scroll-motion-the-scroll-subpath) |
|
|
54
|
-
| `@hirobius/design-system/patterns` | The `pattern
|
|
56
|
+
| `@hirobius/design-system/patterns` | The 12 pattern modules: the hds#254 `pattern` tier (page shells, forms, code blocks, page sections). The only entry that exports them: 0.20.0 removed their root re-exports (the `hds-patterns-subpath` codemod, see MIGRATIONS.md). |
|
|
55
57
|
| `@hirobius/design-system/icons` | Curated Lucide icon set for `Icon`, and so for `Button iconOnly` (`Ellipsis`, `Pencil`, `Trash2`, `X`, …). Names listed in the manifest `iconSet`. |
|
|
56
58
|
| `@hirobius/design-system/static.css` | CSS-only static-primitive layer — `.hds-badge`/`.hds-card`/`.hds-alert`/`.hds-divider`/`.hds-tag` classes, no React. See [`docs/CONSUMING.md` §14](docs/CONSUMING.md#14-css-only-static-primitives--badgecardalertdividertag-with-no-react) |
|
|
57
59
|
|
package/DESIGN.md
CHANGED
|
@@ -28,28 +28,29 @@ Feedback hues are never decorative; do not use them as accents. Light and dark m
|
|
|
28
28
|
<!-- auto:start:typography -->
|
|
29
29
|
HDS ships three typefaces — each with a distinct and exclusive role:
|
|
30
30
|
|
|
31
|
-
- **Display / Heading font**: Satoshi. Bound exclusively to `display
|
|
31
|
+
- **Display / Heading font**: Satoshi. Bound exclusively to the `display` and `title` styles. Never used for body copy or UI labels.
|
|
32
32
|
- **Body / UI font**: Satoshi. All prose, labels, small text, captions, and UI copy.
|
|
33
33
|
- **Mono font**: Geist Mono. Reserved for tokens, code, technical callouts, and metric readouts.
|
|
34
34
|
|
|
35
|
-
Weights declared: `400` regular, `500` medium, `700` bold. Heading styles (display ·
|
|
35
|
+
Weights declared: `400` regular, `500` medium, `700` bold. Heading styles (display · title) use `700` bold; body, UI, and caption use `400` regular / `500` medium.
|
|
36
36
|
|
|
37
37
|
### Type ramp
|
|
38
38
|
|
|
39
39
|
| Role | Size (desktop max) | Weight | Use |
|
|
40
40
|
| --- | --- | --- | --- |
|
|
41
|
-
| `semantic.typography.display` |
|
|
42
|
-
| `semantic.typography.
|
|
43
|
-
| `semantic.typography.
|
|
44
|
-
| `semantic.typography.
|
|
45
|
-
| `semantic.typography.
|
|
46
|
-
| `semantic.typography.
|
|
47
|
-
| `semantic.typography.
|
|
48
|
-
| `semantic.typography.
|
|
49
|
-
| `semantic.typography.
|
|
41
|
+
| `semantic.typography.display` | 48px | 700 | One per page, hero only |
|
|
42
|
+
| `semantic.typography.title` | 24px | 700 | Section and card headings |
|
|
43
|
+
| `semantic.typography.body` | 16px | 400 | Prose |
|
|
44
|
+
| `semantic.typography.ui` | 14px | 500 | Controls, nav, table text, values |
|
|
45
|
+
| `semantic.typography.caption` | 12px | 500 | Metadata, help text and labels, in sentence case |
|
|
46
|
+
| `semantic.typography.mono` | 13px | 400 | Code and ids |
|
|
47
|
+
| `semantic.typography.h1` | 24px | 700 | deprecated: use semantic.typography.title |
|
|
48
|
+
| `semantic.typography.h2` | 24px | 700 | deprecated: use semantic.typography.title |
|
|
49
|
+
| `semantic.typography.h3` | 24px | 700 | deprecated: use semantic.typography.title |
|
|
50
|
+
| `semantic.typography.eyebrow` | 12px | 500 | deprecated: use semantic.typography.caption |
|
|
50
51
|
| `semantic.typography.lineHeight.none` | | | Semantic alias for leading-none (1) |
|
|
51
52
|
|
|
52
|
-
>
|
|
53
|
+
> The ramp is static: tokens store the value every surface renders. `h1`, `h2`, `h3` and `eyebrow` are deprecated aliases and go in 1.0.0.
|
|
53
54
|
<!-- auto:end:typography -->
|
|
54
55
|
|
|
55
56
|
## Spacing
|
|
@@ -59,9 +60,19 @@ Weights declared: `400` regular, `500` medium, `700` bold. Heading styles (displ
|
|
|
59
60
|
|
|
60
61
|
Scale: `0px` (`primitive.space.0`) · `1px` (`primitive.space.px1`) · `2px` (`primitive.space.px2`) · `4px` (`primitive.space.1`) · `6px` (`primitive.space.px6`) · `8px` (`primitive.space.2`) · `10px` (`primitive.space.px10`) · `12px` (`primitive.space.3`) · `16px` (`primitive.space.4`) · `20px` (`primitive.space.5`) · `24px` (`primitive.space.6`) · `28px` (`primitive.space.7`) · `32px` (`primitive.space.8`) · `40px` (`primitive.space.10`) · `48px` (`primitive.space.12`) · `64px` (`primitive.space.16`) · `80px` (`primitive.space.20`) · `96px` (`primitive.space.24`) · `128px` (`primitive.space.32`)
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
Layout rhythm, padding, and gaps use the `semantic.space.scale.{xs…xl}` steps (and `none`), never a raw `primitive.space.*` value or a numeric Tailwind class; `primitive.space.*` is the ramp behind the scale. Use `semantic.space.*` aliases (e.g. `semantic.space.surface.padding`) when the purpose is established. `data-density="compact"` (on `<html>` or the `[data-hds]` scope element) remaps `semantic.space.scale.*`, `semantic.space.surface.padding` and `semantic.space.region.gutter` one step down the scale, and `Table` follows it. The `--hds-space-{xs…4xl}` vars are a legacy bridge that no component reads.
|
|
63
64
|
<!-- auto:end:spacing -->
|
|
64
65
|
|
|
66
|
+
## Layout contract (v1)
|
|
67
|
+
|
|
68
|
+
Approved 2026-10-07. Data: `docs/guardrails/layout-contract.json`; gates: `pnpm check:layout-contract` and `pnpm check:spacing-scale` (warn mode; baseline in `docs/audits/layout-contract-baseline.md`).
|
|
69
|
+
|
|
70
|
+
1. **Sizing.** Every component declares `fill` or `hug` on each axis. Leaves hug. Input, Textarea, Select, Combobox, Table, Progress and Divider fill width. One override prop, `width="hug|fill"`, on every component. Height always hugs; stretching is the parent's job (`align="stretch"`). No component sets `h-full`, `height: 100%` or `self-*` on its root.
|
|
71
|
+
2. **Padding.** Only containers pad: Card, Surface, Alert, Callout, Dialog, Page. Compound parts (`Card.Header`, `Body`, `Footer`, `Metric`) have zero padding and the container's `gap` spaces them. Padding is `none | sm | md`, default `md`, density-aware. A padded container directly inside a padded container is an error unless the inner one is `padding="none"`.
|
|
72
|
+
3. **Spacing.** One scale, `xs…xl` (plus `none`), for every `gap` and `padding` prop. Every gap defaults to `md`. No outer margins on any component; space between siblings is the parent's `gap`.
|
|
73
|
+
4. **Primitives.** Stack, Grid, Page (absorbs Container) and Surface compose layouts. Box and Pin are escape hatches. Sidebar and Switcher fold into Stack and Grid.
|
|
74
|
+
5. **Forms.** A form control in a form context has a max width (`40rem` by default) and siblings share one width.
|
|
75
|
+
|
|
65
76
|
## Corner-Radius Policy
|
|
66
77
|
|
|
67
78
|
Shape is one knob. `semantic.radius.action` is the system's single shape value — interactive controls (buttons, inputs, badges, alerts, segmented items) all resolve to it, and Tailwind's `rounded-md` maps to it exactly so the utility and the token cannot disagree. Containers sit one step above at `rounded-lg` (`action + 4px`); `rounded-sm` (`action - 2px`) is for chrome nested inside a control. `full` is reserved for pills and circular forms, and `0px` only for intentional outer canvas or substrate boundaries, never everyday UI controls. Reshaping the whole system means overriding `role.radius` in one tenant overlay — that is how `brutalist-demo` goes square in a single value.
|
|
@@ -152,7 +163,7 @@ Every HDS card surface must conform to this anatomy exactly. No creative interpr
|
|
|
152
163
|
| Border radius | `rounded-lg` (`role.radius` + 4 px: 12 px by default, follows the tenant) | `var(--component-card-radius)`, `rounded-full`, or any hard-coded value |
|
|
153
164
|
| Padding | `var(--semantic-space-component-padding)` or `<HdsSurface padding="component">` | Raw pixel values or ad hoc insets |
|
|
154
165
|
| Shadow | Resting cards: none (`elevation.flat`). Interactive lifted state: `shadow.subtle` via `elevation.raised` | Raw `box-shadow` values, `drop-shadow`, glow, or any depth effect not bound to a role token |
|
|
155
|
-
| Title | `hds.typeStyles.
|
|
166
|
+
| Title | `hds.typeStyles.title` / `<Text variant="title">` | Any other type style for the primary card heading |
|
|
156
167
|
| Subtitle / meta | `hds.typeStyles.caption` + `var(--semantic-color-content-secondary)` | Primary content color or body size for secondary text |
|
|
157
168
|
| Hover (interactive only) | `transform: scale(1.02)` | Background fill change, border color shift, or opacity fade on hover |
|
|
158
169
|
|
|
@@ -164,7 +175,7 @@ Five patterns sit above the primitives so that every screen is composed the same
|
|
|
164
175
|
|
|
165
176
|
### Page title rule
|
|
166
177
|
|
|
167
|
-
Every screen has exactly one `PageHeader`. The page title is `
|
|
178
|
+
Every screen has exactly one `PageHeader`. The page title is `title` (24px), a fixed size with no size prop; `level` changes only the DOM heading element. `display` is reserved for marketing and landing surfaces and is never a screen title. Breadcrumb goes in the `breadcrumb` slot, one status `Badge` in `status`, screen-level actions in `actions`.
|
|
168
179
|
|
|
169
180
|
### Which one, when
|
|
170
181
|
|
|
@@ -185,7 +196,7 @@ Three more needs are props on an existing component, not components of their own
|
|
|
185
196
|
|
|
186
197
|
`Card` and `Surface` share one container radius, `rounded-lg` (`role.radius` + 4 px: 12 px by default, 4 px under `brutalist-demo`). Dialogs and alert dialogs use it too. Never read `--component-card-radius` for a container; it ignores the tenant.
|
|
187
198
|
|
|
188
|
-
`MetricTiles` has `min(tiles, 4)` columns, so a row never leaves an empty column, and every tile has one fixed min-height with the value in `
|
|
199
|
+
`MetricTiles` has `min(tiles, 4)` columns, so a row never leaves an empty column, and every tile has one fixed min-height with the value in `title`, the label in `caption` and the sub line in `caption`. Its tone comes from the fixed feedback vocabulary: `neutral | success | warning | danger | info`.
|
|
189
200
|
|
|
190
201
|
### Destructive and table sections
|
|
191
202
|
|
|
@@ -217,6 +228,6 @@ Unresolved rules that the live repo cannot yet answer confidently are tracked in
|
|
|
217
228
|
<!-- auto:start:build-meta -->
|
|
218
229
|
---
|
|
219
230
|
|
|
220
|
-
> Generated from `hirobius.tokens.json` (
|
|
231
|
+
> Generated from `hirobius.tokens.json` (389 tokens) and `public/hds-manifest.json` by `scripts/build-design-md.mjs`.
|
|
221
232
|
> Hand-edit `DESIGN.source.md`; this file (`DESIGN.md`) is overwritten by `pnpm tokens`.
|
|
222
233
|
<!-- auto:end:build-meta -->
|
package/NOTICE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
`@hirobius/design-system` is not under a single license.
|
|
4
4
|
|
|
5
5
|
- **HDS code** (components, compiled JavaScript, types, CSS, and token files): MIT. See [LICENSE](LICENSE).
|
|
6
|
-
- **Satoshi** (weights 500 and 700, by Indian Type Foundry, distributed through [Fontshare](https://www.fontshare.com/fonts/satoshi)): ITF Free Font License.
|
|
6
|
+
- **Satoshi** (weights 400, 500 and 700, by Indian Type Foundry, distributed through [Fontshare](https://www.fontshare.com/fonts/satoshi)): ITF Free Font License.
|
|
7
7
|
- **Geist Mono** (weight 400, by Vercel, [source](https://github.com/vercel/geist-font)): SIL Open Font License 1.1.
|
|
8
8
|
|
|
9
9
|
Both fonts are embedded as base64 `@font-face` data in `dist/tokens.css` and `dist/styles.css`. The MIT license does not cover them; each font keeps its own license. `dist/variables.css` embeds no fonts.
|
package/README.md
CHANGED
|
@@ -12,9 +12,9 @@ pnpm add @hirobius/design-system
|
|
|
12
12
|
|
|
13
13
|
<!-- auto:start:front-door-counts -->
|
|
14
14
|
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
15
|
+
- **53** public component modules, exported from `src/index.ts`
|
|
16
|
+
- **389** DTCG tokens in `hirobius.tokens.json`, compiled to CSS variables and TypeScript constants
|
|
17
|
+
- **341** Storybook stories in **71** story files
|
|
18
18
|
|
|
19
19
|
<!-- auto:end:front-door-counts -->
|
|
20
20
|
|
|
@@ -44,6 +44,35 @@ The Ops dashboard (`hirobius/ops`) is the only product app that uses components:
|
|
|
44
44
|
|
|
45
45
|
The numbers come from `pnpm consumer:usage --root <ops checkout>`, which measures that checkout's `src/` and records its commit in `docs/data/consumer-usage.json` (pass `--commit <sha>` when the root is a `git archive` export); without a root it reuses the committed snapshot. A deprecated alias counts as the component it points to (`HdsCheckbox` as `Checkbox`). The components that Ops's page- and video-clone prompts tell generated code to import are listed there as `promptContracts` and are not counted here. `scripts/__tests__/consumer-usage.test.mjs` fails if this section drifts from that snapshot. The product-app and token-level-site split is a declared figure in that file, not a measurement. It was confirmed on 2026-10-01 (hds#389: there is no second product app), so `consumersConfirmed` there is true and the table above shows it.
|
|
46
46
|
|
|
47
|
+
## What belongs in the system
|
|
48
|
+
|
|
49
|
+
<!-- auto:start:core-set -->
|
|
50
|
+
|
|
51
|
+
**43** components are the core set: the brand-neutral, composable surface every HDS screen is built from, and the part of the system that has to be excellent. Import them from the package root; each carries `core: true` in `public/hds-manifest.json`.
|
|
52
|
+
|
|
53
|
+
- **Actions:** `Button`
|
|
54
|
+
- **Display:** `Avatar`, `Card`, `EmptyState`, `Field`, `Icon`, `Kbd`, `Table`
|
|
55
|
+
- **Feedback:** `Alert`, `Badge`, `Progress`, `Skeleton`, `Spinner`, `ToastProvider`
|
|
56
|
+
- **Inputs:** `Checkbox`, `Combobox`, `Input`, `Radio`, `SegmentedControl`, `Select`, `Slider`, `Tag`, `Textarea`, `Toggle`
|
|
57
|
+
- **Layout:** `Box`, `Container`, `Disclosure`, `Divider`, `Grid`, `Stack`, `Surface`
|
|
58
|
+
- **Navigation:** `Breadcrumb`, `InlineLink`, `Pagination`, `Tabs`
|
|
59
|
+
- **Overlays:** `Dialog`, `Menu`, `Popover`, `Tooltip`
|
|
60
|
+
- **Theming:** `HdsRouterProvider`, `HdsThemeProvider`
|
|
61
|
+
- **Typography:** `Text`
|
|
62
|
+
- **Utility:** `VisuallyHidden`
|
|
63
|
+
|
|
64
|
+
**12** pattern modules ship from `@hirobius/design-system/patterns`, and only from there: composed surfaces that assume a product (page shells, forms, code blocks, page sections), built from the core set. One name per module; its parts and props types come with it.
|
|
65
|
+
|
|
66
|
+
`AssetImg`, `CodeBlock`, `DataTableSection`, `DestructiveSection`, `ErrorPattern`, `Form`, `FormActions`, `MetricTiles`, `Page`, `PageHeader`, `Reveal`, `StatusTile`
|
|
67
|
+
|
|
68
|
+
The package root also exports the rest of the allow-list (compound parts, and the components outside the core set; the [consumer skill](skills/hds-consumer/SKILL.md) lists them by category): reach for the core set first. 0.20.0 removed the root re-exports of the pattern modules, the docs internals and 13 components that fold into a survivor ([MIGRATIONS.md](MIGRATIONS.md#0200-removals-2026-10-01)).
|
|
69
|
+
|
|
70
|
+
Every component's disposition (core, pattern, fold or internal) is in the [architecture doc](docs/hds-architecture-2026-09-18.html), ratified 2026-09-26 in [hds#254](https://github.com/hirobius/hds/issues/254); [ADR-031](docs/adr/031-core-set-and-dispositions.md) records the decision and what has changed since.
|
|
71
|
+
|
|
72
|
+
<!-- auto:end:core-set -->
|
|
73
|
+
|
|
74
|
+
This section is generated by `pnpm readme:counts` (which `pnpm tokens` also runs) from `scripts/lib/core-components.mjs`, `src/patterns.ts` and the manifest. `scripts/__tests__/core-set.test.mjs` fails if it drifts from them.
|
|
75
|
+
|
|
47
76
|
## Using the published package
|
|
48
77
|
|
|
49
78
|
Installing HDS in another project? It ships to the **public npm registry** as
|
|
@@ -66,8 +95,9 @@ npm install @hirobius/design-system react react-dom
|
|
|
66
95
|
```
|
|
67
96
|
|
|
68
97
|
```tsx
|
|
69
|
-
// once at the app root — full bundle: tokens + theme + utilities
|
|
98
|
+
// once at the app root — full bundle: tokens + theme + utilities
|
|
70
99
|
import '@hirobius/design-system/tokens.css';
|
|
100
|
+
import '@hirobius/design-system/fonts.css'; // optional: the HDS brand fonts
|
|
71
101
|
import { Button } from '@hirobius/design-system';
|
|
72
102
|
|
|
73
103
|
// add data-hds to the root (or any section) so the scoped base styles apply
|
|
@@ -168,6 +198,8 @@ Source-of-truth files:
|
|
|
168
198
|
- `DESIGN.md` — lean visual spec for agents and engineers.
|
|
169
199
|
- `DESIGN-HANDOFF.md` — verbose visual mirror for handoff and review.
|
|
170
200
|
|
|
201
|
+
Which components belong in the system, and what happens to the rest, is decided in the [architecture doc](docs/hds-architecture-2026-09-18.html): every component is core, pattern, fold or internal, ratified 2026-09-26 in hds#254 and recorded in [ADR-031](docs/adr/031-core-set-and-dispositions.md). [What belongs in the system](#what-belongs-in-the-system) above lists the result.
|
|
202
|
+
|
|
171
203
|
Component-by-component Figma links live in [docs/DESIGN_LINKS.md](docs/DESIGN_LINKS.md), generated by `pnpm figma:links`.
|
|
172
204
|
|
|
173
205
|
## Accessibility
|
|
@@ -204,7 +236,7 @@ The gates are deterministic and need no browser or live site:
|
|
|
204
236
|
Three agents build the same Client-detail screen from the public docs, and `pnpm eval:consistency` measures how alike the results are: builds, token violations, axe, component-set overlap (Jaccard) and pixel diff. Today it runs the offline half over a directory of apps (`pnpm eval:consistency -- --apps <dir> --offline`, violations and Jaccard from source only). The ledger, the thresholds and the screen spec live in [`eval/consistency/`](eval/consistency/README.md). The latest recorded run, as printed by `pnpm eval:consistency -- --summary`:
|
|
205
237
|
|
|
206
238
|
```text
|
|
207
|
-
Agent consistency 2026-
|
|
239
|
+
Agent consistency 2026-10-05 (harness, design-system 0.20.0): FAIL - builds 3/3, violations 0, axe 0, Jaccard min 0.4091 (limit >= 0.85), light diff max 3.2096% (limit <= 1.5%)
|
|
208
240
|
```
|
|
209
241
|
|
|
210
242
|
The baseline misses its thresholds on purpose: they are not softened to make it pass.
|