@godxjp/ui 21.0.0 → 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 (103) 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/data-table.d.ts +18 -2
  5. package/dist/components/data-display/data-table.js +4 -0
  6. package/dist/components/data-display/index.d.ts +1 -1
  7. package/dist/components/data-display/popover.d.ts +19 -1
  8. package/dist/components/data-display/popover.js +9 -1
  9. package/dist/components/data-display/progress.d.ts +37 -0
  10. package/dist/components/data-display/progress.js +57 -5
  11. package/dist/components/data-entry/date-picker.d.ts +10 -3
  12. package/dist/components/data-entry/date-picker.js +503 -238
  13. package/dist/components/data-entry/form-field.d.ts +1 -1
  14. package/dist/components/data-entry/form-field.js +4 -1
  15. package/dist/components/data-entry/form.js +10 -1
  16. package/dist/components/data-entry/index.d.ts +0 -6
  17. package/dist/components/data-entry/index.js +0 -6
  18. package/dist/components/data-entry/label.d.ts +14 -1
  19. package/dist/components/data-entry/label.js +6 -1
  20. package/dist/components/data-entry/radio.d.ts +27 -6
  21. package/dist/components/data-entry/radio.js +88 -43
  22. package/dist/components/data-entry/search-select.js +8 -1
  23. package/dist/components/data-entry/select.js +2 -0
  24. package/dist/components/data-entry/switch.d.ts +6 -3
  25. package/dist/components/data-entry/switch.js +34 -11
  26. package/dist/components/layout/mobile-shell.d.ts +1 -1
  27. package/dist/components/layout/mobile-shell.js +2 -0
  28. package/dist/components/navigation/menubar.d.ts +10 -3
  29. package/dist/components/navigation/steps.d.ts +1 -1
  30. package/dist/components/navigation/steps.js +3 -1
  31. package/dist/components/navigation/tabs-scroll.d.ts +27 -0
  32. package/dist/components/navigation/tabs-scroll.js +52 -1
  33. package/dist/components/navigation/tabs.d.ts +2 -2
  34. package/dist/components/navigation/tabs.js +88 -23
  35. package/dist/components/ui/index.d.ts +0 -1
  36. package/dist/components/ui/index.js +0 -1
  37. package/dist/components/ui/segmented.d.ts +15 -1
  38. package/dist/components/ui/segmented.js +13 -6
  39. package/dist/i18n/messages/en.json +3 -2
  40. package/dist/i18n/messages/ja.json +3 -2
  41. package/dist/i18n/messages/vi.json +3 -2
  42. package/dist/lib/datetime/picker-format.d.ts +18 -0
  43. package/dist/lib/datetime/picker-format.js +35 -1
  44. package/dist/lib/field-a11y.d.ts +12 -0
  45. package/dist/lib/field-a11y.js +14 -1
  46. package/dist/props/components/data-display.prop.d.ts +7 -0
  47. package/dist/props/components/data-entry.prop.d.ts +180 -99
  48. package/dist/props/components/index.d.ts +1 -1
  49. package/dist/props/components/layout.prop.d.ts +12 -1
  50. package/dist/props/components/navigation.prop.d.ts +76 -1
  51. package/dist/props/registry.d.ts +16 -16
  52. package/dist/props/registry.js +16 -15
  53. package/dist/props/vocabulary/data.prop.d.ts +12 -0
  54. package/dist/props/vocabulary/index.d.ts +2 -2
  55. package/dist/props/vocabulary/layout.prop.d.ts +11 -0
  56. package/dist/styles/badge-layout.css +4 -0
  57. package/dist/styles/card-layout.css +6 -6
  58. package/dist/styles/control.css +15 -6
  59. package/dist/styles/data-display-layout.css +76 -13
  60. package/dist/styles/focus-ring.css +4 -2
  61. package/dist/styles/navigation-layout.css +25 -0
  62. package/dist/styles/shell-layout.css +5 -0
  63. package/dist/styles/table-layout.css +34 -0
  64. package/dist/tokens/components/data-display.css +9 -0
  65. package/dist/tokens/components/navigation.css +6 -0
  66. package/dist/tokens/components/segmented.css +0 -2
  67. package/dist/tokens/components/shell.css +2 -0
  68. package/dist/tokens/components/table.css +3 -0
  69. package/dist/tokens/foundation.css +7 -0
  70. package/docs/COMPONENTS.md +14 -14
  71. package/docs/CONSUMER-RULES.md +24 -1
  72. package/docs/FRAME-COVERAGE-REPORT.md +3 -6
  73. package/docs/TOKENS.md +65 -0
  74. package/docs/data-display/badge.tsx +37 -0
  75. package/docs/data-display/data-table/index.tsx +18 -0
  76. package/docs/data-display/popover.tsx +41 -1
  77. package/docs/data-display/progress.tsx +28 -0
  78. package/docs/data-entry/calendar.tsx +2 -2
  79. package/docs/data-entry/date-picker.tsx +143 -3
  80. package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
  81. package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
  82. package/docs/data-entry/form.tsx +4 -4
  83. package/docs/data-entry/number-input.tsx +31 -0
  84. package/docs/data-entry/segmented.tsx +103 -1
  85. package/docs/layout/mobile-shell.tsx +5 -0
  86. package/docs/navigation/tabs.tsx +149 -0
  87. package/docs/roadmap/antd-parity.md +35 -34
  88. package/docs/roadmap/parity-audit-data-entry.md +178 -165
  89. package/docs/roadmap/parity-backlog.md +6 -7
  90. package/docs/showcase/acme-portal.tsx +7 -0
  91. package/package.json +11 -23
  92. package/scripts/ui-audit.mjs +17 -4
  93. package/dist/components/data-entry/date-range-picker.d.ts +0 -11
  94. package/dist/components/data-entry/date-range-picker.js +0 -349
  95. package/dist/components/data-entry/month-picker.d.ts +0 -10
  96. package/dist/components/data-entry/month-picker.js +0 -241
  97. package/dist/components/data-entry/month-range-picker.d.ts +0 -10
  98. package/dist/components/data-entry/month-range-picker.js +0 -301
  99. package/dist/components/ui/date-range-picker.d.ts +0 -1
  100. package/dist/components/ui/date-range-picker.js +0 -2
  101. package/docs/data-entry/date-range-picker.tsx +0 -175
  102. package/docs/data-entry/month-picker.tsx +0 -101
  103. package/docs/data-entry/month-range-picker.tsx +0 -115
