@godxjp/ui 18.2.0 → 18.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.
package/README.md CHANGED
@@ -70,7 +70,7 @@ Components emit `data-slot` / `data-*`; the look lives in `styles/*-layout.css`.
70
70
  | **Layout** | `@godxjp/ui/layout` | `Flex`, `PageContainer`, `ResponsiveGrid`, `AppShell`, `Sidebar`, `Separator`, `AspectRatio`, `Resizable` |
71
71
  | **General** | `@godxjp/ui/general` | `Button` |
72
72
  | **Data Entry** | `@godxjp/ui/data-entry` | `Input`, `Select`, `FormField`, `Field`, `DatePicker`, `TimePicker`, `Combobox`, `Switch`, `Toggle`, `Upload`, `Cascader`, `TreeSelect`, `ColorPicker`, `Slider`, `PasswordInput`, `PasswordStrength`, `InputOTP`, `Rating`, `TagInput` |
73
- | **Data Display** | `@godxjp/ui/data-display` | `Table`, `DataTable`, `Card`, `StatCard`, `Badge`, `Avatar`, `Descriptions`, `Timeline`, `EmptyState`, `Progress`, `Accordion`, `HoverCard`, `Carousel`, `Popover`, `Collapsible` |
73
+ | **Data Display** | `@godxjp/ui/data-display` | `Table`, `DataTable`, `Card`, `StatCard`, `Badge`, `Avatar`, `Descriptions`, `Timeline`, `EmptyState`, `Progress`, `QrCode`, `CredentialReveal`, `Accordion`, `HoverCard`, `Carousel`, `Popover`, `Collapsible` |
74
74
  | **Feedback** | `@godxjp/ui/feedback` | `Dialog`, `AlertDialog`, `Sheet` (side), `Drawer` (bottom-sheet), `Toast`, `Skeleton`, `Alert`, `Tooltip` |
75
75
  | **Query** | `@godxjp/ui/query` | `DataState`, `InfiniteQueryState`, `PrefetchLink` (adapter subpath — pulls TanStack Query) |
76
76
  | **Navigation** | `@godxjp/ui/navigation` | `Tabs`, `Toolbar`, `DropdownMenu`, `ContextMenu`, `Menubar`, `NavigationMenu`, `Steps`, `Pagination`, `Breadcrumb`, `AppSettingPicker` |
@@ -121,7 +121,7 @@ separate `@godxjp/ui/data-grid` (`DataGrid`) subpath has been merged in and remo
121
121
  ## Consumer setup — theme is self-contained
122
122
 
123
123
  The framework ships colors, the type scale, the wa-iro palette, and (opt-in)
124
- bundled fonts (Noto Sans JP + Montserrat via `@fontsource`). A consumer's entire
124
+ bundled fonts (M PLUS 2 + Noto Sans JP fallback via `@fontsource`). A consumer's entire
125
125
  styling surface is **one import + content sources** — no `:root` overrides, no
126
126
  font `<link>`:
127
127
 
@@ -4,6 +4,9 @@ export { ListRow } from "./list-row.js";
4
4
  export type { ListRowProps } from "./list-row.js";
5
5
  export { CredentialReveal } from "./credential-reveal.js";
6
6
  export type { CredentialRevealProp, CredentialRevealProps, CredentialRevealTone, } from "./credential-reveal.js";
7
+ export { QrCode } from "./qr-code.js";
8
+ export type { QrCodeProps } from "./qr-code.js";
9
+ export type { QrCodeProp } from "../../props/components/data-display.prop.js";
7
10
  export { Avatar, AvatarImage, AvatarFallback } from "./avatar.js";
8
11
  export { Card, CardBar, CardContent, CardCover, CardDescription, CardFooter, CardHeader, CardTitle, CardAction, StatCard, } from "./card.js";
9
12
  export type { StatCardProps, CardBarProps } from "./card.js";
@@ -1,6 +1,7 @@
1
1
  import { Badge } from "./badge.js";
2
2
  import { ListRow } from "./list-row.js";
3
3
  import { CredentialReveal } from "./credential-reveal.js";
4
+ import { QrCode } from "./qr-code.js";
4
5
  import { Avatar, AvatarImage, AvatarFallback } from "./avatar.js";
