@godxjp/ui 21.0.0 → 23.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 (154) hide show
  1. package/README.md +4 -4
  2. package/dist/app/app-provider.js +2 -1
  3. package/dist/components/data-display/badge.d.ts +28 -1
  4. package/dist/components/data-display/badge.js +2 -0
  5. package/dist/components/data-display/data-table.d.ts +18 -2
  6. package/dist/components/data-display/data-table.js +4 -0
  7. package/dist/components/data-display/index.d.ts +1 -1
  8. package/dist/components/data-display/popover.d.ts +19 -1
  9. package/dist/components/data-display/popover.js +9 -1
  10. package/dist/components/data-display/progress.d.ts +37 -0
  11. package/dist/components/data-display/progress.js +57 -5
  12. package/dist/components/data-display/scroll-area.d.ts +24 -4
  13. package/dist/components/data-display/scroll-area.js +34 -72
  14. package/dist/components/data-entry/cascader.js +8 -6
  15. package/dist/components/data-entry/checkbox.js +2 -0
  16. package/dist/components/data-entry/choice-hit-target.d.ts +24 -0
  17. package/dist/components/data-entry/choice-hit-target.js +12 -0
  18. package/dist/components/data-entry/control-surface.d.ts +8 -0
  19. package/dist/components/data-entry/control-surface.js +10 -1
  20. package/dist/components/data-entry/date-picker.d.ts +10 -3
  21. package/dist/components/data-entry/date-picker.js +503 -238
  22. package/dist/components/data-entry/form-field.d.ts +1 -1
  23. package/dist/components/data-entry/form-field.js +7 -3
  24. package/dist/components/data-entry/form.js +10 -1
  25. package/dist/components/data-entry/index.d.ts +0 -6
  26. package/dist/components/data-entry/index.js +0 -6
  27. package/dist/components/data-entry/label.d.ts +14 -1
  28. package/dist/components/data-entry/label.js +6 -1
  29. package/dist/components/data-entry/radio.d.ts +27 -6
  30. package/dist/components/data-entry/radio.js +89 -43
  31. package/dist/components/data-entry/search-select.js +226 -89
  32. package/dist/components/data-entry/select.d.ts +76 -14
  33. package/dist/components/data-entry/select.js +497 -163
  34. package/dist/components/data-entry/slider.d.ts +3 -11
  35. package/dist/components/data-entry/slider.js +582 -93
  36. package/dist/components/data-entry/switch.d.ts +6 -3
  37. package/dist/components/data-entry/switch.js +36 -11
  38. package/dist/components/layout/mobile-shell.d.ts +1 -1
  39. package/dist/components/layout/mobile-shell.js +2 -0
  40. package/dist/components/navigation/dropdown-menu.d.ts +11 -3
  41. package/dist/components/navigation/dropdown-menu.js +190 -15
  42. package/dist/components/navigation/index.d.ts +0 -3
  43. package/dist/components/navigation/index.js +0 -78
  44. package/dist/components/navigation/steps.d.ts +1 -1
  45. package/dist/components/navigation/steps.js +3 -1
  46. package/dist/components/navigation/tabs-scroll.d.ts +27 -0
  47. package/dist/components/navigation/tabs-scroll.js +52 -1
  48. package/dist/components/navigation/tabs.d.ts +2 -2
  49. package/dist/components/navigation/tabs.js +88 -23
  50. package/dist/components/ui/index.d.ts +0 -4
  51. package/dist/components/ui/index.js +0 -4
  52. package/dist/components/ui/input-otp.d.ts +1 -1
  53. package/dist/components/ui/segmented.d.ts +15 -1
  54. package/dist/components/ui/segmented.js +15 -6
  55. package/dist/components/ui/tag-input.js +3 -5
  56. package/dist/i18n/messages/en.json +3 -2
  57. package/dist/i18n/messages/ja.json +3 -2
  58. package/dist/i18n/messages/vi.json +3 -2
  59. package/dist/lib/datetime/picker-format.d.ts +18 -0
  60. package/dist/lib/datetime/picker-format.js +35 -1
  61. package/dist/lib/field-a11y.d.ts +12 -0
  62. package/dist/lib/field-a11y.js +14 -1
  63. package/dist/lib/select-options.d.ts +21 -0
  64. package/dist/lib/select-options.js +46 -0
  65. package/dist/props/components/data-display.prop.d.ts +16 -6
  66. package/dist/props/components/data-entry.prop.d.ts +503 -129
  67. package/dist/props/components/index.d.ts +2 -2
  68. package/dist/props/components/layout.prop.d.ts +12 -1
  69. package/dist/props/components/navigation.prop.d.ts +93 -1
  70. package/dist/props/registry.d.ts +79 -16
  71. package/dist/props/registry.js +85 -15
  72. package/dist/props/vocabulary/data.prop.d.ts +12 -0
  73. package/dist/props/vocabulary/index.d.ts +2 -2
  74. package/dist/props/vocabulary/layout.prop.d.ts +11 -0
  75. package/dist/styles/badge-layout.css +4 -0
  76. package/dist/styles/card-layout.css +6 -6
  77. package/dist/styles/control.css +220 -29
  78. package/dist/styles/data-display-layout.css +94 -23
  79. package/dist/styles/focus-ring.css +6 -4
  80. package/dist/styles/fonts.css +88 -4
  81. package/dist/styles/navigation-layout.css +36 -236
  82. package/dist/styles/shell-layout.css +149 -139
  83. package/dist/styles/table-layout.css +41 -3
  84. package/dist/tokens/components/control.css +4 -0
  85. package/dist/tokens/components/data-display.css +9 -5
  86. package/dist/tokens/components/navigation.css +9 -5
  87. package/dist/tokens/components/scroll-area.css +7 -0
  88. package/dist/tokens/components/segmented.css +0 -2
  89. package/dist/tokens/components/shell.css +2 -0
  90. package/dist/tokens/components/table.css +3 -0
  91. package/dist/tokens/foundation.css +7 -0
  92. package/docs/COMPONENTS.md +14 -14
  93. package/docs/CONSUMER-RULES.md +24 -1
  94. package/docs/CUSTOMER-THEMING.md +7 -1
  95. package/docs/FRAME-COVERAGE-REPORT.md +5 -11
  96. package/docs/TOKENS.md +65 -0
  97. package/docs/data-display/badge.tsx +37 -0
  98. package/docs/data-display/data-table/index.tsx +45 -1
  99. package/docs/data-display/popover.tsx +43 -5
  100. package/docs/data-display/progress.tsx +28 -0
  101. package/docs/data-display/scroll-area.tsx +51 -45
  102. package/docs/data-entry/calendar.tsx +2 -2
  103. package/docs/data-entry/date-picker.tsx +144 -5
  104. package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
  105. package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
  106. package/docs/data-entry/form.tsx +4 -4
  107. package/docs/data-entry/input-otp.tsx +5 -2
  108. package/docs/data-entry/number-input.tsx +31 -0
  109. package/docs/data-entry/segmented.tsx +143 -2
  110. package/docs/data-entry/select-matrix.tsx +1 -2
  111. package/docs/data-entry/select.tsx +108 -3
  112. package/docs/data-entry/slider.tsx +125 -47
  113. package/docs/feedback/dialog.tsx +1 -2
  114. package/docs/feedback/sheet.tsx +1 -2
  115. package/docs/layout/app-shell-states.tsx +143 -0
  116. package/docs/layout/mobile-shell.tsx +5 -0
  117. package/docs/navigation/dropdown-menu.tsx +75 -4
  118. package/docs/navigation/tabs.tsx +149 -0
  119. package/docs/roadmap/antd-parity.md +35 -34
  120. package/docs/roadmap/parity-audit-data-entry.md +196 -172
  121. package/docs/roadmap/parity-audit-layout-navigation-general.md +304 -310
  122. package/docs/roadmap/parity-backlog.md +8 -10
  123. package/docs/showcase/acme-portal.tsx +7 -0
  124. package/package.json +28 -64
  125. package/scripts/ui-audit.mjs +18 -5
  126. package/scripts/visual-audit-rules.mjs +0 -7
  127. package/scripts/visual-audit.mjs +6 -27
  128. package/dist/components/data-entry/date-range-picker.d.ts +0 -11
  129. package/dist/components/data-entry/date-range-picker.js +0 -349
  130. package/dist/components/data-entry/month-picker.d.ts +0 -10
  131. package/dist/components/data-entry/month-picker.js +0 -241
  132. package/dist/components/data-entry/month-range-picker.d.ts +0 -10
  133. package/dist/components/data-entry/month-range-picker.js +0 -301
  134. package/dist/components/navigation/context-menu.d.ts +0 -21
  135. package/dist/components/navigation/context-menu.js +0 -149
  136. package/dist/components/navigation/menubar.d.ts +0 -21
  137. package/dist/components/navigation/menubar.js +0 -136
  138. package/dist/components/navigation/navigation-menu.d.ts +0 -10
  139. package/dist/components/navigation/navigation-menu.js +0 -91
  140. package/dist/components/ui/context-menu.d.ts +0 -1
  141. package/dist/components/ui/context-menu.js +0 -2
  142. package/dist/components/ui/date-range-picker.d.ts +0 -1
  143. package/dist/components/ui/date-range-picker.js +0 -2
  144. package/dist/components/ui/menubar.d.ts +0 -1
  145. package/dist/components/ui/menubar.js +0 -2
  146. package/dist/components/ui/navigation-menu.d.ts +0 -1
  147. package/dist/components/ui/navigation-menu.js +0 -2
  148. package/docs/FRAME-A11Y-CI.md +0 -349
  149. package/docs/data-entry/date-range-picker.tsx +0 -175
  150. package/docs/data-entry/month-picker.tsx +0 -101
  151. package/docs/data-entry/month-range-picker.tsx +0 -115
  152. package/docs/navigation/context-menu.tsx +0 -128
  153. package/docs/navigation/menubar.tsx +0 -141
  154. package/docs/navigation/navigation-menu.tsx +0 -158
