@artemy-tech/datepicker 0.0.3 → 0.2.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/README.md +1 -1
- package/dist/index.cjs +409 -142
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +394 -127
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ function Calendar({ className, ...props }) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// src/components/DatePicker/DatePicker.tsx
|
|
15
|
-
import { useCallback, useRef, useState } from "react";
|
|
15
|
+
import { useCallback, useRef as useRef2, useState } from "react";
|
|
16
16
|
import { format, isValid, parse } from "date-fns";
|
|
17
17
|
import { ru } from "date-fns/locale";
|
|
18
18
|
|
|
@@ -29,14 +29,83 @@ function useClickOutside(ref, handler) {
|
|
|
29
29
|
}, [ref, handler]);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
// src/components/
|
|
32
|
+
// src/components/TimePanel/TimePanel.tsx
|
|
33
|
+
import { useEffect as useEffect2, useRef } from "react";
|
|
33
34
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
35
|
+
var HOURS = Array.from({ length: 24 }, (_, i) => i);
|
|
36
|
+
var MINUTES = Array.from({ length: 60 }, (_, i) => i);
|
|
37
|
+
var SECONDS = Array.from({ length: 60 }, (_, i) => i);
|
|
38
|
+
function pad2(n) {
|
|
39
|
+
return String(n).padStart(2, "0");
|
|
40
|
+
}
|
|
41
|
+
function Column({ values, selected, onSelect }) {
|
|
42
|
+
const selectedRef = useRef(null);
|
|
43
|
+
useEffect2(() => {
|
|
44
|
+
var _a;
|
|
45
|
+
(_a = selectedRef.current) == null ? void 0 : _a.scrollIntoView({ block: "center", behavior: "instant" });
|
|
46
|
+
}, [selected]);
|
|
47
|
+
return /* @__PURE__ */ jsx2("div", { className: "time-panel__column", children: values.map((v) => /* @__PURE__ */ jsx2(
|
|
48
|
+
"button",
|
|
49
|
+
{
|
|
50
|
+
ref: v === selected ? selectedRef : void 0,
|
|
51
|
+
className: "time-panel__item",
|
|
52
|
+
"data-selected": v === selected || void 0,
|
|
53
|
+
onClick: () => onSelect(v),
|
|
54
|
+
type: "button",
|
|
55
|
+
tabIndex: -1,
|
|
56
|
+
children: pad2(v)
|
|
57
|
+
},
|
|
58
|
+
v
|
|
59
|
+
)) });
|
|
60
|
+
}
|
|
61
|
+
function TimePanel({ value, showSeconds, onChange }) {
|
|
62
|
+
var _a, _b, _c;
|
|
63
|
+
const h = (_a = value == null ? void 0 : value.getHours()) != null ? _a : 0;
|
|
64
|
+
const m = (_b = value == null ? void 0 : value.getMinutes()) != null ? _b : 0;
|
|
65
|
+
const s = (_c = value == null ? void 0 : value.getSeconds()) != null ? _c : 0;
|
|
66
|
+
return /* @__PURE__ */ jsxs("div", { className: "time-panel", children: [
|
|
67
|
+
/* @__PURE__ */ jsx2(Column, { values: HOURS, selected: h, onSelect: (v) => onChange(v, m, s) }),
|
|
68
|
+
/* @__PURE__ */ jsx2(Column, { values: MINUTES, selected: m, onSelect: (v) => onChange(h, v, s) }),
|
|
69
|
+
showSeconds && /* @__PURE__ */ jsx2(Column, { values: SECONDS, selected: s, onSelect: (v) => onChange(h, m, v) })
|
|
70
|
+
] });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/components/icons/CalendarIcon.tsx
|
|
74
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
75
|
+
function CalendarIcon() {
|
|
76
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
77
|
+
/* @__PURE__ */ jsx3("rect", { x: "1", y: "2.5", width: "14", height: "12", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
78
|
+
/* @__PURE__ */ jsx3("path", { d: "M1 6.5H15", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
79
|
+
/* @__PURE__ */ jsx3("path", { d: "M5 1V4M11 1V4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
80
|
+
] });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/components/DatePicker/DatePicker.tsx
|
|
84
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
34
85
|
var DATE_FORMAT = "dd.MM.yyyy";
|
|
35
|
-
function
|
|
36
|
-
|
|
86
|
+
function resolveTimeFormat(showTime) {
|
|
87
|
+
if (!showTime) return null;
|
|
88
|
+
if (showTime === true) return "HH:mm:ss";
|
|
89
|
+
return showTime.format;
|
|
90
|
+
}
|
|
91
|
+
function buildDateFormat(timeFormat) {
|
|
92
|
+
return timeFormat ? `${DATE_FORMAT} ${timeFormat}` : DATE_FORMAT;
|
|
93
|
+
}
|
|
94
|
+
function buildMaxDigits(timeFormat) {
|
|
95
|
+
if (!timeFormat) return 8;
|
|
96
|
+
return timeFormat === "HH:mm" ? 12 : 14;
|
|
97
|
+
}
|
|
98
|
+
function buildPlaceholder(timeFormat) {
|
|
99
|
+
if (!timeFormat) return "\u0434\u0434.\u043C\u043C.\u0433\u0433\u0433\u0433";
|
|
100
|
+
return timeFormat === "HH:mm" ? "\u0434\u0434.\u043C\u043C.\u0433\u0433\u0433\u0433 \u0447\u0447:\u043C\u043C" : "\u0434\u0434.\u043C\u043C.\u0433\u0433\u0433\u0433 \u0447\u0447:\u043C\u043C:\u0441\u0441";
|
|
101
|
+
}
|
|
102
|
+
function applyMask(digits, maxDigits) {
|
|
103
|
+
const d = digits.slice(0, maxDigits);
|
|
37
104
|
let result = "";
|
|
38
105
|
for (let i = 0; i < d.length; i++) {
|
|
39
106
|
if (i === 2 || i === 4) result += ".";
|
|
107
|
+
else if (i === 8) result += " ";
|
|
108
|
+
else if (i === 10 || i === 12) result += ":";
|
|
40
109
|
result += d[i];
|
|
41
110
|
}
|
|
42
111
|
return result;
|
|
@@ -52,45 +121,66 @@ function getCursorPos(masked, digitCount) {
|
|
|
52
121
|
}
|
|
53
122
|
return masked.length;
|
|
54
123
|
}
|
|
55
|
-
function
|
|
56
|
-
if (masked.replace(/\D/g, "").length !==
|
|
57
|
-
const date = parse(masked,
|
|
58
|
-
return isValid(date) && format(date,
|
|
124
|
+
function parseDateTime(masked, dateFormat, maxDigits) {
|
|
125
|
+
if (masked.replace(/\D/g, "").length !== maxDigits) return void 0;
|
|
126
|
+
const date = parse(masked, dateFormat, /* @__PURE__ */ new Date());
|
|
127
|
+
return isValid(date) && format(date, dateFormat) === masked ? date : void 0;
|
|
59
128
|
}
|
|
60
129
|
function DatePicker({
|
|
61
130
|
value,
|
|
62
131
|
defaultValue,
|
|
63
132
|
onChange,
|
|
64
133
|
label,
|
|
65
|
-
placeholder
|
|
134
|
+
placeholder,
|
|
66
135
|
fromDate,
|
|
67
136
|
toDate,
|
|
68
137
|
disabled = false,
|
|
69
138
|
failed = false,
|
|
139
|
+
size = "m",
|
|
140
|
+
noCalendar = false,
|
|
141
|
+
showTime,
|
|
142
|
+
icon,
|
|
143
|
+
iconPosition = "end",
|
|
70
144
|
className
|
|
71
145
|
}) {
|
|
146
|
+
const timeFormat = resolveTimeFormat(showTime);
|
|
147
|
+
const dateFormat = buildDateFormat(timeFormat);
|
|
148
|
+
const maxDigits = buildMaxDigits(timeFormat);
|
|
149
|
+
const defaultPlaceholder = placeholder != null ? placeholder : buildPlaceholder(timeFormat);
|
|
150
|
+
const showSeconds = timeFormat === "HH:mm:ss";
|
|
151
|
+
const resolvedIcon = icon === false ? null : icon != null ? icon : /* @__PURE__ */ jsx4(CalendarIcon, {});
|
|
72
152
|
const isControlled = value !== void 0;
|
|
73
153
|
const [internalDate, setInternalDate] = useState(defaultValue);
|
|
74
154
|
const [open, setOpen] = useState(false);
|
|
75
155
|
const [focused, setFocused] = useState(false);
|
|
76
156
|
const [inputValue, setInputValue] = useState(
|
|
77
|
-
() => defaultValue && isValid(defaultValue) ? format(defaultValue,
|
|
157
|
+
() => defaultValue && isValid(defaultValue) ? format(defaultValue, dateFormat) : ""
|
|
78
158
|
);
|
|
79
159
|
const [inputInvalid, setInputInvalid] = useState(false);
|
|
80
|
-
const inputRef =
|
|
81
|
-
const containerRef =
|
|
160
|
+
const inputRef = useRef2(null);
|
|
161
|
+
const containerRef = useRef2(null);
|
|
162
|
+
const lastValidRef = useRef2(inputValue);
|
|
82
163
|
const selected = isControlled ? value : internalDate;
|
|
83
164
|
const filled = inputValue.length > 0;
|
|
84
165
|
const close = useCallback(() => setOpen(false), []);
|
|
85
166
|
useClickOutside(containerRef, close);
|
|
167
|
+
function applyValid(masked, date) {
|
|
168
|
+
lastValidRef.current = masked;
|
|
169
|
+
setInputValue(masked);
|
|
170
|
+
setInputInvalid(false);
|
|
171
|
+
if (!isControlled) setInternalDate(date);
|
|
172
|
+
onChange == null ? void 0 : onChange(date);
|
|
173
|
+
}
|
|
86
174
|
function commit(masked) {
|
|
87
175
|
const digits = masked.replace(/\D/g, "");
|
|
88
176
|
if (digits.length === 0) {
|
|
177
|
+
lastValidRef.current = "";
|
|
89
178
|
setInputInvalid(false);
|
|
90
179
|
if (!isControlled) setInternalDate(void 0);
|
|
91
180
|
onChange == null ? void 0 : onChange(void 0);
|
|
92
|
-
} else if (digits.length ===
|
|
93
|
-
const date =
|
|
181
|
+
} else if (digits.length === maxDigits) {
|
|
182
|
+
const date = parseDateTime(masked, dateFormat, maxDigits);
|
|
183
|
+
if (date) lastValidRef.current = masked;
|
|
94
184
|
setInputInvalid(!date);
|
|
95
185
|
if (!isControlled) setInternalDate(date);
|
|
96
186
|
onChange == null ? void 0 : onChange(date);
|
|
@@ -98,13 +188,21 @@ function DatePicker({
|
|
|
98
188
|
setInputInvalid(false);
|
|
99
189
|
}
|
|
100
190
|
}
|
|
191
|
+
function handleBlur() {
|
|
192
|
+
setFocused(false);
|
|
193
|
+
const digits = inputValue.replace(/\D/g, "");
|
|
194
|
+
if (digits.length > 0 && digits.length < maxDigits || inputInvalid) {
|
|
195
|
+
setInputValue(lastValidRef.current);
|
|
196
|
+
setInputInvalid(false);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
101
199
|
function handleChange(e) {
|
|
102
200
|
var _a;
|
|
103
201
|
const input = e.target;
|
|
104
202
|
const cursorPos = (_a = input.selectionStart) != null ? _a : 0;
|
|
105
203
|
const raw = input.value;
|
|
106
|
-
const digits = raw.replace(/\D/g, "").slice(0,
|
|
107
|
-
const masked = applyMask(digits);
|
|
204
|
+
const digits = raw.replace(/\D/g, "").slice(0, maxDigits);
|
|
205
|
+
const masked = applyMask(digits, maxDigits);
|
|
108
206
|
const digitsBeforeCursor = raw.slice(0, cursorPos).replace(/\D/g, "").length;
|
|
109
207
|
const newCursorPos = getCursorPos(masked, digitsBeforeCursor);
|
|
110
208
|
setInputValue(masked);
|
|
@@ -122,10 +220,10 @@ function DatePicker({
|
|
|
122
220
|
e.preventDefault();
|
|
123
221
|
return;
|
|
124
222
|
}
|
|
125
|
-
if (e.key === "Backspace" && pos > 0 && input.value[pos - 1]
|
|
223
|
+
if (e.key === "Backspace" && pos > 0 && /[.: ]/.test(input.value[pos - 1])) {
|
|
126
224
|
e.preventDefault();
|
|
127
225
|
const val = input.value;
|
|
128
|
-
const masked = applyMask((val.slice(0, pos - 2) + val.slice(pos)).replace(/\D/g, ""));
|
|
226
|
+
const masked = applyMask((val.slice(0, pos - 2) + val.slice(pos)).replace(/\D/g, ""), maxDigits);
|
|
129
227
|
setInputValue(masked);
|
|
130
228
|
commit(masked);
|
|
131
229
|
requestAnimationFrame(() => input.setSelectionRange(pos - 2, pos - 2));
|
|
@@ -133,7 +231,7 @@ function DatePicker({
|
|
|
133
231
|
}
|
|
134
232
|
function handlePaste(e) {
|
|
135
233
|
e.preventDefault();
|
|
136
|
-
const masked = applyMask(e.clipboardData.getData("text").replace(/\D/g, ""));
|
|
234
|
+
const masked = applyMask(e.clipboardData.getData("text").replace(/\D/g, ""), maxDigits);
|
|
137
235
|
setInputValue(masked);
|
|
138
236
|
commit(masked);
|
|
139
237
|
requestAnimationFrame(() => {
|
|
@@ -141,74 +239,148 @@ function DatePicker({
|
|
|
141
239
|
return (_a = inputRef.current) == null ? void 0 : _a.setSelectionRange(masked.length, masked.length);
|
|
142
240
|
});
|
|
143
241
|
}
|
|
144
|
-
function
|
|
145
|
-
if (!
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
242
|
+
function handleCalendarSelect(date) {
|
|
243
|
+
if (!date || !isValid(date)) {
|
|
244
|
+
applyValid("", void 0);
|
|
245
|
+
if (!timeFormat) setOpen(false);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
let dateToCommit = date;
|
|
249
|
+
if (timeFormat) {
|
|
250
|
+
const base = selected && isValid(selected) ? selected : /* @__PURE__ */ new Date(0);
|
|
251
|
+
dateToCommit = new Date(
|
|
252
|
+
date.getFullYear(),
|
|
253
|
+
date.getMonth(),
|
|
254
|
+
date.getDate(),
|
|
255
|
+
base.getHours(),
|
|
256
|
+
base.getMinutes(),
|
|
257
|
+
base.getSeconds()
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
applyValid(format(dateToCommit, dateFormat), dateToCommit);
|
|
261
|
+
if (!timeFormat) setOpen(false);
|
|
262
|
+
}
|
|
263
|
+
function handleTimeChange(h, m, s) {
|
|
264
|
+
const base = selected && isValid(selected) ? selected : /* @__PURE__ */ new Date();
|
|
265
|
+
const newDate = new Date(base.getFullYear(), base.getMonth(), base.getDate(), h, m, s);
|
|
266
|
+
applyValid(format(newDate, dateFormat), newDate);
|
|
150
267
|
}
|
|
151
|
-
return /* @__PURE__ */
|
|
268
|
+
return /* @__PURE__ */ jsxs3(
|
|
152
269
|
"div",
|
|
153
270
|
{
|
|
154
271
|
ref: containerRef,
|
|
155
|
-
className: ["datepicker", className].filter(Boolean).join(" "),
|
|
272
|
+
className: ["datepicker", `datepicker--${size}`, className].filter(Boolean).join(" "),
|
|
156
273
|
"data-focused": focused || open || void 0,
|
|
157
274
|
"data-filled": filled || void 0,
|
|
158
275
|
"data-failed": failed || inputInvalid || void 0,
|
|
159
276
|
"data-disabled": disabled || void 0,
|
|
160
277
|
children: [
|
|
161
|
-
/* @__PURE__ */
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
className: "
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
278
|
+
/* @__PURE__ */ jsxs3(
|
|
279
|
+
"div",
|
|
280
|
+
{
|
|
281
|
+
className: "datepicker__field",
|
|
282
|
+
"data-icon-start": resolvedIcon && iconPosition === "start" ? true : void 0,
|
|
283
|
+
"data-icon-end": resolvedIcon && iconPosition === "end" ? true : void 0,
|
|
284
|
+
onClick: () => {
|
|
285
|
+
var _a;
|
|
286
|
+
return !disabled && ((_a = inputRef.current) == null ? void 0 : _a.focus());
|
|
287
|
+
},
|
|
288
|
+
children: [
|
|
289
|
+
resolvedIcon && iconPosition === "start" && /* @__PURE__ */ jsx4("span", { className: "datepicker__icon datepicker__icon--start", children: resolvedIcon }),
|
|
290
|
+
label && /* @__PURE__ */ jsx4("span", { className: "datepicker__label", children: label }),
|
|
291
|
+
/* @__PURE__ */ jsx4(
|
|
292
|
+
"input",
|
|
293
|
+
{
|
|
294
|
+
ref: inputRef,
|
|
295
|
+
type: "text",
|
|
296
|
+
inputMode: "numeric",
|
|
297
|
+
className: "datepicker__input",
|
|
298
|
+
value: inputValue,
|
|
299
|
+
placeholder: label && !focused ? void 0 : defaultPlaceholder,
|
|
300
|
+
disabled,
|
|
301
|
+
onChange: handleChange,
|
|
302
|
+
onKeyDown: handleKeyDown,
|
|
303
|
+
onPaste: handlePaste,
|
|
304
|
+
onFocus: () => {
|
|
305
|
+
setFocused(true);
|
|
306
|
+
if (!disabled && !noCalendar) setOpen(true);
|
|
307
|
+
},
|
|
308
|
+
onBlur: handleBlur,
|
|
309
|
+
"aria-label": label != null ? label : "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0430\u0442\u0443",
|
|
310
|
+
"aria-expanded": !noCalendar ? open : void 0,
|
|
311
|
+
"aria-haspopup": !noCalendar ? "dialog" : void 0,
|
|
312
|
+
"aria-invalid": inputInvalid || void 0
|
|
313
|
+
}
|
|
314
|
+
),
|
|
315
|
+
resolvedIcon && iconPosition === "end" && /* @__PURE__ */ jsx4("span", { className: "datepicker__icon datepicker__icon--end", children: resolvedIcon })
|
|
316
|
+
]
|
|
317
|
+
}
|
|
318
|
+
),
|
|
319
|
+
!noCalendar && open && /* @__PURE__ */ jsx4(
|
|
320
|
+
"div",
|
|
193
321
|
{
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
322
|
+
className: [
|
|
323
|
+
"datepicker__popover",
|
|
324
|
+
`datepicker__popover--${size}`,
|
|
325
|
+
timeFormat && "datepicker__popover--with-time"
|
|
326
|
+
].filter(Boolean).join(" "),
|
|
327
|
+
role: "dialog",
|
|
328
|
+
"aria-label": "\u041A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u044C",
|
|
329
|
+
children: timeFormat ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
330
|
+
/* @__PURE__ */ jsxs3("div", { className: "datepicker__popover-body", children: [
|
|
331
|
+
/* @__PURE__ */ jsx4("div", { className: "datepicker__popover-calendar", children: /* @__PURE__ */ jsx4(
|
|
332
|
+
Calendar,
|
|
333
|
+
{
|
|
334
|
+
mode: "single",
|
|
335
|
+
selected,
|
|
336
|
+
onSelect: handleCalendarSelect,
|
|
337
|
+
startMonth: fromDate,
|
|
338
|
+
endMonth: toDate,
|
|
339
|
+
locale: ru
|
|
340
|
+
}
|
|
341
|
+
) }),
|
|
342
|
+
/* @__PURE__ */ jsx4("div", { className: "datepicker__time-separator" }),
|
|
343
|
+
/* @__PURE__ */ jsx4("div", { className: "datepicker__popover-time", children: /* @__PURE__ */ jsx4(
|
|
344
|
+
TimePanel,
|
|
345
|
+
{
|
|
346
|
+
value: selected,
|
|
347
|
+
showSeconds,
|
|
348
|
+
onChange: handleTimeChange
|
|
349
|
+
}
|
|
350
|
+
) })
|
|
351
|
+
] }),
|
|
352
|
+
/* @__PURE__ */ jsx4("div", { className: "datepicker__popover-footer", children: /* @__PURE__ */ jsx4(
|
|
353
|
+
"button",
|
|
354
|
+
{
|
|
355
|
+
className: "datepicker__ok-btn",
|
|
356
|
+
type: "button",
|
|
357
|
+
onClick: () => setOpen(false),
|
|
358
|
+
children: "OK"
|
|
359
|
+
}
|
|
360
|
+
) })
|
|
361
|
+
] }) : /* @__PURE__ */ jsx4(
|
|
362
|
+
Calendar,
|
|
363
|
+
{
|
|
364
|
+
mode: "single",
|
|
365
|
+
selected,
|
|
366
|
+
onSelect: handleCalendarSelect,
|
|
367
|
+
startMonth: fromDate,
|
|
368
|
+
endMonth: toDate,
|
|
369
|
+
locale: ru
|
|
370
|
+
}
|
|
371
|
+
)
|
|
200
372
|
}
|
|
201
|
-
)
|
|
373
|
+
)
|
|
202
374
|
]
|
|
203
375
|
}
|
|
204
376
|
);
|
|
205
377
|
}
|
|
206
378
|
|
|
207
379
|
// src/components/DateRangePicker/DateRangePicker.tsx
|
|
208
|
-
import { useCallback as useCallback2, useRef as
|
|
380
|
+
import { useCallback as useCallback2, useRef as useRef3, useState as useState2 } from "react";
|
|
209
381
|
import { format as format2, isValid as isValid2, parse as parse2 } from "date-fns";
|
|
210
382
|
import { ru as ru2 } from "date-fns/locale";
|
|
211
|
-
import { jsx as
|
|
383
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
212
384
|
var DATE_FORMAT2 = "dd.MM.yyyy";
|
|
213
385
|
function applyDateMask(digits) {
|
|
214
386
|
const d = digits.slice(0, 8);
|
|
@@ -237,7 +409,7 @@ function getRangeCursorPos(masked, digitCount) {
|
|
|
237
409
|
}
|
|
238
410
|
return masked.length;
|
|
239
411
|
}
|
|
240
|
-
function
|
|
412
|
+
function parseDate(masked) {
|
|
241
413
|
if (masked.replace(/\D/g, "").length !== 8) return void 0;
|
|
242
414
|
const date = parse2(masked, DATE_FORMAT2, /* @__PURE__ */ new Date());
|
|
243
415
|
return isValid2(date) && format2(date, DATE_FORMAT2) === masked ? date : void 0;
|
|
@@ -248,6 +420,11 @@ function formatRange(from, to) {
|
|
|
248
420
|
if (!to) return fromStr;
|
|
249
421
|
return `${fromStr} \u2014 ${format2(to, DATE_FORMAT2)}`;
|
|
250
422
|
}
|
|
423
|
+
function resolveShowSeconds(showTime) {
|
|
424
|
+
if (!showTime) return false;
|
|
425
|
+
if (showTime === true) return true;
|
|
426
|
+
return showTime.format === "HH:mm:ss";
|
|
427
|
+
}
|
|
251
428
|
function DateRangePicker({
|
|
252
429
|
value,
|
|
253
430
|
defaultValue,
|
|
@@ -257,9 +434,16 @@ function DateRangePicker({
|
|
|
257
434
|
toDate: toConstraint,
|
|
258
435
|
disabled = false,
|
|
259
436
|
failed = false,
|
|
437
|
+
size = "m",
|
|
438
|
+
calendarLayout = "vertical",
|
|
439
|
+
showTime,
|
|
440
|
+
icon,
|
|
441
|
+
iconPosition = "end",
|
|
260
442
|
className
|
|
261
443
|
}) {
|
|
444
|
+
const resolvedIcon = icon === false ? null : icon != null ? icon : /* @__PURE__ */ jsx5(CalendarIcon, {});
|
|
262
445
|
const isControlled = value !== void 0;
|
|
446
|
+
const showSeconds = resolveShowSeconds(showTime);
|
|
263
447
|
const [internalFrom, setInternalFrom] = useState2(defaultValue == null ? void 0 : defaultValue.from);
|
|
264
448
|
const [internalTo, setInternalTo] = useState2(defaultValue == null ? void 0 : defaultValue.to);
|
|
265
449
|
const [inputValue, setInputValue] = useState2(
|
|
@@ -270,8 +454,8 @@ function DateRangePicker({
|
|
|
270
454
|
const [focused, setFocused] = useState2(false);
|
|
271
455
|
const [anchorDate, setAnchorDate] = useState2(void 0);
|
|
272
456
|
const [hoveredDate, setHoveredDate] = useState2(void 0);
|
|
273
|
-
const inputRef =
|
|
274
|
-
const containerRef =
|
|
457
|
+
const inputRef = useRef3(null);
|
|
458
|
+
const containerRef = useRef3(null);
|
|
275
459
|
const confirmedFrom = isControlled ? value == null ? void 0 : value.from : internalFrom;
|
|
276
460
|
const confirmedTo = isControlled ? value == null ? void 0 : value.to : internalTo;
|
|
277
461
|
const filled = inputValue.length > 0;
|
|
@@ -283,20 +467,37 @@ function DateRangePicker({
|
|
|
283
467
|
useClickOutside(containerRef, close);
|
|
284
468
|
const calendarSelected = anchorDate ? hoveredDate ? anchorDate <= hoveredDate ? { from: anchorDate, to: hoveredDate } : { from: hoveredDate, to: anchorDate } : { from: anchorDate, to: void 0 } : { from: confirmedFrom, to: confirmedTo };
|
|
285
469
|
function handleDayClick(day) {
|
|
470
|
+
var _a, _b, _c, _d, _e, _f;
|
|
286
471
|
if (!anchorDate) {
|
|
287
|
-
|
|
472
|
+
const from = showTime ? new Date(
|
|
473
|
+
day.getFullYear(),
|
|
474
|
+
day.getMonth(),
|
|
475
|
+
day.getDate(),
|
|
476
|
+
(_a = confirmedFrom == null ? void 0 : confirmedFrom.getHours()) != null ? _a : 0,
|
|
477
|
+
(_b = confirmedFrom == null ? void 0 : confirmedFrom.getMinutes()) != null ? _b : 0,
|
|
478
|
+
(_c = confirmedFrom == null ? void 0 : confirmedFrom.getSeconds()) != null ? _c : 0
|
|
479
|
+
) : day;
|
|
480
|
+
setAnchorDate(from);
|
|
288
481
|
if (!isControlled) {
|
|
289
|
-
setInternalFrom(
|
|
482
|
+
setInternalFrom(from);
|
|
290
483
|
setInternalTo(void 0);
|
|
291
484
|
}
|
|
292
485
|
setInputValue(format2(day, DATE_FORMAT2));
|
|
293
486
|
setInputInvalid(false);
|
|
294
|
-
onChange == null ? void 0 : onChange(
|
|
487
|
+
onChange == null ? void 0 : onChange({ from, to: void 0 });
|
|
295
488
|
} else {
|
|
296
|
-
let from = anchorDate, to =
|
|
489
|
+
let from = anchorDate, to = showTime ? new Date(
|
|
490
|
+
day.getFullYear(),
|
|
491
|
+
day.getMonth(),
|
|
492
|
+
day.getDate(),
|
|
493
|
+
(_d = confirmedTo == null ? void 0 : confirmedTo.getHours()) != null ? _d : 0,
|
|
494
|
+
(_e = confirmedTo == null ? void 0 : confirmedTo.getMinutes()) != null ? _e : 0,
|
|
495
|
+
(_f = confirmedTo == null ? void 0 : confirmedTo.getSeconds()) != null ? _f : 0
|
|
496
|
+
) : day;
|
|
297
497
|
if (day < anchorDate) {
|
|
298
|
-
|
|
299
|
-
|
|
498
|
+
const tmp = from;
|
|
499
|
+
from = to;
|
|
500
|
+
to = tmp;
|
|
300
501
|
}
|
|
301
502
|
if (!isControlled) {
|
|
302
503
|
setInternalFrom(from);
|
|
@@ -305,12 +506,25 @@ function DateRangePicker({
|
|
|
305
506
|
setInputValue(formatRange(from, to));
|
|
306
507
|
setInputInvalid(false);
|
|
307
508
|
onChange == null ? void 0 : onChange({ from, to });
|
|
308
|
-
close();
|
|
509
|
+
if (!showTime) close();
|
|
510
|
+
else setAnchorDate(void 0);
|
|
309
511
|
}
|
|
310
512
|
}
|
|
311
513
|
function handleDayMouseEnter(day) {
|
|
312
514
|
if (anchorDate) setHoveredDate(day);
|
|
313
515
|
}
|
|
516
|
+
function handleFromTimeChange(h, m, s) {
|
|
517
|
+
const base = confirmedFrom != null ? confirmedFrom : /* @__PURE__ */ new Date();
|
|
518
|
+
const newDate = new Date(base.getFullYear(), base.getMonth(), base.getDate(), h, m, s);
|
|
519
|
+
if (!isControlled) setInternalFrom(newDate);
|
|
520
|
+
onChange == null ? void 0 : onChange({ from: newDate, to: confirmedTo });
|
|
521
|
+
}
|
|
522
|
+
function handleToTimeChange(h, m, s) {
|
|
523
|
+
const base = confirmedTo != null ? confirmedTo : /* @__PURE__ */ new Date();
|
|
524
|
+
const newDate = new Date(base.getFullYear(), base.getMonth(), base.getDate(), h, m, s);
|
|
525
|
+
if (!isControlled) setInternalTo(newDate);
|
|
526
|
+
onChange == null ? void 0 : onChange({ from: confirmedFrom, to: newDate });
|
|
527
|
+
}
|
|
314
528
|
function handleChange(e) {
|
|
315
529
|
var _a;
|
|
316
530
|
const input = e.target;
|
|
@@ -324,8 +538,8 @@ function DateRangePicker({
|
|
|
324
538
|
setHoveredDate(void 0);
|
|
325
539
|
const fromDigits = digits.slice(0, 8);
|
|
326
540
|
const toDigits = digits.slice(8);
|
|
327
|
-
const parsedFrom = fromDigits.length === 8 ?
|
|
328
|
-
const parsedTo = toDigits.length === 8 ?
|
|
541
|
+
const parsedFrom = fromDigits.length === 8 ? parseDate(applyDateMask(fromDigits)) : void 0;
|
|
542
|
+
const parsedTo = toDigits.length === 8 ? parseDate(applyDateMask(toDigits)) : void 0;
|
|
329
543
|
const fromComplete = fromDigits.length === 8;
|
|
330
544
|
const toComplete = toDigits.length === 8;
|
|
331
545
|
setInputInvalid(fromComplete && !parsedFrom || toComplete && !parsedTo);
|
|
@@ -370,8 +584,8 @@ function DateRangePicker({
|
|
|
370
584
|
setInputValue(masked);
|
|
371
585
|
setAnchorDate(void 0);
|
|
372
586
|
setHoveredDate(void 0);
|
|
373
|
-
const parsedFrom = digits.length >= 8 ?
|
|
374
|
-
const parsedTo = digits.length >= 16 ?
|
|
587
|
+
const parsedFrom = digits.length >= 8 ? parseDate(applyDateMask(digits.slice(0, 8))) : void 0;
|
|
588
|
+
const parsedTo = digits.length >= 16 ? parseDate(applyDateMask(digits.slice(8, 16))) : void 0;
|
|
375
589
|
setInputInvalid(digits.length >= 8 && !parsedFrom || digits.length >= 16 && !parsedTo);
|
|
376
590
|
if (!isControlled) {
|
|
377
591
|
setInternalFrom(parsedFrom);
|
|
@@ -384,62 +598,115 @@ function DateRangePicker({
|
|
|
384
598
|
});
|
|
385
599
|
}
|
|
386
600
|
const placeholder = label && !focused && !filled ? void 0 : "\u0434\u0434.\u043C\u043C.\u0433\u0433\u0433\u0433 \u2014 \u0434\u0434.\u043C\u043C.\u0433\u0433\u0433\u0433";
|
|
387
|
-
return /* @__PURE__ */
|
|
601
|
+
return /* @__PURE__ */ jsxs4(
|
|
388
602
|
"div",
|
|
389
603
|
{
|
|
390
604
|
ref: containerRef,
|
|
391
|
-
className: ["datepicker", "daterangepicker", className].filter(Boolean).join(" "),
|
|
605
|
+
className: ["datepicker", "daterangepicker", `datepicker--${size}`, className].filter(Boolean).join(" "),
|
|
392
606
|
"data-focused": focused || open || void 0,
|
|
393
607
|
"data-filled": filled || void 0,
|
|
394
608
|
"data-failed": failed || inputInvalid || void 0,
|
|
395
609
|
"data-disabled": disabled || void 0,
|
|
396
610
|
children: [
|
|
397
|
-
/* @__PURE__ */
|
|
398
|
-
|
|
399
|
-
return !disabled && ((_a = inputRef.current) == null ? void 0 : _a.focus());
|
|
400
|
-
}, children: [
|
|
401
|
-
label && /* @__PURE__ */ jsx3("span", { className: "datepicker__label", children: label }),
|
|
402
|
-
/* @__PURE__ */ jsx3(
|
|
403
|
-
"input",
|
|
404
|
-
{
|
|
405
|
-
ref: inputRef,
|
|
406
|
-
type: "text",
|
|
407
|
-
inputMode: "numeric",
|
|
408
|
-
className: "datepicker__input",
|
|
409
|
-
value: inputValue,
|
|
410
|
-
placeholder,
|
|
411
|
-
disabled,
|
|
412
|
-
onChange: handleChange,
|
|
413
|
-
onKeyDown: handleKeyDown,
|
|
414
|
-
onPaste: handlePaste,
|
|
415
|
-
onFocus: () => {
|
|
416
|
-
setFocused(true);
|
|
417
|
-
if (!disabled) setOpen(true);
|
|
418
|
-
},
|
|
419
|
-
onBlur: () => setFocused(false),
|
|
420
|
-
"aria-label": label != null ? label : "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043F\u0435\u0440\u0438\u043E\u0434",
|
|
421
|
-
"aria-expanded": open,
|
|
422
|
-
"aria-haspopup": "dialog",
|
|
423
|
-
"aria-invalid": inputInvalid || void 0
|
|
424
|
-
}
|
|
425
|
-
)
|
|
426
|
-
] }),
|
|
427
|
-
open && /* @__PURE__ */ jsx3("div", { className: "datepicker__popover", role: "dialog", "aria-label": "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043F\u0435\u0440\u0438\u043E\u0434", children: /* @__PURE__ */ jsx3(
|
|
428
|
-
Calendar,
|
|
611
|
+
/* @__PURE__ */ jsxs4(
|
|
612
|
+
"div",
|
|
429
613
|
{
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
614
|
+
className: "datepicker__field",
|
|
615
|
+
"data-icon-start": resolvedIcon && iconPosition === "start" ? true : void 0,
|
|
616
|
+
"data-icon-end": resolvedIcon && iconPosition === "end" ? true : void 0,
|
|
617
|
+
onClick: () => {
|
|
618
|
+
var _a;
|
|
619
|
+
return !disabled && ((_a = inputRef.current) == null ? void 0 : _a.focus());
|
|
433
620
|
},
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
621
|
+
children: [
|
|
622
|
+
resolvedIcon && iconPosition === "start" && /* @__PURE__ */ jsx5("span", { className: "datepicker__icon datepicker__icon--start", children: resolvedIcon }),
|
|
623
|
+
label && /* @__PURE__ */ jsx5("span", { className: "datepicker__label", children: label }),
|
|
624
|
+
/* @__PURE__ */ jsx5(
|
|
625
|
+
"input",
|
|
626
|
+
{
|
|
627
|
+
ref: inputRef,
|
|
628
|
+
type: "text",
|
|
629
|
+
inputMode: "numeric",
|
|
630
|
+
className: "datepicker__input",
|
|
631
|
+
value: inputValue,
|
|
632
|
+
placeholder,
|
|
633
|
+
disabled,
|
|
634
|
+
onChange: handleChange,
|
|
635
|
+
onKeyDown: handleKeyDown,
|
|
636
|
+
onPaste: handlePaste,
|
|
637
|
+
onFocus: () => {
|
|
638
|
+
setFocused(true);
|
|
639
|
+
if (!disabled) setOpen(true);
|
|
640
|
+
},
|
|
641
|
+
onBlur: () => setFocused(false),
|
|
642
|
+
"aria-label": label != null ? label : "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043F\u0435\u0440\u0438\u043E\u0434",
|
|
643
|
+
"aria-expanded": open,
|
|
644
|
+
"aria-haspopup": "dialog",
|
|
645
|
+
"aria-invalid": inputInvalid || void 0
|
|
646
|
+
}
|
|
647
|
+
),
|
|
648
|
+
resolvedIcon && iconPosition === "end" && /* @__PURE__ */ jsx5("span", { className: "datepicker__icon datepicker__icon--end", children: resolvedIcon })
|
|
649
|
+
]
|
|
650
|
+
}
|
|
651
|
+
),
|
|
652
|
+
open && /* @__PURE__ */ jsx5(
|
|
653
|
+
"div",
|
|
654
|
+
{
|
|
655
|
+
className: [
|
|
656
|
+
"datepicker__popover",
|
|
657
|
+
`datepicker__popover--${size}`,
|
|
658
|
+
calendarLayout === "horizontal" && "datepicker__popover--horizontal",
|
|
659
|
+
showTime && "datepicker__popover--with-time"
|
|
660
|
+
].filter(Boolean).join(" "),
|
|
661
|
+
role: "dialog",
|
|
662
|
+
"aria-label": "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043F\u0435\u0440\u0438\u043E\u0434",
|
|
663
|
+
children: showTime ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
664
|
+
/* @__PURE__ */ jsx5("div", { className: "datepicker__popover-body", children: /* @__PURE__ */ jsx5("div", { className: "datepicker__popover-calendar", children: /* @__PURE__ */ jsx5(
|
|
665
|
+
Calendar,
|
|
666
|
+
{
|
|
667
|
+
mode: "range",
|
|
668
|
+
selected: calendarSelected,
|
|
669
|
+
onSelect: () => {
|
|
670
|
+
},
|
|
671
|
+
onDayClick: handleDayClick,
|
|
672
|
+
onDayMouseEnter: handleDayMouseEnter,
|
|
673
|
+
onDayMouseLeave: () => setHoveredDate(void 0),
|
|
674
|
+
startMonth: fromConstraint,
|
|
675
|
+
endMonth: toConstraint,
|
|
676
|
+
numberOfMonths: 2,
|
|
677
|
+
locale: ru2
|
|
678
|
+
}
|
|
679
|
+
) }) }),
|
|
680
|
+
/* @__PURE__ */ jsxs4("div", { className: "datepicker__time-row", children: [
|
|
681
|
+
/* @__PURE__ */ jsxs4("div", { className: "datepicker__time-col", children: [
|
|
682
|
+
/* @__PURE__ */ jsx5("span", { className: "datepicker__time-label", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
|
|
683
|
+
/* @__PURE__ */ jsx5(TimePanel, { value: confirmedFrom, showSeconds, onChange: handleFromTimeChange })
|
|
684
|
+
] }),
|
|
685
|
+
/* @__PURE__ */ jsx5("div", { className: "datepicker__time-separator" }),
|
|
686
|
+
/* @__PURE__ */ jsxs4("div", { className: "datepicker__time-col", children: [
|
|
687
|
+
/* @__PURE__ */ jsx5("span", { className: "datepicker__time-label", children: "\u041A\u043E\u043D\u0435\u0446" }),
|
|
688
|
+
/* @__PURE__ */ jsx5(TimePanel, { value: confirmedTo, showSeconds, onChange: handleToTimeChange })
|
|
689
|
+
] })
|
|
690
|
+
] }),
|
|
691
|
+
/* @__PURE__ */ jsx5("div", { className: "datepicker__popover-footer", children: /* @__PURE__ */ jsx5("button", { className: "datepicker__ok-btn", type: "button", onClick: close, children: "OK" }) })
|
|
692
|
+
] }) : /* @__PURE__ */ jsx5(
|
|
693
|
+
Calendar,
|
|
694
|
+
{
|
|
695
|
+
mode: "range",
|
|
696
|
+
selected: calendarSelected,
|
|
697
|
+
onSelect: () => {
|
|
698
|
+
},
|
|
699
|
+
onDayClick: handleDayClick,
|
|
700
|
+
onDayMouseEnter: handleDayMouseEnter,
|
|
701
|
+
onDayMouseLeave: () => setHoveredDate(void 0),
|
|
702
|
+
startMonth: fromConstraint,
|
|
703
|
+
endMonth: toConstraint,
|
|
704
|
+
numberOfMonths: 2,
|
|
705
|
+
locale: ru2
|
|
706
|
+
}
|
|
707
|
+
)
|
|
441
708
|
}
|
|
442
|
-
)
|
|
709
|
+
)
|
|
443
710
|
]
|
|
444
711
|
}
|
|
445
712
|
);
|