@@ -1,241 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { 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 { pickFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
8
- import { cn } from "../../lib/utils.js";
9
- import { resolveAllowClear, resolveAriaInvalid } 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
- function MonthPicker({
23
- value: valueProp,
24
- defaultValue,
25
- onValueChange,
26
- placeholder,
27
- disabled,
28
- className,
29
- id,
30
- name,
31
- fromYear,
32
- toYear,
33
- allowClear,
34
- open: openProp,
35
- defaultOpen = false,
36
- onOpenChange,
37
- status,
38
- variant,
39
- size,
40
- inputReadOnly,
41
- preserveInvalidOnBlur,
42
- placement = "bottom-start",
43
- renderExtraFooter,
44
- ref,
45
- ...ariaProps
46
- }) {
47
- const { t } = useTranslation();
48
- const { locale } = usePickerLocales();
49
- const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
50
- const isOpenControlled = openProp !== void 0;
51
- const open = isOpenControlled ? openProp : internalOpen;
52
- const setOpen = React.useCallback(
53
- (next) => {
54
- if (next && inputReadOnly) return;
55
- if (!isOpenControlled) setInternalOpen(next);
56
- onOpenChange?.(next);
57
- },
58
- [isOpenControlled, onOpenChange, inputReadOnly]
59
- );
60
- const autoId = React.useId();
61
- const inputId = id ?? autoId;
62
- const dialogId = `${inputId}-dialog`;
63
- const fieldA11y = pickFieldA11y(ariaProps);
64
- const identity = useFieldIdentity({ id, name, "data-field": fieldA11y["data-field"] });
65
- const isControlled = useControlledLatch(valueProp !== void 0);
66
- const [internalValue, setInternalValue] = React.useState(defaultValue);
67
- const value = isControlled ? valueProp : internalValue;
68
- const [text, setText] = React.useState(() => toYmText(value));
69
- const [viewYear, setViewYear] = React.useState(() => (value ?? /* @__PURE__ */ new Date()).getFullYear());
70
- React.useEffect(() => {
71
- setText(toYmText(value));
72
- if (value) setViewYear(value.getFullYear());
73
- }, [value]);
74
- const monthLabels = React.useMemo(() => {
75
- const fmt = new Intl.DateTimeFormat(locale, { month: "short" });
76
- return Array.from({ length: 12 }, (_, i) => fmt.format(new Date(2026, i, 1)));
77
- }, [locale]);
78
- const emit = (next) => {
79
- if (!isControlled) setInternalValue(next);
80
- onValueChange?.(next);
81
- };
82
- const clearControl = resolveAllowClear(allowClear, true, t("common.clear") ?? "Clear");
83
- const showClear = clearControl.enabled && Boolean(value) && !disabled && !inputReadOnly;
84
- const prevDisabled = fromYear !== void 0 && viewYear <= fromYear;
85
- const nextDisabled = toYear !== void 0 && viewYear >= toYear;
86
- return /* @__PURE__ */ jsx(Popover, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
87
- "div",
88
- {
89
- "data-disabled": disabled ? "" : void 0,
90
- "data-state": open ? "open" : "closed",
91
- "data-size": size,
92
- "data-status": status,
93
- "data-variant": variant,
94
- className: cn(
95
- "ui-control ui-control-composite-field",
96
- "aria-invalid:border-destructive",
97
- CONTROL_VARIANT_CHROME_CLASS[variant ?? "outlined"],
98
- CONTROL_STATUS_CHROME_CLASS,
99
- className
100
- ),
101
- onClick: () => {
102
- if (!disabled) setOpen(true);
103
- },
104
- children: [
105
- /* @__PURE__ */ jsx(
106
- "input",
107
- {
108
- ref,
109
- id: inputId,
110
- name: name ?? identity.name,
111
- "data-field": fieldA11y["data-field"] ?? identity["data-field"],
112
- value: text,
113
- disabled,
114
- readOnly: inputReadOnly,
115
- placeholder: placeholder ?? t("dataEntry.monthPicker.placeholder") ?? YM_HINT,
116
- inputMode: "numeric",
117
- autoComplete: "off",
118
- role: "combobox",
119
- "aria-expanded": open,
120
- "aria-haspopup": "dialog",
121
- "aria-controls": open ? dialogId : void 0,
122
- "aria-readonly": inputReadOnly || void 0,
123
- ...fieldA11y,
124
- "aria-invalid": resolveAriaInvalid(fieldA11y["aria-invalid"], status),
125
- className: "ui-month-picker-input",
126
- onKeyDown: (event) => {
127
- if (event.key === "ArrowDown") {
128
- event.preventDefault();
129
- setOpen(true);
130
- } else if (event.key === "Escape" && open) {
131
- setOpen(false);
132
- }
133
- },
134
- onChange: (event) => {
135
- setText(event.target.value);
136
- const parsed = parseYm(event.target.value);
137
- if (parsed) emit(parsed);
138
- else if (event.target.value.trim() === "") emit(void 0);
139
- },
140
- onBlur: () => {
141
- if (!preserveInvalidOnBlur) setText(toYmText(value));
142
- }
143
- }
144
- ),
145
- showClear ? /* @__PURE__ */ jsx(
146
- "button",
147
- {
148
- type: "button",
149
- tabIndex: -1,
150
- "aria-label": clearControl.label,
151
- className: "text-muted-foreground hover:text-foreground shrink-0",
152
- onClick: (event) => {
153
- event.stopPropagation();
154
- event.currentTarget.closest("div")?.querySelector("input:not([type=hidden])")?.focus();
155
- emit(void 0);
156
- setText("");
157
- },
158
- children: clearControl.clearIcon ?? /* @__PURE__ */ jsx(X, { className: "ui-month-picker-icon", "aria-hidden": "true" })
159
- }
160
- ) : /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
161
- "button",
162
- {
163
- type: "button",
164
- disabled,
165
- tabIndex: -1,
166
- "aria-label": t("dataEntry.monthPicker.openGrid") ?? "Open month grid",
167
- className: "text-muted-foreground hover:text-foreground shrink-0",
168
- children: /* @__PURE__ */ jsx(CalendarIcon, { className: "ui-month-picker-icon", "aria-hidden": "true" })
169
- }
170
- ) }),
171
- /* @__PURE__ */ jsxs(
172
- PopoverContent,
173
- {
174
- id: dialogId,
175
- role: "dialog",
176
- "aria-label": t("dataEntry.monthPicker.openGrid") ?? "Month grid",
177
- className: "ui-month-picker-panel",
178
- side: placement.startsWith("top") ? "top" : "bottom",
179
- align: placement.endsWith("end") ? "end" : "start",
180
- onOpenAutoFocus: (event) => event.preventDefault(),
181
- onClick: (event) => event.stopPropagation(),
182
- children: [
183
- /* @__PURE__ */ jsxs("div", { className: "ui-month-picker-nav", children: [
184
- /* @__PURE__ */ jsx(
185
- Button,
186
- {
187
- type: "button",
188
- variant: "outline",
189
- size: "icon-sm",
190
- disabled: prevDisabled,
191
- "aria-label": t("dataEntry.monthPicker.previousYear") ?? "Previous year",
192
- className: "ui-month-picker-nav-button",
193
- onClick: () => setViewYear((y) => y - 1),
194
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "ui-month-picker-icon", "aria-hidden": "true" })
195
- }
196
- ),
197
- /* @__PURE__ */ jsx("span", { className: "ui-month-picker-nav-label", "aria-live": "polite", children: viewYear }),
198
- /* @__PURE__ */ jsx(
199
- Button,
200
- {
201
- type: "button",
202
- variant: "outline",
203
- size: "icon-sm",
204
- disabled: nextDisabled,
205
- "aria-label": t("dataEntry.monthPicker.nextYear") ?? "Next year",
206
- className: "ui-month-picker-nav-button",
207
- onClick: () => setViewYear((y) => y + 1),
208
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "ui-month-picker-icon", "aria-hidden": "true" })
209
- }
210
- )
211
- ] }),
212
- /* @__PURE__ */ jsx("div", { role: "grid", "aria-label": String(viewYear), className: "ui-month-picker-grid", children: monthLabels.map((label, i) => {
213
- const selected = value?.getFullYear() === viewYear && value?.getMonth() === i;
214
- return /* @__PURE__ */ jsx(
215
- Button,
216
- {
217
- type: "button",
218
- variant: selected ? "default" : "ghost",
219
- size: "sm",
220
- "aria-pressed": selected,
221
- className: "ui-month-picker-cell",
222
- onClick: () => {
223
- emit(new Date(viewYear, i, 1));
224
- setOpen(false);
225
- },
226
- children: label
227
- },
228
- label
229
- );
230
- }) }),
231
- renderExtraFooter?.()
232
- ]
233
- }
234
- )
235
- ]
236
- }
237
- ) }) });
238
- }
239
- export {
240
- MonthPicker
241
- };
@@ -1,10 +0,0 @@
1
- import * as React from "react";
2
- import type { MonthRangePickerProp } from "../../props/components/data-entry.prop.js";
3
- export type { MonthRangePickerProp, MonthRangePickerProp as MonthRangePickerProps, } from "../../props/components/data-entry.prop.js";
4
- /**
5
- * MonthRangePicker — year/month (`yyyy/MM`) RANGE rendered as ONE input-styled control (the
6
- * RangePicker convention): `[ from → to ✕ 📅 ]`. The two inner fields stay real, typeable
7
- * `yyyy/MM` inputs (form-submittable via `${name}_from` / `${name}_to`); the Ant-style month grid
8
- * is the visual affordance.
9
- */
10
- export declare function MonthRangePicker({ value: valueProp, defaultValue, onValueChange, placeholder, disabled, className, id, name, fromYear, toYear, allowClear, open: openProp, defaultOpen, onOpenChange, status, variant, size, inputReadOnly, preserveInvalidOnBlur, placement, renderExtraFooter, ref, ...ariaProps }: MonthRangePickerProp): React.JSX.Element;
@@ -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";