@hirobius/design-system 0.18.0 → 0.19.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/CONSUMING.md +150 -0
- package/DESIGN.md +220 -0
- package/README.md +14 -2
- package/dist/chunks/{activity-feed-C8_e-Btq.js → activity-feed-DIMeUJpW.js} +4907 -2912
- package/dist/chunks/{form-DnGRy27o.js → form-BvNNnJ0t.js} +2 -2
- package/dist/form.js +5 -5
- package/dist/hirobius-ui.js +1986 -2529
- package/dist/icons.js +53 -0
- package/dist/manifest.js +15 -14
- package/dist/patterns.js +292 -101
- package/dist/static.css +3 -3
- package/dist/styles.css +1 -1
- package/dist/tokens.css +1 -1
- package/dist/types/src/app/components/alert-dialog.d.ts +9 -1
- package/dist/types/src/app/components/alert.d.ts +4 -0
- package/dist/types/src/app/components/avatar.d.ts +4 -0
- package/dist/types/src/app/components/badge.d.ts +4 -0
- package/dist/types/src/app/components/box.d.ts +5 -0
- package/dist/types/src/app/components/breadcrumb.d.ts +4 -0
- package/dist/types/src/app/components/button-group.d.ts +4 -0
- package/dist/types/src/app/components/button.d.ts +3 -0
- package/dist/types/src/app/components/card.d.ts +9 -0
- package/dist/types/src/app/components/checkbox.d.ts +4 -0
- package/dist/types/src/app/components/combobox.d.ts +10 -0
- package/dist/types/src/app/components/command-palette.d.ts +3 -1
- package/dist/types/src/app/components/container.d.ts +5 -0
- package/dist/types/src/app/components/context-menu.d.ts +25 -2
- package/dist/types/src/app/components/data-table-section.d.ts +45 -0
- package/dist/types/src/app/components/destructive-section.d.ts +32 -0
- package/dist/types/src/app/components/dialog.d.ts +20 -2
- package/dist/types/src/app/components/disclosure.d.ts +3 -0
- package/dist/types/src/app/components/divider.d.ts +4 -0
- package/dist/types/src/app/components/empty-state.d.ts +4 -0
- package/dist/types/src/app/components/field.d.ts +4 -0
- package/dist/types/src/app/components/form-actions.d.ts +26 -0
- package/dist/types/src/app/components/grid.d.ts +4 -0
- package/dist/types/src/app/components/hds-tooltip.d.ts +14 -2
- package/dist/types/src/app/components/hover-card.d.ts +16 -1
- package/dist/types/src/app/components/icon.d.ts +4 -0
- package/dist/types/src/app/components/inline-link.d.ts +4 -0
- package/dist/types/src/app/components/input.d.ts +5 -0
- package/dist/types/src/app/components/kbd.d.ts +3 -0
- package/dist/types/src/app/components/menu.d.ts +26 -2
- package/dist/types/src/app/components/metric-tiles.d.ts +40 -0
- package/dist/types/src/app/components/page-header.d.ts +34 -0
- package/dist/types/src/app/components/pagination.d.ts +3 -0
- package/dist/types/src/app/components/popover.d.ts +14 -2
- package/dist/types/src/app/components/progress.d.ts +4 -0
- package/dist/types/src/app/components/radio.d.ts +5 -0
- package/dist/types/src/app/components/select.d.ts +16 -0
- package/dist/types/src/app/components/skeleton.d.ts +4 -0
- package/dist/types/src/app/components/slider.d.ts +3 -0
- package/dist/types/src/app/components/spinner.d.ts +4 -0
- package/dist/types/src/app/components/stack.d.ts +4 -0
- package/dist/types/src/app/components/stat.d.ts +4 -0
- package/dist/types/src/app/components/status-tile.d.ts +4 -0
- package/dist/types/src/app/components/table.d.ts +36 -4
- package/dist/types/src/app/components/tabs.d.ts +4 -0
- package/dist/types/src/app/components/tag.d.ts +3 -0
- package/dist/types/src/app/components/text.d.ts +4 -0
- package/dist/types/src/app/components/textarea.d.ts +3 -0
- package/dist/types/src/app/components/toast.d.ts +4 -0
- package/dist/types/src/app/components/toggle.d.ts +4 -0
- package/dist/types/src/app/components/tooltip.d.ts +1 -1
- package/dist/types/src/app/components/visually-hidden.d.ts +3 -0
- package/dist/types/src/app/context/hds-portal.d.ts +52 -0
- package/dist/types/src/app/context/hds-theme.d.ts +10 -0
- package/dist/types/src/app/data/manifest-types.d.ts +27 -0
- package/dist/types/src/app/design-system/generated-token-refs.d.ts +2 -0
- package/dist/types/src/icons.d.ts +13 -0
- package/dist/types/src/index.d.ts +20 -1
- package/dist/types/src/patterns.d.ts +5 -0
- package/dist/variables.css +4 -0
- package/docs/CONSUMING.md +758 -0
- package/hirobius.tokens.json +17 -0
- package/llms.txt +261 -0
- package/package.json +21 -4
- package/public/hds-manifest.json +1545 -89
- package/public/llms/components.txt +1090 -0
- package/public/llms/layout.txt +54 -0
- package/public/llms/scroll.txt +22 -0
- package/public/llms/tokens.txt +32 -0
- package/public/llms-full.txt +1561 -0
- package/public/llms.txt +261 -0
- package/src/app/data/component-api.json +6156 -0
|
@@ -0,0 +1,1561 @@
|
|
|
1
|
+
# Hirobius Design System
|
|
2
|
+
|
|
3
|
+
Generated: 2026-09-30T14:27:19.090Z
|
|
4
|
+
Primary sources: `public/hds-manifest.json`, `src/app/data/component-api.json`, `hirobius.tokens.json`
|
|
5
|
+
|
|
6
|
+
## System Architecture
|
|
7
|
+
|
|
8
|
+
- Engine: React + TypeScript
|
|
9
|
+
- Icons: Lucide React
|
|
10
|
+
- Tokens: W3C DTCG
|
|
11
|
+
- Styling: CSS Variables
|
|
12
|
+
- Token pipeline: `hirobius.tokens.json` -> `pnpm tokens` -> generated CSS vars + generated TS constants
|
|
13
|
+
- Docs pipeline: `public/hds-manifest.json` + `src/app/data/component-api.json` -> reflective docs pages
|
|
14
|
+
- AI entrypoint: read `public/llms.txt` before editing code
|
|
15
|
+
|
|
16
|
+
## Phase Snapshot
|
|
17
|
+
|
|
18
|
+
- foundation. Foundations - 63% - Token architecture, CSS pipeline, accessibility, and primitive scales.
|
|
19
|
+
- Criteria: done: W3C DTCG three-tier token architecture; done: CSS variable pipeline + token verify; partial: Primitive scales complete (color, type, space); todo: Token audit clean
|
|
20
|
+
- components. Components - 75% - Accessible React UI built from foundations and mapped toward Figma parity.
|
|
21
|
+
- Criteria: done: Component inventory with typed props; done: Action system architecture (buttons, links, groups); done: Prop tables and API doc coverage; todo: Figma parity mapping
|
|
22
|
+
- infrastructure-operations. Architecture - 55% - System delivery, Figma sync, automation, quality gates, and operational hygiene.
|
|
23
|
+
- Criteria: done: System manifest + llms.txt AI context; done: Release gate + full audit gate; done: Documentation automation (AST pipeline, LLMS sync); partial: Payload sweep + orphan cleanup; partial: Motion system foundations; todo: Figma library generated from tokens; todo: Code Connect CI + reverse sync; partial: AST gatekeeper + token schema validation; partial: A11y CI + visual regression pipeline; partial: Operational feedback loop + AI retrospective
|
|
24
|
+
|
|
25
|
+
## Component Inventory (Source Of Truth)
|
|
26
|
+
|
|
27
|
+
This file intentionally does not embed the full component list to avoid duplication and excess context.
|
|
28
|
+
|
|
29
|
+
- Canonical inventory + metadata: read `public/hds-manifest.json`.
|
|
30
|
+
- If you see references to `public/manifest.json`, treat it as an optional alias; in this repo prefer `public/hds-manifest.json`.
|
|
31
|
+
|
|
32
|
+
## Component API (Source Of Truth)
|
|
33
|
+
|
|
34
|
+
This file intentionally does not embed prop tables or long-form API docs.
|
|
35
|
+
|
|
36
|
+
- Detailed prop types, unions, defaults, and descriptions: read `src/app/data/component-api.json`.
|
|
37
|
+
- Runtime behavior: read the actual component source under `src/app/components/` (and associated styles).
|
|
38
|
+
|
|
39
|
+
## Which one when
|
|
40
|
+
|
|
41
|
+
One line per component that declares when to use it (`@usage` / `@useInstead` in its JSDoc). Full detail, including `usage.whenNot`, `keyboard` and `aiRules`, is in `public/hds-manifest.json` and `src/app/data/component-api.json`.
|
|
42
|
+
|
|
43
|
+
Alert: Show a persistent inline message with a severity, next to the content it concerns. Use instead: ToastProvider, Badge
|
|
44
|
+
Avatar: Show a person or entity as an image with an initials fallback. Use instead: Icon, Badge
|
|
45
|
+
Badge: Label a status, state or count with a compact neutral or semantic chip. Use instead: Tag, Alert
|
|
46
|
+
Box: Build one-off layout that no named layout primitive covers, using token keys through `sx`. Use instead: Stack, Grid, Container
|
|
47
|
+
Breadcrumb: Show where the current page sits in a hierarchy and link back up it. Use instead: Tabs, Pagination
|
|
48
|
+
Button: Trigger an action (submit, save, open a dialog) with a text label and optional icons; for an icon-only control pass iconOnly with iconLeft. Use instead: InlineLink
|
|
49
|
+
ButtonGroup: Attach related Buttons into one segmented row or column that reads as a single control. Use instead: SegmentedControl, Stack
|
|
50
|
+
Card: Group related content on a raised surface with header, body, footer and metric slots. Use instead: Surface, Card.Metric
|
|
51
|
+
CardMetric: Show one headline figure (a KPI, a count, a total) with its label inside a Card.
|
|
52
|
+
Checkbox: Let people tick one or more independent options, or a parent choice that is partly selected. Use instead: Toggle, Radio
|
|
53
|
+
Combobox: Pick one value from a long list of options, with a search field that filters as you type. Use instead: Select, Menu
|
|
54
|
+
Container: Constrain a page region to the content or maximum width and centre it. Use instead: Stack, Grid, Box
|
|
55
|
+
ContextMenu: Offer actions for an item on right-click, or the equivalent keyboard gesture. Use instead: Menu
|
|
56
|
+
Dialog: Interrupt the page with a modal that needs a decision or focused input before people continue. Use instead: HoverCard, Alert, ToastProvider
|
|
57
|
+
Disclosure: Hide optional explanatory content behind a heading that people can expand. Use instead: Tabs
|
|
58
|
+
Divider: Separate two regions of content with a thin semantic rule. Use instead: Stack, Surface
|
|
59
|
+
EmptyState: Say that a list, grid or section has no data yet, with a title and an optional description. Use instead: Skeleton, Alert
|
|
60
|
+
Field: Show a labelled read-only value, such as a name and its value in a detail view. Use instead: Input, Card.Metric
|
|
61
|
+
Grid: Lay out content in responsive columns with token-governed gaps, or align nested content with subgrid. Use instead: Stack, Box
|
|
62
|
+
HdsThemeProvider: Wrap an app or region once to set theme, density and other root attributes for everything inside it. Use instead: Surface
|
|
63
|
+
HoverCard: Preview extra detail about a link or mention when it is hovered or focused, without navigating. Use instead: Dialog, Tooltip
|
|
64
|
+
Icon: Draw a Lucide glyph at a size and colour from the design tokens. Use instead: Button, Avatar
|
|
65
|
+
IconButton: Trigger an action from a compact icon-only control, always with an accessible label. Use instead: Button
|
|
66
|
+
InlineLink: Link to a route or external URL from inside body copy. Use instead: Button, Text
|
|
67
|
+
Input: Collect a single line of text, a number, an email or a password, with label, helper and error slots. Use instead: Textarea, Select, Combobox
|
|
68
|
+
Kbd: Show a keyboard key or shortcut hint inline, as a native kbd element. Use instead: Text
|
|
69
|
+
Menu: Offer a list of actions from a trigger, closed until opened. Use instead: Select
|
|
70
|
+
Pagination: Move between pages of a long result set, with truncated page numbers. Use instead: Breadcrumb
|
|
71
|
+
Progress: Show how far a task has got, as a bar that is determinate or indeterminate. Use instead: Spinner, Skeleton
|
|
72
|
+
Radio: Choose exactly one option from a small set that should stay visible together. Use instead: Checkbox, Select, SegmentedControl
|
|
73
|
+
SegmentedControl: Switch between two to five mutually exclusive views or modes in a compact row. Use instead: Radio, Tabs, Select
|
|
74
|
+
Select: Choose one value from a short list of options in a form field. Use instead: Menu, Combobox
|
|
75
|
+
Skeleton: Reserve the shape of content that is still loading, so the layout does not jump. Use instead: Progress, Spinner
|
|
76
|
+
Slider: Pick a number within a known range by dragging, when the exact value matters less than the position. Use instead: Input
|
|
77
|
+
Spinner: Show that something is loading when the wait is short or has no measurable end. Use instead: Progress, Skeleton
|
|
78
|
+
Stack: Space a row or column of content with token gaps and simple flex alignment. Use instead: Grid, Surface
|
|
79
|
+
Stat: Show one standalone headline figure with its label and an optional sub-line. Use instead: Card.Metric, StatusTile
|
|
80
|
+
StatusTile: Show a titled status block with optional notes and a trailing badge or affordance. Use instead: Card.Metric, StatusListItem
|
|
81
|
+
Surface: Wrap content in a padded, background-bearing inset surface with no header or footer anatomy. Use instead: Card, Stack
|
|
82
|
+
Table: Show rows of structured data in aligned columns, with optional sorting. Use instead: Field, Stack
|
|
83
|
+
Tabs: Switch between panels of related content in the same place, one visible at a time. Use instead: SegmentedControl, Disclosure
|
|
84
|
+
Tag: Show an interactive filter or category chip that people can toggle. Use instead: Badge
|
|
85
|
+
Text: Set any text on the type ramp, with the element chosen by `as`. Use instead: InlineLink, Kbd
|
|
86
|
+
Textarea: Collect multi-line free text such as a message, note or description. Use instead: Input
|
|
87
|
+
ToastProvider: Confirm an action with a brief message that appears and dismisses itself, through useToast. Use instead: Alert, Dialog
|
|
88
|
+
Toggle: Switch one setting on or off, with the effect applying immediately. Use instead: Checkbox, Radio
|
|
89
|
+
VisuallyHidden: Give assistive technology a label or description that sighted people do not need to see. Use instead: Text
|
|
90
|
+
|
|
91
|
+
## Tokens (Primary Source Of Truth)
|
|
92
|
+
|
|
93
|
+
- Primary token source of truth: `hirobius.tokens.json` (W3C DTCG).
|
|
94
|
+
- Prefer `semantic.*` and `component.*` tokens for product UI. Use `primitive.*` only when editing the token system itself.
|
|
95
|
+
- CSS variable naming convention: token path `semantic.color.surface.page` maps to `var(--semantic-color-surface-page)`.
|
|
96
|
+
|
|
97
|
+
## Quick Token Reference
|
|
98
|
+
|
|
99
|
+
| Need | Token path examples | CSS var examples |
|
|
100
|
+
| --- | --- | --- |
|
|
101
|
+
| Page/background surfaces | `semantic.color.surface.page`, `semantic.color.surface.raised` | `--semantic-color-surface-page`, `--semantic-color-surface-raised` |
|
|
102
|
+
| Text/content colors | `semantic.color.content.primary`, `semantic.color.content.secondary` | `--semantic-color-content-primary`, `--semantic-color-content-secondary` |
|
|
103
|
+
| Borders/dividers | `semantic.color.border.default`, `semantic.color.border.interactive` | `--semantic-color-border-default`, `--semantic-color-border-interactive` |
|
|
104
|
+
| Feedback states | `semantic.color.feedback.error`, `semantic.color.feedback.success` | `--semantic-color-feedback-error`, `--semantic-color-feedback-success` |
|
|
105
|
+
| Spacing (semantic tiers) | `semantic.space.scale.xs`, `semantic.space.surface.padding`, `semantic.space.region.gutter` | use semantic tokens or `--hds-space-px12` style vars |
|
|
106
|
+
| Radius | `semantic.radius.action` | `--semantic-radius-action` |
|
|
107
|
+
| Motion | `semantic.motion.productive`, `semantic.motion.expressive`, `semantic.motion.exit` | use token refs; values are structured (duration/easing) |
|
|
108
|
+
| Typography | `semantic.typography.body`, `semantic.typography.h2`, `semantic.typography.caption` | use token refs; values are structured (family/size/weight/etc) |
|
|
109
|
+
|
|
110
|
+
## How To Lay Out A Screen
|
|
111
|
+
|
|
112
|
+
Canonical skeleton, outermost to innermost:
|
|
113
|
+
|
|
114
|
+
1. `Page` (or `Container`/`Center` for a full-bleed, non-page surface) for the outermost width constraint. Never import `Container` directly inside `src/app/pages/**` — use `Page`, which wraps it and owns vertical rhythm.
|
|
115
|
+
2. `Stack` (vertical rhythm between sections) or `Grid` (two-dimensional/column layout) for the structural skeleton. One section = one Section/Stack — never add a second wrapper to fake a section boundary.
|
|
116
|
+
3. Reach for a named every-layout primitive before hand-rolling flex/grid math for a common intent: `Cluster` (wrapping row of same-ish things), `Center` (centered max-width column with optional gutter), `Sidebar` (fixed-width rail + fluid content, no media query), `Switcher` (row that flips to a column below a threshold, no media query), `Cover` (full-height shell with a centered main region), `Frame` (aspect-ratio-locked clipped media box), `Bleed` (controlled negative margin to escape a parent padding).
|
|
117
|
+
4. `Surface` for any background-bearing, padded wrapper (card, panel, inset). Never a raw element with backgroundColor + padding hand-rolled inline.
|
|
118
|
+
5. Use the screen patterns (`@hirobius/design-system/patterns`) for the parts every screen repeats: `PageHeader` once at the top (breadcrumb, `heading2` title, status, actions), `MetricTiles` for any row of headline numbers, `FormActions` for a form footer (primary right-most and last in DOM order, destructive on the far left), `DataTableSection` for a titled table (toolbar slot, consumer row actions, empty state, scrolls on narrow widths without a caller `minWidth`), and `DestructiveSection` last for an irreversible action (danger button, then an `AlertDialog` confirm). Pick between `MetricTiles`, `Stat`, `Card.Metric` and `StatusTile`, and between `Card` and `Surface`, with the "Which one, when" table in `DESIGN.md`.
|
|
119
|
+
6. `Box` `sx` LAST — only for genuinely one-off layout that no named primitive covers. `sx` spacing/color keys MUST be HDS token keys, never raw hex/px.
|
|
120
|
+
|
|
121
|
+
Negative rules (apply everywhere, checked by `scripts/audit-tokens.mjs --full`, `check-hardcoded-spacing.mjs`, `check-hardcoded-colors.mjs`):
|
|
122
|
+
|
|
123
|
+
- No inline margins on children to fake spacing between siblings — gap/spacing on the parent (Stack/Grid/Cluster/Switcher/Sidebar/Cover) owns rhythm, not margin on the child.
|
|
124
|
+
- No raw px or hex values in any layout or color prop — every spacing value comes from the semantic gap scale (`tight | normal | inset | spacious`, or a component/subgrid step) and every color comes from a `semantic.color.*` token.
|
|
125
|
+
- No repeated outlined cards as the default structure for roadmap/status/process/overview UI — use open bands, dividers, rails, disclosures, and whitespace instead.
|
|
126
|
+
|
|
127
|
+
Density: put `data-density="compact"` on the same `[data-hds]` scope element (or `<html>`) to tighten `semantic.space.scale.*`, surface padding and region gutter; `Table` follows it unless given a `density` prop.
|
|
128
|
+
|
|
129
|
+
Reference: `docs/architecture/variant-contract.md` for structural/semantic/size/density variance; `src/app/data/component-api.json` for every layout primitive's full prop table and `@ai-rules` guidance.
|
|
130
|
+
|
|
131
|
+
## How To Build A Scroll-Driven Section
|
|
132
|
+
|
|
133
|
+
Canonical primitives, cheapest-first (CSS before JS, JS before an opt-in dependency):
|
|
134
|
+
|
|
135
|
+
1. `Reveal` (CSS `animation-timeline: view()`) for fade/slide/scale-in-on-enter — zero JS, zero deps. Pick `animation` from `fade | fade-up | fade-down | scale`. Content is visible by DEFAULT; the effect applies only where `animation-timeline` is supported and the user has not requested reduced motion — never gate visibility behind either.
|
|
136
|
+
2. `Pin` (`position: sticky`) for a pinned scroll scene — the dependency-free basis for the "tall section + sticky child" pattern (GSAP's `pin: true`, done with zero JS). Give the pinned element a TALLER scrolling parent (e.g. `height: 300vh`) so it has room to travel; `top` is a CSS length offset, not a spacing token.
|
|
137
|
+
3. `useScrollProgress` (from `@hirobius/design-system/scroll`) only when the 0→1 scroll value is needed in React — cross-element choreography, canvas/WebGL, or a Motion (`motion/react`) `useTransform` binding that CSS `animation-timeline` cannot express. Thin, SSR-guarded wrapper over Motion `useScroll`; adds no new dependency.
|
|
138
|
+
4. `SmoothScroll` (from `@hirobius/design-system/scroll`, `lenis` as an OPTIONAL peer dep) only for opt-in momentum ("inertia") scrolling, mounted once at the app/site root. Never imported from the main barrel — consumers who skip it pay nothing. Reduced-motion-first: Lenis is not instantiated when the user prefers reduced motion, unless `ignoreReducedMotion` is set for a deliberate art-directed exception.
|
|
139
|
+
5. Do not adopt GSAP/ScrollTrigger, and do not wire Lenis directly outside `SmoothScroll`, inside the core library — the CSS + Motion stack above covers reveal/pin/scrub without new dependencies. Bespoke GSAP/Lenis/WebGL scenes stay app-level/downstream (marketing sites, the clients factory), composed from these primitives (ADR-021, #116).
|
|
140
|
+
|
|
141
|
+
Negative rules:
|
|
142
|
+
|
|
143
|
+
- No hand-rolled IntersectionObserver reveal-on-scroll logic — use `Reveal`.
|
|
144
|
+
- No hand-rolled `position: sticky` scroll scenes — use `Pin`.
|
|
145
|
+
- No GSAP/ScrollTrigger or bespoke Lenis wiring inside `@hirobius/design-system` — those stay app-level/downstream, composed from `Reveal`/`Pin`/`useScrollProgress`/`SmoothScroll`.
|
|
146
|
+
- Every scroll effect must degrade to fully visible/static content — never gate content visibility behind `animation-timeline` support or a scroll listener with no fallback.
|
|
147
|
+
|
|
148
|
+
Reference: `src/app/components/reveal.tsx`, `src/app/components/pin.tsx`, `src/scroll/` (`use-scroll-progress.ts`, `smooth-scroll.tsx`), ADR-021, and `src/stories/patterns-scroll.stories.tsx` for golden-path examples.
|
|
149
|
+
|
|
150
|
+
## HDS Card Anatomy (mandatory — every property is non-negotiable)
|
|
151
|
+
|
|
152
|
+
When building any card component or card-like surface, ALL of the following rules apply. There is no creative latitude here — deviation from any property is a bug.
|
|
153
|
+
|
|
154
|
+
| Property | Required value | Forbidden |
|
|
155
|
+
| --- | --- | --- |
|
|
156
|
+
| Background | `var(--semantic-color-surface-raised)` | Custom colors, gradients, tinted fills, any non-token value |
|
|
157
|
+
| Border | `1px solid var(--semantic-color-border-default)` | `box-shadow` as an elevation substitute |
|
|
158
|
+
| 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 |
|
|
159
|
+
| Padding | `var(--semantic-space-surface-padding)` or `<Surface padding="component">` | Raw pixel values, Tailwind spacing classes, ad hoc insets |
|
|
160
|
+
| Shadow | Resting cards: none (`elevation.flat`). Interactive lifted state: `shadow.subtle` via `elevation.raised`. Never reach for shadow values directly — bind via `var(--semantic-elevation-{role}-shadow)` | Raw `box-shadow` values, `drop-shadow`, glow, or any depth effect not bound to a role token |
|
|
161
|
+
| Title | `hds.typeStyles.heading3` / `<Text variant="heading3">` | Any other type style for the primary card heading |
|
|
162
|
+
| Subtitle / meta | `hds.typeStyles.caption` / `<Text variant="caption">` + `var(--semantic-color-content-secondary)` | Primary color, body size, or custom color for secondary text |
|
|
163
|
+
| Hover (interactive cards only) | `transform: scale(1.02)` CSS transform | Background color change, fill swap, border color shift on hover |
|
|
164
|
+
|
|
165
|
+
**NEVER on any card surface:** gradient backgrounds, glow effects, frosted glass (`backdrop-filter: blur`), decorative overlays, gradient borders, colored or tinted card backgrounds, inner shadows, patterned backgrounds, AI-aesthetic shimmer or particle effects. Never reach for shadow values directly — bind to a `semantic.elevation.*` role bundle so surface + shadow + border stay coherent.
|
|
166
|
+
|
|
167
|
+
## Elevation roles
|
|
168
|
+
|
|
169
|
+
| Surface | Role token | Background | Shadow | Border |
|
|
170
|
+
| --- | --- | --- | --- | --- |
|
|
171
|
+
| Card / panel resting | `semantic.elevation.flat` | `surface.page` | none | `border.subtle` 1px |
|
|
172
|
+
| Card / panel lifted (interactive only) | `semantic.elevation.raised` | `surface.raised` | `shadow.subtle` | none |
|
|
173
|
+
| Popover / dropdown / tooltip | `semantic.elevation.floating` | `surface.raised` | `shadow.floating` | none |
|
|
174
|
+
| Dialog / sheet / modal | `semantic.elevation.overlay` | `surface.overlay` | `shadow.overlay` | none |
|
|
175
|
+
|
|
176
|
+
Cards default to `elevation.flat`. Popovers/tooltips/dropdowns use `elevation.floating`. Dialogs/sheets use `elevation.overlay`. Interactive cards lift to `elevation.raised` on hover. Never combine `raised` with a border — depth is one mechanism (border OR shadow), not both stacked.
|
|
177
|
+
|
|
178
|
+
Overlays (Dialog, AlertDialog, Menu, ContextMenu, Popover, Select, HoverCard, 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.
|
|
179
|
+
|
|
180
|
+
## Slices And Full Bundle
|
|
181
|
+
|
|
182
|
+
Load only what the task needs. Same text as this file, split by topic:
|
|
183
|
+
|
|
184
|
+
- `public/llms/layout.txt` - screen layout recipe, card anatomy, elevation roles
|
|
185
|
+
- `public/llms/tokens.txt` - token rules and the quick token reference
|
|
186
|
+
- `public/llms/scroll.txt` - scroll-driven section recipe
|
|
187
|
+
- `public/llms/components.txt` - component inventory pointer, API pointer, props digest
|
|
188
|
+
|
|
189
|
+
- `public/llms-full.txt` - this file + the full `DESIGN.md` + a compact props digest for every component.
|
|
190
|
+
|
|
191
|
+
Paths in this file that begin with `docs/architecture/`, `src/app/components/`, `src/scroll/`, `src/stories/` or under `scripts/`, or that name `public/manifest.json`, `DESIGN-HANDOFF.md`, `TOKEN_GOVERNANCE.md` or `SYSTEMS_REGISTRY.md` exist only in the source repo, not in the npm package. Everything under "Default context" below ships in the package.
|
|
192
|
+
|
|
193
|
+
## Context Loading Rules (Credit Efficiency)
|
|
194
|
+
|
|
195
|
+
Default context (load first):
|
|
196
|
+
|
|
197
|
+
- `public/llms.txt`
|
|
198
|
+
- `public/hds-manifest.json`
|
|
199
|
+
- `src/app/data/component-api.json`
|
|
200
|
+
- `hirobius.tokens.json`
|
|
201
|
+
- `DESIGN.md`
|
|
202
|
+
|
|
203
|
+
On-demand only (load only if explicitly requested or the task clearly requires it):
|
|
204
|
+
|
|
205
|
+
- `DESIGN-HANDOFF.md`
|
|
206
|
+
- `TOKEN_GOVERNANCE.md`
|
|
207
|
+
- `SYSTEMS_REGISTRY.md`
|
|
208
|
+
|
|
209
|
+
## Pattern Inventory
|
|
210
|
+
|
|
211
|
+
- DataTableSection
|
|
212
|
+
- DestructiveSection
|
|
213
|
+
- FormActions
|
|
214
|
+
- MetricTiles
|
|
215
|
+
- PageHeader
|
|
216
|
+
|
|
217
|
+
## Icons
|
|
218
|
+
|
|
219
|
+
Icons come from the curated subpath `@hirobius/design-system/icons`; nothing extra to install.
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { IconButton } from '@hirobius/design-system';
|
|
223
|
+
import { Ellipsis } from '@hirobius/design-system/icons';
|
|
224
|
+
|
|
225
|
+
<IconButton icon={Ellipsis} label="Row actions" />
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Rule: icon-only actions (row menus, close, edit) use `IconButton`; do not hand-roll a button with a glyph or text "...".
|
|
229
|
+
|
|
230
|
+
Names: Archive, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Bell, Bookmark, Calendar, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, CircleAlert, CircleCheck, CircleHelp, Clock, Copy, Download, Ellipsis, EllipsisVertical, ExternalLink, Eye, EyeOff, FileText, Funnel, Heart, House, Image, Info, Link, Lock, LogIn, LogOut, Mail, Menu, Minus, Pencil, Plus, RefreshCw, Save, Search, Settings, Share, Star, Trash2, TriangleAlert, Upload, User, X
|
|
231
|
+
|
|
232
|
+
Legacy names map to canonical ones: MoreHorizontal -> Ellipsis, MoreVertical -> EllipsisVertical, AlertTriangle -> TriangleAlert, Home -> House, Filter -> Funnel.
|
|
233
|
+
|
|
234
|
+
Name collisions: `Calendar` and `Menu` share names with HDS components; alias the icon: `import { Calendar as CalendarIcon, Menu as MenuIcon } from '@hirobius/design-system/icons'`. For an icon outside the set, install `lucide-react@0.487.0` (same version keeps the `LucideIcon` type identical).
|
|
235
|
+
|
|
236
|
+
## Token Rules
|
|
237
|
+
|
|
238
|
+
- Component inventory: read `public/hds-manifest.json`. Do not duplicate inventories in markdown.
|
|
239
|
+
- Component prop API: read `src/app/data/component-api.json`. Do not inline prop tables in `llms.txt`.
|
|
240
|
+
- Token source of truth: read `hirobius.tokens.json` (W3C DTCG). Prefer `semantic.*` and `component.*` tokens over `primitive.*` for product UI.
|
|
241
|
+
- CSS variables: token path `semantic.color.surface.page` maps to `var(--semantic-color-surface-page)` (see generated token refs).
|
|
242
|
+
- Docs: use `DESIGN.md` as the default lean visual spec. Load `DESIGN-HANDOFF.md` only on-demand.
|
|
243
|
+
- Load `TOKEN_GOVERNANCE.md` and `SYSTEMS_REGISTRY.md` only on-demand (when explicitly requested or required by the task).
|
|
244
|
+
- Read `public/llms.txt` before touching code so AI workflows start from the same system map as humans.
|
|
245
|
+
|
|
246
|
+
## Agent Workflow
|
|
247
|
+
|
|
248
|
+
1. Read `public/llms.txt` and the relevant source files.
|
|
249
|
+
2. Check `public/hds-manifest.json` for component metadata and phase status.
|
|
250
|
+
3. Check `src/app/data/component-api.json` for prop names, unions, defaults, and descriptions.
|
|
251
|
+
4. Use `hirobius.tokens.json` (and generated CSS vars) for styling decisions, never raw hex or ad hoc values.
|
|
252
|
+
5. Run `pnpm tokens:audit` or `pnpm build` after changes that affect docs, tokens, or manifests.
|
|
253
|
+
|
|
254
|
+
## Key Files
|
|
255
|
+
|
|
256
|
+
- `public/hds-manifest.json` - canonical machine-readable system inventory, metadata, and token snapshot
|
|
257
|
+
- `src/app/data/component-api.json` - generated prop reference (source of truth for prop docs)
|
|
258
|
+
- `hirobius.tokens.json` - token source of truth (W3C DTCG)
|
|
259
|
+
- `public/llms.txt` - machine-readable AI context index
|
|
260
|
+
- `DESIGN.md` - lean agent-facing visual spec (default)
|
|
261
|
+
- `DESIGN-HANDOFF.md` - verbose visual language mirror (on-demand only)
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
# DESIGN.md (full)
|
|
266
|
+
|
|
267
|
+
<!-- GENERATED FILE — DO NOT EDIT. Source: DESIGN.source.md. Regenerate with `pnpm tokens`. -->
|
|
268
|
+
|
|
269
|
+
# DESIGN.md
|
|
270
|
+
|
|
271
|
+
A machine- and human-readable specification of the Hirobius Design System for AI agents, design tools, and humans generating or reviewing UI. Values are sourced from `hirobius.tokens.json`; narrative rules are hand-authored. For the full tokens reference see `DESIGN-HANDOFF.md`.
|
|
272
|
+
|
|
273
|
+
## Overview
|
|
274
|
+
|
|
275
|
+
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.
|
|
276
|
+
|
|
277
|
+
## Colors
|
|
278
|
+
|
|
279
|
+
<!-- auto:start:colors -->
|
|
280
|
+
**One accent — one neutral system.**
|
|
281
|
+
|
|
282
|
+
- **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).
|
|
283
|
+
- **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.
|
|
284
|
+
- **Feedback — Error** (`#B91C1C`): destructive confirms, error banners, validation failures. `semantic.color.feedback.error`.
|
|
285
|
+
- **Feedback — Success** (`#047857`): positive confirmations, completed states. `semantic.color.feedback.success`.
|
|
286
|
+
- **Feedback — Warning** (`#92400E`): cautions, recoverable issues. `semantic.color.feedback.warning`.
|
|
287
|
+
- **Feedback — Info** (`#1E2EFD`): neutral announcements and inline guidance. `semantic.color.feedback.info`.
|
|
288
|
+
|
|
289
|
+
Feedback hues are never decorative; do not use them as accents. Light and dark mode values are defined per-token in `hirobius.tokens.json`.
|
|
290
|
+
<!-- auto:end:colors -->
|
|
291
|
+
|
|
292
|
+
## Typography
|
|
293
|
+
|
|
294
|
+
<!-- auto:start:typography -->
|
|
295
|
+
HDS ships three typefaces — each with a distinct and exclusive role:
|
|
296
|
+
|
|
297
|
+
- **Display / Heading font**: Satoshi. Bound exclusively to `display`, `h1`, `h2`, and `h3` styles. Never used for body copy or UI labels.
|
|
298
|
+
- **Body / UI font**: Satoshi. All prose, labels, small text, captions, and UI copy.
|
|
299
|
+
- **Mono font**: Geist Mono. Reserved for tokens, code, technical callouts, and metric readouts.
|
|
300
|
+
|
|
301
|
+
Weights declared: `400` regular, `500` medium, `700` bold. Heading styles (display · h1 · h2 · h3) use `700` bold; body, UI, and caption use `500` medium. Declared but unused by any semantic role: `400` regular.
|
|
302
|
+
|
|
303
|
+
### Type ramp
|
|
304
|
+
|
|
305
|
+
| Role | Size (desktop max) | Weight | Use |
|
|
306
|
+
| --- | --- | --- | --- |
|
|
307
|
+
| `semantic.typography.display` | 60px | 700 | Display headline |
|
|
308
|
+
| `semantic.typography.h1` | 48px | 700 | Primary section headings (h1) |
|
|
309
|
+
| `semantic.typography.h2` | 30px | 700 | Secondary section headings (h2) |
|
|
310
|
+
| `semantic.typography.h3` | 20px | 700 | Component and card headers (h3) |
|
|
311
|
+
| `semantic.typography.body` | 16px | 500 | Body prose |
|
|
312
|
+
| `semantic.typography.ui` | 14px | 500 | UI text for nav, labels, captions |
|
|
313
|
+
| `semantic.typography.caption` | 12px | 500 | Caption / helper text |
|
|
314
|
+
| `semantic.typography.eyebrow` | 12px | 500 | Eyebrow / kicker label |
|
|
315
|
+
| `semantic.typography.mono` | 14px | 400 | Monospace for code, token names, shortcuts |
|
|
316
|
+
| `semantic.typography.lineHeight.none` | | | Semantic alias for leading-none (1) |
|
|
317
|
+
|
|
318
|
+
> Responsive `clamp()` overrides live in `src/styles/theme.css`; tokens store the desktop-max static value.
|
|
319
|
+
<!-- auto:end:typography -->
|
|
320
|
+
|
|
321
|
+
## Spacing
|
|
322
|
+
|
|
323
|
+
<!-- auto:start:spacing -->
|
|
324
|
+
**Base unit: 4px.** All spacing snaps to the primitive scale; never introduce half-steps or arbitrary px values.
|
|
325
|
+
|
|
326
|
+
Scale: `0px` (`primitive.space.0`) · `1px` (`primitive.space.px1`) · `2px` (`primitive.space.px2`) · `4px` (`primitive.space.1`) · `6px` (`primitive.space.px6`) · `8px` (`primitive.space.2`) · `10px` (`primitive.space.px10`) · `12px` (`primitive.space.3`) · `16px` (`primitive.space.4`) · `20px` (`primitive.space.5`) · `24px` (`primitive.space.6`) · `28px` (`primitive.space.7`) · `32px` (`primitive.space.8`) · `40px` (`primitive.space.10`) · `48px` (`primitive.space.12`) · `64px` (`primitive.space.16`) · `80px` (`primitive.space.20`) · `96px` (`primitive.space.24`) · `128px` (`primitive.space.32`)
|
|
327
|
+
|
|
328
|
+
Use `primitive.space.*` for layout rhythm, padding, and gaps. Use `semantic.space.*` aliases (e.g. `semantic.space.surface.padding`) when the purpose is established. `data-density="compact"` (on `<html>` or the `[data-hds]` scope element) remaps `semantic.space.scale.*`, `semantic.space.surface.padding` and `semantic.space.region.gutter` one step down the scale, and `Table` follows it. The `--hds-space-{xs…4xl}` vars are a legacy bridge that no component reads.
|
|
329
|
+
<!-- auto:end:spacing -->
|
|
330
|
+
|
|
331
|
+
## Corner-Radius Policy
|
|
332
|
+
|
|
333
|
+
Shape is one knob. `semantic.radius.action` is the system's single shape value — interactive controls (buttons, inputs, badges, alerts, segmented items) all resolve to it, and Tailwind's `rounded-md` maps to it exactly so the utility and the token cannot disagree. Containers sit one step above at `rounded-lg` (`action + 4px`); `rounded-sm` (`action - 2px`) is for chrome nested inside a control. `full` is reserved for pills and circular forms, and `0px` only for intentional outer canvas or substrate boundaries, never everyday UI controls. Reshaping the whole system means overriding `role.radius` in one tenant overlay — that is how `brutalist-demo` goes square in a single value.
|
|
334
|
+
|
|
335
|
+
<!-- auto:start:radius -->
|
|
336
|
+
| Tier | Value | Token | Applies to |
|
|
337
|
+
| --- | --- | --- | --- |
|
|
338
|
+
| Action | `8px` | `semantic.radius.action` | Buttons, inputs, badges, alerts, disclosures, segmented control items |
|
|
339
|
+
| Container | `12px` | `role.radius` + 4px (`rounded-lg`) | Cards, surfaces, segmented control surface, modal/sheet containers |
|
|
340
|
+
| Full | `9999px` | `primitive.radius.full` | Pills, avatars, indicator dots, any intentionally circular form |
|
|
341
|
+
| Zero | `0px` | `primitive.radius.0` | Outer canvas / substrate boundaries only — never on everyday UI controls |
|
|
342
|
+
<!-- auto:end:radius -->
|
|
343
|
+
|
|
344
|
+
## Elevation
|
|
345
|
+
|
|
346
|
+
Depth is communicated through 4 elevation roles bundled by `semantic.elevation.*`. Each role bundles a surface, shadow, and border so primitives can't mismatch them.
|
|
347
|
+
|
|
348
|
+
### Elevation roles
|
|
349
|
+
|
|
350
|
+
| Surface | Role token | Background | Shadow | Border |
|
|
351
|
+
| -------------------------------------- | ----------------------------- | ----------------- | ----------------- | ------------------- |
|
|
352
|
+
| Card / panel resting | `semantic.elevation.flat` | `surface.page` | none | `border.subtle` 1px |
|
|
353
|
+
| Card / panel lifted (interactive only) | `semantic.elevation.raised` | `surface.raised` | `shadow.subtle` | none |
|
|
354
|
+
| Popover / dropdown / tooltip | `semantic.elevation.floating` | `surface.raised` | `shadow.floating` | none |
|
|
355
|
+
| Dialog / sheet / modal | `semantic.elevation.overlay` | `surface.overlay` | `shadow.overlay` | none |
|
|
356
|
+
|
|
357
|
+
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.
|
|
358
|
+
|
|
359
|
+
Overlays (Dialog, AlertDialog, Menu, ContextMenu, Popover, Select, HoverCard, 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.
|
|
360
|
+
|
|
361
|
+
## Motion
|
|
362
|
+
|
|
363
|
+
<!-- auto:start:motion -->
|
|
364
|
+
Motion (lift on hover, parallax) is the interaction-affordance layer; static depth comes from the `semantic.elevation.*` role-token bundles.
|
|
365
|
+
|
|
366
|
+
### Duration tiers
|
|
367
|
+
|
|
368
|
+
| Tier | Value | When to use |
|
|
369
|
+
| --- | --- | --- |
|
|
370
|
+
| `primitive.duration.instant` | `100ms` | Immediate dismissals, binary toggles |
|
|
371
|
+
| `primitive.duration.short` | `150ms` | Productive micro-interactions (default for hover/focus/press) |
|
|
372
|
+
| `primitive.duration.medium` | `250ms` | Expressive entrances, teaching moments |
|
|
373
|
+
| `primitive.duration.long` | `400ms` | Spatial movement, page travel, parallax |
|
|
374
|
+
|
|
375
|
+
### Semantic intents
|
|
376
|
+
|
|
377
|
+
| Intent | Duration | Purpose |
|
|
378
|
+
| --- | --- | --- |
|
|
379
|
+
| `semantic.motion.productive` | `150ms` | For micro-interactions and status changes. No deformation. |
|
|
380
|
+
| `semantic.motion.expressive` | `250ms` | For teaching moments and significant UI entries. Includes physics-based squish. |
|
|
381
|
+
| `semantic.motion.spatial` | `400ms` | For elements traveling long distances across the viewport. |
|
|
382
|
+
| `semantic.motion.exit` | `100ms` | For elements being removed from the DOM. |
|
|
383
|
+
|
|
384
|
+
Default most interactive feedback to `productive` (150ms, decelerate). Reserve `expressive` (250ms, spring) for teaching moments where the motion itself carries meaning. `spatial` (400ms) is for travel, not decoration.
|
|
385
|
+
|
|
386
|
+
### Other semantic motion tokens
|
|
387
|
+
|
|
388
|
+
| Token | Value | Purpose |
|
|
389
|
+
| --- | --- | --- |
|
|
390
|
+
| `semantic.motion.distance` | `24px` | Travel distance for a scroll-reveal translateY offset. Coincides in value with semantic.space.scale.md today, but names a motion travel distance rather than a spacing tier (hds#242). |
|
|
391
|
+
<!-- auto:end:motion -->
|
|
392
|
+
|
|
393
|
+
## Components
|
|
394
|
+
|
|
395
|
+
<!-- auto:start:components -->
|
|
396
|
+
| Component | Radius | States | Guidance |
|
|
397
|
+
| --- | --- | --- | --- |
|
|
398
|
+
| **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. Icon buttons (`IconButton`) follow the same token surface. Icon-only actions use `IconButton` with an icon from `@hirobius/design-system/icons`. |
|
|
399
|
+
| **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`. |
|
|
400
|
+
| **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. |
|
|
401
|
+
| **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. |
|
|
402
|
+
| **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. |
|
|
403
|
+
| **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`. |
|
|
404
|
+
| **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`. |
|
|
405
|
+
| **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`. |
|
|
406
|
+
|
|
407
|
+
See `public/hds-manifest.json` and `src/app/data/component-api.json` for the full inventory and prop tables.
|
|
408
|
+
<!-- auto:end:components -->
|
|
409
|
+
|
|
410
|
+
### Card Anatomy (mandatory — all properties non-negotiable)
|
|
411
|
+
|
|
412
|
+
Every HDS card surface must conform to this anatomy exactly. No creative interpretation is permitted on any of these properties.
|
|
413
|
+
|
|
414
|
+
| Property | Required value | Forbidden |
|
|
415
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
416
|
+
| Background | `var(--semantic-color-surface-raised)` | Any gradient, tinted fill, or custom color |
|
|
417
|
+
| Border | `1px solid var(--semantic-color-border-default)` | `box-shadow` as an elevation substitute |
|
|
418
|
+
| 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 |
|
|
419
|
+
| Padding | `var(--semantic-space-component-padding)` or `<HdsSurface padding="component">` | Raw pixel values or ad hoc insets |
|
|
420
|
+
| 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 |
|
|
421
|
+
| Title | `hds.typeStyles.heading3` / `<HdsText variant="heading3">` | Any other type style for the primary card heading |
|
|
422
|
+
| Subtitle / meta | `hds.typeStyles.caption` + `var(--semantic-color-content-secondary)` | Primary content color or body size for secondary text |
|
|
423
|
+
| Hover (interactive only) | `transform: scale(1.02)` | Background fill change, border color shift, or opacity fade on hover |
|
|
424
|
+
|
|
425
|
+
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.
|
|
426
|
+
|
|
427
|
+
## Screen Patterns
|
|
428
|
+
|
|
429
|
+
Five patterns sit above the primitives so that every screen is composed the same way. Import them from `@hirobius/design-system/patterns`.
|
|
430
|
+
|
|
431
|
+
### Page title rule
|
|
432
|
+
|
|
433
|
+
Every screen has exactly one `PageHeader`. The page title is `heading2` (30px), a fixed size with no size prop; `level` changes only the DOM heading element. `display` and `h1` are reserved for marketing and landing surfaces and are never a screen title. Breadcrumb goes in the `breadcrumb` slot, one status `Badge` in `status`, screen-level actions in `actions`.
|
|
434
|
+
|
|
435
|
+
### Which one, when
|
|
436
|
+
|
|
437
|
+
Pick by what the thing is. The first four rows are for a headline number or a state; the rest are for containers and sections.
|
|
438
|
+
|
|
439
|
+
| Component | Use it for | Use instead |
|
|
440
|
+
| -------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
441
|
+
| `MetricTiles` | The default for any row of headline numbers on a screen. One fixed tile size. | Nothing: start here. |
|
|
442
|
+
| `Stat` | An inline number inside prose or a dense list. | `MetricTiles` when the number stands alone in a row of its own. |
|
|
443
|
+
| `Card.Metric` | A metric inside an existing `Card` only. | `MetricTiles` when there is no enclosing `Card`. |
|
|
444
|
+
| `StatusTile` | State with notes and a trailing badge, never a number. | `MetricTiles` when the tile is a number; `StatusTile` never carries a value. |
|
|
445
|
+
| `Card` | A titled or interactive content object (header, body, footer, or selectable). | `Surface` when there is no title and nothing to press. |
|
|
446
|
+
| `Surface` | A plain padded background around content that has no header of its own. | `Card` when the content is titled or interactive. |
|
|
447
|
+
| `DestructiveSection` | The one irreversible action on a screen, with an explanation and a confirm. | `FormActions` `destructive` slot for a delete beside a form's own buttons. |
|
|
448
|
+
| `DataTableSection` | A titled table with a toolbar, row actions and an empty state. | `Table` alone when there is no heading, toolbar or empty state to show. |
|
|
449
|
+
|
|
450
|
+
`Card` and `Surface` share one container radius, `rounded-lg` (`role.radius` + 4 px: 12 px by default, 4 px under `brutalist-demo`). Dialogs and alert dialogs use it too. Never read `--component-card-radius` for a container; it ignores the tenant.
|
|
451
|
+
|
|
452
|
+
`MetricTiles` has `min(tiles, 4)` columns, so a row never leaves an empty column, and every tile has one fixed min-height with the value in `heading2`, the label as an eyebrow and the sub line in `caption`. Its tone comes from the fixed feedback vocabulary: `neutral | success | warning | danger | info`.
|
|
453
|
+
|
|
454
|
+
### Destructive and table sections
|
|
455
|
+
|
|
456
|
+
`DestructiveSection` is a titled danger zone with one danger `Button` that opens an `AlertDialog`; it never runs the action from the button itself, only from the dialog's confirm. Put it last on the screen, below the form. `DataTableSection` puts a `Table` under a heading and a toolbar slot. Row actions are consumer nodes in a trailing column, an empty `rows` array shows an `EmptyState`, and the table scrolls horizontally inside the section on narrow widths, so a caller never sets `minWidth`.
|
|
457
|
+
|
|
458
|
+
### Form actions rule
|
|
459
|
+
|
|
460
|
+
`FormActions` puts the primary submit last in DOM order and right-most, with the secondary or cancel action immediately to its left. A destructive action goes on the far left, apart from the other two, and never to the right of the primary. The row is not sticky unless `sticky` is set.
|
|
461
|
+
|
|
462
|
+
## Do's and Don'ts
|
|
463
|
+
|
|
464
|
+
- 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`).
|
|
465
|
+
- 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.
|
|
466
|
+
- Don't tint neutrals warm or cool; greys should remain genuinely neutral and high-contrast.
|
|
467
|
+
- 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`.
|
|
468
|
+
- Don't hardcode colors, spacing, radius, or typography values when governed tokens already exist.
|
|
469
|
+
- Don't crowd the canvas; if a layout feels compressed, remove complexity before removing breathing room.
|
|
470
|
+
- Don't default repeated roadmap, status, process, or overview groups to outlined cards; prefer open bands, section dividers, accent rails, tabs, disclosures, and whitespace. Cards are for genuinely discrete repeated objects, not the primary layout language.
|
|
471
|
+
- Don't sticker badges onto the ends of prose lines. Status and progress should live in a predictable metadata slot, rail, header zone, table column, or progress surface; badges are reserved for compact state markers where their placement is intentional.
|
|
472
|
+
- Don't add decorative illustration, ornamental icons, or trend-driven filler that lacks functional or structural purpose.
|
|
473
|
+
- Don't make motion playful or bouncy by default; movement should feel controlled, precise, and intentional, with expressive motion used sparingly and only when it teaches or clarifies.
|
|
474
|
+
- Don't add `whileTap` scale transforms for press feedback; use color, border, and state-contrast changes instead — transforms are reserved for spatial motion, not interaction acknowledgment.
|
|
475
|
+
- Don't define a global disabled-state rule (opacity multiplier, saturation ramp, etc.); disabled presentation is governed per-component through its dedicated disabled tokens.
|
|
476
|
+
|
|
477
|
+
## Open Questions
|
|
478
|
+
|
|
479
|
+
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.
|
|
480
|
+
|
|
481
|
+
<!-- auto:start:build-meta -->
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
> Generated from `hirobius.tokens.json` (381 tokens) and `public/hds-manifest.json` by `scripts/build-design-md.mjs`.
|
|
485
|
+
> Hand-edit `DESIGN.source.md`; this file (`DESIGN.md`) is overwritten by `pnpm tokens`.
|
|
486
|
+
<!-- auto:end:build-meta -->
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## Component Props Digest
|
|
491
|
+
|
|
492
|
+
Compact: name, first line of description, then prop: type = default. Full detail in `src/app/data/component-api.json`.
|
|
493
|
+
|
|
494
|
+
### ActivityFeed
|
|
495
|
+
ActivityFeed — chronological system event log. Renders a list of activity events using white space as the sole separator. No dividers, no borders between items…
|
|
496
|
+
- events: ActivityEvent[] = [ { id: 'evt-001', title: 'File Uploade…
|
|
497
|
+
|
|
498
|
+
### Alert
|
|
499
|
+
Alert - compact feedback surface with contextual severity.
|
|
500
|
+
- children: ReactNode
|
|
501
|
+
- title: string
|
|
502
|
+
- tone: 'success' | 'danger' | 'warning' | 'info' = info
|
|
503
|
+
|
|
504
|
+
### AlertDialog
|
|
505
|
+
AlertDialog root + parts. Controlled via `open`/`onOpenChange`, or uncontrolled with `defaultOpen`.
|
|
506
|
+
- children: React.ReactNode
|
|
507
|
+
- defaultOpen: boolean
|
|
508
|
+
- onOpenChange: ((open: boolean) => void)
|
|
509
|
+
- open: boolean
|
|
510
|
+
|
|
511
|
+
### AspectRatio
|
|
512
|
+
Locks its single child to the given width-to-height `ratio` so media reserves its box up front and never causes layout shift while it loads.
|
|
513
|
+
- asChild: boolean
|
|
514
|
+
- ratio: number = 1
|
|
515
|
+
|
|
516
|
+
### AssetImg
|
|
517
|
+
AssetImg - responsive asset frame with fallback placeholder handling. Contexts: default, lightbox, and detail.
|
|
518
|
+
- alt: string
|
|
519
|
+
- className: string
|
|
520
|
+
- context: 'default' | 'lightbox' | 'detail' = default
|
|
521
|
+
- draggable: boolean = false
|
|
522
|
+
- expandable: boolean = true
|
|
523
|
+
- expandLabel: string
|
|
524
|
+
- isDark: boolean = false
|
|
525
|
+
- loading: "lazy" | "eager" = lazy
|
|
526
|
+
- naturalHeight: number
|
|
527
|
+
- naturalWidth: number
|
|
528
|
+
- onClick: ((e: MouseEvent<Element, MouseEvent>) => void)
|
|
529
|
+
- onMouseDown: ((e: MouseEvent<Element, MouseEvent>) => void)
|
|
530
|
+
- onMouseLeave: ((e: MouseEvent<Element, MouseEvent>) => void)
|
|
531
|
+
- onMouseMove: ((e: MouseEvent<Element, MouseEvent>) => void)
|
|
532
|
+
- onMouseUp: ((e: MouseEvent<Element, MouseEvent>) => void)
|
|
533
|
+
- src: string
|
|
534
|
+
- style: CSSProperties = {}
|
|
535
|
+
- title: string
|
|
536
|
+
|
|
537
|
+
### Avatar
|
|
538
|
+
Circular avatar. Renders the image when available, else initials from `alt`.
|
|
539
|
+
- alt: string
|
|
540
|
+
- initials: string
|
|
541
|
+
- size: "sm" | "md" | "lg" | null
|
|
542
|
+
- src: string
|
|
543
|
+
|
|
544
|
+
### AvatarGroup
|
|
545
|
+
Renders up to `max` overlapping avatars followed by a `+N` overflow chip.
|
|
546
|
+
- children: ReactNode
|
|
547
|
+
- max: number
|
|
548
|
+
- size: "sm" | "md" | "lg" | null
|
|
549
|
+
|
|
550
|
+
### Badge
|
|
551
|
+
Compact metadata/status chip. Tone is the only styling input.
|
|
552
|
+
- as: ElementType<any, keyof IntrinsicElements> = span
|
|
553
|
+
- tone: "neutral" | "danger" | "success" | "warning" | "info" | "inProgress" | null
|
|
554
|
+
|
|
555
|
+
### Bleed
|
|
556
|
+
Bleed — controlled negative-margin full-bleed within a padded container. Every Layout reference: https://every-layout.dev/layouts/the-stack/ (bleed is the inve…
|
|
557
|
+
- amount: 'tight' | 'normal' | 'inset' | 'spacious' = normal
|
|
558
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
559
|
+
- axis: 'x' | 'y' | 'both' = x
|
|
560
|
+
- children: ReactNode
|
|
561
|
+
- className: string
|
|
562
|
+
- style: CSSProperties
|
|
563
|
+
|
|
564
|
+
### Blockquote
|
|
565
|
+
A quoted passage; pass `cite` for the source URL and `attribution` for a byline.
|
|
566
|
+
- attribution: ReactNode
|
|
567
|
+
- size: "sm" | "md" | "lg" | null
|
|
568
|
+
|
|
569
|
+
### Box
|
|
570
|
+
Box — polymorphic layout primitive with a token-first `sx` engine. `sx` is a deliberate SUBSET of MUI's sx — not all of CSS-in-JS is a feature: - Spacing short…
|
|
571
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
572
|
+
- children: ReactNode
|
|
573
|
+
- sx: SxObject
|
|
574
|
+
|
|
575
|
+
### Breadcrumb
|
|
576
|
+
Breadcrumb trail. Links route through the HDS router seam (plain anchors with no router, client-side nav when a router adapter is provided). The final item is …
|
|
577
|
+
- items: BreadcrumbItem[]
|
|
578
|
+
- label: string = Breadcrumb
|
|
579
|
+
|
|
580
|
+
### Button
|
|
581
|
+
Triggers an action when activated.
|
|
582
|
+
- asChild: boolean = false
|
|
583
|
+
- disabled: boolean
|
|
584
|
+
- iconLeft: ReactNode
|
|
585
|
+
- iconOnly: boolean = false
|
|
586
|
+
- iconRight: ReactNode
|
|
587
|
+
- label: string
|
|
588
|
+
- loading: boolean = false
|
|
589
|
+
- size: "sm" | "md" | "lg" | null
|
|
590
|
+
- tone: "neutral" | "danger" | "success" | "warning" | "info" | null
|
|
591
|
+
- variant: "primary" | "secondary" | "tertiary" | null
|
|
592
|
+
|
|
593
|
+
### ButtonGroup
|
|
594
|
+
Groups Button (or button-like) children into a single attached segment.
|
|
595
|
+
- orientation: "horizontal" | "vertical" | null
|
|
596
|
+
|
|
597
|
+
### Calendar
|
|
598
|
+
Renders an accessible month grid; compose it inside a Popover for the date inputs.
|
|
599
|
+
|
|
600
|
+
### Callout
|
|
601
|
+
Tone-driven side-rule callout for status, quotes, hypotheses.
|
|
602
|
+
- italic: boolean = false
|
|
603
|
+
- tone: 'accent' | 'info' | 'success' | 'warning' | 'danger' = info
|
|
604
|
+
|
|
605
|
+
### Card
|
|
606
|
+
Tagged per-export, not on the file block: this module exports eight components and a file-level @figma would hand all eight this one node.
|
|
607
|
+
- as: ElementType<any, keyof IntrinsicElements>
|
|
608
|
+
- bordered: boolean = false
|
|
609
|
+
- gap: GapOption = tight
|
|
610
|
+
- noPadding: boolean = false
|
|
611
|
+
- padding: PaddingOption = component
|
|
612
|
+
- tone: 'neutral' | 'danger' | 'success' | 'warning' | 'info' = neutral
|
|
613
|
+
- variant: 'default' | 'accent' = default
|
|
614
|
+
|
|
615
|
+
### CardBody
|
|
616
|
+
Card — surface container with slot anatomy (12d-card-anatomy). Slot anatomy (DESIGN.md §"Card Anatomy"). Status, progress, and metadata are layout-bearing — th…
|
|
617
|
+
|
|
618
|
+
### CardDescription
|
|
619
|
+
Card — surface container with slot anatomy (12d-card-anatomy). Slot anatomy (DESIGN.md §"Card Anatomy"). Status, progress, and metadata are layout-bearing — th…
|
|
620
|
+
|
|
621
|
+
### CardFooter
|
|
622
|
+
Card — surface container with slot anatomy (12d-card-anatomy). Slot anatomy (DESIGN.md §"Card Anatomy"). Status, progress, and metadata are layout-bearing — th…
|
|
623
|
+
|
|
624
|
+
### CardHeader
|
|
625
|
+
Card — surface container with slot anatomy (12d-card-anatomy). Slot anatomy (DESIGN.md §"Card Anatomy"). Status, progress, and metadata are layout-bearing — th…
|
|
626
|
+
- metadata: ReactNode
|
|
627
|
+
|
|
628
|
+
### CardMetric
|
|
629
|
+
Card.Metric — one uppercase label, a large value and an optional sub-line inside a Card.
|
|
630
|
+
- label: ReactNode
|
|
631
|
+
- sub: ReactNode
|
|
632
|
+
- tone: 'neutral' | 'danger' | 'success' | 'warning' | 'info' = neutral
|
|
633
|
+
- value: ReactNode
|
|
634
|
+
|
|
635
|
+
### CardProgress
|
|
636
|
+
Card — surface container with slot anatomy (12d-card-anatomy). Slot anatomy (DESIGN.md §"Card Anatomy"). Status, progress, and metadata are layout-bearing — th…
|
|
637
|
+
- label: ReactNode
|
|
638
|
+
- max: number = 100
|
|
639
|
+
- tone: 'neutral' | 'danger' | 'success' | 'warning' | 'info' = neutral
|
|
640
|
+
- value: number
|
|
641
|
+
|
|
642
|
+
### CardTitle
|
|
643
|
+
Card — surface container with slot anatomy (12d-card-anatomy). Slot anatomy (DESIGN.md §"Card Anatomy"). Status, progress, and metadata are layout-bearing — th…
|
|
644
|
+
|
|
645
|
+
### Carousel
|
|
646
|
+
Renders children as a snap-scrolling track with Prev/Next scroll buttons.
|
|
647
|
+
- ariaLabel: string = Carousel
|
|
648
|
+
- children: ReactNode
|
|
649
|
+
- showControls: boolean = true
|
|
650
|
+
|
|
651
|
+
### Center
|
|
652
|
+
Center — max-width column, auto-centered horizontally. Every Layout reference: https://every-layout.dev/layouts/center/
|
|
653
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
654
|
+
- children: ReactNode
|
|
655
|
+
- className: string
|
|
656
|
+
- gutter: 'tight' | 'normal' | 'inset' | 'spacious'
|
|
657
|
+
- maxWidth: 'content' | 'max' = content
|
|
658
|
+
- style: CSSProperties
|
|
659
|
+
|
|
660
|
+
### Checkbox
|
|
661
|
+
Checkbox — custom-drawn checkbox with check / indeterminate glyph.
|
|
662
|
+
- checked: boolean
|
|
663
|
+
- indeterminate: boolean = false
|
|
664
|
+
- label: string
|
|
665
|
+
- onChange: (v: boolean) => void
|
|
666
|
+
|
|
667
|
+
### CinematicLink
|
|
668
|
+
CinematicLink - cinematic editorial link treatment for portfolio surfaces.
|
|
669
|
+
- children: string
|
|
670
|
+
- href: string
|
|
671
|
+
|
|
672
|
+
### CircularProgress
|
|
673
|
+
A circular progress ring; pass `value`/`max` or set `indeterminate`.
|
|
674
|
+
- indeterminate: boolean = false
|
|
675
|
+
- label: string
|
|
676
|
+
- max: number = 100
|
|
677
|
+
- size: "sm" | "md" | "lg" = md
|
|
678
|
+
- tone: "neutral" | "danger" | "success" | "warning" | "info" | null
|
|
679
|
+
- value: number = 0
|
|
680
|
+
|
|
681
|
+
### Cluster
|
|
682
|
+
Cluster — wrapping horizontal group with even gaps. Every Layout reference: https://every-layout.dev/layouts/cluster/
|
|
683
|
+
- align: 'start' | 'center' | 'end' | 'stretch' = center
|
|
684
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
685
|
+
- children: ReactNode
|
|
686
|
+
- className: string
|
|
687
|
+
- gap: 'tight' | 'normal' | 'inset' | 'spacious' = tight
|
|
688
|
+
- justify: 'start' | 'center' | 'end' | 'space-between' = start
|
|
689
|
+
- style: CSSProperties
|
|
690
|
+
|
|
691
|
+
### CodeBlock
|
|
692
|
+
CodeBlock - code display with copy button and optional collapsible toggle.
|
|
693
|
+
- className: string
|
|
694
|
+
- code: string
|
|
695
|
+
- collapsible: boolean = false
|
|
696
|
+
- defaultExpanded: boolean = false
|
|
697
|
+
- filename: string
|
|
698
|
+
- language: string
|
|
699
|
+
- truncateFromStart: boolean = false
|
|
700
|
+
- variant: "inline" | "block" = block
|
|
701
|
+
|
|
702
|
+
### Combobox
|
|
703
|
+
Combobox — searchable single-select (Popover + filtered listbox). A select-with-search built on the HDS Popover. The trigger shows the current selection; openi…
|
|
704
|
+
- aria-label: string
|
|
705
|
+
- className: string
|
|
706
|
+
- disabled: boolean = false
|
|
707
|
+
- emptyMessage: string = No results
|
|
708
|
+
- onChange: (value: string) => void
|
|
709
|
+
- options: ComboboxOption[]
|
|
710
|
+
- placeholder: string = Select…
|
|
711
|
+
- searchPlaceholder: string = Search…
|
|
712
|
+
- value: string | null
|
|
713
|
+
|
|
714
|
+
### CommandPalette
|
|
715
|
+
Mountable trigger + dialog. Drop into header slot; component manages its own open state and Cmd-K / Ctrl-K global keybinding.
|
|
716
|
+
- className: string
|
|
717
|
+
|
|
718
|
+
### ComponentInstanceMatrix
|
|
719
|
+
ComponentInstanceMatrix — responsive specimen matrix for variant and state parity.
|
|
720
|
+
- componentName: string
|
|
721
|
+
- dimensionX: string
|
|
722
|
+
- dimensionY: string
|
|
723
|
+
- freezeRowState: boolean = false
|
|
724
|
+
- isMobile: boolean
|
|
725
|
+
- renderInstance: (rowKey: string, columnKey: string) => ReactNode
|
|
726
|
+
- rowLabelTone: "primary" | "secondary" = primary
|
|
727
|
+
- rowLabelWidth: number = 120
|
|
728
|
+
- title: string
|
|
729
|
+
|
|
730
|
+
### Container
|
|
731
|
+
Container — semantic width-constrained layout. Centers content horizontally and applies semantic max-width constraints. - maxWidth options: 'content' (760px pr…
|
|
732
|
+
- children: ReactNode
|
|
733
|
+
- className: string
|
|
734
|
+
- maxWidth: 'content' | 'max' = max
|
|
735
|
+
- padding: string = var(--semantic-space-surface-padding)
|
|
736
|
+
- style: CSSProperties
|
|
737
|
+
|
|
738
|
+
### ContextMenu
|
|
739
|
+
ContextMenu root + parts. Wrap the right-clickable area in `ContextMenu.Trigger`. Controlled via `onOpenChange`.
|
|
740
|
+
- children: React.ReactNode
|
|
741
|
+
- dir: ("ltr" | "rtl")
|
|
742
|
+
- modal: boolean
|
|
743
|
+
- onOpenChange: ((open: boolean) => void)
|
|
744
|
+
- open: boolean
|
|
745
|
+
|
|
746
|
+
### Cover
|
|
747
|
+
Cover — vertical shell with an auto-centered main region. Every Layout reference: https://every-layout.dev/layouts/cover/
|
|
748
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
749
|
+
- centerSlot: ReactNode
|
|
750
|
+
- children: ReactNode
|
|
751
|
+
- className: string
|
|
752
|
+
- footer: ReactNode
|
|
753
|
+
- gap: 'tight' | 'normal' | 'inset' | 'spacious' = normal
|
|
754
|
+
- header: ReactNode
|
|
755
|
+
- minHeight: string = 100svh
|
|
756
|
+
- style: CSSProperties
|
|
757
|
+
|
|
758
|
+
### DataTableSection
|
|
759
|
+
Section heading and toolbar over a `Table`. Row actions are consumer nodes in a trailing column, the table scrolls horizontally on narrow widths without a `min…
|
|
760
|
+
- actionsLabel: string = Actions
|
|
761
|
+
- columns: TableColumn[]
|
|
762
|
+
- emptyDescription: ReactNode
|
|
763
|
+
- emptyTitle: ReactNode = Nothing here yet
|
|
764
|
+
- level: 2 | 3 | 4 | 5 | 6 = 2
|
|
765
|
+
- rows: DataTableSectionRow[]
|
|
766
|
+
- title: ReactNode
|
|
767
|
+
- toolbar: ReactNode
|
|
768
|
+
|
|
769
|
+
### DateInput
|
|
770
|
+
Text field + calendar popover for picking a single date.
|
|
771
|
+
- aria-label: string
|
|
772
|
+
- disabled: boolean = false
|
|
773
|
+
- displayFormat: string = yyyy-MM-dd
|
|
774
|
+
- id: string
|
|
775
|
+
- onChange: ((date: Date) => void) | undefined
|
|
776
|
+
- placeholder: string
|
|
777
|
+
- value: Date
|
|
778
|
+
|
|
779
|
+
### DateRangeInput
|
|
780
|
+
DateRangeInput — date-range field composing the existing Popover with Calendar in range mode, so picking a start/end date reads as one overlay pattern with Com…
|
|
781
|
+
- aria-label: string
|
|
782
|
+
- disabled: boolean = false
|
|
783
|
+
- displayFormat: string = yyyy-MM-dd
|
|
784
|
+
- id: string
|
|
785
|
+
- numberOfMonths: number = 2
|
|
786
|
+
- onChange: ((range: DateRange) => void) | undefined
|
|
787
|
+
- placeholder: string = Select date range
|
|
788
|
+
- value: DateRange
|
|
789
|
+
|
|
790
|
+
### DateTimeInput
|
|
791
|
+
Text date field + calendar popover, paired with a native time field, producing one Date.
|
|
792
|
+
- aria-label: string
|
|
793
|
+
- dateFormat: string = yyyy-MM-dd
|
|
794
|
+
- disabled: boolean = false
|
|
795
|
+
- id: string
|
|
796
|
+
- onChange: ((date: Date) => void) | undefined
|
|
797
|
+
- value: Date
|
|
798
|
+
|
|
799
|
+
### DestructiveSection
|
|
800
|
+
Titled danger zone: a title, an explanation, and one danger `Button` that opens an `AlertDialog`. Pressing the button never runs the action; only the dialog's …
|
|
801
|
+
- actionLabel: ReactNode
|
|
802
|
+
- cancelLabel: string = Cancel
|
|
803
|
+
- confirmBody: ReactNode
|
|
804
|
+
- confirmLabel: string
|
|
805
|
+
- description: ReactNode
|
|
806
|
+
- level: 2 | 3 | 4 | 5 | 6 = 2
|
|
807
|
+
- onConfirm: () => void
|
|
808
|
+
- title: ReactNode
|
|
809
|
+
|
|
810
|
+
### Dialog
|
|
811
|
+
Tagged per-export, not on the file block: this module exports ten components and a file-level @figma would hand all ten this one node.
|
|
812
|
+
- children: ReactNode
|
|
813
|
+
- defaultOpen: boolean
|
|
814
|
+
- modal: boolean
|
|
815
|
+
- onOpenChange: ((open: boolean) => void)
|
|
816
|
+
- open: boolean
|
|
817
|
+
|
|
818
|
+
### DialogClose
|
|
819
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
820
|
+
- asChild: boolean
|
|
821
|
+
|
|
822
|
+
### DialogContent
|
|
823
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
824
|
+
- asChild: boolean
|
|
825
|
+
- container: HTMLElement | null
|
|
826
|
+
- forceMount: true
|
|
827
|
+
- hideClose: boolean = false
|
|
828
|
+
- onCloseAutoFocus: ((event: Event) => void)
|
|
829
|
+
- onEscapeKeyDown: ((event: KeyboardEvent) => void)
|
|
830
|
+
- onFocusOutside: ((event: CustomEvent<{ originalEvent: FocusEvent; }>) => void)
|
|
831
|
+
- onInteractOutside: ((event: CustomEvent<{ originalEvent: PointerEvent; }> | CustomEvent<{ original…
|
|
832
|
+
- onOpenAutoFocus: ((event: Event) => void)
|
|
833
|
+
- onPointerDownOutside: ((event: CustomEvent<{ originalEvent: PointerEvent; }>) => void)
|
|
834
|
+
|
|
835
|
+
### DialogDescription
|
|
836
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
837
|
+
- asChild: boolean
|
|
838
|
+
|
|
839
|
+
### DialogFooter
|
|
840
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
841
|
+
|
|
842
|
+
### DialogHeader
|
|
843
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
844
|
+
|
|
845
|
+
### DialogOverlay
|
|
846
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
847
|
+
- asChild: boolean
|
|
848
|
+
- forceMount: true
|
|
849
|
+
|
|
850
|
+
### DialogPortal
|
|
851
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
852
|
+
- children: React.ReactNode
|
|
853
|
+
- container: Element | DocumentFragment | null
|
|
854
|
+
- forceMount: true
|
|
855
|
+
|
|
856
|
+
### DialogTitle
|
|
857
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
858
|
+
- asChild: boolean
|
|
859
|
+
|
|
860
|
+
### DialogTrigger
|
|
861
|
+
Dialog — modal dialog (shadcn baseline, compound parts). shadcn-baseline implementation (8s-7): Radix Dialog primitive (@radix-ui/react-dialog) themed with rol…
|
|
862
|
+
- asChild: boolean
|
|
863
|
+
|
|
864
|
+
### Disclosure
|
|
865
|
+
Disclosure - compact disclosure surface for optional explanatory content.
|
|
866
|
+
- accent: boolean = false
|
|
867
|
+
- children: ReactNode
|
|
868
|
+
- className: string
|
|
869
|
+
- contentStyle: CSSProperties
|
|
870
|
+
- defaultOpen: boolean = false
|
|
871
|
+
- label: ReactNode
|
|
872
|
+
- onOpenChange: ((open: boolean) => void)
|
|
873
|
+
- open: boolean
|
|
874
|
+
- triggerStyle: CSSProperties
|
|
875
|
+
- variant: 'panel' | 'nav' | 'card' = panel
|
|
876
|
+
|
|
877
|
+
### Divider
|
|
878
|
+
Divider — semantic separator between content regions.
|
|
879
|
+
- orientation: "horizontal" | "vertical" | null = horizontal
|
|
880
|
+
- spacing: string | number
|
|
881
|
+
- strong: boolean
|
|
882
|
+
- variant: "strong" | "default" | null
|
|
883
|
+
|
|
884
|
+
### DocLinkCard
|
|
885
|
+
DocLinkCard - navigation card for editorial and documentation cross-links.
|
|
886
|
+
- accent: boolean = false
|
|
887
|
+
- affordance: "up-right" | "right" | "left" = up-right
|
|
888
|
+
- description: string
|
|
889
|
+
- disabled: boolean = false
|
|
890
|
+
- href: string
|
|
891
|
+
- icon: LucideIcon
|
|
892
|
+
- meta: string
|
|
893
|
+
- metaStyle: "caption" | "ui" = caption
|
|
894
|
+
- title: string
|
|
895
|
+
- variant: "feature" | "pager" = feature
|
|
896
|
+
|
|
897
|
+
### EmptyState
|
|
898
|
+
EmptyState — consistent no-data placeholder for lists, grids, and sections.
|
|
899
|
+
- className: string
|
|
900
|
+
- description: ReactNode
|
|
901
|
+
- title: ReactNode
|
|
902
|
+
|
|
903
|
+
### Field
|
|
904
|
+
Caption label paired with a value — used in metadata grids and read-only forms.
|
|
905
|
+
- children: React.ReactNode
|
|
906
|
+
- label: string
|
|
907
|
+
- mono: boolean | null
|
|
908
|
+
- tone: "neutral" | "danger" | "success" | "warning" | "info" | null
|
|
909
|
+
- value: ReactNode
|
|
910
|
+
|
|
911
|
+
### FileInput
|
|
912
|
+
A dashed dropzone that opens the native file picker or accepts a drag-and-drop.
|
|
913
|
+
- accept: string
|
|
914
|
+
- disabled: boolean
|
|
915
|
+
- label: ReactNode = Click to upload or drag and drop
|
|
916
|
+
- multiple: boolean
|
|
917
|
+
- onFiles: ((files: File[]) => void)
|
|
918
|
+
|
|
919
|
+
### Form
|
|
920
|
+
Styled `<form>` with consistent vertical field rhythm. Tagged per-export: FormField and FormFieldShell share this module and have no Figma node, so a file-leve…
|
|
921
|
+
|
|
922
|
+
### FormActions
|
|
923
|
+
Form footer with one fixed order: destructive (far left, if any), then secondary, then primary last and right-most. Gap is the tight layout token.
|
|
924
|
+
- destructive: ReactNode
|
|
925
|
+
- primary: ReactNode
|
|
926
|
+
- secondary: ReactNode
|
|
927
|
+
- sticky: boolean = false
|
|
928
|
+
|
|
929
|
+
### FormField
|
|
930
|
+
Label + description + error wrapper that wires the a11y relationships onto its single child control via cloneElement. Validation-library agnostic — pass `error…
|
|
931
|
+
- children: ReactElement<any, string | JSXElementConstructor<any>>
|
|
932
|
+
- className: string
|
|
933
|
+
- description: string
|
|
934
|
+
- error: string
|
|
935
|
+
- htmlFor: string
|
|
936
|
+
- label: string
|
|
937
|
+
- required: boolean = false
|
|
938
|
+
|
|
939
|
+
### FormFieldShell
|
|
940
|
+
Presentational label + control slot + helper/error markup. Renders `children` verbatim — it does NOT clone — so it is safe to use with controls that own a call…
|
|
941
|
+
- children: ReactNode
|
|
942
|
+
- className: string
|
|
943
|
+
- controlId: string
|
|
944
|
+
- description: string
|
|
945
|
+
- error: string
|
|
946
|
+
- label: string
|
|
947
|
+
- required: boolean = false
|
|
948
|
+
|
|
949
|
+
### FoundationSwatch
|
|
950
|
+
FoundationSwatch - governed foundation specimen for color and semantic role previews.
|
|
951
|
+
- background: string
|
|
952
|
+
- bordered: boolean = false
|
|
953
|
+
- details: string[]
|
|
954
|
+
- foreground: string = var(--semantic-color-content-primary)
|
|
955
|
+
- hidePreviewLabel: boolean = false
|
|
956
|
+
- label: string
|
|
957
|
+
- note: ReactNode
|
|
958
|
+
- previewPosition: 'bottom-left' | 'top-left' | 'center' = center
|
|
959
|
+
- specimen: ReactNode
|
|
960
|
+
- swatchVar: string
|
|
961
|
+
- tokenDisplayPreset: 'depth1' | 'depth2' | 'full' = depth2
|
|
962
|
+
- tokenPath: string
|
|
963
|
+
- value: string
|
|
964
|
+
|
|
965
|
+
### Frame
|
|
966
|
+
Frame — aspect-ratio-locked, token-clipped media box. Every Layout reference: https://every-layout.dev/layouts/frame/
|
|
967
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
968
|
+
- children: ReactNode
|
|
969
|
+
- className: string
|
|
970
|
+
- radius: 'none' | 'sm' | 'md' | 'full' = md
|
|
971
|
+
- ratio: number = 16 / 9
|
|
972
|
+
- style: CSSProperties
|
|
973
|
+
|
|
974
|
+
### Grid
|
|
975
|
+
Grid — responsive grid composition primitive. Enforces semantic gap and column values. No arbitrary CSS grid. - layout='fixed': responsive base (collapses via …
|
|
976
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
977
|
+
- children: ReactNode
|
|
978
|
+
- className: string
|
|
979
|
+
- columns: number = 12
|
|
980
|
+
- gap: 'tight' | 'normal' | 'inset' | 'spacious' = inset
|
|
981
|
+
- layout: 'fixed' | 'auto-fit' = fixed
|
|
982
|
+
- style: CSSProperties
|
|
983
|
+
- subgrid: boolean = false
|
|
984
|
+
|
|
985
|
+
### HdsDocsShell
|
|
986
|
+
HdsDocsShell — three-region docs shell (left nav rail, content, right TOC rail), driven by grid columns that default to 0 and are set per breakpoint. hds#280 s…
|
|
987
|
+
- children: ReactNode
|
|
988
|
+
- className: string
|
|
989
|
+
- leftRail: ReactNode
|
|
990
|
+
- rightRail: ReactNode
|
|
991
|
+
- style: CSSProperties
|
|
992
|
+
- topOffset: string = 0px
|
|
993
|
+
|
|
994
|
+
### HdsThemeProvider
|
|
995
|
+
Renders a `data-hds` scope wrapper that carries the four theming dials as root attributes + CSS vars, and exposes them to `useHdsTheme()`.
|
|
996
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
997
|
+
- brand: string
|
|
998
|
+
- children: React.ReactNode
|
|
999
|
+
- className: string
|
|
1000
|
+
- density: 'comfortable' | 'compact'
|
|
1001
|
+
- fontFamily: string
|
|
1002
|
+
- fontFamilyMono: string
|
|
1003
|
+
- style: CSSProperties
|
|
1004
|
+
- theme: 'light' | 'dark'
|
|
1005
|
+
|
|
1006
|
+
### HeadingStack
|
|
1007
|
+
HeadingStack — enforced vertical rhythm for heading + subheading pairs. Automatically handles gap and secondary color, preventing manual stacking. - Heading le…
|
|
1008
|
+
- as: ElementType = div
|
|
1009
|
+
- gap: HdsHeadingGap = px8
|
|
1010
|
+
- heading: string
|
|
1011
|
+
- headingAs: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
|
|
1012
|
+
- level: HdsHeadingLevel
|
|
1013
|
+
- subheading: string
|
|
1014
|
+
- subheadingAs: 'p' | 'div' | 'span' = p
|
|
1015
|
+
|
|
1016
|
+
### HoverCard
|
|
1017
|
+
HoverCard root + parts. Controlled via `open`/`onOpenChange`, or uncontrolled with `defaultOpen`; tune timing with `openDelay`/`closeDelay`.
|
|
1018
|
+
- children: React.ReactNode
|
|
1019
|
+
- closeDelay: number
|
|
1020
|
+
- defaultOpen: boolean
|
|
1021
|
+
- onOpenChange: ((open: boolean) => void)
|
|
1022
|
+
- open: boolean
|
|
1023
|
+
- openDelay: number
|
|
1024
|
+
|
|
1025
|
+
### Icon
|
|
1026
|
+
Icon — semantic icon wrapper for Lucide icons.
|
|
1027
|
+
- aria-hidden: boolean | "true" | "false" = true
|
|
1028
|
+
- className: string
|
|
1029
|
+
- color: string = currentColor
|
|
1030
|
+
- icon: LucideIcon
|
|
1031
|
+
- size: IconSize = small
|
|
1032
|
+
- style: CSSProperties
|
|
1033
|
+
- weight: "fill" | "bold" | "light" | "thin" | "regular" | "duotone"
|
|
1034
|
+
|
|
1035
|
+
### IconButton
|
|
1036
|
+
IconButton ” icon-only action trigger built on the shared Button primitive.
|
|
1037
|
+
- aria-label: string
|
|
1038
|
+
- asChild: boolean
|
|
1039
|
+
- disabled: boolean
|
|
1040
|
+
- icon: LucideIcon
|
|
1041
|
+
- iconColor: string
|
|
1042
|
+
- iconLeft: ReactNode
|
|
1043
|
+
- iconRight: ReactNode
|
|
1044
|
+
- iconSize: IconSize
|
|
1045
|
+
- label: string
|
|
1046
|
+
- loading: boolean
|
|
1047
|
+
- size: "sm" | "md" | "lg"
|
|
1048
|
+
- tone: "neutral" | "danger" | "success" | "warning" | "info" | null
|
|
1049
|
+
- variant: "primary" | "secondary" | "tertiary" | null
|
|
1050
|
+
|
|
1051
|
+
### InlineCode
|
|
1052
|
+
InlineCode — inline code chip for token paths, file paths, and code-adjacent prose.
|
|
1053
|
+
- children: ReactNode
|
|
1054
|
+
- compact: boolean
|
|
1055
|
+
- copyable: boolean = false
|
|
1056
|
+
- density: "comfortable" | "compact" | null
|
|
1057
|
+
- style: CSSProperties
|
|
1058
|
+
|
|
1059
|
+
### InlineLink
|
|
1060
|
+
InlineLink ” inline navigation and external-link primitive for body copy.
|
|
1061
|
+
- children: ReactNode
|
|
1062
|
+
- externalIcon: boolean = true
|
|
1063
|
+
- href: string
|
|
1064
|
+
|
|
1065
|
+
### Input
|
|
1066
|
+
Input — text field primitive with label, helper, and error slots.
|
|
1067
|
+
- className: string
|
|
1068
|
+
- disabled: boolean
|
|
1069
|
+
- error: boolean
|
|
1070
|
+
- errorMessage: string
|
|
1071
|
+
- helperText: string
|
|
1072
|
+
- inputClassName: string
|
|
1073
|
+
- label: string
|
|
1074
|
+
- leadingVisual: ReactNode
|
|
1075
|
+
- loading: boolean = false
|
|
1076
|
+
- size: InputSize = md
|
|
1077
|
+
- textStyle: "body" | "mono" = body
|
|
1078
|
+
- trailingVisual: ReactNode
|
|
1079
|
+
- type: 'text' | 'email' | 'password' | 'search' | 'tel' | 'url' | 'number' = text
|
|
1080
|
+
|
|
1081
|
+
### InputGroup
|
|
1082
|
+
A single-line input with optional `leading`/`trailing` adornments.
|
|
1083
|
+
- className: string
|
|
1084
|
+
- leading: ReactNode
|
|
1085
|
+
- size: "sm" | "md" | "lg" | null
|
|
1086
|
+
- trailing: ReactNode
|
|
1087
|
+
|
|
1088
|
+
### Kbd
|
|
1089
|
+
Renders a keyboard key or shortcut token, e.g. `<Kbd>⌘K</Kbd>`.
|
|
1090
|
+
- size: "sm" | "md" | "lg" | null
|
|
1091
|
+
|
|
1092
|
+
### Lightbox
|
|
1093
|
+
Lightbox — full-bleed image viewer built on Radix Dialog. Full-bleed image viewer built on Radix Dialog (raw primitives, not the card `Dialog` wrapper — a ligh…
|
|
1094
|
+
- alt: string
|
|
1095
|
+
- caption: string
|
|
1096
|
+
- captionHref: string
|
|
1097
|
+
- captionLabel: string
|
|
1098
|
+
- naturalHeight: number
|
|
1099
|
+
- naturalWidth: number
|
|
1100
|
+
- onClose: () => void
|
|
1101
|
+
- open: boolean
|
|
1102
|
+
- src: string
|
|
1103
|
+
|
|
1104
|
+
### Menu
|
|
1105
|
+
Menu root + parts. Controlled via `open`/`onOpenChange`, or uncontrolled with `defaultOpen`.
|
|
1106
|
+
- children: React.ReactNode
|
|
1107
|
+
- defaultOpen: boolean
|
|
1108
|
+
- dir: ("ltr" | "rtl")
|
|
1109
|
+
- modal: boolean
|
|
1110
|
+
- onOpenChange: ((open: boolean) => void)
|
|
1111
|
+
- open: boolean
|
|
1112
|
+
|
|
1113
|
+
### MetadataList
|
|
1114
|
+
Renders object metadata as a semantic `<dl>` of term/description pairs.
|
|
1115
|
+
- footer: ReactNode
|
|
1116
|
+
- items: MetadataListItem[]
|
|
1117
|
+
- orientation: "horizontal" | "vertical" | null = vertical
|
|
1118
|
+
- variant: "plain" | "divided" = plain
|
|
1119
|
+
|
|
1120
|
+
### MetricTile
|
|
1121
|
+
One metric tile: eyebrow label, `heading2` value, caption sub line, on a raised surface at one fixed min-height. Wraps `Card.Metric` (the sibling with the eyeb…
|
|
1122
|
+
- label: ReactNode
|
|
1123
|
+
- sub: ReactNode
|
|
1124
|
+
- tone: 'neutral' | 'success' | 'warning' | 'danger' | 'info' = neutral
|
|
1125
|
+
- value: ReactNode
|
|
1126
|
+
|
|
1127
|
+
### MetricTiles
|
|
1128
|
+
A row of `MetricTile`s. The grid has `min(tiles, 4)` columns, so three tiles fill three columns and never leave an empty fourth. The default for any row of hea…
|
|
1129
|
+
- children: ReactNode
|
|
1130
|
+
|
|
1131
|
+
### MultiSelector
|
|
1132
|
+
MultiSelector — multi-select dropdown composing the existing Popover with a checkbox option list, so choosing several values from a fixed set reads as one over…
|
|
1133
|
+
- className: string
|
|
1134
|
+
- disabled: boolean = false
|
|
1135
|
+
- onChange: (next: string[]) => void
|
|
1136
|
+
- options: MultiSelectorOption[]
|
|
1137
|
+
- placeholder: string = Select…
|
|
1138
|
+
- value: string[]
|
|
1139
|
+
|
|
1140
|
+
### NavGroup
|
|
1141
|
+
NavGroup - labeled navigation group for stacks of nav items.
|
|
1142
|
+
- children: ReactNode
|
|
1143
|
+
- className: string
|
|
1144
|
+
- collapsible: boolean = false
|
|
1145
|
+
- contentStyle: CSSProperties
|
|
1146
|
+
- getExact: ((item: NavItem) => boolean)
|
|
1147
|
+
- items: NavItem[]
|
|
1148
|
+
- label: string
|
|
1149
|
+
- level: NavLevel = section
|
|
1150
|
+
- onNavigate: (() => void)
|
|
1151
|
+
- style: CSSProperties
|
|
1152
|
+
- variant: 'side' | 'toc' = side
|
|
1153
|
+
|
|
1154
|
+
### NavItem
|
|
1155
|
+
NavItem - navigation row primitive for sidebars, table of contents, and list navigation.
|
|
1156
|
+
- active: boolean = false
|
|
1157
|
+
- disabled: boolean = false
|
|
1158
|
+
- label: string
|
|
1159
|
+
- level: NavLevel = root
|
|
1160
|
+
- onNavigate: ((event: MouseEvent<HTMLAnchorElement, MouseEvent>) => void)
|
|
1161
|
+
- variant: NavVariant = side
|
|
1162
|
+
|
|
1163
|
+
### OverflowList
|
|
1164
|
+
Renders up to `max` children followed by a `+N` overflow chip (or custom node).
|
|
1165
|
+
- children: ReactNode
|
|
1166
|
+
- max: number
|
|
1167
|
+
- renderOverflow: ((count: number) => ReactNode)
|
|
1168
|
+
|
|
1169
|
+
### Page
|
|
1170
|
+
Page — standard page shell. Wraps page content in Container (width constraint) and applies the canonical vertical padding so content breathes against the viewp…
|
|
1171
|
+
- children: ReactNode
|
|
1172
|
+
- className: string
|
|
1173
|
+
- maxWidth: 'content' | 'max' = max
|
|
1174
|
+
- paddingY: 'default' | 'compact' | 'none' = default
|
|
1175
|
+
- style: CSSProperties
|
|
1176
|
+
|
|
1177
|
+
### PageHeader
|
|
1178
|
+
Screen header: breadcrumb slot, the title at the one canonical page-title size (`heading2`), a status slot and an actions slot. Every screen has exactly one. `…
|
|
1179
|
+
- actions: ReactNode
|
|
1180
|
+
- breadcrumb: ReactNode
|
|
1181
|
+
- level: PageHeaderLevel = 1
|
|
1182
|
+
- status: ReactNode
|
|
1183
|
+
- title: ReactNode
|
|
1184
|
+
|
|
1185
|
+
### Pagination
|
|
1186
|
+
Paged navigation with first/last anchors, sibling pages, and ellipses.
|
|
1187
|
+
- count: number
|
|
1188
|
+
- label: string = Pagination
|
|
1189
|
+
- onPageChange: (page: number) => void
|
|
1190
|
+
- page: number
|
|
1191
|
+
- siblingCount: number = 1
|
|
1192
|
+
|
|
1193
|
+
### Pin
|
|
1194
|
+
Pin — sticky-pin an element within its scroll region.
|
|
1195
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
1196
|
+
- children: ReactNode
|
|
1197
|
+
- className: string
|
|
1198
|
+
- style: CSSProperties
|
|
1199
|
+
- top: string = 0
|
|
1200
|
+
|
|
1201
|
+
### Popover
|
|
1202
|
+
Popover root + parts. Controlled via `open`/`onOpenChange`, or uncontrolled with `defaultOpen`.
|
|
1203
|
+
- children: React.ReactNode
|
|
1204
|
+
- defaultOpen: boolean
|
|
1205
|
+
- modal: boolean
|
|
1206
|
+
- onOpenChange: ((open: boolean) => void)
|
|
1207
|
+
- open: boolean
|
|
1208
|
+
|
|
1209
|
+
### Progress
|
|
1210
|
+
Linear progress. Determinate when `value` is a number, else indeterminate.
|
|
1211
|
+
- label: string = Progress
|
|
1212
|
+
- size: "sm" | "md" | "lg" | null
|
|
1213
|
+
- value: number | null = null
|
|
1214
|
+
|
|
1215
|
+
### Radio
|
|
1216
|
+
Radio — radio button with animated selection indicator.
|
|
1217
|
+
- checked: boolean
|
|
1218
|
+
- label: string
|
|
1219
|
+
- onChange: (v: boolean) => void
|
|
1220
|
+
|
|
1221
|
+
### Reveal
|
|
1222
|
+
Reveal — reveal-on-scroll primitive via CSS scroll-driven animation.
|
|
1223
|
+
- animation: 'fade' | 'fade-up' | 'fade-down' | 'scale' = fade-up
|
|
1224
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
1225
|
+
- children: ReactNode
|
|
1226
|
+
- className: string
|
|
1227
|
+
- style: CSSProperties
|
|
1228
|
+
|
|
1229
|
+
### SegmentedControl
|
|
1230
|
+
SegmentedControl " segmented selection input for compact mutually-exclusive choices. The active×hover×pressed×disabled×secondary state matrix is expressed thro…
|
|
1231
|
+
- aria-label: string
|
|
1232
|
+
- fullWidth: boolean = false
|
|
1233
|
+
- label: string
|
|
1234
|
+
- onChange: (value: string) => void
|
|
1235
|
+
- options: HdsSegmentedOption[]
|
|
1236
|
+
- railPadding: Padding<string | number>
|
|
1237
|
+
- segmentPaddingX: PaddingLeft<string | number>
|
|
1238
|
+
- size: NonNullable<"sm" | "md" | null> | undefined = md
|
|
1239
|
+
- value: string
|
|
1240
|
+
- variant: NonNullable<"primary" | "secondary" | null> | undefined = primary
|
|
1241
|
+
|
|
1242
|
+
### Select
|
|
1243
|
+
Select — dropdown selector built on Radix Select (ADR-001 Radix convention). Radix owns the listbox a11y contract: managed focus + active-descendant, typeahead…
|
|
1244
|
+
- container: HTMLElement | null
|
|
1245
|
+
- label: string
|
|
1246
|
+
- onChange: (v: string) => void
|
|
1247
|
+
- options: { value: string; label: string; }[]
|
|
1248
|
+
- showLabel: boolean = true
|
|
1249
|
+
- value: string
|
|
1250
|
+
|
|
1251
|
+
### SelectableCard
|
|
1252
|
+
A card-shaped single checkbox — click or activate to toggle selection.
|
|
1253
|
+
- disabled: boolean
|
|
1254
|
+
- onSelectedChange: ((selected: boolean) => void)
|
|
1255
|
+
- selected: boolean = false
|
|
1256
|
+
|
|
1257
|
+
### SideNav
|
|
1258
|
+
SideNav - sidebar navigation row primitive. Two levels: root — top-level section link. Full-width row using the shared nav label type style. nested — child pag…
|
|
1259
|
+
- active: boolean = false
|
|
1260
|
+
- disabled: boolean = false
|
|
1261
|
+
- href: string
|
|
1262
|
+
- indent: number | boolean = 0
|
|
1263
|
+
- label: string
|
|
1264
|
+
- level: 'root' | 'nested' = nested
|
|
1265
|
+
- onNavigate: ((event: MouseEvent<HTMLAnchorElement, MouseEvent>) => void)
|
|
1266
|
+
- titleLabel: boolean = false
|
|
1267
|
+
|
|
1268
|
+
### Sidebar
|
|
1269
|
+
Sidebar — fixed-width rail beside fluid content, no media query. Every Layout reference: https://every-layout.dev/layouts/sidebar/
|
|
1270
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
1271
|
+
- children: [ReactNode, ReactNode]
|
|
1272
|
+
- className: string
|
|
1273
|
+
- contentMin: string = 50%
|
|
1274
|
+
- gap: 'tight' | 'normal' | 'inset' | 'spacious' = normal
|
|
1275
|
+
- side: 'start' | 'end' = start
|
|
1276
|
+
- sideWidth: string = 16rem
|
|
1277
|
+
- style: CSSProperties
|
|
1278
|
+
|
|
1279
|
+
### Skeleton
|
|
1280
|
+
Decorative loading placeholder. Marked aria-hidden — announce the loading state on the surrounding region (e.g. aria-busy) rather than per skeleton.
|
|
1281
|
+
- height: string | number
|
|
1282
|
+
- variant: "text" | "rectangular" | "circular" | null = rectangular
|
|
1283
|
+
- width: string | number
|
|
1284
|
+
|
|
1285
|
+
### Sketch
|
|
1286
|
+
Sketch — shared shell for generative canvases and WebGL sketches.
|
|
1287
|
+
- children: ReactNode
|
|
1288
|
+
- controls: ReactNode
|
|
1289
|
+
- title: string
|
|
1290
|
+
|
|
1291
|
+
### Slider
|
|
1292
|
+
Slider — range slider with label and value display.
|
|
1293
|
+
- label: string
|
|
1294
|
+
- max: number
|
|
1295
|
+
- min: number
|
|
1296
|
+
- onChange: (v: number) => void
|
|
1297
|
+
- step: number = 1
|
|
1298
|
+
- value: number
|
|
1299
|
+
|
|
1300
|
+
### Spinner
|
|
1301
|
+
Indeterminate spinner. Inherits the surrounding text color via currentColor.
|
|
1302
|
+
- label: string = Loading
|
|
1303
|
+
- size: "sm" | "md" | "lg" | null
|
|
1304
|
+
|
|
1305
|
+
### Stack
|
|
1306
|
+
Stack — one-dimensional layout primitive.
|
|
1307
|
+
- align: 'start' | 'center' | 'end' | 'stretch'
|
|
1308
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
1309
|
+
- children: ReactNode
|
|
1310
|
+
- className: string
|
|
1311
|
+
- direction: "row" | "column" = column
|
|
1312
|
+
- gap: GapOption = tight
|
|
1313
|
+
- justify: 'start' | 'center' | 'end' | 'space-between'
|
|
1314
|
+
- style: CSSProperties
|
|
1315
|
+
- wrap: FlexWrap
|
|
1316
|
+
|
|
1317
|
+
### StackedCardRail
|
|
1318
|
+
StackedCardRail — horizontally-scrolling stacked card carousel. Scroll mechanism: vertical scroll on an absolutely-positioned inner container is mapped to hori…
|
|
1319
|
+
- cards: StackedCardRailCard[]
|
|
1320
|
+
|
|
1321
|
+
### Stat
|
|
1322
|
+
Headline metric — large value, uppercase caption label, optional sub-line.
|
|
1323
|
+
- label: string
|
|
1324
|
+
- sub: ReactNode
|
|
1325
|
+
- tone: "neutral" | "danger" | "success" | "warning" | "info" | null
|
|
1326
|
+
- value: ReactNode
|
|
1327
|
+
|
|
1328
|
+
### StatusDot
|
|
1329
|
+
A small solid dot conveying a semantic status via `tone`.
|
|
1330
|
+
- label: string
|
|
1331
|
+
- size: "sm" | "md" | "lg" | null
|
|
1332
|
+
- tone: "neutral" | "danger" | "success" | "warning" | "info" | "inProgress" | null
|
|
1333
|
+
|
|
1334
|
+
### StatusListItem
|
|
1335
|
+
Status dot + title row with optional muted notes and trailing slot (e.g. badge).
|
|
1336
|
+
- notes: ReactNode[]
|
|
1337
|
+
- title: ReactNode
|
|
1338
|
+
- tone: "neutral" | "danger" | "success" | "warning" | "info" | null
|
|
1339
|
+
- trailing: ReactNode
|
|
1340
|
+
|
|
1341
|
+
### StatusTile
|
|
1342
|
+
Block-layout sibling of StatusListItem. Renders a raised surface tile with title, optional muted notes, and a trailing slot for a badge or affordance. Status c…
|
|
1343
|
+
- notes: ReactNode[]
|
|
1344
|
+
- title: ReactNode
|
|
1345
|
+
- tone: 'success' | 'warning' | 'danger' | 'info' | 'neutral' = neutral
|
|
1346
|
+
- trailing: ReactNode
|
|
1347
|
+
|
|
1348
|
+
### Stepper
|
|
1349
|
+
Step indicator for multi-step flows. Purely presentational — no navigation.
|
|
1350
|
+
- activeStep: number
|
|
1351
|
+
- orientation: "horizontal" | "vertical" = horizontal
|
|
1352
|
+
- steps: Step[]
|
|
1353
|
+
|
|
1354
|
+
### StepperField
|
|
1355
|
+
StepperField ” numeric input with decrement/increment controls. Classification baseline: Material Design, Chakra UI, and Ant Design treat steppers as numeric i…
|
|
1356
|
+
- inputStep: number
|
|
1357
|
+
- label: string
|
|
1358
|
+
- max: number
|
|
1359
|
+
- min: number
|
|
1360
|
+
- onChange: (value: number) => void
|
|
1361
|
+
- precision: number
|
|
1362
|
+
- step: number
|
|
1363
|
+
- value: number
|
|
1364
|
+
|
|
1365
|
+
### Surface
|
|
1366
|
+
Surface — governed inset surface primitive. Enforces the "Surface Inset" rule: backgrounds MUST have internal padding. - Default padding: px24 (cards) | px16 (…
|
|
1367
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
1368
|
+
- children: ReactNode
|
|
1369
|
+
- className: string
|
|
1370
|
+
- overflow: Overflow
|
|
1371
|
+
- padding: PaddingOption = component
|
|
1372
|
+
- shadow: boolean = false
|
|
1373
|
+
- style: CSSProperties
|
|
1374
|
+
- theme: "light" | "dark"
|
|
1375
|
+
|
|
1376
|
+
### Switcher
|
|
1377
|
+
Switcher — flips a row to a column below a width threshold, no media query. Every Layout reference: https://every-layout.dev/layouts/the-switcher/
|
|
1378
|
+
- as: ElementType<any, keyof IntrinsicElements> = div
|
|
1379
|
+
- children: ReactNode
|
|
1380
|
+
- className: string
|
|
1381
|
+
- gap: 'tight' | 'normal' | 'inset' | 'spacious' = normal
|
|
1382
|
+
- limit: number
|
|
1383
|
+
- style: CSSProperties
|
|
1384
|
+
- threshold: string = 30rem
|
|
1385
|
+
|
|
1386
|
+
### Table
|
|
1387
|
+
Table - structured data table primitive for documentation and compact UI matrices.
|
|
1388
|
+
- caption: ReactNode
|
|
1389
|
+
- captionAction: ReactNode
|
|
1390
|
+
- columns: TableColumn[]
|
|
1391
|
+
- density: 'compact' | 'comfortable'
|
|
1392
|
+
- description: ReactNode
|
|
1393
|
+
- flush: boolean = false
|
|
1394
|
+
- labelledBy: string
|
|
1395
|
+
- minWidth: string | number
|
|
1396
|
+
- rows: TableRow[]
|
|
1397
|
+
- stickyHeader: boolean = false
|
|
1398
|
+
|
|
1399
|
+
### Tabs
|
|
1400
|
+
The tab set itself. Tagged here rather than in the file block because TabsList and TabsContent share this module and have no Figma node of their own — a file-l…
|
|
1401
|
+
- activationMode: "automatic" | "manual"
|
|
1402
|
+
- asChild: boolean
|
|
1403
|
+
- defaultValue: string
|
|
1404
|
+
- dir: ("ltr" | "rtl")
|
|
1405
|
+
- onValueChange: ((value: string) => void)
|
|
1406
|
+
- orientation: "horizontal" | "vertical"
|
|
1407
|
+
- value: string
|
|
1408
|
+
|
|
1409
|
+
### TabsContent
|
|
1410
|
+
Tabs — Radix-backed underline tabs (Root, List, Trigger, Content). Underline pattern math: - TabsList carries `border-b border-border/40` (the divider, half-st…
|
|
1411
|
+
- asChild: boolean
|
|
1412
|
+
- forceMount: true
|
|
1413
|
+
- value: string
|
|
1414
|
+
|
|
1415
|
+
### TabsList
|
|
1416
|
+
Tabs — Radix-backed underline tabs (Root, List, Trigger, Content). Underline pattern math: - TabsList carries `border-b border-border/40` (the divider, half-st…
|
|
1417
|
+
- asChild: boolean
|
|
1418
|
+
- loop: boolean
|
|
1419
|
+
|
|
1420
|
+
### TabsTrigger
|
|
1421
|
+
Tabs — Radix-backed underline tabs (Root, List, Trigger, Content). Underline pattern math: - TabsList carries `border-b border-border/40` (the divider, half-st…
|
|
1422
|
+
- asChild: boolean
|
|
1423
|
+
- value: string
|
|
1424
|
+
|
|
1425
|
+
### Tag
|
|
1426
|
+
Tag — interactive filter and category chip. The outer <button> carries the accessible 44px hit target directly via the size token while the inner pill keeps th…
|
|
1427
|
+
- active: boolean = false
|
|
1428
|
+
- children: ReactNode
|
|
1429
|
+
|
|
1430
|
+
### Text
|
|
1431
|
+
Text — polymorphic typography primitive spanning the full HDS type ramp.
|
|
1432
|
+
- as: "symbol" | "object" | "map" | "filter" | "title" | "a" | "button" | "div" | "fo… = defaultTagMap[variant]
|
|
1433
|
+
- children: ReactNode
|
|
1434
|
+
- className: string
|
|
1435
|
+
- style: CSSProperties
|
|
1436
|
+
- variant: TextVariant
|
|
1437
|
+
|
|
1438
|
+
### TextLockup
|
|
1439
|
+
TextLockup - governed title-and-description pairing primitive.
|
|
1440
|
+
- align: 'left' | 'center' = left
|
|
1441
|
+
- as: ElementType = div
|
|
1442
|
+
- description: ReactNode
|
|
1443
|
+
- descriptionAs: 'div' | 'p' | 'span' = div
|
|
1444
|
+
- eyebrow: string
|
|
1445
|
+
- id: string
|
|
1446
|
+
- size: 'hero' | 'heroXl' | 'section' | 'metric' | 'detail' | 'numbered'
|
|
1447
|
+
- title: string
|
|
1448
|
+
- titleAs: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span'
|
|
1449
|
+
|
|
1450
|
+
### Textarea
|
|
1451
|
+
Textarea — multi-line text field primitive with label, helper, and error slots. Mirrors Input's shell + token skin as a native `<textarea>`. Figma parity: the …
|
|
1452
|
+
- className: string
|
|
1453
|
+
- disabled: boolean
|
|
1454
|
+
- error: boolean
|
|
1455
|
+
- errorMessage: string
|
|
1456
|
+
- helperText: string
|
|
1457
|
+
- label: string
|
|
1458
|
+
- resize: TextareaResize = vertical
|
|
1459
|
+
- textareaClassName: string
|
|
1460
|
+
|
|
1461
|
+
### TileGrid
|
|
1462
|
+
Auto-fill responsive grid for status/micro tiles. Wraps tile children in a one-line grid declaration so pages don't repeat the auto-fill minmax recipe.
|
|
1463
|
+
- gap: "sm" | "md" | "xs" = sm
|
|
1464
|
+
- minTileWidth: string = 260px
|
|
1465
|
+
|
|
1466
|
+
### TimeInput
|
|
1467
|
+
A native time field skinned with HDS input chrome. Value is a `HH:mm` string.
|
|
1468
|
+
- size: "sm" | "md" | "lg" | null
|
|
1469
|
+
|
|
1470
|
+
### Timestamp
|
|
1471
|
+
Presents a date/time with a machine-readable `dateTime` for accessibility.
|
|
1472
|
+
- date: string | number | Date
|
|
1473
|
+
- format: 'date' | 'time' | 'datetime' | 'relative' = datetime
|
|
1474
|
+
- locale: string
|
|
1475
|
+
- now: string | number | Date
|
|
1476
|
+
|
|
1477
|
+
### ToastProvider
|
|
1478
|
+
Provider + viewport for the toast system. Wrap the app root once.
|
|
1479
|
+
- children: React.ReactNode
|
|
1480
|
+
- duration: number = 5000
|
|
1481
|
+
- swipeDirection: SwipeDirection = right
|
|
1482
|
+
|
|
1483
|
+
### Toggle
|
|
1484
|
+
Toggle — boolean on/off toggle with animated thumb.
|
|
1485
|
+
- checked: boolean
|
|
1486
|
+
- label: string
|
|
1487
|
+
- onChange: (v: boolean) => void
|
|
1488
|
+
|
|
1489
|
+
### ToggleButton
|
|
1490
|
+
A single two-state toggle button exposing a native `aria-pressed` contract — use for one independent on/off control such as bold, mute, or pin.
|
|
1491
|
+
- asChild: boolean
|
|
1492
|
+
- defaultPressed: boolean
|
|
1493
|
+
- onPressedChange: ((pressed: boolean) => void)
|
|
1494
|
+
- pressed: boolean
|
|
1495
|
+
- size: "sm" | "md" | "lg" | null
|
|
1496
|
+
- variant: "secondary" | "ghost" | null
|
|
1497
|
+
|
|
1498
|
+
### Token
|
|
1499
|
+
Token - reflective token specimen for unified node-based token views. The `variant` axis (node | diagram — diagram is a deprecated alias that resolves to the s…
|
|
1500
|
+
- accentColor: string
|
|
1501
|
+
- aria-label: string
|
|
1502
|
+
- className: string
|
|
1503
|
+
- description: ReactNode
|
|
1504
|
+
- fullWidth: boolean
|
|
1505
|
+
- isSelected: boolean
|
|
1506
|
+
- isSourceNode: boolean
|
|
1507
|
+
- label: string
|
|
1508
|
+
- leadingSlot: ReactNode
|
|
1509
|
+
- nodeRef: ((el: HTMLElement | null) => void)
|
|
1510
|
+
- nowrap: boolean
|
|
1511
|
+
- onClick: (() => void) | (() => void)
|
|
1512
|
+
- pathDisplayDepth: number
|
|
1513
|
+
- pathDisplayLeadingDot: boolean
|
|
1514
|
+
- pathDisplayMode: "full" | "compressed"
|
|
1515
|
+
- rawValue: ReactNode
|
|
1516
|
+
- swatchVar: string
|
|
1517
|
+
- tokenPath: string
|
|
1518
|
+
- truncateFromStart: boolean
|
|
1519
|
+
- value: string
|
|
1520
|
+
- variant: "node" | "diagram"
|
|
1521
|
+
|
|
1522
|
+
### Tokenizer
|
|
1523
|
+
A bordered field of Tag chips followed by a text input for adding more.
|
|
1524
|
+
- className: string
|
|
1525
|
+
- disabled: boolean
|
|
1526
|
+
- onChange: (next: string[]) => void
|
|
1527
|
+
- placeholder: string
|
|
1528
|
+
- value: string[]
|
|
1529
|
+
|
|
1530
|
+
### Toolbar
|
|
1531
|
+
Toolbar root. Groups related controls with a single roving tab-stop. Supports the native `orientation` prop (`horizontal` | `vertical`).
|
|
1532
|
+
- asChild: boolean
|
|
1533
|
+
- dir: ("ltr" | "rtl")
|
|
1534
|
+
- loop: boolean
|
|
1535
|
+
- orientation: "horizontal" | "vertical"
|
|
1536
|
+
|
|
1537
|
+
### Tooltip
|
|
1538
|
+
Tooltip root. Bakes in the Radix Provider so a single `<Tooltip>` is self-contained — no app-level provider required. Controlled via `open`/`onOpenChange`, or …
|
|
1539
|
+
- children: React.ReactNode
|
|
1540
|
+
- defaultOpen: boolean
|
|
1541
|
+
- delayDuration: number
|
|
1542
|
+
- disableHoverableContent: boolean
|
|
1543
|
+
- onOpenChange: ((open: boolean) => void)
|
|
1544
|
+
- open: boolean
|
|
1545
|
+
|
|
1546
|
+
### TopNav
|
|
1547
|
+
Top navigation bar with brand, nav, and trailing action slots.
|
|
1548
|
+
- brand: ReactNode
|
|
1549
|
+
- children: ReactNode
|
|
1550
|
+
- sticky: boolean
|
|
1551
|
+
- trailing: ReactNode
|
|
1552
|
+
|
|
1553
|
+
### TreeList
|
|
1554
|
+
Renders a hierarchical `role="tree"` list; nodes with children get an expand/collapse toggle.
|
|
1555
|
+
- defaultExpandedIds: string[]
|
|
1556
|
+
- items: TreeNode[]
|
|
1557
|
+
- onSelect: ((id: string) => void)
|
|
1558
|
+
|
|
1559
|
+
### VisuallyHidden
|
|
1560
|
+
Renders its children off-screen (Tailwind `sr-only`) so they are announced by screen readers without occupying visual space — e.g. a text label for an icon-onl…
|
|
1561
|
+
- as: ElementType<any, keyof IntrinsicElements> = span
|