@@ -23,19 +23,18 @@ compared against, or successive waves will silently measure against different ta
23
23
 
24
24
  ## P0 — fix first, regardless of which strategy wins
25
25
 
26
- | # | Defect | Evidence | Why P0 |
27
- | --- | --- | --- | --- |
28
- | 1 | **`NumberInput` corrupts values 10× in comma-decimal locales, including shipped `vi`** | formats via `Intl.NumberFormat` (`number-input.tsx:100`), parses via hardcoded `replace(/,/g,"")` (`:41`), `handleBlur` re-parses the displayed draft (`:220`). `Intl.NumberFormat("vi",{useGrouping:false}).format(1.5)` → `"1,5"` → parses back as `15` | Silent money/quantity corruption. Focus-then-blur is enough. Keep the NFKC 全角 fold — it is correct. |
29
- | 2 | **`Timeline` hardcodes English screen-reader status text** | `SR_PREFIX = {done:"Completed: ",…}` `timeline.tsx:31-35`, injected `:107`; `grep timeline src/i18n/messages/en.json` → 0 hits | A ja/vi product announces English. Violates the mandatory i18n gate. |
30
- | 3 | **`PasswordStrength` is hardcoded English end-to-end** | `password-strength.tsx:4-8,75,106,113,119-133`; never imports `useTranslation`; `labels` overrides only 3 of ~10 strings | Same gate; and consumers cannot work around it. |
26
+ | # | Defect | Evidence | Why P0 |
27
+ | --- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
28
+ | 1 | **`NumberInput` corrupts values 10× in comma-decimal locales, including shipped `vi`** | formats via `Intl.NumberFormat` (`number-input.tsx:100`), parses via hardcoded `replace(/,/g,"")` (`:41`), `handleBlur` re-parses the displayed draft (`:220`). `Intl.NumberFormat("vi",{useGrouping:false}).format(1.5)` → `"1,5"` → parses back as `15` | Silent money/quantity corruption. Focus-then-blur is enough. Keep the NFKC 全角 fold — it is correct. |
29
+ | 2 | **`Timeline` hardcodes English screen-reader status text** | `SR_PREFIX = {done:"Completed: ",…}` `timeline.tsx:31-35`, injected `:107`; `grep timeline src/i18n/messages/en.json` → 0 hits | A ja/vi product announces English. Violates the mandatory i18n gate. |
30
+ | 3 | **`PasswordStrength` is hardcoded English end-to-end** | `password-strength.tsx:4-8,75,106,113,119-133`; never imports `useTranslation`; `labels` overrides only 3 of ~10 strings | Same gate; and consumers cannot work around it. |
31
31
 
