@godxjp/ui 18.5.0 → 18.6.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 (91) hide show
  1. package/dist/components/charts/compact-bar-trend.d.ts +2 -1
  2. package/dist/components/charts/index.d.ts +4 -1
  3. package/dist/components/data-display/data-table.d.ts +25 -4
  4. package/dist/components/data-display/data-table.js +13 -2
  5. package/dist/components/data-display/empty-state.js +1 -1
  6. package/dist/components/data-display/index.d.ts +1 -1
  7. package/dist/components/data-display/list-row.d.ts +19 -0
  8. package/dist/components/data-display/list-row.js +2 -0
  9. package/dist/components/data-display/qr-code.d.ts +1 -1
  10. package/dist/components/data-display/table.d.ts +47 -2
  11. package/dist/components/data-display/table.js +29 -4
  12. package/dist/components/data-entry/command.d.ts +10 -10
  13. package/dist/components/data-entry/index.d.ts +1 -0
  14. package/dist/components/data-entry/input-otp.d.ts +1 -0
  15. package/dist/components/feedback/dialog.d.ts +14 -1
  16. package/dist/components/feedback/dialog.js +4 -0
  17. package/dist/components/feedback/index.d.ts +1 -1
  18. package/dist/components/feedback/index.js +2 -0
  19. package/dist/components/general/logo.d.ts +7 -1
  20. package/dist/components/general/logo.js +1 -1
  21. package/dist/components/layout/app-shell.d.ts +1 -1
  22. package/dist/components/layout/app-shell.js +55 -46
  23. package/dist/components/layout/auth-account-summary.d.ts +5 -0
  24. package/dist/components/layout/auth-account-summary.js +31 -0
  25. package/dist/components/layout/auth-shell.d.ts +3 -2
  26. package/dist/components/layout/centered-shell.d.ts +1 -1
  27. package/dist/components/layout/centered-shell.js +28 -19
  28. package/dist/components/layout/error-surface.d.ts +35 -0
  29. package/dist/components/layout/error-surface.js +155 -0
  30. package/dist/components/layout/flex.d.ts +1 -1
  31. package/dist/components/layout/flex.js +4 -0
  32. package/dist/components/layout/index.d.ts +5 -0
  33. package/dist/components/layout/index.js +4 -0
  34. package/dist/components/layout/page-container.d.ts +1 -1
  35. package/dist/components/layout/page-container.js +4 -0
  36. package/dist/components/navigation/steps.js +38 -19
  37. package/dist/components/navigation/tabs.js +12 -3
  38. package/dist/components/ui/avatar.d.ts +2 -1
  39. package/dist/components/ui/avatar.js +2 -1
  40. package/dist/components/ui/input-otp.d.ts +4 -1
  41. package/dist/components/ui/input-otp.js +2 -1
  42. package/dist/components/ui/toggle-group.d.ts +7 -4
  43. package/dist/components/ui/toggle-group.js +32 -21
  44. package/dist/email/brand-mark.d.ts +21 -5
  45. package/dist/email/brand-mark.js +5 -0
  46. package/dist/email/color.d.ts +2 -1
  47. package/dist/email/geometry.d.ts +9 -1
  48. package/dist/email/geometry.js +1 -0
  49. package/dist/email/index.d.ts +6 -1
  50. package/dist/email/index.js +6 -0
  51. package/dist/email/inline-style.d.ts +7 -5
  52. package/dist/email/inline-style.js +5 -0
  53. package/dist/email/tokens.generated.d.ts +40 -20
  54. package/dist/email/tokens.generated.js +40 -20
  55. package/dist/email/urgency.d.ts +22 -0
  56. package/dist/email/urgency.js +14 -0
  57. package/dist/i18n/messages/en.json +15 -1
  58. package/dist/i18n/messages/ja.json +15 -1
  59. package/dist/i18n/messages/vi.json +15 -1
  60. package/dist/props/components/data-display.prop.d.ts +63 -1
  61. package/dist/props/components/data-entry.prop.d.ts +6 -0
  62. package/dist/props/components/index.d.ts +1 -1
  63. package/dist/props/components/layout.prop.d.ts +191 -4
  64. package/dist/props/components/navigation.prop.d.ts +5 -1
  65. package/dist/props/registry.d.ts +145 -4
  66. package/dist/props/registry.js +189 -5
  67. package/dist/props/vocabulary/data.prop.d.ts +27 -0
  68. package/dist/props/vocabulary/index.d.ts +3 -3
  69. package/dist/props/vocabulary/interaction.prop.d.ts +9 -0
  70. package/dist/props/vocabulary/layout.prop.d.ts +38 -7
  71. package/dist/styles/control.css +28 -0
  72. package/dist/styles/data-display-layout.css +26 -0
  73. package/dist/styles/layout.css +99 -0
  74. package/dist/styles/logo-layout.css +42 -9
  75. package/dist/styles/navigation-layout.css +109 -0
  76. package/dist/styles/shell-layout.css +302 -0
  77. package/dist/styles/table-layout.css +164 -1
  78. package/dist/theme/dxs.canonical.css +5 -4
  79. package/dist/tokens/axes.css +4 -3
  80. package/dist/tokens/base.css +1 -0
  81. package/dist/tokens/components/data-display.css +13 -0
  82. package/dist/tokens/components/email.css +43 -16
  83. package/dist/tokens/components/error-surface.css +36 -0
  84. package/dist/tokens/components/list-row.css +20 -0
  85. package/dist/tokens/components/logo.css +52 -10
  86. package/dist/tokens/components/navigation.css +15 -0
  87. package/dist/tokens/components/shell.css +72 -0
  88. package/dist/tokens/components/table.css +45 -0
  89. package/dist/tokens/foundation.css +26 -0
  90. package/dist/tokens/semantic/layout.css +25 -0
  91. package/package.json +8 -2
