@godxjp/ui 19.2.0 → 19.3.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 (66) hide show
  1. package/dist/components/data-display/badge.d.ts +18 -2
  2. package/dist/components/data-display/badge.js +18 -4
  3. package/dist/props/components/data-display.prop.d.ts +7 -0
  4. package/dist/props/registry.d.ts +5 -1
  5. package/dist/props/registry.js +12 -1
  6. package/dist/styles/badge-layout.css +15 -0
  7. package/dist/tokens/components/badge.css +8 -0
  8. package/docs/data-display/badge.tsx +36 -0
  9. package/docs/data-display/carousel.tsx +8 -4
  10. package/docs/data-display/data-table/examples/grid-features.tsx +1 -1
  11. package/docs/data-display/permission-matrix.tsx +13 -9
  12. package/docs/data-display/popover.tsx +2 -1
  13. package/docs/data-display/scroll-area.tsx +107 -75
  14. package/docs/data-display/table.tsx +1 -1
  15. package/docs/data-entry/calendar.tsx +1 -1
  16. package/docs/data-entry/checkbox.tsx +1 -1
  17. package/docs/data-entry/country-picker-recipe.tsx +11 -6
  18. package/docs/data-entry/form-field/index.tsx +33 -29
  19. package/docs/data-entry/form-root.tsx +1 -1
  20. package/docs/data-entry/password-input.tsx +1 -5
  21. package/docs/data-entry/select.tsx +7 -7
  22. package/docs/data-entry/textarea.tsx +2 -2
  23. package/docs/feedback/sheet.tsx +112 -102
  24. package/docs/feedback/skeleton.tsx +2 -2
  25. package/docs/foundation/colors.tsx +8 -6
  26. package/docs/foundation/email-tokens.tsx +82 -65
  27. package/docs/foundation/radius-shadow.tsx +13 -11
  28. package/docs/layout/app-shell.tsx +2 -2
  29. package/docs/layout/aspect-ratio.tsx +30 -14
  30. package/docs/layout/flex.tsx +6 -2
  31. package/docs/layout/page-container.tsx +9 -1
  32. package/docs/layout/responsive-grid.tsx +10 -2
  33. package/docs/layout/sidebar.tsx +169 -146
  34. package/docs/layout/split-pane.tsx +44 -27
  35. package/docs/layout/topbar.tsx +17 -15
  36. package/docs/navigation/app-setting-picker.tsx +5 -4
  37. package/docs/navigation/breadcrumb.tsx +12 -5
  38. package/docs/navigation/context-menu.tsx +10 -4
  39. package/docs/navigation/navigation-menu.tsx +89 -96
  40. package/docs/navigation/steps.tsx +12 -10
  41. package/docs/navigation/tabs.tsx +26 -20
  42. package/docs/navigation/toolbar.tsx +15 -15
  43. package/docs/providers/format-date.tsx +2 -2
  44. package/docs/showcase/acme-portal.tsx +41 -27
  45. package/docs/showcase/acme-website.tsx +60 -54
  46. package/docs/showcase/case1-warehouse-dashboard.tsx +46 -30
  47. package/docs/showcase/case2-employee-me.tsx +23 -20
  48. package/docs/showcase/case3-approval-workflow.tsx +34 -32
  49. package/docs/showcase/case4-login.tsx +119 -113
  50. package/docs/showcase/case5-shift-calendar.tsx +3 -3
  51. package/docs/showcase/case6-agency-handy.tsx +340 -299
  52. package/docs/showcase/futurelastic-web.tsx +23 -21
  53. package/docs/showcase/org-switcher.tsx +2 -2
  54. package/docs/showcase/permission-matrix.tsx +7 -4
  55. package/docs/showcase/table-conditional-format.tsx +8 -8
  56. package/docs/showcase/table-crud-list.tsx +3 -3
  57. package/docs/showcase/table-density.tsx +49 -42
  58. package/docs/showcase/table-expandable-rows.tsx +24 -15
  59. package/docs/showcase/table-filter-chips.tsx +2 -7
  60. package/docs/showcase/table-footer-totals.tsx +7 -4
  61. package/docs/showcase/table-grouped-subtotals.tsx +25 -22
  62. package/docs/showcase/table-master-detail.tsx +15 -10
  63. package/docs/showcase/table-pagination.tsx +34 -27
  64. package/docs/showcase/table-states.tsx +8 -5
  65. package/docs/showcase/table-sticky-columns.tsx +8 -5
  66. package/package.json +2 -3
