@godxjp/ui 19.3.1 → 19.4.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 (116) hide show
  1. package/dist/components/data-display/badge.d.ts +9 -1
  2. package/dist/components/data-display/badge.js +3 -2
  3. package/dist/components/data-display/index.d.ts +2 -0
  4. package/dist/components/data-display/index.js +2 -0
  5. package/dist/components/data-display/popover.d.ts +13 -1
  6. package/dist/components/data-display/popover.js +3 -1
  7. package/dist/components/data-display/table.d.ts +19 -2
  8. package/dist/components/data-display/table.js +4 -1
  9. package/dist/components/data-display/timeline-grid.d.ts +18 -0
  10. package/dist/components/data-display/timeline-grid.js +222 -0
  11. package/dist/components/data-entry/cascader.js +4 -6
  12. package/dist/components/data-entry/checkbox.js +1 -1
  13. package/dist/components/data-entry/search-select.js +5 -7
  14. package/dist/components/data-entry/select.js +32 -28
  15. package/dist/components/data-entry/tree-select.js +4 -6
  16. package/dist/components/general/inert-background.d.ts +5 -0
  17. package/dist/components/general/inert-background.js +48 -0
  18. package/dist/components/layout/auth-shell.d.ts +4 -2
  19. package/dist/components/layout/auth-shell.js +7 -1
  20. package/dist/components/layout/centered-shell.d.ts +2 -2
  21. package/dist/components/layout/flex.d.ts +1 -1
  22. package/dist/components/layout/flex.js +2 -1
  23. package/dist/components/layout/index.d.ts +3 -0
  24. package/dist/components/layout/index.js +2 -0
  25. package/dist/components/layout/mobile-shell.d.ts +21 -0
  26. package/dist/components/layout/mobile-shell.js +43 -0
  27. package/dist/components/layout/sidebar-link.d.ts +1 -1
  28. package/dist/components/navigation/context-menu.js +13 -9
  29. package/dist/components/navigation/dropdown-menu.js +17 -13
  30. package/dist/inertia/index.d.ts +1 -1
  31. package/dist/lib/variants.d.ts +3 -3
  32. package/dist/lib/variants.js +1 -0
  33. package/dist/props/components/data-display.prop.d.ts +65 -0
  34. package/dist/props/components/data-entry.prop.d.ts +1 -1
  35. package/dist/props/components/layout.prop.d.ts +93 -6
  36. package/dist/props/registry.d.ts +109 -2
  37. package/dist/props/registry.js +143 -0
  38. package/dist/props/vocabulary/data.prop.d.ts +6 -0
  39. package/dist/props/vocabulary/index.d.ts +3 -3
  40. package/dist/props/vocabulary/layout.prop.d.ts +17 -2
  41. package/dist/props/vocabulary/shared.prop.d.ts +7 -0
  42. package/dist/styles/control.css +18 -1
  43. package/dist/styles/data-display-layout.css +167 -0
  44. package/dist/styles/layout.css +7 -0
  45. package/dist/styles/shell-layout.css +148 -0
  46. package/dist/styles/table-layout.css +23 -4
  47. package/dist/tokens/components/control.css +1 -0
  48. package/dist/tokens/components/data-display.css +20 -0
  49. package/dist/tokens/components/shell.css +22 -0
  50. package/dist/tokens/components/table.css +2 -0
  51. package/docs/SPACING.md +19 -6
  52. package/docs/charts/compact-bar-trend.tsx +5 -6
  53. package/docs/data-display/avatar.tsx +7 -9
  54. package/docs/data-display/badge.tsx +1 -1
  55. package/docs/data-display/card/index.tsx +6 -4
  56. package/docs/data-display/data-table/examples/approval-queue.tsx +1 -1
  57. package/docs/data-display/data-table/index.tsx +1 -1
  58. package/docs/data-display/permission-matrix.tsx +2 -2
  59. package/docs/data-display/scroll-area.tsx +1 -1
  60. package/docs/data-display/table.tsx +1 -1
  61. package/docs/data-display/timeline-grid.tsx +119 -0
  62. package/docs/data-entry/branch-scope-picker.tsx +1 -1
  63. package/docs/data-entry/input-otp.tsx +1 -1
  64. package/docs/data-entry/textarea.tsx +1 -1
  65. package/docs/data-entry/toggle-count.tsx +1 -1
  66. package/docs/feedback/alert.tsx +1 -1
  67. package/docs/feedback/banner.tsx +1 -1
  68. package/docs/foundation/email-tokens.tsx +1 -1
  69. package/docs/general/activity.tsx +1 -1
  70. package/docs/layout/auth-account-summary.tsx +1 -1
  71. package/docs/layout/auth-recovery/examples/mobile-390.tsx +1 -1
  72. package/docs/layout/auth-recovery/examples/password-recovery.tsx +0 -2
  73. package/docs/layout/auth-shell-context.tsx +1 -1
  74. package/docs/layout/auth-shell-device.tsx +2 -2
  75. package/docs/layout/auth-shell-registration.tsx +1 -1
  76. package/docs/layout/auth-shell.tsx +1 -1
  77. package/docs/layout/master-detail.tsx +2 -2
  78. package/docs/layout/mobile-shell.tsx +101 -0
  79. package/docs/layout/page-container.tsx +6 -6
  80. package/docs/layout/responsive-grid.tsx +2 -2
  81. package/docs/layout/separator.tsx +2 -2
  82. package/docs/layout/service-role-panel.tsx +1 -1
  83. package/docs/layout/sidebar.tsx +6 -6
  84. package/docs/layout/split-pane.tsx +1 -1
  85. package/docs/layout/topbar.tsx +2 -8
  86. package/docs/navigation/filter-bar.tsx +2 -2
  87. package/docs/navigation/pagination.tsx +2 -2
  88. package/docs/navigation/steps.tsx +1 -1
  89. package/docs/navigation/tabs.tsx +1 -1
  90. package/docs/showcase/acme-portal.tsx +11 -12
  91. package/docs/showcase/acme-website.tsx +7 -7
  92. package/docs/showcase/case1-warehouse-dashboard.tsx +11 -12
  93. package/docs/showcase/case2-employee-me.tsx +10 -16
  94. package/docs/showcase/case4-login.tsx +144 -156
  95. package/docs/showcase/case5-shift-calendar.tsx +181 -280
  96. package/docs/showcase/case6-agency-handy.tsx +446 -443
  97. package/docs/showcase/futurelastic-web.tsx +9 -8
  98. package/docs/showcase/org-switcher.tsx +18 -11
  99. package/docs/showcase/permission-matrix.tsx +13 -13
  100. package/docs/showcase/public-landing.tsx +1 -1
  101. package/docs/showcase/settings-account-sections.tsx +2 -2
  102. package/docs/showcase/settings-security-mfa.tsx +3 -3
  103. package/docs/showcase/table-approval-queue.tsx +1 -1
  104. package/docs/showcase/table-bulk-actions.tsx +49 -52
  105. package/docs/showcase/table-conditional-format.tsx +1 -1
  106. package/docs/showcase/table-crud-list.tsx +1 -1
  107. package/docs/showcase/table-expandable-rows.tsx +101 -98
  108. package/docs/showcase/table-filter-chips.tsx +78 -66
  109. package/docs/showcase/table-footer-totals.tsx +23 -19
  110. package/docs/showcase/table-grouped-subtotals.tsx +7 -4
  111. package/docs/showcase/table-master-detail.tsx +12 -14
  112. package/docs/showcase/table-states.tsx +34 -29
  113. package/docs/showcase/table-sticky-columns.tsx +3 -2
  114. package/docs/showcase/table-tree-rows.tsx +22 -15
  115. package/docs/showcase/table-view-tabs.tsx +12 -14
  116. 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