@@ -18,6 +18,18 @@
18
18
  font-weight: var(--font-weight-medium);
19
19
  }
20
20
 
21
+ /* Entity-header mark — `<Avatar shape="square">` (gh#249). Opt-in ONLY: without the attribute the
22
+ * avatar above is untouched. Geometry and colour are token-owned (rule #45); the brand fill is
23
+ * handed down through --avatar-background so the fallback slot picks it up with no extra rule,
24
+ * and a service that only wants a neutral square overrides --avatar-square-background. */
25
+ .ui-avatar[data-shape="square"] {
26
+ inline-size: var(--avatar-square-size);
27
+ block-size: var(--avatar-square-size);
28
+ border-radius: var(--avatar-square-radius);
29
+ --avatar-background: var(--avatar-square-background, hsl(var(--primary)));
30
+ color: var(--avatar-square-foreground, hsl(var(--primary-foreground)));
31
+ }
32
+
21
33
  .ui-avatar-image {
22
34
  width: 100%;
23
35
  height: 100%;
@@ -508,6 +520,20 @@
508
520
  [data-slot="list-row"][data-overflow="wrap"] [data-slot="list-row-body"] {
509
521
  overflow-wrap: anywhere;
510
522
  }
523
+ /* `density="compact"` (#246) — the compact inline-actions geometry: tighter block padding and
524
+ * column gap plus a LOWER body threshold, so a 36px avatar, the title/description and one or two
525
+ * small trailing Buttons stay inline inside the canonical 326px content column at 390px. It only
526
+ * LOWERS thresholds; the #224 overflow contract above is untouched (the row still wraps, the body
527
+ * is still clamped with min(…, 100%)), so a compact row can never widen the page root. */
528
+ [data-slot="list-row"][data-density="compact"] {
529
+ gap: var(--list-row-compact-gap, var(--space-2));
530
+ padding: var(--list-row-compact-padding-y, var(--space-2))
531
+ var(--list-row-compact-padding-x, var(--list-row-padding-x));
532
+ }
533
+ [data-slot="list-row"][data-density="compact"] [data-slot="list-row-body"] {
534
+ min-inline-size: min(var(--list-row-compact-body-min-width, 6rem), 100%);
535
+ flex-basis: var(--list-row-compact-body-min-width, 6rem);
536
+ }
511
537
  [data-slot="list-row-trailing"] {
512
538
  display: inline-flex;
513
539
  max-inline-size: 100%;
@@ -411,6 +411,29 @@
411
411
  max-width: 42rem;
412
412
  }
413
413
 
414
+ /* `measure` (gh#245 / gh#247) — a bounded page measure axis ORTHOGONAL to `variant`, so the
415
+ * quiet `ghost` chrome and a narrow/medium measure finally compose (they used to be the same
416
+ * variant axis, which is exactly why a notification feed could not have both). Unlike
417
+ * `variant="narrow"` — which caps only the body and leaves the header `extra` action stranded
418
+ * at the page edge — this caps the HEADER and the BODY to ONE shared measure, so the action
419
+ * ends on the same edge as the body surface. Both elements carry the identical page gutters,
420
+ * so their content edges line up exactly at both ends.
421
+ *
422
+ * `measure="default"` is the inert default: it emits `data-measure="default"`, which matches NO
423
+ * rule here, so every existing page renders byte-identically (the gh#231 `data-layout="stack"`
424
+ * precedent). The cap is a max, never a width — below it the page stays fluid, so 390px keeps
425
+ * the full compact-gutter surface. The footer is deliberately NOT capped: its border/background
426
+ * is page-level chrome that must span the page when `stickyFooter` pins it. */
427
+ .ui-page-container[data-measure="narrow"] .ui-page-header,
428
+ .ui-page-container[data-measure="narrow"] .ui-page-body {
429
+ max-inline-size: var(--page-measure-narrow);
430
+ }
431
+
432
+ .ui-page-container[data-measure="medium"] .ui-page-header,
433
+ .ui-page-container[data-measure="medium"] .ui-page-body {
434
+ max-inline-size: var(--page-measure-medium);
435
+ }
436
+
414
437
  /* flush = full-bleed body (DataTable); header/footer keep their inset. */
415
438
  .ui-page-container--flush .ui-page-body {
416
439
  padding-inline-start: 0;
@@ -711,6 +734,20 @@
711
734
  }
712
735
  }
