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