- border: 1px solid hsl(var(--border));
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
- border: 1px solid hsl(var(--border));
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
- border: 1px solid hsl(var(--border));
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
- border: 1px solid hsl(var(--border));
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);
@@ -31,6 +31,7 @@
31
31
 
32
32
  --rating-focus-ring-offset: 2px;
33
33
 
34
+ --checkbox-border-width: var(--stroke-hairline);
34
35
  --checkbox-size: calc(1rem * var(--scaling));
35
36
  --checkbox-size-compact: 0.875rem;
36
37
  --checkbox-size-comfortable: 1.125rem;
@@ -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/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 (gh#218).
16
+ * CompactBarTrend — the DEPENDENCY-FREE compact bar trend.
17
17
  *
18
- * `BarChart` needs the `recharts` optional peer; a platform whose policy forbids screen
19
- * implementers from adding dependencies cannot use it, and used to fall back to a page-local
20
- * grid with inline heights. `CompactBarTrend` closes that gap: the marks are token-sized CSS
21
- * blocks, so the canonical SCR-201 admin dashboard gets a real framework chart with zero
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
- * They used to be `https://picsum.photos/...`. A docs page that fetches a THIRD-PARTY image cannot
29
- * render without the public internet, and on CI it does not merely look wrong it hangs: the
30
- * request never settles, `networkidle` never fires, and `page.goto` times out at 30s. That is what
31
- * failed `data-display-avatar` and `data-display-card-index` at every viewport in both the axe and
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 (gh#249) */}
94
+ {/* shape="square" — the entity-header organization / service mark */}
97
95
  <Card>
98
96
  <CardHeader>
99
97
  <CardTitle level={2}>エンティティヘッダー · shape=&quot;square&quot;</CardTitle>
@@ -136,7 +134,7 @@ export default function Demo() {
136
134
  </CardContent>
137
135
  </Card>
138
136
 
139
- {/* appearance="tinted" — the capability medallion (gh#12) */}
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 (gh#309) */}
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 (gh#216). They ship the SAME canonical status→tone→icon
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.
@@ -23,10 +23,12 @@ import { MoreHorizontal } from "lucide-react";
23
23
 
24
24
  import coverTerrain from "../../assets/cover-terrain.svg";
25
25
 
26
- /* A committed SVG under docs/assets, imported so the bundler rewrites the URL against
26
+ /*
27
+ * A committed SVG under docs/assets, imported so the bundler rewrites the URL against
27
28
  * PREVIEW_BASE. It replaces a picsum.photos fetch that hung `networkidle` and timed this page out
28
- * at 30s in CI (gh#333); it was briefly an inline data: URI, which fixed the hang but put 700
29
- * unreadable characters in the middle of the example a consumer is meant to copy. */
29
+ * at 30s in CI; it was briefly an inline data: URI, which fixed the hang but put 700
30
+ * unreadable characters in the middle of the example a consumer is meant to copy.
31
+ */
30
32
 
31
33
  /**
32
34
  * Card — surface container. Body content ALWAYS goes in CardContent (a bare Card
@@ -131,7 +133,7 @@ export default function Demo() {
131
133
  </ResponsiveGrid>
132
134
  </Flex>
133
135
 
134
- {/* accentPlacement="perimeter" — the semantic attention border (gh#12) */}
136
+ {/* accentPlacement="perimeter" — the semantic attention border */}
135
137
  <Flex direction="col" gap="sm">
136
138
  <Text as="div" weight="medium">
137
139
  Accent · accentPlacement=&quot;perimeter&quot; (全周のアテンションボーダー)
@@ -19,7 +19,7 @@ import {
19
19
  import { ClipboardCheck, LayoutDashboard, MoreHorizontal, ScrollText } from "lucide-react";
20
20
 
21
21
  /**
22
- * Access-approval queue (SCR-105 / gh#253) — the canonical five-column approval collection driven
22
+ * Access-approval queue (SCR-105 / ) — the canonical five-column approval collection driven
23
23
  * by the TanStack-powered DataTable, at 1440 · 1024 · 390 with ONLY public API.
24
24
  *
25
25
  * The whole responsive contract is two props: `preset="action-collection"` on the DataTable and a
@@ -230,7 +230,7 @@ export default function Demo() {
230
230
  <DataTable data={[]} columns={columns} getRowId={(row) => row.id} />
231
231
  </Flex>
232
232
 
233
- {/* gh#216 — the two failure states, in the same table grid as empty/loading. */}
233
+ {/* — the two failure states, in the same table grid as empty/loading. */}
234
234
  <Flex direction="col" gap="sm">
235
235
  <Text as="div" weight="medium">
236
236
  エラー(error · role=&quot;alert&quot; · onRetry で再試行を表示)
@@ -1,7 +1,7 @@
1
1
  /**
2
- * PermissionMatrix — 権限マトリクス (canonical RBAC role × permission grid, gh#257).
2
+ * PermissionMatrix — 権限マトリクス (canonical RBAC role × permission grid, ).
3
3
  *
4
- * A REAL export from `@godxjp/ui/data-display` (the gh#251 lesson: a consumer cannot import a
4
+ * A REAL export from `@godxjp/ui/data-display` (the lesson: a consumer cannot import a
5
5
  * docs page). Read-only ✓/— by default; `onGrantChange` switches to editable checkbox cells with
6
6
  * locked roles kept read-only; compare + 差分のみ come from `lib/permission-grid`; lifecycle
7
7
  * states follow the DataTable #216 vocabulary. Domain data below is demo-only — the library
@@ -27,7 +27,7 @@ const entries = Array.from(
27
27
  const shortEntries = entries.slice(0, 3);
28
28
 
29
29
  /**
30
- * The live-stream screen (gh#311). A deterministic clock: the demo never reads `Date.now()`, so the
30
+ * The live-stream screen. A deterministic clock: the demo never reads `Date.now()`, so the
31
31
  * frame is stable, and every timestamp still goes through `Intl.DateTimeFormat` (IANA tz, 24h).
32
32
  */
33
33
  const STREAM_EPOCH = Date.UTC(2026, 2, 3, 0, 30, 0);
@@ -131,7 +131,7 @@ export default function Demo() {
131
131
  </CardContent>
132
132
  </Card>
133
133
 
134
- {/* ── The flush full-bleed FRAME contract (gh#305 · gh#306) ───────────────────────────
134
+ {/* ── The flush full-bleed FRAME contract ───────────────────────────
135
135
  Four cards, side by side, so the whole rule is visible at once: which edges a
136
136
  full-bleed table keeps inside a card, and who draws the line under the header. */}
137
137
  <Card>
@@ -0,0 +1,119 @@
1
+ import {
2
+ Card,
3
+ CardContent,
4
+ CardDescription,
5
+ CardHeader,
6
+ CardTitle,
7
+ TimelineGrid,
8
+ type TimelineGridColumnProp,
9
+ type TimelineGridEventProp,
10
+ } from "@godxjp/ui/data-display";
11
+ import { Flex, PageContainer } from "@godxjp/ui/layout";
12
+
13
+ /**
14
+ * TimelineGrid — a vertical hour axis, one column per day, and event blocks placed by start time
15
+ * and duration. It is the time-axis half of the Timeline family; Timeline itself is one lane of
16
+ * ordered events with no scale.
17
+ */
18
+ const WEEK: TimelineGridColumnProp[] = [
19
+ { id: "05-11", label: "月 11" },
20
+ { id: "05-12", label: "火 12" },
21
+ { id: "05-13", label: "水 13" },
22
+ { id: "05-14", label: "木 14", description: "本日", current: true },
23
+ { id: "05-15", label: "金 15" },
24
+ ];
25
+
26
+ const SHIFTS: TimelineGridEventProp[] = [
27
+ { id: "s1", columnId: "05-11", start: "09:00", end: "22:00", title: "通し", description: "佐藤" },
28
+ { id: "s2", columnId: "05-12", start: "06:00", end: "22:00", title: "有給", description: "鈴木" },
29
+ { id: "s3", columnId: "05-14", start: "09:00", end: "17:30", title: "早番", description: "田中" },
30
+ { id: "s4", columnId: "05-14", start: "13:00", end: "22:00", title: "遅番", description: "高橋" },
31
+ // end at or before start = the shift runs into the next day (夜勤 22:00–06:00).
32
+ { id: "s5", columnId: "05-14", start: "22:00", end: "06:00", title: "夜勤", description: "伊藤" },
33
+ { id: "s6", columnId: "05-15", start: "09:00", end: "17:30", title: "早番", description: "佐藤" },
34
+ { id: "s7", columnId: "05-15", start: "18:00", end: "21:00", title: "残業", description: "鈴木" },
35
+ ];
36
+
37
+ // One column, a finer axis, and a colour carried by the record itself — the day view of the same
38
+ // data. `color` is decorative: the block still prints its hours and its title as text.
39
+ const ROOMS: TimelineGridColumnProp[] = [
40
+ { id: "a", label: "会議室 A", description: "12名" },
41
+ { id: "b", label: "会議室 B", description: "6名" },
42
+ ];
43
+
44
+ const BOOKINGS: TimelineGridEventProp[] = [
45
+ {
46
+ id: "b1",
47
+ columnId: "a",
48
+ start: "09:30",
49
+ end: "10:30",
50
+ title: "定例会",
51
+ description: "営業部",
52
+ color: "var(--wa-gunjo)",
53
+ },
54
+ {
55
+ id: "b2",
56
+ columnId: "a",
57
+ start: "10:00",
58
+ end: "11:00",
59
+ title: "面談",
60
+ description: "人事",
61
+ color: "var(--wa-akane)",
62
+ },
63
+ {
64
+ id: "b3",
65
+ columnId: "b",
66
+ start: "13:00",
67
+ end: "14:30",
68
+ title: "設計レビュー",
69
+ description: "開発部",
70
+ color: "var(--wa-wakatake)",
71
+ },
72
+ ];
73
+
74
+ export default function Demo() {
75
+ return (
76
+ <PageContainer title="TimelineGrid" subtitle="時間軸に沿って予定ブロックを置く週/日グリッド">
77
+ <Flex direction="col" gap="lg">
78
+ <Card>
79
+ <CardHeader>
80
+ <CardTitle level={2}>週シフト</CardTitle>
81
+ <CardDescription>
82
+ start / end で軸を 06:00–24:00 に固定し、interval=2
83
+ で2時間ごとに目盛りを引きます。木曜の早番と遅番は時間が重なるため、自動で横に並びます。
84
+ </CardDescription>
85
+ </CardHeader>
86
+ <CardContent flush>
87
+ <TimelineGrid
88
+ label="週シフト 2026年5月11日〜15日"
89
+ columns={WEEK}
90
+ events={SHIFTS}
91
+ start="06:00"
92
+ end="24:00"
93
+ interval={2}
94
+ now="14:35"
95
+ />
96
+ </CardContent>
97
+ </Card>
98
+
99
+ <Card>
100
+ <CardHeader>
101
+ <CardTitle level={2}>会議室の予約</CardTitle>
102
+ <CardDescription>
103
+ start / end を省略すると、軸は予定の範囲から自動で決まります。onEventSelect
104
+ を渡すと各ブロックが button になり、キーボードでも選べます。
105
+ </CardDescription>
106
+ </CardHeader>
107
+ <CardContent flush>
108
+ <TimelineGrid
109
+ label="会議室の予約 5月14日"
110
+ columns={ROOMS}
111
+ events={BOOKINGS}
112
+ onEventSelect={() => {}}
113
+ />
114
+ </CardContent>
115
+ </Card>
116
+ </Flex>
117
+ </PageContainer>
118
+ );
119
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * BranchScopePicker — 適用範囲 (all branches vs an explicit subset, gh#257).
2
+ * BranchScopePicker — 適用範囲 (all branches vs an explicit subset).
3
3
  *
4
4
  * One controlled `{ mode, branchIds }` value; real RadioGroup + CheckboxGroup + SearchInput
5
5
  * underneath. `error` is FIELD VALIDATION (aria-errormessage); a failed branch read is
@@ -140,7 +140,7 @@ export default function Demo() {
140
140
  </CardContent>
141
141
  </Card>
142
142
 
143
- {/* align — the centred challenge, without a consumer wrapper div (gh#12) */}
143
+ {/* Align — the centred challenge, without a consumer wrapper div */}
144
144
  <Card>
145
145
  <CardHeader>
146
146
  <CardTitle level={2}>中央寄せ(align=&quot;center&quot;)</CardTitle>
@@ -18,7 +18,7 @@ const SEED_MESSAGES: Message[] = [
18
18
  ];
19
19
 
20
20
  /**
21
- * The godx-chatter composer (gh#310). One line at rest, grows line by line, scrolls itself past
21
+ * The godx-chatter composer. One line at rest, grows line by line, scrolls itself past
22
22
  * eight rows, and collapses back to one line the moment the post is sent — the send button just
23
23
  * resets the controlled value, and `autoGrow` follows it without a single line of layout code.
24
24
  */
@@ -14,7 +14,7 @@ import { Button, Text } from "@godxjp/ui/general";
14
14
  import { Flex, PageContainer } from "@godxjp/ui/layout";
15
15
 
16
16
  /**
17
- * Toggle `count` — the counted, PRESSED chip (gh#312).
17
+ * Toggle `count` — the counted, PRESSED chip.
18
18
  *
19
19
  * `Button` owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`) and `Toggle`
20
20
  * owns the pressed state, so a faceted filter chip ("未対応 42", selected or not) and a reaction