5
6
  import {
6
7
  Card,
@@ -86,6 +87,7 @@ export {
86
87
  PopoverTitle,
87
88
  PopoverTrigger,
88
89
  Progress,
90
+ QrCode,
89
91
  ScrollArea,
90
92
  ScrollBar,
91
93
  StatCard,
@@ -0,0 +1,8 @@
1
+ import * as React from "react";
2
+ import type { QrCodeProp } from "../../props/components/data-display.prop.js";
3
+ export type QrCodeProps = QrCodeProp & Omit<React.ComponentPropsWithoutRef<"svg">, keyof QrCodeProp | "children" | "role" | "style" | "type">;
4
+ /**
5
+ * Renders a QR code entirely in-process. The encoded value is never sent to a network service,
6
+ * written to an element attribute, or included in accessible text.
7
+ */
8
+ export declare const QrCode: React.ForwardRefExoticComponent<QrCodeProp & Omit<Omit<React.SVGProps<SVGSVGElement>, "ref">, "style" | "children" | "role" | "type" | keyof QrCodeProp> & React.RefAttributes<SVGSVGElement>>;
@@ -0,0 +1,34 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { QRCodeSVG } from "qrcode.react";
4
+ import { cn } from "../../lib/utils.js";
5
+ const QR_INTRINSIC_SIZE = 256;
6
+ const QrCode = React.forwardRef(
7
+ ({ value, label, size = "md", className, ...props }, ref) => {
8
+ return /* @__PURE__ */ jsx(
9
+ QRCodeSVG,
10
+ {
11
+ ref,
12
+ ...props,
13
+ value,
14
+ title: label,
15
+ size: QR_INTRINSIC_SIZE,
16
+ level: "M",
17
+ boostLevel: true,
18
+ marginSize: 4,
19
+ bgColor: "hsl(var(--qr-code-background))",
20
+ fgColor: "hsl(var(--qr-code-foreground))",
21
+ role: "img",
22
+ "aria-label": label,
23
+ focusable: "false",
24
+ "data-slot": "qr-code",
25
+ "data-size": size,
26
+ className: cn("ui-qr-code", className)
27
+ }
28
+ );
29
+ }
30
+ );
31
+ QrCode.displayName = "QrCode";
32
+ export {
33
+ QrCode
34
+ };
@@ -49,7 +49,7 @@ function AppShell({
49
49
  type: "button",
50
50
  variant: "ghost",
51
51
  size: "sm",
52
- className: "app-mobile-nav-trigger hidden max-lg:inline-flex",
52
+ className: "app-mobile-nav-trigger hidden max-[900px]:inline-flex",
53
53
  "aria-label": t("layout.appShell.openNav"),
54
54
  "aria-haspopup": "dialog",
55
55
  children: /* @__PURE__ */ jsx(Menu, { className: "size-5", "aria-hidden": "true" })
@@ -110,6 +110,17 @@ export type CredentialRevealProp = {
110
110
  id?: IdProp;
111
111
  "aria-label"?: string;
112
112
  };
113
+ /** @see QrCode */
114
+ export type QrCodeProp = {
115
+ /** Sensitive or public value encoded locally into the QR modules. */
116
+ value: string;
117
+ /** Purpose-specific accessible name. The encoded value is never used as accessible text. */
118
+ label: string;
119
+ /** Natural display size. Default `md`. */
120
+ size?: SizeProp;
121
+ className?: ClassNameProp;
122
+ id?: IdProp;
123
+ };
113
124
  /** @see DataTable */
114
125
  export type DataTableProp<T> = {
115
126
  data: T[];
@@ -1,7 +1,7 @@
1
1
  export type { AppShellProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
2
2
  export type { ButtonProp } from "./general.prop.js";
3
3
  export type { InputProp, TextareaProp, FormFieldProp, SearchInputProp, CheckboxProp, CheckboxGroupProp, ChoiceOptionProp, RadioProp, RadioGroupProp, SwitchProp, SliderProp, CalendarProp, DatePickerProp, DateRangePickerProp, TimePickerProp, ColorPickerProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
4
- export type { EmptyStateProp, DescriptionsProp, DescriptionsItemProp, BadgeProp, DataTableProp, } from "./data-display.prop.js";
4
+ export type { EmptyStateProp, DescriptionsProp, DescriptionsItemProp, BadgeProp, DataTableProp, QrCodeProp, } from "./data-display.prop.js";
5
5
  export type { ChartDatum, ChartSeriesProp, LineChartProp, BarChartProp, AreaChartProp, PieChartProp, } from "./charts.prop.js";
6
6
  export type { AlertQueryErrorProp, AlertProp, AlertTitleProp, AlertContentProp, AlertDescriptionProp, AlertActionsProp, SkeletonRowsProp, } from "./feedback.prop.js";
7
7
  export type { DataStateProp, InfiniteQueryStateProp, InfiniteQueryHelpers, PrefetchLinkProp, } from "./query.prop.js";
@@ -76,7 +76,7 @@ export type AppShellProp = {
76
76
  footer?: ReactNode;
77
77
  sidebarCollapsed?: boolean;
78
78
  /**
79
- * Navigation shown in the mobile drawer below the `lg` breakpoint, where the docked sidebar is
79
+ * Navigation shown in the mobile drawer at the DXS 900px breakpoint, where the docked sidebar is
80
80
  * hidden. AppShell OWNS the drawer: it renders a hamburger trigger in the topbar and a focus-
81
81
  * trapped Sheet (Esc + overlay close, focus returns to the trigger) — hiding the sidebar without
82
82
  * a reachable alternative is invalid (gh#165). Defaults to `sidebar`, so the same nav is
@@ -734,6 +734,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
734
734
  readonly file: "components/data-display.prop.ts";
735
735
  readonly vocabulary: readonly ["LabelProp", "SizeProp", "ToneProp", "OnValueChangeProp", "HandlerProp", "ClassNameProp", "IdProp"];
736
736
  };
737
+ readonly QrCodeProp: {
738
+ readonly group: "data-display";
739
+ readonly file: "components/data-display.prop.ts";
740
+ readonly vocabulary: readonly ["ValueProp", "LabelProp", "SizeProp", "ClassNameProp", "IdProp"];
741
+ };
737
742
  readonly ChartSeriesProp: {
738
743
  readonly group: "data-display";
739
744
  readonly file: "components/charts.prop.ts";
@@ -810,6 +810,11 @@ const COMPONENT_PROP_REGISTRY = {
810
810
  "IdProp"
811
811
  ]
812
812
  },
813
+ QrCodeProp: {
814
+ group: "data-display",
815
+ file: "components/data-display.prop.ts",
816
+ vocabulary: ["ValueProp", "LabelProp", "SizeProp", "ClassNameProp", "IdProp"]
817
+ },
813
818
  ChartSeriesProp: {
814
819
  group: "data-display",
815
820
  file: "components/charts.prop.ts",
@@ -27,7 +27,7 @@
27
27
  * base sans. Consumers switch a locale's face by setting its slot, e.g.
28
28
  * :root { --font-sans-ja: "Noto Sans JP", var(--font-sans-base); }
29
29
  * without writing any [lang] selectors. The opt-in bundle styles/fonts fills
30
- * these slots for its Noto Sans JP + Montserrat faces. `--font-sans-base` is a
30
+ * these slots for its M PLUS 2 + Noto Sans JP fallback. `--font-sans-base` is a
31
31
  * separate token (not --font-family-sans) so the fallback can't self-reference. */
32
32
  [lang="ja"] {
33
33
  --font-family-sans: var(--font-sans-ja, var(--font-sans-base));
@@ -42,7 +42,7 @@
42
42
  overflow: hidden;
43
43
  }
44
44
 
45
- /* ── Surface variants — fill only; flat at rest (border, no shadow) ──── */
45
+ /* ── Surface variants — fill only; retain the shared DXS surface elevation ──── */
46
46
  [data-slot="card"][data-variant="muted"] {
47
47
  background: hsl(var(--secondary));
48
48
  }
@@ -534,4 +534,23 @@
534
534
  display: flex;
535
535
  justify-content: flex-end;
536
536
  }
537
+
538
+ /* QrCode — a quiet, scanner-safe SVG surface with an ISO/IEC-style four-module quiet zone
539
+ * supplied by the encoder. Sizing is natural rather than stretched across its container. */
540
+ .ui-qr-code {
541
+ display: block;
542
+ inline-size: var(--qr-code-size-md);
543
+ block-size: auto;
544
+ max-inline-size: 100%;
545
+ aspect-ratio: 1;
546
+ }
547
+ .ui-qr-code[data-size="xs"] {
548
+ inline-size: var(--qr-code-size-xs);
549
+ }
550
+ .ui-qr-code[data-size="sm"] {
551
+ inline-size: var(--qr-code-size-sm);
552
+ }
553
+ .ui-qr-code[data-size="lg"] {
554
+ inline-size: var(--qr-code-size-lg);
555
+ }
537
556
  }
@@ -132,4 +132,8 @@
132
132
  font-size: var(--font-size-base);
133
133
  color: hsl(var(--muted-foreground));
134
134
  }
135
+
136
+ [data-slot="dialog-header"]:not([data-tone="default"]) [data-slot="dialog-description"] {
137
+ color: hsl(var(--foreground));
138
+ }
135
139
  }
@@ -3,35 +3,33 @@
3
3
  *
4
4
  * Self-contained so consumers need no font config. The browser only downloads
5
5
  * the subset files matching the rendered text:
6
- * · Noto Sans JP — the DEFAULT face (Japanese + Latin), used for all locales
7
- * except `vi`.
8
- * · Montserrat swapped in for the Vietnamese locale (`<html lang="vi">`),
9
- * incl. its `vietnamese` subset for full diacritics.
10
- * See --font-family-sans + :lang(vi) in base.css.
6
+ * · M PLUS 2 — the DXS DEFAULT face for Japanese and Latin, including the
7
+ * Vietnamese glyph coverage used by the product locales.
8
+ * · Noto Sans JP retained as the CJK fallback after M PLUS 2.
11
9
  *
12
10
  * The all-in-one `@godxjp/ui/styles` entry pulls this in automatically. If you
13
11
  * manage fonts yourself (e.g. next/font), DON'T import this — import
14
12
  * `@godxjp/ui/styles/base` + the layout layers you use and supply your own
15
13
  * faces via the --font-family-* tokens.
16
14
  * ───────────────────────────────────────────────────────────────────────── */
15
+ @import "@fontsource/m-plus-2/400.css";
16
+ @import "@fontsource/m-plus-2/500.css";
17
+ @import "@fontsource/m-plus-2/700.css";
17
18
  @import "@fontsource/noto-sans-jp/400.css";
18
19
  @import "@fontsource/noto-sans-jp/500.css";
19
20
  @import "@fontsource/noto-sans-jp/700.css";
20
- @import "@fontsource/montserrat/400.css";
21
- @import "@fontsource/montserrat/500.css";
22
- @import "@fontsource/montserrat/700.css";
23
21
 
24
22
  /* Fill the font-token slots (see tokens/foundation.css + styles/base.css) with
25
23
  * the bundled faces, so the all-in-one `@godxjp/ui/styles` entry stays
26
- * zero-config: Noto Sans JP is the default face (Japanese + clean Latin), and
27
- * the Vietnamese locale leads with Montserrat (Noto Sans JP tail keeps CJK
28
- * glyphs, which Montserrat lacks). Consumers on the per-layer setup who supply
29
- * their own faces simply DON'T import this file and set the slots themselves. */
24
+ * zero-config: M PLUS 2 is the DXS default face for every supported locale and
25
+ * Noto Sans JP remains its CJK fallback. Consumers on the per-layer setup who
26
+ * supply their own faces simply DON'T import this file and set the slots. */
30
27
  :root {
31
28
  --font-sans-base:
32
- "Noto Sans JP", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
33
- system-ui, "Hiragino Sans", sans-serif;
29
+ "M PLUS 2", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic Medium", YuGothic,
30
+ "Noto Sans JP", Meiryo, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui,
31
+ sans-serif;
34
32
  --font-sans-vi:
35
- "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
36
- system-ui, "Noto Sans JP", sans-serif;
33
+ "M PLUS 2", "Noto Sans JP", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui,
34
+ sans-serif;
37
35
  }
@@ -414,7 +414,7 @@
414
414
  * touch targets remain readable while page chrome stops competing with primary actions. A
415
415
  * single Flex action group must wrap even when the consumer omitted `wrap`, because clipping
416
416
  * header actions makes functionality unreachable. */
417
- @media (max-width: 639px) {
417
+ @media (max-width: 720px) {
418
418
  .ui-page-container {
419
419
  --space-page-active-x: var(--space-page-compact-x);
420
420
  --space-page-active-y: var(--space-page-compact-y);
@@ -11,11 +11,9 @@
11
11
  "sidebar main"
12
12
  "sidebar footer";
13
13
  grid-template-columns: 16rem minmax(0, 1fr);
14
- grid-template-rows: 3.25rem minmax(0, 1fr) auto;
14
+ grid-template-rows: var(--app-shell-bar-height) minmax(0, 1fr) auto;
15
15
  height: 100vh;
16
- background:
17
- linear-gradient(180deg, hsl(var(--primary) / 0.035), transparent 14rem),
18
- hsl(var(--background));
16
+ background: hsl(var(--background));
19
17
  }
20
18
 
21
19
  .app-root[data-collapsed="true"] {
@@ -46,10 +44,9 @@
46
44
  gap: var(--space-3);
47
45
  padding-inline: var(--space-4);
48
46
  border-bottom: 1px solid hsl(var(--border));
49
- background: hsl(var(--background) / 0.92);
47
+ background: hsl(var(--card));
50
48
  /* Opt-in brand-chrome wash — invisible by default (--topbar-gradient: none). */
51
49
  background-image: var(--topbar-gradient);
52
- backdrop-filter: blur(12px);
53
50
  }
54
51
 
55
52
  .app-main {
@@ -69,6 +66,7 @@
69
66
  * content can never extend the document scroll height (gh#104 — same shell-containment
70
67
  * family as the gh#103 body-stretch void). */
71
68
  contain: paint;
69
+ background-color: var(--app-shell-main-background);
72
70
  }
73
71
 
74
72
  .app-footer {
@@ -78,7 +76,8 @@
78
76
  }
79
77
 
80
78
  .app-main .ui-page-container {
81
- max-width: none;
79
+ width: 100%;
80
+ max-width: var(--app-shell-page-max-width);
82
81
  }
83
82
 
84
83
  /*
@@ -92,9 +91,7 @@
92
91
  display: flex;
93
92
  min-height: 100dvh;
94
93
  flex-direction: column;
95
- background:
96
- linear-gradient(180deg, hsl(var(--primary) / 0.035), transparent 14rem),
97
- hsl(var(--background));
94
+ background: hsl(var(--muted));
98
95
  }
99
96
 
100
97
  .ui-auth-shell-bar {
@@ -135,9 +132,7 @@
135
132
  display: flex;
136
133
  min-height: 100dvh;
137
134
  flex-direction: column;
138
- background:
139
- linear-gradient(180deg, hsl(var(--primary) / 0.035), transparent 14rem),
140
- hsl(var(--background));
135
+ background: hsl(var(--muted));
141
136
  }
142
137
 
143
138
  .ui-centered-shell-bar {
@@ -149,10 +144,9 @@
149
144
  gap: var(--space-3);
150
145
  padding-inline: var(--centered-shell-bar-padding-x);
151
146
  border-bottom: 1px solid hsl(var(--border));
152
- background: hsl(var(--background) / 0.92);
147
+ background: hsl(var(--card));
153
148
  /* Opt-in brand-chrome wash — shares the topbar hook, invisible by default (none). */
154
149
  background-image: var(--topbar-gradient);
155
- backdrop-filter: blur(12px);
156
150
  }
157
151
 
158
152
  .ui-centered-shell-main {
@@ -235,7 +229,7 @@
235
229
  font-size: var(--font-size-base);
236
230
  }
237
231
 
238
- @media (width < 64rem) {
232
+ @media (width <= 56.25rem) {
239
233
  .app-root,
240
234
  .app-root[data-collapsed="true"] {
241
235
  grid-template-areas:
@@ -265,7 +259,7 @@
265
259
  .sb-product,
266
260
  .sb-brand {
267
261
  display: flex;
268
- min-height: 3.25rem;
262
+ min-height: var(--app-shell-bar-height);
269
263
  align-items: center;
270
264
  gap: var(--space-2);
271
265
  padding-inline: var(--space-4);
@@ -294,8 +288,8 @@
294
288
 
295
289
  .sb-logo-mark {
296
290
  display: grid;
297
- width: 1.75rem;
298
- height: 1.75rem;
291
+ width: var(--sidebar-brand-mark-size);
292
+ height: var(--sidebar-brand-mark-size);
299
293
  flex: 0 0 auto;
300
294
  place-items: center;
301
295
  border-radius: var(--radius);
@@ -344,14 +338,15 @@
344
338
  .sb-nav-scroll {
345
339
  flex: 1;
346
340
  overflow-y: auto;
341
+ padding: var(--space-3) var(--space-2);
347
342
  }
348
343
 
349
344
  .sb-section {
350
- padding: var(--space-3) var(--space-2);
345
+ padding: 0;
351
346
  }
352
347
 
353
348
  .sb-section + .sb-section {
354
- border-top: 1px solid hsl(var(--border));
349
+ margin-top: var(--space-4);
355
350
  }
356
351
 
357
352
  .sb-section-label {
@@ -373,18 +368,18 @@
373
368
  .sb-nav-item {
374
369
  display: flex;
375
370
  width: 100%;
376
- height: var(--control-height);
371
+ height: var(--sidebar-nav-item-height);
377
372
  min-width: 0;
378
373
  align-items: center;
379
- gap: var(--space-2);
380
- padding-inline: var(--space-2);
374
+ gap: 0.625rem;
375
+ padding-inline: 0.625rem;
381
376
  border: 0;
382
377
  border-radius: calc(var(--radius) - 1px);
383
378
  background: transparent;
384
379
  color: hsl(var(--muted-foreground));
385
380
  cursor: pointer;
386
381
  font-family: inherit;
387
- font-size: var(--font-size-base);
382
+ font-size: var(--sidebar-nav-item-font-size);
388
383
  text-align: start;
389
384
  }
390
385
 
@@ -737,7 +732,7 @@
737
732
 
738
733
  .tb-search {
739
734
  display: flex;
740
- width: min(20rem, 30vw);
735
+ width: min(var(--topbar-search-max-width), 40vw);
741
736
  height: var(--control-height-sm);
742
737
  align-items: center;
743
738
  gap: var(--space-2);
@@ -41,11 +41,10 @@
41
41
  * --card-header-background-alpha: 0 for a quiet borderless-band header.
42
42
  * Default = 1px solid hsl(var(--card-border)) (resolved at the call site). */
43
43
  --card-header-border-bottom: initial;
44
- --card-radius: var(--radius);
45
- /* Resting elevation quiet by default (rule #44): cards are flat (1px border, no shadow) in the
46
- * reference-design baseline. A service that wants lifted cards sets this to an elevation token once,
47
- * e.g. --card-shadow: var(--shadow-sm), and every Card picks up the shadow with no markup change. */
48
- --card-shadow: 0 0 0 0 transparent;
44
+ --card-radius: var(--radius-xl);
45
+ /* The DXS hi-fi baseline uses a quiet 10px data surface with one shadow-sm
46
+ * elevation layer. Consumers can still flatten or lift cards through this knob. */
47
+ --card-shadow: var(--shadow-sm);
49
48
  /* Brand glow layer — invisible no-op at rest (rule #44). Paired AFTER --card-shadow in the
50
49
  * surface box-shadow so a service can wash every card with the global glow, e.g.
51
50
  * --card-glow: var(--shadow-glow), with no markup change. */
@@ -31,4 +31,13 @@
31
31
  re-resolves under a scoped theme. Defaults = hsl(var(--primary) / 0.3) border · 0.05 fill. */
32
32
  --tree-item-active-border: initial;
33
33
  --tree-item-active-background: initial;
34
+
35
+ /* QR codes stay scanner-safe in light and dark application themes. Consumers may override these
36
+ component tokens only when the resulting pair retains strong contrast. */
37
+ --qr-code-foreground: 0 0% 0%;
38
+ --qr-code-background: 0 0% 100%;
39
+ --qr-code-size-xs: 6rem;
40
+ --qr-code-size-sm: 8rem;
41
+ --qr-code-size-md: 10rem;
42
+ --qr-code-size-lg: 12.5rem;
34
43
  }
@@ -20,6 +20,16 @@
20
20
  --sidebar-gradient: none;
21
21
  --topbar-gradient: none;
22
22
 
23
+ /* DXS application-shell geometry. These defaults mirror the checked-in
24
+ * Admin/Console hi-fi source while remaining themeable by consumers. */
25
+ --app-shell-bar-height: 3rem;
26
+ --app-shell-page-max-width: 80rem;
27
+ --app-shell-main-background: hsl(var(--muted) / 0.4);
28
+ --sidebar-brand-mark-size: 1.375rem;
29
+ --sidebar-nav-item-height: 2rem;
30
+ --sidebar-nav-item-font-size: 0.8125rem;
31
+ --topbar-search-max-width: 26.25rem;
32
+
23
33
  /* Sidebar active-item tint/marker — `initial` so the role defaults re-resolve at the call site
24
34
  * under a scoped theme (a :root binding to a role var freezes at :root; a scoped role override
25
35
  * never reaches it). A service re-tunes the active sub-item accent without forking CSS.
@@ -47,7 +57,7 @@
47
57
  * account, standalone settings). The bar mirrors AppShell's `.app-topbar` chrome (fixed height +
48
58
  * inline padding); the column max-width has three tiers, all wider than the 24rem auth card. A
49
59
  * service retunes the bar inset, block padding and each width tier without forking CSS. */
50
- --centered-shell-bar-height: 3.25rem;
60
+ --centered-shell-bar-height: var(--app-shell-bar-height);
51
61
  --centered-shell-bar-padding-x: var(--space-4);
52
62
  --centered-shell-main-padding: var(--space-6);
53
63
  --centered-shell-footer-padding: var(--space-3) var(--space-6) var(--space-4);
@@ -161,8 +161,8 @@
161
161
  * --font-sans-zh-hans (lang="zh" | "zh-Hans" | "zh-CN")
162
162
  * --font-sans-zh-hant (lang="zh-Hant" | "zh-TW")
163
163
  * e.g. `--font-sans-ja: "Noto Sans JP", var(--font-sans-base);`
164
- * The opt-in bundle `@godxjp/ui/styles/fonts` fills these slots for its bundled
165
- * Noto Sans JP + Montserrat faces, so the all-in-one entry is zero-config. */
164
+ * The opt-in bundle `@godxjp/ui/styles/fonts` fills these slots with the DXS
165
+ * M PLUS 2 face and Noto Sans JP fallback, so the all-in-one entry is zero-config. */
166
166
  --font-sans-base:
167
167
  -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, system-ui,
168
168
  sans-serif;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "18.2.0",
4
- "godxUiMcp": "18.2.0",
3
+ "version": "18.4.0",
4
+ "godxUiMcp": "18.3.0",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.29.1",
7
7
  "pnpm": {
@@ -374,7 +374,7 @@
374
374
  },
375
375
  "dependencies": {
376
376
  "@date-fns/tz": "^1.5.0",
377
- "@fontsource/montserrat": "^5.2.8",
377
+ "@fontsource/m-plus-2": "^5.2.9",
378
378
  "@fontsource/noto-sans-jp": "^5.2.9",
379
379
  "@radix-ui/react-accordion": "^1.2.16",
380
380
  "@radix-ui/react-alert-dialog": "^1.1.19",
@@ -410,6 +410,7 @@
410
410
  "embla-carousel-react": "^8.6.0",
411
411
  "input-otp": "^1.4.2",
412
412
  "lucide-react": "^1.25.0",
413
+ "qrcode.react": "4.2.0",
413
414
  "react-day-picker": "^10.0.1",
414
415
  "react-resizable-panels": "^4.12.2",
415
416
  "sonner": "^2.0.7",
@@ -427,6 +428,7 @@
427
428
  "@testing-library/react": "^16.3.2",
428
429
  "@testing-library/user-event": "^14.6.1",
429
430
  "@types/node": "^22.19.19",
431
+ "@types/pngjs": "^6.0.5",
430
432
  "@types/react": "^19.2.17",
431
433
  "@types/react-dom": "^19.2.3",
432
434
  "@vitejs/plugin-react": "^6.0.3",
@@ -437,7 +439,9 @@
437
439
  "eslint-plugin-react-hooks": "^7.1.1",
438
440
  "globals": "^15.15.0",
439
441
  "jsdom": "^29.1.1",
442
+ "jsqr": "^1.4.0",
440
443
  "playwright": "^1.61.1",
444
+ "pngjs": "^7.0.0",
441
445
  "prettier": "^3.9.5",
442
446
  "prettier-plugin-tailwindcss": "^0.6.14",
443
447
  "react": "^19.2.7",