@godxjp/ui 20.2.1 → 22.0.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 (141) hide show
  1. package/dist/app/app-provider.js +2 -1
  2. package/dist/components/data-display/badge.d.ts +28 -1
  3. package/dist/components/data-display/badge.js +2 -0
  4. package/dist/components/data-display/chat-bubble.d.ts +30 -0
  5. package/dist/components/data-display/chat-bubble.js +229 -0
  6. package/dist/components/data-display/data-table.d.ts +18 -2
  7. package/dist/components/data-display/data-table.js +4 -0
  8. package/dist/components/data-display/descriptions.js +4 -1
  9. package/dist/components/data-display/index.d.ts +5 -3
  10. package/dist/components/data-display/index.js +5 -2
  11. package/dist/components/data-display/popover.d.ts +19 -1
  12. package/dist/components/data-display/popover.js +12 -3
  13. package/dist/components/data-display/progress.d.ts +37 -0
  14. package/dist/components/data-display/progress.js +57 -5
  15. package/dist/components/data-display/scroll-area.js +26 -1
  16. package/dist/components/data-display/tree.d.ts +8 -0
  17. package/dist/components/data-display/tree.js +426 -0
  18. package/dist/components/data-entry/chat-composer.d.ts +50 -0
  19. package/dist/components/data-entry/chat-composer.js +163 -0
  20. package/dist/components/data-entry/chat-suggestion.d.ts +28 -0
  21. package/dist/components/data-entry/chat-suggestion.js +285 -0
  22. package/dist/components/data-entry/date-picker.d.ts +10 -3
  23. package/dist/components/data-entry/date-picker.js +503 -238
  24. package/dist/components/data-entry/form-field.d.ts +1 -1
  25. package/dist/components/data-entry/form-field.js +4 -1
  26. package/dist/components/data-entry/form.js +10 -1
  27. package/dist/components/data-entry/index.d.ts +4 -6
  28. package/dist/components/data-entry/index.js +4 -6
  29. package/dist/components/data-entry/label.d.ts +14 -1
  30. package/dist/components/data-entry/label.js +6 -1
  31. package/dist/components/data-entry/radio.d.ts +27 -6
  32. package/dist/components/data-entry/radio.js +88 -43
  33. package/dist/components/data-entry/search-select.js +8 -1
  34. package/dist/components/data-entry/select.js +2 -0
  35. package/dist/components/data-entry/switch.d.ts +6 -3
  36. package/dist/components/data-entry/switch.js +34 -11
  37. package/dist/components/data-entry/textarea.js +3 -1
  38. package/dist/components/data-entry/tree-utils.d.ts +10 -48
  39. package/dist/components/data-entry/tree-utils.js +1 -154
  40. package/dist/components/layout/mobile-shell.d.ts +1 -1
  41. package/dist/components/layout/mobile-shell.js +2 -0
  42. package/dist/components/navigation/menubar.d.ts +10 -3
  43. package/dist/components/navigation/steps.d.ts +1 -1
  44. package/dist/components/navigation/steps.js +3 -1
  45. package/dist/components/navigation/tabs-scroll.d.ts +27 -0
  46. package/dist/components/navigation/tabs-scroll.js +52 -1
  47. package/dist/components/navigation/tabs.d.ts +2 -2
  48. package/dist/components/navigation/tabs.js +88 -23
  49. package/dist/components/ui/index.d.ts +0 -1
  50. package/dist/components/ui/index.js +0 -1
  51. package/dist/components/ui/segmented.d.ts +15 -1
  52. package/dist/components/ui/segmented.js +13 -6
  53. package/dist/i18n/messages/en.json +48 -2
  54. package/dist/i18n/messages/ja.json +46 -2
  55. package/dist/i18n/messages/vi.json +47 -2
  56. package/dist/lib/datetime/picker-format.d.ts +18 -0
  57. package/dist/lib/datetime/picker-format.js +35 -1
  58. package/dist/lib/field-a11y.d.ts +12 -0
  59. package/dist/lib/field-a11y.js +14 -1
  60. package/dist/lib/tree.d.ts +53 -0
  61. package/dist/lib/tree.js +155 -0
  62. package/dist/props/components/data-display.prop.d.ts +194 -1
  63. package/dist/props/components/data-entry.prop.d.ts +307 -99
  64. package/dist/props/components/index.d.ts +1 -1
  65. package/dist/props/components/layout.prop.d.ts +12 -1
  66. package/dist/props/components/navigation.prop.d.ts +76 -1
  67. package/dist/props/registry.d.ts +156 -19
  68. package/dist/props/registry.js +218 -18
  69. package/dist/props/vocabulary/data.prop.d.ts +12 -0
  70. package/dist/props/vocabulary/index.d.ts +2 -2
  71. package/dist/props/vocabulary/layout.prop.d.ts +11 -0
  72. package/dist/styles/badge-layout.css +4 -0
  73. package/dist/styles/card-layout.css +6 -6
  74. package/dist/styles/control.css +22 -6
  75. package/dist/styles/data-display-layout.css +385 -68
  76. package/dist/styles/data-entry-layout.css +64 -0
  77. package/dist/styles/focus-ring.css +4 -2
  78. package/dist/styles/navigation-layout.css +25 -0
  79. package/dist/styles/shell-layout.css +7 -1
  80. package/dist/styles/table-layout.css +34 -0
  81. package/dist/tokens/base.css +3 -0
  82. package/dist/tokens/components/chat-bubble.css +36 -0
  83. package/dist/tokens/components/chat-composer.css +19 -0
  84. package/dist/tokens/components/data-display.css +9 -6
  85. package/dist/tokens/components/descriptions.css +4 -0
  86. package/dist/tokens/components/navigation.css +6 -0
  87. package/dist/tokens/components/segmented.css +0 -2
  88. package/dist/tokens/components/shell.css +3 -0
  89. package/dist/tokens/components/table.css +3 -0
  90. package/dist/tokens/components/tree.css +27 -0
  91. package/dist/tokens/foundation.css +7 -0
  92. package/docs/COMPONENTS.md +14 -14
  93. package/docs/CONSUMER-RULES.md +24 -1
  94. package/docs/FRAME-COVERAGE-LEDGER.md +1 -1
  95. package/docs/FRAME-COVERAGE-REPORT.md +9 -7
  96. package/docs/TOKENS.md +65 -0
  97. package/docs/data-display/badge.tsx +37 -0
  98. package/docs/data-display/chat-bubble.tsx +397 -0
  99. package/docs/data-display/data-table/index.tsx +18 -0
  100. package/docs/data-display/popover.tsx +41 -1
  101. package/docs/data-display/progress.tsx +28 -0
  102. package/docs/data-display/timeline.tsx +46 -0
  103. package/docs/data-display/tree.tsx +394 -0
  104. package/docs/data-entry/calendar.tsx +2 -2
  105. package/docs/data-entry/chat-composer.tsx +464 -0
  106. package/docs/data-entry/chat-suggestion.tsx +301 -0
  107. package/docs/data-entry/date-picker.tsx +143 -3
  108. package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
  109. package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
  110. package/docs/data-entry/form.tsx +4 -4
  111. package/docs/data-entry/number-input.tsx +31 -0
  112. package/docs/data-entry/segmented.tsx +103 -1
  113. package/docs/layout/mobile-shell.tsx +5 -0
  114. package/docs/navigation/tabs.tsx +149 -0
  115. package/docs/roadmap/ai-chat-components.md +207 -0
  116. package/docs/roadmap/antd-parity.md +155 -0
  117. package/docs/roadmap/badge-tag-chip-count.md +172 -0
  118. package/docs/roadmap/list-masonry.md +159 -0
  119. package/docs/roadmap/parity-audit-data-display-feedback.md +567 -0
  120. package/docs/roadmap/parity-audit-data-entry.md +357 -0
  121. package/docs/roadmap/parity-audit-layout-navigation-general.md +464 -0
  122. package/docs/roadmap/parity-backlog.md +78 -0
  123. package/docs/roadmap/tree-components.md +151 -0
  124. package/docs/showcase/acme-portal.tsx +7 -0
  125. package/docs/showcase/table-tree-rows.tsx +4 -4
  126. package/package.json +13 -23
  127. package/scripts/ui-audit.mjs +17 -4
  128. package/dist/components/data-display/tree-list.d.ts +0 -13
  129. package/dist/components/data-display/tree-list.js +0 -26
  130. package/dist/components/data-entry/date-range-picker.d.ts +0 -11
  131. package/dist/components/data-entry/date-range-picker.js +0 -349
  132. package/dist/components/data-entry/month-picker.d.ts +0 -10
  133. package/dist/components/data-entry/month-picker.js +0 -241
  134. package/dist/components/data-entry/month-range-picker.d.ts +0 -10
  135. package/dist/components/data-entry/month-range-picker.js +0 -301
  136. package/dist/components/ui/date-range-picker.d.ts +0 -1
  137. package/dist/components/ui/date-range-picker.js +0 -2
  138. package/docs/data-display/tree-list.tsx +0 -107
  139. package/docs/data-entry/date-range-picker.tsx +0 -175
  140. package/docs/data-entry/month-picker.tsx +0 -101
  141. package/docs/data-entry/month-range-picker.tsx +0 -115
