@bigbinary/neeto-atoms 1.0.38 → 1.0.39
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/DatePicker-CJfkNORC.js +634 -0
- package/dist/DatePicker-CJfkNORC.js.map +1 -0
- package/dist/{TimePicker-BzlF3JWj.js → TimePicker-D4cwQB7b.js} +11 -7
- package/dist/TimePicker-D4cwQB7b.js.map +1 -0
- package/dist/{TimePickerPanel-CgEbjExH.js → TimePickerPanel-DN5mK2he.js} +18 -7
- package/dist/TimePickerPanel-DN5mK2he.js.map +1 -0
- package/dist/cjs/DatePicker-DaVdS--q.js +636 -0
- package/dist/cjs/DatePicker-DaVdS--q.js.map +1 -0
- package/dist/cjs/{TimePicker-Cwwa1DD8.js → TimePicker-DrHKSjhU.js} +11 -7
- package/dist/cjs/TimePicker-DrHKSjhU.js.map +1 -0
- package/dist/cjs/{TimePickerPanel-CAdLD7qW.js → TimePickerPanel-Df904uM-.js} +22 -10
- package/dist/cjs/TimePickerPanel-Df904uM-.js.map +1 -0
- package/dist/cjs/components/DatePicker.js +4 -3
- package/dist/cjs/components/DatePicker.js.map +1 -1
- package/dist/cjs/components/TimePicker.js +3 -2
- package/dist/cjs/components/TimePicker.js.map +1 -1
- package/dist/cjs/components/index.js +5 -4
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/index.js +11 -247
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/primitives/Calendar.js +8129 -10
- package/dist/cjs/primitives/Calendar.js.map +1 -1
- package/dist/cjs/primitives/index.js +1 -1
- package/dist/components/DatePicker/constants.d.ts +0 -1
- package/dist/components/DatePicker/types.d.ts +7 -5
- package/dist/components/DatePicker/utils.d.ts +16 -5
- package/dist/components/DatePicker.js +4 -3
- package/dist/components/DatePicker.js.map +1 -1
- package/dist/components/TimePicker/types.d.ts +3 -3
- package/dist/components/TimePicker/utils.d.ts +12 -1
- package/dist/components/TimePicker.js +3 -2
- package/dist/components/TimePicker.js.map +1 -1
- package/dist/components/index.js +5 -4
- package/dist/components/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +9 -239
- package/dist/index.js.map +1 -1
- package/dist/primitives/Calendar.js +8112 -8
- package/dist/primitives/Calendar.js.map +1 -1
- package/dist/primitives/index.js +1 -1
- package/dist/utils/timezone.d.ts +7 -0
- package/package.json +2 -1
- package/dist/Calendar-CjOBwDbx.js +0 -8134
- package/dist/Calendar-CjOBwDbx.js.map +0 -1
- package/dist/DatePicker-IrQUHqdL.js +0 -3233
- package/dist/DatePicker-IrQUHqdL.js.map +0 -1
- package/dist/TimePicker-BzlF3JWj.js.map +0 -1
- package/dist/TimePickerPanel-CgEbjExH.js.map +0 -1
- package/dist/cjs/Calendar-02KiUZTT.js +0 -8175
- package/dist/cjs/Calendar-02KiUZTT.js.map +0 -1
- package/dist/cjs/DatePicker-DdTclP8E.js +0 -3235
- package/dist/cjs/DatePicker-DdTclP8E.js.map +0 -1
- package/dist/cjs/TimePicker-Cwwa1DD8.js.map +0 -1
- package/dist/cjs/TimePickerPanel-CAdLD7qW.js.map +0 -1
- package/dist/utils/dayjs/index.d.ts +0 -4
- package/dist/utils/dayjs/timezonePlugin.d.ts +0 -3
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var primitives_Calendar = require('./primitives/Calendar.js');
|
|
6
|
+
var primitives_Popover = require('./primitives/Popover.js');
|
|
7
|
+
var primitives_Field = require('./primitives/Field.js');
|
|
8
|
+
var utils$1 = require('./utils-BhM0B89p.js');
|
|
9
|
+
var utils = require('@bigbinary/neeto-commons-frontend/utils');
|
|
10
|
+
var TimePickerPanel = require('./TimePickerPanel-Df904uM-.js');
|
|
11
|
+
var primitives_Button = require('./primitives/Button.js');
|
|
12
|
+
var createLucideIcon = require('./createLucideIcon-D0tRgV6l.js');
|
|
13
|
+
var x = require('./x-Brw3FJst.js');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @license lucide-react v0.577.0 - ISC
|
|
17
|
+
*
|
|
18
|
+
* This source code is licensed under the ISC license.
|
|
19
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
const __iconNode = [
|
|
24
|
+
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
25
|
+
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
26
|
+
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
27
|
+
["path", { d: "M3 10h18", key: "8toen8" }]
|
|
28
|
+
];
|
|
29
|
+
const Calendar = createLucideIcon.createLucideIcon("calendar", __iconNode);
|
|
30
|
+
|
|
31
|
+
const DEFAULT_DATE_FORMAT = "dd/MM/yyyy";
|
|
32
|
+
const DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
|
33
|
+
const SIZE_CONFIG = {
|
|
34
|
+
small: { trigger: "h-7 text-xs", icon: "size-3.5" },
|
|
35
|
+
medium: { trigger: "h-8 text-sm", icon: "size-4" },
|
|
36
|
+
large: { trigger: "h-10 text-sm", icon: "size-4" }
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const dayjsParse = utils.dayjs;
|
|
40
|
+
const toNativeDate = (value) => {
|
|
41
|
+
if (value == null) return null;
|
|
42
|
+
if (value instanceof Date) return value;
|
|
43
|
+
if (typeof value.toDate === "function") {
|
|
44
|
+
return value.toDate();
|
|
45
|
+
}
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
const parsed = new Date(value);
|
|
48
|
+
if (!isNaN(parsed.getTime())) return parsed;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
};
|
|
52
|
+
const coerceDateValue = (value, type) => {
|
|
53
|
+
if (value == null) return null;
|
|
54
|
+
if (type === "range" && Array.isArray(value)) {
|
|
55
|
+
return [toNativeDate(value[0]), toNativeDate(value[1])];
|
|
56
|
+
}
|
|
57
|
+
return toNativeDate(value);
|
|
58
|
+
};
|
|
59
|
+
const normalizeToDayjsFormat = (fmt) => fmt.replace(/\byyyy\b/g, "YYYY").replace(/\byy\b/g, "YY").replace(/\bdd\b/g, "DD").replace(/\bd\b/g, "D");
|
|
60
|
+
const normalizeToDateFnsFormat = (fmt) => fmt.replace(/YYYY/g, "yyyy").replace(/YY/g, "yy").replace(/DD/g, "dd").replace(/\bD\b/g, "d");
|
|
61
|
+
const formatDate = (date, formatStr) => {
|
|
62
|
+
if (!date) return "";
|
|
63
|
+
try {
|
|
64
|
+
return utils.dayjs(date).format(normalizeToDayjsFormat(formatStr));
|
|
65
|
+
} catch {
|
|
66
|
+
return "";
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const parseDate = (str, formatStr) => {
|
|
70
|
+
if (!str) return null;
|
|
71
|
+
const dayjsFmt = normalizeToDayjsFormat(formatStr);
|
|
72
|
+
const parsed = dayjsParse(str, dayjsFmt);
|
|
73
|
+
if (parsed.isValid()) return parsed.toDate();
|
|
74
|
+
const fallbackFormats = [
|
|
75
|
+
"DD/MM/YYYY",
|
|
76
|
+
"MM/DD/YYYY",
|
|
77
|
+
"YYYY-MM-DD",
|
|
78
|
+
"DD-MM-YYYY",
|
|
79
|
+
"DD/MM/YYYY HH:mm:ss",
|
|
80
|
+
"DD/MM/YYYY HH:mm"
|
|
81
|
+
];
|
|
82
|
+
for (const fmt of fallbackFormats) {
|
|
83
|
+
if (fmt === dayjsFmt) continue;
|
|
84
|
+
const attempt = dayjsParse(str, fmt);
|
|
85
|
+
if (attempt.isValid()) return attempt.toDate();
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
};
|
|
89
|
+
const applyTimeToDate = (date, time) => {
|
|
90
|
+
const result = new Date(date);
|
|
91
|
+
result.setHours(time.hours, time.minutes, time.seconds ?? 0, 0);
|
|
92
|
+
return result;
|
|
93
|
+
};
|
|
94
|
+
const applyTimezone = (date) => {
|
|
95
|
+
const dateStr = utils.dayjs(date).format("YYYY-MM-DD HH:mm:ss");
|
|
96
|
+
return utils.dayjs(dateStr).toDate();
|
|
97
|
+
};
|
|
98
|
+
const toDayjs = (date) => utils.dayjs(date);
|
|
99
|
+
const getDisplayFormat = (dateFormat, timeFormat, showTime) => {
|
|
100
|
+
const fmt = showTime ? `${dateFormat} ${timeFormat}` : dateFormat;
|
|
101
|
+
return normalizeToDateFnsFormat(fmt);
|
|
102
|
+
};
|
|
103
|
+
const isDatePartComplete = (part, maskEnabled, singleDateLen) => maskEnabled ? part.length >= singleDateLen : part.length > 0;
|
|
104
|
+
const parseRangeText = (text, displayFormat, maskEnabled, singleDateLen) => {
|
|
105
|
+
const parts = text.split(" - ");
|
|
106
|
+
if (parts.length !== 2) return null;
|
|
107
|
+
if (!isDatePartComplete(parts[0], maskEnabled, singleDateLen) || !isDatePartComplete(parts[1], maskEnabled, singleDateLen))
|
|
108
|
+
return null;
|
|
109
|
+
const from = parseDate(parts[0], displayFormat);
|
|
110
|
+
const to = parseDate(parts[1], displayFormat);
|
|
111
|
+
return from && to ? [from, to] : null;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const TIMEZONE_OPTIONS = [
|
|
115
|
+
{ label: "Local", value: "" },
|
|
116
|
+
{ label: "UTC", value: "utc" }
|
|
117
|
+
];
|
|
118
|
+
const TimezoneSelect = ({
|
|
119
|
+
value,
|
|
120
|
+
onChange,
|
|
121
|
+
className
|
|
122
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils$1.cn("flex items-center gap-1.5 text-sm", className), children: [
|
|
123
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-xs", children: "Timezone" }),
|
|
124
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
125
|
+
"select",
|
|
126
|
+
{
|
|
127
|
+
value: value ?? "",
|
|
128
|
+
onChange: (e) => onChange(e.target.value || void 0),
|
|
129
|
+
className: utils$1.cn(
|
|
130
|
+
"rounded-md border border-input bg-background px-2 py-0.5 text-xs",
|
|
131
|
+
"focus:outline-none focus:ring-1 focus:ring-ring"
|
|
132
|
+
),
|
|
133
|
+
"aria-label": "Select timezone",
|
|
134
|
+
children: TIMEZONE_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
] });
|
|
138
|
+
TimezoneSelect.displayName = "TimezoneSelect";
|
|
139
|
+
|
|
140
|
+
const DatePickerFooter = ({
|
|
141
|
+
showTime,
|
|
142
|
+
needConfirm,
|
|
143
|
+
timezone,
|
|
144
|
+
onTimezoneChange,
|
|
145
|
+
onNow,
|
|
146
|
+
onOk,
|
|
147
|
+
className
|
|
148
|
+
}) => {
|
|
149
|
+
const showOkButton = showTime || needConfirm;
|
|
150
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
151
|
+
"div",
|
|
152
|
+
{
|
|
153
|
+
className: utils$1.cn(
|
|
154
|
+
"flex items-center border-t border-border px-3 py-2",
|
|
155
|
+
className
|
|
156
|
+
),
|
|
157
|
+
children: [
|
|
158
|
+
/* @__PURE__ */ jsxRuntime.jsx(primitives_Button.Button, { variant: "ghost", size: "sm", onClick: onNow, className: "text-xs", children: "Now" }),
|
|
159
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
|
|
160
|
+
onTimezoneChange && /* @__PURE__ */ jsxRuntime.jsx(
|
|
161
|
+
TimezoneSelect,
|
|
162
|
+
{
|
|
163
|
+
value: timezone,
|
|
164
|
+
onChange: onTimezoneChange,
|
|
165
|
+
className: "me-2"
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
showOkButton && /* @__PURE__ */ jsxRuntime.jsx(primitives_Button.Button, { size: "sm", onClick: onOk, className: "text-xs", children: "OK" })
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
};
|
|
173
|
+
DatePickerFooter.displayName = "DatePickerFooter";
|
|
174
|
+
|
|
175
|
+
const DatePicker = React.forwardRef(
|
|
176
|
+
({
|
|
177
|
+
value,
|
|
178
|
+
defaultValue,
|
|
179
|
+
onChange,
|
|
180
|
+
type = "date",
|
|
181
|
+
dateFormat = DEFAULT_DATE_FORMAT,
|
|
182
|
+
timeFormat = DEFAULT_TIME_FORMAT,
|
|
183
|
+
showTime = false,
|
|
184
|
+
timePickerFormat = "24",
|
|
185
|
+
showSeconds = false,
|
|
186
|
+
minDate,
|
|
187
|
+
maxDate,
|
|
188
|
+
placeholder,
|
|
189
|
+
label,
|
|
190
|
+
error,
|
|
191
|
+
helpText,
|
|
192
|
+
size = "medium",
|
|
193
|
+
disabled = false,
|
|
194
|
+
allowClear = true,
|
|
195
|
+
required = false,
|
|
196
|
+
timezone,
|
|
197
|
+
onTimezoneChange,
|
|
198
|
+
onOk,
|
|
199
|
+
needConfirm = false,
|
|
200
|
+
onOpenChange,
|
|
201
|
+
className,
|
|
202
|
+
labelProps
|
|
203
|
+
}, ref) => {
|
|
204
|
+
const generatedId = React.useId();
|
|
205
|
+
const errorId = `error_${generatedId}`;
|
|
206
|
+
const helpTextId = `helpText_${generatedId}`;
|
|
207
|
+
const containerRef = React.useRef(null);
|
|
208
|
+
const inputRef = React.useRef(null);
|
|
209
|
+
const cursorPosRef = React.useRef(null);
|
|
210
|
+
const popoverContentId = React.useRef(
|
|
211
|
+
`datepicker-popover-${generatedId}`
|
|
212
|
+
).current;
|
|
213
|
+
const [open, setOpen] = React.useState(false);
|
|
214
|
+
const [internalValue, setInternalValue] = React.useState(coerceDateValue(defaultValue, type) ?? null);
|
|
215
|
+
const currentValue = value !== void 0 ? coerceDateValue(value, type) : internalValue;
|
|
216
|
+
const [calendarMonth, setCalendarMonth] = React.useState(
|
|
217
|
+
(type === "date" ? value ?? defaultValue : null) ?? /* @__PURE__ */ new Date()
|
|
218
|
+
);
|
|
219
|
+
const [rangeSelectionStep, setRangeSelectionStep] = React.useState(
|
|
220
|
+
"from"
|
|
221
|
+
);
|
|
222
|
+
const [pendingDate, setPendingDate] = React.useState(null);
|
|
223
|
+
const [pendingTime, setPendingTime] = React.useState({
|
|
224
|
+
hours: 0,
|
|
225
|
+
minutes: 0,
|
|
226
|
+
seconds: 0
|
|
227
|
+
});
|
|
228
|
+
const displayFormat = getDisplayFormat(dateFormat, timeFormat, showTime);
|
|
229
|
+
const sizeConfig = SIZE_CONFIG[size];
|
|
230
|
+
const maskEnabled = TimePickerPanel.isFixedWidthFormat(displayFormat);
|
|
231
|
+
const maskTemplate = React.useMemo(
|
|
232
|
+
() => maskEnabled ? type === "range" ? TimePickerPanel.buildRangeMaskTemplate(displayFormat) : TimePickerPanel.buildMaskTemplate(displayFormat) : null,
|
|
233
|
+
[displayFormat, type, maskEnabled]
|
|
234
|
+
);
|
|
235
|
+
const singlePlaceholder = showTime ? `${dateFormat.toUpperCase()} ${timeFormat}` : dateFormat.toUpperCase();
|
|
236
|
+
const defaultPlaceholder = type === "range" ? `${singlePlaceholder} - ${singlePlaceholder}` : singlePlaceholder;
|
|
237
|
+
const getDisplayText = React.useCallback(() => {
|
|
238
|
+
if (type === "range") {
|
|
239
|
+
const rangeValue = currentValue;
|
|
240
|
+
if (!rangeValue || !rangeValue[0] && !rangeValue[1]) return "";
|
|
241
|
+
const from = rangeValue[0] ? formatDate(rangeValue[0], displayFormat) : "";
|
|
242
|
+
const to = rangeValue[1] ? formatDate(rangeValue[1], displayFormat) : "";
|
|
243
|
+
return `${from} - ${to}`;
|
|
244
|
+
}
|
|
245
|
+
return formatDate(currentValue, displayFormat);
|
|
246
|
+
}, [currentValue, displayFormat, type]);
|
|
247
|
+
const [inputText, setInputText] = React.useState(() => getDisplayText());
|
|
248
|
+
React.useEffect(() => {
|
|
249
|
+
if (!open) setInputText(getDisplayText());
|
|
250
|
+
}, [getDisplayText, open]);
|
|
251
|
+
const closePopover = React.useCallback(() => {
|
|
252
|
+
setOpen(false);
|
|
253
|
+
onOpenChange?.(false);
|
|
254
|
+
setInputText(getDisplayText());
|
|
255
|
+
}, [onOpenChange, getDisplayText]);
|
|
256
|
+
const openPopover = React.useCallback(() => {
|
|
257
|
+
setOpen(true);
|
|
258
|
+
onOpenChange?.(true);
|
|
259
|
+
setRangeSelectionStep("from");
|
|
260
|
+
const dateVal = type === "date" ? currentValue : null;
|
|
261
|
+
if (dateVal) {
|
|
262
|
+
setCalendarMonth(dateVal);
|
|
263
|
+
setPendingDate(dateVal);
|
|
264
|
+
setPendingTime(TimePickerPanel.dateToTimeValue(dateVal));
|
|
265
|
+
} else {
|
|
266
|
+
setPendingDate(null);
|
|
267
|
+
setPendingTime({ hours: 0, minutes: 0, seconds: 0 });
|
|
268
|
+
}
|
|
269
|
+
}, [type, currentValue, onOpenChange]);
|
|
270
|
+
React.useEffect(() => {
|
|
271
|
+
if (!open) return;
|
|
272
|
+
const handlePointerDown = (e) => {
|
|
273
|
+
const target = e.target;
|
|
274
|
+
if (containerRef.current?.contains(target)) return;
|
|
275
|
+
const popoverEl = document.getElementById(popoverContentId);
|
|
276
|
+
if (popoverEl?.contains(target)) return;
|
|
277
|
+
closePopover();
|
|
278
|
+
};
|
|
279
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
280
|
+
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
281
|
+
}, [open, closePopover]);
|
|
282
|
+
const commitValue = (date) => {
|
|
283
|
+
if (date === null) {
|
|
284
|
+
setInternalValue(null);
|
|
285
|
+
onChange?.(null, "");
|
|
286
|
+
setInputText("");
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (Array.isArray(date)) {
|
|
290
|
+
const converted2 = [
|
|
291
|
+
applyTimezone(date[0]),
|
|
292
|
+
applyTimezone(date[1])
|
|
293
|
+
];
|
|
294
|
+
setInternalValue(converted2);
|
|
295
|
+
const formatted2 = [
|
|
296
|
+
formatDate(converted2[0], displayFormat),
|
|
297
|
+
formatDate(converted2[1], displayFormat)
|
|
298
|
+
];
|
|
299
|
+
onChange?.([toDayjs(converted2[0]), toDayjs(converted2[1])], formatted2);
|
|
300
|
+
setInputText(`${formatted2[0]} - ${formatted2[1]}`);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const converted = applyTimezone(date);
|
|
304
|
+
setInternalValue(converted);
|
|
305
|
+
const formatted = formatDate(converted, displayFormat);
|
|
306
|
+
onChange?.(toDayjs(converted), formatted);
|
|
307
|
+
setInputText(formatted);
|
|
308
|
+
};
|
|
309
|
+
const handleDateSelect = (selected) => {
|
|
310
|
+
if (!selected) return;
|
|
311
|
+
setCalendarMonth(selected);
|
|
312
|
+
if (showTime || needConfirm) {
|
|
313
|
+
setPendingDate(selected);
|
|
314
|
+
} else {
|
|
315
|
+
commitValue(selected);
|
|
316
|
+
setOpen(false);
|
|
317
|
+
onOpenChange?.(false);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const handleRangeSelect = (range) => {
|
|
321
|
+
if (!range) return;
|
|
322
|
+
const from = range.from ?? null;
|
|
323
|
+
const to = range.to ?? null;
|
|
324
|
+
if (rangeSelectionStep === "from") {
|
|
325
|
+
setInternalValue([from, null]);
|
|
326
|
+
setRangeSelectionStep("to");
|
|
327
|
+
} else {
|
|
328
|
+
if (from && to) {
|
|
329
|
+
if (showTime || needConfirm) {
|
|
330
|
+
setPendingDate(from);
|
|
331
|
+
} else {
|
|
332
|
+
commitValue([from, to]);
|
|
333
|
+
setOpen(false);
|
|
334
|
+
onOpenChange?.(false);
|
|
335
|
+
}
|
|
336
|
+
} else if (from) {
|
|
337
|
+
setInternalValue([from, null]);
|
|
338
|
+
}
|
|
339
|
+
setRangeSelectionStep("from");
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
const handleTimeChange = (time) => {
|
|
343
|
+
setPendingTime(time);
|
|
344
|
+
};
|
|
345
|
+
const handleNow = () => {
|
|
346
|
+
const now = /* @__PURE__ */ new Date();
|
|
347
|
+
if (showTime || needConfirm) {
|
|
348
|
+
setPendingDate(now);
|
|
349
|
+
setPendingTime(TimePickerPanel.dateToTimeValue(now));
|
|
350
|
+
} else {
|
|
351
|
+
commitValue(now);
|
|
352
|
+
setOpen(false);
|
|
353
|
+
onOpenChange?.(false);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
const handleOk = () => {
|
|
357
|
+
if (pendingDate) {
|
|
358
|
+
const finalDate = showTime ? applyTimeToDate(pendingDate, pendingTime) : pendingDate;
|
|
359
|
+
commitValue(finalDate);
|
|
360
|
+
onOk?.(finalDate);
|
|
361
|
+
}
|
|
362
|
+
setOpen(false);
|
|
363
|
+
onOpenChange?.(false);
|
|
364
|
+
};
|
|
365
|
+
const handleClear = (e) => {
|
|
366
|
+
e.stopPropagation();
|
|
367
|
+
e.preventDefault();
|
|
368
|
+
commitValue(null);
|
|
369
|
+
};
|
|
370
|
+
React.useLayoutEffect(() => {
|
|
371
|
+
if (cursorPosRef.current !== null && inputRef.current && document.activeElement === inputRef.current) {
|
|
372
|
+
inputRef.current.setSelectionRange(
|
|
373
|
+
cursorPosRef.current,
|
|
374
|
+
cursorPosRef.current
|
|
375
|
+
);
|
|
376
|
+
cursorPosRef.current = null;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
const singleDateLen = React.useMemo(
|
|
380
|
+
() => TimePickerPanel.buildMaskTemplate(displayFormat).pattern.length,
|
|
381
|
+
[displayFormat]
|
|
382
|
+
);
|
|
383
|
+
const parseAndApplyRange = (text) => {
|
|
384
|
+
const parts = text.split(" - ");
|
|
385
|
+
if (!isDatePartComplete(parts[0] ?? "", maskEnabled, singleDateLen))
|
|
386
|
+
return;
|
|
387
|
+
const from = parseDate(parts[0], displayFormat);
|
|
388
|
+
if (from) setCalendarMonth(from);
|
|
389
|
+
const range = parseRangeText(
|
|
390
|
+
text,
|
|
391
|
+
displayFormat,
|
|
392
|
+
maskEnabled,
|
|
393
|
+
singleDateLen
|
|
394
|
+
);
|
|
395
|
+
if (range) commitValue(range);
|
|
396
|
+
};
|
|
397
|
+
const handleInputChange = (e) => {
|
|
398
|
+
let text = e.target.value;
|
|
399
|
+
if (maskTemplate) {
|
|
400
|
+
const masked = TimePickerPanel.applyMask(
|
|
401
|
+
text,
|
|
402
|
+
maskTemplate,
|
|
403
|
+
inputText,
|
|
404
|
+
e.target.selectionStart
|
|
405
|
+
);
|
|
406
|
+
text = masked.text;
|
|
407
|
+
cursorPosRef.current = masked.cursorPosition;
|
|
408
|
+
}
|
|
409
|
+
setInputText(text);
|
|
410
|
+
if (type === "range") {
|
|
411
|
+
parseAndApplyRange(text);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const isComplete = maskTemplate ? text.length >= maskTemplate.pattern.length : true;
|
|
415
|
+
if (!isComplete) return;
|
|
416
|
+
const parsed = parseDate(text, displayFormat);
|
|
417
|
+
if (!parsed) return;
|
|
418
|
+
setCalendarMonth(parsed);
|
|
419
|
+
if (showTime || needConfirm) {
|
|
420
|
+
setPendingDate(parsed);
|
|
421
|
+
setPendingTime(TimePickerPanel.dateToTimeValue(parsed));
|
|
422
|
+
} else {
|
|
423
|
+
commitValue(parsed);
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
const handleInputKeyDown = (e) => {
|
|
427
|
+
if (e.key === "Escape") return closePopover();
|
|
428
|
+
if (e.key !== "Enter") return;
|
|
429
|
+
if (type === "range") {
|
|
430
|
+
const range = parseRangeText(
|
|
431
|
+
inputText,
|
|
432
|
+
displayFormat,
|
|
433
|
+
maskEnabled,
|
|
434
|
+
singleDateLen
|
|
435
|
+
);
|
|
436
|
+
if (range) commitValue(range);
|
|
437
|
+
} else {
|
|
438
|
+
const parsed = parseDate(inputText, displayFormat);
|
|
439
|
+
if (parsed) commitValue(parsed);
|
|
440
|
+
}
|
|
441
|
+
setOpen(false);
|
|
442
|
+
onOpenChange?.(false);
|
|
443
|
+
};
|
|
444
|
+
const handleInputFocus = () => {
|
|
445
|
+
if (!open) openPopover();
|
|
446
|
+
};
|
|
447
|
+
const hasField = !!(label || error || helpText);
|
|
448
|
+
const showFooter = showTime || needConfirm || !!onTimezoneChange;
|
|
449
|
+
const todayDayjs = utils.dayjs(/* @__PURE__ */ new Date());
|
|
450
|
+
const todayDate = new Date(
|
|
451
|
+
todayDayjs.year(),
|
|
452
|
+
todayDayjs.month(),
|
|
453
|
+
todayDayjs.date()
|
|
454
|
+
);
|
|
455
|
+
const ariaDescribedBy = [error ? errorId : null, helpText ? helpTextId : null].filter(Boolean).join(" ") || void 0;
|
|
456
|
+
const calendarDisabled = React.useCallback(
|
|
457
|
+
(date) => {
|
|
458
|
+
if (minDate && date < new Date(minDate.setHours(0, 0, 0, 0)))
|
|
459
|
+
return true;
|
|
460
|
+
if (maxDate && date > new Date(maxDate.setHours(23, 59, 59, 999)))
|
|
461
|
+
return true;
|
|
462
|
+
return false;
|
|
463
|
+
},
|
|
464
|
+
[minDate, maxDate]
|
|
465
|
+
);
|
|
466
|
+
const calendarSelected = React.useCallback(() => {
|
|
467
|
+
if (showTime || needConfirm) return pendingDate ?? void 0;
|
|
468
|
+
return currentValue ?? void 0;
|
|
469
|
+
}, [showTime, needConfirm, pendingDate, currentValue]);
|
|
470
|
+
const triggerContent = /* @__PURE__ */ jsxRuntime.jsxs(primitives_Popover.Popover, { open, children: [
|
|
471
|
+
/* @__PURE__ */ jsxRuntime.jsx(primitives_Popover.PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
472
|
+
"div",
|
|
473
|
+
{
|
|
474
|
+
ref: containerRef,
|
|
475
|
+
className: utils$1.cn(
|
|
476
|
+
"relative flex w-full items-center gap-2 rounded-md border border-input bg-background pe-8 ps-3",
|
|
477
|
+
"focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
|
|
478
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
479
|
+
!!error && "border-destructive ring-destructive/20 ring-3",
|
|
480
|
+
sizeConfig.trigger,
|
|
481
|
+
!hasField && className
|
|
482
|
+
),
|
|
483
|
+
children: [
|
|
484
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
485
|
+
Calendar,
|
|
486
|
+
{
|
|
487
|
+
className: utils$1.cn("shrink-0 text-muted-foreground", sizeConfig.icon)
|
|
488
|
+
}
|
|
489
|
+
),
|
|
490
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
491
|
+
"input",
|
|
492
|
+
{
|
|
493
|
+
ref: inputRef,
|
|
494
|
+
type: "text",
|
|
495
|
+
disabled,
|
|
496
|
+
"aria-label": label || "Pick a date",
|
|
497
|
+
"aria-describedby": ariaDescribedBy,
|
|
498
|
+
"aria-invalid": !!error || void 0,
|
|
499
|
+
placeholder: placeholder ?? defaultPlaceholder,
|
|
500
|
+
value: inputText,
|
|
501
|
+
onChange: handleInputChange,
|
|
502
|
+
onKeyDown: handleInputKeyDown,
|
|
503
|
+
onFocus: handleInputFocus,
|
|
504
|
+
className: utils$1.cn(
|
|
505
|
+
"min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground",
|
|
506
|
+
"disabled:cursor-not-allowed",
|
|
507
|
+
sizeConfig.trigger.split(" ").find((c) => c.startsWith("text-"))
|
|
508
|
+
)
|
|
509
|
+
}
|
|
510
|
+
),
|
|
511
|
+
timezone && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground", children: timezone.toUpperCase() }),
|
|
512
|
+
allowClear && /* @__PURE__ */ jsxRuntime.jsx(
|
|
513
|
+
"button",
|
|
514
|
+
{
|
|
515
|
+
type: "button",
|
|
516
|
+
onPointerDown: (e) => e.preventDefault(),
|
|
517
|
+
onClick: handleClear,
|
|
518
|
+
className: utils$1.cn(
|
|
519
|
+
"absolute inset-y-0 end-2 flex items-center text-muted-foreground hover:text-foreground focus:outline-none",
|
|
520
|
+
!(inputText && !disabled) && "invisible"
|
|
521
|
+
),
|
|
522
|
+
"aria-label": "Clear date",
|
|
523
|
+
tabIndex: -1,
|
|
524
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(x.X, { className: sizeConfig.icon })
|
|
525
|
+
}
|
|
526
|
+
)
|
|
527
|
+
]
|
|
528
|
+
}
|
|
529
|
+
) }),
|
|
530
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
531
|
+
primitives_Popover.PopoverContent,
|
|
532
|
+
{
|
|
533
|
+
id: popoverContentId,
|
|
534
|
+
className: "w-auto p-0",
|
|
535
|
+
align: "start",
|
|
536
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
537
|
+
onCloseAutoFocus: (e) => e.preventDefault(),
|
|
538
|
+
onPointerDownOutside: (e) => e.preventDefault(),
|
|
539
|
+
onInteractOutside: (e) => e.preventDefault(),
|
|
540
|
+
children: [
|
|
541
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils$1.cn("flex", showTime && "flex-row"), children: [
|
|
542
|
+
type === "date" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
543
|
+
primitives_Calendar.Calendar,
|
|
544
|
+
{
|
|
545
|
+
mode: "single",
|
|
546
|
+
captionLayout: "dropdown",
|
|
547
|
+
today: todayDate,
|
|
548
|
+
month: calendarMonth,
|
|
549
|
+
onMonthChange: setCalendarMonth,
|
|
550
|
+
selected: calendarSelected(),
|
|
551
|
+
onSelect: handleDateSelect,
|
|
552
|
+
disabled: calendarDisabled,
|
|
553
|
+
...minDate && { fromDate: minDate },
|
|
554
|
+
...maxDate && { toDate: maxDate }
|
|
555
|
+
}
|
|
556
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
557
|
+
primitives_Calendar.Calendar,
|
|
558
|
+
{
|
|
559
|
+
mode: "range",
|
|
560
|
+
numberOfMonths: 2,
|
|
561
|
+
captionLayout: "dropdown",
|
|
562
|
+
today: todayDate,
|
|
563
|
+
className: "[&_[data-outside][data-selected=true]]:!bg-transparent [&_[data-outside][data-selected=true]]:after:!bg-transparent [&_[data-outside]_button]:!bg-transparent [&_[data-outside]_button]:!text-muted-foreground",
|
|
564
|
+
month: calendarMonth,
|
|
565
|
+
onMonthChange: setCalendarMonth,
|
|
566
|
+
selected: currentValue ? {
|
|
567
|
+
from: currentValue[0] ?? void 0,
|
|
568
|
+
to: currentValue[1] ?? void 0
|
|
569
|
+
} : void 0,
|
|
570
|
+
onSelect: handleRangeSelect,
|
|
571
|
+
disabled: calendarDisabled,
|
|
572
|
+
...minDate && { fromDate: minDate },
|
|
573
|
+
...maxDate && { toDate: maxDate }
|
|
574
|
+
}
|
|
575
|
+
),
|
|
576
|
+
showTime && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-inline-start border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
577
|
+
TimePickerPanel.TimePickerPanel,
|
|
578
|
+
{
|
|
579
|
+
value: pendingTime,
|
|
580
|
+
onChange: handleTimeChange,
|
|
581
|
+
format: timePickerFormat,
|
|
582
|
+
showSeconds,
|
|
583
|
+
disabled
|
|
584
|
+
}
|
|
585
|
+
) })
|
|
586
|
+
] }),
|
|
587
|
+
showFooter && /* @__PURE__ */ jsxRuntime.jsx(
|
|
588
|
+
DatePickerFooter,
|
|
589
|
+
{
|
|
590
|
+
showTime,
|
|
591
|
+
needConfirm,
|
|
592
|
+
timezone,
|
|
593
|
+
onTimezoneChange,
|
|
594
|
+
onNow: handleNow,
|
|
595
|
+
onOk: handleOk
|
|
596
|
+
}
|
|
597
|
+
)
|
|
598
|
+
]
|
|
599
|
+
}
|
|
600
|
+
)
|
|
601
|
+
] });
|
|
602
|
+
if (!hasField) {
|
|
603
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className, children: triggerContent });
|
|
604
|
+
}
|
|
605
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
606
|
+
primitives_Field.Field,
|
|
607
|
+
{
|
|
608
|
+
ref,
|
|
609
|
+
"data-disabled": disabled || void 0,
|
|
610
|
+
"data-invalid": !!error || void 0,
|
|
611
|
+
className,
|
|
612
|
+
children: [
|
|
613
|
+
label && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
614
|
+
primitives_Field.FieldLabel,
|
|
615
|
+
{
|
|
616
|
+
...labelProps,
|
|
617
|
+
children: [
|
|
618
|
+
label,
|
|
619
|
+
required && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "text-destructive", children: "*" })
|
|
620
|
+
]
|
|
621
|
+
}
|
|
622
|
+
),
|
|
623
|
+
/* @__PURE__ */ jsxRuntime.jsxs(primitives_Field.FieldContent, { children: [
|
|
624
|
+
triggerContent,
|
|
625
|
+
!!error && /* @__PURE__ */ jsxRuntime.jsx(primitives_Field.FieldError, { id: errorId, children: error }),
|
|
626
|
+
helpText && /* @__PURE__ */ jsxRuntime.jsx(primitives_Field.FieldDescription, { id: helpTextId, children: helpText })
|
|
627
|
+
] })
|
|
628
|
+
]
|
|
629
|
+
}
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
);
|
|
633
|
+
DatePicker.displayName = "DatePicker";
|
|
634
|
+
|
|
635
|
+
exports.DatePicker = DatePicker;
|
|
636
|
+
//# sourceMappingURL=DatePicker-DaVdS--q.js.map
|