713
736
 
737
+ @layer components {
738
+ .ui-page-container[data-preset="admin-collection"] {
739
+ --control-height: var(--admin-collection-control-height);
740
+ --space-section-active: var(--admin-collection-section-gap);
741
+ --filter-bar-padding-y: var(--admin-collection-toolbar-padding-y);
742
+ --table-row-height: var(--admin-collection-table-row-height);
743
+ --table-cell-padding-y: var(--admin-collection-table-cell-padding-y);
744
+ }
745
+
746
+ .ui-page-container[data-preset="admin-collection"] .ui-toolbar .ui-search-input {
747
+ inline-size: min(100%, var(--admin-collection-search-measure));
748
+ }
749
+ }
750
+
714
751
  @layer components {
715
752
  /* Pagination is ONE horizontal row and never wraps to a second desktop line (gh#153 — the old
716
753
  * `flex-wrap: wrap` split the range / size-changer / page strip across rows). The number strip
@@ -1122,3 +1159,65 @@
1122
1159
  }
1123
1160
  }
1124
1161
  }
1162
+
1163
+ @layer components {
1164
+ /* ── Flex responsive region visibility (gh#252) ──────────────────────────────────────────────
1165
+ * `hideBelow` / `hideFrom` are the ONE public way to drop a layout region at a breakpoint step.
1166
+ * Without them a public header cannot hide its anchor navigation below the tablet step, or show
1167
+ * a compact-only affordance, without a page-local media query — which is exactly the API-first
1168
+ * violation gh#252 reports. The steps are the package's canonical breakpoint scale, the same
1169
+ * values `--master-detail-collapse-below` uses (sm 40rem · md 48rem · lg 64rem · xl 80rem); a
1170
+ * media query cannot read a `var()`, so the step values are the tokenized scale written out.
1171
+ *
1172
+ * Both props default to `undefined`, so NO `data-hide-*` attribute is emitted and none of these
1173
+ * selectors can match — every existing Flex is untouched (the gh#231 inert-default contract).
1174
+ * `display: none` removes the region from the a11y tree too, which is the point: the destination
1175
+ * must stay reachable from another region (the footer nav) at that width. */
1176
+ @media (width < 40rem) {
1177
+ .ui-flex[data-hide-below="sm"] {
1178
+ display: none;
1179
+ }
1180
+ }
1181
+
1182
+ @media (width < 48rem) {
1183
+ .ui-flex[data-hide-below="md"] {
1184
+ display: none;
1185
+ }
1186
+ }
1187
+
1188
+ @media (width < 64rem) {
1189
+ .ui-flex[data-hide-below="lg"] {
1190
+ display: none;
1191
+ }
1192
+ }
1193
+
1194
+ @media (width < 80rem) {
1195
+ .ui-flex[data-hide-below="xl"] {
1196
+ display: none;
1197
+ }
1198
+ }
1199
+
1200
+ @media (width >= 40rem) {
1201
+ .ui-flex[data-hide-from="sm"] {
1202
+ display: none;
1203
+ }
1204
+ }
1205
+
1206
+ @media (width >= 48rem) {
1207
+ .ui-flex[data-hide-from="md"] {
1208
+ display: none;
1209
+ }
1210
+ }
1211
+
1212
+ @media (width >= 64rem) {
1213
+ .ui-flex[data-hide-from="lg"] {
1214
+ display: none;
1215
+ }
1216
+ }
1217
+
1218
+ @media (width >= 80rem) {
1219
+ .ui-flex[data-hide-from="xl"] {
1220
+ display: none;
1221
+ }
1222
+ }
1223
+ }
@@ -39,19 +39,52 @@
39
39
  font-size: var(--logo-font-size-lg);