@@ -1,301 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { ArrowRight, CalendarIcon, ChevronLeft, ChevronRight, X } from "lucide-react";
5
- import { usePickerLocales, useTranslation } from "../../i18n/use-translation.js";
6
- import { useControlledLatch } from "../../lib/hooks.js";
7
- import { pickGroupFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
8
- import { cn } from "../../lib/utils.js";
9
- import { resolveAllowClear } from "./control-surface.js";
10
- import { CONTROL_STATUS_CHROME_CLASS, CONTROL_VARIANT_CHROME_CLASS } from "./control-appearance.js";
11
- import { Button } from "../general/button.js";
12
- import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
13
- const YM_HINT = "yyyy/mm";
14
- const toYmText = (d) => d ? `${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, "0")}` : "";
15
- const parseYm = (raw) => {
16
- const m = /^(\d{4})[/-](\d{1,2})$/.exec(raw.trim());
17
- if (!m) return void 0;
18
- const month = Number(m[2]);
19
- if (month < 1 || month > 12) return void 0;
20
- return new Date(Number(m[1]), month - 1, 1);
21
- };
22
- const ymIndex = (d) => d.getFullYear() * 12 + d.getMonth();
23
- function MonthRangePicker({
24
- value: valueProp,
25
- defaultValue,
26
- onValueChange,
27
- placeholder,
28
- disabled,
29
- className,
30
- id,
31
- name,
32
- fromYear,
33
- toYear,
34
- allowClear,
35
- open: openProp,
36
- defaultOpen = false,
37
- onOpenChange,
38
- status,
39
- variant,
40
- size,
41
- inputReadOnly,
42
- preserveInvalidOnBlur,
43
- placement = "bottom-start",
44
- renderExtraFooter,
45
- ref,
46
- ...ariaProps
47
- }) {
48
- const { t } = useTranslation();
49
- const { locale } = usePickerLocales();
50
- const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
51
- const isOpenControlled = openProp !== void 0;
52
- const open = isOpenControlled ? openProp : internalOpen;
53
- const setOpen = React.useCallback(
54
- (next) => {
55
- if (next && inputReadOnly) return;
56
- if (!isOpenControlled) setInternalOpen(next);
57
- onOpenChange?.(next);
58
- },
59
- [isOpenControlled, onOpenChange, inputReadOnly]
60
- );
61
- const groupA11y = pickGroupFieldA11y(ariaProps);
62
- const autoId = React.useId();
63
- const groupId = id ?? autoId;
64
- const fromId = `${groupId}-from`;
65
- const toId = `${groupId}-to`;
66
- const identity = useFieldIdentity({ id: groupId, name, "data-field": groupA11y["data-field"] });
67
- const rangeField = groupA11y["data-field"] ?? identity["data-field"];
68
- const rangeName = name ?? identity.name;
69
- const isControlled = useControlledLatch(valueProp !== void 0);
70
- const [internalValue, setInternalValue] = React.useState(defaultValue);
71
- const value = isControlled ? valueProp : internalValue;
72
- const [fromText, setFromText] = React.useState(() => toYmText(value?.from));
73
- const [toText, setToText] = React.useState(() => toYmText(value?.to));
74
- const [viewYear, setViewYear] = React.useState(() => (value?.from ?? /* @__PURE__ */ new Date()).getFullYear());
75
- React.useEffect(() => {
76
- setFromText(toYmText(value?.from));
77
- setToText(toYmText(value?.to));
78
- if (value?.from) setViewYear(value.from.getFullYear());
79
- }, [value?.from, value?.to]);
80
- const monthLabels = React.useMemo(() => {
81
- const fmt = new Intl.DateTimeFormat(locale, { month: "short" });
82
- return Array.from({ length: 12 }, (_, i) => fmt.format(new Date(2026, i, 1)));
83
- }, [locale]);
84
- const emit = (next) => {
85
- if (!isControlled) setInternalValue(next);
86
- onValueChange?.(next);
87
- };
88
- const clearControl = resolveAllowClear(allowClear, true, t("common.clear") ?? "Clear");
89
- const showClear = clearControl.enabled && Boolean(value?.from || value?.to) && !disabled && !inputReadOnly;
90
- const prevDisabled = fromYear !== void 0 && viewYear <= fromYear;
91
- const nextDisabled = toYear !== void 0 && viewYear >= toYear;
92
- const clear = () => {
93
- emit(void 0);
94
- setFromText("");
95
- setToText("");
96
- };
97
- const commitEdge = (edge, raw) => {
98
- const trimmed = raw.trim();
99
- const parsed = trimmed === "" ? void 0 : parseYm(trimmed);
100
- if (trimmed !== "" && !parsed) return;
101
- const next = { from: value?.from, to: value?.to, [edge]: parsed };
102
- if (next.from && next.to && ymIndex(next.from) > ymIndex(next.to)) {
103
- const swapped = { from: next.to, to: next.from };
104
- emit(swapped);
105
- return;
106
- }
107
- emit(next.from || next.to ? next : void 0);
108
- };
109
- const pickMonth = (picked) => {
110
- const pendingFrom = value?.from && !value?.to ? value.from : void 0;
111
- if (!pendingFrom) {
112
- emit({ from: picked, to: void 0 });
113
- return;
114
- }
115
- const [from, to] = ymIndex(picked) < ymIndex(pendingFrom) ? [picked, pendingFrom] : [pendingFrom, picked];
116
- emit({ from, to });
117
- setOpen(false);
118
- };
119
- const sharedKeyHandlers = {
120
- onKeyDown: (event) => {
121
- if (event.key === "ArrowDown") {
122
- event.preventDefault();
123
- setOpen(true);
124
- } else if (event.key === "Escape" && open) {
125
- setOpen(false);
126
- }
127
- }
128
- };
129
- const innerInputClass = "ui-month-picker-input";
130
- const resolvedPlaceholder = placeholder ?? t("dataEntry.monthPicker.placeholder") ?? YM_HINT;
131
- return /* @__PURE__ */ jsx(Popover, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
132
- "div",
133
- {
134
- role: "group",
135
- id: groupId,
136
- ...groupA11y,
137
- "data-field": rangeField,
138
- "aria-disabled": disabled ? true : void 0,
139
- "data-disabled": disabled ? "" : void 0,
140
- "data-state": open ? "open" : "closed",
141
- "data-size": size,
142
- "data-status": status,
143
- "data-variant": variant,
144
- className: cn(
145
- "ui-control ui-control-composite-field",
146
- "aria-invalid:border-destructive",
147
- CONTROL_VARIANT_CHROME_CLASS[variant ?? "outlined"],
148
- CONTROL_STATUS_CHROME_CLASS,
149
- className
150
- ),
151
- onClick: () => {
152
- if (!disabled) setOpen(true);
153
- },
154
- children: [
155
- /* @__PURE__ */ jsx(
156
- "input",
157
- {
158
- ref,
159
- id: fromId,
160
- "data-field": rangeField ? `${rangeField}_from` : void 0,
161
- name: rangeName ? `${rangeName}_from` : void 0,
162
- value: fromText,
163
- disabled,
164
- readOnly: inputReadOnly,
165
- "aria-readonly": inputReadOnly || void 0,
166
- placeholder: resolvedPlaceholder,
167
- inputMode: "numeric",
168
- autoComplete: "off",
169
- "aria-label": t("dataEntry.dateRangePicker.from") ?? "From",
170
- className: innerInputClass,
171
- ...sharedKeyHandlers,
172
- onChange: (event) => {
173
- setFromText(event.target.value);
174
- commitEdge("from", event.target.value);
175
- },
176
- onBlur: () => {
177
- if (!preserveInvalidOnBlur) setFromText(toYmText(value?.from));
178
- }
179
- }
180
- ),
181
- /* @__PURE__ */ jsx(ArrowRight, { className: "ui-month-picker-separator-icon", "aria-hidden": "true" }),
182
- /* @__PURE__ */ jsx(
183
- "input",
184
- {
185
- id: toId,
186
- "data-field": rangeField ? `${rangeField}_to` : void 0,
187
- name: rangeName ? `${rangeName}_to` : void 0,
188
- value: toText,
189
- disabled,
190
- readOnly: inputReadOnly,
191
- "aria-readonly": inputReadOnly || void 0,
192
- placeholder: resolvedPlaceholder,
193
- inputMode: "numeric",
194
- autoComplete: "off",
195
- "aria-label": t("dataEntry.dateRangePicker.to") ?? "To",
196
- className: innerInputClass,
197
- ...sharedKeyHandlers,
198
- onChange: (event) => {
199
- setToText(event.target.value);
200
- commitEdge("to", event.target.value);
201
- },
202
- onBlur: () => {
203
- if (!preserveInvalidOnBlur) setToText(toYmText(value?.to));
204
- }
205
- }
206
- ),
207
- showClear ? /* @__PURE__ */ jsx(
208
- "button",
209
- {
210
- type: "button",
211
- tabIndex: -1,
212
- "aria-label": clearControl.label,
213
- className: "text-muted-foreground hover:text-foreground shrink-0",
214
- onClick: (event) => {
215
- event.stopPropagation();
216
- event.currentTarget.closest("div")?.querySelector("input:not([type=hidden])")?.focus();
217
- clear();
218
- },
219
- children: clearControl.clearIcon ?? /* @__PURE__ */ jsx(X, { className: "ui-month-picker-icon", "aria-hidden": "true" })
220
- }
221
- ) : /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
222
- "button",
223
- {
224
- type: "button",
225
- disabled,
226
- tabIndex: -1,
227
- "aria-label": t("dataEntry.monthPicker.openGrid") ?? "Open month grid",
228
- className: "text-muted-foreground hover:text-foreground shrink-0",
229
- children: /* @__PURE__ */ jsx(CalendarIcon, { className: "ui-month-picker-icon", "aria-hidden": "true" })
230
- }
231
- ) }),
232
- /* @__PURE__ */ jsxs(
233
- PopoverContent,
234
- {
235
- className: "ui-month-picker-panel",
236
- side: placement.startsWith("top") ? "top" : "bottom",
237
- align: placement.endsWith("end") ? "end" : "start",
238
- onOpenAutoFocus: (event) => event.preventDefault(),
239
- onClick: (event) => event.stopPropagation(),
240
- children: [
241
- /* @__PURE__ */ jsxs("div", { className: "ui-month-picker-nav", children: [
242
- /* @__PURE__ */ jsx(
243
- Button,
244
- {
245
- type: "button",
246
- variant: "outline",
247
- size: "icon-sm",
248
- disabled: prevDisabled,
249
- "aria-label": t("dataEntry.monthPicker.previousYear") ?? "Previous year",
250
- className: "ui-month-picker-nav-button",
251
- onClick: () => setViewYear((y) => y - 1),
252
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "ui-month-picker-icon", "aria-hidden": "true" })
253
- }
254
- ),
255
- /* @__PURE__ */ jsx("span", { className: "ui-month-picker-nav-label", "aria-live": "polite", children: viewYear }),
256
- /* @__PURE__ */ jsx(
257
- Button,
258
- {
259
- type: "button",
260
- variant: "outline",
261
- size: "icon-sm",
262
- disabled: nextDisabled,
263
- "aria-label": t("dataEntry.monthPicker.nextYear") ?? "Next year",
264
- className: "ui-month-picker-nav-button",
265
- onClick: () => setViewYear((y) => y + 1),
266
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "ui-month-picker-icon", "aria-hidden": "true" })
267
- }
268
- )
269
- ] }),
270
- /* @__PURE__ */ jsx("div", { role: "grid", "aria-label": String(viewYear), className: "ui-month-picker-grid", children: monthLabels.map((label, i) => {
271
- const cell = new Date(viewYear, i, 1);
272
- const cellIdx = ymIndex(cell);
273
- const fromIdx = value?.from ? ymIndex(value.from) : void 0;
274
- const toIdx = value?.to ? ymIndex(value.to) : void 0;
275
- const isEdge = cellIdx === fromIdx || cellIdx === toIdx;
276
- const inRange = fromIdx !== void 0 && toIdx !== void 0 && cellIdx > fromIdx && cellIdx < toIdx;
277
- return /* @__PURE__ */ jsx(
278
- Button,
279
- {
280
- type: "button",
281
- variant: isEdge ? "default" : inRange ? "secondary" : "ghost",
282
- size: "sm",
283
- "aria-pressed": isEdge,
284
- className: "ui-month-picker-cell",
285
- onClick: () => pickMonth(cell),
286
- children: label
287
- },
288
- label
289
- );
290
- }) }),
291
- renderExtraFooter?.()
292
- ]
293
- }
294
- )
295
- ]
296
- }
297
- ) }) });
298
- }
299
- export {
300
- MonthRangePicker
301
- };
@@ -1 +0,0 @@
1
- export * from "../data-entry/date-range-picker.js";
@@ -1,2 +0,0 @@
1
- "use client";
2
- export * from "../data-entry/date-range-picker.js";
@@ -1,107 +0,0 @@
1
- import {
2
- Badge,
3
- Card,
4
- CardContent,
5
- CardDescription,
6
- CardHeader,
7
- CardTitle,
8
- EmptyState,
9
- TreeList,
10
- } from "@godxjp/ui/data-display";
11
- import { Flex, PageContainer } from "@godxjp/ui/layout";
12
- import { FolderTree } from "lucide-react";
13
-
14
- /**
15
- * TreeList — a flat array rendered as an indented hierarchy; depth is data-driven
16
- * (never nest DOM). active highlights a row (aria-current); badge surfaces a
17
- * secondary label. Indentation is defined for depth 0-2, so flatten deeper
18
- * branches before rendering. Composed only from real @godxjp/ui components.
19
- */
20
- const accounts = [
21
- { id: "1000", title: "資産", depth: 0, badge: "親科目" },
22
- { id: "1100", title: "流動資産", depth: 1, description: "1年以内に現金化" },
23
- {
24
- id: "1110",
25
- title: "現金及び預金",
26
- description: "普通・当座・小口",
27
- depth: 2,
28
- badge: "3 口座",
29
- active: true,
30
- },
31
- {
32
- id: "1120",
33
- title: "売掛金",
34
- description: "得意先への未回収債権",
35
- depth: 2,
36
- badge: (
37
- <Badge variant="outline" tone="warning">
38
- 要確認
39
- </Badge>
40
- ),
41
- },
42
- { id: "2000", title: "負債", depth: 0, badge: "親科目" },
43
- { id: "2100", title: "流動負債", depth: 1, description: "1年以内に支払" },
44
- { id: "2110", title: "買掛金", depth: 2, badge: "12 件" },
45
- ];
46
-
47
- // Independent data: active is allowed on any depth, including a top-level parent.
48
- const departments = [
49
- { id: "d0", title: "本社", depth: 0, active: true, badge: "選択中" },
50
- { id: "d1", title: "営業部", depth: 1, description: "首都圏・関西" },
51
- { id: "d2", title: "開発部", depth: 1, description: "プロダクト・基盤" },
52
- ];
53
-
54
- export default function Demo() {
55
- return (
56
- <PageContainer
57
- title="TreeList"
58
- subtitle="Hierarchical list · depth lives in the data, not the DOM"
59
- >
60
- <Flex direction="col" gap="lg">
61
- <Card>
62
- <CardHeader>
63
- <CardTitle level={2}>勘定科目ツリー</CardTitle>
64
- <CardDescription>
65
- Pre-filter server-side; each item still carries its depth (0-2). An active leaf
66
- carries aria-current; badges accept a string or a nested Badge node.
67
- </CardDescription>
68
- </CardHeader>
69
- <CardContent>
70
- <TreeList items={accounts} />
71
- </CardContent>
72
- </Card>
73
-
74
- <Card>
75
- <CardHeader>
76
- <CardTitle level={2}>組織ツリー(親を選択中)</CardTitle>
77
- <CardDescription>
78
- active is data-driven and works at any depth. Here the depth-0 parent is the current
79
- row.
80
- </CardDescription>
81
- </CardHeader>
82
- <CardContent>
83
- <TreeList items={departments} />
84
- </CardContent>
85
- </Card>
86
-
87
- <Card>
88
- <CardHeader>
89
- <CardTitle level={2}>空の状態</CardTitle>
90
- <CardDescription>
91
- An empty items={"{[]}"} array renders an empty list. Pair it with an EmptyState
92
- placeholder.
93
- </CardDescription>
94
- </CardHeader>
95
- <CardContent>
96
- <TreeList items={[]} />
97
- <EmptyState
98
- icon={FolderTree}
99
- title="科目がありません"
100
- description="フィルター条件に一致する勘定科目が見つかりませんでした。"
101
- />
102
- </CardContent>
103
- </Card>
104
- </Flex>
105
- </PageContainer>
106
- );
107
- }
@@ -1,175 +0,0 @@
1
- import { useState } from "react";
2
- import { ja } from "date-fns/locale";
3
-
4
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
5
- import { DateRangePicker, FormField } from "@godxjp/ui/data-entry";
6
- import { Flex, PageContainer } from "@godxjp/ui/layout";
7
- import type { DateRange } from "react-day-picker";
8
-
9
- /**
10
- * DateRangePicker — WAI-ARIA date-range control with two typeable ISO inputs
11
- * + popover calendar. Submits as ${name}_from / ${name}_to. Never compose
12
- * two DatePickers side-by-side to fake a range. Composed only from real
13
- * @godxjp/ui components.
14
- */
15
- export default function Demo() {
16
- const [period, setPeriod] = useState<DateRange | undefined>({
17
- from: new Date(2026, 3, 1),
18
- to: new Date(2027, 2, 31),
19
- });
20
- const [reportRange, setReportRange] = useState<DateRange | undefined>(undefined);
21
- const [campaign, setCampaign] = useState<DateRange | undefined>({
22
- from: new Date(2026, 5, 1),
23
- to: new Date(2026, 5, 30),
24
- });
25
-
26
- return (
27
- <PageContainer
28
- title="DateRangePicker"
29
- subtitle="期間入力 · 開始/終了 ISO 入力 + 範囲カレンダーポップオーバー"
30
- >
31
- <Flex direction="col" gap="lg">
32
- <Card>
33
- <CardHeader>
34
- <CardTitle level={2}>基本 (controlled)</CardTitle>
35
- <CardDescription>
36
- value + onValueChange
37
- で制御。開始/終了を直接タイプ入力するか、カレンダーアイコンを開いて
38
- 範囲を選択できる。name=&#34;period&#34; を指定すると period_from / period_to として
39
- ISO yyyy-MM-dd でフォーム送信される。
40
- </CardDescription>
41
- </CardHeader>
42
- <CardContent>
43
- <FormField id="period" label="会計期間" required>
44
- <DateRangePicker
45
- id="period"
46
- name="period"
47
- value={period}
48
- onValueChange={setPeriod}
49
- fromDate={new Date(2020, 0, 1)}
50
- toDate={new Date(2030, 11, 31)}
51
- />
52
- </FormField>
53
- </CardContent>
54
- </Card>
55
-
56
- <Card>
57
- <CardHeader>
58
- <CardTitle level={2}>レポート期間フィルター (未選択)</CardTitle>
59
- <CardDescription>
60
- 初期値なし。選択後は reportRange_from / reportRange_to
61
- がクエリパラメータとして使われる。
62
- </CardDescription>
63
- </CardHeader>
64
- <CardContent>
65
- <FormField id="report-range" label="レポート期間">
66
- <DateRangePicker
67
- id="report-range"
68
- name="reportRange"
69
- value={reportRange}
70
- onValueChange={setReportRange}
71
- fromDate={new Date(2024, 0, 1)}
72
- toDate={new Date(2026, 11, 31)}
73
- placeholder="yyyy-mm-dd"
74
- />
75
- </FormField>
76
- </CardContent>
77
- </Card>
78
-
79
- <Card>
80
- <CardHeader>
81
- <CardTitle level={2}>非制御 (defaultValue)</CardTitle>
82
- <CardDescription>
83
- value / onValueChange を渡さず defaultValue
84
- で初期範囲だけ与える。状態はコンポーネント内部で 保持され、name=&#34;fiscal_year&#34;
85
- のまま fiscal_year_from / fiscal_year_to として送信される。
86
- </CardDescription>
87
- </CardHeader>
88
- <CardContent>
89
- <FormField id="fiscal-year" label="会計年度 (初期値のみ)">
90
- <DateRangePicker
91
- id="fiscal-year"
92
- name="fiscal_year"
93
- defaultValue={{
94
- from: new Date(2026, 3, 1),
95
- to: new Date(2027, 2, 31),
96
- }}
97
- fromDate={new Date(2020, 0, 1)}
98
- toDate={new Date(2030, 11, 31)}
99
- />
100
- </FormField>
101
- </CardContent>
102
- </Card>
103
-
104
- <Card>
105
- <CardHeader>
106
- <CardTitle level={2}>locale で日本語カレンダー</CardTitle>
107
- <CardDescription>
108
- locale=&#123;ja&#125; を渡すとポップオーバーのカレンダーが日本語表記 (曜日・月名)
109
- になる。 入力欄は常に ISO yyyy-MM-dd を保持する。
110
- </CardDescription>
111
- </CardHeader>
112
- <CardContent>
113
- <FormField id="campaign-period" label="キャンペーン期間">
114
- <DateRangePicker
115
- id="campaign-period"
116
- name="campaign_period"
117
- value={campaign}
118
- onValueChange={setCampaign}
119
- locale={ja}
120
- fromDate={new Date(2024, 0, 1)}
121
- toDate={new Date(2027, 11, 31)}
122
- />
123
- </FormField>
124
- </CardContent>
125
- </Card>
126
-
127
- <Card>
128
- <CardHeader>
129
- <CardTitle level={2}>disabled 状態</CardTitle>
130
- <CardDescription>確定済み期間や読み取り専用フィールドに使用。</CardDescription>
131
- </CardHeader>
132
- <CardContent>
133
- <FormField id="locked-period" label="確定期間">
134
- <DateRangePicker
135
- id="locked-period"
136
- name="locked_period"
137
- value={{
138
- from: new Date(2025, 3, 1),
139
- to: new Date(2026, 2, 31),
140
- }}
141
- disabled
142
- />
143
- </FormField>
144
- </CardContent>
145
- </Card>
146
-
147
- <Card>
148
- <CardHeader>
149
- <CardTitle level={2}>期間プリセットと確定</CardTitle>
150
- </CardHeader>
151
- <CardContent>
152
- <FormField id="preset-range" label="集計期間">
153
- <DateRangePicker
154
- id="preset-range"
155
- name="report"
156
- format="yyyy/MM/dd"
157
- needConfirm
158
- allowEmpty={[false, true]}
159
- showWeek
160
- minDate={new Date(2026, 0, 1)}
161
- maxDate={new Date(2026, 11, 31)}
162
- presets={[
163
- {
164
- label: "9月",
165
- value: () => ({ from: new Date(2026, 8, 1), to: new Date(2026, 8, 30) }),
166
- },
167
- ]}
168
- />
169
- </FormField>
170
- </CardContent>
171
- </Card>
172
- </Flex>
173
- </PageContainer>
174
- );
175
- }