@hirobius/design-system 0.23.1 → 0.23.2

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,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.23.2
4
+
5
+ ### Upgrade
6
+
7
+ ```sh
8
+ npx @hirobius/design-system@latest upgrade
9
+ ```
10
+
11
+ - Looks different: The disabled primary Button fill is now the muted surface instead of the accent-subtle surface.
12
+ - Looks different: The disabled primary Button text is now the disabled content colour instead of the on-accent colour.
13
+ - Every step is also in [UPGRADING.md](https://github.com/hirobius/hds/blob/main/UPGRADING.md#0232).
14
+
15
+ ### Patch Changes
16
+
17
+ - 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.
18
+ - 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.
19
+ - 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.
20
+
3
21
  ## 0.23.1
4
22
 
5
23
  ### Upgrade
package/README.md CHANGED
@@ -13,20 +13,19 @@ 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
21
  - **400** DTCG tokens in `hirobius.tokens.json`, compiled to CSS variables and TypeScript constants
22
- - **341** Storybook stories in **71** story files
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, bundle budgets, a consumer smoke build, and a docs-site build with an axe gate — run in git hooks and 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.
@@ -178,7 +177,7 @@ What each Figma plan allows, and the Pro-plan architecture this follows, are in
178
177
  pnpm install
179
178
  # Generated data files are gitignored; create them once (the same step CI runs):
180
179
  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
180
+ pnpm docs:dev # docs site (component pages with live demos)
182
181
  ```
183
182
 
184
183
  Core verification commands:
@@ -189,7 +188,7 @@ pnpm lint
189
188
  pnpm test # pretest gates + unit + contract tests, exactly as the pre-push hook and CI run them
190
189
  pnpm tokens:verify
191
190
  pnpm check:size
192
- pnpm build-storybook
191
+ pnpm docs:publish # docs-site build, then: node scripts/check-docs-axe.mjs
193
192
  ```
194
193
 
195
194
  ## Architecture
@@ -219,7 +218,6 @@ What CI and the hooks check today, and nothing more:
219
218
  - **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
219
  - **Lint:** `jsx-a11y` rules run inside ESLint with zero warnings allowed.
221
220
  - **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
221
  - **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
222
 
225
223
  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.
@@ -239,8 +237,8 @@ The gates are deterministic and need no browser or live site:
239
237
 
240
238
  - **pre-commit** (`.husky/pre-commit`): secrets scan, Prettier on staged files, typecheck, zero-warning ESLint, and token validity and contrast.
241
239
  - **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).
240
+ - **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.
241
+ - **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
242
 
245
243
  ### Agent consistency
246
244
 
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.23.2. 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,15 @@ 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.23.2
14
+
15
+ Released 2026-10-11 (patch). 2 that look different.
16
+
17
+ ### Looks different
18
+
19
+ - The disabled primary Button fill is now the muted surface instead of the accent-subtle surface.
20
+ - The disabled primary Button text is now the disabled content colour instead of the on-accent colour.
21
+
13
22
  ## 0.23.1
14
23
 
15
24
  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