32
32
  ## P1 — grouped by owning file, so one agent owns one group
33
33
 
34
- **`data-entry`** — `Slider` missing `aria-valuetext` (`slider.tsx:138-157`) · `SearchInput` Enter does
34
+ **`data-entry`** — `SearchInput` Enter does
35
35
  not commit (no `onKeyDown` in the file; `:59-63`) · `ColorPicker` has no `size`/`status`/`variant`
36
36
  and no `presets` (`data-entry.prop.ts:893-908`) · `PasswordStrength` uses `role="img"` instead of
37
- `role="meter"` (`:74-76`) · `Upload showUploadList` boolean-only (`:1196`) · `DateRangePicker
38
- disabled` scalar, cannot lock one end (`:787`) · no `defaultPickerValue` on either date picker ·
37
+ `role="meter"` (`:74-76`) · `Upload showUploadList` boolean-only (`:1196`) ·
39
38
  `Transfer` has no `status` (`:1413-1459`) · `Cascader` search uncapped (`cascader.tsx:389-393`) ·
40
39
  `Select` lacks `fieldNames` although `Cascader` and `TreeSelect` both have it · `NumberInput` has
41
40
  no `stringMode`.
@@ -57,8 +56,7 @@ derives delta tone from a regex on a stringified node (`card.tsx:233-246`) · `Q
57
56
  `isDismissable`) · `Pagination` is controlled-only, breaking the full-triad rule · `AppShell` has no
58
57
  `onSidebarCollapsedChange` and no built-in trigger (`app-shell.tsx:30`) · shell collapse breakpoint
59
58
  hardcoded (`shell-layout.css:1119`) while the overlay family's equivalent is a token · `Sidebar`
60
- submenu open state is unreachable local state (`sidebar.tsx:271`) · `NavigationMenu` has no overflow
61
- affordance (WCAG 2.4.3 / 1.4.10) · no `copyable` anywhere despite `ErrorSurface` rendering a
59
+ submenu open state is unreachable local state (`sidebar.tsx:271`) · no `copyable` anywhere despite `ErrorSurface` rendering a
62
60
  `requestId` "so it can be read out or copied accurately" (`layout.prop.ts:787`) · clamped text
63
61
  cannot expand.
64
62
 
@@ -112,6 +112,13 @@ const THEME = `
112
112
  --warning: 41 73% 53%; --warning-foreground: 217 61% 12%; /* = brand gold */
113
113
  --destructive: 12 83% 44%; --destructive-foreground: 0 0% 100%;
114
114
  --info: 217 69% 47%; --info-foreground: 0 0% 100%;
