@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
@@ -9,7 +9,7 @@ export type BadgeVariant = "default" | "secondary" | "outline" | "dashed";
9
9
  */
10
10
  export type BadgeTone = ToneProp | "primary";
11
11
  declare const badgeVariants: (props?: ({
12
- variant?: "dashed" | "default" | "outline" | "secondary" | null | undefined;
12
+ variant?: "dashed" | "default" | "outline" | "secondary" | "tinted" | null | undefined;
13
13
  shape?: "default" | "pill" | "sharp" | null | undefined;
14
14
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
15
15
  export interface BadgeProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children">, Omit<VariantProps<typeof badgeVariants>, "variant" | "shape"> {
@@ -17,13 +17,29 @@ export interface BadgeProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "
17
17
  /** Corner shape — `default` (badge radius) · `pill` (fully rounded) · `sharp` (square). */
18
18
  shape?: ShapeProp | null;
19
19
  tone?: BadgeTone | null;
20
+ /**
21
+ * The entity's OWN colour — a status colour, an issue type, a tag — as a CSS
22
+ * colour. A third axis beside `variant` (structure) and `tone` (meaning):
23
+ * this one carries DATA, a colour a person picked in a settings screen.
24
+ *
25
+ * The chip is washed rather than filled, and the reason is a contrast floor
26
+ * rather than taste: no foreground clears WCAG AA against every colour a
27
+ * picker can produce (near-black and white measure equal at luminance 0.2029,
28
+ * both 4.15:1). Washing the colour `--badge-tint-fill` into
29
+ * `--badge-tint-surface` and keeping the surface's own label makes the ratio
30
+ * a function of the tokens instead — 8.52:1 at the defaults, worst case
31
+ * across the sRGB cube on both themes.
32
+ *
33
+ * Wins over `tone` and over `variant`'s fill when both are given.
34
+ */
35
+ color?: string;
20
36
  icon?: React.ComponentType<{
21
37
  className?: string;
22
38
  }> | null;
23
39
  status?: string;
24
40
  children?: React.ReactNode;
25
41
  }
26
- export declare function Badge({ className, variant, shape, tone, icon, status, children, ...props }: BadgeProps): React.JSX.Element;
42
+ export declare function Badge({ className, variant, shape, tone, color, icon, status, style, children, ...props }: BadgeProps): React.JSX.Element;
27
43
  /**
28
44
  * Status-aware badge with the shared domain-status-to-tone mapping. `Badge` remains the
29
45
  * general-purpose primitive.
@@ -57,7 +57,13 @@ const badgeVariants = cva(
57
57
  default: "border-transparent bg-primary text-primary-foreground",
58
58
  secondary: "border-transparent bg-secondary text-secondary-foreground",
59
59
  outline: "text-foreground",
60
- dashed: "border-dashed text-foreground"
60
+ dashed: "border-dashed text-foreground",
61
+ /* `color` mode. Deliberately empty and deliberately NOT in the public
62
+ * `BadgeVariant` union: every fill, border and text utility has to stay
63
+ * off the element so badge-layout.css's `[data-tinted]` rule is
64
+ * reachable (a utility beats a components-layer rule whatever the
65
+ * specificity — gh#260). Selected by the `color` prop, never by hand. */
66
+ tinted: ""
61
67
  },
62
68
  // Corner shape — default inherits the badge radius token; pill/sharp override via the tokens.
63
69
  shape: {
@@ -84,8 +90,10 @@ function Badge({
84
90
  variant,
85
91
  shape,
86
92
  tone,
93
+ color,
87
94
  icon,
88
95
  status,
96
+ style,
89
97
  children,
90
98
  ...props
91
99
  }) {
@@ -94,17 +102,23 @@ function Badge({
94
102
  const resolvedTone = tone ?? statusDef?.tone ?? "default";
95
103
  const ResolvedIcon = icon === void 0 ? statusDef?.icon : icon;
96
104
  const resolvedChildren = children ?? (status ? status in STATUS_MAP ? t(`status.${status}`) : status : void 0);
105
+ const tinted = color != null && color !== "";
97
106
  return /* @__PURE__ */ jsxs(
98
107
  "div",
99
108
  {
100
109
  "data-slot": "badge",
101
- "data-tone": resolvedTone,
110
+ "data-tone": tinted ? void 0 : resolvedTone,
111
+ "data-tinted": tinted ? "" : void 0,
102
112
  "data-shape": shape ?? "default",
103
113
  className: cn(
104
- badgeVariants({ variant: variant ?? "default", shape: shape ?? "default" }),
105
- badgeToneClass[resolvedTone],
114
+ badgeVariants({
115
+ variant: tinted ? "tinted" : variant ?? "default",
116
+ shape: shape ?? "default"
117
+ }),
118
+ tinted ? void 0 : badgeToneClass[resolvedTone],
106
119
  className
107
120
  ),
121
+ style: tinted ? { ...style, ["--badge-color"]: color } : style,
108
122
  ...props,
109
123
  children: [
110
124
  ResolvedIcon ? /* @__PURE__ */ jsx(ResolvedIcon, { "data-slot": "badge-icon", "aria-hidden": "true" }) : null,
@@ -140,6 +140,13 @@ export type BadgeProp = {
140
140
  variant?: "default" | "secondary" | "outline";
141
141
  /** Status tones plus a brand `primary` tone (soft brand pill); solid brand = `variant="default"`. */
142
142
  tone?: ToneProp | "primary";
143
+ /**
144
+ * The entity's OWN colour (a status, an issue type, a tag) as a CSS colour —
145
+ * DATA, not a semantic tone. Washed into `--badge-tint-surface` rather than
146
+ * filled, because no foreground clears WCAG AA against every colour a picker
147
+ * can produce. Wins over `tone` and over `variant`'s fill.
148
+ */
149
+ color?: string;
143
150
  status?: string;
144
151
  icon?: React.ComponentType<{
145
152
  className?: string;
@@ -1160,7 +1160,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
1160
1160
  readonly BadgeProp: {
1161
1161
  readonly group: "data-display";
1162
1162
  readonly file: "components/data-display.prop.ts";
1163
- readonly vocabulary: readonly ["BadgeVariantProp", "ShapeProp", "ToneProp", "ChildrenProp", "ClassNameProp"];
1163
+ readonly vocabulary: readonly ["BadgeVariantProp", "ShapeProp", "ToneProp", "ChildrenProp", "ClassNameProp", {
1164
+ readonly field: "color";
1165
+ readonly local: true;
1166
+ readonly reason: "The entity's OWN colour as a CSS colour string — DATA a person picked in a settings screen (a status, an issue type, a tag), a third axis beside `variant` (structure) and `tone` (meaning). No vocabulary type fits: ToneProp is the closed semantic set, and this value is open by definition. Washed into --badge-tint-surface rather than filled, because no foreground clears WCAG AA against every colour a picker can produce.";
1167
+ }];
1164
1168
  };
1165
1169
  readonly DataTableProp: {
1166
1170
  readonly group: "data-display";
@@ -1345,7 +1345,18 @@ const COMPONENT_PROP_REGISTRY = {
1345
1345
  BadgeProp: {
1346
1346
  group: "data-display",
1347
1347
  file: "components/data-display.prop.ts",
1348
- vocabulary: ["BadgeVariantProp", "ShapeProp", "ToneProp", "ChildrenProp", "ClassNameProp"]
1348
+ vocabulary: [
1349
+ "BadgeVariantProp",
1350
+ "ShapeProp",
1351
+ "ToneProp",
1352
+ "ChildrenProp",
1353
+ "ClassNameProp",
1354
+ {
1355
+ field: "color",
1356
+ local: true,
1357
+ reason: "The entity's OWN colour as a CSS colour string \u2014 DATA a person picked in a settings screen (a status, an issue type, a tag), a third axis beside `variant` (structure) and `tone` (meaning). No vocabulary type fits: ToneProp is the closed semantic set, and this value is open by definition. Washed into --badge-tint-surface rather than filled, because no foreground clears WCAG AA against every colour a picker can produce."
1358
+ }
1359
+ ]
1349
1360
  },
1350
1361
  DataTableProp: {
1351
1362
  group: "data-display",
@@ -25,6 +25,21 @@
25
25
  }
26
26
  }
27
27
 
28
+ [data-slot="badge"][data-tinted] {
29
+
30
+ background-color: color-mix(
31
+ in srgb,
32
+ var(--badge-tint-surface),
33
+ var(--badge-color) var(--badge-tint-fill)
34
+ );
35
+ border-color: color-mix(
36
+ in srgb,
37
+ var(--badge-tint-surface),
38
+ var(--badge-color) var(--badge-tint-edge)
39
+ );
40
+ color: var(--badge-tint-foreground);
41
+ }
42
+
28
43
  [data-slot="badge-icon"] {
29
44
  width: var(--badge-icon-size);
30
45
  height: var(--badge-icon-size);
@@ -10,4 +10,12 @@
10
10
  --badge-line-height: calc(1 / 0.75);
11
11
 
12
12
  --badge-icon-size: var(--icon-size-xs);
13
+
14
+ --badge-tint-fill: 18%;
15
+ --badge-tint-edge: 45%;
16
+
17
+ --badge-tint-surface: hsl(var(--card));
18
+ --badge-tint-foreground: hsl(var(--card-foreground));
19
+
20
+ --badge-color: var(--badge-tint-surface);
13
21
  }
@@ -30,6 +30,21 @@ const shapes = [
30
30
  { shape: "sharp" as const, label: "角 Sharp" },
31
31
  ];
32
32
 
33
+ /**
34
+ * Colours a person picked, not colours that mean something — a status and an
35
+ * issue type out of a project's own settings screen, plus the two ends of the
36
+ * range an administrator can still type. `#488a5a` is here because it is the
37
+ * worst case for a SOLID chip: near-black and white measure equal on it, both
38
+ * 4.15:1, under the 4.5 badge-sized text needs. Washed, it clears 8.52.
39
+ */
40
+ const dataColours = [
41
+ { color: "#4488c5", label: "処理中 In progress" },
42
+ { color: "#ea9a10", label: "未対応 Open" },
43
+ { color: "#488a5a", label: "完了 Done" },
44
+ { color: "#000000", label: "黒 Black" },
45
+ { color: "#ffffff", label: "白 White" },
46
+ ];
47
+
33
48
  const tones = [
34
49
  { tone: "default" as const, label: "既定 Default" },
35
50
  { tone: "primary" as const, label: "ブランド Brand" },
@@ -120,6 +135,27 @@ export default function Demo() {
120
135
  </CardContent>
121
136
  </Card>
122
137
 
138
+ <Card>
139
+ <CardHeader>
140
+ <CardTitle level={2}>The record&rsquo;s own colour</CardTitle>
141
+ <CardDescription>
142
+ color carries DATA: a status an administrator coloured, an issue type, a tag. The chip
143
+ is washed into the surface rather than filled, because a solid chip has to choose a
144
+ foreground and no choice is readable for every colour a picker can produce. Retune the
145
+ wash with --badge-tint-fill / --badge-tint-edge.
146
+ </CardDescription>
147
+ </CardHeader>
148
+ <CardContent>
149
+ <Flex direction="row" wrap align="center" gap="sm">
150
+ {dataColours.map((c) => (
151
+ <Badge key={c.color} shape="pill" color={c.color}>
152
+ {c.label}
153
+ </Badge>
154
+ ))}
155
+ </Flex>
156
+ </CardContent>
157
+ </Card>
158
+
123
159
  <Card>
124
160
  <CardHeader>
125
161
  <CardTitle level={2}>Semantic tones</CardTitle>
@@ -39,7 +39,7 @@ const slides = [
39
39
  function DotNavExample() {
40
40
  return (
41
41
  <Carousel
42
- className="px-10"
42
+ style={{ paddingInline: "var(--space-10)" }}
43
43
  opts={{ loop: true }}
44
44
  aria-label="ドットナビゲーション付きカルーセル"
45
45
  >
@@ -71,7 +71,7 @@ export default function Demo() {
71
71
  </CardDescription>
72
72
  </CardHeader>
73
73
  <CardContent>
74
- <Carousel className="px-10" aria-label="月次 KPI カルーセル">
74
+ <Carousel style={{ paddingInline: "var(--space-10)" }} aria-label="月次 KPI カルーセル">
75
75
  <CarouselContent>
76
76
  {months.map((m) => (
77
77
  <CarouselItem key={m.label} className="basis-full sm:basis-1/2 lg:basis-1/3">
@@ -96,7 +96,7 @@ export default function Demo() {
96
96
  </CardHeader>
97
97
  <CardContent>
98
98
  <Carousel
99
- className="px-10"
99
+ style={{ paddingInline: "var(--space-10)" }}
100
100
  opts={{ loop: true, align: "start" }}
101
101
  aria-label="ループギャラリーカルーセル"
102
102
  >
@@ -137,7 +137,11 @@ export default function Demo() {
137
137
  </CardDescription>
138
138
  </CardHeader>
139
139
  <CardContent>
140
- <Carousel className="py-10" opts={{ axis: "y" }} aria-label="縦方向カルーセル">
140
+ <Carousel
141
+ style={{ paddingBlock: "var(--space-10)" }}
142
+ opts={{ axis: "y" }}
143
+ aria-label="縦方向カルーセル"
144
+ >
141
145
  <CarouselContent className="h-48">
142
146
  {slides.map((s) => (
143
147
  <CarouselItem key={s.label}>
@@ -149,7 +149,7 @@ export default function Demo() {
149
149
  </Card>
150
150
 
151
151
  {lastClicked ? (
152
- <Text as="p" tone="muted" className="mt-3">
152
+ <Text as="p" tone="muted">
153
153
  行クリック: {lastClicked}
154
154
  </Text>
155
155
  ) : null}
@@ -145,15 +145,19 @@ export default function Demo() {
145
145
  <Label htmlFor="pm-doc-diff-only">差分のみ</Label>
146
146
  </Flex>
147
147
  </Flex>
148
- <div className="border-border overflow-hidden rounded-md border">
149
- <PermissionMatrix
150
- roles={ROLES}
151
- permissions={PERMISSIONS}
152
- grants={grants}
153
- compare={[compareA, compareB]}
154
- diffOnly={diffOnly}
155
- />
156
- </div>
148
+ <Card variant="outline" className="overflow-hidden">
149
+ <CardContent flush>
150
+ <div>
151
+ <PermissionMatrix
152
+ roles={ROLES}
153
+ permissions={PERMISSIONS}
154
+ grants={grants}
155
+ compare={[compareA, compareB]}
156
+ diffOnly={diffOnly}
157
+ />
158
+ </div>
159
+ </CardContent>
160
+ </Card>
157
161
  </Flex>
158
162
  </CardContent>
159
163
  </Card>
@@ -1,5 +1,6 @@
1
1
  import { useState } from "react";
2
2
  import {
3
+ Badge,
3
4
  Card,
4
5
  CardContent,
5
6
  CardDescription,
@@ -40,7 +41,7 @@ export default function Demo() {
40
41
  <CardContent>
41
42
  <Popover defaultOpen>
42
43
  <PopoverAnchor asChild>
43
- <span className="inline-flex rounded border px-3 py-2">請求額 ¥482,000</span>
44
+ <Badge variant="outline">請求額 ¥482,000</Badge>
44
45
  </PopoverAnchor>
45
46
  <PopoverContent side="right" aria-label="請求額の補足">
46
47
  <PopoverDescription>税額と支払条件の補足情報です。</PopoverDescription>
@@ -109,31 +109,38 @@ export default function Demo() {
109
109
  </CardDescription>
110
110
  </CardHeader>
111
111
  <CardContent>
112
- <ScrollArea
113
- anchor="bottom"
114
- viewportRef={streamViewport}
115
- onAnchoredChange={setAnchored}
116
- type="always"
117
- className="border-border h-64 w-full rounded-md border"
118
- >
119
- <Flex direction="col" className="px-3">
120
- {posts.map((post) => (
121
- <Flex key={post.id} direction="col" className="py-2">
122
- <Flex gap="sm" align="baseline">
123
- <Text size="sm" weight="medium">
124
- {post.author}
125
- </Text>
126
- <Text size="xs" tone="muted">
127
- {timeFormatter.format(new Date(STREAM_EPOCH + post.id * STREAM_STEP_MS))}
128
- </Text>
112
+ <Card variant="outline" className="h-64 w-full">
113
+ <CardContent flush>
114
+ <ScrollArea
115
+ anchor="bottom"
116
+ viewportRef={streamViewport}
117
+ onAnchoredChange={setAnchored}
118
+ type="always"
119
+ >
120
+ <CardContent>
121
+ <Flex direction="col">
122
+ {posts.map((post) => (
123
+ <Flex key={post.id} direction="col" gap="xs">
124
+ <Flex gap="sm" align="baseline">
125
+ <Text size="sm" weight="medium">
126
+ {post.author}
127
+ </Text>
128
+ <Text size="xs" tone="muted">
129
+ {timeFormatter.format(
130
+ new Date(STREAM_EPOCH + post.id * STREAM_STEP_MS),
131
+ )}
132
+ </Text>
133
+ </Flex>
134
+ <Text size="sm" tone="muted">
135
+ {post.body}
136
+ </Text>
137
+ </Flex>
138
+ ))}
129
139
  </Flex>
130
- <Text size="sm" tone="muted">
131
- {post.body}
132
- </Text>
133
- </Flex>
134
- ))}
135
- </Flex>
136
- </ScrollArea>
140
+ </CardContent>
141
+ </ScrollArea>
142
+ </CardContent>
143
+ </Card>
137
144
  </CardContent>
138
145
  <CardFooter>
139
146
  <Flex gap="sm" wrap>
@@ -164,20 +171,21 @@ export default function Demo() {
164
171
  </CardDescription>
165
172
  </CardHeader>
166
173
  <CardContent>
167
- <ScrollArea
168
- anchor="bottom"
169
- anchorOffset={0}
170
- type="always"
171
- className="border-border h-40 w-full rounded-md border"
172
- >
173
- <Flex direction="col" gap="xs" className="p-3">
174
- {entries.map((e) => (
175
- <Text key={e} size="sm" className="tabular-nums">
176
- {e}
177
- </Text>
178
- ))}
179
- </Flex>
180
- </ScrollArea>
174
+ <Card variant="outline" className="h-40 w-full">
175
+ <CardContent flush>
176
+ <ScrollArea anchor="bottom" anchorOffset={0} type="always">
177
+ <CardContent>
178
+ <Flex direction="col" gap="xs">
179
+ {entries.map((e) => (
180
+ <Text key={e} size="sm" className="tabular-nums">
181
+ {e}
182
+ </Text>
183
+ ))}
184
+ </Flex>
185
+ </CardContent>
186
+ </ScrollArea>
187
+ </CardContent>
188
+ </Card>
181
189
  </CardContent>
182
190
  </Card>
183
191
 
@@ -189,15 +197,21 @@ export default function Demo() {
189
197
  </CardDescription>
190
198
  </CardHeader>
191
199
  <CardContent>
192
- <ScrollArea className="border-border h-56 w-full rounded-md border">
193
- <Flex direction="col" gap="xs" className="p-3">
194
- {entries.map((e) => (
195
- <div key={e} className="text-sm tabular-nums">
196
- {e}
197
- </div>
198
- ))}
199
- </Flex>
200
- </ScrollArea>
200
+ <Card variant="outline" className="h-56 w-full">
201
+ <CardContent flush>
202
+ <ScrollArea>
203
+ <CardContent>
204
+ <Flex direction="col" gap="xs">
205
+ {entries.map((e) => (
206
+ <div key={e} className="text-sm tabular-nums">
207
+ {e}
208
+ </div>
209
+ ))}
210
+ </Flex>
211
+ </CardContent>
212
+ </ScrollArea>
213
+ </CardContent>
214
+ </Card>
201
215
  </CardContent>
202
216
  </Card>
203
217
 
@@ -210,15 +224,21 @@ export default function Demo() {
210
224
  </CardDescription>
211
225
  </CardHeader>
212
226
  <CardContent>
213
- <ScrollArea type="always" className="border-border h-56 w-full rounded-md border">
214
- <Flex direction="col" gap="xs" className="p-3">
215
- {entries.map((e) => (
216
- <div key={e} className="text-sm tabular-nums">
217
- {e}
218
- </div>
219
- ))}
220
- </Flex>
221
- </ScrollArea>
227
+ <Card variant="outline" className="h-56 w-full">
228
+ <CardContent flush>
229
+ <ScrollArea type="always">
230
+ <CardContent>
231
+ <Flex direction="col" gap="xs">
232
+ {entries.map((e) => (
233
+ <div key={e} className="text-sm tabular-nums">
234
+ {e}
235
+ </div>
236
+ ))}
237
+ </Flex>
238
+ </CardContent>
239
+ </ScrollArea>
240
+ </CardContent>
241
+ </Card>
222
242
  </CardContent>
223
243
  </Card>
224
244
 
@@ -233,16 +253,22 @@ export default function Demo() {
233
253
  </CardDescription>
234
254
  </CardHeader>
235
255
  <CardContent>
236
- <ScrollArea className="border-border w-full rounded-md border">
237
- <Flex gap="lg" className="w-max p-3">
238
- {columns.map((c) => (
239
- <div key={c} className="text-sm whitespace-nowrap tabular-nums">
240
- {c}
241
- </div>
242
- ))}
243
- </Flex>
244
- <ScrollBar orientation="horizontal" />
245
- </ScrollArea>
256
+ <Card variant="outline" className="w-full">
257
+ <CardContent flush>
258
+ <ScrollArea>
259
+ <CardContent>
260
+ <Flex gap="lg" className="w-max">
261
+ {columns.map((c) => (
262
+ <div key={c} className="text-sm whitespace-nowrap tabular-nums">
263
+ {c}
264
+ </div>
265
+ ))}
266
+ </Flex>
267
+ </CardContent>
268
+ <ScrollBar orientation="horizontal" />
269
+ </ScrollArea>
270
+ </CardContent>
271
+ </Card>
246
272
  </CardContent>
247
273
  </Card>
248
274
 
@@ -254,15 +280,21 @@ export default function Demo() {
254
280
  </CardDescription>
255
281
  </CardHeader>
256
282
  <CardContent>
257
- <ScrollArea type="always" className="border-border h-56 w-full rounded-md border">
258
- <Flex direction="col" gap="xs" className="p-3">
259
- {shortEntries.map((e) => (
260
- <div key={e} className="text-sm tabular-nums">
261
- {e}
262
- </div>
263
- ))}
264
- </Flex>
265
- </ScrollArea>
283
+ <Card variant="outline" className="h-56 w-full">
284
+ <CardContent flush>
285
+ <ScrollArea type="always">
286
+ <CardContent>
287
+ <Flex direction="col" gap="xs">
288
+ {shortEntries.map((e) => (
289
+ <div key={e} className="text-sm tabular-nums">
290
+ {e}
291
+ </div>
292
+ ))}
293
+ </Flex>
294
+ </CardContent>
295
+ </ScrollArea>
296
+ </CardContent>
297
+ </Card>
266
298
  </CardContent>
267
299
  </Card>
268
300
  </Flex>
@@ -38,7 +38,7 @@ export default function Demo() {
38
38
  </CardHeader>
39
39
  <CardContent flush>
40
40
  <Table>
41
- <caption className="px-4 py-2 text-start">
41
+ <caption className="text-start" style={{ padding: "var(--space-2) var(--space-4)" }}>
42
42
  <Text size="xs" tone="muted">
43
43
  2026年5月 売上計上(税込)
44
44
  </Text>
@@ -83,7 +83,7 @@ export default function Demo() {
83
83
  期間を選択
84
84
  </Button>
85
85
  </PopoverTrigger>
86
- <PopoverContent className="w-auto p-0" align="start">
86
+ <PopoverContent className="w-auto" style={{ padding: 0 }} align="start">
87
87
  <Calendar
88
88
  mode="range"
89
89
  selected={range}
@@ -111,7 +111,7 @@ export default function Demo() {
111
111
  onCheckedChange={(next) => setScopes(next === true ? ALL_SCOPES : [])}
112
112
  />
113
113
  </Field>
114
- <Flex direction="col" gap="sm" className="ps-6">
114
+ <Flex direction="col" gap="sm" style={{ paddingInlineStart: "var(--space-6)" }}>
115
115
  <Field id="scope-read" label="閲覧">
116
116
  <Checkbox
117
117
  id="scope-read"
@@ -1,6 +1,13 @@
1
1
  import { useState } from "react";
2
2
 
3
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
3
+ import {
4
+ Badge,
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from "@godxjp/ui/data-display";
4
11
  import { FormField, Select } from "@godxjp/ui/data-entry";
5
12
  import { Text } from "@godxjp/ui/general";
6
13
  import { Flex, PageContainer } from "@godxjp/ui/layout";
@@ -63,12 +70,10 @@ async function loadCountries({ query }: SelectLoadParams): Promise<SelectLoadRes
63
70
  // real product ships an SVG flag set and renders it here. Tokens only — no hex, no inline style.
64
71
  function renderCountry(option: SelectOption) {
65
72
  return (
66
- <span className="flex items-center gap-2">
67
- <Text size="xs" tone="muted" mono className="bg-muted rounded px-1.5 py-0.5">
68
- {option.value}
69
- </Text>
73
+ <Flex align="center" gap="sm">
74
+ <Badge variant="secondary">{option.value}</Badge>
70
75
  <Text truncate>{option.label}</Text>
71
- </span>
76
+ </Flex>
72
77
  );
73
78
  }
74
79