@hirobius/design-system 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/AGENTS.md +11 -1
  2. package/CHANGELOG.md +74 -0
  3. package/CONSUMING.md +2 -2
  4. package/DESIGN.md +24 -24
  5. package/NOTICE.md +1 -1
  6. package/README.md +20 -12
  7. package/UPGRADING.md +22 -1
  8. package/dist/chunks/{empty-state-DNoThgfV.js → empty-state-ChC_xZfg.js} +109 -92
  9. package/dist/chunks/{form-By82qZcC.js → form-zCZ_B83I.js} +16 -16
  10. package/dist/css-contract.json +1 -0
  11. package/dist/fonts/ibm-plex-mono-400.woff2 +0 -0
  12. package/dist/fonts.css +5 -5
  13. package/dist/form.js +1 -1
  14. package/dist/hirobius-ui.js +1254 -1181
  15. package/dist/manifest.js +5 -4
  16. package/dist/patterns.js +164 -162
  17. package/dist/styles.css +1 -1
  18. package/dist/tokens.css +1 -1
  19. package/dist/tokens.js +14 -1
  20. package/dist/types/src/app/components/asset-img.d.ts +1 -0
  21. package/dist/types/src/app/components/button.d.ts +1 -1
  22. package/dist/types/src/app/components/callout.d.ts +2 -1
  23. package/dist/types/src/app/components/card.d.ts +5 -3
  24. package/dist/types/src/app/components/code-block.d.ts +1 -0
  25. package/dist/types/src/app/components/combobox.d.ts +1 -1
  26. package/dist/types/src/app/components/data-table-section.d.ts +1 -0
  27. package/dist/types/src/app/components/destructive-section.d.ts +1 -0
  28. package/dist/types/src/app/components/divider.d.ts +1 -1
  29. package/dist/types/src/app/components/form-actions.d.ts +1 -0
  30. package/dist/types/src/app/components/form.d.ts +1 -0
  31. package/dist/types/src/app/components/grid.d.ts +1 -1
  32. package/dist/types/src/app/components/icon.d.ts +1 -1
  33. package/dist/types/src/app/components/metric-tiles.d.ts +2 -0
  34. package/dist/types/src/app/components/page-header.d.ts +1 -0
  35. package/dist/types/src/app/components/page.d.ts +1 -0
  36. package/dist/types/src/app/components/reveal.d.ts +1 -0
  37. package/dist/types/src/app/components/stack.d.ts +1 -1
  38. package/dist/types/src/app/components/tabs.d.ts +3 -1
  39. package/dist/types/src/app/context/hds-theme.d.ts +1 -1
  40. package/dist/types/src/app/design-system/generated-token-refs.d.ts +13 -0
  41. package/dist/types/src/app/design-system/generated-token-values.d.ts +14 -1
  42. package/dist/types/src/app/hooks/useInteractionState.d.ts +7 -1
  43. package/dist/types/src/index.d.ts +47 -0
  44. package/dist/variables.css +33 -22
  45. package/docs/CONSUMING.md +2 -2
  46. package/hirobius.tokens.json +87 -40
  47. package/llms.txt +29 -7
  48. package/package.json +7 -6
  49. package/public/hds-manifest.json +257 -99
  50. package/public/llms/components.txt +1 -1
  51. package/public/llms-full.txt +54 -32
  52. package/public/llms.txt +29 -7
  53. package/src/app/data/component-api.json +51 -18
  54. package/upgrade/index.json +8 -1
  55. package/upgrade/releases/0.23.0.json +259 -0
  56. package/upgrade/schema.json +114 -1
  57. package/dist/fonts/geist-mono-400.woff2 +0 -0
package/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTS.md — @hirobius/design-system
2
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 -->
3
+ <!-- Generated by scripts/generate-agents-md.mjs from mcp/guide.mjs, src/app/data/component-api.json and content/docs/voice.mdx. Do not hand-edit above the repo-notes marker: pnpm agents:generate -->
4
4
 
5
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
6
 
@@ -79,6 +79,16 @@ One answer per need. Use the components after the arrow; what follows "Not:" is
79
79
  - Every control has an accessible name: fields take `label`, a repeated row action takes an `aria-label` naming its row.