115
+ /* A TRACK IS A QUIET SURFACE, AND THIS THEME REPOINTED --secondary AT AN ACTION COLOUR.
116
+ Progress reads --progress-track-background, which defaults to hsl(var(--secondary)) — a pale
117
+ neutral in the stock palette. Here --secondary is the navy BUTTON, so the bar's track came out
118
+ near-black and the fill (a MARK: nothing is written on it, so SC 1.4.11 asks 3:1 against the
119
+ track) measured 2.50:1 success / 2.90:1 warning on it. Naming the track is the fix; the fills
120
+ then sit on --muted like everywhere else. Any theme that repurposes --secondary owes this line. */
121
+ --progress-track-background: hsl(var(--muted));
115
122
  /* Shape - base radius + exact ACME steps; re-declare the intermediates so the scope re-resolves */
116
123
  --radius: 0.875rem; /* 14px card */
117
124
  --radius-xs: 4px; --radius-sm: 6px; --radius-md: 10px;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "21.0.0",
4
- "godxUiMcp": "21.0.0",
3
+ "version": "23.0.0",
4
+ "godxUiMcp": "23.0.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -213,10 +213,6 @@
213
213
  "types": "./dist/components/data-entry/date-picker.d.ts",
214
214
  "import": "./dist/components/data-entry/date-picker.js"
215
215
  },
216
- "./ui/date-range-picker": {
217
- "types": "./dist/components/data-entry/date-range-picker.d.ts",
218
- "import": "./dist/components/data-entry/date-range-picker.js"
219
- },
220
216
  "./ui/time-picker": {
221
217
  "types": "./dist/components/data-entry/time-picker.d.ts",
222
218
  "import": "./dist/components/data-entry/time-picker.js"
@@ -249,18 +245,6 @@
249
245
  "types": "./dist/components/data-entry/command.d.ts",
250
246
  "import": "./dist/components/data-entry/command.js"
251
247
  },