40
40
  }
41
41
 
42
- /* Identity fills — role defaults live HERE (call site), not on :root, so a scoped `.dark` /
43
- * `[data-tenant]` override of --success re-resolves (docs/TOKENS.md · role-mirror knobs). */
42
+ /* Identity fills — the IDENTITY role --brand (canonical GoDX emerald), NOT the --success STATUS
43
+ * green: `tone="success"` names the semantic slot, not the status role, and a badge/progress
44
+ * green must never drag the product mark with it (gh#250). Role defaults live HERE (call site),
45
+ * not on :root, so a scoped `.dark` / `[data-tenant]` override of --brand re-resolves
46
+ * (docs/TOKENS.md · role-mirror knobs).
47
+ *
48
+ * The INK is --logo-identity-foreground, NOT --brand-foreground: this branch sets caller-supplied
49
+ * TEXT on the fill, so WCAG 2.2 SC 1.4.3 applies at 4.5:1 (14px bold is not "large text"), while
50
+ * --brand-foreground is the artwork KNOCKOUT colour that tracks --background and only owes 3:1 as
51
+ * non-text (SC 1.4.11). Knockout white on the emerald measured 3.67:1 — an AA failure on every
52
+ * boxed `tone="success"` glyph. See src/tokens/components/logo.css. */
44
53
  .ui-logo[data-tone="success"] {
45
- background: hsl(var(--logo-success-background, var(--success)));
46
- color: hsl(var(--logo-success-foreground, var(--success-foreground)));
54
+ background: hsl(var(--logo-success-background, var(--brand)));
55
+ color: hsl(var(--logo-success-foreground, var(--logo-identity-foreground)));
47
56
  }
