@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
@@ -139,7 +139,7 @@ export default function Demo() {
139
139
  </CardContent>
140
140
  </Card>
141
141
 
142
- {/* Banner — the SAME component at the page measure (gh#255). variant="banner" swaps only
142
+ {/* Banner — the SAME component at the page measure. variant="banner" swaps only
143
143
  the box: square, edge-to-edge, ruled on the block-end edge, measured by the --banner-*
144
144
  tokens. Every tone, the icon, the actions grid and the dismiss ✕ are inherited from the
145
145
  inline alert above, so there is nothing new to learn and nothing duplicated.
@@ -5,7 +5,7 @@ import { Button } from "@godxjp/ui/general";
5
5
  import { Flex, PageContainer } from "@godxjp/ui/layout";
6
6
 
7
7
  /**
8
- * Banner · full-bleed page/shell attention strip (godxjp-ui#255) — the Alert
8
+ * Banner · full-bleed page/shell attention strip — the Alert
9
9
  * primitive with the structural axis fixed to variant="banner". Persistent,
10
10
  * page/shell-scoped, at most one per surface. tone owns colour + icon +
11
11
  * live-region politeness; onDismiss renders the built-in dismiss (last in focus
@@ -25,7 +25,7 @@ import { Flex, PageContainer, ResponsiveGrid } from "@godxjp/ui/layout";
25
25
  import { buildEmailSpecimenHtml } from "./_email-specimen";
26
26
 
27
27
  /**
28
- * Email tokens · the `@godxjp/ui/email` contract (issue #227).
28
+ * Email tokens · the `@godxjp/ui/email` contract.
29
29
  *
30
30
  * A transactional email is rendered by Blade/Twig/MJML, by clients that strip `<style>`, ignore
31
31
  * CSS custom properties and block remote images — so neither the React components nor the CSS
@@ -12,7 +12,7 @@ import { Flex, PageContainer, Separator } from "@godxjp/ui/layout";
12
12
 
13
13
  /**
14
14
  * Activity · the official AMBIENT-motion primitive: a continuous, unbounded "something is happening
15
- * right now, elsewhere". The LOOP counterpart to `Reveal`'s one-shot entrance (gh#313).
15
+ * right now, elsewhere". The LOOP counterpart to `Reveal`'s one-shot entrance.
16
16
  *
17
17
  * Reads the DS motion tokens (`--activity-interval`, `--activity-stagger-step`,
18
18
  * `--activity-mark-offset`, `--activity-color`, `--ease-standard`) so a consumer never hand-rolls a
@@ -8,7 +8,7 @@ import { AuthAccountSummary, AuthStack, PageContainer } from "@godxjp/ui/layout"
8
8
  * the account address, and exactly one ghost action. Everything else is consumer data.
9
9
  *
10
10
  * The address CLIPS with an ellipsis, so it declares its own line box rather than inheriting one
11
- * (gh#254): a tight inherited line-height makes the clip box shorter than the font's ascent plus
11
+ *: a tight inherited line-height makes the clip box shorter than the font's ascent plus
12
12
  * descent and shears Vietnamese tone marks and Latin descenders off, while the DOM text stays
13
13
  * correct. The Vietnamese row below is the regression case for that.
14
14
  */
@@ -9,7 +9,7 @@ import { AppSettingPicker } from "@godxjp/ui/navigation";
9
9
  /**
10
10
  * Viewport fixture — 390x844 (mobile). THE MOBILE CONTRACT, decided here.
11
11
  *
12
- * ⚠️ The 390 canonical reference supplied with gh#233 is a desktop 2x2 COMPOSITE that overflows and
12
+ * ⚠️ The 390 canonical reference supplied with is a desktop 2x2 COMPOSITE that overflows and
13
13
  * crops horizontally. It is not a route-level mobile artboard and it was NOT traced. The behaviour
14
14
  * below is a decided, documented contract — see the Overview page.
15
15
  *
@@ -28,8 +28,6 @@ export default function Demo() {
28
28
  const [password, setPassword] = useState("Godx-2026");
29
29
  const [confirmation, setConfirmation] = useState("Godx-202");
30
30
 
31
- // The address is masked by the SERVER before it reaches the panel — the library never
32
- // reconstructs an identifier, it only renders the string the consumer sends.
33
31
  const maskedEmail = "h*****@example.co.jp";
34
32
 
35
33
  return (
@@ -16,7 +16,7 @@ import { AuthFooter, AuthIdentity, AuthShell, Flex } from "@godxjp/ui/layout";
16
16
  import { AppSettingPicker } from "@godxjp/ui/navigation";
17
17
 
18
18
  /**
19
- * AuthShell preset="context-selection" (gh#217) — the canonical organisation / context picker.
19
+ * AuthShell preset="context-selection" — the canonical organisation / context picker.
20
20
  *
21
21
  * The preset owns the whole page measure: a 25rem card at 1440/1024 and an edge-to-edge card at
22
22
  * 390 (0 inline gutter), plus the vertical rhythm between the three direct sections of the auth
@@ -18,7 +18,7 @@ import {
18
18
  import { AppSettingPicker, Steps } from "@godxjp/ui/navigation";
19
19
 
20
20
  /**
21
- * AuthShell preset="device-authorization" (gh#220) — the canonical OAuth device-grant screen.
21
+ * AuthShell preset="device-authorization" — the canonical OAuth device-grant screen.
22
22
  *
23
23
  * The whole page measure is owned by the preset: a 380px card at 1440/1024 and a 5px inline page
24
24
  * gutter at 390 (card x=5px, width=380px). Nothing here sets a width, an inset or a colour — a
@@ -28,7 +28,7 @@ import { AppSettingPicker, Steps } from "@godxjp/ui/navigation";
28
28
  * `variant="canonical"` still owns control density + heading size; the preset only re-measures.
29
29
  * Verify at 1440x900 · 1024x900 · 390x844.
30
30
  *
31
- * gh#12 — the preset also owns the CODE FIELD now: `--otp-slot-{inline,block}-size` come from
31
+ * The preset also owns the CODE FIELD now: `--otp-slot-{inline,block}-size` come from
32
32
  * `--auth-shell-device-otp-slot-*`, so each 4-slot grouped box measures the canonical 112x54
33
33
  * instead of the 146x38 the square control tier produced. Nothing on this page sets it. The row is
34
34
  * centred with `align="center"` (not a wrapper div) and the progress marker is the canonical
@@ -33,7 +33,7 @@ import {
33
33
  import { AppSettingPicker } from "@godxjp/ui/navigation";
34
34
 
35
35
  /**
36
- * AuthShell preset="registration" (gh#256) — the canonical sign-up measure.
36
+ * AuthShell preset="registration" — the canonical sign-up measure.
37
37
  *
38
38
  * The preset owns the whole page geometry: a 360px (22.5rem) form measure at 1440/1024, a 15px
39
39
  * inline gutter at 390 (card x=15, width=360 — the same page rhythm as preset="login", so
@@ -14,7 +14,7 @@ import {
14
14
  * SCR-001 Login visual contract. `?state=standalone|one-line|wrapped` drives the package visual
15
15
  * test; all three keep the same card anchor without consumer CSS or fake requester data.
16
16
  *
17
- * The composition mirrors the documented consumer page exactly (gh#263): NO top brand bar (the
17
+ * The composition mirrors the documented consumer page exactly: NO top brand bar (the
18
18
  * canonical SCR-001 artboard has none — the in-flow AuthIdentity mark IS the brand), a header-less
19
19
  * `<CardContent solo>` body, `AuthFooter` as the third direct child (the login preset's third grid
20
20
  * row), and a plain 12px text-link row like the artboard's.
@@ -102,7 +102,7 @@ const COLLAPSE_STEPS = ["token", "sm", "md", "lg", "xl", "false"] as const;
102
102
  const MASTER_VIEWPORTS = ["auto", "compact", "standard"] as const;
103
103
 
104
104
  /**
105
- * 実サービスの「長い」コレクション (gh#231)。auto のままだと一覧が数千 px に伸び、
105
+ * 実サービスの「長い」コレクション。auto のままだと一覧が数千 px に伸び、
106
106
  * 積み重なった 390px 画面では詳細がフォールドの遥か下に押し出される。
107
107
  */
108
108
  const MEMBERS = Array.from({ length: 60 }, (_, i) => ({
@@ -339,7 +339,7 @@ export default function Demo() {
339
339
  </Card>
340
340
  </MasterDetail>
341
341
 
342
- {/* ── 3. masterViewport — 長い実コレクションを境界付きビューポートに収める (gh#231)。
342
+ {/* ── 3. masterViewport — 長い実コレクションを境界付きビューポートに収める。
343
343
  auto: 一覧が 60 行ぶん伸び、390px では詳細がフォールドの遥か下に落ちる。
344
344
  compact / standard: --master-detail-master-viewport-* が block サイズを
345
345
  上限とし、コレクションは region の中でスクロールする。
@@ -0,0 +1,101 @@
1
+ import * as React from "react";
2
+ import { Inbox, Package, ScanLine, Truck } from "lucide-react";
3
+
4
+ import { Badge, Card, CardContent } from "@godxjp/ui/data-display";
5
+ import { Button, Heading, Text } from "@godxjp/ui/general";
6
+ import { Flex, MobileShell } from "@godxjp/ui/layout";
7
+
8
+ /**
9
+ * MobileShell — the handheld app shell: a status band, an app bar, ONE scroll region, a sticky
10
+ * action bar and a bottom tab bar. The two things a composed `Card` stack cannot do are exactly
11
+ * what the shell owns: the root is one screen tall so the DOCUMENT never scrolls (the tab bar can
12
+ * never slide away under a collapsing URL bar), and every band pads itself out of the device
13
+ * safe areas. Zero custom CSS — no `min-h-dvh`, no `position: sticky`, no page gutter by hand.
14
+ */
15
+ const ITEMS = [
16
+ { rc: "RC-204881", name: "洗顔フォーム", status: "未仕分け", tone: "warning" as const },
17
+ { rc: "RC-204882", name: "日焼け止め", status: "棚上", tone: "info" as const },
18
+ { rc: "RC-204879", name: "ビタミン B", status: "棚上", tone: "info" as const },
19
+ { rc: "RC-204875", name: "歯ブラシ", status: "梱包済み", tone: "muted" as const },
20
+ { rc: "RC-204871", name: "入浴剤", status: "棚上", tone: "info" as const },
21
+ { rc: "RC-204864", name: "解熱鎮痛薬", status: "梱包済み", tone: "muted" as const },
22
+ ];
23
+
24
+ const TABS = [
25
+ { id: "inbound", label: "入庫", icon: Inbox },
26
+ { id: "packing", label: "梱包", icon: Package },
27
+ { id: "outbound", label: "出庫", icon: Truck },
28
+ ];
29
+
30
+ export default function Demo() {
31
+ const [tab, setTab] = React.useState("inbound");
32
+
33
+ return (
34
+ <MobileShell
35
+ statusBar={
36
+ <>
37
+ <Text size="sm" weight="medium" tabular>
38
+ 9:41
39
+ </Text>
40
+ <Text size="sm" weight="medium" tone="muted" tabular>
41
+ Acme Handy
42
+ </Text>
43
+ </>
44
+ }
45
+ header={
46
+ <Flex align="center" justify="between" gap="xs" className="w-full">
47
+ <Heading level={3} as="h1">
48
+ 入庫
49
+ </Heading>
50
+ <Button variant="ghost" size="sm">
51
+ 選択
52
+ </Button>
53
+ </Flex>
54
+ }
55
+ actions={
56
+ <>
57
+ <Button className="flex-[2]">
58
+ <ScanLine aria-hidden="true" />
59
+ スキャン
60
+ </Button>
61
+ <Button variant="outline" className="flex-1">
62
+ 手入力
63
+ </Button>
64
+ </>
65
+ }
66
+ tabBar={TABS.map((t) => {
67
+ const Icon = t.icon;
68
+ return (
69
+ <Button
70
+ key={t.id}
71
+ variant="ghost"
72
+ onClick={() => setTab(t.id)}
73
+ aria-current={t.id === tab ? "page" : undefined}
74
+ className="h-full flex-col rounded-none"
75
+ >
76
+ <Icon aria-hidden="true" />
77
+ <Text size="2xs">{t.label}</Text>
78
+ </Button>
79
+ );
80
+ })}
81
+ >
82
+ <Flex direction="col" gap="sm">
83
+ {ITEMS.map((item) => (
84
+ <Card key={item.rc} density="tight">
85
+ <CardContent solo>
86
+ <Flex align="center" justify="between" gap="sm">
87
+ <Flex direction="col" gap="none">
88
+ <Text weight="medium">{item.name}</Text>
89
+ <Text size="xs" mono tone="muted" tabular>
90
+ {item.rc}
91
+ </Text>
92
+ </Flex>
93
+ <Badge tone={item.tone}>{item.status}</Badge>
94
+ </Flex>
95
+ </CardContent>
96
+ </Card>
97
+ ))}
98
+ </Flex>
99
+ </MobileShell>
100
+ );
101
+ }
@@ -47,7 +47,7 @@ const TOOLBAR_CHROME_TOKENS = {
47
47
  } as CSSProperties;
48
48
 
49
49
  /**
50
- * `--page-header-min-block-size-chrome` · クロム帯の「高さ」(gh#331)。文書のヘッダーは中身なりの
50
+ * `--page-header-min-block-size-chrome` · クロム帯の「高さ」。文書のヘッダーは中身なりの
51
51
  * 高さで正しい · 見出しは見出しの高さだからです。クロムは逆で、家具には「ものが中央に収まる帯」が
52
52
  * 要ります。既定は `auto`(=rule #44 の最も静かな状態)なので、このトークンを置くまで DOM も
53
53
  * 見え方も従来どおり · 文書ページはそもそもこの規則に一致しません。
@@ -109,7 +109,7 @@ const journalColumns: ColumnDef<JournalEntry>[] = [
109
109
  * PageContainer · mandatory page shell.
110
110
  * Covers: title/subtitle/status/extra/footer/breadcrumb/linkComponent + variant
111
111
  * default/narrow/flush/ghost + density compact/default/comfortable + PageContainer.Inset.
112
- * The embedded header is the CANONICAL DXS PageHeader (gh#255) — status/meta band included.
112
+ * The embedded header is the CANONICAL DXS PageHeader — status/meta band included.
113
113
  * Each example is standalone (no AppShell) so the variant behaviour is visible in
114
114
  * isolation. Composed only from real @godxjp/ui components.
115
115
  */
@@ -165,7 +165,7 @@ export default function Demo() {
165
165
  </ResponsiveGrid>
166
166
  </PageContainer>
167
167
 
168
- {/* ── 1b. Canonical page-header contract (gh#255) · status/meta band ── */}
168
+ {/* ── 1b. Canonical page-header contract · status/meta band ── */}
169
169
  {/* PageContainer's embedded header IS the DXS PageHeader: breadcrumbs + title +
170
170
  subtitle + status/meta + actions + responsive overflow on ONE renderer. The
171
171
  `status` band shares the title line at --page-header-status-gap and wraps
@@ -405,7 +405,7 @@ export default function Demo() {
405
405
  </Card>
406
406
  </PageContainer>
407
407
 
408
- {/* ── 6. fill · body height behaviour on a tall shell (gh#103) ──
408
+ {/* ── 6. fill · body height behaviour on a tall shell ──
409
409
  Each PageContainer sits in a fixed-height framed box that stands in for the
410
410
  viewport-tall app shell, so the two behaviours are visible side by side. */}
411
411
  <ResponsiveGrid columns={{ sm: 1, md: 2 }}>
@@ -452,7 +452,7 @@ export default function Demo() {
452
452
  </div>
453
453
  </ResponsiveGrid>
454
454
 
455
- {/* ── 7. headerLayout · 390px でヘッダー extra をタイトル行に残す (gh#231) ──
455
+ {/* ── 7. headerLayout · 390px でヘッダー extra をタイトル行に残す ──
456
456
  stack (既定) は 640px 未満で extra を subtitle の下の全幅行に落とす。
457
457
  responsive-inline は --page-header-extra-measure (11rem) の測度で
458
458
  title 帯の横に残す。640px 以上では両者は同一。
@@ -505,7 +505,7 @@ export default function Demo() {
505
505
  </PageContainer>
506
506
  </ResponsiveGrid>
507
507
 
508
- {/* ── 8. measure · ヘッダーとボディを 1 つの測度で束ねる (gh#245 / gh#247) ──
508
+ {/* ── 8. measure · ヘッダーとボディを 1 つの測度で束ねる ──
509
509
  measure は variant(クローム)と直交する第 3 の軸。variant="narrow" は
510
510
  .ui-page-body しか絞らないため、ヘッダーのアクションはページ端に取り残される。
511
511
  measure はヘッダーとボディの両方を同じトークン測度で絞るので、extra の終端が
@@ -13,7 +13,7 @@ import { Flex, PageContainer, ResponsiveGrid, SplitPane } from "@godxjp/ui/layou
13
13
  * ResponsiveGrid · equal-width multi-column tile grid with automatic responsive
14
14
  * collapse (CSS container queries, not viewport). It OWNS its query container
15
15
  * (container-type: inline-size), so it responds to the width available to the grid
16
- * with no external container-type declaration (gh#165). Direct children are typically
16
+ * with no external container-type declaration. Direct children are typically
17
17
  * StatCard (self-contained bordered card · never wrap in Card/CardContent) or
18
18
  * Card+CardContent for richer tile bodies. columns accepts a number OR breakpoint
19
19
  * object { sm?, md?, lg? } — or use the named `preset` prop (e.g. "pricing-plans") for a
@@ -45,7 +45,7 @@ export default function Demo() {
45
45
  aside={
46
46
  <Flex direction="col" gap="sm">
47
47
  <Text tone="muted">狭いコンテナ(約 20rem)→ sm=1 列</Text>
48
- {/* No wrapping `@container` needed — ResponsiveGrid OWNS its query container (gh#165). */}
48
+ {/* No wrapping `@container` needed — ResponsiveGrid OWNS its query container. */}
49
49
  <ResponsiveGrid columns={4}>
50
50
  <StatCard label="今日の入金" value="¥420,000" />
51
51
  <StatCard label="未処理" value="6 件" />
@@ -19,7 +19,7 @@ import { Flex, PageContainer, Separator } from "@godxjp/ui/layout";
19
19
  * defaults to true · set false only when the divider carries semantic meaning for
20
20
  * a11y.
21
21
  *
22
- * gh#308 — `label` INTERRUPTS the rule: a message stream's day divider, a "new messages"
22
+ * `label` INTERRUPTS the rule: a message stream's day divider, a "new messages"
23
23
  * watermark, an auth conjunction. A labelled rule flips `decorative` to false, so it is a real
24
24
  * role="separator" NAMED by the label (the visible node is aria-hidden, so the string is announced
25
25
  * exactly once). `labelAlign` is a controlled vocabulary value — start | center | end, logical, so
@@ -172,7 +172,7 @@ export default function Demo() {
172
172
  </CardContent>
173
173
  </Card>
174
174
 
175
- {/* ── gh#308 — the real screen the labelled rule exists for ─────────────────────────── */}
175
+ {/* ── — the real screen the labelled rule exists for ─────────────────────────── */}
176
176
  <Card>
177
177
  <CardHeader>
178
178
  <CardTitle level={2}>実画面 · チャンネルの投稿ストリーム</CardTitle>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * ServiceRolePanel — ロール一覧 ⇄ 詳細 (canonical master-detail roles surface, gh#257).
2
+ * ServiceRolePanel — ロール一覧 ⇄ 詳細 (canonical master-detail roles surface).
3
3
  *
4
4
  * MasterDetail (rail=master) underneath owns all geometry: two tracks at 1440/1024, stacked
5
5
  * list-then-detail at 390. The panel adds selection (aria-current rows), locked system roles,
@@ -127,7 +127,7 @@ const MENTION_SECTIONS: SidebarSectionProp[] = [
127
127
  ];
128
128
 
129
129
  /**
130
- * gh#228 · nav row and nav icon read SEPARATE colour tokens. A service normally sets these once in
130
+ * nav row and nav icon read SEPARATE colour tokens. A service normally sets these once in
131
131
  * its theme.css (`:root` or a scoped `[data-tenant] .app-sidebar`); here they are scoped to one
132
132
  * demo frame so the default rail can sit next to the themed one. Icons only — geometry (16px icon,
133
133
  * 32px row, 10px gap) is untouched.
@@ -138,7 +138,7 @@ const CANONICAL_NAV_TOKENS = {
138
138
  } as CSSProperties;
139
139
 
140
140
  /**
141
- * gh#213 · THE router-link contract. `createSidebarLink` adapts any router `Link` — React Router /
141
+ * THE router-link contract. `createSidebarLink` adapts any router `Link` — React Router /
142
142
  * TanStack use `to`, Inertia and Next.js use `href` (the default, and
143
143
  * `inertiaSidebarLink(Link)` from `@godxjp/ui/inertia` is the same thing pre-bound). The consumer
144
144
  * writes NO row markup: the Sidebar composes the icon slot, the label, the badge, the active state
@@ -171,7 +171,7 @@ const ROUTED_SECTIONS: SidebarSectionProp[] = [
171
171
  ];
172
172
 
173
173
  /**
174
- * renderItem · DEPRECATED (gh#213) — kept working for existing consumers. It leaves the row CONTENT
174
+ * renderItem · DEPRECATED — kept working for existing consumers. It leaves the row CONTENT
175
175
  * to the caller, which is how a `<Link>{item.label}</Link>` silently dropped every icon in
176
176
  * production. `rowProps` now carries the library-composed `children`, so spreading it (or rendering
177
177
  * `rowProps.children`) restores the canonical row; the star is a decorative, non-interactive affix.
@@ -346,7 +346,7 @@ export default function Demo() {
346
346
  </CardContent>
347
347
  </Card>
348
348
 
349
- {/* linkComponent prop · THE router-link contract (gh#213) — library composes the row. */}
349
+ {/* linkComponent prop · THE router-link contract — library composes the row. */}
350
350
  <Card>
351
351
  <CardHeader>
352
352
  <CardTitle level={2}>linkComponent プロップ(ルーターリンク)</CardTitle>
@@ -395,7 +395,7 @@ export default function Demo() {
395
395
  </CardContent>
396
396
  </Card>
397
397
 
398
- {/* renderItem prop · DEPRECATED escape hatch (gh#213) — kept for back-compat. */}
398
+ {/* renderItem prop · DEPRECATED escape hatch — kept for back-compat. */}
399
399
  <Card>
400
400
  <CardHeader>
401
401
  <CardTitle level={2}>renderItem プロップ(非推奨)</CardTitle>
@@ -526,7 +526,7 @@ export default function Demo() {
526
526
  </CardContent>
527
527
  </Card>
528
528
 
529
- {/* Nav colour tokens · icon and label are themed SEPARATELY (gh#228). */}
529
+ {/* Nav colour tokens · icon and label are themed SEPARATELY. */}
530
530
  <Card>
531
531
  <CardHeader>
532
532
  <CardTitle level={2}>ナビの配色トークン(アイコンとラベルを別々に)</CardTitle>
@@ -17,7 +17,7 @@ import { FileText, Building2, Calendar, CreditCard, ArrowRight } from "lucide-re
17
17
  * Shows: main list + detail panel, asideWidth sm/md, nested inside PageContainer.
18
18
  * It OWNS its query container (container-type: inline-size), so the two-column split
19
19
  * is chosen from the PANE's own width (≥48rem), not the viewport — a narrow embedded
20
- * pane on a large screen correctly stays single-column (gh#165).
20
+ * pane on a large screen correctly stays single-column.
21
21
  * Composed only from real @godxjp/ui components.
22
22
  *
23
23
  * NOTE: <Flex> defaults to direction="row"; vertical stacks set direction="col"
@@ -37,10 +37,7 @@ import {
37
37
 
38
38
  /**
39
39
  * Topbar · a PURE SLOT bar. The shell only positions `start` / `center` / `end`; the CONSUMER
40
- * composes every control. This demo builds the chrome the OLD baked Topbar used to force ·
41
- * sidebar toggle, brand mark (Avatar), an entity switcher, a search trigger, a notifications button, a
42
- * user menu · entirely from real primitives, so you can see there is no hidden template (and no
43
- * dead dropdown: a control exists ONLY because it's placed here).
40
+ * composes every control.
44
41
  */
45
42
  const SECTIONS: SidebarSectionProp[] = [
46
43
  {
@@ -153,10 +150,7 @@ export default function Demo() {
153
150
  // end · notifications + user menu, both consumer-composed.
154
151
  const end = (
155
152
  <>
156
- {/* The end slot is `flex: 0 0 auto` — whatever sits here is taken out of the start slot's
157
- budget before it gets a say. At 320 this environment chip alone claimed 93 of the bar's
158
- 198px, squeezing start to 25px and clipping the entity switcher inside it. An ambient
159
- status label is the first thing a compact bar drops, so it appears from sm up. */}
153
+ {}
160
154
  <Badge tone="warning" className="text-xs">
161
155
  ステージング
162
156
  </Badge>
@@ -39,7 +39,7 @@ export default function Demo() {
39
39
  const [period, setPeriod] = useState("all");
40
40
  const hasActiveFilters = query !== "" || status !== "all";
41
41
 
42
- // Typed model (gh#258) — ALL state is consumer data; the bar only renders it.
42
+ // Typed model — ALL state is consumer data; the bar only renders it.
43
43
  const [modelQuery, setModelQuery] = useState("田中");
44
44
  const [modelStatus, setModelStatus] = useState("active");
45
45
  const [modelRole, setModelRole] = useState("");
@@ -80,7 +80,7 @@ export default function Demo() {
80
80
  subtitle="Search, labelled filters, active state, consumer-owned reset, and both responsive overflow strategies"
81
81
  >
82
82
  <Flex direction="col" gap="lg">
83
- {/* Typed model (gh#258) — search/filters/chips/reset/result-count/actions as DATA.
83
+ {/* Typed model — search/filters/chips/reset/result-count/actions as DATA.
84
84
  The bar owns layout, token widths, chip lifecycle and keyboard order; the page owns
85
85
  every piece of state. Remove a chip, reset, or pick a filter and watch the chips row
86
86
  and the localized result count follow. */}
@@ -97,7 +97,7 @@ export default function Demo() {
97
97
  onValueChange={handleChange}
98
98
  />
99
99
 
100
- {/* Regression: total=0, exactly one page, multiple pages, + the single-page opt-in (gh#153). */}
100
+ {/* Regression: total=0, exactly one page, multiple pages, + the single-page opt-in. */}
101
101
  <Card>
102
102
  <CardHeader>
103
103
  <CardTitle level={2}>境界状態 · 0 件 / 1 ページ / 複数ページ</CardTitle>
@@ -136,7 +136,7 @@ export default function Demo() {
136
136
  </CardContent>
137
137
  </Card>
138
138
 
139
- {/* Long localized total label — the row stays ONE line and never wraps on desktop (gh#153). */}
139
+ {/* Long localized total label — the row stays ONE line and never wraps on desktop. */}
140
140
  <Card>
141
141
  <CardHeader>
142
142
  <CardTitle level={2}>長いローカライズ済みラベル · 折り返さない</CardTitle>
@@ -229,7 +229,7 @@ export default function Demo() {
229
229
  </CardContent>
230
230
  </Card>
231
231
 
232
- {/* Inline row — the hosted-identity / device progression (gh#12) */}
232
+ {/* Inline row — the hosted-identity / device progression */}
233
233
  <Card>
234
234
  <CardHeader>
235
235
  <CardTitle level={2}>
@@ -67,7 +67,7 @@ export default function Demo() {
67
67
  </CardContent>
68
68
  </Card>
69
69
 
70
- {/* Disabled first item — fallback selection must skip it (gh#175) */}
70
+ {/* Disabled first item — fallback selection must skip it */}
71
71
  <Card>
72
72
  <CardHeader>
73
73
  <CardTitle level={2}>先頭タブが disabled · フォールバック選択</CardTitle>
@@ -50,6 +50,7 @@ import {
50
50
  CardContent,
51
51
  CardHeader,
52
52
  CardTitle,
53
+ ListRow,
53
54
  Progress,
54
55
  StatCard,
55
56
  Table,
@@ -353,27 +354,25 @@ export default function AcmePortalShowcase() {
353
354
  <CardContent flush>
354
355
  <ul className="divide-border divide-y">
355
356
  {QUEUE.map((q) => (
356
- <li key={q.title} className="px-4 py-3">
357
- <Flex align="center" gap="md">
357
+ <ListRow
358
+ as="li"
359
+ key={q.title}
360
+ leading={
358
361
  <Badge
359
362
  tone={q.tone}
360
363
  variant="outline"
361
364
  icon={q.icon}
362
365
  aria-label={q.title}
363
366
  />
364
- <div className="min-w-0 flex-1">
365
- <Text as="div" size="sm" weight="medium" truncate>
366
- {q.title}
367
- </Text>
368
- <Text as="div" size="xs" tone="muted" truncate>
369
- {q.meta}
370
- </Text>
371
- </div>
367
+ }
368
+ title={q.title}
369
+ description={q.meta}
370
+ trailing={
372
371
  <Button variant="outline" size="sm">
373
372
  {q.action}
374
373
  </Button>
375
- </Flex>
376
- </li>
374
+ }
375
+ />
377
376
  ))}
378
377
  </ul>
379
378
  </CardContent>
@@ -237,7 +237,7 @@ function SectionHead({
237
237
  center?: boolean;
238
238
  }) {
239
239
  return (
240
- <div className={center ? "mx-auto mb-10 text-center" : "mb-8"}>
240
+ <div className={center ? "mx-auto text-center" : undefined}>
241
241
  <div className="tx-eyebrow">{eyebrow}</div>
242
242
  <h2 className="tx-h2">{title}</h2>
243
243
  {sub ? <p className="tx-lead mx-auto">{sub}</p> : null}
@@ -272,7 +272,7 @@ function Services() {
272
272
  ];
273
273
  return (
274
274
  <section className="bg-card tx-section">
275
- <div className={SHELL}>
275
+ <Flex direction="col" gap="xl" className={SHELL}>
276
276
  <SectionHead
277
277
  center
278
278
  eyebrow="Dịch vụ"
@@ -296,7 +296,7 @@ function Services() {
296
296
  </Card>
297
297
  ))}
298
298
  </ResponsiveGrid>
299
- </div>
299
+ </Flex>
300
300
  </section>
301
301
  );
302
302
  }
@@ -310,7 +310,7 @@ function Steps() {
310
310
  ];
311
311
  return (
312
312
  <section className="bg-background tx-section">
313
- <div className={SHELL}>
313
+ <Flex direction="col" gap="xl" className={SHELL}>
314
314
  <SectionHead eyebrow="Quy trình" title="Mua hàng quốc tế trong 4 bước" />
315
315
  <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 4 }}>
316
316
  {steps.map(([Icon, t, d], i) => (
@@ -332,7 +332,7 @@ function Steps() {
332
332
  </Flex>
333
333
  ))}
334
334
  </ResponsiveGrid>
335
- </div>
335
+ </Flex>
336
336
  </section>
337
337
  );
338
338
  }
@@ -346,7 +346,7 @@ function Routes() {
346
346
  ];
347
347
  return (
348
348
  <section className="bg-card tx-section">
349
- <div className={SHELL}>
349
+ <Flex direction="col" gap="xl" className={SHELL}>
350
350
  <SectionHead eyebrow="Tuyến vận chuyển" title="Giá cước rõ ràng theo từng tuyến" />
351
351
  <ResponsiveGrid columns={{ sm: 1, md: 2, lg: 4 }}>
352
352
  {routes.map(([c, code, mode, price]) => (
@@ -370,7 +370,7 @@ function Routes() {
370
370
  </Card>
371
371
  ))}
372
372
  </ResponsiveGrid>
373
- </div>
373
+ </Flex>
374
374
  </section>
375
375
  );
376
376
  }
@@ -43,6 +43,7 @@ import {
43
43
  CardContent,
44
44
  CardHeader,
45
45
  CardTitle,
46
+ ListRow,
46
47
  Progress,
47
48
  StatCard,
48
49
  Table,
@@ -241,27 +242,25 @@ export default function WarehouseDashboardShowcase() {
241
242
  <ul className="divide-border divide-y">
242
243
  {QUEUE.map((q) => {
243
244
  return (
244
- <li key={q.title} className="px-4 py-3">
245
- <Flex align="center" gap="md">
245
+ <ListRow
246
+ as="li"
247
+ key={q.title}
248
+ leading={
246
249
  <Badge
247
250
  tone={q.tone}
248
251
  variant="outline"
249
252
  icon={q.icon}
250
253
  aria-label={q.title}
251
254
  />
252
- <div className="min-w-0 flex-1">
253
- <Text as="div" size="sm" weight="medium" truncate>
254
- {q.title}
255
- </Text>
256
- <Text as="div" size="2xs" tone="muted" truncate>
257
- {q.meta}
258
- </Text>
259
- </div>
255
+ }
256
+ title={q.title}
257
+ description={q.meta}
258
+ trailing={
260
259
  <Button variant="outline" size="sm">
261
260
  {q.action}
262
261
  </Button>
263
- </Flex>
264
- </li>
262
+ }
263
+ />
265
264
  );
266
265
  })}
267
266
  </ul>