@hirobius/design-system 0.23.1 → 0.24.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 CHANGED
@@ -110,7 +110,7 @@ the full engineering protocol; this section is the home for autonomous-loop rule
110
110
  ## Ralph quality bar
111
111
 
112
112
  REPO_TYPE: library
113
- QUALITY BAR: Public npm package. Backward compatibility matters. Tests + Storybook stories required.
113
+ QUALITY BAR: Public npm package. Backward compatibility matters. Tests required, and a live demo on the docs site (docs-site/components/component-demos.tsx) for a core component or pattern.
114
114
 
115
115
  Rules for any autonomous loop in this repo:
116
116
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.24.0
4
+
5
+ ### Upgrade
6
+
7
+ ```sh
8
+ npx @hirobius/design-system@latest upgrade
9
+ ```
10
+
11
+ - Do by hand: The --primitive-color-apple-100 variable is gone; use --primitive-color-graphite-100 for the same accent step.
12
+ - Do by hand: The --primitive-color-apple-200 variable is gone; use --primitive-color-graphite-200 for the same accent step.
13
+ - Do by hand: The --primitive-color-apple-300 variable is gone; use --primitive-color-graphite-300 for the same accent step.
14
+ - Do by hand: The --primitive-color-apple-400 variable is gone; use --primitive-color-graphite-400 for the same accent step.
15
+ - And 31 more: see [UPGRADING.md](https://github.com/hirobius/hds/blob/main/UPGRADING.md#0240).
16
+
17
+ ### Minor Changes
18
+
19
+ - 72800bc: feat(brand): change the default accent from apple green to graphite (warm charcoal).
20
+
21
+ The base brand accent moves from the bright apple green shipped in 0.23.0 to a warm
22
+ graphite — a full-monochrome accent that reads calmer and more considered. A new
23
+ `primitive.color.graphite` scale replaces `primitive.color.apple`; feedback hues
24
+ (`green`/`red`/`amber` for success/danger/warning) are untouched, so the system stays
25
+ monochrome without flattening its status colors.
26
+ - `semantic.accent.{rest,hover,pressed,content,contentHover,subtle}`, `semantic.color.surface.accent`/`accentSubtle`, `semantic.color.content.accent`, and `semantic.color.border.accent` now resolve through `primitive.color.graphite.*`.
27
+ - The accent **inverts per theme** so fills never vanish on a dark page: a dark graphite step in light mode (near-white on-accent text) and a light warm-grey step in dark mode (dark on-accent text). `semantic.color.content.onAccent` flips to `neutral.50` in light mode and `graphite.900` in dark mode — `content.onAccent / surface.accent` is 10.5:1 light / 10.0:1 dark.
28
+ - Per-tenant accents are unchanged: `accent-lilac` and `concrete-creations` set their own accent (and their own `onAccent`); `brutalist-demo` inherits the new graphite base.
29
+
30
+ The `--primitive-color-apple-*` CSS variables (introduced in 0.23.0) are removed in favor of `--primitive-color-graphite-*`; consumers who referenced a raw accent primitive should repoint to the graphite scale, though the semantic accent tokens are the intended surface and the per-tenant accent knob is unchanged — set your own accent overlay to override the base.
31
+
32
+ ### Patch Changes
33
+
34
+ - 72800bc: fix(theming): the font dial now works.
35
+
36
+ Setting `--hds-font-family` / `--hds-font-family-mono` (or `<HdsThemeProvider fontFamily fontFamilyMono>`) used to change nothing: the type roles were resolved once on `:root`, so descendants inherited the default stack. They are now re-declared on each element of the `[data-hds]` subtree, so the dial applies at whatever scope you set it — headings, body, UI text, captions, code, and the JS style objects (`hds.fontFamily`, `hds.typeStyles`) all follow it. With no override, nothing changes: the default is still the brand typeface.
37
+
38
+ - 72800bc: feat(tokens): add a reserved mauve primitive scale.
39
+
40
+ `primitive.color.mauve.{50…950}` (anchor `#734B5E` at 500) is added alongside graphite, lightness-matched to it step for step. Nothing maps to it yet: graphite stays the brand accent, and no semantic or component token reads mauve. It is available as `--primitive-color-mauve-*` for exploration.
41
+
42
+ ## 0.23.2
43
+
44
+ ### Upgrade
45
+
46
+ ```sh
47
+ npx @hirobius/design-system@latest upgrade
48
+ ```
49
+
50
+ - Looks different: The disabled primary Button fill is now the muted surface instead of the accent-subtle surface.
51
+ - Looks different: The disabled primary Button text is now the disabled content colour instead of the on-accent colour.
52
+ - Every step is also in [UPGRADING.md](https://github.com/hirobius/hds/blob/main/UPGRADING.md#0232).
53
+
54
+ ### Patch Changes
55
+
56
+ - b2ebd7d: A disabled primary Button now reads as a neutral muted button in light and dark: `component.button.primary.bgDisabled` points at `semantic.color.surface.muted` and `textDisabled` at `semantic.color.content.disabled` (they were `accentSubtle` and `onAccent`, which assumed a coloured accent), and Button binds those tokens. The small Button's icon is 12px, as its `component.button.size.sm.iconSize` token says (it was 14px); medium and large are unchanged at 16px and 20px.
57
+ - 4626131: Storybook is gone from the repo (retirement, step 3): the `storybook` package keyword, the story files, the Storybook config and the Storybook-only scripts are removed. The docs site is the visual verification surface. Nothing for a consumer to change.
58
+ - 9f1acfc: The manifest (`public/hds-manifest.json`) points each core component and pattern at its docs-site page with `docsPage` (for example `/docs/components/button`), replacing `storyFiles` and `storyIds`. `AGENTS.md` and the llms files now point agents at the docs site instead of the Storybook stories.
59
+
3
60
  ## 0.23.1
4
61
 
5
62
  ### Upgrade
package/DESIGN.md CHANGED
@@ -6,14 +6,14 @@ A machine- and human-readable specification of the Hirobius Design System for AI
6
6
 
7
7
  ## Overview
8
8
 
9
- Hirobius is a clean, systems-first visual language that bridges digital precision and physical fabrication through a high-contrast monochromatic neutral palette and a single accent that each tenant sets — a bright apple green by default. Its personality is disciplined, tactile, and quietly technical: structure is explicit, motion is purposeful, and visual noise is stripped away. Whitespace is treated as material, not leftover space, so every screen should feel deliberate, breathable, and exact.
9
+ Hirobius is a clean, structured visual language that bridges digital precision and physical fabrication through a high-contrast monochromatic neutral palette and a single accent that each tenant sets — a warm graphite by default. Its personality is disciplined, tactile, and quietly technical: structure is explicit, motion is purposeful, and visual noise is stripped away. Whitespace is treated as material, not leftover space, so every screen should feel deliberate, breathable, and exact.
10
10
 
11
11
  ## Colors
12
12
 
13
13
  <!-- auto:start:colors -->
14
14
  **One accent — one neutral system.**
15
15
 
16
- - **Accent** (`#66B239`): CTAs, active states, selected focus rings, and the single brand accent. `semantic.accent.rest` — a per-tenant knob, not a fixed hue (#208).
16
+ - **Accent** (`#433A3F`): CTAs, active states, selected focus rings, and the single brand accent. `semantic.accent.rest` — a per-tenant knob, not a fixed hue (#208).
17
17
  - **Neutral**: backgrounds, surfaces, borders, text. True monochromatic — `primitive.color.neutral.50` through `950`. Use `semantic.color.surface.*`, `semantic.color.content.*`, `semantic.color.border.*`; never reach directly for primitives in components.
18
18
  - **Feedback — Error** (`#B91C1C`): destructive confirms, error banners, validation failures. `semantic.color.feedback.error`.
19
19
  - **Feedback — Success** (`#047857`): positive confirmations, completed states. `semantic.color.feedback.success`.
@@ -26,10 +26,9 @@ Feedback hues are never decorative; do not use them as accents. Light and dark m
26
26
  ## Typography
27
27
 
28
28
  <!-- auto:start:typography -->
29
- HDS ships three typefaces — each with a distinct and exclusive role:
29
+ HDS ships two typefaces:
30
30
 
31
- - **Display / Heading font**: Plus Jakarta Sans. Bound exclusively to the `display` and `title` styles. Never used for body copy or UI labels.
32
- - **Body / UI font**: Plus Jakarta Sans. All prose, labels, small text, captions, and UI copy.
31
+ - **Text font**: Plus Jakarta Sans. Headings, prose, labels, captions, and UI copy; the type roles set size and weight.
33
32
  - **Mono font**: IBM Plex Mono. Reserved for tokens, code, technical callouts, and metric readouts.
34
33
 
35
34
  Weights declared: `400` regular, `500` medium, `700` bold. Heading styles (display · title) use `700` bold; body, UI, and caption use `400` regular / `500` medium.
@@ -65,7 +64,7 @@ Layout rhythm, padding, and gaps use the `semantic.space.scale.{xs…xl}` steps
65
64
 
66
65
  ## Layout contract (v1)
67
66
 
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`).
67
+ Approved 2026-10-07 as the **target**; adoption is in progress, so some components below (Container, Sidebar, Switcher) still ship until they fold in. 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
68
 
70
69
  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
70
  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"`.
@@ -209,7 +208,7 @@ Three more needs are props on an existing component, not components of their own
209
208
  ## Do's and Don'ts
210
209
 
211
210
  - Don't invent new corner behavior for interactive controls; buttons, inputs, disclosures, and similar action surfaces should follow the shared action radius (`semantic.radius.action`).
212
- - Don't introduce additional accent hues; Hirobius uses exactly one accent, resolved from `semantic.accent.rest`, over a true monochromatic neutral system. The accent is a per-tenant knob (#208) and defaults to a bright apple green — read the token, never assume a hue.
211
+ - Don't introduce additional accent hues; Hirobius uses exactly one accent, resolved from `semantic.accent.rest`, over a true monochromatic neutral system. The accent is a per-tenant knob and defaults to a warm graphite — read the token, never assume a hue.
213
212
  - Don't tint neutrals warm or cool; greys should remain genuinely neutral and high-contrast.
214
213
  - Don't reach for shadow values directly — bind to a `semantic.elevation.*` role so surface + shadow + border stay paired. Cards default to `flat` (border, no shadow). Popovers/tooltips/dropdowns use `floating`. Dialogs/sheets use `overlay`.
215
214
  - Don't hardcode colors, spacing, radius, or typography values when governed tokens already exist.
@@ -223,11 +222,11 @@ Three more needs are props on an existing component, not components of their own
223
222
 
224
223
  ## Open Questions
225
224
 
226
- Unresolved rules that the live repo cannot yet answer confidently are tracked in [`OPEN_DS_QUESTIONS.md`](OPEN_DS_QUESTIONS.md). Do not invent rules here to fill those gaps.
225
+ Unresolved rules that the live repo cannot yet answer confidently are tracked as GitHub issues. Do not invent rules here to fill those gaps.
227
226
 
228
227
  <!-- auto:start:build-meta -->
229
228
  ---
230
229
 
231
- > Generated from `hirobius.tokens.json` (400 tokens) and `public/hds-manifest.json` by `scripts/build-design-md.mjs`.
230
+ > Generated from `hirobius.tokens.json` (411 tokens) and `public/hds-manifest.json` by `scripts/build-design-md.mjs`.
232
231
  > Hand-edit `DESIGN.source.md`; this file (`DESIGN.md`) is overwritten by `pnpm tokens`.
233
232
  <!-- auto:end:build-meta -->
package/README.md CHANGED
@@ -13,46 +13,47 @@ pnpm add @hirobius/design-system
13
13
 
14
14
  Upgrading: [UPGRADING.md](UPGRADING.md) lists what each release asks of you. From 0.22.0, `npx @hirobius/design-system@latest upgrade` does it for you.
15
15
 
16
- [![Buttons under the Brand and Theme dials: base and accent-lilac, light and dark](docs/images/storybook-brand-theme-dials.png)](https://hirobius-hds-components.vercel.app)
16
+ [![Buttons under the Brand and Theme dials: base and accent-lilac, light and dark](docs/images/brand-theme-dials.png)](https://hirobius-hds-components.vercel.app)
17
17
 
18
18
  <!-- auto:start:front-door-counts -->
19
19
 
20
20
  - **53** public component modules, exported from `src/index.ts`
21
- - **400** DTCG tokens in `hirobius.tokens.json`, compiled to CSS variables and TypeScript constants
22
- - **341** Storybook stories in **71** story files
21
+ - **411** DTCG tokens in `hirobius.tokens.json`, compiled to CSS variables and TypeScript constants
23
22
 
24
23
  <!-- auto:end:front-door-counts -->
25
24
 
26
25
  What the system includes:
27
26
 
28
27
  - **Token pipeline.** DTCG tokens in `hirobius.tokens.json` compile to CSS variables and TypeScript constants through a validated alias chain, with AA-contrast gates in light and dark.
29
- - **Gates with proof-of-firing.** Typecheck, zero-warning ESLint, token validity and contrast, Vitest unit and contract tests, bundle budgets, a consumer smoke build, and a Storybook build — run in git hooks and CI. Many gates carry a passing and a violating fixture that demonstrate the gate catches what it describes.
28
+ - **Gates with proof-of-firing.** Typecheck, zero-warning ESLint, token validity and contrast, Vitest unit and contract tests, and a consumer smoke build run in git hooks and CI; bundle budgets and a docs-site accessibility (axe) gate run in CI. Many gates carry a passing and a violating fixture that demonstrate the gate catches what it describes.
30
29
  - **Upgrade path.** A release ledger and one consumer command: `npx @hirobius/design-system@latest upgrade`.
31
30
  - **One-way Figma sync.** Code is the source of truth; tokens project into Figma, and `pnpm check:figma-drift` compares a committed snapshot against the model.
32
31
  - **Theming without JavaScript.** Four root attributes — theme, density, brand, font — re-skin HDS descendants through CSS variables.
33
32
 
34
33
  The counts are generated from source by `pnpm readme:counts`, which `pnpm tokens` also runs. `scripts/__tests__/front-door.test.mjs` fails if this README claims more than the source has.
35
34
 
35
+ **How it's built:** [How HDS is engineered](docs/ENGINEERING.md) walks the token pipeline, the quality gates (and how they're proven to fire), testing, release and upgrade, and Figma sync.
36
+
36
37
  Agents: install the consumer skill with `npx skills add hirobius/hds --skill hds-consumer` (see `docs/CONSUMING.md`, "Agent skill").
37
38
 
38
39
  ## In use
39
40
 
40
41
  <!-- auto:start:consumer-usage -->
41
42
 
42
- The Ops dashboard (`hirobius/ops`) is the only product app that uses components: **33** of its source files import from `@hirobius/design-system`, using **25** distinct components. The two screenshots below are Ops pages rendered from its `main` (measured at commit `76ef65e`).
43
+ An internal operations dashboard is the only product app that uses components: **33** of its source files import from `@hirobius/design-system`, using **25** distinct components. The two screenshots below are pages of that app, rendered from its `main` branch.
43
44
 
44
45
  | Consumer kind | Count | How it uses HDS |
45
46
  | ----------------- | ----- | ----------------------------------------- |
46
47
  | Product apps | 1 | Components and tokens |
47
48
  | Token-level sites | 4 | Tokens and CSS only, no component imports |
48
49
 
49
- [![Ops library page](docs/images/ops-library.png)](docs/images/ops-library.png)
50
+ [![Library page of the product app](docs/images/product-app-library.png)](docs/images/product-app-library.png)
50
51
 
51
- [![Ops fleet audit page](docs/images/ops-fleet-audit.png)](docs/images/ops-fleet-audit.png)
52
+ [![Audit page of the product app](docs/images/product-app-audit.png)](docs/images/product-app-audit.png)
52
53
 
53
54
  <!-- auto:end:consumer-usage -->
54
55
 
55
- 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.
56
+ The numbers come from `pnpm consumer:usage --root <consumer 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 the app'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 (there is no second product app), so `consumersConfirmed` there is true and the table above shows it.
56
57
 
57
58
  ## What belongs in the system
58
59
 
@@ -178,7 +179,7 @@ What each Figma plan allows, and the Pro-plan architecture this follows, are in
178
179
  pnpm install
179
180
  # Generated data files are gitignored; create them once (the same step CI runs):
180
181
  node scripts/generate-manifest.mjs && node scripts/generate-component-api.mjs && node scripts/enrich-manifest.mjs && node scripts/sync-icons.mjs && node scripts/audit-tokens.mjs --full
181
- pnpm storybook # component workbench on http://localhost:6006
182
+ pnpm docs:dev # docs site (component pages with live demos)
182
183
  ```
183
184
 
184
185
  Core verification commands:
@@ -189,7 +190,7 @@ pnpm lint
189
190
  pnpm test # pretest gates + unit + contract tests, exactly as the pre-push hook and CI run them
190
191
  pnpm tokens:verify
191
192
  pnpm check:size
192
- pnpm build-storybook
193
+ pnpm docs:publish # docs-site build, then: node scripts/check-docs-axe.mjs
193
194
  ```
194
195
 
195
196
  ## Architecture
@@ -219,7 +220,6 @@ What CI and the hooks check today, and nothing more:
219
220
  - **Contrast:** `scripts/check-contrast.mjs` enforces WCAG AA contrast on the core token pairs, in light and dark. It runs in CI and the pre-commit hook.
220
221
  - **Lint:** `jsx-a11y` rules run inside ESLint with zero warnings allowed.
221
222
  - **Focus:** `scripts/check-focus-states.mjs` (`pnpm check:focus`) audits focus styles on interactive components. It runs in `pretest` under `pnpm test`, so in the pre-push hook and in CI, and passes with 0 violations.
222
- - **Storybook:** the `addon-a11y` panel shows axe results for each story while you review it. The gate is `scripts/check-storybook-axe.mjs`: CI scans every built story in light and dark, including the open Select and Combobox, and fails on serious or critical violations outside its allowlist (`scripts/axe-allowlist.json`). The allowlist has one entry: `aria-hidden-focus` on the open Select story, where Radix Select hides the page around its listbox while focus stays trapped inside it (hds#407).
223
223
  - **Docs site:** `scripts/check-docs-axe.mjs` (`pnpm check:docs-axe`, after `pnpm docs:publish`) scans the live demo of every `/docs/components/*` and `/docs/patterns/*` page of the built docs site in light and dark with the same axe rules, scoped to the demo frame so the Fumadocs chrome does not count. CI runs it and fails on serious or critical violations outside `scripts/docs-axe-allowlist.json`, which is empty.
224
224
 
225
225
  Screen-reader output is checked by `tests/primitive-contracts/screen-reader.contract.test.tsx`, which runs in `pnpm test` and walks Dialog, Menu, Select, Combobox, Table and Alert with a virtual screen-reader (`@guidepup/virtual-screen-reader`) under jsdom, asserting the role, name and state phrases it reads and the alert's live-region announcement; it reads the jsdom accessibility tree, not what a desktop or mobile screen-reader says.
@@ -237,10 +237,10 @@ The governing direction is "Editorial Enterprise" — enterprise rigor with edit
237
237
 
238
238
  The gates are deterministic and need no browser or live site:
239
239
 
240
- - **pre-commit** (`.husky/pre-commit`): secrets scan, Prettier on staged files, typecheck, zero-warning ESLint, and token validity and contrast.
240
+ - **pre-commit** (`.husky/pre-commit`): secrets scan (when `gitleaks` is installed locally; not yet in CI), Prettier on staged files, typecheck, zero-warning ESLint, and token validity and contrast.
241
241
  - **pre-push** (`.husky/pre-push`): `pnpm test` (the pretest gates, then Vitest unit and contract tests), then the consumer smoke build (library build, subpath resolution, publint, consumer typecheck).
242
- - **CI** (`.github/workflows/ci.yml`): typecheck, zero-warning ESLint, token validity and contrast, Vitest, and the consumer smoke build, plus bundle budgets and a Storybook build.
243
- - **Visual review:** Storybook is the visual verification surface, reviewed by hand. The earlier browser test suite drove a docs site that no longer exists and was removed (ADR-018).
242
+ - **CI** (`.github/workflows/ci.yml`): typecheck, zero-warning ESLint, token validity and contrast, Vitest, and the consumer smoke build, plus bundle budgets and the docs-site build with its axe gate.
243
+ - **Visual review:** the docs site (`docs-site/`) is the visual verification surface: every core component and pattern has a page with a live demo, `check-docs-axe` gates its accessibility.
244
244
 
245
245
  ### Agent consistency
246
246
 
@@ -265,18 +265,26 @@ Releases are cut with [Changesets](https://github.com/changesets/changesets). A
265
265
  ```text
266
266
  src/
267
267
  app/
268
- components/
269
- layouts/
270
- pages/
271
- styles/
272
- scripts/
273
- docs/
274
- public/
268
+ components/ the components
269
+ context/ theme provider
270
+ design-system/ generated token constants
271
+ styles/ tokens.css, theme.css, generated CSS
272
+ brand/ form/ mui/ scroll/ subpath entry points
273
+ hirobius.tokens.json the single token source
274
+ scripts/ generators and gates
275
+ codemods/ the upgrade command and its codemods
276
+ mcp/ the MCP server shipped in the package
277
+ docs-site/ the documentation site
278
+ content/ docs-site pages
279
+ eval/ agent-consistency eval
280
+ docs/ ADRs, ENGINEERING.md, guardrail registry
281
+ public/ manifest, llms.txt
275
282
  ```
276
283
 
277
284
  ## Primary docs
278
285
 
279
286
  - [`docs/CONSUMING.md`](docs/CONSUMING.md) — installing & using the published package
287
+ - [`docs/ENGINEERING.md`](docs/ENGINEERING.md) — how the system is built (pipeline, gates, release, Figma sync)
280
288
  - `CLAUDE.md` — agent operating contract
281
289
  - `DESIGN.md` — lean visual spec
282
290
  - `DESIGN-HANDOFF.md` — verbose visual mirror
package/UPGRADING.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Upgrading @hirobius/design-system
2
2
 
3
- This file only knows the releases up to the version you have installed, 0.23.1. For newer releases, run `npx @hirobius/design-system@latest upgrade`: it always fetches the newest steps.
3
+ This file only knows the releases up to the version you have installed, 0.24.0. For newer releases, run `npx @hirobius/design-system@latest upgrade`: it always fetches the newest steps.
4
4
 
5
5
  ## How to upgrade
6
6
 
@@ -10,6 +10,60 @@ npx @hirobius/design-system@latest upgrade
10
10
 
11
11
  It finds the version you have, moves you to the newest release, runs each release's codemods (Fixed for you) and lists what is left for you (Do by hand). It works from 0.16.0 on; from an older version, first reach 0.16.0 with the notes in CHANGELOG.md. MIGRATIONS.md has longer guides for the big releases.
12
12
 
13
+ ## 0.24.0
14
+
15
+ Released 2026-10-12 (minor). 11 changes to make by hand (11 breaking) and 24 that look different.
16
+
17
+ ### Looks different
18
+
19
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
20
+ - This variable now follows the code-font dial (--hds-font-family-mono) at any scope; if you overrode it directly, override the dial instead.
21
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
22
+ - Accent-intent text and icons (such as links) now render in graphite instead of a dark apple green.
23
+ - Hovered accent text now shifts within the graphite scale instead of toward a darker apple green.
24
+ - The accent fill on hover is now a deeper graphite (light mode) or lighter warm-grey (dark mode) instead of a green.
25
+ - The accent fill while pressed is now a darker graphite (light mode) or lighter warm-grey (dark mode) instead of a green.
26
+ - Interactive accent fills at rest (primary buttons, selected controls) now render in warm graphite — a dark fill in light mode and a light warm-grey fill in dark mode — instead of a bright apple green.
27
+ - The low-emphasis accent tint (hover and selection backgrounds) is now a faint graphite tint instead of a faint apple green.
28
+ - Accent borders now render in graphite instead of apple green.
29
+ - Accent-intent text and icons on page and card surfaces now render in graphite instead of a dark apple green.
30
+ - Text and icons on accent fills are now near-white in light mode and dark graphite in dark mode (the fill inverts per theme), instead of a dark neutral in both modes.
31
+ - Accent background surfaces now render in warm graphite that inverts per theme instead of a bright apple green.
32
+ - Faint accent background surfaces are now a pale graphite tint instead of a pale apple green.
33
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
34
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
35
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
36
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
37
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
38
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
39
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
40
+ - This variable now follows the code-font dial (--hds-font-family-mono) at any scope; if you overrode it directly, override the dial instead.
41
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
42
+ - This variable now follows the font dial (--hds-font-family) at any scope; if you overrode it directly, override the dial instead.
43
+
44
+ ### Do by hand
45
+
46
+ - The --primitive-color-apple-100 variable is gone; use --primitive-color-graphite-100 for the same accent step.
47
+ - The --primitive-color-apple-200 variable is gone; use --primitive-color-graphite-200 for the same accent step.
48
+ - The --primitive-color-apple-300 variable is gone; use --primitive-color-graphite-300 for the same accent step.
49
+ - The --primitive-color-apple-400 variable is gone; use --primitive-color-graphite-400 for the same accent step.
50
+ - The --primitive-color-apple-50 variable is gone; use --primitive-color-graphite-50 for the same lightest accent step.
51
+ - The --primitive-color-apple-500 variable is gone; use --primitive-color-graphite-500 (or a semantic accent token) instead.
52
+ - The --primitive-color-apple-600 variable is gone; use --primitive-color-graphite-600 for the same accent step.
53
+ - The --primitive-color-apple-700 variable is gone; use --primitive-color-graphite-700 for the rest accent step.
54
+ - The --primitive-color-apple-800 variable is gone; use --primitive-color-graphite-800 for the same accent step.
55
+ - The --primitive-color-apple-900 variable is gone; use --primitive-color-graphite-900 for the same accent step.
56
+ - The --primitive-color-apple-950 variable is gone; use --primitive-color-graphite-950 for the darkest accent step.
57
+
58
+ ## 0.23.2
59
+
60
+ Released 2026-10-11 (patch). 2 that look different.
61
+
62
+ ### Looks different
63
+
64
+ - The disabled primary Button fill is now the muted surface instead of the accent-subtle surface.
65
+ - The disabled primary Button text is now the disabled content colour instead of the on-accent colour.
66
+
13
67
  ## 0.23.1
14
68
 
15
69
  Released 2026-10-11 (patch). 6 that look different.
@@ -46,7 +46,6 @@ const SKIP_DIRS = new Set([
46
46
  '.next',
47
47
  '.vercel',
48
48
  'coverage',
49
- 'storybook-static',
50
49
  ]);
51
50
 
52
51
  /** The aliases 0.19.1 exported from the root, and the bare name each pointed at. */
@@ -40,7 +40,6 @@ const SKIP_DIRS = new Set([
40
40
  '.next',
41
41
  '.vercel',
42
42
  'coverage',
43
- 'storybook-static',
44
43
  ]);
45
44
  const ID = String.raw`[A-Za-z_$][\w$]*`;
46
45
  const esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@@ -28,7 +28,6 @@ export const SKIP_DIRS = new Set([
28
28
  '.turbo',
29
29
  '.svelte-kit',
30
30
  'coverage',
31
- 'storybook-static',
32
31
  ]);
33
32
 
34
33
  const CODE = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.mts', '.cts', '.mdx']);
@@ -59,7 +59,6 @@ const SKIP_DIRS = new Set([
59
59
  '.next',
60
60
  '.vercel',
61
61
  'coverage',
62
- 'storybook-static',
63
62
  ]);
64
63
 
65
64
  export function loadPatternNames() {
@@ -128,7 +128,7 @@ const Ne = {
128
128
  spacious: "var(--semantic-space-layout-spacious)"
129
129
  },
130
130
  numbers: "units"
131
- }, j = (t, e) => Object.prototype.hasOwnProperty.call(t, e) ? t[e] : void 0, _e = {
131
+ }, z = (t, e) => Object.prototype.hasOwnProperty.call(t, e) ? t[e] : void 0, _e = {
132
132
  tight: "sm",
133
133
  normal: "md",
134
134
  inset: "lg",
@@ -153,7 +153,7 @@ const Ne = {
153
153
  columnGap: ["column-gap"]
154
154
  };
155
155
  function $(t, e) {
156
- return "closed" in e ? typeof t == "string" ? j(e.names, t) : void 0 : typeof t == "number" ? e.numbers === "raw" ? t : Re.has(t) ? `var(--primitive-space-${t})` : `calc(var(--primitive-space-1) * ${t})` : j(e.names, t) ?? t;
156
+ return "closed" in e ? typeof t == "string" ? z(e.names, t) : void 0 : typeof t == "number" ? e.numbers === "raw" ? t : Re.has(t) ? `var(--primitive-space-${t})` : `calc(var(--primitive-space-1) * ${t})` : z(e.names, t) ?? t;
157
157
  }
158
158
  const Oe = {
159
159
  color: "color",
@@ -161,7 +161,7 @@ const Oe = {
161
161
  borderColor: "border-color",
162
162
  fill: "fill",
163
163
  stroke: "stroke"
164
- }, $e = /* @__PURE__ */ new Set(["primary", "secondary", "disabled", "inverse", "accent"]), Ie = /* @__PURE__ */ new Set(["page", "raised", "overlay", "accent"]), Le = /* @__PURE__ */ new Set(["default", "subtle", "subdued", "strong", "accent"]), je = /* @__PURE__ */ new Set(["success", "warning", "error", "info"]), ze = /* @__PURE__ */ new Set(["hover", "pressed", "subtle", "content"]);
164
+ }, $e = /* @__PURE__ */ new Set(["primary", "secondary", "disabled", "inverse", "accent"]), Ie = /* @__PURE__ */ new Set(["page", "raised", "overlay", "accent"]), Le = /* @__PURE__ */ new Set(["default", "subtle", "subdued", "strong", "accent"]), ze = /* @__PURE__ */ new Set(["success", "warning", "error", "info"]), je = /* @__PURE__ */ new Set(["hover", "pressed", "subtle", "content"]);
165
165
  function Me(t) {
166
166
  if (t === "accent") return "var(--semantic-accent-rest)";
167
167
  const e = t.indexOf(".");
@@ -170,8 +170,8 @@ function Me(t) {
170
170
  if (r === "content" && $e.has(n)) return `var(--semantic-color-content-${n})`;
171
171
  if (r === "surface" && Ie.has(n)) return `var(--semantic-color-surface-${n})`;
172
172
  if (r === "border" && Le.has(n)) return `var(--semantic-color-border-${n})`;
173
- if (r === "feedback" && je.has(n)) return `var(--semantic-color-feedback-${n})`;
174
- if (r === "accent" && ze.has(n)) return `var(--semantic-accent-${n})`;
173
+ if (r === "feedback" && ze.has(n)) return `var(--semantic-color-feedback-${n})`;
174
+ if (r === "accent" && je.has(n)) return `var(--semantic-accent-${n})`;
175
175
  }
176
176
  function Be(t) {
177
177
  return t.replace(/[A-Z]/g, (e) => `-${e.toLowerCase()}`);
@@ -179,7 +179,7 @@ function Be(t) {
179
179
  function W(t, e) {
180
180
  const r = Pe[t];
181
181
  if (r) {
182
- const c = typeof e == "string" ? j(_e, e) : void 0;
182
+ const c = typeof e == "string" ? z(_e, e) : void 0;
183
183
  c && Ae(
184
184
  `box-sx-spacing-${e}`,
185
185
  `Box sx spacing name '${e}' is deprecated (hds#206) and is removed in 1.0.0. Use '${c}': same pixels at the default density, tighter under compact (MIGRATIONS.md).`
@@ -237,8 +237,8 @@ function Ge(t, e) {
237
237
  }
238
238
  return d;
239
239
  }
240
- function z(t) {
241
- return t === void 0 ? "undefined" : t === null || typeof t != "object" ? JSON.stringify(t) : Array.isArray(t) ? `[${t.map(z).join(",")}]` : `{${Object.keys(t).sort().map((r) => `${JSON.stringify(r)}:${z(t[r])}`).join(",")}}`;
240
+ function j(t) {
241
+ return t === void 0 ? "undefined" : t === null || typeof t != "object" ? JSON.stringify(t) : Array.isArray(t) ? `[${t.map(j).join(",")}]` : `{${Object.keys(t).sort().map((r) => `${JSON.stringify(r)}:${j(t[r])}`).join(",")}}`;
242
242
  }
243
243
  function He(t) {
244
244
  let e = 5381;
@@ -247,7 +247,7 @@ function He(t) {
247
247
  return (e >>> 0).toString(36);
248
248
  }
249
249
  function Ke(t) {
250
- return `hds-sx-${He(z(t))}`;
250
+ return `hds-sx-${He(j(t))}`;
251
251
  }
252
252
  const U = /* @__PURE__ */ new Set();
253
253
  let T = null;
@@ -273,7 +273,7 @@ function Xt(t) {
273
273
  return e;
274
274
  }
275
275
  const Ue = /* @__PURE__ */ E(
276
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md transition-[colors,filter] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:bg-muted disabled:text-[var(--semantic-color-content-disabled)] active:inset-shadow-[0_0_0_9999px] active:inset-shadow-pressed-overlay/5 [&_svg]:pointer-events-none [&_svg]:shrink-0",
276
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md transition-[colors,filter] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:bg-[var(--component-button-primary-bgDisabled)] disabled:text-[var(--component-button-primary-textDisabled)] active:inset-shadow-[0_0_0_9999px] active:inset-shadow-pressed-overlay/5 [&_svg]:pointer-events-none [&_svg]:shrink-0",
277
277
  {
278
278
  variants: {
279
279
  variant: {
@@ -307,9 +307,9 @@ const Ue = /* @__PURE__ */ E(
307
307
  info: "border-transparent bg-feedback-bg-info text-feedback-info hover:bg-feedback-bg-info hover:border-transparent hover:brightness-95 dark:hover:brightness-110"
308
308
  },
309
309
  size: {
310
- sm: "h-8 px-3 hds-type-caption [&_svg]:size-3.5",
311
- md: "h-10 px-4 py-2 hds-type-ui [&_svg]:size-4",
312
- lg: "h-12 px-6 hds-type-ui [&_svg]:size-5"
310
+ sm: "h-8 px-3 hds-type-caption [&_svg]:size-[var(--component-button-size-sm-iconSize)]",
311
+ md: "h-10 px-4 py-2 hds-type-ui [&_svg]:size-[var(--component-button-size-md-iconSize)]",
312
+ lg: "h-12 px-6 hds-type-ui [&_svg]:size-[var(--component-button-size-lg-iconSize)]"
313
313
  },
314
314
  iconOnly: {
315
315
  true: "p-0",
@@ -1171,7 +1171,7 @@ const Tt = A.Trigger, ie = /* @__PURE__ */ se(A.Portal), _t = A.Action, Pt = A.C
1171
1171
  );
1172
1172
  }), Lt = /* @__PURE__ */ h.forwardRef(function({ className: e, children: r, ...n }, a) {
1173
1173
  return /* @__PURE__ */ s(A.Title, { asChild: !0, children: /* @__PURE__ */ s(I, { ref: a, as: "h2", variant: "title", className: e, ...n, children: r }) });
1174
- }), jt = /* @__PURE__ */ h.forwardRef(function({ className: e, children: r, ...n }, a) {
1174
+ }), zt = /* @__PURE__ */ h.forwardRef(function({ className: e, children: r, ...n }, a) {
1175
1175
  return /* @__PURE__ */ s(A.Description, { asChild: !0, children: /* @__PURE__ */ s(
1176
1176
  I,
1177
1177
  {
@@ -1191,7 +1191,7 @@ const Tt = A.Trigger, ie = /* @__PURE__ */ se(A.Portal), _t = A.Action, Pt = A.C
1191
1191
  Header: $t,
1192
1192
  Footer: It,
1193
1193
  Title: Lt,
1194
- Description: jt,
1194
+ Description: zt,
1195
1195
  Action: _t,
1196
1196
  Cancel: Pt,
1197
1197
  // Set here, not by a later `AlertDialog.displayName = …` write: a top-level