@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.
- package/dist/app/app-provider.js +2 -1
- package/dist/components/data-display/badge.d.ts +28 -1
- package/dist/components/data-display/badge.js +2 -0
- package/dist/components/data-display/chat-bubble.d.ts +30 -0
- package/dist/components/data-display/chat-bubble.js +229 -0
- package/dist/components/data-display/data-table.d.ts +18 -2
- package/dist/components/data-display/data-table.js +4 -0
- package/dist/components/data-display/descriptions.js +4 -1
- package/dist/components/data-display/index.d.ts +5 -3
- package/dist/components/data-display/index.js +5 -2
- package/dist/components/data-display/popover.d.ts +19 -1
- package/dist/components/data-display/popover.js +12 -3
- package/dist/components/data-display/progress.d.ts +37 -0
- package/dist/components/data-display/progress.js +57 -5
- package/dist/components/data-display/scroll-area.js +26 -1
- package/dist/components/data-display/tree.d.ts +8 -0
- package/dist/components/data-display/tree.js +426 -0
- package/dist/components/data-entry/chat-composer.d.ts +50 -0
- package/dist/components/data-entry/chat-composer.js +163 -0
- package/dist/components/data-entry/chat-suggestion.d.ts +28 -0
- package/dist/components/data-entry/chat-suggestion.js +285 -0
- package/dist/components/data-entry/date-picker.d.ts +10 -3
- package/dist/components/data-entry/date-picker.js +503 -238
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +4 -1
- package/dist/components/data-entry/form.js +10 -1
- package/dist/components/data-entry/index.d.ts +4 -6
- package/dist/components/data-entry/index.js +4 -6
- package/dist/components/data-entry/label.d.ts +14 -1
- package/dist/components/data-entry/label.js +6 -1
- package/dist/components/data-entry/radio.d.ts +27 -6
- package/dist/components/data-entry/radio.js +88 -43
- package/dist/components/data-entry/search-select.js +8 -1
- package/dist/components/data-entry/select.js +2 -0
- package/dist/components/data-entry/switch.d.ts +6 -3
- package/dist/components/data-entry/switch.js +34 -11
- package/dist/components/data-entry/textarea.js +3 -1
- package/dist/components/data-entry/tree-utils.d.ts +10 -48
- package/dist/components/data-entry/tree-utils.js +1 -154
- package/dist/components/layout/mobile-shell.d.ts +1 -1
- package/dist/components/layout/mobile-shell.js +2 -0
- package/dist/components/navigation/menubar.d.ts +10 -3
- package/dist/components/navigation/steps.d.ts +1 -1
- package/dist/components/navigation/steps.js +3 -1
- package/dist/components/navigation/tabs-scroll.d.ts +27 -0
- package/dist/components/navigation/tabs-scroll.js +52 -1
- package/dist/components/navigation/tabs.d.ts +2 -2
- package/dist/components/navigation/tabs.js +88 -23
- package/dist/components/ui/index.d.ts +0 -1
- package/dist/components/ui/index.js +0 -1
- package/dist/components/ui/segmented.d.ts +15 -1
- package/dist/components/ui/segmented.js +13 -6
- package/dist/i18n/messages/en.json +48 -2
- package/dist/i18n/messages/ja.json +46 -2
- package/dist/i18n/messages/vi.json +47 -2
- package/dist/lib/datetime/picker-format.d.ts +18 -0
- package/dist/lib/datetime/picker-format.js +35 -1
- package/dist/lib/field-a11y.d.ts +12 -0
- package/dist/lib/field-a11y.js +14 -1
- package/dist/lib/tree.d.ts +53 -0
- package/dist/lib/tree.js +155 -0
- package/dist/props/components/data-display.prop.d.ts +194 -1
- package/dist/props/components/data-entry.prop.d.ts +307 -99
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +12 -1
- package/dist/props/components/navigation.prop.d.ts +76 -1
- package/dist/props/registry.d.ts +156 -19
- package/dist/props/registry.js +218 -18
- package/dist/props/vocabulary/data.prop.d.ts +12 -0
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/layout.prop.d.ts +11 -0
- package/dist/styles/badge-layout.css +4 -0
- package/dist/styles/card-layout.css +6 -6
- package/dist/styles/control.css +22 -6
- package/dist/styles/data-display-layout.css +385 -68
- package/dist/styles/data-entry-layout.css +64 -0
- package/dist/styles/focus-ring.css +4 -2
- package/dist/styles/navigation-layout.css +25 -0
- package/dist/styles/shell-layout.css +7 -1
- package/dist/styles/table-layout.css +34 -0
- package/dist/tokens/base.css +3 -0
- package/dist/tokens/components/chat-bubble.css +36 -0
- package/dist/tokens/components/chat-composer.css +19 -0
- package/dist/tokens/components/data-display.css +9 -6
- package/dist/tokens/components/descriptions.css +4 -0
- package/dist/tokens/components/navigation.css +6 -0
- package/dist/tokens/components/segmented.css +0 -2
- package/dist/tokens/components/shell.css +3 -0
- package/dist/tokens/components/table.css +3 -0
- package/dist/tokens/components/tree.css +27 -0
- package/dist/tokens/foundation.css +7 -0
- package/docs/COMPONENTS.md +14 -14
- package/docs/CONSUMER-RULES.md +24 -1
- package/docs/FRAME-COVERAGE-LEDGER.md +1 -1
- package/docs/FRAME-COVERAGE-REPORT.md +9 -7
- package/docs/TOKENS.md +65 -0
- package/docs/data-display/badge.tsx +37 -0
- package/docs/data-display/chat-bubble.tsx +397 -0
- package/docs/data-display/data-table/index.tsx +18 -0
- package/docs/data-display/popover.tsx +41 -1
- package/docs/data-display/progress.tsx +28 -0
- package/docs/data-display/timeline.tsx +46 -0
- package/docs/data-display/tree.tsx +394 -0
- package/docs/data-entry/calendar.tsx +2 -2
- package/docs/data-entry/chat-composer.tsx +464 -0
- package/docs/data-entry/chat-suggestion.tsx +301 -0
- package/docs/data-entry/date-picker.tsx +143 -3
- package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
- package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
- package/docs/data-entry/form.tsx +4 -4
- package/docs/data-entry/number-input.tsx +31 -0
- package/docs/data-entry/segmented.tsx +103 -1
- package/docs/layout/mobile-shell.tsx +5 -0
- package/docs/navigation/tabs.tsx +149 -0
- package/docs/roadmap/ai-chat-components.md +207 -0
- package/docs/roadmap/antd-parity.md +155 -0
- package/docs/roadmap/badge-tag-chip-count.md +172 -0
- package/docs/roadmap/list-masonry.md +159 -0
- package/docs/roadmap/parity-audit-data-display-feedback.md +567 -0
- package/docs/roadmap/parity-audit-data-entry.md +357 -0
- package/docs/roadmap/parity-audit-layout-navigation-general.md +464 -0
- package/docs/roadmap/parity-backlog.md +78 -0
- package/docs/roadmap/tree-components.md +151 -0
- package/docs/showcase/acme-portal.tsx +7 -0
- package/docs/showcase/table-tree-rows.tsx +4 -4
- package/package.json +13 -23
- package/scripts/ui-audit.mjs +17 -4
- package/dist/components/data-display/tree-list.d.ts +0 -13
- package/dist/components/data-display/tree-list.js +0 -26
- package/dist/components/data-entry/date-range-picker.d.ts +0 -11
- package/dist/components/data-entry/date-range-picker.js +0 -349
- package/dist/components/data-entry/month-picker.d.ts +0 -10
- package/dist/components/data-entry/month-picker.js +0 -241
- package/dist/components/data-entry/month-range-picker.d.ts +0 -10
- package/dist/components/data-entry/month-range-picker.js +0 -301
- package/dist/components/ui/date-range-picker.d.ts +0 -1
- package/dist/components/ui/date-range-picker.js +0 -2
- package/docs/data-display/tree-list.tsx +0 -107
- package/docs/data-entry/date-range-picker.tsx +0 -175
- package/docs/data-entry/month-picker.tsx +0 -101
- 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,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="period" を指定すると 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="fiscal_year"
|
|
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={ja} を渡すとポップオーバーのカレンダーが日本語表記 (曜日・月名)
|
|
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
|
-
}
|