48
57
 
58
+ /* The identity mark honours `size` like every other Logo branch. The godx box has its OWN tier
59
+ * scale (--logo-godx-size-*) because the artwork is a horizontal capsule in a square viewBox and
60
+ * needs ~+0.25rem over the filled glyph box to read at the same weight — but a public `size` prop
61
+ * that renders identically at xs and lg is a silent no-op, and the lockup already scaled its
62
+ * wordmark per tier, so a frozen mark broke the mark↔wordmark proportion at `size="lg"`.
63
+ * These are `[data-mark][data-size]` (0,3,0) so they beat BOTH `.ui-logo[data-size]` and the
64
+ * `[data-mark="godx"]` base regardless of source order — the ordering bug that hid `size` here.
65
+ * --logo-godx-size stays the documented PIN: unset by default, and set once by a service theme it
66
+ * wins at every tier (call-site default, docs/TOKENS.md). */
49
67
  .ui-logo[data-mark="godx"] {
50
- width: var(--logo-godx-size);
51
- height: var(--logo-godx-size);
68
+ width: var(--logo-godx-size, var(--logo-godx-size-md));
69
+ height: var(--logo-godx-size, var(--logo-godx-size-md));
52
70
  border-radius: 0;
53
71
  background: transparent;
54
- color: hsl(var(--logo-godx-color, var(--success)));
72
+ color: hsl(var(--logo-godx-color, var(--brand)));
73
+ }
74
+
75
+ .ui-logo[data-mark="godx"][data-size="xs"] {
76
+ width: var(--logo-godx-size, var(--logo-godx-size-xs));
77
+ height: var(--logo-godx-size, var(--logo-godx-size-xs));
78
+ }
79
+
80
+ .ui-logo[data-mark="godx"][data-size="sm"] {
81
+ width: var(--logo-godx-size, var(--logo-godx-size-sm));
82
+ height: var(--logo-godx-size, var(--logo-godx-size-sm));
83
+ }
84
+
85
+ .ui-logo[data-mark="godx"][data-size="lg"] {
86
+ width: var(--logo-godx-size, var(--logo-godx-size-lg));
87
+ height: var(--logo-godx-size, var(--logo-godx-size-lg));
55
88
  }
56
89
 
57
90
  .ui-logo[data-mark="godx"] [data-slot="logo-artwork"] {
@@ -95,9 +128,9 @@
95
128
  font-size: var(--logo-wordmark-font-size-lg);
96
129
  }
97
130
 
98
- /* Canonical brand-green GoDX wordmark — the identity role, independent of --primary. */
131
+ /* Canonical GoDX wordmark — the --brand IDENTITY role, independent of --primary AND of --success. */
99
132
  .ui-logo-lockup[data-mark="godx"] .ui-logo-wordmark,
100
133
  .ui-logo-lockup[data-tone="success"] .ui-logo-wordmark {
101
- color: hsl(var(--logo-wordmark-color, var(--logo-godx-color, var(--success))));
134
+ color: hsl(var(--logo-wordmark-color, var(--logo-godx-color, var(--brand))));
102
135
  }
103
136
  }
@@ -49,6 +49,45 @@
49
49
  scrollbar-width: thin;
50
50
  }
51
51
 
