@godxjp/ui 19.3.1 → 19.4.1
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/badge.d.ts +9 -1
- package/dist/components/data-display/badge.js +3 -2
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/popover.d.ts +13 -1
- package/dist/components/data-display/popover.js +3 -1
- package/dist/components/data-display/table.d.ts +19 -2
- package/dist/components/data-display/table.js +4 -1
- package/dist/components/data-display/timeline-grid.d.ts +18 -0
- package/dist/components/data-display/timeline-grid.js +222 -0
- package/dist/components/data-entry/cascader.js +4 -6
- package/dist/components/data-entry/checkbox.js +1 -1
- package/dist/components/data-entry/search-select.js +5 -7
- package/dist/components/data-entry/select.js +32 -28
- package/dist/components/data-entry/tree-select.js +4 -6
- package/dist/components/general/inert-background.d.ts +5 -0
- package/dist/components/general/inert-background.js +48 -0
- package/dist/components/layout/auth-shell.d.ts +4 -2
- package/dist/components/layout/auth-shell.js +7 -1
- package/dist/components/layout/centered-shell.d.ts +2 -2
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +2 -1
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/components/layout/mobile-shell.d.ts +21 -0
- package/dist/components/layout/mobile-shell.js +43 -0
- package/dist/components/layout/sidebar-link.d.ts +1 -1
- package/dist/components/navigation/context-menu.js +13 -9
- package/dist/components/navigation/dropdown-menu.js +17 -13
- package/dist/inertia/index.d.ts +1 -1
- package/dist/lib/variants.d.ts +3 -3
- package/dist/lib/variants.js +1 -0
- package/dist/props/components/data-display.prop.d.ts +65 -0
- package/dist/props/components/data-entry.prop.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +93 -6
- package/dist/props/registry.d.ts +109 -2
- package/dist/props/registry.js +143 -0
- package/dist/props/vocabulary/data.prop.d.ts +6 -0
- package/dist/props/vocabulary/index.d.ts +3 -3
- package/dist/props/vocabulary/layout.prop.d.ts +17 -2
- package/dist/props/vocabulary/shared.prop.d.ts +7 -0
- package/dist/styles/control.css +18 -1
- package/dist/styles/data-display-layout.css +167 -0
- package/dist/styles/layout.css +7 -0
- package/dist/styles/shell-layout.css +148 -0
- package/dist/styles/table-layout.css +23 -4
- package/dist/tokens/components/control.css +1 -0
- package/dist/tokens/components/data-display.css +20 -0
- package/dist/tokens/components/shell.css +22 -0
- package/dist/tokens/components/table.css +2 -0
- package/docs/FRAME-A11Y-CI.md +99 -17
- package/docs/FRAME-COVERAGE-REPORT.md +4 -2
- package/docs/SPACING.md +19 -6
- package/docs/charts/compact-bar-trend.tsx +5 -6
- package/docs/data-display/avatar.tsx +7 -9
- package/docs/data-display/badge.tsx +1 -1
- package/docs/data-display/card/index.tsx +6 -4
- package/docs/data-display/data-table/examples/approval-queue.tsx +1 -1
- package/docs/data-display/data-table/index.tsx +1 -1
- package/docs/data-display/permission-matrix.tsx +2 -2
- package/docs/data-display/popover.tsx +4 -1
- package/docs/data-display/scroll-area.tsx +1 -1
- package/docs/data-display/table.tsx +1 -1
- package/docs/data-display/timeline-grid.tsx +119 -0
- package/docs/data-entry/branch-scope-picker.tsx +1 -1
- package/docs/data-entry/date-picker.tsx +2 -1
- package/docs/data-entry/form-field/index.tsx +2 -2
- package/docs/data-entry/input-otp.tsx +1 -1
- package/docs/data-entry/select-matrix.tsx +2 -1
- package/docs/data-entry/select.tsx +3 -1
- package/docs/data-entry/textarea.tsx +1 -1
- package/docs/data-entry/toggle-count.tsx +1 -1
- package/docs/feedback/alert.tsx +1 -1
- package/docs/feedback/banner.tsx +1 -1
- package/docs/feedback/dialog.tsx +2 -1
- package/docs/feedback/sheet.tsx +2 -1
- package/docs/foundation/email-tokens.tsx +1 -1
- package/docs/general/activity.tsx +1 -1
- package/docs/layout/app-shell.tsx +4 -4
- package/docs/layout/auth-account-summary.tsx +1 -1
- package/docs/layout/auth-recovery/examples/mobile-390.tsx +1 -1
- package/docs/layout/auth-recovery/examples/password-recovery.tsx +0 -2
- package/docs/layout/auth-shell-context.tsx +1 -1
- package/docs/layout/auth-shell-device.tsx +2 -2
- package/docs/layout/auth-shell-registration.tsx +1 -1
- package/docs/layout/auth-shell.tsx +1 -1
- package/docs/layout/master-detail.tsx +2 -2
- package/docs/layout/mobile-shell.tsx +101 -0
- package/docs/layout/page-container.tsx +6 -6
- package/docs/layout/responsive-grid.tsx +5 -5
- package/docs/layout/separator.tsx +2 -2
- package/docs/layout/service-role-panel.tsx +1 -1
- package/docs/layout/sidebar.tsx +9 -9
- package/docs/layout/split-pane.tsx +5 -6
- package/docs/layout/topbar.tsx +2 -8
- package/docs/navigation/context-menu.tsx +6 -1
- package/docs/navigation/dropdown-menu.tsx +2 -1
- package/docs/navigation/filter-bar.tsx +2 -2
- package/docs/navigation/pagination.tsx +2 -2
- package/docs/navigation/steps.tsx +1 -1
- package/docs/navigation/tabs.tsx +3 -3
- package/docs/showcase/acme-portal.tsx +11 -12
- package/docs/showcase/acme-website.tsx +7 -7
- package/docs/showcase/case1-warehouse-dashboard.tsx +11 -12
- package/docs/showcase/case2-employee-me.tsx +10 -16
- package/docs/showcase/case4-login.tsx +144 -156
- package/docs/showcase/case5-shift-calendar.tsx +181 -280
- package/docs/showcase/case6-agency-handy.tsx +446 -443
- package/docs/showcase/futurelastic-web.tsx +9 -8
- package/docs/showcase/org-switcher.tsx +18 -11
- package/docs/showcase/permission-matrix.tsx +13 -13
- package/docs/showcase/public-landing.tsx +1 -1
- package/docs/showcase/settings-account-sections.tsx +4 -4
- package/docs/showcase/settings-security-mfa.tsx +3 -3
- package/docs/showcase/table-approval-queue.tsx +1 -1
- package/docs/showcase/table-bulk-actions.tsx +49 -52
- package/docs/showcase/table-conditional-format.tsx +1 -1
- package/docs/showcase/table-crud-list.tsx +1 -1
- package/docs/showcase/table-expandable-rows.tsx +101 -98
- package/docs/showcase/table-filter-chips.tsx +78 -66
- package/docs/showcase/table-footer-totals.tsx +23 -19
- package/docs/showcase/table-grouped-subtotals.tsx +7 -4
- package/docs/showcase/table-master-detail.tsx +13 -15
- package/docs/showcase/table-states.tsx +34 -29
- package/docs/showcase/table-sticky-columns.tsx +3 -2
- package/docs/showcase/table-tree-rows.tsx +22 -15
- package/docs/showcase/table-view-tabs.tsx +12 -14
- package/package.json +7 -6
|
@@ -112,9 +112,19 @@
|
|
|
112
112
|
.ui-auth-shell-bar {
|
|
113
113
|
display: flex;
|
|
114
114
|
align-items: center;
|
|
115
|
+
|
|
116
|
+
flex-wrap: wrap;
|
|
117
|
+
gap: var(--auth-shell-bar-gap);
|
|
115
118
|
padding: var(--auth-shell-bar-padding);
|
|
116
119
|
}
|
|
117
120
|
|
|
121
|
+
.ui-auth-shell-bar-actions {
|
|
122
|
+
display: flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
gap: var(--auth-shell-bar-gap);
|
|
125
|
+
margin-inline-start: auto;
|
|
126
|
+
}
|
|
127
|
+
|
|
118
128
|
.ui-auth-shell-main {
|
|
119
129
|
display: flex;
|
|
120
130
|
flex: 1 1 auto;
|
|
@@ -142,6 +152,15 @@
|
|
|
142
152
|
--auth-shell-main-padding: var(--auth-shell-canonical-main-padding);
|
|
143
153
|
}
|
|
144
154
|
|
|
155
|
+
.ui-auth-shell[data-measure="wide"]:not([data-preset]) {
|
|
156
|
+
--auth-shell-card-max-width: var(--auth-shell-wide-card-max-width);
|
|
157
|
+
--auth-shell-main-align: flex-start;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.ui-auth-shell[data-measure="wide"]:not([data-preset]) .ui-auth-shell-card {
|
|
161
|
+
margin-block: auto;
|
|
162
|
+
}
|
|
163
|
+
|
|
145
164
|
.ui-auth-shell[data-preset] .ui-auth-shell-card {
|
|
146
165
|
display: flex;
|
|
147
166
|
flex-direction: column;
|
|
@@ -1417,6 +1436,135 @@
|
|
|
1417
1436
|
}
|
|
1418
1437
|
}
|
|
1419
1438
|
|
|
1439
|
+
@layer components {
|
|
1440
|
+
.ui-mobile-shell {
|
|
1441
|
+
--control-height: var(--mobile-shell-control-height);
|
|
1442
|
+
|
|
1443
|
+
--mobile-shell-padding-inline: calc(
|
|
1444
|
+
var(--mobile-shell-inset-inline) + var(--mobile-shell-safe-inset-inline)
|
|
1445
|
+
);
|
|
1446
|
+
display: flex;
|
|
1447
|
+
|
|
1448
|
+
block-size: var(--mobile-shell-block-size);
|
|
1449
|
+
flex-direction: column;
|
|
1450
|
+
overflow: hidden;
|
|
1451
|
+
background: hsl(var(--background));
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
.ui-mobile-shell[data-height="fill"] {
|
|
1455
|
+
--mobile-shell-block-size: 100%;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
.ui-mobile-shell-chrome {
|
|
1459
|
+
display: flex;
|
|
1460
|
+
min-inline-size: 0;
|
|
1461
|
+
flex: 0 0 auto;
|
|
1462
|
+
flex-direction: column;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
.ui-mobile-shell-status {
|
|
1466
|
+
display: flex;
|
|
1467
|
+
min-block-size: calc(
|
|
1468
|
+
var(--mobile-shell-status-bar-height) + var(--mobile-shell-safe-inset-block-start)
|
|
1469
|
+
);
|
|
1470
|
+
flex: 0 0 auto;
|
|
1471
|
+
align-items: center;
|
|
1472
|
+
justify-content: space-between;
|
|
1473
|
+
gap: var(--mobile-shell-region-gap);
|
|
1474
|
+
padding-block-start: var(--mobile-shell-safe-inset-block-start);
|
|
1475
|
+
padding-inline: var(--mobile-shell-padding-inline);
|
|
1476
|
+
background: hsl(var(--card));
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
.ui-mobile-shell-header {
|
|
1480
|
+
display: flex;
|
|
1481
|
+
min-block-size: var(--mobile-shell-header-bar-height);
|
|
1482
|
+
min-inline-size: 0;
|
|
1483
|
+
flex: 0 0 auto;
|
|
1484
|
+
|
|
1485
|
+
overflow: clip;
|
|
1486
|
+
overflow-clip-margin: var(--focus-ring-clip-margin);
|
|
1487
|
+
align-items: center;
|
|
1488
|
+
gap: var(--mobile-shell-region-gap);
|
|
1489
|
+
padding-inline: var(--mobile-shell-padding-inline);
|
|
1490
|
+
border-block-end: 1px solid hsl(var(--border));
|
|
1491
|
+
background: hsl(var(--card));
|
|
1492
|
+
background-image: var(--topbar-gradient);
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
.ui-mobile-shell-header:first-child {
|
|
1496
|
+
min-block-size: calc(
|
|
1497
|
+
var(--mobile-shell-header-bar-height) + var(--mobile-shell-safe-inset-block-start)
|
|
1498
|
+
);
|
|
1499
|
+
padding-block-start: var(--mobile-shell-safe-inset-block-start);
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
.ui-mobile-shell-main {
|
|
1503
|
+
display: flex;
|
|
1504
|
+
min-block-size: 0;
|
|
1505
|
+
min-inline-size: 0;
|
|
1506
|
+
|
|
1507
|
+
flex: 1 1 auto;
|
|
1508
|
+
flex-direction: column;
|
|
1509
|
+
overflow-y: auto;
|
|
1510
|
+
|
|
1511
|
+
overscroll-behavior-block: contain;
|
|
1512
|
+
|
|
1513
|
+
contain: paint;
|
|
1514
|
+
padding-block: var(--mobile-shell-main-padding-block);
|
|
1515
|
+
padding-inline: var(--mobile-shell-padding-inline);
|
|
1516
|
+
background-image: var(--gradient-glow);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
.ui-mobile-shell-main:focus-visible {
|
|
1520
|
+
outline: none;
|
|
1521
|
+
box-shadow: inset 0 0 0 var(--region-focus-ring-width)
|
|
1522
|
+
var(--region-focus-ring-color, hsl(var(--focus-ring-color, var(--ring))));
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
.ui-mobile-shell-actions {
|
|
1526
|
+
display: flex;
|
|
1527
|
+
min-inline-size: 0;
|
|
1528
|
+
flex: 0 0 auto;
|
|
1529
|
+
align-items: center;
|
|
1530
|
+
gap: var(--mobile-shell-region-gap);
|
|
1531
|
+
padding-block: var(--mobile-shell-actions-padding-block);
|
|
1532
|
+
padding-inline: var(--mobile-shell-padding-inline);
|
|
1533
|
+
border-block-start: 1px solid hsl(var(--border));
|
|
1534
|
+
background: hsl(var(--card));
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
.ui-mobile-shell-tabbar {
|
|
1538
|
+
display: flex;
|
|
1539
|
+
min-block-size: calc(
|
|
1540
|
+
var(--mobile-shell-tab-bar-height) + var(--mobile-shell-safe-inset-block-end)
|
|
1541
|
+
);
|
|
1542
|
+
min-inline-size: 0;
|
|
1543
|
+
flex: 0 0 auto;
|
|
1544
|
+
padding-block-end: var(--mobile-shell-safe-inset-block-end);
|
|
1545
|
+
padding-inline: var(--mobile-shell-safe-inset-inline);
|
|
1546
|
+
border-block-start: 1px solid hsl(var(--border));
|
|
1547
|
+
background: hsl(var(--card));
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
.ui-mobile-shell-tabbar > * {
|
|
1551
|
+
min-inline-size: 0;
|
|
1552
|
+
flex: 1 1 0;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
.ui-mobile-shell-actions:last-child {
|
|
1556
|
+
padding-block-end: calc(
|
|
1557
|
+
var(--mobile-shell-actions-padding-block) + var(--mobile-shell-safe-inset-block-end)
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
.ui-mobile-shell-main:last-child {
|
|
1562
|
+
padding-block-end: calc(
|
|
1563
|
+
var(--mobile-shell-main-padding-block) + var(--mobile-shell-safe-inset-block-end)
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1420
1568
|
@layer components {
|
|
1421
1569
|
|
|
1422
1570
|
.ui-centered-shell[data-preset="public-landing"] {
|
|
@@ -46,6 +46,17 @@
|
|
|
46
46
|
padding-inline-end: 0;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
[data-slot="table-cell"][data-indent] {
|
|
50
|
+
padding-inline-start: calc(
|
|
51
|
+
var(--table-cell-space-x) + var(--table-cell-indent-level, 0) *
|
|
52
|
+
var(--table-cell-indent-space-step)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
[data-slot="table-cell"][data-flush] {
|
|
57
|
+
padding: 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
49
60
|
.ui-data-table-toolbar {
|
|
50
61
|
display: flex;
|
|
51
62
|
flex-wrap: wrap;
|
|
@@ -520,7 +531,9 @@
|
|
|
520
531
|
|
|
521
532
|
[data-collapse-below="sm"] .ui-table-row {
|
|
522
533
|
display: block;
|
|
523
|
-
|
|
534
|
+
|
|
535
|
+
height: auto;
|
|
536
|
+
border: var(--stroke-hairline) solid hsl(var(--border));
|
|
524
537
|
border-radius: var(--radius-md);
|
|
525
538
|
padding: var(--table-stacked-collection-card-padding-y)
|
|
526
539
|
var(--table-stacked-collection-card-padding-x);
|
|
@@ -562,7 +575,9 @@
|
|
|
562
575
|
|
|
563
576
|
[data-collapse-below="md"] .ui-table-row {
|
|
564
577
|
display: block;
|
|
565
|
-
|
|
578
|
+
|
|
579
|
+
height: auto;
|
|
580
|
+
border: var(--stroke-hairline) solid hsl(var(--border));
|
|
566
581
|
border-radius: var(--radius-md);
|
|
567
582
|
padding: var(--table-stacked-collection-card-padding-y)
|
|
568
583
|
var(--table-stacked-collection-card-padding-x);
|
|
@@ -604,7 +619,9 @@
|
|
|
604
619
|
|
|
605
620
|
[data-collapse-below="lg"] .ui-table-row {
|
|
606
621
|
display: block;
|
|
607
|
-
|
|
622
|
+
|
|
623
|
+
height: auto;
|
|
624
|
+
border: var(--stroke-hairline) solid hsl(var(--border));
|
|
608
625
|
border-radius: var(--radius-md);
|
|
609
626
|
padding: var(--table-stacked-collection-card-padding-y)
|
|
610
627
|
var(--table-stacked-collection-card-padding-x);
|
|
@@ -646,7 +663,9 @@
|
|
|
646
663
|
|
|
647
664
|
[data-collapse-below="xl"] .ui-table-row {
|
|
648
665
|
display: block;
|
|
649
|
-
|
|
666
|
+
|
|
667
|
+
height: auto;
|
|
668
|
+
border: var(--stroke-hairline) solid hsl(var(--border));
|
|
650
669
|
border-radius: var(--radius-md);
|
|
651
670
|
padding: var(--table-stacked-collection-card-padding-y)
|
|
652
671
|
var(--table-stacked-collection-card-padding-x);
|
|
@@ -83,6 +83,26 @@
|
|
|
83
83
|
--scroll-area-bar-padding: 1px;
|
|
84
84
|
--scroll-area-thumb-radius: var(--radius-pill);
|
|
85
85
|
|
|
86
|
+
--timeline-grid-hour-height: 2.5rem;
|
|
87
|
+
--timeline-grid-axis-width: 3.25rem;
|
|
88
|
+
--timeline-grid-column-min-width: 6rem;
|
|
89
|
+
--timeline-grid-event-min-height: 1.5rem;
|
|
90
|
+
--timeline-grid-axis-font-size: var(--font-size-2xs);
|
|
91
|
+
--timeline-grid-head-font-size: var(--font-size-xs);
|
|
92
|
+
--timeline-grid-event-font-size: var(--font-size-2xs);
|
|
93
|
+
--timeline-grid-event-gap: var(--space-1);
|
|
94
|
+
--timeline-grid-event-space-inset: var(--space-1);
|
|
95
|
+
--timeline-grid-event-radius: var(--radius-sm);
|
|
96
|
+
--timeline-grid-event-border-width: var(--stroke-md);
|
|
97
|
+
--timeline-grid-now-width: var(--stroke-sm);
|
|
98
|
+
|
|
99
|
+
--timeline-grid-line-color: initial;
|
|
100
|
+
--timeline-grid-event-color: initial;
|
|
101
|
+
|
|
102
|
+
--timeline-grid-event-muted-color: hsl(var(--foreground));
|
|
103
|
+
--timeline-grid-now-color: initial;
|
|
104
|
+
--timeline-grid-current-tint: initial;
|
|
105
|
+
|
|
86
106
|
--permission-matrix-label-width: 16rem;
|
|
87
107
|
--permission-matrix-role-space-gap: var(--space-1);
|
|
88
108
|
--permission-matrix-name-space-gap: 0.375rem;
|
|
@@ -107,6 +107,10 @@
|
|
|
107
107
|
--auth-shell-main-padding: var(--space-6);
|
|
108
108
|
--auth-shell-footer-padding: var(--space-3) var(--space-6) var(--space-4);
|
|
109
109
|
|
|
110
|
+
--auth-shell-bar-gap: var(--space-inline-sm);
|
|
111
|
+
|
|
112
|
+
--auth-shell-wide-card-max-width: 64rem;
|
|
113
|
+
|
|
110
114
|
--auth-shell-canonical-control-height: var(--band-height-lg);
|
|
111
115
|
--auth-shell-canonical-card-max-width: 22.5rem;
|
|
112
116
|
--auth-shell-canonical-heading-size: var(--font-size-base);
|
|
@@ -228,3 +232,21 @@
|
|
|
228
232
|
--app-shell-bar-height: var(--band-height-3xl);
|
|
229
233
|
}
|
|
230
234
|
}
|
|
235
|
+
|
|
236
|
+
:root {
|
|
237
|
+
--mobile-shell-block-size: 100dvh;
|
|
238
|
+
--mobile-shell-safe-inset-block-start: env(safe-area-inset-top);
|
|
239
|
+
--mobile-shell-safe-inset-block-end: env(safe-area-inset-bottom);
|
|
240
|
+
--mobile-shell-safe-inset-inline: max(env(safe-area-inset-left), env(safe-area-inset-right));
|
|
241
|
+
|
|
242
|
+
--mobile-shell-inset-inline: var(--space-4);
|
|
243
|
+
|
|
244
|
+
--mobile-shell-control-height: var(--control-height-comfortable);
|
|
245
|
+
--mobile-shell-region-gap: var(--space-2);
|
|
246
|
+
--mobile-shell-status-bar-height: var(--band-height-lg);
|
|
247
|
+
--mobile-shell-header-bar-height: var(--band-height-3xl);
|
|
248
|
+
|
|
249
|
+
--mobile-shell-tab-bar-height: calc(var(--band-height-3xl) + var(--space-2));
|
|
250
|
+
--mobile-shell-main-padding-block: var(--space-4);
|
|
251
|
+
--mobile-shell-actions-padding-block: var(--space-3);
|
|
252
|
+
}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
--table-cell-padding-y: var(--space-2);
|
|
9
9
|
--table-cell-space-x: var(--control-padding-x);
|
|
10
10
|
|
|
11
|
+
--table-cell-indent-space-step: var(--space-4);
|
|
12
|
+
|
|
11
13
|
--table-border-color: initial;
|
|
12
14
|
--table-pagination-padding-y: initial;
|
|
13
15
|
--table-pagination-padding-x: initial;
|
package/docs/FRAME-A11Y-CI.md
CHANGED
|
@@ -20,11 +20,56 @@ A control the **user cannot bring into the frame** — not merely one whose box
|
|
|
20
20
|
|
|
21
21
|
- `check:contrast` (`scripts/check-contrast.mjs`) — a hand-picked set of ~6 pages checked for WCAG-AA text contrast. It never saw the other ~100 component frames. - `audit:examples` (`pnpm audit docs`) — a static source-regex linter. It can catch a hard-coded hex value but cannot see what actually renders: computed contrast, DOM landmark structure, focus order, or anything a Radix portal produces at runtime.
|
|
22
22
|
|
|
23
|
-
## Chrome vs component:
|
|
23
|
+
## Chrome vs component vs overlay: three independently-tracked scopes
|
|
24
24
|
|
|
25
|
-
`check:frame-axe` runs axe **twice** per frame/viewport:
|
|
25
|
+
`check:frame-axe` runs axe **twice** per frame/viewport, and a **third** time on the frames that declare an open step:
|
|
26
26
|
|
|
27
27
|
- **Preview chrome** = the zoom / dimension **toolbar** (`.demo-block-toolbar`, `preview/src/demo-block.tsx`). We own this. It **must be 0** — a chrome violation fails the build.
|
|
28
|
+
- **Component/demo** = everything else, in the frame's **default** state (the rendered frame _and_ its Radix portals). Allowlisted in `baseline.component`.
|
|
29
|
+
- **Overlay** = the same scope re-measured **after opening an overlay** — see below. Allowlisted separately in `baseline.overlay`.
|
|
30
|
+
|
|
31
|
+
### The overlay scope: opening the thing before measuring it (#355)
|
|
32
|
+
|
|
33
|
+
The gate used to load each frame in its default state and scan once, so every axe rule whose _condition only exists while an overlay is open_ — `aria-hidden-focus` first among them — was **outside its field of view**, not merely un-triggered. 164 frames × 2 viewports reported clean while `aria-hidden-focus` fired on the app background the moment a `Select` or `DropdownMenu` opened in a consumer app.
|
|
34
|
+
|
|
35
|
+
A frame opts in **declaratively**, from the demo itself:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
// the trigger itself, when it forwards DOM props
|
|
39
|
+
<DropdownMenuTrigger asChild>
|
|
40
|
+
<Button data-axe-open …>…</Button>
|
|
41
|
+
</DropdownMenuTrigger>
|
|
42
|
+
|
|
43
|
+
// the region that owns the trigger, when the component renders it internally
|
|
44
|
+
<CardContent data-axe-open>
|
|
45
|
+
<FormField id="status" label="状態"><Select … /></FormField>
|
|
46
|
+
</CardContent>
|
|
47
|
+
|
|
48
|
+
// right-click, for the one overlay that opens on no other gesture
|
|
49
|
+
<ContextMenuTrigger data-axe-open="contextmenu" …>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
What the gate does with it, per frame/viewport, **after** the two default-state scans (opening an overlay is destructive to the state those measure):
|
|
53
|
+
|
|
54
|
+
1. Take the **first** `[data-axe-open]` on the page. No declaration ⇒ the frame skips this scope entirely and costs nothing.
|
|
55
|
+
2. Press **Escape** up to three times while any overlay is mounted. Several demos deliberately render one open at rest, and a modal one makes the rest of the page inert — so the trigger is unreachable until it is dismissed. This also makes the measurement a real **closed → open transition** rather than whatever the demo happened to leave mounted.
|
|
56
|
+
3. Resolve the click target: the declaring element itself when it matches `button, [role=button], [role=combobox], [role=menuitem], a[href], summary`, otherwise the first such control inside it. (`DatePicker`, the data-driven `Select` and `SearchSelect` own their trigger DOM and forward no `data-*` to it — hence the "declare on the region" form. `DatePicker`'s combobox `<input>` opens the calendar on click, which is what gets pressed there.)
|
|
57
|
+
4. Click (or right-click), then wait until **one more** overlay is mounted (`[data-radix-popper-content-wrapper], [role=dialog], [role=alertdialog], [role=menu], [role=listbox]`) plus a 400 ms animation settle — never a bare timer.
|
|
58
|
+
5. Re-run axe with the same scope as the component pass and record it under `baseline.overlay`.
|
|
59
|
+
|
|
60
|
+
A declaration whose overlay never opens is an **infrastructure error** (blocking), not a silent skip: a broken declaration must not read as a clean frame.
|
|
61
|
+
|
|
62
|
+
**Frames declaring an open step today** (the overlay families named in #355): `data-entry-select`, `data-entry-select-matrix` (SearchSelect), `data-entry-date-picker`, `data-display-popover`, `navigation-dropdown-menu`, `navigation-context-menu`, `feedback-dialog`, `feedback-sheet`.
|
|
63
|
+
|
|
64
|
+
**Cost**: the overlay pass only runs on declaring frames, so it is ~8 frames × 2 viewports, measured at **+~55 s on a ~9.5 min local sweep (~10 %)**. Both viewports are kept for now; if the declaring set grows, narrow `OVERLAY_VIEWPORTS` in the script to `["desktop"]` — an overlay is portalled to `<body>` and its aria-hidden background is the same tree at either width.
|
|
65
|
+
|
|
66
|
+
**What is still outside this scope** — deliberately, and worth knowing before trusting a green run:
|
|
67
|
+
|
|
68
|
+
- Only the **first** declaration per frame is exercised. A frame with several distinct overlays (the Sheet demo has five) is measured on one of them.
|
|
69
|
+
- Only **one step deep**: submenus (`DropdownMenuSub`), an overlay opened _from inside_ another overlay, and the state _after_ a selection are not reached.
|
|
70
|
+
- **Keyboard-only opening** is not exercised — the gate clicks. A trigger that opens on click but not on `Enter`/`Space` would pass.
|
|
71
|
+
- The overlay's own **focus trap and focus order** are still not asserted by axe here (`focus-order-semantics` needs the focus to actually move); `src/components/__tests__/overlay-hidden-background.a11y.test.tsx` remains the DOM-level guard for the aria-hidden/inert contract, and it is what fails first if the `inert` mirror in `src/components/general/inert-background.ts` regresses in jsdom.
|
|
72
|
+
- Frames with **no declaration** (156 of 164) are unchanged: default state only.
|
|
28
73
|
|
|
29
74
|
## The component allowlist — and how it shrinks to zero
|
|
30
75
|
|
|
@@ -43,6 +88,10 @@ git add scripts/frame-axe.baseline.json && git commit -m "chore(a11y): tighten f
|
|
|
43
88
|
|
|
44
89
|
There is **no blanket suppression**: a documented axe false positive would be an explicit per-rule entry with a comment, never a mute.
|
|
45
90
|
|
|
91
|
+
`baseline.overlay` is the same shape and obeys the same rule, for the overlay-open scope. It is only rewritten for frames whose open step **actually ran** — a frame that stopped declaring one has not been proven clean, it has been left unmeasured.
|
|
92
|
+
|
|
93
|
+
**Keys that are not violation data are preserved (#356).** The baseline also carries human notes — `scopeGap` records what the gate cannot see and which violations are deliberately unfixed. `--update-baseline` used to rebuild the file from scratch and delete them without a word. It now regenerates only the keys it owns (`generatedAt`, `note`, `component`, `overlay`), carries every other key over verbatim, and **names them in its log line** (`carried over: scopeGap`) so a disappearing key cannot go unnoticed.
|
|
94
|
+
|
|
46
95
|
`0` chrome violations, `0` regressions. See [Remaining baseline debt](#remaining-baseline-debt--the-12-frames) below for exactly what's left and the path to zero.
|
|
47
96
|
|
|
48
97
|
## Running it locally
|
|
@@ -68,28 +117,47 @@ pnpm exec playwright install chromium # local dev — downloads Playwrigh
|
|
|
68
117
|
| `pnpm check:frame-axe --format json` | Machine-readable result on stdout (same exit-code semantics) — no colored human report |
|
|
69
118
|
| `pnpm check:frame-axe --update-baseline` | Regenerate the allowlist (2-pass union by default) — see below |
|
|
70
119
|
| `AXE_RUNS=3 pnpm check:frame-axe --update-baseline` | More union passes, for a component with flaky portal timing |
|
|
120
|
+
| `AXE_SHARD=2/4 pnpm check:frame-axe` | Run only shard 2 of 4 (1-based) for CI fan-out — see below |
|
|
71
121
|
| `pnpm check:frame-axe http://localhost:6008` | Point at an already-running preview instead of building+serving one |
|
|
72
122
|
|
|
123
|
+
#### Sharding the sweep (`AXE_SHARD=i/n`)
|
|
124
|
+
|
|
125
|
+
`AXE_SHARD=2/4` runs only the frames of shard 2 of 4. The partition is taken over frame ids sorted **by code point**, not in manifest/directory order, so the same tree always yields the same partition, every frame lands in exactly one shard, and the union of all `n` shards is exactly the full sweep. Unset (the default) leaves the frame list untouched — sharding changes nothing until you ask for it.
|
|
126
|
+
|
|
127
|
+
Two things are deliberately _not_ the same under a shard, because a shard cannot know them:
|
|
128
|
+
|
|
129
|
+
- **"Baseline rule no longer fires" (shrink hints) is skipped.** The baseline is keyed per frame, so _new_ rule detection stays exact on a partial run — but a frame this shard never visited looks identical to a frame that got fixed. Only a full sweep can tell those apart.
|
|
130
|
+
- **`--update-baseline` refuses to run** with `AXE_SHARD` set (exit 2). Writing the baseline from a fraction of the frames would delete every frame the shard did not visit.
|
|
131
|
+
|
|
132
|
+
`AXE_FRAMES_LIMIT` truncates the list instead of partitioning it; it is a local smoke-test knob, not a fan-out mechanism.
|
|
133
|
+
|
|
73
134
|
If no preview server answers at the base URL (`http://localhost:6008` by default), the script builds one itself: `pnpm preview:build` then serves the static output with `vite preview` (`ensurePreviewServer` in `scripts/frame-harness.mjs`) — deterministic and stable under a long headless sweep, unlike the dev server's per-request recompilation. If a `pnpm preview` dev server (or a remote base) is already reachable, it's reused as-is and never rebuilt.
|
|
74
135
|
|
|
75
136
|
### Reading the output
|
|
76
137
|
|
|
77
|
-
Terminal report (human mode) has
|
|
138
|
+
Terminal report (human mode) has three blocks:
|
|
78
139
|
|
|
79
140
|
```
|
|
80
141
|
Preview-chrome axe (blocking — must be 0):
|
|
81
|
-
✓ 0 chrome violations across all
|
|
142
|
+
✓ 0 chrome violations across all 164 frame(s).
|
|
82
143
|
|
|
83
144
|
Component/demo axe (allowlisted — baseline may only shrink):
|
|
84
|
-
|
|
145
|
+
0 component violation node(s) remaining across 0 frame(s).
|
|
85
146
|
✓ no new component violation types (rule-set within baseline).
|
|
147
|
+
|
|
148
|
+
Overlay axe (frames declaring data-axe-open — baseline may only shrink):
|
|
149
|
+
8 frame(s) opened an overlay before scanning; 128 violation node(s) while open.
|
|
150
|
+
✓ no new overlay violation types (rule-set within baseline).
|
|
86
151
|
```
|
|
87
152
|
|
|
88
153
|
- A **red `✗ <rule>`** under chrome is always blocking.
|
|
89
154
|
- A **red `✗ N NEW violation-type(s) not in baseline`** under component means a frame gained a
|
|
90
155
|
rule the baseline didn't have — that's the actual CI failure mode for a component regression.
|
|
156
|
+
- A **red `✗ N NEW violation-type(s) not in the overlay baseline`** is the same failure for the
|
|
157
|
+
overlay-open state — that is what turns red when, say, the `inert` background patch regresses
|
|
158
|
+
and `aria-hidden-focus` comes back.
|
|
91
159
|
- A **yellow `↓ shrink hint`** means a baseline rule no longer fires anywhere it's listed — free
|
|
92
|
-
baseline tightening available via `--update-baseline`.
|
|
160
|
+
baseline tightening available via `--update-baseline`. Not emitted under `AXE_SHARD`.
|
|
93
161
|
|
|
94
162
|
### Evidence JSON
|
|
95
163
|
|
|
@@ -103,19 +171,27 @@ Shape:
|
|
|
103
171
|
"base": "http://localhost:6008",
|
|
104
172
|
"summary": {
|
|
105
173
|
"status": "ok", // "ok" | "fail"
|
|
106
|
-
"frames":
|
|
174
|
+
"frames": 164,
|
|
175
|
+
"shard": null, // "i/n" when AXE_SHARD is set
|
|
107
176
|
"viewports": ["desktop", "mobile"],
|
|
108
177
|
"chromeViolations": 0, // total chrome violation NODE count
|
|
109
|
-
"componentViolations":
|
|
178
|
+
"componentViolations": 0, // total component violation NODE count (reporting only)
|
|
110
179
|
"componentRegressions": 0, // rules present now but not in the baseline
|
|
180
|
+
"overlayFrames": 8, // frames whose declared open step ran
|
|
181
|
+
"overlayViolations": 128, // total NODE count measured with an overlay open
|
|
182
|
+
"overlayRegressions": 0, // overlay rules present now but not in baseline.overlay
|
|
111
183
|
"infrastructureErrors": 0, // frames that failed to load / axe crashed
|
|
112
184
|
},
|
|
113
185
|
"chrome": {/* rule → { impact, nodes, frames: ["<frameId>@<viewport>", …] } */},
|
|
114
186
|
"componentCurrent": {/* frameId → viewport → ruleId → node count, this run */},
|
|
115
187
|
"regressions": [/* { frame, rule } — new rules, the actual gate failure */],
|
|
116
188
|
"shrinkHints": [/* { frame, rule } — baseline rules that no longer fire */],
|
|
117
|
-
"
|
|
118
|
-
"
|
|
189
|
+
"overlayCurrent": {/* frameId → viewport → ruleId → node count, with the overlay OPEN */},
|
|
190
|
+
"overlayFrames": [/* frame ids whose declared open step ran */],
|
|
191
|
+
"overlayRegressions": [/* { frame, rule } — new rules in the overlay-open state */],
|
|
192
|
+
"overlayShrinkHints": [/* { frame, rule } */],
|
|
193
|
+
"infraErrors": [/* { frame, viewport, message } — includes "overlay open: …" failures */],
|
|
194
|
+
"results": [/* per-frame { id, viewports: { desktop: { chrome, component, overlay? }, … } } */],
|
|
119
195
|
}
|
|
120
196
|
```
|
|
121
197
|
|
|
@@ -140,6 +216,8 @@ Playwright Inspector / browser devtools with the `axe-core` extension against th
|
|
|
140
216
|
violation, not fixed an old one).
|
|
141
217
|
4. Commit the baseline alongside the fix in the same PR.
|
|
142
218
|
|
|
219
|
+
`--update-baseline` also preserves every non-violation key in the file verbatim (see #356 above) and refuses to run under `AXE_SHARD`.
|
|
220
|
+
|
|
143
221
|
`AXE_FRAMES_LIMIT` + `--update-baseline` together only touch the frames actually run — the merge
|
|
144
222
|
logic in `check-frame-axe.mjs` overwrites `runFrameIds` and leaves every other frame's baseline
|
|
145
223
|
entry untouched, so a scoped re-snapshot (e.g. after fixing just `Select`) never silently drops
|
|
@@ -258,10 +336,14 @@ Before opening a PR that adds or meaningfully changes a `/frame/**` example:
|
|
|
258
336
|
8. If you do land a frame with a tracked violation, add it to `scripts/frame-axe.baseline.json` via
|
|
259
337
|
`--update-baseline` (never hand-edit the JSON) and note _why_ + the follow-up issue in the PR
|
|
260
338
|
description — the baseline file's own `note` field explains it may only shrink from here.
|
|
261
|
-
9.
|
|
262
|
-
|
|
263
|
-
a
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
339
|
+
9. **If the frame demos an overlay, declare its open step**: `data-axe-open` on the trigger (or on
|
|
340
|
+
the region that owns it when the component renders the trigger itself), `data-axe-open="contextmenu"`
|
|
341
|
+
for a context menu. Without it the frame is only ever measured closed, and the whole
|
|
342
|
+
`aria-hidden-focus` family of rules cannot fire — see [the overlay scope](#the-overlay-scope-opening-the-thing-before-measuring-it-355).
|
|
343
|
+
10. Register the case you authored in `preview/frame-coverage.ledger.json` so
|
|
344
|
+
`check:frame-coverage-ledger` stops reporting that dimension `UNTESTED`. You **cannot** hand-write
|
|
345
|
+
a verdict — add an entry to the ledger's `cases` array (frame path + case heading + resolvable
|
|
346
|
+
evidence paths + reviewer + HTTPS review link + ISO timestamp) and run
|
|
347
|
+
`pnpm gen:frame-coverage-ledger`; the gate recomputes every cell from that evidence and rejects
|
|
348
|
+
any verdict it cannot reproduce. See [FRAME-COVERAGE-LEDGER.md](./FRAME-COVERAGE-LEDGER.md) and
|
|
349
|
+
[FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md).
|
|
@@ -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: **126**
|
|
7
|
+
- With ≥1 frame: **126** · zero-frame: **0**
|
|
8
8
|
- Fully covered (every contract axis declared): **0**
|
|
9
9
|
|
|
10
10
|
## Per-component contract axes
|
|
@@ -19,6 +19,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
19
19
|
| AppShell | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
20
20
|
| AuthShell | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
21
21
|
| CenteredShell | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
22
|
+
| MobileShell | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
22
23
|
| Sidebar | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
23
24
|
| Topbar | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
24
25
|
| MasterDetail | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
@@ -47,6 +48,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
47
48
|
| CodeBlock | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
48
49
|
| Prose | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
49
50
|
| Timeline | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
51
|
+
| TimelineGrid | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
50
52
|
| Table | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
51
53
|
| DataState | ✓ | N/A | · | N/A | · | · | · | · | · | · |
|
|
52
54
|
| InfiniteQueryState | ✓ | N/A | · | N/A | · | · | · | · | · | · |
|
package/docs/SPACING.md
CHANGED
|
@@ -42,15 +42,28 @@ Implementation: `src/tokens/base.css` (values) · layout owners: `src/styles/*-l
|
|
|
42
42
|
| `--card-space-body-y` | `--space-section-active` | Header↔body gap |
|
|
43
43
|
| `--card-space-header-y` / `--card-space-footer-y` | `--space-stack-sm` | Banded header + separated footer band |
|
|
44
44
|
|
|
45
|
-
| Component | Use
|
|
46
|
-
| ------------------------- |
|
|
47
|
-
| `StatCard` | KPI / stat tile (`solo` path)
|
|
48
|
-
| `CardContent solo` | Body-only card (same padding as `StatCard`)
|
|
49
|
-
| `CardContent flush tight` | Edge-to-edge table/tabs in card
|
|
50
|
-
| `ui-card-inset-x` | Align nested cells to shell (tables in flush body) |
|
|
45
|
+
| Component | Use |
|
|
46
|
+
| ------------------------- | ------------------------------------------- |
|
|
47
|
+
| `StatCard` | KPI / stat tile (`solo` path) |
|
|
48
|
+
| `CardContent solo` | Body-only card (same padding as `StatCard`) |
|
|
49
|
+
| `CardContent flush tight` | Edge-to-edge table/tabs in card |
|
|
51
50
|
|
|
52
51
|
See preview **Data Display → Card** for live examples.
|
|
53
52
|
|
|
53
|
+
### Inset classes (padding on something that is not a `Card*` slot)
|
|
54
|
+
|
|
55
|
+
`Card*` slots get their padding from `data-slot`. Everything else that must sit on the same rhythm (a table cell, a grid header strip, a scroll body, a sticky action row, a full-bleed toolbar) uses one of three public classes. They are the only legal way to take card-token padding onto a plain element, because the audit rejects Tailwind `p-*` / `px-*` (`no-utility-spacing`).
|
|
56
|
+
|
|
57
|
+
Pick by AXIS, and note that the three do **not** share one value: each reads a different card token, so `ui-card-inset` is not `ui-card-inset-x` plus `ui-card-inset-y`.
|
|
58
|
+
|
|
59
|
+
| Class | Axis | Token | Use when |
|
|
60
|
+
| ----------------- | ------------------ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
61
|
+
| `ui-card-inset-x` | inline (start/end) | `--card-space-inset` | The element must line up with the card shell edge, and the block axis is owned by something else (a fixed row height, a table cell). Rows in a `CardContent flush` table, a header strip in a bordered grid. |
|
|
62
|
+
| `ui-card-inset-y` | block (top/bottom) | `--card-space-header-y` | The element runs edge to edge inline but needs the band rhythm of a banded header / separated footer. A weekday header strip, a full-bleed toolbar cell. |
|
|
63
|
+
| `ui-card-inset` | all four sides | `--card-space-body-y` | A self-contained panel that owns its own padding on every side: a scrollable body, a sticky action bar, an expanded row panel below a table row. |
|
|
64
|
+
|
|
65
|
+
Because `ui-card-inset-x` reads `--card-space-inset`, it follows the card it sits in: a `Card density="tight"` or `"cozy"` moves those cells with the shell. The other two read fixed steps (band and body) and do not.
|
|
66
|
+
|
|
54
67
|
## MCP
|
|
55
68
|
|
|
56
69
|
`get_pattern page-sections` (a page of Cards, spaced by the page) · `get_rule 40` (mobile-first spacing) · `list_audit_rules` (the spacing rules the CLI enforces).
|
|
@@ -13,13 +13,12 @@ import { Text } from "@godxjp/ui/general";
|
|
|
13
13
|
import { Flex, PageContainer, ResponsiveGrid } from "@godxjp/ui/layout";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* CompactBarTrend — the DEPENDENCY-FREE compact bar trend
|
|
16
|
+
* CompactBarTrend — the DEPENDENCY-FREE compact bar trend.
|
|
17
17
|
*
|
|
18
|
-
* `BarChart` needs the `recharts` optional peer
|
|
19
|
-
* implementers from adding dependencies cannot use it
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* consumer CSS, zero inline height math and zero hardcoded colour.
|
|
18
|
+
* `BarChart` needs the `recharts` optional peer, so a platform whose policy forbids screen
|
|
19
|
+
* implementers from adding dependencies cannot use it. The marks here are token-sized CSS
|
|
20
|
+
* blocks instead, so a dashboard gets a real framework chart with zero consumer CSS, zero
|
|
21
|
+
* inline height math and zero hardcoded colour.
|
|
23
22
|
*
|
|
24
23
|
* Everything below is composed from real @godxjp/ui primitives only.
|
|
25
24
|
*/
|
|
@@ -25,12 +25,10 @@ import portraitSlate from "../assets/portrait-slate.svg";
|
|
|
25
25
|
* URL against PREVIEW_BASE — an absolute "/assets/…" would 404 wherever the site is served from a
|
|
26
26
|
* sub-path.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* geometry sweeps (gh#333), long after the preview server itself was fixed. Committed files cost
|
|
33
|
-
* no request that can hang and no service that can disappear.
|
|
28
|
+
* A docs page must never fetch a THIRD-PARTY image: without the public internet it cannot render,
|
|
29
|
+
* and on CI it does not merely look wrong, it hangs — the request never settles, `networkidle`
|
|
30
|
+
* never fires, and `page.goto` times out. Committed files cost no request that can hang and no
|
|
31
|
+
* service that can disappear.
|
|
34
32
|
*/
|
|
35
33
|
|
|
36
34
|
/**
|
|
@@ -93,7 +91,7 @@ export default function Demo() {
|
|
|
93
91
|
</CardContent>
|
|
94
92
|
</Card>
|
|
95
93
|
|
|
96
|
-
{/* shape="square" — the entity-header organization / service mark
|
|
94
|
+
{/* shape="square" — the entity-header organization / service mark */}
|
|
97
95
|
<Card>
|
|
98
96
|
<CardHeader>
|
|
99
97
|
<CardTitle level={2}>エンティティヘッダー · shape="square"</CardTitle>
|
|
@@ -136,7 +134,7 @@ export default function Demo() {
|
|
|
136
134
|
</CardContent>
|
|
137
135
|
</Card>
|
|
138
136
|
|
|
139
|
-
{/* appearance="tinted" — the capability medallion
|
|
137
|
+
{/* appearance="tinted" — the capability medallion */}
|
|
140
138
|
<Card>
|
|
141
139
|
<CardHeader>
|
|
142
140
|
<CardTitle level={2}>
|
|
@@ -192,7 +190,7 @@ export default function Demo() {
|
|
|
192
190
|
</CardContent>
|
|
193
191
|
</Card>
|
|
194
192
|
|
|
195
|
-
{/* presence — the realtime reachability dot
|
|
193
|
+
{/* presence — the realtime reachability dot */}
|
|
196
194
|
<Card>
|
|
197
195
|
<CardHeader>
|
|
198
196
|
<CardTitle level={2}>プレゼンス · presence</CardTitle>
|
|
@@ -59,7 +59,7 @@ const tones = [
|
|
|
59
59
|
const statuses = ["active", "draft", "pending", "cancelled", "failed", "scheduled"];
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
|
-
* Subscription/billing lifecycle keys
|
|
62
|
+
* Subscription/billing lifecycle keys. They ship the SAME canonical status→tone→icon
|
|
63
63
|
* map as every other key, so a billing screen never keeps a page-local colour table. They are
|
|
64
64
|
* demoed explicitly because their i18n labels were once missing. A missing key renders the raw
|
|
65
65
|
* `status.trialing` string, and only a rendered demo makes that regression visible.
|