@godxjp/ui 19.3.1 → 19.4.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 (128) 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/FRAME-A11Y-CI.md +99 -17
  52. package/docs/FRAME-COVERAGE-REPORT.md +4 -2
  53. package/docs/SPACING.md +19 -6
  54. package/docs/charts/compact-bar-trend.tsx +5 -6
  55. package/docs/data-display/avatar.tsx +7 -9
  56. package/docs/data-display/badge.tsx +1 -1
  57. package/docs/data-display/card/index.tsx +6 -4
  58. package/docs/data-display/data-table/examples/approval-queue.tsx +1 -1
  59. package/docs/data-display/data-table/index.tsx +1 -1
  60. package/docs/data-display/permission-matrix.tsx +2 -2
  61. package/docs/data-display/popover.tsx +4 -1
  62. package/docs/data-display/scroll-area.tsx +1 -1
  63. package/docs/data-display/table.tsx +1 -1
  64. package/docs/data-display/timeline-grid.tsx +119 -0
  65. package/docs/data-entry/branch-scope-picker.tsx +1 -1
  66. package/docs/data-entry/date-picker.tsx +2 -1
  67. package/docs/data-entry/form-field/index.tsx +2 -2
  68. package/docs/data-entry/input-otp.tsx +1 -1
  69. package/docs/data-entry/select-matrix.tsx +2 -1
  70. package/docs/data-entry/select.tsx +3 -1
  71. package/docs/data-entry/textarea.tsx +1 -1
  72. package/docs/data-entry/toggle-count.tsx +1 -1
  73. package/docs/feedback/alert.tsx +1 -1
  74. package/docs/feedback/banner.tsx +1 -1
  75. package/docs/feedback/dialog.tsx +2 -1
  76. package/docs/feedback/sheet.tsx +2 -1
  77. package/docs/foundation/email-tokens.tsx +1 -1
  78. package/docs/general/activity.tsx +1 -1
  79. package/docs/layout/app-shell.tsx +4 -4
  80. package/docs/layout/auth-account-summary.tsx +1 -1
  81. package/docs/layout/auth-recovery/examples/mobile-390.tsx +1 -1
  82. package/docs/layout/auth-recovery/examples/password-recovery.tsx +0 -2
  83. package/docs/layout/auth-shell-context.tsx +1 -1
  84. package/docs/layout/auth-shell-device.tsx +2 -2
  85. package/docs/layout/auth-shell-registration.tsx +1 -1
  86. package/docs/layout/auth-shell.tsx +1 -1
  87. package/docs/layout/master-detail.tsx +2 -2
  88. package/docs/layout/mobile-shell.tsx +101 -0
  89. package/docs/layout/page-container.tsx +6 -6
  90. package/docs/layout/responsive-grid.tsx +5 -5
  91. package/docs/layout/separator.tsx +2 -2
  92. package/docs/layout/service-role-panel.tsx +1 -1
  93. package/docs/layout/sidebar.tsx +9 -9
  94. package/docs/layout/split-pane.tsx +5 -6
  95. package/docs/layout/topbar.tsx +2 -8
  96. package/docs/navigation/context-menu.tsx +6 -1
  97. package/docs/navigation/dropdown-menu.tsx +2 -1
  98. package/docs/navigation/filter-bar.tsx +2 -2
  99. package/docs/navigation/pagination.tsx +2 -2
  100. package/docs/navigation/steps.tsx +1 -1
  101. package/docs/navigation/tabs.tsx +3 -3
  102. package/docs/showcase/acme-portal.tsx +11 -12
  103. package/docs/showcase/acme-website.tsx +7 -7
  104. package/docs/showcase/case1-warehouse-dashboard.tsx +11 -12
  105. package/docs/showcase/case2-employee-me.tsx +10 -16
  106. package/docs/showcase/case4-login.tsx +144 -156
  107. package/docs/showcase/case5-shift-calendar.tsx +181 -280
  108. package/docs/showcase/case6-agency-handy.tsx +446 -443
  109. package/docs/showcase/futurelastic-web.tsx +9 -8
  110. package/docs/showcase/org-switcher.tsx +18 -11
  111. package/docs/showcase/permission-matrix.tsx +13 -13
  112. package/docs/showcase/public-landing.tsx +1 -1
  113. package/docs/showcase/settings-account-sections.tsx +4 -4
  114. package/docs/showcase/settings-security-mfa.tsx +3 -3
  115. package/docs/showcase/table-approval-queue.tsx +1 -1
  116. package/docs/showcase/table-bulk-actions.tsx +49 -52
  117. package/docs/showcase/table-conditional-format.tsx +1 -1
  118. package/docs/showcase/table-crud-list.tsx +1 -1
  119. package/docs/showcase/table-expandable-rows.tsx +101 -98
  120. package/docs/showcase/table-filter-chips.tsx +78 -66
  121. package/docs/showcase/table-footer-totals.tsx +23 -19
  122. package/docs/showcase/table-grouped-subtotals.tsx +7 -4
  123. package/docs/showcase/table-master-detail.tsx +13 -15
  124. package/docs/showcase/table-states.tsx +34 -29
  125. package/docs/showcase/table-sticky-columns.tsx +3 -2
  126. package/docs/showcase/table-tree-rows.tsx +22 -15
  127. package/docs/showcase/table-view-tabs.tsx +12 -14
  128. package/package.json +7 -6