52
+ /* Tabs `line` — the ACTIVE decoration is a token-owned bar and nothing else (gh#248). It is
53
+ * deliberately painted here (not as an `after:*` utility) so it stays independent of the
54
+ * `:focus-visible` ring utilities: "selected" and "keyboard-focused" are two different states and
55
+ * must remain visually distinct (WCAG 2.4.7). Logical insets keep the vertical rail on the
56
+ * inline-END edge under dir="rtl" too. */
57
+ [data-slot="tabs-list"][data-variant="line"] [data-slot="tabs-trigger"]::after {
58
+ content: "";
59
+ position: absolute;
60
+ background: var(--tabs-indicator-background, hsl(var(--primary)));
61
+ opacity: 0;
62
+ transition: opacity var(--duration-fast) var(--ease-standard);
63
+ pointer-events: none;
64
+ }
65
+
66
+ [data-slot="tabs-list"][data-variant="line"][data-orientation="horizontal"]
67
+ [data-slot="tabs-trigger"]::after {
68
+ inset-inline: 0;
69
+ inset-block-end: calc(-1 * var(--tabs-indicator-offset));
70
+ block-size: var(--tabs-indicator-size);
71
+ }
72
+
73
+ [data-slot="tabs-list"][data-variant="line"][data-orientation="vertical"]
74
+ [data-slot="tabs-trigger"]::after {
75
+ inset-block: 0;
76
+ inset-inline-end: calc(-1 * var(--tabs-indicator-offset));
77
+ inline-size: var(--tabs-indicator-size);
78
+ }
79
+
80
+ [data-slot="tabs-list"][data-variant="line"]
81
+ [data-slot="tabs-trigger"][data-state="active"]::after {
82
+ opacity: 1;
83
+ }
84
+
85
+ @media (prefers-reduced-motion: reduce) {
86
+ [data-slot="tabs-list"][data-variant="line"] [data-slot="tabs-trigger"]::after {
87
+ transition: none;
88
+ }
89
+ }
90
+
52
91
  .ui-context-menu-content {
53
92
  z-index: 50;
54
93
  min-width: 10rem;
@@ -320,3 +359,73 @@
320
359
  transform-origin: center;
321
360
  }
322
361
  }
362
+
363
+ @layer components {
364
+ .ui-steps-inline {
365
+ display: flex;
366
+ width: 100%;
367
+ flex-wrap: wrap;
368
+ align-items: center;
369
+ justify-content: center;
370
+ gap: var(--steps-inline-gap);
371
+ font-size: var(--steps-inline-font-size);
372
+ line-height: var(--line-height-tight);
373
+ }
374
+
375
+ .ui-steps-inline-item {
376
+ display: inline-flex;
377
+ min-width: 0;
378
+ flex: 0 1 auto;
379
+ align-items: center;
380
+ gap: var(--steps-inline-gap);
381
+ text-align: start;
382
+ }
383
+
384
+ .ui-steps-inline-control {
385
+ display: inline-flex;
386
+ min-width: 0;
387
+ align-items: center;
388
+ gap: var(--steps-inline-item-gap);
389
+ border-radius: var(--radius-sm);
390
+ outline: none;
391
+ }
392
+
393
+ button.ui-steps-inline-control:focus-visible {
394
+ box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
395
+ }
396
+
397
+ .ui-steps-inline-index {
398
+ flex: none;
399
+ font-variant-numeric: tabular-nums;
400
+ font-weight: var(--font-weight-bold);
401
+ }
402
+
403
+ .ui-steps-inline-title {
404
+ min-width: 0;
405
+ overflow-wrap: anywhere;
406
+ }
407
+
408
+ .ui-steps-inline-item[data-status="finish"] .ui-steps-inline-control {
409
+ color: hsl(var(--primary));
410
+ }
411
+
412
+ .ui-steps-inline-item[data-status="process"] .ui-steps-inline-control {
413
+ color: hsl(var(--foreground));
414
+ font-weight: var(--font-weight-medium);
415
+ }
416
+
417
+ .ui-steps-inline-item[data-status="error"] .ui-steps-inline-control {
418
+ color: hsl(var(--destructive));
419
+ }
420
+
421
+ .ui-steps-inline-item[data-status="wait"] .ui-steps-inline-control,
422
+ .ui-steps-inline-separator {
423
+ color: hsl(var(--muted-foreground));
424
+ }
425
+
426
+ .ui-steps-inline-separator {
427
+ width: var(--steps-inline-separator-size);
428
+ height: var(--steps-inline-separator-size);
429
+ flex: none;
430
+ }
431
+ }