@@ -247,13 +247,15 @@ function Bento() {
247
247
  {cells.map((c) => (
248
248
  <Card key={c.title} className={`fl-cell ${c.span ?? ""}`}>
249
249
  <CardContent>
250
- <Medallion icon={c.icon} />
251
- <Text as="div" weight="bold" size="lg" className="mt-5">
252
- {c.title}
253
- </Text>
254
- <Text as="p" size="sm" tone="muted" className="mt-2">
255
- {c.text}
256
- </Text>
250
+ <Flex direction="col" gap="lg">
251
+ <Medallion icon={c.icon} />
252
+ <Text as="div" weight="bold" size="lg">
253
+ {c.title}
254
+ </Text>
255
+ <Text as="p" size="sm" tone="muted">
256
+ {c.text}
257
+ </Text>
258
+ </Flex>
257
259
  </CardContent>
258
260
  </Card>
259
261
  ))}
@@ -275,12 +277,12 @@ function Stats() {
275
277
  <div className={SHELL}>
276
278
  <div className="fl-stats">
277
279
  {stats.map(([n, l]) => (
278
- <div key={l} className="text-center">
280
+ <Flex key={l} direction="col" gap="sm" className="text-center">
279
281
  <div className="fl-stat-num">{n}</div>
280
- <Text as="div" size="sm" tone="muted" className="mt-2">
282
+ <Text as="div" size="sm" tone="muted">
281
283
  {l}
282
284
  </Text>
283
- </div>
285
+ </Flex>
284
286
  ))}
285
287
  </div>
286
288
  </div>
@@ -294,20 +296,20 @@ function Cta() {
294
296
  <div className={SHELL}>
295
297
  <div className="fl-cta">
296
298
  <div className="fl-cta-glow" />
297
- <div className="fl-cta-inner">
299
+ <Flex direction="col" gap="xl" className="fl-cta-inner">
298
300
  <h2 className="fl-h2">Cùng xây điều mới?</h2>
299
- <p className="fl-lead mx-auto mt-3">
301
+ <p className="fl-lead mx-auto">
300
302
  Chúng tôi tìm đối tác, nhân tài và cơ hội M&amp;A trong công nghệ, logistics và
301
303
  F&amp;B tại Nhật Bản &amp; Việt Nam.
302
304
  </p>
303
- <Flex direction="row" gap="md" className="mt-7 justify-center">
305
+ <Flex direction="row" gap="md" className="justify-center">
304
306
  <Button size="lg">Đặt lịch trao đổi</Button>
305
307
  <Button variant="ghost" size="lg">
306
308
  Đọc blog
307
309
  <ArrowRight aria-hidden="true" />
308
310
  </Button>
309
311
  </Flex>
310
- </div>
312
+ </Flex>
311
313
  </div>
312
314
  </div>
313
315
  </section>
@@ -323,26 +325,26 @@ function Footer() {
323
325
  return (
324
326
  <footer className="fl-footer">
325
327
  <div className={`${SHELL} fl-footer-grid`}>
326
- <div>
328
+ <Flex direction="col" gap="md">
327
329
  <span className="fl-brand">
328
330
  futur<span className="fl-gold">elastic</span>
329
331
  </span>
330
- <Text as="p" size="sm" tone="muted" className="fl-footer-tagline mt-4">
332
+ <Text as="p" size="sm" tone="muted" className="fl-footer-tagline">
331
333
  Tech · AI · Holdings · building the elastic infrastructure of the future across Japan
332
334
  &amp; Vietnam.
333
335
  </Text>
334
- </div>
336
+ </Flex>
335
337
  {cols.map(([h, items]) => (
336
- <div key={h}>
338
+ <Flex direction="col" gap="md" key={h}>
337
339
  <Text
338
340
  as="div"
339
341
  size="2xs"
340
342
  weight="bold"
341
- className="text-foreground mb-3 tracking-widest uppercase"
343
+ className="text-foreground tracking-widest uppercase"
342
344
  >
343
345
  {h}
344
346
  </Text>
345
- <Flex direction="col" gap="xs" className="mt-2">
347
+ <Flex direction="col" gap="xs">
346
348
  {items.map((i) => (
347
349
  <Button
348
350
  key={i}
@@ -354,7 +356,7 @@ function Footer() {
354
356
  </Button>
355
357
  ))}
356
358
  </Flex>
357
- </div>
359
+ </Flex>
358
360
  ))}
359
361
  </div>
360
362
  <div className={`${SHELL} fl-footer-bottom`}>
@@ -181,7 +181,7 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
181
181
  type="button"
182
182
  variant="ghost"
183
183
  size="sm"
184
- className="w-full justify-start gap-2"
184
+ className="w-full justify-start"
185
185
  onClick={() => {
186
186
  onCreate();
187
187
  setOpen(false);
@@ -194,7 +194,7 @@ function OrgSwitcher({ organizations, currentId, onSelect, onCreate, onJoin }: O
194
194
  type="button"
195
195
  variant="ghost"
196
196
  size="sm"
197
- className="w-full justify-start gap-2"
197
+ className="w-full justify-start"
198
198
  onClick={() => {
199
199
  onJoin();
200
200
  setOpen(false);
@@ -34,6 +34,7 @@ import { Check, Minus } from "lucide-react";
34
34
  import {
35
35
  Badge,
36
36
  Card,
37
+ CardAction,
37
38
  CardContent,
38
39
  CardHeader,
39
40
  CardTitle,
@@ -217,11 +218,13 @@ export default function Demo() {
217
218
 
218
219
  {/* ── マトリクス本体 ── */}
219
220
  <Card>
220
- <CardHeader className="flex flex-row items-center justify-between">
221
+ <CardHeader>
221
222
  <CardTitle level={2}>ロール × 権限</CardTitle>
222
- <Text size="xs" tone="muted" tabular>
223
- 権限 {rows.length} / {PERMISSIONS.length} 件 · ロール {ROLES.length}
224
- </Text>
223
+ <CardAction>
224
+ <Text size="xs" tone="muted" tabular>
225
+ 権限 {rows.length} / {PERMISSIONS.length} 件 · ロール {ROLES.length}
226
+ </Text>
227
+ </CardAction>
225
228
  </CardHeader>
226
229
  <CardContent flush>
227
230
  <div className="overflow-x-auto">
@@ -205,11 +205,11 @@ export default function Demo() {
205
205
  sortable: true,
206
206
  render: (r) =>
207
207
  isEarlyCell(r) ? (
208
- <span className="bg-attention/10 text-attention inline-flex rounded-sm px-1.5 py-0.5">
208
+ <Badge tone="warning" shape="sharp">
209
209
  <Text as="span" weight="medium" tabular style={{ color: "inherit" }}>
210
210
  {hours(r.earlyLeaveHours)}
211
211
  </Text>
212
- </span>
212
+ </Badge>
213
213
  ) : (
214
214
  <Text tabular>{hours(r.earlyLeaveHours)}</Text>
215
215
  ),
@@ -221,11 +221,11 @@ export default function Demo() {
221
221
  sortable: true,
222
222
  render: (r) =>
223
223
  isOvertimeCell(r) ? (
224
- <span className="bg-warning/10 text-warning-foreground inline-flex rounded-sm px-1.5 py-0.5">
224
+ <Badge tone="warning" shape="sharp">
225
225
  <Text as="span" weight="medium" tabular style={{ color: "inherit" }}>
226
226
  {hours(r.overtime)}
227
227
  </Text>
228
- </span>
228
+ </Badge>
229
229
  ) : (
230
230
  <Text tabular>{hours(r.overtime)}</Text>
231
231
  ),
@@ -312,11 +312,11 @@ export default function Demo() {
312
312
  {/* 早退セル: > 2.0h は attention(朱) で背景+前景強調 */}
313
313
  <TableCell className="text-end">
314
314
  {isEarlyCell(r) ? (
315
- <span className="bg-attention/10 text-attention inline-flex rounded-sm px-1.5 py-0.5">
315
+ <Badge tone="warning" shape="sharp">
316
316
  <Text as="span" weight="medium" tabular style={{ color: "inherit" }}>
317
317
  {hours(r.earlyLeaveHours)}
318
318
  </Text>
319
- </span>
319
+ </Badge>
320
320
  ) : (
321
321
  <Text tone="muted" tabular>
322
322
  {hours(r.earlyLeaveHours)}
@@ -326,11 +326,11 @@ export default function Demo() {
326
326
  {/* 残業セル: ≥ 45h は warning(山吹) で注意 */}
327
327
  <TableCell className="text-end">
328
328
  {isOvertimeCell(r) ? (
329
- <span className="bg-warning/10 text-warning-foreground inline-flex rounded-sm px-1.5 py-0.5">
329
+ <Badge tone="warning" shape="sharp">
330
330
  <Text as="span" weight="medium" tabular style={{ color: "inherit" }}>
331
331
  {hours(r.overtime)}
332
332
  </Text>
333
- </span>
333
+ </Badge>
334
334
  ) : (
335
335
  <Text tabular>{hours(r.overtime)}</Text>
336
336
  )}
@@ -508,19 +508,19 @@ export default function Demo() {
508
508
  </Text>
509
509
  <Badge tone="success" variant="outline">
510
510
  出勤{" "}
511
- <Text as="span" tabular className="ms-1">
511
+ <Text as="span" tabular>
512
512
  {tally.present}
513
513
  </Text>
514
514
  </Badge>
515
515
  <Badge tone="warning" variant="outline">
516
516
  遅刻{" "}
517
- <Text as="span" tabular className="ms-1">
517
+ <Text as="span" tabular>
518
518
  {tally.late}
519
519
  </Text>
520
520
  </Badge>
521
521
  <Badge tone="muted" variant="outline">
522
522
  承認待ち{" "}
523
- <Text as="span" tabular className="ms-1">
523
+ <Text as="span" tabular>
524
524
  {tally.pendingApproval}
525
525
  </Text>
526
526
  </Badge>
@@ -25,12 +25,13 @@ import { Clock } from "lucide-react";
25
25
 
26
26
  import {
27
27
  Badge,
28
- type BadgeProps,
29
28
  Card,
29
+ CardAction,
30
30
  CardContent,
31
31
  CardHeader,
32
32
  CardTitle,
33
33
  DataTable,
34
+ type BadgeProps,
34
35
  type ColumnDef,
35
36
  } from "@godxjp/ui/data-display";
36
37
  import { Button, Text } from "@godxjp/ui/general";
@@ -233,44 +234,48 @@ export default function Demo() {
233
234
  <Flex direction="col" gap="lg">
234
235
  {/* Control + live readout */}
235
236
  <Card>
236
- <CardHeader className="flex flex-row items-center justify-between gap-4">
237
+ <CardHeader>
237
238
  <CardTitle level={2}>行密度</CardTitle>
238
- <Flex direction="row" align="center" gap="md">
239
- <Text as="span" size="xs" tone="muted" className="inline-flex items-center gap-1.5">
240
- <Clock className="size-3.5" aria-hidden="true" />
241
- 行高
242
- <Text as="strong" weight="medium" tabular>
243
- {meta.px}px
244
- </Text>
245
- <span aria-hidden="true">·</span>
246
- {meta.note}
247
- </Text>
248
- <ToggleGroup
249
- type="single"
250
- value={density}
251
- onValueChange={(v) => {
252
- if (v) setDensity(v as DensityKey);
253
- }}
254
- variant="outline"
255
- size="sm"
256
- aria-label="行密度を切り替え"
257
- >
258
- {DENSITY_ORDER.map((key) => (
259
- <ToggleGroupItem
260
- key={key}
261
- value={key}
262
- aria-label={`${DENSITY_META[key].label} ${DENSITY_META[key].px}px`}
263
- >
264
- <Flex direction="row" align="center" gap="xs">
265
- <span>{DENSITY_META[key].label}</span>
266
- <Text size="2xs" tone="muted" tabular>
267
- {DENSITY_META[key].px}
268
- </Text>
269
- </Flex>
270
- </ToggleGroupItem>
271
- ))}
272
- </ToggleGroup>
273
- </Flex>
239
+ <CardAction>
240
+ <Flex direction="row" align="center" gap="md">
241
+ <Flex align="center" gap="xs">
242
+ <Text as="span" size="xs" tone="muted">
243
+ <Clock className="size-3.5" aria-hidden="true" />
244
+ 行高
245
+ <Text as="strong" weight="medium" tabular>
246
+ {meta.px}px
247
+ </Text>
248
+ <span aria-hidden="true">·</span>
249
+ {meta.note}
250
+ </Text>
251
+ </Flex>
252
+ <ToggleGroup
253
+ type="single"
254
+ value={density}
255
+ onValueChange={(v) => {
256
+ if (v) setDensity(v as DensityKey);
257
+ }}
258
+ variant="outline"
259
+ size="sm"
260
+ aria-label="行密度を切り替え"
261
+ >
262
+ {DENSITY_ORDER.map((key) => (
263
+ <ToggleGroupItem
264
+ key={key}
265
+ value={key}
266
+ aria-label={`${DENSITY_META[key].label} ${DENSITY_META[key].px}px`}
267
+ >
268
+ <Flex direction="row" align="center" gap="xs">
269
+ <span>{DENSITY_META[key].label}</span>
270
+ <Text size="2xs" tone="muted" tabular>
271
+ {DENSITY_META[key].px}
272
+ </Text>
273
+ </Flex>
274
+ </ToggleGroupItem>
275
+ ))}
276
+ </ToggleGroup>
277
+ </Flex>
278
+ </CardAction>
274
279
  </CardHeader>
275
280
  <CardContent flush>
276
281
  {/* The SAME DataTable. Only the density class changes — same columns,
@@ -314,11 +319,13 @@ export default function Demo() {
314
319
  const m = DENSITY_META[key];
315
320
  return (
316
321
  <Card key={key}>
317
- <CardHeader className="flex flex-row items-center justify-between">
322
+ <CardHeader>
318
323
  <CardTitle level={2}>{m.label}</CardTitle>
319
- <Text size="xs" tone="muted" tabular>
320
- 行高 {m.px}px · {m.note}
321
- </Text>
324
+ <CardAction>
325
+ <Text size="xs" tone="muted" tabular>
326
+ 行高 {m.px}px · {m.note}
327
+ </Text>
328
+ </CardAction>
322
329
  </CardHeader>
323
330
  <CardContent flush>
324
331
  <DataTable
@@ -23,8 +23,8 @@ import { ChevronRight, Clock, Coffee, MapPin } from "lucide-react";
23
23
 
24
24
  import {
25
25
  Badge,
26
- type BadgeProps,
27
26
  Card,
27
+ CardAction,
28
28
  CardContent,
29
29
  CardHeader,
30
30
  CardTitle,
@@ -35,6 +35,7 @@ import {
35
35
  TableHead,
36
36
  TableHeader,
37
37
  TableRow,
38
+ type BadgeProps,
38
39
  } from "@godxjp/ui/data-display";
39
40
  import { Button, Text } from "@godxjp/ui/general";
40
41
  import { Flex, PageContainer } from "@godxjp/ui/layout";
@@ -249,7 +250,7 @@ const EMPLOYEES: Employee[] = [
249
250
 
250
251
  // ── Shared cell padding to match compact DataTable density ─────────────────────
251
252
 
252
- const CELL = "px-3 py-2 align-middle";
253
+ const CELL = "align-middle";
253
254
  const HEAD = "px-3";
254
255
 
255
256
  function StatusBadge({ status }: { status: ShiftStatus }) {
@@ -270,10 +271,12 @@ function DetailPanel({ employee }: { employee: Employee }) {
270
271
  <Text size="sm" weight="medium">
271
272
  {employee.name} · {employee.dept}
272
273
  </Text>
273
- <Text size="xs" tone="muted" className="inline-flex items-center gap-1">
274
- <MapPin className="size-3.5" aria-hidden="true" />
275
- {employee.site}
276
- </Text>
274
+ <Flex align="center" gap="xs">
275
+ <Text size="xs" tone="muted">
276
+ <MapPin className="size-3.5" aria-hidden="true" />
277
+ {employee.site}
278
+ </Text>
279
+ </Flex>
277
280
  </Flex>
278
281
 
279
282
  {/* KPI mini-row inside the panel — real StatCard primitives */}
@@ -295,14 +298,18 @@ function DetailPanel({ employee }: { employee: Employee }) {
295
298
 
296
299
  {/* Per-day breakdown — quiet nested list, real Card chrome */}
297
300
  <Card>
298
- <CardHeader className="flex flex-row items-center justify-between">
301
+ <CardHeader>
299
302
  <CardTitle level={2} className="text-[var(--font-size-xs)]">
300
303
  今週の打刻
301
304
  </CardTitle>
302
- <Text size="xs" tone="muted" className="inline-flex items-center gap-1">
303
- <Clock className="size-3.5" aria-hidden="true" />
304
- 直近 3
305
- </Text>
305
+ <CardAction>
306
+ <Flex align="center" gap="xs">
307
+ <Text size="xs" tone="muted">
308
+ <Clock className="size-3.5" aria-hidden="true" />
309
+ 直近 3 日
310
+ </Text>
311
+ </Flex>
312
+ </CardAction>
306
313
  </CardHeader>
307
314
  <CardContent flush>
308
315
  <Table>
@@ -449,11 +456,13 @@ export default function Demo() {
449
456
  >
450
457
  <Flex direction="col" gap="lg">
451
458
  <Card>
452
- <CardHeader className="flex flex-row items-center justify-between">
459
+ <CardHeader>
453
460
  <CardTitle level={2}>従業員の勤怠(今週)</CardTitle>
454
- <Text size="xs" tone="muted" tabular>
455
- 4 · 06/04 時点
456
- </Text>
461
+ <CardAction>
462
+ <Text size="xs" tone="muted" tabular>
463
+ 4 名 · 06/04 時点
464
+ </Text>
465
+ </CardAction>
457
466
  </CardHeader>
458
467
  <CardContent flush>
459
468
  <ExpandableList />
@@ -407,12 +407,7 @@ export default function Demo() {
407
407
  )}
408
408
 
409
409
  {hasFilters && (
410
- <Button
411
- variant="ghost"
412
- size="sm"
413
- className="ms-auto h-6 px-2 text-xs"
414
- onClick={clearAll}
415
- >
410
+ <Button variant="ghost" size="sm" className="ms-auto h-6 text-xs" onClick={clearAll}>
416
411
  すべて解除
417
412
  </Button>
418
413
  )}
@@ -435,7 +430,7 @@ export default function Demo() {
435
430
  <Text size="xs" tone="muted">
436
431
  フィルター条件を解除すると全件を表示します
437
432
  </Text>
438
- <Button variant="outline" size="sm" className="mt-1" onClick={clearAll}>
433
+ <Button variant="outline" size="sm" onClick={clearAll}>
439
434
  フィルターを解除
440
435
  </Button>
441
436
  </Flex>
@@ -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. */}
@@ -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,7 +226,7 @@ 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 className="ps-2 pe-0" colSpan={2}>
229
230
  <Button
230
231
  variant="ghost"
231
232
  size="sm"
@@ -241,10 +242,10 @@ function GroupHeaderRow({
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
  }
@@ -330,18 +331,16 @@ function GroupedTable({
330
331
  })}
331
332
  {/* 総計フッター行 */}
332
333
  <TableRow className="bg-muted/40 hover:bg-muted/40 border-t-2">
333
- <TableCell className="py-2 font-medium" colSpan={2}>
334
+ <TableCell className="font-medium" colSpan={2}>
334
335
  総計 · 全{groups.reduce((n, g) => n + g.members.length, 0)}名
335
336
  </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">
337
+ <TableCell className="text-end font-bold tabular-nums">{total.days}日</TableCell>
338
+ <TableCell className="text-end font-bold tabular-nums">{fmtH(total.work)}</TableCell>
339
+ <TableCell className="text-end font-bold tabular-nums">
341
340
  {fmtH(total.overtime)}
342
341
  </TableCell>
343
- <TableCell className="py-2 text-end font-bold tabular-nums">{total.late}回</TableCell>
344
- <TableCell className="py-2" />
342
+ <TableCell className="text-end font-bold tabular-nums">{total.late}回</TableCell>
343
+ <TableCell />
345
344
  </TableRow>
346
345
  </TableBody>
347
346
  </Table>
@@ -359,11 +358,13 @@ export default function Demo() {
359
358
  <Flex direction="col" gap="lg">
360
359
  {/* 全展開(既定)— 各グループの小計と明細が同時に見える */}
361
360
  <Card>
362
- <CardHeader className="flex flex-row items-center justify-between">
361
+ <CardHeader>
363
362
  <CardTitle level={2}>2026年5月度 勤怠集計</CardTitle>
364
- <Text size="xs" tone="muted" tabular>
365
- 締め: 2026-05-31
366
- </Text>
363
+ <CardAction>
364
+ <Text size="xs" tone="muted" tabular>
365
+ 締め: 2026-05-31
366
+ </Text>
367
+ </CardAction>
367
368
  </CardHeader>
368
369
  <CardContent flush>
369
370
  <GroupedTable groups={GROUPS} />
@@ -372,11 +373,13 @@ export default function Demo() {
372
373
 
373
374
  {/* 折りたたみ済みの状態を静的に提示 — 「カスタマーサポート部」は閉じて小計のみ表示 */}
374
375
  <Card>
375
- <CardHeader className="flex flex-row items-center justify-between">
376
+ <CardHeader>
376
377
  <CardTitle level={2}>折りたたみ状態</CardTitle>
377
- <Text size="xs" tone="muted">
378
- 閉じたグループは小計のみ表示(クリックで展開)
379
- </Text>
378
+ <CardAction>
379
+ <Text size="xs" tone="muted">
380
+ 閉じたグループは小計のみ表示(クリックで展開)
381
+ </Text>
382
+ </CardAction>
380
383
  </CardHeader>
381
384
  <CardContent flush>
382
385
  <GroupedTable groups={GROUPS} defaultClosed={["support"]} />
@@ -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]">
@@ -452,11 +455,13 @@ export default function Demo() {
452
455
 
453
456
  {/* ── Narrow fallback: stacked list + detail (no side room) ── */}
454
457
  <Card>
455
- <CardHeader className="flex flex-row items-center justify-between">
458
+ <CardHeader>
456
459
  <CardTitle level={2}>狭幅レイアウト(縦積み)</CardTitle>
457
- <Text size="xs" tone="muted">
458
- サイドペインが取れない幅では一覧の下に詳細を重ねます
459
- </Text>
460
+ <CardAction>
461
+ <Text size="xs" tone="muted">
462
+ サイドペインが取れない幅では一覧の下に詳細を重ねます
463
+ </Text>
464
+ </CardAction>
460
465
  </CardHeader>
461
466
  <CardContent flush>
462
467
  <DataTable