@@ -83,6 +83,7 @@ const THEME = `
83
83
  [data-tenant="futurelastic"] .fl-lead { font-size: 1.25rem; line-height: 1.65; color: hsl(var(--muted-foreground)); max-width: 620px; }
84
84
  [data-tenant="futurelastic"] .fl-note { font-size: 0.9375rem; color: hsl(var(--muted-foreground)); margin-top: 2.5rem; }
85
85
  [data-tenant="futurelastic"] .fl-head { max-width: 640px; margin-inline: auto; text-align: center; }
86
+ [data-tenant="futurelastic"] .fl-hero-actions { margin-top: 1.75rem; }
86
87
  [data-tenant="futurelastic"] .fl-cta-inner { position: relative; max-width: 680px; margin-inline: auto; }
87
88
  [data-tenant="futurelastic"] .fl-footer-tagline { max-width: 260px; }
88
89
  [data-tenant="futurelastic"] .fl-logocloud { display: flex; flex-wrap: wrap; justify-content: center; gap: 1rem 2.5rem; }
@@ -121,7 +122,7 @@ function Navbar() {
121
122
  <span className="fl-brand">
122
123
  futur<span className="fl-gold">elastic</span>
123
124
  </span>
124
- <Flex direction="row" gap="xs" align="center" className="ms-4">
125
+ <Flex direction="row" gap="xs" align="center">
125
126
  {links.map((l, i) => (
126
127
  <Button key={l} variant="ghost" size="sm" aria-current={i === 0 ? "page" : undefined}>
127
128
  {l}
@@ -154,7 +155,7 @@ function Hero() {
154
155
  Futurelastic là pháp nhân holding của nhóm công ty công nghệ &amp; AI vận hành xuyên Nhật
155
156
  Bản và Việt Nam, từ logistics, fintech đến F&amp;B và thương mại.
156
157
  </p>
157
- <Flex direction="row" gap="md" className="mt-7">
158
+ <Flex direction="row" gap="md" className="fl-hero-actions">
158
159
  <Button size="lg">Khám phá hệ sinh thái</Button>
159
160
  <Button variant="outline" size="lg">
160
161
  Liên hệ hợp tác
@@ -176,8 +177,8 @@ function LogoCloud() {
176
177
  ];
177
178
  return (
178
179
  <section className="fl-section-tint">
179
- <div className={SHELL}>
180
- <Text as="p" size="xs" tone="muted" className="mb-6 text-center tracking-widest uppercase">
180
+ <Flex direction="col" gap="lg" className={SHELL}>
181
+ <Text as="p" size="xs" tone="muted" className="text-center tracking-widest uppercase">
181
182
  Các pháp nhân vận hành dưới Futurelastic
182
183
  </Text>
183
184
  <div className="fl-logocloud">
@@ -187,7 +188,7 @@ function LogoCloud() {
187
188
  </span>
188
189
  ))}
189
190
  </div>
190
- </div>
191
+ </Flex>
191
192
  </section>
192
193
  );
193
194
  }
@@ -235,8 +236,8 @@ function Bento() {
235
236
  ];
236
237
  return (
237
238
  <section className="fl-section" id="ventures">
238
- <div className={SHELL}>
239
- <div className="fl-head mb-12">
239
+ <Flex direction="col" gap="xl" className={SHELL}>
240
+ <div className="fl-head">
240
241
  <div className="fl-eyebrow">Hệ sinh thái</div>
241
242
  <h2 className="fl-h2">Một mái nhà, nhiều mũi nhọn</h2>
242
243
  <p className="fl-lead mx-auto">
@@ -260,7 +261,7 @@ function Bento() {
260
261
  </Card>
261
262
  ))}
262
263
  </div>
263
- </div>
264
+ </Flex>
264
265
  </section>
265
266
  );
266
267
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Showcase · OrgSwitcher — sidebar organization/tenant switcher (Slack/Linear pattern)
3
3
  *
4
- * Requested by dxs-platform (godxjp-ui#196) as a "first-class OrgSwitcher component".
4
+ * Requested by dxs-platform as a "first-class OrgSwitcher component".
5
5
  * GATE 0 — Framework-Component Test verdict: **COMPOSITION PATTERN**, not a framework
6
6
  * component. It owns NO new behaviour — search/keyboard/filtering come from `Command`
7
7
  * (cmdk), open/focus-trap/dismiss from `Popover`, the trigger from `Button` + `Avatar`.
@@ -44,6 +44,7 @@ import {
44
44
  AppShell,
45
45
  Flex,
46
46
  PageContainer,
47
+ Separator,
47
48
  Sidebar,
48
49
  type SidebarSectionProp,
49
50
  Topbar,
@@ -116,25 +117,29 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
116
117
  type="button"
117
118
  variant="ghost"
118
119
  aria-label={`Tổ chức hiện tại: ${current.name}. Nhấn để đổi tổ chức`}
119
- className="w-full justify-between gap-2 px-2"
120
+ className="w-full justify-between"
120
121
  >
121
- <Flex align="center" gap="sm" className="min-w-0">
122
+ {/* Inside a Button, i.e. inside a <button>, whose content model is phrasing content
123
+ only — so every Flex on this branch renders as a <span>. */}
124
+ <Flex as="span" align="center" gap="sm" className="min-w-0">
122
125
  <Avatar className="size-7 rounded-md">
123
126
  <AvatarFallback>{monogram(current.name)}</AvatarFallback>
124
127
  </Avatar>
125
- <span className="flex min-w-0 flex-col text-start">
128
+ <Flex as="span" direction="col" gap="none" className="min-w-0 text-start">
126
129
  <Text as="span" size="sm" weight="medium" truncate>
127
130
  {current.name}
128
131
  </Text>
129
132
  <Text as="span" size="xs" tone="muted" truncate>
130
133
  {current.role}
131
134
  </Text>
132
- </span>
135
+ </Flex>
133
136
  </Flex>
134
137
  <ChevronsUpDown aria-hidden className="size-4 shrink-0 opacity-60" />
135
138
  </Button>
136
139
  </PopoverTrigger>
137
- <PopoverContent align="start" sideOffset={6} className="w-64 p-0">
140
+ {/* `flush` the Command list owns its own inset, so its rows and separators run edge to
141
+ edge inside the popover instead of being indented by the panel padding. */}
142
+ <PopoverContent flush align="start" sideOffset={6} className="w-64">
138
143
  <Command label="Chọn tổ chức">
139
144
  <CommandInput
140
145
  placeholder="Tìm tổ chức…"
@@ -154,18 +159,18 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
154
159
  keywords={[org.id]}
155
160
  onSelect={() => choose(org.id)}
156
161
  >
157
- <Flex align="center" gap="sm" className="w-full min-w-0">
162
+ <Flex as="span" align="center" gap="sm" className="w-full min-w-0">
158
163
  <Avatar className="size-6 rounded">
159
164
  <AvatarFallback>{monogram(org.name)}</AvatarFallback>
160
165
  </Avatar>
161
- <span className="flex min-w-0 flex-col text-start">
166
+ <Flex as="span" direction="col" gap="none" className="min-w-0 text-start">
162
167
  <Text as="span" size="sm" truncate>
163
168
  {org.name}
164
169
  </Text>
165
170
  <Text as="span" size="xs" tone="muted" truncate>
166
171
  {org.role}
167
172
  </Text>
168
- </span>
173
+ </Flex>
169
174
  {active ? (
170
175
  <Check aria-hidden className="text-primary ms-auto size-4 shrink-0" />
171
176
  ) : null}
@@ -176,7 +181,9 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
176
181
  })}
177
182
  </CommandGroup>
178
183
  </CommandList>
179
- <div className="border-t p-1">
184
+ <Separator />
185
+ {/* Menu-style footer: the two actions read as one list, so no seam between them. */}
186
+ <Flex direction="col" gap="none">
180
187
  <Button
181
188
  type="button"
182
189
  variant="ghost"
@@ -203,7 +210,7 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
203
210
  <TicketPlus aria-hidden className="size-4" />
204
211
  Tham gia bằng mã mời
205
212
  </Button>
206
- </div>
213
+ </Flex>
207
214
  </Command>
208
215
  </PopoverContent>
209
216
  </Popover>
@@ -4,12 +4,12 @@
4
4
  * A role × permission matrix with a STICKY first column (権限), ✓/— cells, a
5
5
  * two-role COMPARE mode, and a 差分のみ (differences-only) filter — the pattern
6
6
  * DXS role tabs (SCR-203) and the org role editor (SCR-111b) each hand-rolled
7
- * (godxjp-ui#194). Read-only by default.
7
+ *. Read-only by default.
8
8
  *
9
- * SINCE gh#257 the grid itself IS a package export — `PermissionMatrix` from
9
+ * SINCE the grid itself IS a package export — `PermissionMatrix` from
10
10
  * `@godxjp/ui/data-display` (see docs/data-display/permission-matrix.tsx). The
11
11
  * original Gate-0 "composition pattern" verdict was OUTCOME-corrected the same
12
- * way ErrorSurface was (gh#251): a consumer cannot import a docs page, so the
12
+ * way ErrorSurface was: a consumer cannot import a docs page, so the
13
13
  * canonical grid needed an importable home. Prefer the export in app code.
14
14
  *
15
15
  * This showcase remains as the COMPOSED form of the same screen — the full
@@ -129,10 +129,10 @@ function GrantCell({ granted }: { granted: boolean }) {
129
129
  <span className="sr-only">許可</span>
130
130
  </Badge>
131
131
  ) : (
132
- <span className="text-muted-foreground inline-flex items-center justify-center">
132
+ <Flex align="center" justify="center" gap="none" className="text-muted-foreground">
133
133
  <Minus aria-hidden="true" className="size-4" />
134
134
  <span className="sr-only">不許可</span>
135
- </span>
135
+ </Flex>
136
136
  );
137
137
  }
138
138
 
@@ -240,19 +240,19 @@ export default function Demo() {
240
240
  className={cn("text-center", isCompared && "bg-primary/[0.06]")}
241
241
  aria-label={isCompared ? `${role.name}(比較対象)` : role.name}
242
242
  >
243
- <span className="inline-flex flex-col items-center leading-tight">
244
- <span className="inline-flex items-center gap-1">
243
+ <Flex direction="col" align="center" gap="none" className="leading-tight">
244
+ <Flex align="center" gap="xs">
245
245
  <Text weight="medium">{role.name}</Text>
246
246
  {isCompared && (
247
247
  <Badge tone="primary" variant="outline">
248
248
  {role.id === compareA ? "A" : "B"}
249
249
  </Badge>
250
250
  )}
251
- </span>
251
+ </Flex>
252
252
  <Text size="2xs" tone="muted">
253
253
  {role.hint} · {countGrants(PERMISSIONS, GRANTS, role.id)}件
254
254
  </Text>
255
- </span>
255
+ </Flex>
256
256
  </TableHead>
257
257
  );
258
258
  })}
@@ -270,14 +270,14 @@ export default function Demo() {
270
270
  >
271
271
  <TableCell className={cn(PIN_START, "w-64 min-w-64 align-middle")}>
272
272
  <Flex direction="col" className="leading-tight">
273
- <span className="inline-flex items-center gap-1.5">
273
+ <Flex align="center" gap="xs">
274
274
  <Text weight="medium">{perm.name}</Text>
275
275
  {isDiffRow && (
276
276
  <Badge tone="warning" variant="outline">
277
277
  差分
278
278
  </Badge>
279
279
  )}
280
- </span>
280
+ </Flex>
281
281
  <Text size="2xs" tone="muted">
282
282
  {perm.category} · {perm.description}
283
283
  </Text>
@@ -322,9 +322,9 @@ export default function Demo() {
322
322
  </Text>
323
323
  </Flex>
324
324
  <Flex direction="row" align="center" gap="xs">
325
- <span className="text-muted-foreground inline-flex">
325
+ <Flex align="center" gap="none" className="text-muted-foreground">
326
326
  <Minus aria-hidden="true" className="size-4" />
327
- </span>
327
+ </Flex>
328
328
  <Text size="xs" tone="muted">
329
329
  不許可
330
330
  </Text>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Showcase · Public landing (gh#252) — the PUBLIC marketing/product landing page composed from
2
+ * Showcase · Public landing — the PUBLIC marketing/product landing page composed from
3
3
  * real @godxjp/ui primitives with **zero page-local CSS**.
4
4
  *
5
5
  * Gate 0 (docs/COMPOSITION-VS-COMPONENT.md): a landing header / hero / section grid / legal footer
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Showcase · settings-account-sections — the canonical SETTINGS SECTION / ROW composition (gh#216)
2
+ * Showcase · settings-account-sections — the canonical SETTINGS SECTION / ROW composition
3
3
  *
4
4
  * ── Gate 0 verdict: COMPOSITION PATTERN, not a framework component ────────────────────────────
5
5
  * A "SettingsSection" / "SettingsRow" / "DangerZone" fails the Framework-Component Test
@@ -61,7 +61,7 @@ import { AlertDialog } from "@godxjp/ui/feedback";
61
61
  import { Flex, PageContainer } from "@godxjp/ui/layout";
62
62
 
63
63
  // ── Label bundles: the SAME screen at its longest JA / EN / VI wording ────────────────────────
64
- // Long-label stress is a first-class acceptance criterion (#216), so the bundle intentionally
64
+ // Long-label stress is a first-class acceptance criterion, so the bundle intentionally
65
65
  // carries the verbose form of each label instead of the tidy demo form.
66
66
 
67
67
  type LabelBundle = {
@@ -348,7 +348,7 @@ export default function SettingsAccountSectionsShowcase() {
348
348
  title={b.pageTitle}
349
349
  subtitle={b.pageSubtitle}
350
350
  breadcrumb={[{ label: b.pageTitle }]}
351
- // PageHeader action composition (#216): the header owns the page-level actions through
351
+ // PageHeader action composition: the header owns the page-level actions through
352
352
  // `extra`. It wraps at 390 instead of overflowing, so no page-local header geometry.
353
353
  extra={
354
354
  <Flex direction="row" align="end" gap="sm" wrap>
@@ -477,7 +477,7 @@ export default function SettingsAccountSectionsShowcase() {
477
477
  </Descriptions>
478
478
  </CardContent>
479
479
  <CardFooter separated>
480
- <Flex direction="col" gap="xs" className="sm:flex-row sm:items-center sm:gap-4">
480
+ <Flex direction="col" gap="md" className="sm:flex-row sm:items-center">
481
481
  <Button variant="outline" asChild>
482
482
  <a href="https://billing.example.com/portal" target="_blank" rel="noreferrer">
483
483
  <ExternalLink aria-hidden="true" />
@@ -7,13 +7,13 @@
7
7
  * ✗ wrong (hand-rolled) ✓ here (rule)
8
8
  * ─────────────────────────────────────────────────────────────────────────────────────────
9
9
  * factor row = a centered <div> with the ListRow — leading icon · title/description ·
10
- * title duplicated as its own description trailing action (no redundant copy) (#113)
10
+ * title duplicated as its own description trailing action (no redundant copy)
11
11
  * "Xoá" rendered as plain black text destructive-toned ghost button — delete is a
12
12
  * destructive action, color carries intent
13
13
  * every action a full-width stacked bar right-aligned, auto-width actions; ONE primary
14
14
  * (rule 217 explicitly forbids this) per card, secondary = outline (rule 217)
15
15
  * 📱 / ✉️ emoji as "icons" lucide icons (no emoji in product UI) (anti-tell)
16
- * brand glyph = a styled <span> (size/radius Avatar primitive — real brand mark (#116)
16
+ * brand glyph = a styled <span> (size/radius Avatar primitive — real brand mark
17
17
  * baked as literals)
18
18
  *
19
19
  * Built ENTIRELY from real @godxjp/ui primitives. reference-design DNA: small headings, 14/1.7 body,
@@ -130,7 +130,7 @@ export default function SecurityMfaShowcase() {
130
130
  </Text>
131
131
  </Flex>
132
132
  </CardContent>
133
- <CardFooter separated className="justify-end gap-2">
133
+ <CardFooter separated className="justify-end">
134
134
  <Button variant="ghost" size="sm">
135
135
  Tải xuống
136
136
  </Button>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Showcase · アクセス承認キュー / Access approval queue (gh#253) — the canonical five-column
2
+ * Showcase · アクセス承認キュー / Access approval queue — the canonical five-column
3
3
  * approval collection at 1440 · 1024 · 390 using ONLY public API.
4
4
  *
5
5
  * The whole responsive contract is `Table preset="action-collection"` plus a `priority` on each
@@ -202,61 +202,58 @@ function BulkActionBar({
202
202
  }) {
203
203
  const effective = spanAll ? total : count;
204
204
  return (
205
- <Flex
206
- role="region"
207
- aria-label="一括操作"
208
- wrap
209
- align="center"
210
- gap="md"
211
- className="bg-primary/5 border-primary/30 rounded-md border px-3 py-2"
212
- >
213
- {/* left: count + cross-page select-all escalation + safe batch actions */}
214
- <Flex direction="row" align="center" gap="sm" className="min-w-0 flex-1">
215
- <Text tone="primary" weight="medium" tabular className="whitespace-nowrap">
216
- {effective}件を選択中
217
- </Text>
218
-
219
- {/* cross-page select-all: only offered once the whole page is selected */}
220
- {pageAllSelected &&
221
- (spanAll ? (
222
- <Text size="xs" tone="muted">
223
- フィルタ条件の全{" "}
224
- <Text as="span" tabular>
225
- {total}
226
- </Text>{" "}
227
- 件を選択しました
205
+ <Card className="bg-primary/5 border-primary/30">
206
+ <CardContent solo>
207
+ <Flex role="region" aria-label="一括操作" wrap align="center" gap="md">
208
+ {/* left: count + cross-page select-all escalation + safe batch actions */}
209
+ <Flex direction="row" align="center" gap="sm" className="min-w-0 flex-1">
210
+ <Text tone="primary" weight="medium" tabular className="whitespace-nowrap">
211
+ {effective}件を選択中
228
212
  </Text>
229
- ) : (
230
- <Button variant="link" size="sm" onClick={onSelectSpanAll}>
231
- 全 <span className="tabular-nums">{total}</span> 件を選択
213
+
214
+ {/* cross-page select-all: only offered once the whole page is selected */}
215
+ {pageAllSelected &&
216
+ (spanAll ? (
217
+ <Text size="xs" tone="muted">
218
+ フィルタ条件の全{" "}
219
+ <Text as="span" tabular>
220
+ {total}
221
+ </Text>{" "}
222
+ 件を選択しました
223
+ </Text>
224
+ ) : (
225
+ <Button variant="link" size="sm" onClick={onSelectSpanAll}>
226
+ 全 <span className="tabular-nums">{total}</span> 件を選択
227
+ </Button>
228
+ ))}
229
+
230
+ <span className="bg-border h-4 w-px" aria-hidden="true" />
231
+
232
+ <Button variant="outline" size="sm" onClick={onApprove}>
233
+ <CheckCheck aria-hidden="true" />
234
+ 一括承認
232
235
  </Button>
233
- ))}
234
-
235
- <span className="bg-border h-4 w-px" aria-hidden="true" />
236
-
237
- <Button variant="outline" size="sm" onClick={onApprove}>
238
- <CheckCheck aria-hidden="true" />
239
- 一括承認
240
- </Button>
241
- <Button variant="outline" size="sm" onClick={onExport}>
242
- <Download aria-hidden="true" />
243
- CSV出力
244
- </Button>
245
- </Flex>
236
+ <Button variant="outline" size="sm" onClick={onExport}>
237
+ <Download aria-hidden="true" />
238
+ CSV出力
239
+ </Button>
240
+ </Flex>
246
241
 
247
- {/* right: ISOLATED destructive action, kept apart from the safe ones */}
248
- <Flex direction="row" align="center" gap="sm">
249
- <Button variant="destructive" size="sm" onClick={onDelete}>
250
- <Trash2 aria-hidden="true" />
251
- 一括削除
252
- </Button>
253
- <span className="bg-border h-4 w-px" aria-hidden="true" />
254
- <Button variant="ghost" size="sm" onClick={onClear} aria-label="選択を解除">
255
- <X aria-hidden="true" />
256
- 解除
257
- </Button>
258
- </Flex>
259
- </Flex>
242
+ {/* right: ISOLATED destructive action, kept apart from the safe ones */}
243
+ <Flex direction="row" align="center" gap="sm">
244
+ <Button variant="destructive" size="sm" onClick={onDelete}>
245
+ <Trash2 aria-hidden="true" />
246
+ 一括削除
247
+ </Button>
248
+ <span className="bg-border h-4 w-px" aria-hidden="true" />
249
+ <Button variant="ghost" size="sm" onClick={onClear} aria-label="選択を解除">
250
+ <X aria-hidden="true" />
251
+ 解除
252
+ </Button>
253
+ </Flex>
254
+ </Flex>
255
+ </CardContent>
256
+ </Card>
260
257
  );
261
258
  }
262
259
 
@@ -247,7 +247,7 @@ export default function Demo() {
247
247
  <Flex direction="col" gap="lg">
248
248
  {/* ── 行レベル + セルレベルの条件付き書式(実 Table primitive で合成) ── */}
249
249
  <Card>
250
- <CardHeader className="gap-2">
250
+ <CardHeader>
251
251
  <Flex direction="row" wrap align="center" justify="between" gap="sm">
252
252
  <CardTitle level={2}>勤怠サマリ · 製造部(当月締め)</CardTitle>
253
253
  <Text size="xs" tone="muted" tabular>
@@ -497,7 +497,7 @@ export default function Demo() {
497
497
  </CardContent>
498
498
 
499
499
  {/* Footer totals — composed from CardFooter + Badge, not a hand-rolled bar. */}
500
- <CardFooter className="flex-wrap justify-between gap-3">
500
+ <CardFooter className="flex-wrap justify-between">
501
501
  <Flex direction="row" gap="md" align="center" wrap>
502
502
  <Text size="xs" tone="muted">
503
503
  選択中{" "}