@godxjp/ui 28.7.0 → 28.8.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/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/marquee.d.ts +16 -0
- package/dist/components/data-display/marquee.js +155 -0
- package/dist/components/general/reveal.d.ts +23 -2
- package/dist/components/general/reveal.js +37 -7
- package/dist/components/general/typography.d.ts +4 -1
- package/dist/components/general/typography.js +14 -1
- package/dist/components/layout/affix.d.ts +86 -0
- package/dist/components/layout/affix.js +187 -0
- package/dist/components/layout/index.d.ts +4 -0
- package/dist/components/layout/index.js +4 -0
- package/dist/components/layout/legal-document-shell.js +4 -3
- package/dist/components/layout/masonry.d.ts +74 -0
- package/dist/components/layout/masonry.js +214 -0
- package/dist/components/layout/page-container.js +5 -20
- package/dist/components/navigation/anchor.d.ts +64 -0
- package/dist/components/navigation/anchor.js +284 -0
- package/dist/components/navigation/index.d.ts +4 -0
- package/dist/components/navigation/index.js +4 -0
- package/dist/components/navigation/mega-menu.d.ts +21 -0
- package/dist/components/navigation/mega-menu.js +526 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +517 -0
- package/dist/i18n/messages/ja.json +513 -0
- package/dist/i18n/messages/vi.json +513 -0
- package/dist/lib/hooks.d.ts +68 -0
- package/dist/lib/hooks.js +52 -0
- package/dist/lib/platform.d.ts +14 -0
- package/dist/lib/platform.js +10 -1
- package/dist/lib/utils.d.ts +1 -1
- package/dist/lib/utils.js +3 -2
- package/dist/props/components/data-display.prop.d.ts +95 -1
- package/dist/props/components/general.prop.d.ts +47 -3
- package/dist/props/components/layout.prop.d.ts +194 -0
- package/dist/props/components/navigation.prop.d.ts +263 -0
- package/dist/props/registry.d.ts +359 -4
- package/dist/props/registry.js +472 -3
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +39 -2
- package/dist/styles/control.css +5 -6
- package/dist/styles/data-display-layout.css +2 -1
- package/dist/styles/density.css +4 -0
- package/dist/styles/layout.css +79 -0
- package/dist/styles/motion.css +121 -1
- package/dist/styles/navigation-layout.css +397 -1
- package/dist/styles/shell-layout.css +3 -0
- package/dist/styles/text-layout.css +52 -4
- package/dist/tokens/base.css +5 -0
- package/dist/tokens/components/affix.css +7 -0
- package/dist/tokens/components/anchor.css +17 -0
- package/dist/tokens/components/control.css +3 -3
- package/dist/tokens/components/form.css +1 -1
- package/dist/tokens/components/marquee.css +7 -0
- package/dist/tokens/components/masonry.css +6 -0
- package/dist/tokens/components/mega-menu.css +62 -0
- package/dist/tokens/components/shell.css +3 -0
- package/dist/tokens/foundation.css +11 -0
- package/dist/tokens/semantic/layout.css +7 -0
- package/docs/COMPOSITION-VS-COMPONENT.md +19 -1
- package/docs/DESIGN-AUTHORITY.md +99 -18
- package/docs/FRAME-COVERAGE-REPORT.md +7 -2
- package/docs/data-display/marquee.tsx +254 -0
- package/docs/foundation/_theme-editor-scope.ts +222 -0
- package/docs/foundation/density.tsx +12 -2
- package/docs/foundation/spacing.tsx +5 -0
- package/docs/foundation/theme-editor.tsx +645 -0
- package/docs/general/activity.tsx +65 -0
- package/docs/general/reveal.tsx +290 -22
- package/docs/general/typography.tsx +91 -1
- package/docs/layout/affix.tsx +209 -0
- package/docs/layout/masonry.tsx +291 -0
- package/docs/navigation/anchor.tsx +285 -0
- package/docs/navigation/mega-menu-panel.tsx +86 -0
- package/docs/navigation/mega-menu.tsx +254 -0
- package/docs/roadmap/website-components.md +779 -0
- package/docs/showcase/acme-website.tsx +75 -39
- package/docs/showcase/futurelastic-web.tsx +91 -49
- package/docs/showcase/marketing-page.tsx +885 -0
- package/docs/showcase/table-footer-totals.tsx +12 -2
- package/docs/showcase/theme-customization.tsx +1259 -0
- package/package.json +5 -3
- package/scripts/brand-accent.generated.mjs +27 -0
- package/scripts/ui-audit.mjs +66 -0
- package/scripts/visual-audit-rules.mjs +46 -2
|
@@ -27,6 +27,22 @@
|
|
|
27
27
|
font-size: var(--font-size-2xl);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
[data-slot="text"][data-size="3xl"],
|
|
31
|
+
[data-slot="text"][data-size="4xl"],
|
|
32
|
+
[data-slot="text"][data-size="5xl"] {
|
|
33
|
+
line-height: var(--line-height-tight);
|
|
34
|
+
letter-spacing: var(--letter-spacing-tight);
|
|
35
|
+
}
|
|
36
|
+
[data-slot="text"][data-size="3xl"] {
|
|
37
|
+
font-size: var(--font-size-3xl);
|
|
38
|
+
}
|
|
39
|
+
[data-slot="text"][data-size="4xl"] {
|
|
40
|
+
font-size: var(--font-size-4xl);
|
|
41
|
+
}
|
|
42
|
+
[data-slot="text"][data-size="5xl"] {
|
|
43
|
+
font-size: var(--font-size-5xl);
|
|
44
|
+
}
|
|
45
|
+
|
|
30
46
|
[data-slot="text"][data-weight="regular"],
|
|
31
47
|
[data-slot="heading"][data-weight="regular"] {
|
|
32
48
|
font-weight: var(--font-weight-normal);
|
|
@@ -154,18 +170,50 @@
|
|
|
154
170
|
letter-spacing: var(--letter-spacing-tight);
|
|
155
171
|
line-height: var(--line-height-tight);
|
|
156
172
|
}
|
|
157
|
-
|
|
173
|
+
|
|
174
|
+
[data-slot="heading"][data-level="1"]:not([data-size]) {
|
|
158
175
|
font-size: var(--heading-h1);
|
|
159
176
|
}
|
|
160
|
-
[data-slot="heading"][data-level="2"] {
|
|
177
|
+
[data-slot="heading"][data-level="2"]:not([data-size]) {
|
|
161
178
|
font-size: var(--heading-h2);
|
|
162
179
|
}
|
|
163
|
-
[data-slot="heading"][data-level="3"] {
|
|
180
|
+
[data-slot="heading"][data-level="3"]:not([data-size]) {
|
|
164
181
|
font-size: var(--heading-h3);
|
|
165
182
|
}
|
|
166
|
-
[data-slot="heading"][data-level="4"] {
|
|
183
|
+
[data-slot="heading"][data-level="4"]:not([data-size]) {
|
|
167
184
|
font-size: var(--heading-h4);
|
|
168
185
|
}
|
|
186
|
+
|
|
187
|
+
[data-slot="heading"][data-size="2xs"] {
|
|
188
|
+
font-size: var(--font-size-2xs);
|
|
189
|
+
}
|
|
190
|
+
[data-slot="heading"][data-size="xs"] {
|
|
191
|
+
font-size: var(--font-size-xs);
|
|
192
|
+
}
|
|
193
|
+
[data-slot="heading"][data-size="sm"] {
|
|
194
|
+
font-size: var(--font-size-sm);
|
|
195
|
+
}
|
|
196
|
+
[data-slot="heading"][data-size="md"] {
|
|
197
|
+
font-size: var(--font-size-base);
|
|
198
|
+
}
|
|
199
|
+
[data-slot="heading"][data-size="lg"] {
|
|
200
|
+
font-size: var(--font-size-lg);
|
|
201
|
+
}
|
|
202
|
+
[data-slot="heading"][data-size="xl"] {
|
|
203
|
+
font-size: var(--font-size-xl);
|
|
204
|
+
}
|
|
205
|
+
[data-slot="heading"][data-size="2xl"] {
|
|
206
|
+
font-size: var(--font-size-2xl);
|
|
207
|
+
}
|
|
208
|
+
[data-slot="heading"][data-size="3xl"] {
|
|
209
|
+
font-size: var(--font-size-3xl);
|
|
210
|
+
}
|
|
211
|
+
[data-slot="heading"][data-size="4xl"] {
|
|
212
|
+
font-size: var(--font-size-4xl);
|
|
213
|
+
}
|
|
214
|
+
[data-slot="heading"][data-size="5xl"] {
|
|
215
|
+
font-size: var(--font-size-5xl);
|
|
216
|
+
}
|
|
169
217
|
}
|
|
170
218
|
|
|
171
219
|
@layer components {
|
package/dist/tokens/base.css
CHANGED
|
@@ -44,3 +44,8 @@
|
|
|
44
44
|
@import "./components/conversations.css";
|
|
45
45
|
@import "./components/float-button.css";
|
|
46
46
|
@import "./components/draggable-panel.css";
|
|
47
|
+
@import "./components/masonry.css";
|
|
48
|
+
@import "./components/mega-menu.css";
|
|
49
|
+
@import "./components/marquee.css";
|
|
50
|
+
@import "./components/affix.css";
|
|
51
|
+
@import "./components/anchor.css";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
:root {
|
|
3
|
+
|
|
4
|
+
--anchor-ink-width: 2px;
|
|
5
|
+
|
|
6
|
+
--anchor-ink-color: initial;
|
|
7
|
+
|
|
8
|
+
--anchor-track-color: initial;
|
|
9
|
+
|
|
10
|
+
--anchor-item-padding-block: var(--space-1);
|
|
11
|
+
|
|
12
|
+
--anchor-item-padding-inline: var(--space-3);
|
|
13
|
+
|
|
14
|
+
--anchor-nested-padding-inline: var(--space-4);
|
|
15
|
+
|
|
16
|
+
--anchor-gap: var(--space-inline-lg);
|
|
17
|
+
}
|
|
@@ -377,11 +377,11 @@
|
|
|
377
377
|
|
|
378
378
|
--control-label-disabled-alpha: 0.7;
|
|
379
379
|
|
|
380
|
-
--control-surface-border-color:
|
|
381
|
-
--control-surface-background:
|
|
380
|
+
--control-surface-border-color: initial;
|
|
381
|
+
--control-surface-background: initial;
|
|
382
382
|
|
|
383
383
|
--control-filled-border-color: transparent;
|
|
384
|
-
--control-filled-background:
|
|
384
|
+
--control-filled-background: initial;
|
|
385
385
|
--control-filled-shadow: none;
|
|
386
386
|
|
|
387
387
|
--control-borderless-border-color: transparent;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
|
|
5
|
+
--mega-menu-bar-gap: var(--space-inline-xs);
|
|
6
|
+
--mega-menu-trigger-height: var(--control-height);
|
|
7
|
+
--mega-menu-trigger-padding-x: var(--space-3);
|
|
8
|
+
--mega-menu-trigger-gap: var(--space-inline-sm);
|
|
9
|
+
--mega-menu-trigger-radius: var(--radius-sm);
|
|
10
|
+
--mega-menu-trigger-font-size: var(--font-size-sm);
|
|
11
|
+
--mega-menu-trigger-foreground: hsl(var(--foreground));
|
|
12
|
+
--mega-menu-trigger-background: transparent;
|
|
13
|
+
|
|
14
|
+
--mega-menu-trigger-hover-background: initial;
|
|
15
|
+
--mega-menu-trigger-hover-foreground: initial;
|
|
16
|
+
--mega-menu-trigger-open-background: initial;
|
|
17
|
+
--mega-menu-trigger-open-foreground: initial;
|
|
18
|
+
--mega-menu-trigger-current-foreground: initial;
|
|
19
|
+
--mega-menu-trigger-disabled-alpha: 0.5;
|
|
20
|
+
--mega-menu-expand-icon-size: var(--control-icon-size-sm);
|
|
21
|
+
|
|
22
|
+
--mega-menu-panel-background: hsl(var(--popover));
|
|
23
|
+
--mega-menu-panel-foreground: hsl(var(--popover-foreground));
|
|
24
|
+
--mega-menu-panel-border-color: hsl(var(--border));
|
|
25
|
+
--mega-menu-panel-border-width: 1px;
|
|
26
|
+
--mega-menu-panel-radius: var(--radius-md);
|
|
27
|
+
--mega-menu-panel-padding: var(--space-6);
|
|
28
|
+
--mega-menu-panel-shadow: var(--shadow-md);
|
|
29
|
+
--mega-menu-panel-offset: 0px;
|
|
30
|
+
|
|
31
|
+
--mega-menu-panel-max-height: 70vh;
|
|
32
|
+
|
|
33
|
+
--mega-menu-panel-translate: var(--space-1);
|
|
34
|
+
|
|
35
|
+
--mega-menu-groups-gap: var(--space-6);
|
|
36
|
+
--mega-menu-group-gap: var(--space-inline-sm);
|
|
37
|
+
|
|
38
|
+
--mega-menu-group-min-width: 12rem;
|
|
39
|
+
--mega-menu-group-label-font-size: var(--font-size-xs);
|
|
40
|
+
--mega-menu-group-label-foreground: hsl(var(--muted-foreground));
|
|
41
|
+
--mega-menu-group-description-font-size: var(--font-size-xs);
|
|
42
|
+
--mega-menu-group-description-foreground: hsl(var(--muted-foreground));
|
|
43
|
+
--mega-menu-group-icon-size: var(--control-icon-size-sm);
|
|
44
|
+
|
|
45
|
+
--mega-menu-link-gap: var(--space-inline-sm);
|
|
46
|
+
--mega-menu-link-padding-x: var(--space-2);
|
|
47
|
+
--mega-menu-link-padding-y: var(--space-2);
|
|
48
|
+
--mega-menu-link-radius: var(--radius-sm);
|
|
49
|
+
--mega-menu-link-font-size: var(--font-size-sm);
|
|
50
|
+
--mega-menu-link-foreground: hsl(var(--foreground));
|
|
51
|
+
--mega-menu-link-hover-background: initial;
|
|
52
|
+
--mega-menu-link-hover-foreground: initial;
|
|
53
|
+
--mega-menu-link-current-foreground: initial;
|
|
54
|
+
--mega-menu-link-description-font-size: var(--font-size-xs);
|
|
55
|
+
--mega-menu-link-description-foreground: hsl(var(--muted-foreground));
|
|
56
|
+
--mega-menu-link-icon-size: var(--control-icon-size-sm);
|
|
57
|
+
|
|
58
|
+
--mega-menu-link-min-height: var(--touch-target-min);
|
|
59
|
+
|
|
60
|
+
--mega-menu-panel-footer-gap: var(--space-4);
|
|
61
|
+
--mega-menu-panel-footer-border-color: hsl(var(--border));
|
|
62
|
+
}
|
|
@@ -205,6 +205,9 @@
|
|
|
205
205
|
--space-10: calc(2.5rem * var(--scaling));
|
|
206
206
|
--space-12: calc(3rem * var(--scaling));
|
|
207
207
|
|
|
208
|
+
--space-20: calc(5rem * var(--scaling));
|
|
209
|
+
--space-24: calc(6rem * var(--scaling));
|
|
210
|
+
|
|
208
211
|
--icon-size-2xs: 0.625rem;
|
|
209
212
|
--icon-size-xs: 0.75rem;
|
|
210
213
|
--icon-size-sm: 0.875rem;
|
|
@@ -254,6 +257,10 @@
|
|
|
254
257
|
--activity-interval: var(--duration-loop);
|
|
255
258
|
|
|
256
259
|
--activity-stagger-step: 160ms;
|
|
260
|
+
|
|
261
|
+
--marquee-interval: 20s;
|
|
262
|
+
--marquee-interval-slow: calc(var(--marquee-interval) * 2);
|
|
263
|
+
--marquee-interval-fast: calc(var(--marquee-interval) / 2);
|
|
257
264
|
}
|
|
258
265
|
|
|
259
266
|
.ui-scale-fixed {
|
|
@@ -267,6 +274,8 @@
|
|
|
267
274
|
--space-8: 2rem;
|
|
268
275
|
--space-10: 2.5rem;
|
|
269
276
|
--space-12: 3rem;
|
|
277
|
+
--space-20: 5rem;
|
|
278
|
+
--space-24: 6rem;
|
|
270
279
|
--radius: 0.375rem;
|
|
271
280
|
--control-height: var(--control-height-default);
|
|
272
281
|
|
|
@@ -289,6 +298,8 @@
|
|
|
289
298
|
--space-page-x: var(--space-6);
|
|
290
299
|
--space-page-y: var(--space-6);
|
|
291
300
|
--space-section: var(--space-4);
|
|
301
|
+
--space-section-band: var(--space-20);
|
|
302
|
+
--space-section-hero: var(--space-24);
|
|
292
303
|
--space-stack-xs: var(--space-1);
|
|
293
304
|
--space-stack-sm: var(--space-2);
|
|
294
305
|
--space-stack-md: var(--space-4);
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
--space-page-x: var(--space-6);
|
|
6
6
|
--space-page-y: var(--space-6);
|
|
7
7
|
--space-section: var(--space-4);
|
|
8
|
+
|
|
9
|
+
--space-section-band: var(--space-20);
|
|
10
|
+
--space-section-hero: var(--space-24);
|
|
8
11
|
--space-stack-xs: var(--space-1);
|
|
9
12
|
--space-stack-sm: var(--space-2);
|
|
10
13
|
--space-stack-md: var(--space-4);
|
|
@@ -17,6 +20,8 @@
|
|
|
17
20
|
|
|
18
21
|
--overlay-z-index: 50;
|
|
19
22
|
|
|
23
|
+
--sticky-z-index: 20;
|
|
24
|
+
|
|
20
25
|
--master-detail-rail-compact: 18.75rem;
|
|
21
26
|
--master-detail-rail-narrow: 12rem;
|
|
22
27
|
--master-detail-rail-wide: 24rem;
|
|
@@ -64,6 +69,8 @@
|
|
|
64
69
|
--page-measure-narrow: 42rem;
|
|
65
70
|
--page-measure-medium: 48rem;
|
|
66
71
|
|
|
72
|
+
--page-measure-wide: 72rem;
|
|
73
|
+
|
|
67
74
|
--page-title-font-size: var(--heading-h1);
|
|
68
75
|
--page-title-font-size-compact: var(--heading-h2);
|
|
69
76
|
--page-subtitle-font-size: var(--font-size-base);
|
|
@@ -77,7 +77,8 @@ new UI need
|
|
|
77
77
|
| `Select` (incl. search/async) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | **Framework component** |
|
|
78
78
|
| `DataTable`, `Dialog`, `Calendar`, `Switch`, `Combobox` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | **Framework component** |
|
|
79
79
|
| `StatCard` (+ `icon`) | ✅ | ➖ | ✅ | ✅ | ✅ | ✅ | ✅ | **Framework component** (a reusable KPI tile with a stable API + tokens) |
|
|
80
|
-
| `ServiceLauncherCard` | ➖ | ❌ | ❌ | ✅ | ✅ | ➖ | ➖ | **Composition by the test — RETAINED as a recorded exception** (gh#814)
|
|
80
|
+
| `ServiceLauncherCard` | ➖ | ❌ | ❌ | ✅ | ✅ | ➖ | ➖ | **Composition by the test — RETAINED as a recorded exception** (gh#814) |
|
|
81
|
+
| `MegaMenu` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ➖ | **Framework component** — the instructive contrast with Hero, below |
|
|
81
82
|
| Marketing **Hero** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **Composition** — section, static, composable, brand-specific |
|
|
82
83
|
| **Navbar** / **Footer** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **Composition** — layout of `Text`/`Button`/`Flex` |
|
|
83
84
|
| **PricingTable** / feature grid | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **Composition** — `ResponsiveGrid` + `Card` |
|
|
@@ -86,6 +87,23 @@ new UI need
|
|
|
86
87
|
|
|
87
88
|
`✅ pass · ❌ fail · ➖ borderline`. **StatCard** is the instructive borderline: C2 is weak (it owns little behavior), but it is a universal KPI tile with a controlled API, fully tokenized, broadly reused — so it earns its place. A **Hero** fails six of seven; it is unambiguously a composition.
|
|
88
89
|
|
|
90
|
+
**MegaMenu is the instructive PASS, and it is in this table because it sits next to Navbar.** A
|
|
91
|
+
Navbar fails every criterion; a megamenu is the same bar with behaviour bolted through it, and that
|
|
92
|
+
one difference flips the verdict. **C2** is the whole case: a roving tabindex across the top-level
|
|
93
|
+
items, `aria-expanded`/`aria-controls` per trigger, hover intent (a diagonal pointer path toward the
|
|
94
|
+
panel must not close it), `Escape` closing and returning focus to its trigger, Tab-out and
|
|
95
|
+
outside-click closing, and close-on-route-change. None of that is layout. **C3** is the one people
|
|
96
|
+
get wrong: `DropdownMenu` looks like the answer and is the WRONG primitive, not an awkward one — it
|
|
97
|
+
is react-aria-components `Menu`, i.e. `role="menu"` / `role="menuitem"`, which announces a set of
|
|
98
|
+
site links as a desktop application menu and takes Tab out of the widget. The APG says so itself in
|
|
99
|
+
its Disclosure Navigation example. A recipe over `DropdownMenu` would therefore ship the classic
|
|
100
|
+
megamenu accessibility defect, which is exactly the case C3 is asking about. **C7 is the weak
|
|
101
|
+
one** — marked ➖ deliberately: this is a JP business-software library, and a marketing megamenu is
|
|
102
|
+
not in every consumer's build. It is kept because the same disclosure bar is what an admin console
|
|
103
|
+
with several product areas needs, and because the cost is one file with no new dependency (no
|
|
104
|
+
`@radix-ui/react-navigation-menu`, no animation runtime). Compare `StatCard`, whose borderline is
|
|
105
|
+
C2 rather than C7.
|
|
106
|
+
|
|
89
107
|
**ServiceLauncherCard is the ONE recorded exception, and it is recorded so that it stays one.** It shipped before the test was run against it, and when the test was run it came back with two hard FAILs: **C2** — no state, no keyboard handling, no focus management, its only ARIA three static attributes — and **C3** — its own imports are `Card` + `CardContent` + `Badge` + a Lucide glyph, so "could I build this right now from primitives?" is yes. By §2 that makes it a composition pattern. It is kept anyway because `src/components/layout/app-launcher.tsx` consumes it: it is an internal building block of a component that **does** pass, so the question was never "should it exist" but "should it be PUBLIC", and removing a public export is breaking. Keeping it public was the cheaper call and the ledger lives on gh#814 and at the top of `src/components/data-display/service-launcher-card.tsx`. **Consumers should compose `Card` + `Badge` for a service tile** — reach for `ServiceLauncherCard` only to match `AppLauncher`'s own tiles — and this row is not precedent for adding another static tile to `src/components/`.
|
|
90
108
|
|
|
91
109
|
---
|
package/docs/DESIGN-AUTHORITY.md
CHANGED
|
@@ -12,17 +12,17 @@ It changes no code by itself. It is the tie-breaker a reviewer points at.
|
|
|
12
12
|
|
|
13
13
|
## The layers, and who owns each
|
|
14
14
|
|
|
15
|
-
| Layer | Authority | Status in this repo
|
|
16
|
-
| ------------------------------------------------------------------ | ----------------------------------------------- |
|
|
17
|
-
| Interaction semantics, keyboard, ARIA | **WAI-ARIA APG** | already followed — 33 references in `src/`
|
|
18
|
-
| Behaviour primitives | **Radix** | already the implementation — 193 references
|
|
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` — a naming precedent, nothing is installed
|
|
15
|
+
| Layer | Authority | Status in this repo |
|
|
16
|
+
| ------------------------------------------------------------------ | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| Interaction semantics, keyboard, ARIA | **WAI-ARIA APG** | already followed — 33 references in `src/` |
|
|
18
|
+
| Behaviour primitives | **Radix** | already the implementation — 193 references |
|
|
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` — a naming precedent, nothing is installed |
|
|
21
21
|
| Colour foundation | **SmartHR**, brand roles aside | the NEUTRAL spine is SmartHR's — `--foreground` = TEXT_BLACK, `--border` = BORDER. `--primary` was SmartHR MAIN `#0071bd` until identity v2.3 took the brand roles back: it is GoDX violet `#7A00FF` today |
|
|
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, and a fifth holds it to the seed's HUE (gh#648) — see below
|
|
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
|
-
| **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
|
-
| **Spacing, density, type scale, information architecture** | **IBM Carbon** | **NEW — this decision**
|
|
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, and a fifth holds it to the seed's HUE (gh#648) — see below |
|
|
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
|
+
| **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
|
+
| **Spacing, density, type scale, information architecture** | **IBM Carbon** | **NEW — this decision** |
|
|
26
26
|
|
|
27
27
|
The first five were already true and merely unwritten. The last three are the choices being made
|
|
28
28
|
here. Carbon fills the one layer that had no outside answer at all: page rhythm, table density, form layout,
|
|
@@ -282,6 +282,87 @@ bottomEnd | none` (`TablePaginationPositionProp`, default `['bottomEnd']`), the
|
|
|
282
282
|
rows, so an expanded detail row shifts every stripe after it, and `ui-audit` blocks the
|
|
283
283
|
utilities it would need.
|
|
284
284
|
|
|
285
|
+
- **`Masonry.gap` is antd `gutter`, and its breakpoint steps are this library's (gh-masonry
|
|
286
|
+
port).** Three divergences on one component, each for a reason already written down elsewhere in
|
|
287
|
+
this file:
|
|
288
|
+
|
|
289
|
+
1. **`gutter` → `gap`.** antd's `gutter` takes a raw pixel number (or a per-breakpoint map of
|
|
290
|
+
them). This library already owns that axis under the name `gap` on `Flex`, `ResponsiveGrid`
|
|
291
|
+
and `AuthStack`, `check:prop-vocabulary` maps a field called `gap` to `GapProp`, and a token
|
|
292
|
+
step is what makes spacing follow `--scaling` (density) and a tenant theme. "This library's
|
|
293
|
+
controlled vocabulary wins on values" is the rule; here it wins on the name too, because the
|
|
294
|
+
name and the value type move together. antd's tuple `[Gap, Gap]` survives as
|
|
295
|
+
`[GapProp, GapProp]` = `[inline, block]`. **`gutter` is not silently absent**: it is declared
|
|
296
|
+
on the prop type as `never`, so a consumer arriving from antd's docs gets a compile error and
|
|
297
|
+
a `@deprecated` hint naming `gap`, plus a development-time `console.warn`.
|
|
298
|
+
2. **`columns` steps are `base sm md lg xl`, not antd's `xs sm md lg xl xxl`.** antd's `xs` IS
|
|
299
|
+
this library's `base` (the mobile-first floor), and a second spelling of one axis is what
|
|
300
|
+
`check:prop-vocabulary` exists to prevent; `xxl` has no step here at all. `Flex direction`
|
|
301
|
+
is the precedent shape and the media queries are literally the `--flex-direction-*` cascade's
|
|
302
|
+
(sm 40rem · md 48rem · lg 64rem · xl 80rem). Both antd spellings FAIL LOUDLY — TypeScript
|
|
303
|
+
rejects them as excess properties and the component names them in a development warning —
|
|
304
|
+
because a silently-ignored `xs` is the worst outcome of the three.
|
|
305
|
+
3. **`MasonryItem.height` is HONOURED, where antd declares it and never reads it.** Verified in
|
|
306
|
+
antd `master`: `Masonry.tsx` builds every `ItemHeightData` from `getBoundingClientRect()`
|
|
307
|
+
alone, and all six demos carry their heights in `data`. Porting the field as inert would ship
|
|
308
|
+
a documented prop that does nothing. Here a finite `height` sizes the tile and replaces its
|
|
309
|
+
measurement, which is also what lets a first paint and an SSR render land in the right place.
|
|
310
|
+
|
|
311
|
+
Not ported, each under a rule that already exists: `classNames` / `styles` (a knob only a fork
|
|
312
|
+
could reach — `src/tokens/components/masonry.css` is the answer), `prefixCls` / `rootClassName`
|
|
313
|
+
(no `prefixCls` layer here), and rc-motion's tile-REMOVAL animation (the arrival fade and the
|
|
314
|
+
re-flow slide are ported in CSS and both snap under `prefers-reduced-motion`). `fresh` keeps
|
|
315
|
+
antd's name and antd's `false` default even though `docs/roadmap/list-masonry.md` (2026-09-10)
|
|
316
|
+
proposed renaming it `observeItems` and defaulting it on — that proposal predates the
|
|
317
|
+
2026-09-12 restatement above, and "the antd name says nothing" is exactly the reasoning the
|
|
318
|
+
restatement rejects. The same roadmap's invented `sequential` prop is not ported for the same
|
|
319
|
+
reason: antd has no such knob, and improvements come after parity, not instead of it.
|
|
320
|
+
|
|
321
|
+
- **`Affix` and `Anchor` take the LOGICAL axis where antd takes the physical one (gh#827/gh#828).**
|
|
322
|
+
Ported from `ant-design@master`, read out of `components/affix/{index.tsx,utils.ts}` and
|
|
323
|
+
`components/anchor/{Anchor,AnchorLink}.tsx` on 2026-09-21, not out of the docs tables. Every
|
|
324
|
+
antd prop is present. Four renames, and nothing else:
|
|
325
|
+
|
|
326
|
+
1. **`offsetTop` → `offsetBlockStart`, `offsetBottom` → `offsetBlockEnd`** (both components;
|
|
327
|
+
`Anchor.targetOffset` → `targetOffsetBlockStart` with it). `check:rtl` exists to keep
|
|
328
|
+
`inset-block-start` out of `top`'s hands in every stylesheet here, and a prop that names a
|
|
329
|
+
physical edge re-opens that door at the API. It is also load-bearing rather than cosmetic:
|
|
330
|
+
the offset is a CSS custom property (`--affix-inset-block-start`), read once by the sentinel
|
|
331
|
+
that detects the crossing and once by the pinned bar that paints it, so the name has to be
|
|
332
|
+
the one CSS uses. All three antd spellings are declared `never` — a compile error carrying an
|
|
333
|
+
`@deprecated` hint that names the replacement — plus a development `console.warn`, plus the
|
|
334
|
+
MCP catalog entry. The `Masonry gutter → gap` precedent, applied to a second component.
|
|
335
|
+
2. **`Anchor.onChange` → `onValueChange`,** beside new `value` / `defaultValue`. The active
|
|
336
|
+
`href` is a controlled value and this library has one spelling for that. antd has no
|
|
337
|
+
controlled form of it at all (`getCurrentAnchor` is a transform of the computed answer, not a
|
|
338
|
+
value), so this is an ADDITION with a rename attached rather than a substitution, and
|
|
339
|
+
`getCurrentAnchor` is ported unchanged beside it — a controlled `value` simply outranks it.
|
|
340
|
+
antd's own note is ported too: `onValueChange` reports the link the SCROLL POSITION resolved,
|
|
341
|
+
not the one `getCurrentAnchor` substituted.
|
|
342
|
+
|
|
343
|
+
**`Affix.onChange` is NOT renamed**, and the distinction is the point: there is no pinned VALUE
|
|
344
|
+
to control, only an observation of a derived boolean, so no triad applies. `Attachments.onChange`
|
|
345
|
+
and `ActionsFeedback.onChange` already carry antd's name with a non-DOM payload for the same
|
|
346
|
+
reason.
|
|
347
|
+
|
|
348
|
+
**Not ported, each under a rule that already exists:** `classNames` / `styles` on `Anchor` (a
|
|
349
|
+
knob only a fork could reach — `src/tokens/components/anchor.css` is the answer),
|
|
350
|
+
`prefixCls` / `rootClassName`, and antd's deprecated `Anchor children` / `Anchor.Link` JSX form
|
|
351
|
+
(antd itself warns on it and says to use `items`).
|
|
352
|
+
|
|
353
|
+
**One deliberate behavioural difference, in `Anchor`.** antd resolves from scroll position on
|
|
354
|
+
mount unconditionally, which overwrites a landing hash on any page whose hashed section happens
|
|
355
|
+
to be above the fold. Here the hash is read in the state INITIALISER and the mount resolution is
|
|
356
|
+
skipped when it matched, so `/page#section` is correct on the first render with no scroll event
|
|
357
|
+
ever firing — which is gh#828's acceptance criterion, and the one place antd's behaviour is
|
|
358
|
+
worse rather than merely differently named.
|
|
359
|
+
|
|
360
|
+
**Two things antd does not have at all**, both required by the contract rather than invented:
|
|
361
|
+
`Anchor.label` (antd ships an unnamed `<div>`; a `<nav>` landmark on a page that already has a
|
|
362
|
+
breadcrumb and a rail must be named, so `label` defaults through `t()`), and `Affix`'s
|
|
363
|
+
`scroll-padding-block-start` on the scroll box while pinned (WCAG 2.4.11 — without it the pinned
|
|
364
|
+
bar covers whatever the browser scrolls a focused element to).
|
|
365
|
+
|
|
285
366
|
- **`Command.split` is antd `List.split`, with this library's default.** Same name, same meaning:
|
|
286
367
|
a divider between rows and none after the last (gh#699). antd's `List` defaults it to `true`;
|
|
287
368
|
`Command` defaults it to `false`, because its resting home is a command palette, where inset
|
|
@@ -501,11 +582,11 @@ snapped to the seed's hue (1.008:1 / 1.010:1 from the kit value, i.e. the same c
|
|
|
501
582
|
the kit's `action.primary.hover` and then reflects the pressed step, because the dark seed sits at
|
|
502
583
|
86.9% L and the conventional step runs out of LIGHTNESS rather than out of contrast:
|
|
503
584
|
|
|
504
|
-
| token | conventional step
|
|
505
|
-
| ------------------------ |
|
|
506
|
-
| light `--primary-hover` | kit #6400D4
|
|
507
|
-
| light `--primary-active` | kit #5200B0
|
|
508
|
-
| dark `--primary-hover` | kit #E8DAFF
|
|
585
|
+
| token | conventional step | shipped |
|
|
586
|
+
| ------------------------ | ---------------------------- | ------------------------------- |
|
|
587
|
+
| light `--primary-hover` | kit #6400D4 | #6500d4 · 8.23:1 |
|
|
588
|
+
| light `--primary-active` | kit #5200B0 | #5400b0 · 10.31:1 |
|
|
589
|
+
| dark `--primary-hover` | kit #E8DAFF | #ecdaff · 13.51:1 |
|
|
509
590
|
| dark `--primary-active` | #fbf7ff · 1.056:1 from white | #cd9fff · 8.41:1 (sign flipped) |
|
|
510
591
|
|
|
511
592
|
**The ratio is blind to hue, and that cost a release (gh#648).** Identity v2.3 moved the seed 63
|
|
@@ -604,10 +685,10 @@ the **field** indicator on every control — one hairline (1px) in the focus hue
|
|
|
604
685
|
`--control-outline` halo — rather than the heavy 3px outline form. Measured, in Chromium, on
|
|
605
686
|
`ql.test` after the transition settles:
|
|
606
687
|
|
|
607
|
-
| control | switch off | switch on
|
|
608
|
-
| -------------------------- | ---------------------------------------------------- |
|
|
688
|
+
| control | switch off | switch on |
|
|
689
|
+
| -------------------------- | ---------------------------------------------------- | --------------------------------------------------------------- |
|
|
609
690
|
| Input / Select trigger | border `1px rgb(144,135,127)`, resting shadow intact | border `1px` of `--ring` + `--control-outline` halo `0 0 0 2px` |
|
|
610
|
-
| Button (primary) | outline `0px`, resting shadow intact | `outline: 1px solid` `--ring` @ `0px` + same halo
|
|
691
|
+
| Button (primary) | outline `0px`, resting shadow intact | `outline: 1px solid` `--ring` @ `0px` + same halo |
|
|
611
692
|
| Sidebar nav row / list row | outline `0px` | `outline: 1px solid` `--ring` @ **`-1px`** (inset into the row) |
|
|
612
693
|
|
|
613
694
|
The GEOMETRY above is the Chromium measurement; the COLOUR is named by token rather than pinned as
|
|
@@ -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: **
|
|
7
|
-
- With ≥1 frame: **
|
|
6
|
+
- Public components: **170**
|
|
7
|
+
- With ≥1 frame: **149** · zero-frame: **21**
|
|
8
8
|
- Fully covered (every contract axis declared): **0**
|
|
9
9
|
|
|
10
10
|
## UNTESTED — no `/frame/**` route
|
|
@@ -198,8 +198,13 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
198
198
|
| ChatComposer | ✓ | · | · | · | · | · | · | · | · | · |
|
|
199
199
|
| ChatSuggestion | ✓ | N/A | N/A | · | · | · | · | · | · | · |
|
|
200
200
|
| Conversations | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
201
|
+
| MegaMenu | ✓ | · | N/A | · | · | · | · | · | · | · |
|
|
201
202
|
| Welcome | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
202
203
|
| Actions | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
203
204
|
| ThoughtChain | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
204
205
|
| Attachments | ✓ | N/A | · | N/A | · | · | · | · | · | · |
|
|
206
|
+
| Marquee | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
207
|
+
| Masonry | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
208
|
+
| Affix | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
209
|
+
| Anchor | ✓ | N/A | N/A | · | · | · | · | · | · | · |
|
|
205
210
|
|