252
- "./ui/context-menu": {
253
- "types": "./dist/components/navigation/context-menu.d.ts",
254
- "import": "./dist/components/navigation/context-menu.js"
255
- },
256
- "./ui/menubar": {
257
- "types": "./dist/components/navigation/menubar.d.ts",
258
- "import": "./dist/components/navigation/menubar.js"
259
- },
260
- "./ui/navigation-menu": {
261
- "types": "./dist/components/navigation/navigation-menu.d.ts",
262
- "import": "./dist/components/navigation/navigation-menu.js"
263
- },
264
248
  "./ui/resizable": {
265
249
  "types": "./dist/components/layout/resizable.d.ts",
266
250
  "import": "./dist/components/layout/resizable.js"
@@ -347,21 +331,26 @@
347
331
  "check:data-entry-touch-aria": "node scripts/check-data-entry-touch-aria.mjs",
348
332
  "check:layout-nav-frames": "node scripts/check-layout-nav-frames.mjs",
349
333
  "check:provider-feedback-query-runtime": "for frames in navigation-app-setting-picker,feedback-dialog,feedback-sheet,feedback-alert-dialog feedback-tooltip,feedback-toast,feedback-skeleton,query-data-state query-infinite-query-state,query-mutation-feedback,query-prefetch-link; do FRAMES=$frames node scripts/check-provider-feedback-query-runtime.mjs || exit 1; done",
350
- "check:layout-nav-closure": "for frames in layout-flex,layout-app-shell,layout-aspect-ratio,layout-auth-shell layout-page-container,layout-resizable-panel,layout-separator,layout-sidebar layout-split-pane,layout-topbar,navigation-breadcrumb,navigation-app-setting-picker navigation-context-menu,navigation-dropdown-menu,navigation-menubar,navigation-navigation-menu navigation-steps,navigation-toolbar,navigation-tabs,navigation-pagination; do FRAMES=$frames node scripts/check-layout-nav-closure.mjs || exit 1; done",
334
+ "check:layout-nav-closure": "for frames in layout-flex,layout-app-shell,layout-aspect-ratio,layout-auth-shell layout-page-container,layout-resizable-panel,layout-separator,layout-sidebar layout-split-pane,layout-topbar,navigation-breadcrumb,navigation-app-setting-picker navigation-dropdown-menu navigation-steps,navigation-toolbar,navigation-tabs,navigation-pagination; do FRAMES=$frames node scripts/check-layout-nav-closure.mjs || exit 1; done",
351
335
  "check:display-runtime-evidence": "node scripts/check-display-runtime-evidence.mjs",
352
336
  "check:data-table-pagination-wrap": "node scripts/check-data-table-pagination-wrap.mjs",
337
+ "check:choice-hit-target": "node scripts/check-choice-hit-target.mjs",
338
+ "check:data-table-overflow": "node scripts/check-data-table-overflow.mjs",
339
+ "check:app-shell-narrow-grid": "node scripts/check-app-shell-narrow-grid.mjs",
340
+ "check:segmented-wrap": "node scripts/check-segmented-wrap.mjs",
341
+ "check:tabs-overflow-menu": "node scripts/check-tabs-overflow-menu.mjs",
353
342
  "check:button-icon-xs": "node scripts/check-button-icon-xs.mjs",
354
343
  "check:timeline-title-fill": "node scripts/check-timeline-title-fill.mjs",
355
344
  "check:descriptions-label-value-step": "node scripts/check-descriptions-label-value-step.mjs",
356
345
  "check:frame-contracts": "pnpm check:component-api-manifest && pnpm audit:component-cases && pnpm check:frame-coverage && pnpm check:frame-coverage-ledger && pnpm check:screen-reader-evidence && pnpm check:data-entry-owner-source && pnpm check:display-runtime-evidence",
357
346
  "check:final-touch-rtl": "node scripts/check-final-touch-rtl.mjs",
358
- "check:frame-runtime": "pnpm check:data-entry-frame-runtime && pnpm check:data-entry-touch-aria && pnpm check:layout-nav-frames && pnpm check:provider-feedback-query-runtime && pnpm check:layout-nav-closure && pnpm check:final-touch-rtl && pnpm check:data-table-pagination-wrap && pnpm check:button-icon-xs && pnpm check:timeline-title-fill && pnpm check:descriptions-label-value-step",
359
- "verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:frame-coverage && pnpm test",
360
- "verify:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:token-scale-bypass && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm check:contrast && pnpm check:visual-audit && pnpm test",
347
+ "check:frame-runtime": "pnpm check:data-entry-frame-runtime && pnpm check:data-entry-touch-aria && pnpm check:layout-nav-frames && pnpm check:provider-feedback-query-runtime && pnpm check:layout-nav-closure && pnpm check:final-touch-rtl && pnpm check:data-table-pagination-wrap && pnpm check:data-table-overflow && pnpm check:app-shell-narrow-grid && pnpm check:choice-hit-target && pnpm check:segmented-wrap && pnpm check:tabs-overflow-menu && pnpm check:button-icon-xs && pnpm check:timeline-title-fill && pnpm check:descriptions-label-value-step",
348
+ "verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:radix-surface && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:disclosure-duplication && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:frame-coverage && pnpm test",
349
+ "verify:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:token-scale-bypass && pnpm check:radix-surface && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:disclosure-duplication && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm check:contrast && pnpm check:visual-audit && pnpm test",
361
350
  "verify:ci": "pnpm verify:ci:static && pnpm check:frame-contracts && pnpm test",
362
- "verify:ci:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:registry && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:no-antd-runtime && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:gate-coverage && pnpm check:mcp-prop-sync && pnpm check:catalog-contradictions",
363
- "verify:browser": "pnpm check:contrast && pnpm check:text-ink-clip && pnpm check:visual-audit",
364
- "verify:release": "pnpm verify:static && pnpm check:frame-contracts && pnpm check:frame-coverage && pnpm check:frame-axe",
351
+ "verify:ci:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:registry && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:no-antd-runtime && pnpm check:radix-surface && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:disclosure-duplication && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:gate-coverage && pnpm check:mcp-prop-sync && pnpm check:catalog-contradictions && pnpm check:catalog-snippets",
352
+ "verify:browser": "pnpm check:contrast && pnpm check:text-ink-clip && pnpm check:font-fallback-metrics && pnpm check:visual-audit",
353
+ "verify:release": "pnpm verify:static && pnpm check:frame-contracts && pnpm check:frame-coverage",
365
354
  "verify:publish-tree": "pnpm build && pnpm check:packed-public-contract && pnpm check:use-client && pnpm check:dist-tokens-resolve",
366
355
  "check:release-plan": "node scripts/check-release-command-plan.mjs",
367
356
  "check:packed-public-contract": "node scripts/check-packed-public-contract.mjs",
@@ -383,6 +372,7 @@
383
372
  "check:no-hardcoded-geometry": "node scripts/check-no-hardcoded-geometry.mjs",
384
373
  "check:no-external-assets": "node scripts/check-no-external-assets.mjs",
385
374
  "check:no-hardcoded-css-values": "node scripts/check-no-hardcoded-css-values.mjs",
375
+ "check:disclosure-duplication": "node scripts/check-disclosure-duplication.mjs",
386
376
  "check:no-inline-magic-numbers": "node scripts/check-no-inline-magic-numbers.mjs",
387
377
  "check:no-tailwind-class-assertions": "node scripts/check-no-tailwind-class-assertions.mjs",
388
378
  "check:control-sizing": "node scripts/check-control-sizing.mjs",
@@ -390,6 +380,7 @@
390
380
  "check:typography": "node scripts/check-typography.mjs",
391
381
  "gen:component-tokens": "node scripts/gen-component-tokens.mjs",
392
382
  "check:no-antd-runtime": "node scripts/check-no-antd-runtime.mjs",
383
+ "check:radix-surface": "node scripts/check-radix-surface.mjs",
393
384
  "gen:email-tokens": "node scripts/gen-email-tokens.mjs",
394
385
  "check:core-isolation": "node scripts/check-core-isolation.mjs",
395
386
  "check:no-consumer-coupling": "node scripts/check-no-consumer-coupling.mjs",
@@ -408,19 +399,18 @@
408
399
  "check:gate-coverage": "node scripts/check-gate-coverage.mjs",
409
400
  "check:contrast": "node scripts/check-contrast.mjs",
410
401
  "check:text-ink-clip": "node scripts/check-text-ink-clip.mjs",
402
+ "check:font-fallback-metrics": "node scripts/check-font-fallback-metrics.mjs",
411
403
  "visual-audit": "node scripts/visual-audit.mjs",
412
404
  "check:visual-audit": "node scripts/visual-audit-smoke.mjs",
413
- "check:frame-axe": "node scripts/check-frame-axe.mjs",
414
405
  "check:frame-geometry": "node scripts/frame-geometry.mjs",
415
406
  "postinstall": "node scripts/postinstall.mjs",
416
407
  "init-agent": "node scripts/init-agent-kit.mjs",
417
- "check:use-client": "node scripts/check-use-client.mjs"
408
+ "check:use-client": "node scripts/check-use-client.mjs",
409
+ "check:catalog-snippets": "node scripts/audit-catalog-snippets.mjs"
418
410
  },
