@godxjp/ui 19.5.0 → 20.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/components/data-display/card.d.ts +2 -2
  2. package/dist/components/data-display/collapsible.d.ts +23 -4
  3. package/dist/components/data-display/collapsible.js +119 -4
  4. package/dist/components/data-display/index.d.ts +3 -1
  5. package/dist/components/data-display/index.js +2 -0
  6. package/dist/components/data-display/legend.d.ts +15 -0
  7. package/dist/components/data-display/legend.js +11 -0
  8. package/dist/components/data-display/list-row.js +1 -1
  9. package/dist/components/data-display/popover.d.ts +58 -5
  10. package/dist/components/data-display/popover.js +206 -27
  11. package/dist/components/data-display/progress.d.ts +50 -2
  12. package/dist/components/data-display/progress.js +57 -9
  13. package/dist/components/data-entry/calendar.d.ts +1 -1
  14. package/dist/components/data-entry/calendar.js +67 -32
  15. package/dist/components/data-entry/checkbox.d.ts +19 -6
  16. package/dist/components/data-entry/checkbox.js +55 -16
  17. package/dist/components/data-entry/choice-option.d.ts +1 -1
  18. package/dist/components/data-entry/date-range-picker.d.ts +1 -1
  19. package/dist/components/data-entry/field.js +0 -1
  20. package/dist/components/data-entry/form.js +1 -1
  21. package/dist/components/data-entry/label.d.ts +3 -2
  22. package/dist/components/data-entry/label.js +23 -10
  23. package/dist/components/data-entry/month-picker.d.ts +1 -1
  24. package/dist/components/data-entry/month-range-picker.d.ts +1 -1
  25. package/dist/components/data-entry/transfer.js +16 -6
  26. package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
  27. package/dist/components/data-entry/tree-select.js +29 -12
  28. package/dist/components/data-entry/tree-utils.d.ts +1 -1
  29. package/dist/components/data-entry/upload.js +7 -2
  30. package/dist/components/feedback/dialog.d.ts +105 -38
  31. package/dist/components/feedback/dialog.js +272 -194
  32. package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
  33. package/dist/components/feedback/overlay-close-focus.js +31 -0
  34. package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
  35. package/dist/components/feedback/sheet.d.ts +53 -11
  36. package/dist/components/feedback/sheet.js +150 -81
  37. package/dist/components/feedback/tooltip.d.ts +51 -7
  38. package/dist/components/feedback/tooltip.js +107 -25
  39. package/dist/components/general/button.js +2 -2
  40. package/dist/components/general/logo.d.ts +17 -0
  41. package/dist/components/general/logo.js +22 -16
  42. package/dist/components/general/typography.d.ts +7 -1
  43. package/dist/components/general/typography.js +20 -5
  44. package/dist/components/layout/app-shell.d.ts +1 -1
  45. package/dist/components/layout/app-shell.js +52 -8
  46. package/dist/components/layout/aspect-ratio.js +0 -1
  47. package/dist/components/layout/auth-divider.js +0 -1
  48. package/dist/components/layout/flex.d.ts +1 -1
  49. package/dist/components/layout/flex.js +19 -2
  50. package/dist/components/layout/nav-surface.d.ts +26 -0
  51. package/dist/components/layout/nav-surface.js +17 -0
  52. package/dist/components/layout/org-switcher.d.ts +5 -1
  53. package/dist/components/layout/org-switcher.js +5 -3
  54. package/dist/components/layout/separator.js +0 -1
  55. package/dist/components/layout/sidebar.js +4 -1
  56. package/dist/components/layout/split-pane.d.ts +14 -1
  57. package/dist/components/layout/split-pane.js +26 -13
  58. package/dist/components/layout/topbar-item.js +1 -2
  59. package/dist/components/navigation/app-setting-picker.js +21 -2
  60. package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
  61. package/dist/components/navigation/app-setting-toggle.js +96 -0
  62. package/dist/components/navigation/dropdown-menu.d.ts +199 -18
  63. package/dist/components/navigation/dropdown-menu.js +344 -117
  64. package/dist/components/navigation/index.d.ts +2 -0
  65. package/dist/components/navigation/index.js +2 -0
  66. package/dist/components/navigation/pagination-utils.d.ts +2 -1
  67. package/dist/components/navigation/tabs.d.ts +47 -6
  68. package/dist/components/navigation/tabs.js +152 -90
  69. package/dist/components/ui/accordion.d.ts +50 -5
  70. package/dist/components/ui/accordion.js +239 -33
  71. package/dist/components/ui/aspect-ratio.d.ts +23 -2
  72. package/dist/components/ui/aspect-ratio.js +15 -13
  73. package/dist/components/ui/avatar.d.ts +29 -4
  74. package/dist/components/ui/avatar.js +111 -25
  75. package/dist/components/ui/hover-card.d.ts +42 -4
  76. package/dist/components/ui/hover-card.js +183 -27
  77. package/dist/components/ui/label.js +0 -1
  78. package/dist/components/ui/segmented.d.ts +3 -3
  79. package/dist/components/ui/separator.d.ts +8 -2
  80. package/dist/components/ui/separator.js +17 -9
  81. package/dist/components/ui/toggle-group.d.ts +50 -5
  82. package/dist/components/ui/toggle-group.js +79 -20
  83. package/dist/components/ui/toggle.d.ts +31 -5
  84. package/dist/components/ui/toggle.js +42 -3
  85. package/dist/i18n/messages/en.json +8 -0
  86. package/dist/i18n/messages/ja.json +8 -0
  87. package/dist/i18n/messages/vi.json +8 -0
  88. package/dist/lib/control-styles.d.ts +1 -1
  89. package/dist/lib/control-styles.js +1 -1
  90. package/dist/lib/slot.d.ts +32 -0
  91. package/dist/lib/slot.js +22 -0
  92. package/dist/lib/variants.d.ts +22 -3
  93. package/dist/lib/variants.js +56 -1
  94. package/dist/props/components/app.prop.d.ts +25 -1
  95. package/dist/props/components/data-display.prop.d.ts +17 -0
  96. package/dist/props/components/data-entry.prop.d.ts +32 -4
  97. package/dist/props/components/general.prop.d.ts +31 -1
  98. package/dist/props/components/index.d.ts +1 -1
  99. package/dist/props/components/layout.prop.d.ts +118 -5
  100. package/dist/props/components/navigation.prop.d.ts +1 -1
  101. package/dist/props/registry.d.ts +22 -2
  102. package/dist/props/registry.js +33 -2
  103. package/dist/props/vocabulary/content.prop.d.ts +1 -1
  104. package/dist/props/vocabulary/index.d.ts +2 -2
  105. package/dist/props/vocabulary/interaction.prop.d.ts +17 -1
  106. package/dist/props/vocabulary/layout.prop.d.ts +57 -1
  107. package/dist/styles/control.css +142 -1
  108. package/dist/styles/core.css +5 -2
  109. package/dist/styles/data-display-layout.css +72 -0
  110. package/dist/styles/focus-ring.css +13 -1
  111. package/dist/styles/index.css +5 -2
  112. package/dist/styles/layout.css +106 -0
  113. package/dist/styles/shell-layout.css +140 -8
  114. package/dist/styles/text-layout.css +16 -4
  115. package/dist/tokens/base.css +2 -1
  116. package/dist/tokens/components/data-display.css +11 -0
  117. package/dist/tokens/components/shell.css +3 -1
  118. package/dist/tokens/components/text.css +7 -0
  119. package/dist/tokens/foundation.css +2 -0
  120. package/docs/COMPONENTS.md +9 -3
  121. package/docs/DESIGN-AUTHORITY.md +96 -71
  122. package/docs/FRAME-COVERAGE-REPORT.md +5 -3
  123. package/docs/README.md +14 -14
  124. package/docs/WHAT-BELONGS-HERE.md +179 -0
  125. package/docs/data-display/legend.tsx +145 -0
  126. package/docs/data-display/progress.tsx +32 -0
  127. package/docs/data-entry/segmented.tsx +1 -1
  128. package/docs/data-entry/select.tsx +2 -2
  129. package/docs/feedback/sheet.tsx +1 -1
  130. package/docs/general/typography.tsx +84 -1
  131. package/docs/layout/app-shell-arrangements.tsx +225 -0
  132. package/docs/layout/aspect-ratio.tsx +1 -1
  133. package/docs/navigation/app-setting-picker.tsx +26 -1
  134. package/docs/navigation/app-setting-toggle.tsx +111 -0
  135. package/package.json +11 -8
  136. package/scripts/_agent-setup.mjs +165 -3
  137. package/scripts/consumer-rule.md +98 -0
  138. package/scripts/guinea-pig-skill.md +322 -0
  139. package/scripts/init-guinea-pig.mjs +62 -0
  140. package/scripts/postinstall.mjs +13 -2
  141. package/scripts/ui-audit.mjs +115 -14
  142. /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
