@godxjp/ui 19.2.0 → 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 (144) hide show
  1. package/dist/components/data-display/badge.d.ts +26 -2
  2. package/dist/components/data-display/badge.js +20 -5
  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 +72 -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 +113 -2
  37. package/dist/props/registry.js +155 -1
  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/badge-layout.css +15 -0
  43. package/dist/styles/control.css +18 -1
  44. package/dist/styles/data-display-layout.css +167 -0
  45. package/dist/styles/layout.css +7 -0
  46. package/dist/styles/shell-layout.css +148 -0
  47. package/dist/styles/table-layout.css +23 -4
  48. package/dist/tokens/components/badge.css +8 -0
  49. package/dist/tokens/components/control.css +1 -0
  50. package/dist/tokens/components/data-display.css +20 -0
  51. package/dist/tokens/components/shell.css +22 -0
  52. package/dist/tokens/components/table.css +2 -0
  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 +37 -1
  57. package/docs/data-display/card/index.tsx +6 -4
  58. package/docs/data-display/carousel.tsx +8 -4
  59. package/docs/data-display/data-table/examples/approval-queue.tsx +1 -1
  60. package/docs/data-display/data-table/examples/grid-features.tsx +1 -1
  61. package/docs/data-display/data-table/index.tsx +1 -1
  62. package/docs/data-display/permission-matrix.tsx +15 -11
  63. package/docs/data-display/popover.tsx +2 -1
  64. package/docs/data-display/scroll-area.tsx +108 -76
  65. package/docs/data-display/table.tsx +2 -2
  66. package/docs/data-display/timeline-grid.tsx +119 -0
  67. package/docs/data-entry/branch-scope-picker.tsx +1 -1
  68. package/docs/data-entry/calendar.tsx +1 -1
  69. package/docs/data-entry/checkbox.tsx +1 -1
  70. package/docs/data-entry/country-picker-recipe.tsx +11 -6
  71. package/docs/data-entry/form-field/index.tsx +33 -29
  72. package/docs/data-entry/form-root.tsx +1 -1
  73. package/docs/data-entry/input-otp.tsx +1 -1
  74. package/docs/data-entry/password-input.tsx +1 -5
  75. package/docs/data-entry/select.tsx +7 -7
  76. package/docs/data-entry/textarea.tsx +3 -3
  77. package/docs/data-entry/toggle-count.tsx +1 -1
  78. package/docs/feedback/alert.tsx +1 -1
  79. package/docs/feedback/banner.tsx +1 -1
  80. package/docs/feedback/sheet.tsx +112 -102
  81. package/docs/feedback/skeleton.tsx +2 -2
  82. package/docs/foundation/colors.tsx +8 -6
  83. package/docs/foundation/email-tokens.tsx +83 -66
  84. package/docs/foundation/radius-shadow.tsx +13 -11
  85. package/docs/general/activity.tsx +1 -1
  86. package/docs/layout/app-shell.tsx +2 -2
  87. package/docs/layout/aspect-ratio.tsx +30 -14
  88. package/docs/layout/auth-account-summary.tsx +1 -1
  89. package/docs/layout/auth-recovery/examples/mobile-390.tsx +1 -1
  90. package/docs/layout/auth-recovery/examples/password-recovery.tsx +0 -2
  91. package/docs/layout/auth-shell-context.tsx +1 -1
  92. package/docs/layout/auth-shell-device.tsx +2 -2
  93. package/docs/layout/auth-shell-registration.tsx +1 -1
  94. package/docs/layout/auth-shell.tsx +1 -1
  95. package/docs/layout/flex.tsx +6 -2
  96. package/docs/layout/master-detail.tsx +2 -2
  97. package/docs/layout/mobile-shell.tsx +101 -0
  98. package/docs/layout/page-container.tsx +15 -7
  99. package/docs/layout/responsive-grid.tsx +12 -4
  100. package/docs/layout/separator.tsx +2 -2
  101. package/docs/layout/service-role-panel.tsx +1 -1
  102. package/docs/layout/sidebar.tsx +175 -152
  103. package/docs/layout/split-pane.tsx +45 -28
  104. package/docs/layout/topbar.tsx +19 -23
  105. package/docs/navigation/app-setting-picker.tsx +5 -4
  106. package/docs/navigation/breadcrumb.tsx +12 -5
  107. package/docs/navigation/context-menu.tsx +10 -4
  108. package/docs/navigation/filter-bar.tsx +2 -2
  109. package/docs/navigation/navigation-menu.tsx +89 -96
  110. package/docs/navigation/pagination.tsx +2 -2
  111. package/docs/navigation/steps.tsx +13 -11
  112. package/docs/navigation/tabs.tsx +27 -21
  113. package/docs/navigation/toolbar.tsx +15 -15
  114. package/docs/providers/format-date.tsx +2 -2
  115. package/docs/showcase/acme-portal.tsx +41 -28
  116. package/docs/showcase/acme-website.tsx +67 -61
  117. package/docs/showcase/case1-warehouse-dashboard.tsx +46 -31
  118. package/docs/showcase/case2-employee-me.tsx +33 -36
  119. package/docs/showcase/case3-approval-workflow.tsx +34 -32
  120. package/docs/showcase/case4-login.tsx +95 -101
  121. package/docs/showcase/case5-shift-calendar.tsx +182 -281
  122. package/docs/showcase/case6-agency-handy.tsx +514 -470
  123. package/docs/showcase/futurelastic-web.tsx +32 -29
  124. package/docs/showcase/org-switcher.tsx +20 -13
  125. package/docs/showcase/permission-matrix.tsx +20 -17
  126. package/docs/showcase/public-landing.tsx +1 -1
  127. package/docs/showcase/settings-account-sections.tsx +2 -2
  128. package/docs/showcase/settings-security-mfa.tsx +3 -3
  129. package/docs/showcase/table-approval-queue.tsx +1 -1
  130. package/docs/showcase/table-bulk-actions.tsx +49 -52
  131. package/docs/showcase/table-conditional-format.tsx +9 -9
  132. package/docs/showcase/table-crud-list.tsx +4 -4
  133. package/docs/showcase/table-density.tsx +49 -42
  134. package/docs/showcase/table-expandable-rows.tsx +112 -100
  135. package/docs/showcase/table-filter-chips.tsx +78 -71
  136. package/docs/showcase/table-footer-totals.tsx +30 -23
  137. package/docs/showcase/table-grouped-subtotals.tsx +31 -25
  138. package/docs/showcase/table-master-detail.tsx +27 -24
  139. package/docs/showcase/table-pagination.tsx +34 -27
  140. package/docs/showcase/table-states.tsx +42 -34
  141. package/docs/showcase/table-sticky-columns.tsx +11 -7
  142. package/docs/showcase/table-tree-rows.tsx +22 -15
  143. package/docs/showcase/table-view-tabs.tsx +12 -14
  144. package/package.json +7 -7