80
80
  - Section headings come from the pattern that owns the section (`title` props). Do not add a `Text` heading the screen does not ask for.
81
81
 
82
+ ## Voice
83
+
84
+ How these docs speak. Every page, and every agent writing for HDS, follows it. Source: `content/docs/voice.mdx` (published at `/docs/voice`).
85
+
86
+ - Use plain words a reader already knows. Name a thing by what it does, not by how it is built.
87
+ - Keep sentences short, one idea each.
88
+ - Tell the reader what to do. Leave out brand adjectives.
89
+ - Keep maintainer references off public pages: issue and ADR numbers, script names, internal counts.
90
+ - Don't use: "systems-first".
91
+
82
92
  ## Finish with the lint plugin
83
93
 
84
94
  The ESLint plugin ships in this package. Pass its `recommended` rules before you report done:
package/CHANGELOG.md CHANGED
@@ -1,5 +1,79 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.23.0
4
+
5
+ ### Upgrade
6
+
7
+ ```sh
8
+ npx @hirobius/design-system@latest upgrade
9
+ ```
10
+
11
+ - Looks different: Accent-intent text and icons (such as links) now render in a dark apple green instead of a dark neutral.
12
+ - Looks different: Hovered accent text now shifts to a darker apple green instead of a darker neutral.
13
+ - Looks different: The accent fill on hover is now a deeper apple green instead of a dark neutral.
14
+ - Looks different: The accent fill while pressed is now a darker apple green instead of a near-black neutral.
15
+ - And 10 more: see [UPGRADING.md](https://github.com/hirobius/hds/blob/main/UPGRADING.md#0230).
16
+
17
+ ### Minor Changes
18
+
19
+ - 8edd926: The code font is now IBM Plex Mono 400 (OFL-1.1), replacing Geist Mono. The `primitive.typography.family.mono` token value changes (names unchanged), `fonts.css` ships `ibm-plex-mono-400.woff2` instead of `geist-mono-400.woff2`, and the 13px mono role is unchanged. Figma needs the IBM Plex Mono font installed before `figma:push`.
20
+
21
+ ### Patch Changes
22
+
23
+ - 66cb4e2: fix(a11y): Tier-2 accessibility fixes across the primitives.
24
+ - **Radio / Checkbox / Toggle** show a keyboard focus ring only on `:focus-visible` (not on mouse click), and focus is no longer masked by hover (focus now outranks hover in `useInteractionState`).
25
+ - **Input / Textarea / FormField** no longer point `aria-describedby` at a description that isn't rendered (error replaces helper); `Input`'s `loading` uses `readOnly` + `aria-busy` instead of `disabled`, so a search-as-you-type field keeps focus.
26
+ - **Select** renders a real `<label htmlFor>` wired to the trigger, so clicking the label focuses it.
27
+ - **Combobox** keyboard: options are not tab stops, Arrow keys skip disabled options and scroll the active one into view, option ids are index-based (no break on special chars), and the active index resets on open / option change.
28
+ - **Tabs** focus ring is `ring-inset` so it isn't clipped by the scroll container.
29
+ - **InlineLink** only treats a single-leading-slash path as an internal router link (not `//host`); `mailto:`/`tel:`/`#hash` are plain same-tab links; external links keep `target=_blank` + a visually-hidden "(opens in new tab)"; the internal branch gains `hds-focus`.
30
+
31
+ - c88ab39: fix(feedback): unify Alert + Callout on one tinted-fill tone language.
32
+
33
+ The two feedback components carried tone in opposite ways — Alert by a tinted fill (`bg-feedback-bg-*`), Callout by a 3px colored left stripe — reading as two systems, and the stripe was the lone >1px colored side-rule anti-pattern left in the set. DESIGN.md also still claimed Alert carries tone "by left-border color, not by tinted fills", which the shipped Alert already contradicted.
34
+ - **Callout** now uses the same tinted feedback fill as Alert (rounded, no stripe); `accent` (not a feedback state) takes a neutral `bg-muted` fill. It stays distinct from Alert by role — no icon, no status role, optional `italic` — not by mechanism.
35
+ - **Alert** unchanged (already fill-based).
36
+ - **DESIGN.md** (via build-design-md.mjs) corrected: tone is carried by a tinted feedback fill, not a left-border stripe.
37
+
38
+ Visual change to Callout; no API change.
39
+
40
+ - c88ab39: feat(brand): set the default accent to a bright apple green.
41
+
42
+ The base brand accent moves from a neutral (monochrome) to a bright apple green. A
43
+ new `primitive.color.apple` scale backs it, kept distinct from the emerald `green`
44
+ feedback/success scale so an accent and a success state never read as the same hue.
45
+ - `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.apple.*`.
46
+ - `semantic.color.content.onAccent` flips to a dark neutral (`neutral.900`) in both modes, since a bright accent fill needs dark text to clear AA — `content.onAccent / surface.accent` is 7.2:1 light / 9.3:1 dark.
47
+ - Per-tenant accents are unchanged: `accent-lilac` and `concrete-creations` set their own accent (and their own white `onAccent`); `brutalist-demo` inherits the new green base.
48
+
49
+ Visual-only; no API changes. The accent remains a single per-tenant knob — consumers who set their own accent overlay are unaffected.
50
+
51
+ - c88ab39: docs(card): reconcile DESIGN.md with the shipped borderless-default Card.
52
+
53
+ The Card Anatomy / elevation tables said a resting card carries a 1px border, contradicting the 12d-3 outline rule (and DESIGN.md's own "don't default to outlined cards" guidance) that made the default `Card` variant borderless, with a resting border opt-in via `bordered` / a feedback `tone` / `accent`. Updated the elevation-role table, the component table, and the (mandatory) Card Anatomy Border row to document the borderless default + opt-in border, and corrected the stale card.tsx module docstring that claimed depth comes from a resting border. No component behavior change.
54
+
55
+ - 0a6b830: fix(components): five Tier-1 component bugs from the audit.
56
+ - **Select** no longer crashes the page when `options` is empty (async list mid-load) or when `value` matches no option; the trigger label degrades to the field name.
57
+ - **Combobox** can now be closed by clicking its trigger again (the trigger was a `Popover.Anchor`, so Radix dismissed on pointerdown and the onClick reopened).
58
+ - **Button `asChild`** now enforces the disabled/loading contract on a slotted element (e.g. an `<a>`): non-interactive (`pointer-events-none`, `tabIndex=-1`) and dimmed, since native `disabled:` utilities can't apply to it.
59
+ - **AssetImg** and **Avatar** recover when `src` changes to a working image after a prior load error, instead of staying stuck on the fallback.
60
+
61
+ - b43d6bc: The package now ships `dist/css-contract.json` (hds#449): for each stylesheet it exports, every CSS custom property with its value per context (`:root`, dark, compact, each `[data-brand]`, each `@media`), the class names, the `@font-face` entries and the `@layer` names, plus `publicClasses` (the classes you may write yourself: `hds-focus` and the `static.css` set, also listed in `public/hds-manifest.json`). The upgrade ledger reads it, so from the next release a removed CSS variable or `hds-*` class needs a breaking upgrade step, and a changed token value a look step that `npx @hirobius/design-system upgrade` reports where your code uses it. Nothing changes in the stylesheets themselves.
62
+ - c88ab39: fix(disabled): unify the disabled state onto per-component tokens, off the global opacity multiplier.
63
+
64
+ DESIGN.md forbids a global disabled-state rule (opacity multiplier); disabled presentation must be governed per-component through its dedicated disabled tokens. Button, Combobox, Input, Textarea, Tabs and Tag were dimming with `disabled:opacity-50`/`opacity-70` — now they use `content.disabled` text (and a neutral `bg-muted` surface where a fill is needed), matching Checkbox/Radio/Toggle/SegmentedControl.
65
+ - **Button** — disabled is now `bg-muted` + `content-disabled` text for every variant AND tone (a disabled danger/success/… button now reads as disabled instead of fully coloured). Note: the pre-existing `component-button-primary-bgDisabled`/`textDisabled` tokens resolve to `accentSubtle` + `content-onAccent`, which render near-white-on-near-white under the neutral accent, so the component uses the neutral `bg-muted` pair instead (token fix tracked separately).
66
+ - **Input / Textarea** — drop the redundant `disabled:opacity-70`; keep `bg-muted`, switch disabled text to `content-disabled`.
67
+ - **Combobox / Tabs / Tag** — `disabled:opacity-50` → `content-disabled` text.
68
+
69
+ Visual-only; no API changes.
70
+
71
+ - 2d2a874: Plain-language `@usage` lines for Button, Grid, Surface, Divider, Icon, Stack and every pattern. Docs pages now open with that line instead of the code note.
72
+ - 8016b7a: AGENTS.md and llms.txt carry a Voice section generated from the Voice page (`content/docs/voice.mdx`, published at `/docs/voice`): how HDS docs and agents writing for HDS should speak, and the words not to use.
73
+ - c88ab39: fix(polish): Table cell alignment + caption spacing, and reduced-motion guards (docs-site rubric findings).
74
+ - **Table**: data cells now `items-center` (was `items-start`), so a badge/status slot lines up on a shared vertical center with its text siblings instead of floating above them; the caption/description block gains a token gap so it no longer touches the table's header band.
75
+ - **Reduced motion**: the Button and Input loading spinners (`animate-spin`) and the Progress bar's width transition now carry a `motion-reduce:` guard, matching Spinner/Progress's existing policy, so they stop animating under `prefers-reduced-motion`.
76
+
3
77
  ## 0.22.0
4
78
 
5
79
  ### Upgrade
package/CONSUMING.md CHANGED
@@ -29,7 +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
+ import '@hirobius/design-system/fonts.css'; // optional — the HDS brand fonts (Satoshi, IBM Plex Mono)
33
33
 
34
34
  export function Example() {
35
35
  return (
@@ -45,7 +45,7 @@ Available subpaths:
45
45
  | Import | What |
46
46
  | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
47
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` |
48
+ | `@hirobius/design-system/fonts.css` | Optional brand fonts (Satoshi, IBM Plex Mono); woff2 files ship in the package, relative URLs, `font-display: swap` |
49
49
  | `@hirobius/design-system/tokens.css` | Token CSS variables (import once at app root) |
50
50
  | `@hirobius/design-system/tokens` | Token values as TS constants |
51
51
  | `@hirobius/design-system/cn` | `cn()` class-merge helper |
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 palette and a single accent that each tenant sets — neutral by default (#208). 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, 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.
10
10
 
11
11
  ## Colors
12
12
 
13
13
  <!-- auto:start:colors -->
14
14
  **One accent — one neutral system.**
15
15
 
16
- - **Accent** (`#111111`): 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** (`#66B239`): 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`.
@@ -30,7 +30,7 @@ HDS ships three typefaces — each with a distinct and exclusive role:
30
30
 
31
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
- - **Mono font**: Geist Mono. Reserved for tokens, code, technical callouts, and metric readouts.
33
+ - **Mono font**: IBM Plex Mono. Reserved for tokens, code, technical callouts, and metric readouts.
34
34
 
35
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
 
@@ -92,14 +92,14 @@ Depth is communicated through 4 elevation roles bundled by `semantic.elevation.*
92
92
 
93
93
  ### Elevation roles
94
94
 
95
- | Surface | Role token | Background | Shadow | Border |
96
- | -------------------------------------- | ----------------------------- | ----------------- | ----------------- | ------------------- |
97
- | Card / panel resting | `semantic.elevation.flat` | `surface.page` | none | `border.subtle` 1px |
98
- | Card / panel lifted (interactive only) | `semantic.elevation.raised` | `surface.raised` | `shadow.subtle` | none |
99
- | Popover / dropdown / tooltip | `semantic.elevation.floating` | `surface.raised` | `shadow.floating` | none |
100
- | Dialog / sheet / modal | `semantic.elevation.overlay` | `surface.overlay` | `shadow.overlay` | none |
95
+ | Surface | Role token | Background | Shadow | Border |
96
+ | -------------------------------------- | ----------------------------- | ----------------- | ----------------- | -------------------------------------------------------- |
97
+ | Card / panel resting | `semantic.elevation.flat` | `surface.page` | none | none by default; opt-in 1px (`bordered`/`tone`/`accent`) |
98
+ | Card / panel lifted (interactive only) | `semantic.elevation.raised` | `surface.raised` | `shadow.subtle` | none |
99
+ | Popover / dropdown / tooltip | `semantic.elevation.floating` | `surface.raised` | `shadow.floating` | none |
100
+ | Dialog / sheet / modal | `semantic.elevation.overlay` | `surface.overlay` | `shadow.overlay` | none |
101
101
 
102
- Cards default to `flat`. They lift to `raised` only on interactive hover or when explicitly elevated above siblings. Never combine `raised` with a border — depth is one mechanism (border OR shadow), not both stacked.
102
+ Cards default to `flat`. They lift to `raised` only on interactive hover or when explicitly elevated above siblings. Never combine `raised` with a border — depth is one mechanism (border OR shadow), not both stacked. The default `Card` variant is **borderless** (12d-3 outline rule: repeated outlined cards crowd a layout, so the edge is not the default) — a resting 1px border is **opt-in** via `bordered`, a feedback `tone`, or the `accent` variant (`border.default` / feedback color / `border.accent` respectively). Rely on whitespace, dividers, and rails for grouping; reach for `bordered` only for a genuinely discrete standalone object.
103
103
 
104
104
  Overlays (Dialog, AlertDialog, Menu, Popover, Select, Tooltip) portal into the nearest `data-hds` scope, so they inherit its theme (for example `<div data-hds data-theme="dark">`); pass `container` on the Content part to override.
105
105
 
@@ -142,9 +142,9 @@ Default most interactive feedback to `productive` (150ms, decelerate). Reserve `
142
142
  | --- | --- | --- | --- |
143
143
  | **Buttons** (`Button`) | `8px` (`semantic.radius.action`) | default · hover · focus · active · disabled · loading | Three variants: primary (accent-filled), secondary (outline), tertiary (ghost). Primary uses `semantic.accent.*` ramp per state. Pressed is a 5% `semantic.color.state.pressed.overlay` wash over the fill (`role.pressed-overlay`: black in light, white in dark), not a brightness filter. Icon-only buttons (`iconOnly`) follow the same token surface. Icon-only actions use `Button iconOnly` with a `label` and an `Icon` from `@hirobius/design-system/icons` in `iconLeft`. |
144
144
  | **Inputs** (`Input`) | `8px` (`semantic.radius.action`) | default · focus · filled · error · disabled · loading | Border-driven treatment; no filled background by default. Focus uses `semantic.color.border.accent` plus a 2px outline offset. Error swaps to `component.input.borderError`. |
145
- | **Cards** (`Card`) | `12px` (`rounded-lg`, role radius + 4px) | default · hover (optional parallax) · pressed (when interactive) | Cards default to `elevation.flat` (1px border `border.subtle`, no shadow). Interactive cards lift to `elevation.raised` (shadow.subtle, no border) on hover. Bind via `semantic.elevation.{role}` — never raw box-shadow values. Radius: `rounded-lg` (role radius + 4 px, follows the tenant knob) — never a hard-coded value. Padding: `var(--semantic-space-surface-padding)`. Title: `heading3`. Meta: `caption` + `var(--semantic-color-content-secondary)`. Hover (interactive): `scale(1.02)` transform + lift to raised. Never: gradients, glow, frosted glass, tinted surfaces, decorative overlays, or inner shadows. |
145
+ | **Cards** (`Card`) | `12px` (`rounded-lg`, role radius + 4px) | default · hover (optional parallax) · pressed (when interactive) | Cards default to `elevation.flat` (borderless by default; an opt-in 1px border via `bordered`/`tone`/`accent`, no shadow). Interactive cards lift to `elevation.raised` (shadow.subtle, no border) on hover. Bind via `semantic.elevation.{role}` — never raw box-shadow values. Radius: `rounded-lg` (role radius + 4 px, follows the tenant knob) — never a hard-coded value. Padding: `var(--semantic-space-surface-padding)`. Title: `heading3`. Meta: `caption` + `var(--semantic-color-content-secondary)`. Hover (interactive): `scale(1.02)` transform + lift to raised. Never: gradients, glow, frosted glass, tinted surfaces, decorative overlays, or inner shadows. |
146
146
  | **Badges** (`Badge`) | `8px` (`primitive.radius.4`) | neutral · accent · feedback (error/success/warning/info) | Single-line status markers. Feedback colors come from `semantic.color.feedback.*`. Never used as decorative chrome. |
147
- | **Alerts** (`Alert`) | `8px` (via `hds.borderRadius.4`) | info · success · warning · error | Inline banner pattern with icon + message + optional action. Tone is carried by left-border color, not by tinted fills. |
147
+ | **Alerts** (`Alert`) | `8px` (via `hds.borderRadius.4`) | info · success · warning · error | Inline banner pattern with icon + message + optional action. Tone is carried by a tinted feedback fill (`bg-feedback-bg-*`, matching Badge), NOT a left-border stripe. Callout shares this fill language and differs only by role (no icon, no status role, optional italic). |
148
148
  | **Disclosures** (`Disclosure`) | `8px` (`hds.borderRadius.action`) | collapsed · expanded · hover · focus | Accordion primitive. Expansion uses `semantic.motion.productive`; no spring bounce. Dividers follow `semantic.color.border.subtle`. |
149
149
  | **Toggles** (`Toggle`) | `full` (pill track + circular thumb) | off · on · focus · disabled | Accent-filled track in the on state; neutral track otherwise. Track + thumb transitions share `semantic.motion.productive`. |
150
150
  | **Segmented Control** (`SegmentedControl`) | Outer `12px` · inner segments `8px` | rest · hover · selected · disabled | Selected segment fills with the accent; unselected segments are transparent. Use for 2–5 mutually exclusive options; beyond that, prefer `Select`. |
@@ -156,16 +156,16 @@ See `public/hds-manifest.json` and `src/app/data/component-api.json` for the ful
156
156
 
157
157
  Every HDS card surface must conform to this anatomy exactly. No creative interpretation is permitted on any of these properties.
158
158
 
159
- | Property | Required value | Forbidden |
160
- | ------------------------ | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
161
- | Background | `var(--semantic-color-surface-raised)` | Any gradient, tinted fill, or custom color |
162
- | Border | `1px solid var(--semantic-color-border-default)` | `box-shadow` as an elevation substitute |
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 |
164
- | Padding | `var(--semantic-space-component-padding)` or `<HdsSurface padding="component">` | Raw pixel values or ad hoc insets |
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 |
166
- | Title | `hds.typeStyles.title` / `<Text variant="title">` | Any other type style for the primary card heading |
167
- | Subtitle / meta | `hds.typeStyles.caption` + `var(--semantic-color-content-secondary)` | Primary content color or body size for secondary text |
168
- | Hover (interactive only) | `transform: scale(1.02)` | Background fill change, border color shift, or opacity fade on hover |
159
+ | Property | Required value | Forbidden |
160
+ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
161
+ | Background | `var(--semantic-color-surface-raised)` | Any gradient, tinted fill, or custom color |
162
+ | Border | Default variant: **borderless**. Opt-in (`bordered`/`tone`/`accent`): 1px solid the matching token (`border.default` / feedback color / `border.accent`). Never border + shadow together. | `box-shadow` as an elevation substitute; a border on the default variant (use `bordered`) |
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 |
164
+ | Padding | `var(--semantic-space-component-padding)` or `<HdsSurface padding="component">` | Raw pixel values or ad hoc insets |
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 |
166
+ | Title | `hds.typeStyles.title` / `<Text variant="title">` | Any other type style for the primary card heading |
167
+ | Subtitle / meta | `hds.typeStyles.caption` + `var(--semantic-color-content-secondary)` | Primary content color or body size for secondary text |
168
+ | Hover (interactive only) | `transform: scale(1.02)` | Background fill change, border color shift, or opacity fade on hover |
169
169
 
170
170
  Never use on any card surface: gradient backgrounds, glow effects, frosted glass (`backdrop-filter: blur`), decorative overlays, gradient borders, colored or tinted backgrounds, inner shadows, patterned fills, shimmer or noise effects.
171
171
 
@@ -209,7 +209,7 @@ Three more needs are props on an existing component, not components of their own
209
209
  ## Do's and Don'ts
210
210
 
211
211
  - 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 neutral — read the token, never assume a hue.
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.
213
213
  - Don't tint neutrals warm or cool; greys should remain genuinely neutral and high-contrast.
214
214
  - 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
215
  - Don't hardcode colors, spacing, radius, or typography values when governed tokens already exist.
@@ -228,6 +228,6 @@ Unresolved rules that the live repo cannot yet answer confidently are tracked in
228
228
  <!-- auto:start:build-meta -->
229
229
  ---
230
230
 
231
- > Generated from `hirobius.tokens.json` (389 tokens) and `public/hds-manifest.json` by `scripts/build-design-md.mjs`.
231
+ > Generated from `hirobius.tokens.json` (400 tokens) and `public/hds-manifest.json` by `scripts/build-design-md.mjs`.
232
232
  > Hand-edit `DESIGN.source.md`; this file (`DESIGN.md`) is overwritten by `pnpm tokens`.
233
233
  <!-- auto:end:build-meta -->
package/NOTICE.md CHANGED
@@ -4,6 +4,6 @@
4
4
 
5
5
  - **HDS code** (components, compiled JavaScript, types, CSS, and token files): MIT. See [LICENSE](LICENSE).
6
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
- - **Geist Mono** (weight 400, by Vercel, [source](https://github.com/vercel/geist-font)): SIL Open Font License 1.1.
7
+ - **IBM Plex Mono** (weight 400, by IBM, [source](https://github.com/IBM/plex)): 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
@@ -2,7 +2,10 @@
2
2
 
3
3
  [![CI](https://github.com/hirobius/hds/actions/workflows/ci.yml/badge.svg)](https://github.com/hirobius/hds/actions/workflows/ci.yml) [![npm](https://img.shields.io/npm/v/@hirobius/design-system)](https://www.npmjs.com/package/@hirobius/design-system) [![Storybook](https://img.shields.io/badge/Storybook-live-ff4785)](https://hirobius-design-system.vercel.app)
4
4
 
5
- React + TypeScript component library on a governed design-token pipeline. Live Storybook: **<https://hirobius-design-system.vercel.app>**
5
+ **A governed, token-first React design system.** Components plus the system
6
+ around them: a DTCG token pipeline (CSS variables + TypeScript constants),
7
+ quality gates in git hooks and CI, one-way Figma sync, and WCAG-checked contrast
8
+ and focus. Live Storybook: **<https://hirobius-design-system.vercel.app>**
6
9
 
7
10
  ```bash
8
11
  pnpm add @hirobius/design-system
@@ -15,13 +18,18 @@ Upgrading: [UPGRADING.md](UPGRADING.md) lists what each release asks of you. Fro
15
18
  <!-- auto:start:front-door-counts -->
16
19
 
17
20
  - **53** public component modules, exported from `src/index.ts`
18
- - **389** DTCG tokens in `hirobius.tokens.json`, compiled to CSS variables and TypeScript constants
21
+ - **400** DTCG tokens in `hirobius.tokens.json`, compiled to CSS variables and TypeScript constants
19
22
  - **341** Storybook stories in **71** story files
20
23
 
21
24
  <!-- auto:end:front-door-counts -->
22
25
 
23
- - Theming through four root attributes and CSS variables (theme, density, brand, font) that need no JavaScript
24
- - Deterministic gates in git hooks and CI: typecheck, zero-warning ESLint, token validity and contrast, Vitest unit and contract tests, bundle budgets, a consumer smoke build, and a Storybook build
26
+ What the system includes:
27
+
28
+ - **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.
30
+ - **Upgrade path.** A release ledger and one consumer command: `npx @hirobius/design-system@latest upgrade`.
31
+ - **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
+ - **Theming without JavaScript.** Four root attributes — theme, density, brand, font — re-skin HDS descendants through CSS variables.
25
33
 
26
34
  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.
27
35
 
@@ -120,12 +128,12 @@ HDS theming is driven by root attributes + CSS variables, so it works with **zer
120
128
  JavaScript** — set them on any element (React, Astro, plain HTML) and every HDS
121
129
  descendant re-skins:
122
130
 
123
- | Dial | Attribute / var | Values | Default |
124
- | ------- | ---------------------------------------------- | --------------- | -------------------- |
125
- | theme | `data-theme` | `dark` | light (unset) |
126
- | density | `data-density` | `compact` | comfortable (unset) |
127
- | brand | `data-brand` (+ `data-tenant` alias) | overlay slug | base (unset) |
128
- | font | `--hds-font-family` / `--hds-font-family-mono` | any font-family | Satoshi / Geist Mono |
131
+ | Dial | Attribute / var | Values | Default |
132
+ | ------- | ---------------------------------------------- | --------------- | ----------------------- |
133
+ | theme | `data-theme` | `dark` | light (unset) |
134
+ | density | `data-density` | `compact` | comfortable (unset) |
135
+ | brand | `data-brand` (+ `data-tenant` alias) | overlay slug | base (unset) |
136
+ | font | `--hds-font-family` / `--hds-font-family-mono` | any font-family | Satoshi / IBM Plex Mono |
129
137
 
130
138
  ```html
131
139
  <!-- zero-JS: static markup (e.g. an Astro layout) -->
@@ -217,7 +225,7 @@ Screen-reader output is checked by `tests/primitive-contracts/screen-reader.cont
217
225
 
218
226
  ## Visual direction: Editorial Enterprise
219
227
 
220
- The governing direction is "Editorial Enterprise" — enterprise rigor with editorial pacing. It favors sharp hierarchy, open whitespace, monochrome neutrals, and a single electric-blue accent. In practice:
228
+ The governing direction is "Editorial Enterprise" — enterprise rigor with editorial pacing. It favors sharp hierarchy, open whitespace, monochrome neutrals, and a single tenant-set accent. In practice:
221
229
 
222
230
  - documentation reads like a designed publication, not a component dump
223
231
  - cards are used sparingly; whitespace, rails, dividers, and bands carry structure first
@@ -276,4 +284,4 @@ public/
276
284
 
277
285
  ## License
278
286
 
279
- The HDS code is MIT ([LICENSE](LICENSE)). The package CSS also embeds the Satoshi and Geist Mono fonts, which keep their own licenses and are not covered by MIT. See [NOTICE.md](NOTICE.md).
287
+ The HDS code is MIT ([LICENSE](LICENSE)). The package CSS also embeds the Satoshi and IBM Plex Mono fonts, which keep their own licenses and are not covered by MIT. See [NOTICE.md](NOTICE.md).
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.22.0. 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.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,27 @@ 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.0
14
+
15
+ Released 2026-10-10 (minor). 14 that look different.
16
+
17
+ ### Looks different
18
+
19
+ - Accent-intent text and icons (such as links) now render in a dark apple green instead of a dark neutral.
20
+ - Hovered accent text now shifts to a darker apple green instead of a darker neutral.
21
+ - The accent fill on hover is now a deeper apple green instead of a dark neutral.
22
+ - The accent fill while pressed is now a darker apple green instead of a near-black neutral.
23
+ - Interactive accent fills at rest (primary buttons, selected controls) now render in a bright apple green instead of a dark neutral, paired with dark on-accent text.
24
+ - The low-emphasis accent tint (hover and selection backgrounds) is now a faint apple green instead of a neutral tint.
25
+ - Accent borders now render in apple green instead of a dark neutral.
26
+ - Accent-intent text and icons on page and card surfaces now render in a dark apple green instead of a neutral.
27
+ - Text and icons on accent fills are now a dark neutral instead of white, because the accent fill is a bright apple green that needs dark text for contrast.
28
+ - Accent background surfaces now render in a bright apple green instead of a dark neutral.
29
+ - Faint accent background surfaces are now a pale apple green instead of a neutral tint.
30
+ - Callout now renders as a tinted feedback fill (rounded, no left stripe) matching Alert, with the accent tone using a neutral muted fill.
31
+ - Code text now draws in IBM Plex Mono instead of Geist Mono, so if you preload or self-host geist-mono-400.woff2, point it at ibm-plex-mono-400.woff2 from fonts.css instead.
32
+ - Table data cells vertically center their content (badge/status slots no longer float above text) and the caption gains spacing above the table; loading spinners and the progress bar stop animating under prefers-reduced-motion.
33
+
13
34
  ## 0.22.0
14
35
 
15
36
  Released 2026-10-08 (minor). 3 changes to make by hand (1 breaking), 1 that looks different and 2 deprecations.