419
411
  "peerDependencies": {
420
- "@axe-core/playwright": "*",
421
412
  "@hookform/resolvers": "^5.2.0",
422
413
  "@tanstack/react-query": ">=5.0.0",
423
- "axe-core": "*",
424
414
  "playwright": "*",
425
415
  "react": ">=19.0.0",
426
416
  "react-dom": ">=19.0.0",
@@ -436,44 +426,12 @@
436
426
  },
437
427
  "playwright": {
438
428
  "optional": true
439
- },
440
- "@axe-core/playwright": {
441
- "optional": true
442
- },
443
- "axe-core": {
444
- "optional": true
445
429
  }
446
430
  },
447
431
  "dependencies": {
448
432
  "@date-fns/tz": "^1.5.0",
449
433
  "@fontsource/m-plus-2": "^5.3.0",
450
434
  "@fontsource/noto-sans-jp": "^5.3.0",
451
- "@radix-ui/react-accordion": "^1.2.20",
452
- "@radix-ui/react-alert-dialog": "^1.1.23",
453
- "@radix-ui/react-aspect-ratio": "^1.1.15",
454
- "@radix-ui/react-avatar": "^1.2.6",
455
- "@radix-ui/react-checkbox": "^1.3.11",
456
- "@radix-ui/react-collapsible": "^1.1.20",
457
- "@radix-ui/react-context": "^1.2.2",
458
- "@radix-ui/react-context-menu": "^2.3.7",
459
- "@radix-ui/react-dialog": "^1.1.23",
460
- "@radix-ui/react-dropdown-menu": "^2.1.24",
461
- "@radix-ui/react-hover-card": "^1.1.23",
462
- "@radix-ui/react-label": "^2.1.15",
463
- "@radix-ui/react-menubar": "^1.1.24",
464
- "@radix-ui/react-navigation-menu": "^1.2.22",
465
- "@radix-ui/react-popover": "^1.1.23",
466
- "@radix-ui/react-radio-group": "^1.4.7",
467
- "@radix-ui/react-scroll-area": "^1.2.18",
468
- "@radix-ui/react-select": "^2.3.7",
469
- "@radix-ui/react-separator": "^1.1.15",
470
- "@radix-ui/react-slider": "^1.4.7",
471
- "@radix-ui/react-slot": "^1.3.3",
472
- "@radix-ui/react-switch": "^1.3.7",
473
- "@radix-ui/react-tabs": "^1.1.21",
474
- "@radix-ui/react-toggle": "^1.1.18",
475
- "@radix-ui/react-toggle-group": "^1.1.19",
476
- "@radix-ui/react-tooltip": "^1.2.16",
477
435
  "@react-aria/utils": "^3.34.1",
478
436
  "@tanstack/react-table": "^9.2.4",
479
437
  "class-variance-authority": "^0.7.1",
@@ -495,9 +453,17 @@
495
453
  "vaul": "^1.1.2"
496
454
  },
497
455
  "devDependencies": {
498
- "@axe-core/playwright": "^4.13.0",
499
456
  "@eslint/js": "^10.0.1",
500
457
  "@hookform/resolvers": "^5.9.1",
458
+ "@radix-ui/react-accordion": "^1.2.20",
459
+ "@radix-ui/react-avatar": "^1.2.6",
460
+ "@radix-ui/react-collapsible": "^1.1.20",
461
+ "@radix-ui/react-label": "^2.1.15",
462
+ "@radix-ui/react-select": "^2.3.7",
463
+ "@radix-ui/react-separator": "^1.1.15",
464
+ "@radix-ui/react-slot": "^1.3.3",
465
+ "@radix-ui/react-toggle": "^1.1.18",
466
+ "@radix-ui/react-toggle-group": "^1.1.19",
501
467
  "@tailwindcss/vite": "^4.3.3",
502
468
  "@tanstack/react-query": "^5.102.8",
503
469
  "@testing-library/jest-dom": "^7.0.1",
@@ -509,7 +475,6 @@
509
475
  "@types/react-dom": "^19.2.5",
510
476
  "@vitejs/plugin-react": "^6.1.1",
511
477
  "@vitest/coverage-v8": "^4.1.11",
512
- "axe-core": "^4.13.0",
513
478
  "eslint": "^10.9.1",
514
479
  "eslint-plugin-react": "^7.37.5",
515
480
  "eslint-plugin-react-hooks": "^7.1.1",
@@ -532,7 +497,6 @@
532
497
  "typescript-eslint": "^8.68.0",
533
498
  "vite": "^8.2.2",
534
499
  "vitest": "^4.1.11",
535
- "vitest-axe": "1.0.0-pre.5",
536
500
  "zod": "^4.5.4"
537
501
  },