@@ -28,6 +28,7 @@ import * as React from "react";
28
28
  import {
29
29
  Badge,
30
30
  Card,
31
+ CardAction,
31
32
  CardContent,
32
33
  CardHeader,
33
34
  CardTitle,
@@ -199,11 +200,13 @@ export default function Demo() {
199
200
  density="compact"
200
201
  >
201
202
  <Card>
202
- <CardHeader className="flex flex-row items-center justify-between">
203
+ <CardHeader>
203
204
  <CardTitle level={2}>従業員別 月次集計</CardTitle>
204
- <Text size="xs" tone="muted" tabular>
205
- 対象 {ROWS.length}
206
- </Text>
205
+ <CardAction>
206
+ <Text size="xs" tone="muted" tabular>
207
+ 対象 {ROWS.length} 名
208
+ </Text>
209
+ </CardAction>
207
210
  </CardHeader>
208
211
  {/* flush so the table meets the card edge; vertical scroll inside the
209
212
  card with header pinned top and totals pinned bottom. */}
@@ -286,25 +289,29 @@ export default function Demo() {
286
289
  </CardContent>
287
290
  </Card>
288
291
 
289
- <Flex direction="row" align="center" gap="xs" className="mt-3">
290
- <Text size="xs" tone="muted">
291
- 残業 凡例:
292
- </Text>
293
- <Badge tone="success" variant="outline">
294
- ~15h
295
- </Badge>
296
- <Badge tone="info" variant="outline">
297
- 15h~
298
- </Badge>
299
- <Badge tone="warning" variant="outline">
300
- 25h~
301
- </Badge>
302
- <Text size="xs" tone="muted" className="ms-2">
303
- 遅刻:
304
- </Text>
305
- <Badge tone="destructive" variant="outline">
306
- 回数
307
- </Badge>
292
+ <Flex direction="row" align="center" wrap gap="md">
293
+ <Flex direction="row" align="center" gap="xs">
294
+ <Text size="xs" tone="muted">
295
+ 残業 凡例:
296
+ </Text>
297
+ <Badge tone="success" variant="outline">
298
+ ~15h
299
+ </Badge>
300
+ <Badge tone="info" variant="outline">
301
+ 15h~
302
+ </Badge>
303
+ <Badge tone="warning" variant="outline">
304
+ 25h~
305
+ </Badge>
306
+ </Flex>
307
+ <Flex direction="row" align="center" gap="xs">
308
+ <Text size="xs" tone="muted">
309
+ 遅刻:
310
+ </Text>
311
+ <Badge tone="destructive" variant="outline">
312
+ 回数
313
+ </Badge>
314
+ </Flex>
308
315
  </Flex>
309
316
  </PageContainer>
310
317
  );
@@ -19,6 +19,7 @@ import { Button, Text } from "@godxjp/ui/general";
19
19
  import {
20
20
  Badge,
21
21
  Card,
22
+ CardAction,
22
23
  CardContent,
23
24
  CardHeader,
24
25
  CardTitle,
@@ -225,26 +226,26 @@ function GroupHeaderRow({
225
226
  const Chevron = open ? ChevronDown : ChevronRight;
226
227
  return (
227
228
  <TableRow className="bg-secondary hover:bg-secondary border-b">
228
- <TableCell className="py-2 ps-2 pe-0" colSpan={2}>
229
+ <TableCell colSpan={2}>
229
230
  <Button
230
231
  variant="ghost"
231
232
  size="sm"
232
233
  onClick={onToggle}
233
234
  aria-expanded={open}
234
235
  aria-controls={`grp-${group.id}`}
235
- className="h-7 gap-2 font-medium"
236
+ className="h-7 font-medium"
236
237
  >
237
238
  <Chevron className="text-muted-foreground size-4" aria-hidden="true" />
238
239
  {group.label}
239
- <Badge variant="outline" tone="neutral" className="ms-1">
240
+ <Badge variant="outline" tone="neutral">
240
241
  {group.members.length}名
241
242
  </Badge>
242
243
  </Button>
243
244
  </TableCell>
244
- <TableCell className="py-2 text-end font-medium tabular-nums">{s.days}日</TableCell>
245
- <TableCell className="py-2 text-end font-medium tabular-nums">{fmtH(s.work)}</TableCell>
246
- <TableCell className="py-2 text-end font-medium tabular-nums">{fmtH(s.overtime)}</TableCell>
247
- <TableCell className="py-2 text-end tabular-nums">
245
+ <TableCell className="text-end font-medium tabular-nums">{s.days}日</TableCell>
246
+ <TableCell className="text-end font-medium tabular-nums">{fmtH(s.work)}</TableCell>
247
+ <TableCell className="text-end font-medium tabular-nums">{fmtH(s.overtime)}</TableCell>
248
+ <TableCell className="text-end tabular-nums">
248
249
  {s.late > 0 ? (
249
250
  <Badge variant="outline" tone="warning">
250
251
  {s.late}回
@@ -255,7 +256,7 @@ function GroupHeaderRow({
255
256
  </Text>
256
257
  )}
257
258
  </TableCell>
258
- <TableCell className="py-2" />
259
+ <TableCell />
259
260
  </TableRow>
260
261
  );
261
262
  }
@@ -265,7 +266,10 @@ function GroupHeaderRow({
265
266
  function MemberRow({ m }: { m: Employee }) {
266
267
  return (
267
268
  <TableRow>
268
- <TableCell className="text-muted-foreground ps-10 font-mono text-xs">{m.id}</TableCell>
269
+ {/* `indent` the detail row sits one hierarchy level under its group header. */}
270
+ <TableCell indent={1} className="text-muted-foreground font-mono text-xs">
271
+ {m.id}
272
+ </TableCell>
269
273
  <TableCell>{m.name}</TableCell>
270
274
  <TableCell className="text-end tabular-nums">{m.days}日</TableCell>
271
275
  <TableCell className="text-end tabular-nums">{fmtH(m.work)}</TableCell>
@@ -330,18 +334,16 @@ function GroupedTable({
330
334
  })}
331
335
  {/* 総計フッター行 */}
332
336
  <TableRow className="bg-muted/40 hover:bg-muted/40 border-t-2">
333
- <TableCell className="py-2 font-medium" colSpan={2}>
337
+ <TableCell className="font-medium" colSpan={2}>
334
338
  総計 · 全{groups.reduce((n, g) => n + g.members.length, 0)}名
335
339
  </TableCell>
336
- <TableCell className="py-2 text-end font-bold tabular-nums">{total.days}日</TableCell>
337
- <TableCell className="py-2 text-end font-bold tabular-nums">
338
- {fmtH(total.work)}
339
- </TableCell>
340
- <TableCell className="py-2 text-end font-bold tabular-nums">
340
+ <TableCell className="text-end font-bold tabular-nums">{total.days}日</TableCell>
341
+ <TableCell className="text-end font-bold tabular-nums">{fmtH(total.work)}</TableCell>
342
+ <TableCell className="text-end font-bold tabular-nums">
341
343
  {fmtH(total.overtime)}
342
344
  </TableCell>
343
- <TableCell className="py-2 text-end font-bold tabular-nums">{total.late}回</TableCell>
344
- <TableCell className="py-2" />
345
+ <TableCell className="text-end font-bold tabular-nums">{total.late}回</TableCell>
346
+ <TableCell />
345
347
  </TableRow>
346
348
  </TableBody>
347
349
  </Table>
@@ -359,11 +361,13 @@ export default function Demo() {
359
361
  <Flex direction="col" gap="lg">
360
362
  {/* 全展開(既定)— 各グループの小計と明細が同時に見える */}
361
363
  <Card>
362
- <CardHeader className="flex flex-row items-center justify-between">
364
+ <CardHeader>
363
365
  <CardTitle level={2}>2026年5月度 勤怠集計</CardTitle>
364
- <Text size="xs" tone="muted" tabular>
365
- 締め: 2026-05-31
366
- </Text>
366
+ <CardAction>
367
+ <Text size="xs" tone="muted" tabular>
368
+ 締め: 2026-05-31
369
+ </Text>
370
+ </CardAction>
367
371
  </CardHeader>
368
372
  <CardContent flush>
369
373
  <GroupedTable groups={GROUPS} />
@@ -372,11 +376,13 @@ export default function Demo() {
372
376
 
373
377
  {/* 折りたたみ済みの状態を静的に提示 — 「カスタマーサポート部」は閉じて小計のみ表示 */}
374
378
  <Card>
375
- <CardHeader className="flex flex-row items-center justify-between">
379
+ <CardHeader>
376
380
  <CardTitle level={2}>折りたたみ状態</CardTitle>
377
- <Text size="xs" tone="muted">
378
- 閉じたグループは小計のみ表示(クリックで展開)
379
- </Text>
381
+ <CardAction>
382
+ <Text size="xs" tone="muted">
383
+ 閉じたグループは小計のみ表示(クリックで展開)
384
+ </Text>
385
+ </CardAction>
380
386
  </CardHeader>
381
387
  <CardContent flush>
382
388
  <GroupedTable groups={GROUPS} defaultClosed={["support"]} />
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Composition map (intent → real @godxjp/ui primitive):
10
10
  * resizable split ........ ResizablePanelGroup + ResizablePanel + ResizableHandle
11
- * fixed-track split ...... MasterDetail (tokenized rail + stacking threshold, gh#223)
11
+ * fixed-track split ...... MasterDetail (tokenized rail + stacking threshold, )
12
12
  * master list ............ DataTable (compact, clickable rows, selected row)
13
13
  * status cell ............ Badge tone (出勤/遅刻/早退/休暇 — fixed signaling)
14
14
  * detail header .......... Avatar + heading + Badge + action Buttons
@@ -31,16 +31,17 @@ import {
31
31
  Avatar,
32
32
  AvatarFallback,
33
33
  Badge,
34
- type BadgeProps,
35
34
  Card,
35
+ CardAction,
36
36
  CardContent,
37
37
  CardHeader,
38
38
  CardTitle,
39
- type ColumnDef,
40
39
  DataTable,
41
40
  Descriptions,
42
41
  EmptyState,
43
42
  Timeline,
43
+ type BadgeProps,
44
+ type ColumnDef,
44
45
  type TimelineItem,
45
46
  } from "@godxjp/ui/data-display";
46
47
  import {
@@ -369,11 +370,13 @@ export default function Demo() {
369
370
  <Flex direction="col" gap="lg">
370
371
  {/* ── Resizable master/detail split (Gmail-style) ── */}
371
372
  <Card>
372
- <CardHeader className="flex flex-row items-center justify-between">
373
+ <CardHeader>
373
374
  <CardTitle level={2}>本日の出勤状況</CardTitle>
374
- <Text size="xs" tone="muted" tabular>
375
- 2026-06-04 · {EMPLOYEES.length}名
376
- </Text>
375
+ <CardAction>
376
+ <Text size="xs" tone="muted" tabular>
377
+ 2026-06-04 · {EMPLOYEES.length}名
378
+ </Text>
379
+ </CardAction>
377
380
  </CardHeader>
378
381
  <CardContent flush>
379
382
  <ResizablePanelGroup orientation="horizontal" className="min-h-[460px]">
@@ -395,7 +398,7 @@ export default function Demo() {
395
398
 
396
399
  {/* Detail pane */}
397
400
  <ResizablePanel defaultSize="58%" minSize="34%">
398
- <div className="h-full overflow-auto p-5">
401
+ <CardContent solo className="h-full overflow-auto">
399
402
  {selected ? (
400
403
  <EmployeeDetail employee={selected} />
401
404
  ) : (
@@ -407,7 +410,7 @@ export default function Demo() {
407
410
  />
408
411
  </Flex>
409
412
  )}
410
- </div>
413
+ </CardContent>
411
414
  </ResizablePanel>
412
415
  </ResizablePanelGroup>
413
416
  </CardContent>
@@ -439,24 +442,24 @@ export default function Demo() {
439
442
  />
440
443
  }
441
444
  >
442
- <div className="rounded-md border border-dashed p-8">
443
- <EmptyState
444
- icon={UserRound}
445
- title="従業員を選択してください"
446
- description="一覧から行を選ぶと詳細が表示されます。"
447
- />
448
- </div>
445
+ <EmptyState
446
+ icon={UserRound}
447
+ title="従業員を選択してください"
448
+ description="一覧から行を選ぶと詳細が表示されます。"
449
+ />
449
450
  </MasterDetail>
450
451
  </CardContent>
451
452
  </Card>
452
453
 
453
454
  {/* ── Narrow fallback: stacked list + detail (no side room) ── */}
454
455
  <Card>
455
- <CardHeader className="flex flex-row items-center justify-between">
456
+ <CardHeader>
456
457
  <CardTitle level={2}>狭幅レイアウト(縦積み)</CardTitle>
457
- <Text size="xs" tone="muted">
458
- サイドペインが取れない幅では一覧の下に詳細を重ねます
459
- </Text>
458
+ <CardAction>
459
+ <Text size="xs" tone="muted">
460
+ サイドペインが取れない幅では一覧の下に詳細を重ねます
461
+ </Text>
462
+ </CardAction>
460
463
  </CardHeader>
461
464
  <CardContent flush>
462
465
  <DataTable
@@ -467,10 +470,10 @@ export default function Demo() {
467
470
  selected={new Set(["E-1042"])}
468
471
  onRowClick={() => {}}
469
472
  />
470
- <Separator />
471
- <div className="p-5">
472
- <EmployeeDetail employee={EMPLOYEES[0]} />
473
- </div>
473
+ </CardContent>
474
+ <Separator />
475
+ <CardContent solo>
476
+ <EmployeeDetail employee={EMPLOYEES[0]} />
474
477
  </CardContent>
475
478
  </Card>
476
479
  </Flex>
@@ -26,6 +26,7 @@ import * as React from "react";
26
26
  import {
27
27
  Badge,
28
28
  Card,
29
+ CardAction,
29
30
  CardContent,
30
31
  CardHeader,
31
32
  CardTitle,
@@ -145,11 +146,13 @@ function NumberedPaginationCard() {
145
146
 
146
147
  return (
147
148
  <Card>
148
- <CardHeader className="flex flex-row items-center justify-between">
149
+ <CardHeader>
149
150
  <CardTitle level={2}>番号付き + 件数選択</CardTitle>
150
- <Text size="xs" tone="muted" tabular>
151
- {NUMBERED_DATA.length}
152
- </Text>
151
+ <CardAction>
152
+ <Text size="xs" tone="muted" tabular>
153
+ 全 {NUMBERED_DATA.length} 件
154
+ </Text>
155
+ </CardAction>
153
156
  </CardHeader>
154
157
  <CardContent flush>
155
158
  <DataTable data={rows} columns={columns} getRowId={(row) => row.id} density="compact" />
@@ -198,11 +201,13 @@ function LoadMoreCard() {
198
201
 
199
202
  return (
200
203
  <Card>
201
- <CardHeader className="flex flex-row items-center justify-between">
204
+ <CardHeader>
202
205
  <CardTitle level={2}>もっと読む</CardTitle>
203
- <Text size="xs" tone="muted" tabular>
204
- {rows.length} / {LOADMORE_DATA.length} 件表示
205
- </Text>
206
+ <CardAction>
207
+ <Text size="xs" tone="muted" tabular>
208
+ {rows.length} / {LOADMORE_DATA.length} 件表示
209
+ </Text>
210
+ </CardAction>
206
211
  </CardHeader>
207
212
  <CardContent flush>
208
213
  <DataTable data={rows} columns={columns} getRowId={(row) => row.id} density="compact" />
@@ -263,26 +268,28 @@ function CursorPeriodCard() {
263
268
 
264
269
  return (
265
270
  <Card>
266
- <CardHeader className="flex flex-row items-center justify-between gap-3">
271
+ <CardHeader>
267
272
  <CardTitle level={2}>カーソル / 期間ジャンプ</CardTitle>
268
- <Select
269
- value={period}
270
- onValueChange={(v: string) => {
271
- setPeriod(v);
272
- setCursor(undefined); // jumping period resets the cursor to the first page
273
- }}
274
- >
275
- <SelectTrigger size="sm" aria-label="期間を選択" className="w-36">
276
- <SelectValue />
277
- </SelectTrigger>
278
- <SelectContent>
279
- {PERIODS.map((p) => (
280
- <SelectItem key={p.value} value={p.value}>
281
- {p.label}
282
- </SelectItem>
283
- ))}
284
- </SelectContent>
285
- </Select>
273
+ <CardAction>
274
+ <Select
275
+ value={period}
276
+ onValueChange={(v: string) => {
277
+ setPeriod(v);
278
+ setCursor(undefined); // jumping period resets the cursor to the first page
279
+ }}
280
+ >
281
+ <SelectTrigger size="sm" aria-label="期間を選択" className="w-36">
282
+ <SelectValue />
283
+ </SelectTrigger>
284
+ <SelectContent>
285
+ {PERIODS.map((p) => (
286
+ <SelectItem key={p.value} value={p.value}>
287
+ {p.label}
288
+ </SelectItem>
289
+ ))}
290
+ </SelectContent>
291
+ </Select>
292
+ </CardAction>
286
293
  </CardHeader>
287
294
  <CardContent flush>
288
295
  <DataTable data={rows} columns={columns} getRowId={(row) => row.id} density="compact" />
@@ -29,12 +29,13 @@ import { Button, Heading, Text } from "@godxjp/ui/general";
29
29
  import {
30
30
  Badge,
31
31
  Card,
32
+ CardAction,
32
33
  CardContent,
33
34
  CardHeader,
34
35
  CardTitle,
35
- type ColumnDef,
36
36
  DataTable,
37
37
  EmptyState,
38
+ type ColumnDef,
38
39
  } from "@godxjp/ui/data-display";
39
40
  import {
40
41
  Alert,
@@ -190,20 +191,26 @@ function StateSection({
190
191
  * the loading skeleton visibly preserves the table's column layout. */
191
192
  function TableShell({
192
193
  caption,
194
+ banner,
193
195
  children,
194
196
  }: {
195
197
  caption: React.ReactNode;
196
- children: React.ReactNode;
198
+ /** Padded band between the header and the flush table body (an Alert). */
199
+ banner?: React.ReactNode;
200
+ children?: React.ReactNode;
197
201
  }) {
198
202
  return (
199
203
  <Card>
200
- <CardHeader className="flex flex-row items-center justify-between">
204
+ <CardHeader>
201
205
  <CardTitle level={2}>本日の打刻</CardTitle>
202
- <Text size="xs" tone="muted">
203
- {caption}
204
- </Text>
206
+ <CardAction>
207
+ <Text size="xs" tone="muted">
208
+ {caption}
209
+ </Text>
210
+ </CardAction>
205
211
  </CardHeader>
206
- <CardContent flush>{children}</CardContent>
212
+ {banner ? <CardContent>{banner}</CardContent> : null}
213
+ {children ? <CardContent flush>{children}</CardContent> : null}
207
214
  </Card>
208
215
  );
209
216
  }
@@ -285,8 +292,9 @@ export default function Demo() {
285
292
  title="エラー"
286
293
  note="エラーコード・リクエストID・再試行を明示する。"
287
294
  >
288
- <TableShell caption="取得に失敗しました">
289
- <div className="p-4">
295
+ <TableShell
296
+ caption="取得に失敗しました"
297
+ banner={
290
298
  <Alert tone="destructive">
291
299
  <AlertTitle>勤怠データを取得できませんでした</AlertTitle>
292
300
  <AlertDescription>
@@ -304,8 +312,8 @@ export default function Demo() {
304
312
  </Button>
305
313
  </AlertActions>
306
314
  </Alert>
307
- </div>
308
- </TableShell>
315
+ }
316
+ />
309
317
  </StateSection>
310
318
 
311
319
  {/* 4 ─ partial: some rows loaded, one segment failed / stale */}
@@ -314,29 +322,29 @@ export default function Demo() {
314
322
  title="部分的"
315
323
  note="一部のみ取得できた状態。失敗した区分だけを再取得できる。"
316
324
  >
317
- <TableShell caption="4 / 5 部署を表示中">
318
- <div>
319
- <div className="p-4 pb-0">
320
- <Alert tone="warning">
321
- <AlertTitle>一部のデータを取得できませんでした</AlertTitle>
322
- <AlertDescription>
323
- 「倉庫」部署の打刻が取得できなかったため、最新ではない可能性があります。
324
- <br />
325
- <Text tone="muted">
326
- コード <code className="tabular-nums">ATTEND_PARTIAL_倉庫</code> ・
327
- リクエストID <code className="tabular-nums">req_7f3a91c0e8</code>
328
- </Text>
329
- </AlertDescription>
330
- <AlertActions>
331
- <Button variant="outline" size="sm">
332
- <RefreshCw aria-hidden="true" />
333
- 倉庫を再取得
334
- </Button>
335
- </AlertActions>
336
- </Alert>
337
- </div>
338
- <DataTable data={PARTIAL_ROWS} columns={COLUMNS} getRowId={(r) => r.id} />
339
- </div>
325
+ <TableShell
326
+ caption="4 / 5 部署を表示中"
327
+ banner={
328
+ <Alert tone="warning">
329
+ <AlertTitle>一部のデータを取得できませんでした</AlertTitle>
330
+ <AlertDescription>
331
+ 「倉庫」部署の打刻が取得できなかったため、最新ではない可能性があります。
332
+ <br />
333
+ <Text tone="muted">
334
+ コード <code className="tabular-nums">ATTEND_PARTIAL_倉庫</code> ・ リクエストID{" "}
335
+ <code className="tabular-nums">req_7f3a91c0e8</code>
336
+ </Text>
337
+ </AlertDescription>
338
+ <AlertActions>
339
+ <Button variant="outline" size="sm">
340
+ <RefreshCw aria-hidden="true" />
341
+ 倉庫を再取得
342
+ </Button>
343
+ </AlertActions>
344
+ </Alert>
345
+ }
346
+ >
347
+ <DataTable data={PARTIAL_ROWS} columns={COLUMNS} getRowId={(r) => r.id} />
340
348
  </TableShell>
341
349
  </StateSection>
342
350
 
@@ -22,8 +22,8 @@ import { Check } from "lucide-react";
22
22
  import { Button, Text } from "@godxjp/ui/general";
23
23
  import {
24
24
  Badge,
25
- type BadgeProps,
26
25
  Card,
26
+ CardAction,
27
27
  CardContent,
28
28
  CardHeader,
29
29
  CardTitle,
@@ -33,6 +33,7 @@ import {
33
33
  TableHead,
34
34
  TableHeader,
35
35
  TableRow,
36
+ type BadgeProps,
36
37
  } from "@godxjp/ui/data-display";
37
38
  import { Flex, PageContainer } from "@godxjp/ui/layout";
38
39
 
@@ -221,11 +222,13 @@ export default function Demo() {
221
222
  >
222
223
  <Flex direction="col" gap="lg">
223
224
  <Card>
224
- <CardHeader className="flex flex-row items-center justify-between">
225
+ <CardHeader>
225
226
  <CardTitle level={2}>2026年6月 第1週</CardTitle>
226
- <Text size="xs" tone="muted" tabular>
227
- 従業員 {EMPLOYEES.length} · 横スクロールで全日表示
228
- </Text>
227
+ <CardAction>
228
+ <Text size="xs" tone="muted" tabular>
229
+ 従業員 {EMPLOYEES.length} 名 · 横スクロールで全日表示
230
+ </Text>
231
+ </CardAction>
229
232
  </CardHeader>
230
233
  <CardContent flush>
231
234
  {/* The scroll container. `overflow-x-auto` clips; the table holds a
@@ -238,12 +241,13 @@ export default function Demo() {
238
241
  <TableHead className={`${PIN_LEFT} w-56 min-w-56`}>従業員</TableHead>
239
242
  {DAYS.map((d) => (
240
243
  <TableHead key={d.key} className="text-center">
241
- <span className="flex flex-col leading-tight">
244
+ {/* Weekday over its date reads as ONE label — no seam between the lines. */}
245
+ <Flex direction="col" gap="none" className="leading-tight">
242
246
  <Text weight="medium">{d.label}</Text>
243
247
  <Text size="2xs" tone="muted" tabular>
244
248
  {d.date}
245
249
  </Text>
246
- </span>
250
+ </Flex>
247
251
  </TableHead>
248
252
  ))}
249
253
  <TableHead className="text-end tabular-nums">実働</TableHead>