@godxjp/ui 16.10.0 → 17.0.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.
Files changed (62) hide show
  1. package/README.md +30 -5
  2. package/dist/components/charts/chart-cartesian.js +1 -6
  3. package/dist/components/charts/pie-chart.js +1 -8
  4. package/dist/components/data-display/empty-state.d.ts +1 -1
  5. package/dist/components/data-display/empty-state.js +25 -7
  6. package/dist/components/data-entry/form-field.js +13 -4
  7. package/dist/components/data-entry/search-select.d.ts +1 -1
  8. package/dist/components/data-entry/search-select.js +97 -19
  9. package/dist/components/data-entry/select.js +15 -4
  10. package/dist/components/feedback/alert.d.ts +11 -2
  11. package/dist/components/feedback/alert.js +51 -9
  12. package/dist/components/general/button.js +2 -0
  13. package/dist/components/general/index.d.ts +2 -0
  14. package/dist/components/general/index.js +2 -0
  15. package/dist/components/general/reveal.d.ts +14 -0
  16. package/dist/components/general/reveal.js +21 -0
  17. package/dist/components/layout/auth-shell.d.ts +11 -0
  18. package/dist/components/layout/auth-shell.js +15 -0
  19. package/dist/components/layout/flex.js +1 -1
  20. package/dist/components/layout/index.d.ts +2 -0
  21. package/dist/components/layout/index.js +2 -0
  22. package/dist/components/layout/page-container.js +4 -4
  23. package/dist/components/navigation/app-setting-picker.js +19 -4
  24. package/dist/components/navigation/pagination.d.ts +1 -1
  25. package/dist/components/navigation/pagination.js +2 -1
  26. package/dist/components/query/data-state.d.ts +1 -1
  27. package/dist/components/query/data-state.js +27 -4
  28. package/dist/components/query/index.d.ts +2 -0
  29. package/dist/components/query/index.js +4 -1
  30. package/dist/i18n/messages/en.json +30 -2
  31. package/dist/i18n/messages/ja.json +30 -2
  32. package/dist/i18n/messages/vi.json +30 -2
  33. package/dist/lib/query-error.d.ts +17 -0
  34. package/dist/lib/query-error.js +58 -0
  35. package/dist/props/components/app.prop.d.ts +9 -1
  36. package/dist/props/components/data-display.prop.d.ts +15 -0
  37. package/dist/props/components/data-entry.prop.d.ts +8 -0
  38. package/dist/props/components/feedback.prop.d.ts +6 -0
  39. package/dist/props/components/general.prop.d.ts +23 -1
  40. package/dist/props/components/layout.prop.d.ts +17 -0
  41. package/dist/props/components/query.prop.d.ts +7 -1
  42. package/dist/props/registry.d.ts +31 -2
  43. package/dist/props/registry.js +44 -2
  44. package/dist/props/vocabulary/index.d.ts +1 -1
  45. package/dist/props/vocabulary/interaction.prop.d.ts +17 -1
  46. package/dist/styles/alert-layout.css +1 -2
  47. package/dist/styles/base.css +1 -1
  48. package/dist/styles/card-layout.css +6 -6
  49. package/dist/styles/index.css +1 -0
  50. package/dist/styles/layout.css +28 -0
  51. package/dist/styles/motion.css +52 -0
  52. package/dist/styles/shell-layout.css +42 -0
  53. package/dist/styles/text-layout.css +1 -1
  54. package/dist/theme/famgia.service.css +15 -14
  55. package/dist/tokens/components/card.css +1 -1
  56. package/dist/tokens/components/feedback.css +4 -0
  57. package/dist/tokens/components/shell.css +10 -0
  58. package/dist/tokens/foundation.css +11 -5
  59. package/package.json +7 -3
  60. package/scripts/ui-audit.mjs +2 -2
  61. package/scripts/visual-audit-rules.mjs +2 -2
  62. package/scripts/visual-audit.mjs +293 -126
@@ -8,13 +8,19 @@ import type { ClassNameProp, HandlerProp } from "../vocabulary/index.js";
8
8
  export type DataStateProp<T> = {
9
9
  query: UseQueryResult<T>;
10
10
  skeleton: React.ReactNode;
11
+ /** Rendered when a query is disabled/unstarted (`fetchStatus: "idle"` with no data). */
12
+ prerequisite?: React.ReactNode;
11
13
  empty?: React.ReactNode;
12
14
  isEmpty?: (data: NonNullable<T>) => boolean;
13
15
  errorRenderer?: (error: unknown, retry: () => void) => React.ReactNode;
14
- /** Default error UI retry button. Default `true`. */
16
+ /** Force the Retry affordance even for non-transient causes. Retry is offered automatically for
17
+ * transient/network/5xx errors regardless of this flag; default `false` for all other causes. */
15
18
  showRetry?: boolean;
16
19
  /** Default `() => query.refetch()`. */
17
20
  onRetry?: HandlerProp;
21
+ /** Recovery for authentication errors (401 / expired token): renew the session or sign in again.
22
+ * When provided, a 401 renders this action instead of Retry. */
23
+ onAuthError?: HandlerProp;
18
24
  children: (data: NonNullable<T>) => React.ReactNode;
19
25
  };