538
502
  "bin": {
@@ -33,7 +33,20 @@ const PALETTE =
33
33
  * Emoji in product text — Unicode "Extended_Pictographic" set (UTS #51). Catches
34
34
  * ✅🎉🔥🚀 etc. but NOT typographic punctuation (· — × ✓), which have their own rules.
35
35
  */
36
- const EMOJI = /\p{Extended_Pictographic}/u;
36
+ /*
37
+ * EMOJI — pictographs, but NOT the three typographic marks that happen to carry the property.
38
+ *
39
+ * `\p{Extended_Pictographic}` includes U+00A9 ©, U+00AE ® and U+2122 ™. All three are
40
+ * `Emoji_Presentation=No`: they default to TEXT presentation, they have been in typography since
41
+ * long before emoji existed, and none of the reasons in this rule's message applies to them — a
42
+ * copyright line does not "break on Win/Linux" and does not pollute an accessible name. The
43
+ * catalog's own CenteredShell recipe was flagged for the `©` in its footer, which is unavoidable
44
+ * product copy, and every consumer with a footer would be flagged for the same thing.
45
+ *
46
+ * Followed by U+FE0F they are asking for emoji presentation on purpose, and then they ARE emoji —
47
+ * so that spelling is still caught.
48
+ */
49
+ const EMOJI = /[\u00A9\u00AE\u2122]\uFE0F|(?![\u00A9\u00AE\u2122])\p{Extended_Pictographic}/u;
37
50
  /** Regional-indicator pairs = emoji flags (🇯🇵) — broken on Win/Linux; use Intl.DisplayNames. */
38
51
  const EMOJI_FLAG = /\p{Regional_Indicator}/u;
39
52
 
@@ -147,7 +160,7 @@ const RULES = [
147
160
  spansElement: true,
148
161
  // Only the tone-driven status components (Badge/Tag/StatCard) are wrong here — they expose a
149
162
  // `tone` prop and reserve `variant` for STRUCTURE (default|secondary|outline). Button, Alert,
150
- // DropdownMenuItem, ContextMenuItem, AlertDialog etc. legitimately use `variant` for emphasis,
163
+ // DropdownMenuItem, AlertDialog etc. legitimately use `variant` for emphasis,
151
164
  // so they must NOT be flagged.
152
165
  test: new RegExp(
153
166
  `<(?:Badge|Tag|StatCard)\\b${ATTRS}\\bvariant=["'](?:success|warning|destructive|info|neutral)["']`,
@@ -169,7 +182,7 @@ const RULES = [
169
182
  spansElement: true,
170
183
  test: new RegExp(
171
184
  "<(?:Checkbox\\.Group|Upload|Cascader|TreeSelect|Transfer|Select|SearchSelect|DatePicker|" +
172
- `DateRangePicker|TimePicker|ColorPicker|LocalePicker|TimezonePicker|DateFormatPicker|TimeFormatPicker)\\b${ATTRS}\\bonChange=`,
185
+ `TimePicker|ColorPicker|LocalePicker|TimezonePicker|DateFormatPicker|TimeFormatPicker)\\b${ATTRS}\\bonChange=`,
173
186
  "g",
174
187
  ),
175
188
  message:
@@ -729,8 +742,8 @@ const CARD_FLUSH = new RegExp(
729
742
  // legitimately, so they are NOT matched. Whole-file pass (the pair spans lines).
730
743
  const BARE_FIELD = new RegExp(
731
744
  `<(?:label|Label)\\b${ATTRS}>[\\s\\S]{0,240}?</(?:label|Label)>\\s*` +
732
- "<(?:Input|Select|Textarea|NumberInput|SearchInput|SearchSelect|DatePicker|DateRangePicker|" +
733
- "TimePicker|MonthPicker|MonthRangePicker|Cascader|TreeSelect|input)\\b",
745
+ "<(?:Input|Select|Textarea|NumberInput|SearchInput|SearchSelect|DatePicker|" +
746
+ "TimePicker|Cascader|TreeSelect|input)\\b",
734
747
  "g",
735
748
  );
736
749
 
@@ -7,13 +7,6 @@
7
7
 
8
8
  /** Catalog (agent-facing mirror lives in mcp/src/data/visual-rules.ts; kept in sync by a guard). */
9
9
  export const VISUAL_RULES = [
10
- {
11
- id: "axe-violations",
12
- severity: "warn",
13
- category: "a11y",
14
- standard: "WCAG 2.2 A/AA · WAI-ARIA 1.2 (axe-core engine)",
15
- fix: "Fix each axe violation at its node — contrast (1.4.3), name/role/value (4.1.2), ARIA, landmarks. axe runs on the REAL DOM, catching what static analysis cannot.",
16
- },
17
10
  {
18
11
  id: "target-size-min",
19
12
  severity: "warn",
@@ -23,8 +23,6 @@ import {
23
23
  */
24
24
  export const TESTED_VERSIONS = {
25
25
  playwright: { range: ">=1.55 <2", tested: "1.61.1" },
26
- "@axe-core/playwright": { range: ">=4.10 <5", tested: "4.12.1" },
27
- "axe-core": { range: ">=4.10 <5", tested: "4.12.1" },
28
26
  };
29
27
 
30
28
  /** Shape one product finding from a rule id (pure — unit-tested without a browser). */
@@ -138,9 +136,7 @@ function collectInPage() {
138
136
  // SPACING exception: undersized is allowed when a 24px-DIAMETER circle centred on the target
139
137
  // does not intersect the circle of any other target. Two circles of radius 12 intersect when
140
138
  // their centres are closer than 24px, so that is the whole test.
141
- const crowded = rawTargets.some(
142
- (o) => o !== t && Math.hypot(o.cx - t.cx, o.cy - t.cy) < 24,
143
- );
139
+ const crowded = rawTargets.some((o) => o !== t && Math.hypot(o.cx - t.cx, o.cy - t.cy) < 24);
144
140
  return { ...t, exempt: crowded ? null : "spacing" };
145
141
  });
146
142
 
@@ -278,18 +274,13 @@ function collectInPage() {
278
274
  /** Optional-peer loader — throws a tagged bootstrap error instead of a raw stack. */
279
275
  async function loadDeps() {
280
276
  try {
281
- const [{ chromium }, axe] = await Promise.all([
282
- import("playwright"),
283
- import("@axe-core/playwright"),
284
- ]);
285
- return { chromium, AxeBuilder: axe.default ?? axe.AxeBuilder };
277
+ const { chromium } = await import("playwright");
278
+ return { chromium };
286
279
  } catch (cause) {
287
- const err = new Error(
288
- "visual-audit needs the optional peers `playwright` and `@axe-core/playwright`",
289
- );
280
+ const err = new Error("visual-audit needs the optional peer `playwright`");
290
281
  err.bootstrap = true;
291
282
  err.hint =
292
- "pnpm add -D playwright @axe-core/playwright && pnpm exec playwright install chromium " +
283
+ "pnpm add -D playwright && pnpm exec playwright install chromium " +
293
284
  "(or set PLAYWRIGHT_CHROMIUM_EXECUTABLE to a system Chromium).";
294
285
  err.cause = cause;
295
286
  throw err;
@@ -301,7 +292,7 @@ async function loadDeps() {
301
292
  * (page/context/browser) is guaranteed via finally on BOTH success and failure.
302
293
  */
303
294
  /* c8 ignore start — the browser-driving glue; exercised by scripts/visual-audit-smoke.mjs in CI. */
304
- async function audit(targets, { chromium, AxeBuilder }) {
295
+ async function audit(targets, { chromium }) {
305
296
  const findings = [];
306
297
  const errors = [];
307
298
  let browser;
@@ -331,18 +322,6 @@ async function audit(targets, { chromium, AxeBuilder }) {
331
322
  }
332
323
 
333
324
  try {
334
- // 1) axe-core — real WCAG/ARIA engine.
335
- const { violations } = await new AxeBuilder({ page }).analyze();
336
- for (const v of violations) {
337
- findings.push(
338
- buildFinding(
339
- "axe-violations",
340
- url,
341
- `${v.id} (${v.impact}) — ${v.help} [${v.nodes.length} node(s)] ${v.helpUrl}`,
342
- ),
343
- );
344
- }
345
-
346
325
  // 2) computed-style / layout heuristics via the PURE rules.
347
326
  const m = await page.evaluate(collectInPage);
348
327
  for (const a of m.accents) {
@@ -1,11 +0,0 @@
1
- import * as React from "react";
2
- import type { DateRangePickerProp } from "../../props/components/data-entry.prop.js";
3
- export type { DateRangePickerProp, DateRangePickerProp as DateRangePickerProps, } from "../../props/components/data-entry.prop.js";
4
- /**
5
- * DateRangePicker — WAI-ARIA date-range combobox rendered as ONE input-styled control
6
- * (the established RangePicker convention): `[ from → to ✕ 📅 ]`. The two inner fields stay
7
- * real, typeable ISO `yyyy-MM-dd` inputs (form-submittable via `${name}_from` /
8
- * `${name}_to`, screen-reader friendly, e2e-testable by filling either input); the
9
- * range calendar is the visual affordance.
10
- */
11
- export declare function DateRangePicker({ value: valueProp, defaultValue, onValueChange, placeholder, disabled, className, id, name, locale: localeProp, showToday, showClose, fromDate, toDate, disabledDate, cellRender, allowClear, format, parseFormat, minDate, maxDate, showWeek, presets, needConfirm, allowEmpty, order, open: openProp, defaultOpen, onOpenChange, inputReadOnly, preserveInvalidOnBlur, placement, renderExtraFooter, size, status, variant, ref, ...ariaProps }: DateRangePickerProp): React.JSX.Element;