@@ -62,21 +62,22 @@
62
62
  [data-slot="heading"][data-tone="primary"] {
63
63
  color: hsl(var(--primary));
64
64
  }
65
+
65
66
  [data-slot="text"][data-tone="success"],
66
67
  [data-slot="heading"][data-tone="success"] {
67
- color: hsl(var(--success));
68
+ color: hsl(var(--text-success));
68
69
  }
69
70
  [data-slot="text"][data-tone="warning"],
70
71
  [data-slot="heading"][data-tone="warning"] {
71
- color: hsl(var(--warning));
72
+ color: hsl(var(--text-warning));
72
73
  }
73
74
  [data-slot="text"][data-tone="destructive"],
74
75
  [data-slot="heading"][data-tone="destructive"] {
75
- color: hsl(var(--destructive));
76
+ color: hsl(var(--text-error));
76
77
  }
77
78
  [data-slot="text"][data-tone="info"],
78
79
  [data-slot="heading"][data-tone="info"] {
79
- color: hsl(var(--info));
80
+ color: hsl(var(--text-info));
80
81
  }
81
82
 
82
83
  [data-slot="text"][data-align="start"],
@@ -107,6 +108,17 @@
107
108
  overflow: hidden;
108
109
  min-width: 0;
109
110
  }
111
+
112
+ [data-slot="text"][data-link] {
113
+ text-decoration-line: none;
114
+ text-underline-offset: var(--text-link-underline-offset);
115
+ text-decoration-thickness: var(--text-link-underline-width);
116
+ }
117
+ [data-slot="text"][data-link]:hover,
118
+ [data-slot="text"][data-link]:focus-visible {
119
+ text-decoration-line: underline;
120
+ }
121
+
110
122
  [data-slot="text"][data-tabular] {
111
123
  font-variant-numeric: tabular-nums;
112
124
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  @import "./foundation.css";
4
4
 
5
- @import "./antd.generated.css";
5
+ @import "./derived.css";
6
6
  @import "./semantic/layout.css";
7
7
  @import "./axes.css";
8
8
  @import "./components/control.css";
@@ -31,3 +31,4 @@
31
31
  @import "./components/legal-document.css";
32
32
  @import "./components/error-surface.css";
33
33
  @import "./components/activity.css";
34
+ @import "./components/text.css";
@@ -64,6 +64,17 @@
64
64
  --progress-track-background: initial;
65
65
  --progress-fill-background: initial;
66
66
 
67
+ --progress-breakdown-block-size: 1.375rem;
68
+ --progress-breakdown-radius: var(--radius);
69
+
70
+ --legend-gap: 0.875rem;
71
+ --legend-item-gap: 0.3125rem;
72
+ --legend-swatch-size: 0.625rem;
73
+ --legend-swatch-radius: 0.125rem;
74
+ --legend-font-size: var(--font-size-xs);
75
+
76
+ --legend-color: initial;
77
+
67
78
  --timeline-dot-done-background: initial;
68
79
  --timeline-dot-current-background: initial;
69
80
  --timeline-line-completed-background: initial;
@@ -42,7 +42,9 @@
42
42
  --app-shell-bar-gap: var(--space-3);
43
43
 
44
44
  --app-shell-sidebar-width: 16rem;
45
- --app-shell-rail-width: 4rem;
45
+ --app-shell-sidebar-collapsed-width: 4rem;
46
+
47
+ --app-shell-nav-rail-width: 3.5rem;
46
48
  --app-shell-page-max-width: 80rem;
47
49
  --app-shell-main-background: hsl(var(--muted) / 0.4);
48
50
  --app-shell-mobile-nav-width: 22.5rem;
@@ -0,0 +1,7 @@
1
+
2
+ :root {
3
+
4
+ --text-link-underline-offset: 0.2em;
5
+
6
+ --text-link-underline-width: auto;
7
+ }
@@ -273,6 +273,8 @@
273
273
  --space-inline-sm: var(--space-2);
274
274
  --space-inline-md: var(--space-3);
275
275
  --space-inline-lg: var(--space-4);
276
+
277
+ --space-inline-xl: var(--space-6);
276
278
  --space-chrome-x: var(--space-6);
277
279
  --space-chrome-y: var(--space-4);
278
280
  --space-chrome-gap: var(--space-2);
@@ -48,9 +48,13 @@ All UI is **mobile-first**: base layout targets ~320–428px viewport; `sm` (640
48
48
 
49
49
  Default `direction="row"`; use `direction="col"` for vertical rhythm.
50
50
 
51
- | Component | Prop | Key props |
52
- | --------- | ---------- | ----------------------------------------------------------------------- |
53
- | `Flex` | `FlexProp` | `direction: "row" \| "col"`, `gap: GapProp`, `align`, `justify`, `wrap` |
51
+ | Component | Prop | Key props |
52
+ | --------- | ---------- | ---------------------------------------------------------------------------------------------------- |
53
+ | `Flex` | `FlexProp` | `direction: "row" \| "col"`, `gap: GapProp`, `gapRaw`, `pad`, `padRaw`, `fill`, `width`, `align`, `justify`, `wrap` |
54
+
55
+ `fill` / `width` are the `fixed | elastic | fixed` row: `width` pins a column (number = px, and
56
+ leaves `data-width-raw` on the DOM so the measurement stays countable), `fill` takes what is left
57
+ and sets `min-inline-size: 0` so a truncating child ellipses instead of widening the row.
54
58
 
55
59
  ---
56
60
 
@@ -92,6 +96,8 @@ Default `direction="row"`; use `direction="col"` for vertical rhythm.
92
96
  | `Descriptions` | `DescriptionsProp` | `items[]` |
93
97
  | `Badge` | `BadgeProp` | `status`, `tone: ToneProp` |
94
98
  | `Badge` | `BadgeProp` | shadcn badge variants |
99
+ | `Progress` | `ProgressProp` | `value` (meter) \| `segments` (breakdown) |
100
+ | `Legend` | `LegendProp` | `items[]` — the key for a tone |
95
101
  | `Popover` | Radix primitives | floating content panel |
96
102
  | `ScrollArea` | Radix primitives | scrollable regions |
97
103
  | `Collapsible` | Radix primitives | expand/collapse sections |
@@ -17,9 +17,9 @@ It changes no code by itself. It is the tie-breaker a reviewer points at.
17
17
  | Interaction semantics, keyboard, ARIA | **WAI-ARIA APG** | already followed — 33 references in `src/` |
18
18
  | Behaviour primitives | **Radix** | already the implementation — 193 references |
19
19
  | Component composition shape | **shadcn** | already the structural convention — 23 references |
20
- | Component taxonomy / grouping | **Ant Design** groups | already the catalog shape: `data-entry`, `data-display`, `layout`, `feedback`, `navigation`, `general` |
20
+ | Component taxonomy / grouping | **Ant Design** groups | already the catalog shape: `data-entry`, `data-display`, `layout`, `feedback`, `navigation`, `general` — a naming precedent, nothing is installed |
21
21
  | Colour foundation | **SmartHR** | already the palette source — `--primary` = SmartHR MAIN `#0071bd`, `--foreground` = TEXT_BLACK, `--border` = BORDER |
22
- | **Derived colour — every step computed from a seed** | **Ant Design (the algorithm itself)** | **NEW this decision.** antd is no longer a shape reference here: `scripts/gen-antd-tokens.mjs` runs `theme.getDesignToken()` at build time and emits the derived map |
22
+ | **Derived colour — the interaction states hanging off each seed** | **Measured contrast (WCAG 2.2 / JIS X 8341-3)** | Authored in `src/tokens/derived.css`; no algorithm derives them. Four contrast suites read that file and hold every value to a threshold see below |
23
23
  | **Japanese UI convention — density, JP typography, form patterns** | **SmartHR** | **NEW — this decision.** Extends SmartHR from "where the colours came from" to the authority for how a JP business screen behaves |
24
24
  | **Japanese accessibility / public-sector convention** | **デジタル庁 Design System** (Digital Agency) | **NEW — this decision.** The reference when a JP customer asks which standard a screen meets (JIS X 8341-3) |
25
25
  | **Spacing, density, type scale, information architecture** | **IBM Carbon** | **NEW — this decision** |
@@ -187,70 +187,94 @@ Recorded rather than silently fixed, because each is a real decision:
187
187
  strokes blur far more visibly than Latin letterforms. Another reason to prefer Carbon's integer
188
188
  steps if the scale is ever revisited.
189
189
 
190
- ## Derived colour is GENERATED, not authored
190
+ ## Derived colour is AUTHORED, and MEASUREMENT is what makes it authoritative
191
191
 
192
- **The problem this fixes.** The library hand-authored roughly a thousand tokens and reasoned about
193
- each one. A hover step was chosen by eye, an active step was chosen by eye, a focus-halo alpha was
194
- chosen by eye and then justified in a paragraph. Every one of those is a decision with no outside
195
- authority behind it, and every one has to be re-argued the next time somebody looks at it.
192
+ **Twenty values, in `src/tokens/derived.css`:** `--primary-hover`, `--primary-active`,
193
+ `--primary-border`, `--destructive-hover`, `--destructive-active`, `--control-outline` and its
194
+ alpha, `--control-outline-error` and its alpha, and `--ring` each in both themes. They are the
195
+ interaction states that hang off the five authored seeds per theme (SmartHR MAIN plus four 和色,
196
+ and the lifted dark ramp), which stay in `src/tokens/foundation.css`.
196
197
 
197
- **Ant Design already solves this exactly once**: a SEED colour goes in, an ALGORITHM runs, and the
198
- whole derived map falls out. This document already named antd as the authority for component
199
- taxonomy and focus shape; that is now extended to make antd the **generator** of derived colour.
198
+ **These twenty were once generated.** A colour algorithm ran at build time, took the seeds and
199
+ emitted the derived map; the authority behind each value was "the algorithm said so". That
200
+ generator has been removed and its dependency with it. The values did not change but the reason
201
+ to trust them had to.
200
202
 
201
- `scripts/gen-antd-tokens.mjs` reads the seeds out of `src/tokens/foundation.css`, runs antd 6.6.2's
202
- own `theme.getDesignToken()` (`defaultAlgorithm` for light, `darkAlgorithm` for dark) and writes
203
- `src/tokens/antd.generated.css`. `pnpm check:antd-tokens` fails CI if that file drifts from the
204
- algorithm. **antd is a devDependency and a build-time tool only** — `pnpm check:no-antd-runtime`
205
- asserts it never reaches `dependencies`, `src/`, or `dist/`.
203
+ **The authority is now the measurement, not the derivation.** Four suites read `derived.css`
204
+ directly and hold every value in it to a threshold this repo has already committed to:
206
205
 
207
- **What is authored:** five brand colours per theme (SmartHR MAIN plus four 和色, and the lifted dark
208
- ramp). **What is computed:** `--primary-hover`, `--primary-active`, `--primary-border`,
209
- `--destructive-hover`, `--destructive-active`, `--control-outline*` and `--ring`.
206
+ | suite | what it holds |
207
+ | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
208
+ | `src/tokens/__tests__/focus-ring-contrast.test.ts` | the focus mark in both switch positions — ≥3:1 (WCAG 2.2 SC 1.4.11) on every surface a control sits on, and the halo proven to be decoration rather than the indicator |
209
+ | `src/tokens/__tests__/interactive-fill-contrast.test.ts` | an interactive fill must clear **4.5:1** against the label sitting on it |
210
+ | `src/tokens/__tests__/destructive-contrast.test.ts` | `--destructive-hover` / `--destructive-active` against the same bar |
211
+ | `src/lib/__tests__/theme-tokens-css.test.ts` | the tier is actually loaded, and complete in both themes |
210
212
 
211
- **What is deliberately NOT taken from antd, and why each a measurement, not a preference:**
213
+ The first three also pin each value as a literal, so an edit to `derived.css` alone turns CI red
214
+ rather than quietly retinting the library. **That is a stronger claim than the generator made, not
215
+ a weaker one.** An algorithm guarantees a value is _consistent_; this repo had to override it four
216
+ times (below) precisely because consistent is not the same as _accessible_. A threshold guarantees
217
+ the property actually being sold.
212
218
 
213
- - **The neutral spine.** Colour foundation stays SmartHR's (see the table above); the neutrals are
214
- not derived from the brand seed. `colorBorder` is also the only role antd offers for a control
215
- boundary and it measures **1.43:1** on the page, where `--input` is held to 3:1 by SC 1.4.11 and
216
- by `input-boundary-contrast.test.ts`.
217
- - **The text ramp.** antd's is alpha-based (`rgba(0,0,0,0.88)`), which cannot enter this library's
218
- opaque `H S% L%` triple without choosing a surface to composite against — lossy by construction.
219
- - **The dark `--primary` itself.** `darkAlgorithm` MOVES the seed (antd's own `#1677ff` becomes
220
- `#1668dc`). Feeding this library's light seed in gives `#0363a4` at **2.81:1** on the dark spine,
221
- which `primary-text-contrast.test.ts` rejects outright; antd's transform of the committed dark
222
- seed gives `#3794d3` at 5.36:1 where the seed itself measures 7.07:1. The dark theme therefore
223
- keeps its seed and everything derived from it is antd's. This is the one structural divergence,
224
- recorded in `DIVERGENCES` in the generator.
225
-
226
- **Geometry antd owns was already correct.** `lineWidth` 1, `controlOutlineWidth` 2,
227
- `lineWidthFocus` 3, `borderRadius` 6, `controlHeight` 32 and `fontSize` 14 all match the named
228
- scales this library already ships (`--stroke-*`, `--radius`, `--band-height-md`,
229
- `--font-size-base`). The generator asserts that agreement rather than emitting a second copy, so
230
- the two cannot drift apart silently.
231
-
232
- ## Focus appearance — Ant Design owns the shape, and the indicator SHIPS OFF
233
-
234
- ### The two forms, read from antd's source
219
+ **To change a derived value:** change it, run `pnpm test`, and if a threshold breaks the value is
220
+ wrong. Do not relax the threshold.
235
221
 
236
- **SmartHR** (`smarthr-ui@99.6.0`) draws focus as an opaque ring held off the control by a white
237
- spacer. **Ant Design** (`antd@6.6.2`) has two forms instead:
222
+ **The four overrides that existed even while a generator did** the clearest evidence the
223
+ algorithm was never the real authority. Stepping an interactive fill towards the label sitting on
224
+ it lands under 4.5:1, so those four states take the same ramp at the same step size in the
225
+ opposite direction:
238
226
 
239
- - **Field** `borderColor: colorPrimary` at the unchanged `lineWidth`, plus
240
- `boxShadow: 0 0 0 ${controlOutlineWidth}px ${controlOutline}`
241
- (`es/input/style/token.js:48-50`). `es/select/style/select-input.js:32` emits the same
242
- declarations, which is why an antd Select focuses exactly like an antd Input.
243
- - **Non-field** `genFocusOutline` (`es/style/index.js:60-64`):
244
- `outline: ${lineWidthFocus}px solid ${colorPrimaryBorder}; outline-offset: 1`.
227
+ | token | conventional step | shipped |
228
+ | ------------------------ | ----------------- | ----------------- |
229
+ | light `--primary-hover` | #208bc9 · 3.69:1 | #005596 · 7.53:1 |
230
+ | light `--primary-active` | #005596 · 7.53:1 | #003c70 · 10.97:1 |
231
+ | dark `--primary-hover` | #61b6e8 · 7.92:1 | #61b6e8 · 7.92:1 |
232
+ | dark `--primary-active` | #2f76a6 · 3.60:1 | #8bd0f3 · 10.50:1 |
245
233
 
246
- **v5 v6 changed none of this.** Both majors were unpacked and their own `formatToken` run side by
247
- side; every value is identical to the digit in `antd@5.29.3`.
234
+ **What was deliberately never derived, and why each a measurement, not a preference:**
248
235
 
249
- **Ant Design wins the shape.** The library shipped an opaque brand ring drawn immediately outside an
250
- untouched grey border two outlines of different colours claiming the same edge and a Select that
251
- could not be told to agree with an Input. antd's rule resolves both. SmartHR still owns the hue: the
252
- focus colour is `--ring`, which the generated tier declares as `var(--primary)` because antd has no
253
- separate focus-colour token at all.
236
+ - **The neutral spine.** Colour foundation stays SmartHR's (see the table above); the neutrals are
237
+ not derived from the brand seed. The one derived role on offer for a control boundary measures
238
+ **1.43:1** on the page, where `--input` is held to 3:1 by SC 1.4.11 and by
239
+ `input-boundary-contrast.test.ts`.
240
+ - **The text ramp.** The derived one is alpha-based (`rgba(0,0,0,0.88)`), which cannot enter this
241
+ library's opaque `H S% L%` triple without choosing a surface to composite against — lossy by
242
+ construction.
243
+ - **The dark `--primary` itself.** A mechanical dark derivation MOVES the seed. Deriving from this
244
+ library's light seed gives `#0363a4` at **2.81:1** on the dark spine, which
245
+ `primary-text-contrast.test.ts` rejects outright; deriving from the committed dark seed gives
246
+ `#3794d3` at 5.36:1, where the seed itself measures 7.07:1. The dark theme therefore keeps its
247
+ own seed — recorded, with the measurement, in `focus-ring-contrast.test.ts`.
248
+
249
+ **The focus geometry was already on the named scale.** Border 1, halo width 2, heavy outline 3,
250
+ radius 6, control height 32 and font size 14 all match scales this library already ships
251
+ (`--stroke-*`, `--radius`, `--band-height-md`, `--font-size-base`), so the focus tokens bind to
252
+ those steps instead of restating a second copy of the number.
253
+
254
+ **antd itself is gone from this repository**, and `pnpm check:no-antd-runtime` is what keeps it
255
+ gone: it fails if antd or any `@ant-design/*` package appears in any manifest field, is imported
256
+ anywhere in `src/`, or leaves a trace in `dist/`. Deleting that gate re-opens the door it closes.
257
+
258
+ ## Focus appearance — a two-form convention, and the indicator SHIPS OFF
259
+
260
+ ### The two forms
261
+
262
+ **SmartHR** (`smarthr-ui@99.6.0`) draws focus as an opaque ring held off the control by a white
263
+ spacer. This library takes a different, two-form convention instead — widely used in enterprise
264
+ component libraries, and surveyed across several before it was adopted here:
265
+
266
+ - **Field** — the boundary RECOLOURS to the primary at its unchanged hairline width, plus
267
+ `box-shadow: 0 0 0 var(--control-outline-width) var(--control-outline)`. A Select emits the same
268
+ declarations as an Input, which is why the two focus identically.
269
+ - **Non-field** — an outline outside the box model:
270
+ `outline: var(--focus-outline-weight) solid var(--primary-border); outline-offset: 1px`.
271
+
272
+ **Why this shape wins.** The library previously shipped an opaque brand ring drawn immediately
273
+ outside an untouched grey border — two outlines of different colours claiming the same edge — and a
274
+ Select that could not be told to agree with an Input. Recolouring the existing boundary rather than
275
+ adding a second one resolves both. SmartHR still owns the hue: the focus colour is `--ring`, which
276
+ the derived tier declares as `var(--primary)`, because a focused field takes the primary rather than
277
+ a focus colour of its own.
254
278
 
255
279
  ### The indicator ships OFF. That forfeits WCAG 2.4.7 and a JIS X 8341-3 AA claim.
256
280
 
@@ -272,15 +296,15 @@ owner chose to ship it off and let whoever needs it turn it on. What that costs,
272
296
  <html data-focus-outline="on">
273
297
  ```
274
298
 
275
- **The switch is antd's own mechanism, not one invented here.** antd 6.6.2 carries a `focusOutline`
276
- seed flag (`es/theme/themes/seed.js:67`) and consumes it in `es/theme/util/alias.js:71`:
299
+ **The switch is a single multiplier, not a scatter of overrides.** `--focus-outline` is one flag,
300
+ and every painted focus length multiplies by it:
277
301
 
278
- ```js
279
- lineWidthFocus: mergedToken.focusOutline === false ? 0 : mergedToken.lineWidth * 3
302
+ ```css
303
+ --focus-ring-width: calc(var(--focus-ring-weight) * var(--focus-outline));
280
304
  ```
281
305
 
282
- The flag zeroes the focus line width. `--focus-outline` is that flag in CSS: every painted length
283
- multiplies by it, so no component rebind can bring the mark back while it is `0`. The two paints
306
+ Setting it to `0` zeroes every focus length at once, so no component rebind can bring the mark back
307
+ while it is off which is the property a scatter of per-component overrides could never give. The two paints
284
308
  that are not lengths — the halo and a field's recoloured boundary — are scoped to the same attribute
285
309
  in `styles/focus-ring.css`. **Every `:focus-visible` selector stays exactly where it is**; only the
286
310
  painted result disappears.
@@ -288,8 +312,8 @@ painted result disappears.
288
312
  ### The ON state is the LIGHT one
289
313
 
290
314
  The complaint was weight, not existence, so the on-position is not the old mark restored. It paints
291
- antd's **field** indicator on every control — one `lineWidth` (1px) in the focus hue, plus antd's
292
- `controlOutline` halo — rather than antd's 3px `genFocusOutline`. Measured, in Chromium, on
315
+ the **field** indicator on every control — one hairline (1px) in the focus hue, plus the
316
+ `--control-outline` halo — rather than the heavy 3px outline form. Measured, in Chromium, on
293
317
  `ql.test` after the transition settles:
294
318
 
295
319
  | control | switch off | switch on |
@@ -298,8 +322,8 @@ antd's **field** indicator on every control — one `lineWidth` (1px) in the foc
298
322
  | Button (primary) | outline `0px`, resting shadow intact | `outline: 1px solid rgb(0,113,189)` @ `0px` + same halo |
299
323
  | Sidebar nav row / list row | outline `0px` | `outline: 1px solid rgb(0,113,189)` @ **`-1px`** (inset into the row) |
300
324
 
301
- The field pair is **byte-identical to antd's own `activeBorderColor` + `activeShadow`** for this
302
- seed. The nav row insets its mark into its own shape rather than wrapping an already-shaded surface,
325
+ The field pair is the recoloured boundary plus the halo, exactly as the convention specifies for
326
+ this seed. The nav row insets its mark into its own shape rather than wrapping an already-shaded surface,
303
327
  which is the specific stacking that read as heavy.
304
328
 
305
329
  **No control's box moves when it is focused**, measured with `getBoundingClientRect()` before and
@@ -308,11 +332,12 @@ Input, Save and Delete all stay at 32.00px.
308
332
 
309
333
  **Two criteria, and only one is met by thickness alone.** SC 1.4.11 (AA, non-text contrast) is about
310
334
  COLOUR — the 1px mark measures 5.05:1 light and 7.07:1 dark on every surface a control sits on, so
311
- the light weight costs nothing there. antd's own `colorPrimaryBorder` (#6dc0e3) measures **2.00:1
312
- light / 1.66:1 dark** and could not have satisfied it at any thickness, which is why the on-state
313
- takes the focus hue instead — the single place it departs from `genFocusOutline`. SC 2.4.13 Focus
314
- Appearance (AAA) additionally wants a 2px perimeter; the on-state does not target it, and
315
- `--focus-outline-weight: var(--stroke-lg)` restores antd's 3px if a customer needs the area clause.
335
+ the light weight costs nothing there. `--primary-border` (#6dc0e3) measures **2.00:1 light /
336
+ 1.66:1 dark** and could not have satisfied it at any thickness, which is why the on-state takes the
337
+ focus hue instead — the single place it departs from the outline form. SC 2.4.13 Focus Appearance
338
+ (AAA) additionally wants a 2px perimeter; the on-state does not target it, and
339
+ `--focus-outline-weight: var(--stroke-lg)` restores the 3px weight if a customer needs the area
340
+ clause.
316
341
 
317
342
  Both positions of the switch are gated in `src/tokens/__tests__/focus-ring-contrast.test.ts`: with
318
343
  it off nothing paints and no rebind can route around it, with it on the geometry and the ≥3:1
@@ -3,8 +3,8 @@
3
3
  > Generated by `scripts/frame-coverage.mjs` (issue #163). Do not edit by hand — run `pnpm check:frame-coverage`.
4
4
  > Standard: [FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md). A missing dimension is **UNTESTED**, never a pass.
5
5
 
6
- - Public components: **129**
7
- - With ≥1 frame: **129** · zero-frame: **0**
6
+ - Public components: **131**
7
+ - With ≥1 frame: **131** · zero-frame: **0**
8
8
  - Fully covered (every contract axis declared): **0**
9
9
 
10
10
  ## Per-component contract axes
@@ -41,6 +41,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
41
41
  | StatCard | ✓ | N/A | N/A | · | · | · | · | · | · | · |
42
42
  | ServiceLauncherCard | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
43
43
  | Badge | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
44
+ | Legend | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
44
45
  | ListRow | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
45
46
  | CredentialReveal | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
46
47
  | QrCode | ✓ | ✓ | N/A | · | · | · | · | · | · | · |
@@ -106,7 +107,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
106
107
  | Avatar | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
107
108
  | Separator | ✓ | · | N/A | N/A | · | · | · | · | · | · |
108
109
  | Skeleton | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
109
- | Toggle | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
110
+ | Toggle | ✓ | ✓ | · | N/A | · | · | · | · | · | · |
110
111
  | ToggleGroup | ✓ | ✓ | · | · | · | · | · | · | · | · |
111
112
  | AspectRatio | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
112
113
  | Accordion | ✓ | N/A | · | · | · | · | · | · | · | · |
@@ -123,6 +124,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
123
124
  | ResizablePanel | ✓ | N/A | · | N/A | · | · | · | · | · | · |
124
125
  | Carousel | ✓ | N/A | N/A | · | · | · | · | · | · | · |
125
126
  | AppSettingPicker | ✓ | N/A | · | · | · | · | · | · | · | · |
127
+ | AppSettingToggle | ✓ | N/A | · | · | · | · | · | · | · | · |
126
128
  | Field | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
127
129
  | LineChart | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
128
130
  | BarChart | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
package/docs/README.md CHANGED
@@ -1,19 +1,19 @@
1
1
  # @godxjp/ui Documentation
2
2
 
3
- | Doc | Purpose |
4
- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5
- | [CONSUMER-RULES.md](./CONSUMER-RULES.md) | **Start here if you build an app with @godxjp/ui** — the ten rules the audit enforces (styles entry, layout owners, real primitives, tokens) |
6
- | [DEVELOPMENT.md](./DEVELOPMENT.md) | **Contributor guideline** — role/boundary, architecture, how to add/extend, verify |
7
- | [COMPONENTS.md](./COMPONENTS.md) | Component catalog by Ant Design group |
8
- | [PROPS-VOCABULARY.md](./PROPS-VOCABULARY.md) | Atomic prop types (`*Prop` suffix) |
9
- | [PROPS-REGISTRY.md](./PROPS-REGISTRY.md) | Machine-readable registry + forbidden aliases |
10
- | [DATETIME.md](./DATETIME.md) | **Mandatory** `formatDate` — all date/time display |
11
- | [DESIGN-AUTHORITY.md](./DESIGN-AUTHORITY.md) | **Which external standard owns which decision** — APG, Radix, shadcn, Ant Design groups, SmartHR colour, Carbon geometry. Read before inventing a spacing/density/layout answer |
12
- | [SPACING.md](./SPACING.md) | Golden ratio (φ) macro spacing — PageContainer sections, Flex gap, Card rhythm |
13
- | [FORMS.md](./FORMS.md) | **Mandatory** react-hook-form + Zod 4 |
14
- | [TESTING.md](./TESTING.md) | **Mandatory** Vitest per component |
15
- | [FRAME-A11Y-CI.md](./FRAME-A11Y-CI.md) | Per-frame axe a11y + geometry + coverage CI gates — how to run/regenerate locally |
16
- | [../README.md](../README.md) | Setup, workspace wiring, theme |
3
+ | Doc | Purpose |
4
+ | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5
+ | [CONSUMER-RULES.md](./CONSUMER-RULES.md) | **Start here if you build an app with @godxjp/ui** — the ten rules the audit enforces (styles entry, layout owners, real primitives, tokens) |
6
+ | [DEVELOPMENT.md](./DEVELOPMENT.md) | **Contributor guideline** — role/boundary, architecture, how to add/extend, verify |
7
+ | [COMPONENTS.md](./COMPONENTS.md) | Component catalog by taxonomy group |
8
+ | [PROPS-VOCABULARY.md](./PROPS-VOCABULARY.md) | Atomic prop types (`*Prop` suffix) |
9
+ | [PROPS-REGISTRY.md](./PROPS-REGISTRY.md) | Machine-readable registry + forbidden aliases |
10
+ | [DATETIME.md](./DATETIME.md) | **Mandatory** `formatDate` — all date/time display |
11
+ | [DESIGN-AUTHORITY.md](./DESIGN-AUTHORITY.md) | **Which external standard owns which decision** — APG, Radix, shadcn, Ant Design groups, SmartHR colour, Carbon geometry, measured contrast for derived colour. Read before inventing a spacing/density/layout answer |
12
+ | [SPACING.md](./SPACING.md) | Golden ratio (φ) macro spacing — PageContainer sections, Flex gap, Card rhythm |
13
+ | [FORMS.md](./FORMS.md) | **Mandatory** react-hook-form + Zod 4 |
14
+ | [TESTING.md](./TESTING.md) | **Mandatory** Vitest per component |
15
+ | [FRAME-A11Y-CI.md](./FRAME-A11Y-CI.md) | Per-frame axe a11y + geometry + coverage CI gates — how to run/regenerate locally |
16
+ | [../README.md](../README.md) | Setup, workspace wiring, theme |
17
17
 
18
18
  ## Preview
19
19