20
26
  type MutationLike = Pick<UseMutationResult<unknown, unknown, unknown, unknown>, "isError" | "error" | "isPending">;
@@ -209,6 +209,11 @@ export declare const VOCABULARY_REGISTRY: {
209
209
  readonly category: "interaction";
210
210
  readonly description: "Badge visual variant (default | secondary | outline | dashed)";
211
211
  };
212
+ readonly AppSettingPickerAppearanceProp: {
213
+ readonly file: "vocabulary/interaction.prop.ts";
214
+ readonly category: "interaction";
215
+ readonly description: "AppSettingPicker trigger presentation: labeled (icon + value) | icon (square icon-only topbar trigger)";
216
+ };
212
217
  readonly ShapeProp: {
213
218
  readonly file: "vocabulary/interaction.prop.ts";
214
219
  readonly category: "interaction";
@@ -289,6 +294,11 @@ export declare const VOCABULARY_REGISTRY: {
289
294
  readonly category: "interaction";
290
295
  readonly description: "Active table sort";
291
296
  };
297
+ readonly RevealDelayProp: {
298
+ readonly file: "vocabulary/interaction.prop.ts";
299
+ readonly category: "interaction";
300
+ readonly description: "Reveal entrance-stagger ordinal (0..6) — an index into the motion ladder, never a raw ms";
301
+ };
292
302
  readonly BreadcrumbItemProp: {
293
303
  readonly file: "vocabulary/navigation.prop.ts";
294
304
  readonly category: "navigation";
@@ -380,7 +390,7 @@ export declare const COMPONENT_PROP_REGISTRY: {
380
390
  readonly AppSettingPickerProp: {
381
391
  readonly group: "app";
382
392
  readonly file: "components/app.prop.ts";
383
- readonly vocabulary: readonly ["ValueProp", "OnValueChangeProp", "DisabledProp", "IdProp", "ClassNameProp"];
393
+ readonly vocabulary: readonly ["ValueProp", "OnValueChangeProp", "DisabledProp", "IdProp", "ClassNameProp", "AppSettingPickerAppearanceProp"];
384
394
  };
385
395
  readonly PageContainerProp: {
386
396
  readonly group: "layout";
@@ -438,6 +448,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
438
448
  readonly file: "components/layout.prop.ts";
439
449
  readonly vocabulary: readonly ["ChildrenProp"];
440
450
  };
451
+ readonly AuthShellProp: {
452
+ readonly group: "layout";
453
+ readonly file: "components/layout.prop.ts";
454
+ readonly vocabulary: readonly ["ChildrenProp", "ClassNameProp"];
455
+ };
441
456
  readonly SidebarProductProp: {
442
457
  readonly group: "layout";
443
458
  readonly file: "components/layout.prop.ts";
@@ -468,6 +483,15 @@ export declare const COMPONENT_PROP_REGISTRY: {
468
483
  readonly file: "components/general.prop.ts";
469
484
  readonly vocabulary: readonly ["ButtonVariantProp", "SizeProp", "ShapeProp", "AsChildProp", "DisabledProp", "OnClickProp", "PendingProp"];
470
485
  };
486
+ readonly RevealProp: {
487
+ readonly group: "general";
488
+ readonly file: "components/general.prop.ts";
489
+ readonly vocabulary: readonly ["ChildrenProp", "RevealDelayProp", "AsChildProp", "ClassNameProp", {
490
+ readonly field: "delay";
491
+ readonly local: true;
492
+ readonly reason: "Reveal stagger ordinal — RevealDelayProp vocabulary.";
493
+ }];
494
+ };
471
495
  readonly TextProp: {
472
496
  readonly group: "general";
473
497
  readonly file: "components/general.prop.ts";
@@ -663,7 +687,12 @@ export declare const COMPONENT_PROP_REGISTRY: {
663
687
  readonly EmptyStateProp: {
664
688
  readonly group: "data-display";
665
689
  readonly file: "components/data-display.prop.ts";
666
- readonly vocabulary: readonly ["IconProp", "TitleProp", "DescriptionProp", "ActionProp"];
690
+ readonly vocabulary: readonly ["IconProp", "TitleProp", "DescriptionProp", "ActionProp", "ToneProp"];
691
+ };
692
+ readonly EmptyStateToneProp: {
693
+ readonly group: "data-display";
694
+ readonly file: "components/data-display.prop.ts";
695
+ readonly vocabulary: readonly [];
667
696
  };
668
697
  readonly DescriptionsProp: {
669
698
  readonly group: "data-display";
@@ -208,6 +208,11 @@ const VOCABULARY_REGISTRY = {
208
208
  category: "interaction",
209
209
  description: "Badge visual variant (default | secondary | outline | dashed)"
210
210
  },
211
+ AppSettingPickerAppearanceProp: {
212
+ file: "vocabulary/interaction.prop.ts",
213
+ category: "interaction",
214
+ description: "AppSettingPicker trigger presentation: labeled (icon + value) | icon (square icon-only topbar trigger)"
215
+ },
211
216
  ShapeProp: {
212
217
  file: "vocabulary/interaction.prop.ts",
213
218
  category: "interaction",
@@ -288,6 +293,11 @@ const VOCABULARY_REGISTRY = {
288
293
  category: "interaction",
289
294
  description: "Active table sort"
290
295
  },
296
+ RevealDelayProp: {
297
+ file: "vocabulary/interaction.prop.ts",
298
+ category: "interaction",
299
+ description: "Reveal entrance-stagger ordinal (0..6) \u2014 an index into the motion ladder, never a raw ms"
300
+ },
291
301
  // navigation.prop.ts
292
302
  BreadcrumbItemProp: {
293
303
  file: "vocabulary/navigation.prop.ts",
@@ -376,7 +386,14 @@ const COMPONENT_PROP_REGISTRY = {
376
386
  AppSettingPickerProp: {
377
387
  group: "app",
378
388
  file: "components/app.prop.ts",
379
- vocabulary: ["ValueProp", "OnValueChangeProp", "DisabledProp", "IdProp", "ClassNameProp"]
389
+ vocabulary: [
390
+ "ValueProp",
391
+ "OnValueChangeProp",
392
+ "DisabledProp",
393
+ "IdProp",
394
+ "ClassNameProp",
395
+ "AppSettingPickerAppearanceProp"
396
+ ]
380
397
  },
381
398
  PageContainerProp: {
382
399
  group: "layout",
@@ -416,6 +433,11 @@ const COMPONENT_PROP_REGISTRY = {
416
433
  file: "components/layout.prop.ts",
417
434
  vocabulary: ["ChildrenProp"]
418
435
  },
436
+ AuthShellProp: {
437
+ group: "layout",
438
+ file: "components/layout.prop.ts",
439
+ vocabulary: ["ChildrenProp", "ClassNameProp"]
440
+ },
419
441
  SidebarProductProp: {
420
442
  group: "layout",
421
443
  file: "components/layout.prop.ts",
@@ -454,6 +476,21 @@ const COMPONENT_PROP_REGISTRY = {
454
476
  "PendingProp"
455
477
  ]
456
478
  },
479
+ RevealProp: {
480
+ group: "general",
481
+ file: "components/general.prop.ts",
482
+ vocabulary: [
483
+ "ChildrenProp",
484
+ "RevealDelayProp",
485
+ "AsChildProp",
486
+ "ClassNameProp",
487
+ {
488
+ field: "delay",
489
+ local: true,
490
+ reason: "Reveal stagger ordinal \u2014 RevealDelayProp vocabulary."
491
+ }
492
+ ]
493
+ },
457
494
  TextProp: {
458
495
  group: "general",
459
496
  file: "components/general.prop.ts",
@@ -705,7 +742,12 @@ const COMPONENT_PROP_REGISTRY = {
705
742
  EmptyStateProp: {
706
743
  group: "data-display",
707
744
  file: "components/data-display.prop.ts",
708
- vocabulary: ["IconProp", "TitleProp", "DescriptionProp", "ActionProp"]
745
+ vocabulary: ["IconProp", "TitleProp", "DescriptionProp", "ActionProp", "ToneProp"]
746
+ },
747
+ EmptyStateToneProp: {
748
+ group: "data-display",
749
+ file: "components/data-display.prop.ts",
750
+ vocabulary: []
709
751
  },
710
752
  DescriptionsProp: {
711
753
  group: "data-display",
@@ -2,6 +2,6 @@
2
2
  export type { ClassNameProp, ChildrenProp, IdProp, OpenProp, DefaultOpenProp, OnOpenChangeProp, HandlerProp, PendingProp, RequiredProp, DisabledProp, LabelProp, HelperProp, ErrorProp, PlaceholderProp, NameProp, ValueProp, DefaultValueProp, OnValueChangeProp, OnChangeProp, OnClickProp, AsChildProp, WidthProp, } from "./shared.prop.js";
3
3
  export type { TitleProp, SubtitleProp, DescriptionProp, ExtraProp, FooterProp, ActionProp, IconProp, ConfirmLabelProp, CancelLabelProp, ActionsProp, EmptyMessageProp, } from "./content.prop.js";
4
4
  export type { PageDensityProp, PageContainerVariantProp, TableDensityProp, DensityProp, GapProp, } from "./layout.prop.js";
5
- export type { ButtonVariantProp, ButtonSizeProp, BadgeVariantProp, ShapeProp, TextSizeProp, TextToneProp, FontWeightProp, HeadingLevelProp, TextAlignProp, SizeProp, FormLayoutProp, BreakpointProp, ConfirmVariantProp, ToneProp, AlertVariantProp, SortDirectionProp, ColumnAlignProp, SortStateProp, } from "./interaction.prop.js";
5
+ export type { ButtonVariantProp, ButtonSizeProp, BadgeVariantProp, AppSettingPickerAppearanceProp, ShapeProp, TextSizeProp, TextToneProp, FontWeightProp, HeadingLevelProp, TextAlignProp, SizeProp, FormLayoutProp, BreakpointProp, ConfirmVariantProp, ToneProp, AlertVariantProp, SortDirectionProp, ColumnAlignProp, SortStateProp, RevealDelayProp, } from "./interaction.prop.js";
6
6
  export type { BreadcrumbItemProp, BreadcrumbProp } from "./navigation.prop.js";
7
7
  export type { GetRowIdProp, OnRowClickProp, ColumnDefProp, SelectedIdsProp, OnSelectChangeProp, OnTableDensityChangeProp, OnSortChangeProp, OnSearchChangeProp, OnClearFiltersProp, HasActiveFiltersProp, } from "./data.prop.js";
@@ -11,7 +11,7 @@ export type ShapeProp = "default" | "pill" | "sharp";
11
11
  export type TextSizeProp = "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
12
12
  /** Text colour intent — maps to semantic foreground tokens (no raw palette). */
13
13
  export type TextToneProp = "default" | "muted" | "primary" | "success" | "warning" | "destructive" | "info";
14
- /** Font weight — the dxs-kintai canon is THREE weights only: `regular` (400 body), `medium` (500
14
+ /** Font weight — the reference-design canon is THREE weights only: `regular` (400 body), `medium` (500
15
15
  * heading/label), `bold` (700 emphasis). 600/`semibold` is forbidden. */
16
16
  export type FontWeightProp = "regular" | "medium" | "bold";
17
17
  /** Heading level — drives both the `--heading-h*` size token and the semantic `<h1..h4>` element. */
@@ -20,6 +20,16 @@ export type HeadingLevelProp = 1 | 2 | 3 | 4;
20
20
  export type TextAlignProp = "start" | "center" | "end";
21
21
  /** Badge visual style. */
22
22
  export type BadgeVariantProp = "default" | "secondary" | "outline" | "dashed";
23
+ /**
24
+ * AppSettingPicker trigger presentation.
25
+ * - `labeled` (default) — the leading icon + the selected value inside a full-width control
26
+ * (settings forms, preference panels).
27
+ * - `icon` — a square, icon-only utility trigger (e.g. a topbar globe locale switcher). It
28
+ * STRUCTURALLY drops the value text and the picker's owned trigger width, keeping the localized
29
+ * `aria-label`, focus ring, keyboard behaviour and a `--control-height` tap target (which is
30
+ * ≥44px on coarse/touch pointers per Rule #24) — so consumers never hide internal nodes via CSS.
31
+ */
32
+ export type AppSettingPickerAppearanceProp = "labeled" | "icon";
23
33
  /** Button size preset. */
24
34
  export type SizeProp = "xs" | "sm" | "md" | "lg";
25
35
  /** Button size preset; icon-only sizes are a documented Button subset. */
@@ -46,3 +56,9 @@ export type SortStateProp = {
46
56
  key: string;
47
57
  direction: SortDirectionProp;
48
58
  };
59
+ /**
60
+ * Entrance-stagger ordinal for `Reveal` — an INDEX into the motion ladder, never a raw ms.
61
+ * `0` = enter immediately; `1..6` each add one `--reveal-stagger-step` of delay so a column of
62
+ * revealed rows cascades in. Reduced-motion collapses every step to 0 (content stays visible).
63
+ */
64
+ export type RevealDelayProp = 0 | 1 | 2 | 3 | 4 | 5 | 6;
@@ -107,8 +107,7 @@
107
107
  grid-column: 1;
108
108
  }
109
109
 
110
- [data-slot="alert-body"]:has(> [data-slot="alert-actions"])
111
- > [data-slot="alert-actions"] {
110
+ [data-slot="alert-body"]:has(> [data-slot="alert-actions"]) > [data-slot="alert-actions"] {
112
111
  grid-column: 2;
113
112
  grid-row: 1;
114
113
  }
@@ -218,7 +218,7 @@
218
218
 
219
219
  /* Semantic heading scale — SEO + accessibility: real <h1>–<h6> elements carry
220
220
  * the document outline (one <h1> per page, levels never skipped). Visual size
221
- * follows the dxs-kintai scale; component titles override via their own class.
221
+ * follows the reference-design scale; component titles override via their own class.
222
222
  * Headings read --font-family-display (defaults to --font-family-sans → unchanged) for dual-font
223
223
  * brands (display face on headings, body face on prose). */
224
224
  :where(h1, h2, h3, h4, h5, h6) {
@@ -34,8 +34,7 @@
34
34
  * --card-background defaults to the LIVE --card role at the call site (re-resolves under a
35
35
  * scoped theme); a service overrides --card-background to win. */
36
36
  background:
37
- linear-gradient(var(--card-tint), var(--card-tint)),
38
- hsl(var(--card-background, var(--card)));
37
+ linear-gradient(var(--card-tint), var(--card-tint)), hsl(var(--card-background, var(--card)));
39
38
  color: hsl(var(--card-foreground));
40
39
  /* Resting elevation + opt-in brand glow — both quiet no-ops by default so a service theme can
41
40
  * lift (--card-shadow) and/or glow (--card-glow) every card with no markup change. */
@@ -100,9 +99,7 @@
100
99
  [data-slot="card"][data-accent] > [data-slot="card-header"],
101
100
  [data-slot="card"][data-accent] > [data-slot="card-content"]:not([data-flush]),
102
101
  [data-slot="card"][data-accent] > [data-slot="card-footer"]:not([data-flush]) {
103
- padding-inline-start: calc(
104
- var(--card-space-inset) - var(--card-accent-rail-width)
105
- );
102
+ padding-inline-start: calc(var(--card-space-inset) - var(--card-accent-rail-width));
106
103
  }
107
104
 
108
105
  /* ── Header ──────────────────────────────────────────────────────────── */
@@ -156,7 +153,10 @@
156
153
  }
157
154
 
158
155
  .ui-card-header--banded {
159
- border-bottom: var(--card-header-border-bottom, 1px solid hsl(var(--card-border, var(--border))));
156
+ border-bottom: var(
157
+ --card-header-border-bottom,
158
+ 1px solid hsl(var(--card-border, var(--border)))
159
+ );
160
160
  background-color: hsl(
161
161
  var(--card-header-background, var(--muted)) / var(--card-header-background-alpha)
162
162
  );
@@ -15,6 +15,7 @@
15
15
  @import "./fonts.css";
16
16
  @import "./base.css";
17
17
  @import "./shell-layout.css";
18
+ @import "./motion.css";
18
19
  @import "./layout.css";
19
20
  @import "./control.css";
20
21
  @import "./logo-layout.css";
@@ -46,6 +46,15 @@
46
46
  flex-direction: column;
47
47
  }
48
48
 
49
+ .ui-empty-state[data-variant="section"] {
50
+ padding: var(--empty-state-section-space-y) var(--empty-state-section-space-x);
51
+ }
52
+
53
+ .ui-empty-state[data-variant="compact"] {
54
+ padding: var(--empty-state-compact-space-y) var(--empty-state-compact-space-x);
55
+ gap: var(--space-stack-xs);
56
+ }
57
+
49
58
  .ui-flex[data-wrap="true"] {
50
59
  flex-wrap: wrap;
51
60
  }
@@ -512,6 +521,25 @@
512
521
  background-color: var(--empty-state-icon-tint, hsl(var(--muted)));
513
522
  color: var(--empty-state-icon-foreground, hsl(var(--muted-foreground)));
514
523
  }
524
+
525
+ /* tone — set the medallion foreground + tint from the matching role token, so a consumer never
526
+ * hand-rolls a `.ui-success-state` class. `muted` (default) keeps the neutral role fallback. */
527
+ .ui-empty-state[data-tone="success"] {
528
+ --empty-state-icon-foreground: hsl(var(--success));
529
+ --empty-state-icon-tint: hsl(var(--success) / 0.12);
530
+ }
531
+ .ui-empty-state[data-tone="warning"] {
532
+ --empty-state-icon-foreground: hsl(var(--warning));
533
+ --empty-state-icon-tint: hsl(var(--warning) / 0.12);
534
+ }
535
+ .ui-empty-state[data-tone="destructive"] {
536
+ --empty-state-icon-foreground: hsl(var(--destructive));
537
+ --empty-state-icon-tint: hsl(var(--destructive) / 0.12);
538
+ }
539
+ .ui-empty-state[data-tone="info"] {
540
+ --empty-state-icon-foreground: hsl(var(--info));
541
+ --empty-state-icon-tint: hsl(var(--info) / 0.12);
542
+ }
515
543
  }
516
544
 
517
545
  @layer components {
@@ -0,0 +1,52 @@
1
+ /*
2
+ * MOTION — entrance/reveal animation for the `Reveal` primitive.
3
+ * Reads the DS motion tokens (--duration-slow / --ease-emphasized / --reveal-distance) instead of
4
+ * a hand-rolled @keyframes, and staggers via the --reveal-stagger-step ladder. Under
5
+ * prefers-reduced-motion the animation is dropped: content renders in its final, fully-visible
6
+ * position with no transform and no layout shift.
7
+ */
8
+
9
+ @layer components {
10
+ .ui-reveal {
11
+ animation: ui-reveal-in var(--duration-slow) var(--ease-emphasized) both;
12
+ will-change: transform, opacity;
13
+ }
14
+
15
+ .ui-reveal[data-reveal-delay="1"] {
16
+ animation-delay: calc(var(--reveal-stagger-step) * 1);
17
+ }
18
+ .ui-reveal[data-reveal-delay="2"] {
19
+ animation-delay: calc(var(--reveal-stagger-step) * 2);
20
+ }
21
+ .ui-reveal[data-reveal-delay="3"] {
22
+ animation-delay: calc(var(--reveal-stagger-step) * 3);
23
+ }
24
+ .ui-reveal[data-reveal-delay="4"] {
25
+ animation-delay: calc(var(--reveal-stagger-step) * 4);
26
+ }
27
+ .ui-reveal[data-reveal-delay="5"] {
28
+ animation-delay: calc(var(--reveal-stagger-step) * 5);
29
+ }
30
+ .ui-reveal[data-reveal-delay="6"] {
31
+ animation-delay: calc(var(--reveal-stagger-step) * 6);
32
+ }
33
+
34
+ @keyframes ui-reveal-in {
35
+ from {
36
+ opacity: 0;
37
+ transform: translateY(var(--reveal-distance));
38
+ }
39
+ to {
40
+ opacity: 1;
41
+ transform: none;
42
+ }
43
+ }
44
+
45
+ /* Accessibility: no motion → no animation, content stays visible (WCAG 2.3.3 / 2.2.2). */
46
+ @media (prefers-reduced-motion: reduce) {
47
+ .ui-reveal,
48
+ .ui-reveal[data-reveal-delay] {
49
+ animation: none;
50
+ }
51
+ }
52
+ }
@@ -81,6 +81,48 @@
81
81
  max-width: none;
82
82
  }
83
83
 
84
+ /*
85
+ * AUTH SHELL — centred auth/login page shell (brand bar + centred card + footer).
86
+ * Comfortable control density + a larger auth heading are scoped to the shell so login/mfa/reset
87
+ * forms read at the right size without a consumer scope class. Everything reads a token knob.
88
+ */
89
+ .ui-auth-shell {
90
+ --control-height: var(--auth-shell-control-height);
91
+ --heading-h1: var(--auth-shell-heading-size);
92
+ display: flex;
93
+ min-height: 100dvh;
94
+ flex-direction: column;
95
+ background:
96
+ linear-gradient(180deg, hsl(var(--primary) / 0.035), transparent 14rem),
97
+ hsl(var(--background));
98
+ }
99
+
100
+ .ui-auth-shell-bar {
101
+ display: flex;
102
+ align-items: center;
103
+ padding: var(--auth-shell-bar-padding);
104
+ }
105
+
106
+ .ui-auth-shell-main {
107
+ display: flex;
108
+ flex: 1 1 auto;
109
+ flex-direction: column;
110
+ align-items: center;
111
+ justify-content: center;
112
+ padding: var(--auth-shell-main-padding);
113
+ }
114
+
115
+ .ui-auth-shell-card {
116
+ width: 100%;
117
+ max-width: var(--auth-shell-card-max-width);
118
+ }
119
+
120
+ .ui-auth-shell-footer {
121
+ padding: var(--auth-shell-footer-padding);
122
+ text-align: center;
123
+ color: hsl(var(--muted-foreground));
124
+ }
125
+
84
126
  .app-topbar-rail {
85
127
  display: flex;
86
128
  min-width: 0;
@@ -33,7 +33,7 @@
33
33
  font-size: var(--font-size-2xl);
34
34
  }
35
35
 
36
- /* Weight — the dxs-kintai canon (400 body · 500 heading/label · 700 emphasis). No 600.
36
+ /* Weight — the reference-design canon (400 body · 500 heading/label · 700 emphasis). No 600.
37
37
  * Shared by text + heading; the two-attribute heading selectors outrank the base heading
38
38
  * rule below, so `<Heading weight="bold">` renders a semantic, emphasised title. */
39
39
  [data-slot="text"][data-weight="regular"],
@@ -11,33 +11,34 @@
11
11
  /* ── Light (default) ── */
12
12
  :root {
13
13
  /* Brand primary ramp — electric blue */
14
- --primary: 221 83% 53%; /* #2563EB */
14
+ --primary: 221 83% 53%; /* #2563EB */
15
15
  --primary-foreground: 0 0% 100%;
16
- --primary-hover: 224 71% 48%; /* #1D4ED8 */
17
- --primary-active: 226 71% 40%; /* #1E40AF */
18
- --ring: 221 83% 53%;
16
+ --primary-hover: 224 71% 48%; /* #1D4ED8 */
17
+ --primary-active: 226 71% 40%; /* #1E40AF */
18
+ --ring: 221 83% 53%;
19
19
 
20
20
  /* Brand-colored text (AA on tint/white) */
21
- --text-link: 224 76% 45%;
22
- --text-brand: 221 83% 53%;
21
+ --text-link: 224 76% 45%;
22
+ --text-brand: 221 83% 53%;
23
23
  --text-primary: 224 76% 42%;
24
24
 
25
25
  /* Signature brand gradient: blue → violet */
26
26
  --gradient-brand: linear-gradient(135deg, hsl(221 83% 53%), hsl(262 83% 58%));
27
27
 
28
28
  /* Typography — Inter (Latin/VI) + Noto Sans JP (kana/kanji) */
29
- --font-family-sans: "Inter", "Noto Sans JP", -apple-system, BlinkMacSystemFont,
30
- "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
29
+ --font-family-sans:
30
+ "Inter", "Noto Sans JP", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
31
+ "Helvetica Neue", Arial, sans-serif;
31
32
  }
32
33
 
33
34
  /* ── Dark ── lifted blue for contrast */
34
35
  .dark {
35
- --primary: 221 90% 66%;
36
+ --primary: 221 90% 66%;
36
37
  --primary-foreground: 222 47% 11%;
37
- --primary-hover: 221 90% 72%;
38
+ --primary-hover: 221 90% 72%;
38
39
  --primary-active: 221 90% 60%;
39
- --ring: 221 90% 66%;
40
- --text-link: 221 90% 72%;
41
- --text-brand: 221 90% 70%;
42
- --text-primary: 221 90% 68%;
40
+ --ring: 221 90% 66%;
41
+ --text-link: 221 90% 72%;
42
+ --text-brand: 221 90% 70%;
43
+ --text-primary: 221 90% 68%;
43
44
  }
@@ -43,7 +43,7 @@
43
43
  --card-header-border-bottom: initial;
44
44
  --card-radius: var(--radius);
45
45
  /* Resting elevation — quiet by default (rule #44): cards are flat (1px border, no shadow) in the
46
- * dxs-kintai baseline. A service that wants lifted cards sets this to an elevation token once,
46
+ * reference-design baseline. A service that wants lifted cards sets this to an elevation token once,
47
47
  * e.g. --card-shadow: var(--shadow-sm), and every Card picks up the shadow with no markup change. */
48
48
  --card-shadow: 0 0 0 0 transparent;
49
49
  /* Brand glow layer — invisible no-op at rest (rule #44). Paired AFTER --card-shadow in the
@@ -22,6 +22,10 @@
22
22
  --dialog-content-glow: 0 0 0 0 transparent;
23
23
  --empty-state-space-y: var(--space-10);
24
24
  --empty-state-space-x: var(--space-6);
25
+ --empty-state-section-space-y: var(--space-6);
26
+ --empty-state-section-space-x: var(--space-4);
27
+ --empty-state-compact-space-y: var(--space-3);
28
+ --empty-state-compact-space-x: var(--space-2);
25
29
  /* EmptyState icon medallion colour — `initial` so the role defaults re-resolve at the call site
26
30
  * under a scoped theme (rule #44). A service recolours the glyph (--empty-state-icon-foreground)
27
31
  * or washes the medallion fill (--empty-state-icon-tint) without forking.
@@ -32,4 +32,14 @@
32
32
  * Defaults = hsl(var(--accent)) fill · hsl(var(--foreground)) text. */
33
33
  --sidebar-item-active-background: initial;
34
34
  --sidebar-item-active-foreground: initial;
35
+
36
+ /* AuthShell — centred auth/login page shell. Comfortable control density (44px, WCAG touch floor)
37
+ * + a larger auth heading, scoped to the shell; a service re-tunes the auth card width, insets
38
+ * and heading size without forking. */
39
+ --auth-shell-control-height: var(--control-height-comfortable);
40
+ --auth-shell-heading-size: var(--font-size-2xl);
41
+ --auth-shell-card-max-width: 24rem;
42
+ --auth-shell-bar-padding: var(--space-5) var(--space-6);
43
+ --auth-shell-main-padding: var(--space-6);
44
+ --auth-shell-footer-padding: var(--space-3) var(--space-6) var(--space-4);
35
45
  }
@@ -1,7 +1,7 @@
1
1
  /* Foundation tokens: color, typography, raw spacing, ratio, radius, shadow. */
2
2
 
3
3
  :root {
4
- /* Color system (HSL components) — dxs-kintai: warm hue-60 neutral spine,
4
+ /* Color system (HSL components) — the reference design: warm hue-60 neutral spine,
5
5
  * SmartHR blue primary, 和色/wa-iro semantics. */
6
6
  --background: 60 33% 99%; /* #fdfdfb warm off-white */
7
7
  --foreground: 48 8% 13%; /* #23221e SmartHR TEXT_BLACK */
@@ -83,7 +83,8 @@
83
83
  --disabled-opacity: 0.5;
84
84
 
85
85
  /* Shape and elevation */
86
- --radius: calc(0.375rem * var(--scaling)); /* 6px base × scaling; override to retheme every step */
86
+ /* 6px base × scaling; override to retheme every radius step */
87
+ --radius: calc(0.375rem * var(--scaling));
87
88
  --radius-ratio: 1.618; /* φ — radii scale by the golden ratio (steps derive in @theme) */
88
89
  --radius-pill: 9999px; /* fully-round: switch / radio / slider / pill badges (NOT --radius-derived) */
89
90
  --radius-sharp: 0; /* squared corners: table cells, flush inputs */
@@ -202,7 +203,9 @@
202
203
  --font-size-3xl: calc(
203
204
  var(--font-size-display) / var(--font-size-display-ratio) / var(--font-size-display-ratio)
204
205
  ); /* ≈ 33 → 28px feature heading */
205
- --font-size-4xl: calc(var(--font-size-display) / var(--font-size-display-ratio)); /* ≈ 36px section */
206
+ --font-size-4xl: calc(
207
+ var(--font-size-display) / var(--font-size-display-ratio)
208
+ ); /* ≈ 36px section */
206
209
  --font-size-5xl: var(--font-size-display); /* 54px hero */
207
210
 
208
211
  /* Headings — also golden-derived. h1=ratio³, h2=ratio²; h3/h4 reuse body sizes (single source). */
@@ -217,7 +220,7 @@
217
220
 
218
221
  --font-weight-normal: 400;
219
222
  --font-weight-medium: 500;
220
- /* dxs-kintai uses three weights only: 400 body · 500 heading/label · 700 emphasis. 600 is
223
+ /* the reference design uses three weights only: 400 body · 500 heading/label · 700 emphasis. 600 is
221
224
  * forbidden (ambiguous between 500 and 700) — the legacy "semibold" token collapses to medium
222
225
  * so any remaining reference renders at 500. `bold` is the 700 emphasis weight. */
223
226
  --font-weight-semibold: 500;
@@ -322,7 +325,7 @@
322
325
 
323
326
  /* Motion — the primitive tier for animation, so enter/transition timing reads a token
324
327
  * instead of a literal 0.5s / cubic-bezier(...) / translateY(10px) (cardinal rule #2).
325
- * dxs-kintai keeps motion LOW: short durations, a calm decelerate curve, a small reveal shift.
328
+ * the reference design keeps motion LOW: short durations, a calm decelerate curve, a small reveal shift.
326
329
  * Consumers honour prefers-reduced-motion at the call site. */
327
330
  --duration-fast: 150ms;
328
331
  --duration-base: 250ms;
@@ -332,6 +335,9 @@
332
335
  --ease-decelerate: cubic-bezier(0, 0, 0, 1);
333
336
  --ease-accelerate: cubic-bezier(0.3, 0, 1, 1);
334
337
  --reveal-distance: 10px;
338
+ /* One step of the Reveal stagger ladder — `<Reveal delay={n}>` waits n × this before entering,
339
+ * so a column of reveals cascades. Read instead of a literal `.04s`/`.09s` per-item delay. */
340
+ --reveal-stagger-step: 60ms;
335
341
  }
336
342
 
337
343
  .dark,
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "16.10.0",
3
+ "version": "17.0.1",
4
+ "godxUiMcp": "17.0.0",
4
5
  "type": "module",
5
6
  "packageManager": "pnpm@10.29.1",
6
7
  "sideEffects": false,
@@ -275,8 +276,9 @@
275
276
  "test:watch": "vitest",
276
277
  "test:coverage": "vitest run --coverage",
277
278
  "check:example-imports": "node scripts/check-example-imports.mjs",
278
- "verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-token-sync && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:audit-sync && pnpm test",
279
- "verify:release": "pnpm build && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-token-sync && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm check:contrast && pnpm test",
279
+ "verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-token-sync && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:audit-sync && pnpm test",
280
+ "verify:release": "pnpm build && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-token-sync && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm check:contrast && pnpm check:visual-audit && pnpm test",
281
+ "check:mcp-lockstep": "node scripts/check-release-lockstep.mjs",
280
282
  "check:mcp-sync": "node scripts/check-mcp-sync.mjs",
281
283
  "check:mcp-orphans": "node scripts/check-mcp-orphans.mjs",
282
284
  "check:mcp-prop-sync": "node scripts/check-mcp-prop-sync.mjs",
@@ -288,6 +290,7 @@
288
290
  "gen:component-tokens": "node scripts/gen-component-tokens.mjs",
289
291
  "check:mcp-token-sync": "node scripts/gen-component-tokens.mjs --check",
290
292
  "check:core-isolation": "node scripts/check-core-isolation.mjs",
293
+ "check:no-consumer-coupling": "node scripts/check-no-consumer-coupling.mjs",
291
294
  "release": "node scripts/release.mjs",
292
295
  "preview": "node preview/scripts/kill-port.mjs && vite --config preview/vite.config.ts --port 6008 --strictPort",
293
296
  "preview:build": "vite build --config preview/vite.config.ts",
@@ -300,6 +303,7 @@
300
303
  "check:audit-sync": "node scripts/check-audit-sync.mjs",
301
304
  "check:contrast": "node scripts/check-contrast.mjs",
302
305
  "visual-audit": "node scripts/visual-audit.mjs",
306
+ "check:visual-audit": "node scripts/visual-audit-smoke.mjs",
303
307
  "postinstall": "node scripts/postinstall.mjs",
304
308
  "init-agent": "node scripts/init-agent-kit.mjs",
305
309
  "check:use-client": "node scripts/check-use-client.mjs"
@@ -281,9 +281,9 @@ const RULES = [
281
281
  {
282
282
  id: "no-em-dash-in-copy",
283
283
  severity: "warn",
284
- // Em-dash (U+2014) in JSX text — dxs-kintai uses the middot `·` for JP/EN pairs and calm copy.
284
+ // Em-dash (U+2014) in JSX text — the reference design uses the middot `·` for JP/EN pairs and calm copy.
285
285
  test: /[A-Za-z0-9぀-ヿ一-鿿]\s*—\s*[A-Za-z0-9぀-ヿ一-鿿]/,
286
- standard: "@godxjp/ui dxs-kintai typography (best-ux) · Unicode punctuation",
286
+ standard: "@godxjp/ui reference-design typography (best-ux) · Unicode punctuation",
287
287
  message:
288
288
  "No em-dash (—) in product copy. Use a middot `·` for JP/EN label pairs, or restructure into two calm sentences. Keep copy factual and quiet.",
289
289
  },