@gravity-ui/date-components 1.1.0 → 1.1.1
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/cjs/components/Calendar/hooks/useRangeCalendarState.js +10 -5
- package/dist/cjs/components/DateField/hooks/useDateFieldProps.js +21 -14
- package/dist/cjs/components/DateField/hooks/useDateFieldState.js +16 -160
- package/dist/cjs/components/DateField/utils.d.ts +13 -1
- package/dist/cjs/components/DateField/utils.js +168 -1
- package/dist/cjs/components/DatePicker/DatePicker.css +6 -0
- package/dist/cjs/components/DatePicker/DatePicker.d.ts +2 -2
- package/dist/cjs/components/DatePicker/DatePicker.js +6 -33
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.js +134 -0
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +15 -0
- package/dist/cjs/components/DatePicker/index.d.ts +1 -0
- package/dist/cjs/components/DatePicker/index.js +1 -0
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
- package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +29 -27
- package/dist/esm/components/Calendar/hooks/useRangeCalendarState.js +10 -5
- package/dist/esm/components/DateField/hooks/useDateFieldProps.js +21 -14
- package/dist/esm/components/DateField/hooks/useDateFieldState.js +14 -158
- package/dist/esm/components/DateField/utils.d.ts +13 -1
- package/dist/esm/components/DateField/utils.js +162 -0
- package/dist/esm/components/DatePicker/DatePicker.css +6 -0
- package/dist/esm/components/DatePicker/DatePicker.d.ts +2 -2
- package/dist/esm/components/DatePicker/DatePicker.js +8 -35
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.js +127 -0
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +15 -0
- package/dist/esm/components/DatePicker/index.d.ts +1 -0
- package/dist/esm/components/DatePicker/index.js +1 -0
- package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
- package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +29 -27
- package/package.json +8 -7
- package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +0 -17
- package/dist/cjs/components/DatePicker/DesktopCalendar.js +0 -65
- package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +0 -17
- package/dist/esm/components/DatePicker/DesktopCalendar.js +0 -57
|
@@ -28,8 +28,16 @@ function useRangeCalendarState(props) {
|
|
|
28
28
|
const highlightedRange = anchorDate
|
|
29
29
|
? makeRange(anchorDate, calendar.focusedDate, calendar.mode)
|
|
30
30
|
: (_b = (value && makeRange(value.start, value.end, calendar.mode))) !== null && _b !== void 0 ? _b : undefined;
|
|
31
|
-
const
|
|
32
|
-
|
|
31
|
+
const minMode = calendar.availableModes[0];
|
|
32
|
+
const selectDate = (date, force = false) => {
|
|
33
|
+
if (props.disabled) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (!force && calendar.mode !== minMode) {
|
|
37
|
+
calendar.zoomIn();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (props.readOnly) {
|
|
33
41
|
return;
|
|
34
42
|
}
|
|
35
43
|
date = (0, utils_1.constrainValue)(date, props.minValue, props.maxValue);
|
|
@@ -49,9 +57,6 @@ function useRangeCalendarState(props) {
|
|
|
49
57
|
setValue,
|
|
50
58
|
selectDate,
|
|
51
59
|
anchorDate, setAnchorDate: setAnchorDateState, highlightedRange,
|
|
52
|
-
selectFocusedDate() {
|
|
53
|
-
selectDate(calendar.focusedDate);
|
|
54
|
-
},
|
|
55
60
|
isSelected(date) {
|
|
56
61
|
if (!highlightedRange) {
|
|
57
62
|
return false;
|
|
@@ -86,12 +86,16 @@ function useDateFieldProps(state, props) {
|
|
|
86
86
|
if (state.selectedSectionIndexes !== null) {
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
|
-
const input =
|
|
89
|
+
const input = e.target;
|
|
90
|
+
const isAutofocus = !inputRef.current;
|
|
90
91
|
setTimeout(() => {
|
|
91
92
|
if (!input || input !== inputRef.current) {
|
|
92
93
|
return;
|
|
93
94
|
}
|
|
94
|
-
if (
|
|
95
|
+
if (isAutofocus) {
|
|
96
|
+
state.focusSectionInPosition(0);
|
|
97
|
+
}
|
|
98
|
+
else if (
|
|
95
99
|
// avoid selecting all sections when focusing empty field without value
|
|
96
100
|
input.value.length &&
|
|
97
101
|
Number(input.selectionEnd) - Number(input.selectionStart) ===
|
|
@@ -169,32 +173,35 @@ function useDateFieldProps(state, props) {
|
|
|
169
173
|
onBeforeInput(e) {
|
|
170
174
|
e.preventDefault();
|
|
171
175
|
// @ts-expect-error
|
|
172
|
-
const key = e.
|
|
173
|
-
|
|
174
|
-
if (key != null) {
|
|
176
|
+
const key = e.data;
|
|
177
|
+
if (key !== undefined && key !== null) {
|
|
175
178
|
state.onInput(key);
|
|
176
179
|
}
|
|
177
180
|
},
|
|
178
181
|
onPaste(e) {
|
|
182
|
+
e.preventDefault();
|
|
179
183
|
if (state.readOnly) {
|
|
180
|
-
e.preventDefault();
|
|
181
184
|
return;
|
|
182
185
|
}
|
|
183
186
|
const pastedValue = e.clipboardData.getData('text');
|
|
184
|
-
if (state.
|
|
185
|
-
e.preventDefault();
|
|
186
|
-
}
|
|
187
|
-
else if (state.selectedSectionIndexes &&
|
|
187
|
+
if (state.selectedSectionIndexes &&
|
|
188
188
|
state.selectedSectionIndexes.startIndex ===
|
|
189
189
|
state.selectedSectionIndexes.endIndex) {
|
|
190
190
|
const activeSection = state.sections[state.selectedSectionIndexes.startIndex];
|
|
191
|
+
const digitsOnly = /^\d+$/.test(pastedValue);
|
|
192
|
+
const lettersOnly = /^[a-zA-Z]+$/.test(pastedValue);
|
|
191
193
|
const isValidValue = Boolean(activeSection) &&
|
|
192
|
-
((activeSection.contentType === 'digit' &&
|
|
193
|
-
activeSection.contentType === 'letter');
|
|
194
|
-
if (
|
|
195
|
-
|
|
194
|
+
((activeSection.contentType === 'digit' && digitsOnly) ||
|
|
195
|
+
(activeSection.contentType === 'letter' && lettersOnly));
|
|
196
|
+
if (isValidValue) {
|
|
197
|
+
state.onInput(pastedValue);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (digitsOnly || lettersOnly) {
|
|
201
|
+
return;
|
|
196
202
|
}
|
|
197
203
|
}
|
|
204
|
+
state.setValueFromString(pastedValue);
|
|
198
205
|
},
|
|
199
206
|
},
|
|
200
207
|
},
|
|
@@ -19,11 +19,6 @@ const EDITABLE_SEGMENTS = {
|
|
|
19
19
|
dayPeriod: true,
|
|
20
20
|
weekday: true,
|
|
21
21
|
};
|
|
22
|
-
const TYPE_MAPPING = {
|
|
23
|
-
weekday: 'day',
|
|
24
|
-
day: 'date',
|
|
25
|
-
dayPeriod: 'hour',
|
|
26
|
-
};
|
|
27
22
|
const PAGE_STEP = {
|
|
28
23
|
year: 5,
|
|
29
24
|
month: 2,
|
|
@@ -69,10 +64,7 @@ function useDateFieldState(props) {
|
|
|
69
64
|
? value
|
|
70
65
|
: placeholderDate;
|
|
71
66
|
const sectionsState = useSectionsState(sections, displayValue, validSegments);
|
|
72
|
-
const [selectedSections, setSelectedSections] = react_1.default.useState(
|
|
73
|
-
var _a, _b;
|
|
74
|
-
return (_b = (_a = sectionsState.editableSections[0]) === null || _a === void 0 ? void 0 : _a.previousEditableSection) !== null && _b !== void 0 ? _b : -1;
|
|
75
|
-
});
|
|
67
|
+
const [selectedSections, setSelectedSections] = react_1.default.useState(-1);
|
|
76
68
|
const selectedSectionIndexes = react_1.default.useMemo(() => {
|
|
77
69
|
if (selectedSections === -1) {
|
|
78
70
|
return null;
|
|
@@ -97,9 +89,14 @@ function useDateFieldState(props) {
|
|
|
97
89
|
return;
|
|
98
90
|
}
|
|
99
91
|
if (Object.keys(validSegments).length >= Object.keys(allSegments).length) {
|
|
100
|
-
|
|
92
|
+
if (!value || !newValue.isSame(value)) {
|
|
93
|
+
setDate(newValue);
|
|
94
|
+
}
|
|
101
95
|
}
|
|
102
96
|
else {
|
|
97
|
+
if (value) {
|
|
98
|
+
setDate(null);
|
|
99
|
+
}
|
|
103
100
|
setPlaceholderDate(newValue);
|
|
104
101
|
}
|
|
105
102
|
}
|
|
@@ -115,12 +112,12 @@ function useDateFieldState(props) {
|
|
|
115
112
|
}
|
|
116
113
|
function setSection(section, amount) {
|
|
117
114
|
markValid(section.type);
|
|
118
|
-
setValue(setSegment(section, displayValue, amount));
|
|
115
|
+
setValue((0, utils_1.setSegment)(section, displayValue, amount));
|
|
119
116
|
}
|
|
120
117
|
function adjustSection(sectionIndex, amount) {
|
|
121
118
|
const section = sectionsState.editableSections[sectionIndex];
|
|
122
119
|
if (validSegments[section.type]) {
|
|
123
|
-
setValue(addSegment(section, displayValue, amount));
|
|
120
|
+
setValue((0, utils_1.addSegment)(section, displayValue, amount));
|
|
124
121
|
}
|
|
125
122
|
else {
|
|
126
123
|
markValid(section.type);
|
|
@@ -285,12 +282,9 @@ function useDateFieldState(props) {
|
|
|
285
282
|
}
|
|
286
283
|
}
|
|
287
284
|
else {
|
|
288
|
-
const type = getDurationUnitFromSectionType(section.type);
|
|
285
|
+
const type = (0, utils_1.getDurationUnitFromSectionType)(section.type);
|
|
289
286
|
currentValue = displayValue.set(type, placeholder[type]());
|
|
290
287
|
}
|
|
291
|
-
if (value) {
|
|
292
|
-
setDate(null);
|
|
293
|
-
}
|
|
294
288
|
setValue(currentValue);
|
|
295
289
|
},
|
|
296
290
|
clearAll() {
|
|
@@ -417,6 +411,7 @@ function useDateFieldState(props) {
|
|
|
417
411
|
}
|
|
418
412
|
},
|
|
419
413
|
setValueFromString(str) {
|
|
414
|
+
enteredKeys.current = '';
|
|
420
415
|
let date = parseDate({ input: str, format, timeZone: props.timeZone });
|
|
421
416
|
if ((0, date_utils_1.isValid)(date)) {
|
|
422
417
|
if (props.timeZone && !isDateStringWithTimeZone(str)) {
|
|
@@ -441,64 +436,6 @@ function parseDate(options) {
|
|
|
441
436
|
function isDateStringWithTimeZone(str) {
|
|
442
437
|
return /z$/i.test(str) || /[+-]\d\d:\d\d$/.test(str);
|
|
443
438
|
}
|
|
444
|
-
function addSegment(section, date, amount) {
|
|
445
|
-
var _a;
|
|
446
|
-
let val = (_a = section.value) !== null && _a !== void 0 ? _a : 0;
|
|
447
|
-
if (section.type === 'dayPeriod') {
|
|
448
|
-
val = date.hour() + (date.hour() > 12 ? -12 : 12);
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
val = val + amount;
|
|
452
|
-
const min = section.minValue;
|
|
453
|
-
const max = section.maxValue;
|
|
454
|
-
if (typeof min === 'number' && typeof max === 'number') {
|
|
455
|
-
const length = max - min + 1;
|
|
456
|
-
val = ((val - min + length) % length) + min;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
const type = getDurationUnitFromSectionType(section.type);
|
|
460
|
-
return date.set(type, val);
|
|
461
|
-
}
|
|
462
|
-
function setSegment(section, date, amount) {
|
|
463
|
-
const type = section.type;
|
|
464
|
-
switch (type) {
|
|
465
|
-
case 'day':
|
|
466
|
-
case 'weekday':
|
|
467
|
-
case 'month':
|
|
468
|
-
case 'year': {
|
|
469
|
-
return date.set(getDurationUnitFromSectionType(type), amount);
|
|
470
|
-
}
|
|
471
|
-
case 'dayPeriod': {
|
|
472
|
-
const hours = date.hour();
|
|
473
|
-
const wasPM = hours >= 12;
|
|
474
|
-
const isPM = amount >= 12;
|
|
475
|
-
if (isPM === wasPM) {
|
|
476
|
-
return date;
|
|
477
|
-
}
|
|
478
|
-
return date.set('hour', wasPM ? hours - 12 : hours + 12);
|
|
479
|
-
}
|
|
480
|
-
case 'hour': {
|
|
481
|
-
// In 12 hour time, ensure that AM/PM does not change
|
|
482
|
-
let sectionAmount = amount;
|
|
483
|
-
if (section.minValue === 12 || section.maxValue === 11) {
|
|
484
|
-
const hours = date.hour();
|
|
485
|
-
const wasPM = hours >= 12;
|
|
486
|
-
if (!wasPM && sectionAmount === 12) {
|
|
487
|
-
sectionAmount = 0;
|
|
488
|
-
}
|
|
489
|
-
if (wasPM && sectionAmount < 12) {
|
|
490
|
-
sectionAmount += 12;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
return date.set('hour', sectionAmount);
|
|
494
|
-
}
|
|
495
|
-
case 'minute':
|
|
496
|
-
case 'second': {
|
|
497
|
-
return date.set(type, amount);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
return date;
|
|
501
|
-
}
|
|
502
439
|
function getCurrentEditableSectionIndex(sections, selectedSections) {
|
|
503
440
|
const currentIndex = selectedSections === 'all' || selectedSections === -1 ? 0 : selectedSections;
|
|
504
441
|
const section = sections[currentIndex];
|
|
@@ -548,9 +485,13 @@ function getEditableSections(sections, value, validSegments) {
|
|
|
548
485
|
let renderedValue = section.placeholder;
|
|
549
486
|
if ((isEditable && validSegments[section.type]) || section.type === 'timeZoneName') {
|
|
550
487
|
renderedValue = value.format(section.format);
|
|
488
|
+
if (section.contentType === 'digit' &&
|
|
489
|
+
renderedValue.length < section.placeholder.length) {
|
|
490
|
+
renderedValue = renderedValue.padStart(section.placeholder.length, '0');
|
|
491
|
+
}
|
|
551
492
|
}
|
|
552
493
|
const sectionLength = renderedValue.length;
|
|
553
|
-
const newSection = Object.assign(Object.assign(Object.assign({}, section), { value:
|
|
494
|
+
const newSection = Object.assign(Object.assign(Object.assign({}, section), { value: (0, utils_1.getSectionValue)(section, value), textValue: renderedValue, start: position, end: position + sectionLength, modified: false, previousEditableSection, nextEditableSection: previousEditableSection }), (0, utils_1.getSectionLimits)(section, value));
|
|
554
495
|
newSections.push(newSection);
|
|
555
496
|
if (isEditable) {
|
|
556
497
|
for (let j = Math.max(0, previousEditableSection); j <= i; j++) {
|
|
@@ -568,88 +509,3 @@ function getEditableSections(sections, value, validSegments) {
|
|
|
568
509
|
}
|
|
569
510
|
return newSections;
|
|
570
511
|
}
|
|
571
|
-
function getValue(date, type) {
|
|
572
|
-
switch (type) {
|
|
573
|
-
case 'year':
|
|
574
|
-
case 'month':
|
|
575
|
-
case 'hour':
|
|
576
|
-
case 'minute':
|
|
577
|
-
case 'second': {
|
|
578
|
-
return date[type]();
|
|
579
|
-
}
|
|
580
|
-
case 'day': {
|
|
581
|
-
return date.date();
|
|
582
|
-
}
|
|
583
|
-
case 'weekday': {
|
|
584
|
-
return date.day();
|
|
585
|
-
}
|
|
586
|
-
case 'dayPeriod': {
|
|
587
|
-
return date.hour() >= 12 ? 12 : 0;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
return undefined;
|
|
591
|
-
}
|
|
592
|
-
function isHour12(section) {
|
|
593
|
-
if (section.type === 'hour') {
|
|
594
|
-
return (0, date_utils_1.dateTime)().set('hour', 15).format(section.format) !== '15';
|
|
595
|
-
}
|
|
596
|
-
return false;
|
|
597
|
-
}
|
|
598
|
-
function getSectionLimits(date, type, options) {
|
|
599
|
-
switch (type) {
|
|
600
|
-
case 'year': {
|
|
601
|
-
return {
|
|
602
|
-
minValue: 1,
|
|
603
|
-
maxValue: 9999,
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
case 'month': {
|
|
607
|
-
return {
|
|
608
|
-
minValue: 0,
|
|
609
|
-
maxValue: 11,
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
case 'weekday': {
|
|
613
|
-
return {
|
|
614
|
-
minValue: 0,
|
|
615
|
-
maxValue: 6,
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
case 'day': {
|
|
619
|
-
return {
|
|
620
|
-
minValue: 1,
|
|
621
|
-
maxValue: date ? date.daysInMonth() : 31,
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
case 'hour': {
|
|
625
|
-
if (options.hour12) {
|
|
626
|
-
const isPM = date.hour() >= 12;
|
|
627
|
-
return {
|
|
628
|
-
minValue: isPM ? 12 : 0,
|
|
629
|
-
maxValue: isPM ? 23 : 11,
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
return {
|
|
633
|
-
minValue: 0,
|
|
634
|
-
maxValue: 23,
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
case 'minute':
|
|
638
|
-
case 'second': {
|
|
639
|
-
return {
|
|
640
|
-
minValue: 0,
|
|
641
|
-
maxValue: 59,
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
return {};
|
|
646
|
-
}
|
|
647
|
-
function getDurationUnitFromSectionType(type) {
|
|
648
|
-
if (type === 'literal' || type === 'timeZoneName' || type === 'unknown') {
|
|
649
|
-
throw new Error(`${type} section does not have duration unit.`);
|
|
650
|
-
}
|
|
651
|
-
if (type in TYPE_MAPPING) {
|
|
652
|
-
return TYPE_MAPPING[type];
|
|
653
|
-
}
|
|
654
|
-
return type;
|
|
655
|
-
}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
|
+
import type { DateFieldSection, DateFieldSectionType, DateFieldSectionWithoutPosition } from './types';
|
|
2
3
|
export declare const isMac: boolean;
|
|
3
4
|
export declare const CtrlCmd: string;
|
|
4
5
|
export declare function expandFormat(format: string): string;
|
|
6
|
+
export declare function getSectionLimits(section: DateFieldSectionWithoutPosition, date: DateTime): {
|
|
7
|
+
minValue: number;
|
|
8
|
+
maxValue: number;
|
|
9
|
+
} | {
|
|
10
|
+
minValue?: undefined;
|
|
11
|
+
maxValue?: undefined;
|
|
12
|
+
};
|
|
13
|
+
export declare function getSectionValue(sections: DateFieldSectionWithoutPosition, date: DateTime): number | undefined;
|
|
14
|
+
export declare function getDurationUnitFromSectionType(type: DateFieldSectionType): "year" | "month" | "day" | "date" | "hour" | "minute" | "second";
|
|
15
|
+
export declare function addSegment(section: DateFieldSection, date: DateTime, amount: number): DateTime;
|
|
16
|
+
export declare function setSegment(section: DateFieldSection, date: DateTime, amount: number): DateTime;
|
|
5
17
|
export declare function splitFormatIntoSections(format: string): DateFieldSectionWithoutPosition[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.splitFormatIntoSections = exports.expandFormat = exports.CtrlCmd = exports.isMac = void 0;
|
|
3
|
+
exports.splitFormatIntoSections = exports.setSegment = exports.addSegment = exports.getDurationUnitFromSectionType = exports.getSectionValue = exports.getSectionLimits = exports.expandFormat = exports.CtrlCmd = exports.isMac = void 0;
|
|
4
4
|
const date_utils_1 = require("@gravity-ui/date-utils");
|
|
5
5
|
const i18n_1 = require("./i18n");
|
|
6
6
|
exports.isMac = window.navigator.userAgent.indexOf('Macintosh') >= 0;
|
|
@@ -81,6 +81,173 @@ function getDateSectionConfigFromFormatToken(formatToken) {
|
|
|
81
81
|
function isFourDigitYearFormat(format) {
|
|
82
82
|
return (0, date_utils_1.dateTime)().format(format).length === 4;
|
|
83
83
|
}
|
|
84
|
+
function isHour12(format) {
|
|
85
|
+
return (0, date_utils_1.dateTime)().set('hour', 15).format(format) !== '15';
|
|
86
|
+
}
|
|
87
|
+
function getSectionLimits(section, date) {
|
|
88
|
+
const { type, format } = section;
|
|
89
|
+
switch (type) {
|
|
90
|
+
case 'year': {
|
|
91
|
+
const isFourDigit = isFourDigitYearFormat(format);
|
|
92
|
+
return {
|
|
93
|
+
minValue: isFourDigit ? 1 : 0,
|
|
94
|
+
maxValue: isFourDigit ? 9999 : 99,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
case 'month': {
|
|
98
|
+
return {
|
|
99
|
+
minValue: 0,
|
|
100
|
+
maxValue: 11,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
case 'weekday': {
|
|
104
|
+
return {
|
|
105
|
+
minValue: 0,
|
|
106
|
+
maxValue: 6,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
case 'day': {
|
|
110
|
+
return {
|
|
111
|
+
minValue: 1,
|
|
112
|
+
maxValue: date ? date.daysInMonth() : 31,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
case 'hour': {
|
|
116
|
+
if (isHour12(format)) {
|
|
117
|
+
const isPM = date.hour() >= 12;
|
|
118
|
+
return {
|
|
119
|
+
minValue: isPM ? 12 : 0,
|
|
120
|
+
maxValue: isPM ? 23 : 11,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
minValue: 0,
|
|
125
|
+
maxValue: 23,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
case 'minute':
|
|
129
|
+
case 'second': {
|
|
130
|
+
return {
|
|
131
|
+
minValue: 0,
|
|
132
|
+
maxValue: 59,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
138
|
+
exports.getSectionLimits = getSectionLimits;
|
|
139
|
+
function getSectionValue(sections, date) {
|
|
140
|
+
const type = sections.type;
|
|
141
|
+
switch (type) {
|
|
142
|
+
case 'year': {
|
|
143
|
+
return isFourDigitYearFormat(sections.format)
|
|
144
|
+
? date.year()
|
|
145
|
+
: Number(date.format(sections.format));
|
|
146
|
+
}
|
|
147
|
+
case 'month':
|
|
148
|
+
case 'hour':
|
|
149
|
+
case 'minute':
|
|
150
|
+
case 'second': {
|
|
151
|
+
return date[type]();
|
|
152
|
+
}
|
|
153
|
+
case 'day': {
|
|
154
|
+
return date.date();
|
|
155
|
+
}
|
|
156
|
+
case 'weekday': {
|
|
157
|
+
return date.day();
|
|
158
|
+
}
|
|
159
|
+
case 'dayPeriod': {
|
|
160
|
+
return date.hour() >= 12 ? 12 : 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
exports.getSectionValue = getSectionValue;
|
|
166
|
+
const TYPE_MAPPING = {
|
|
167
|
+
weekday: 'day',
|
|
168
|
+
day: 'date',
|
|
169
|
+
dayPeriod: 'hour',
|
|
170
|
+
};
|
|
171
|
+
function getDurationUnitFromSectionType(type) {
|
|
172
|
+
if (type === 'literal' || type === 'timeZoneName' || type === 'unknown') {
|
|
173
|
+
throw new Error(`${type} section does not have duration unit.`);
|
|
174
|
+
}
|
|
175
|
+
if (type in TYPE_MAPPING) {
|
|
176
|
+
return TYPE_MAPPING[type];
|
|
177
|
+
}
|
|
178
|
+
return type;
|
|
179
|
+
}
|
|
180
|
+
exports.getDurationUnitFromSectionType = getDurationUnitFromSectionType;
|
|
181
|
+
function addSegment(section, date, amount) {
|
|
182
|
+
var _a;
|
|
183
|
+
let val = (_a = section.value) !== null && _a !== void 0 ? _a : 0;
|
|
184
|
+
if (section.type === 'dayPeriod') {
|
|
185
|
+
val = date.hour() + (date.hour() > 12 ? -12 : 12);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
val = val + amount;
|
|
189
|
+
const min = section.minValue;
|
|
190
|
+
const max = section.maxValue;
|
|
191
|
+
if (typeof min === 'number' && typeof max === 'number') {
|
|
192
|
+
const length = max - min + 1;
|
|
193
|
+
val = ((val - min + length) % length) + min;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (section.type === 'year' && !isFourDigitYearFormat(section.format)) {
|
|
197
|
+
val = (0, date_utils_1.dateTime)({ input: `${val}`.padStart(2, '0'), format: section.format }).year();
|
|
198
|
+
}
|
|
199
|
+
const type = getDurationUnitFromSectionType(section.type);
|
|
200
|
+
return date.set(type, val);
|
|
201
|
+
}
|
|
202
|
+
exports.addSegment = addSegment;
|
|
203
|
+
function setSegment(section, date, amount) {
|
|
204
|
+
const type = section.type;
|
|
205
|
+
switch (type) {
|
|
206
|
+
case 'year': {
|
|
207
|
+
return date.set('year', isFourDigitYearFormat(section.format)
|
|
208
|
+
? amount
|
|
209
|
+
: (0, date_utils_1.dateTime)({
|
|
210
|
+
input: `${amount}`.padStart(2, '0'),
|
|
211
|
+
format: section.format,
|
|
212
|
+
}).year());
|
|
213
|
+
}
|
|
214
|
+
case 'day':
|
|
215
|
+
case 'weekday':
|
|
216
|
+
case 'month': {
|
|
217
|
+
return date.set(getDurationUnitFromSectionType(type), amount);
|
|
218
|
+
}
|
|
219
|
+
case 'dayPeriod': {
|
|
220
|
+
const hours = date.hour();
|
|
221
|
+
const wasPM = hours >= 12;
|
|
222
|
+
const isPM = amount >= 12;
|
|
223
|
+
if (isPM === wasPM) {
|
|
224
|
+
return date;
|
|
225
|
+
}
|
|
226
|
+
return date.set('hour', wasPM ? hours - 12 : hours + 12);
|
|
227
|
+
}
|
|
228
|
+
case 'hour': {
|
|
229
|
+
// In 12 hour time, ensure that AM/PM does not change
|
|
230
|
+
let sectionAmount = amount;
|
|
231
|
+
if (section.minValue === 12 || section.maxValue === 11) {
|
|
232
|
+
const hours = date.hour();
|
|
233
|
+
const wasPM = hours >= 12;
|
|
234
|
+
if (!wasPM && sectionAmount === 12) {
|
|
235
|
+
sectionAmount = 0;
|
|
236
|
+
}
|
|
237
|
+
if (wasPM && sectionAmount < 12) {
|
|
238
|
+
sectionAmount += 12;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return date.set('hour', sectionAmount);
|
|
242
|
+
}
|
|
243
|
+
case 'minute':
|
|
244
|
+
case 'second': {
|
|
245
|
+
return date.set(type, amount);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return date;
|
|
249
|
+
}
|
|
250
|
+
exports.setSegment = setSegment;
|
|
84
251
|
function doesSectionHaveLeadingZeros(contentType, sectionType, format) {
|
|
85
252
|
if (contentType !== 'digit') {
|
|
86
253
|
return false;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
.g-date-date-picker {
|
|
2
2
|
position: relative;
|
|
3
3
|
display: inline-block;
|
|
4
|
+
outline: none;
|
|
4
5
|
}
|
|
5
6
|
.g-date-date-picker__field {
|
|
6
7
|
width: 100%;
|
|
@@ -8,6 +9,11 @@
|
|
|
8
9
|
.g-date-date-picker__field_mobile {
|
|
9
10
|
pointer-events: none;
|
|
10
11
|
}
|
|
12
|
+
.g-date-date-picker__popup-anchor {
|
|
13
|
+
position: absolute;
|
|
14
|
+
z-index: -1;
|
|
15
|
+
inset: 0;
|
|
16
|
+
}
|
|
11
17
|
.g-date-date-picker__popup-content {
|
|
12
18
|
outline: none;
|
|
13
19
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type
|
|
2
|
+
import { type CalendarProps } from '../Calendar';
|
|
3
3
|
import type { AccessibilityProps, DateFieldBase, DomProps, FocusableProps, KeyboardEvents, StyleProps, TextInputProps } from '../types';
|
|
4
4
|
import './DatePicker.css';
|
|
5
5
|
export interface DatePickerProps extends DateFieldBase, TextInputProps, FocusableProps, KeyboardEvents, DomProps, StyleProps, AccessibilityProps {
|
|
6
6
|
children?: (props: CalendarProps) => React.ReactNode;
|
|
7
7
|
}
|
|
8
|
-
export declare function DatePicker({ value, defaultValue, onUpdate, className,
|
|
8
|
+
export declare function DatePicker({ value, defaultValue, onUpdate, className, ...props }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -17,50 +17,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.DatePicker = void 0;
|
|
18
18
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
19
19
|
const react_1 = __importDefault(require("react"));
|
|
20
|
+
const icons_1 = require("@gravity-ui/icons");
|
|
20
21
|
const uikit_1 = require("@gravity-ui/uikit");
|
|
22
|
+
const Calendar_1 = require("../Calendar");
|
|
21
23
|
const DateField_1 = require("../DateField");
|
|
22
|
-
const DesktopCalendar_1 = require("./DesktopCalendar");
|
|
23
24
|
const MobileCalendar_1 = require("./MobileCalendar");
|
|
25
|
+
const useDatePickerProps_1 = require("./hooks/useDatePickerProps");
|
|
24
26
|
const useDatePickerState_1 = require("./hooks/useDatePickerState");
|
|
25
27
|
const utils_1 = require("./utils");
|
|
26
28
|
require("./DatePicker.css");
|
|
27
29
|
function DatePicker(_a) {
|
|
28
|
-
var { value, defaultValue, onUpdate, className
|
|
30
|
+
var { value, defaultValue, onUpdate, className } = _a, props = __rest(_a, ["value", "defaultValue", "onUpdate", "className"]);
|
|
29
31
|
const anchorRef = react_1.default.useRef(null);
|
|
30
32
|
const state = (0, useDatePickerState_1.useDatePickerState)(Object.assign(Object.assign({}, props), { value,
|
|
31
33
|
defaultValue,
|
|
32
34
|
onUpdate }));
|
|
35
|
+
const { groupProps, fieldProps, calendarButtonProps, popupProps, calendarProps, timeInputProps } = (0, useDatePickerProps_1.useDatePickerProps)(state, props);
|
|
33
36
|
const [isMobile] = (0, uikit_1.useMobile)();
|
|
34
|
-
|
|
35
|
-
const { focusWithinProps } = (0, uikit_1.useFocusWithin)({
|
|
36
|
-
onFocusWithin: onFocus,
|
|
37
|
-
onBlurWithin: onBlur,
|
|
38
|
-
onFocusWithinChange(isFocusWithin) {
|
|
39
|
-
setActive(isFocusWithin);
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
const fieldState = (0, DateField_1.useDateFieldState)({
|
|
43
|
-
value: state.value,
|
|
44
|
-
onUpdate: state.setValue,
|
|
45
|
-
disabled: state.disabled,
|
|
46
|
-
readOnly: state.readOnly,
|
|
47
|
-
validationState: props.validationState,
|
|
48
|
-
minValue: props.minValue,
|
|
49
|
-
maxValue: props.maxValue,
|
|
50
|
-
isDateUnavailable: props.isDateUnavailable,
|
|
51
|
-
format: state.format,
|
|
52
|
-
placeholderValue: props.placeholderValue,
|
|
53
|
-
timeZone: props.timeZone,
|
|
54
|
-
});
|
|
55
|
-
const { inputProps } = (0, DateField_1.useDateFieldProps)(fieldState, props);
|
|
56
|
-
return (
|
|
57
|
-
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
|
|
58
|
-
(0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: anchorRef, className: (0, utils_1.b)(null, className), style: props.style }, focusWithinProps, { role: "group", "aria-disabled": state.disabled || undefined, onKeyDown: (e) => {
|
|
59
|
-
if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
60
|
-
e.preventDefault();
|
|
61
|
-
e.stopPropagation();
|
|
62
|
-
state.setOpen(true);
|
|
63
|
-
}
|
|
64
|
-
}, children: [isMobile ? ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendar, { props: props, state: state })) : ((0, jsx_runtime_1.jsx)(DesktopCalendar_1.DesktopCalendar, { anchorRef: anchorRef, props: props, state: state, renderCalendar: children })), (0, jsx_runtime_1.jsx)(uikit_1.TextInput, Object.assign({}, inputProps, { value: fieldState.isEmpty && !isActive && props.placeholder ? '' : inputProps.value, className: (0, utils_1.b)('field', { mobile: isMobile }), hasClear: !isMobile && inputProps.hasClear, rightContent: isMobile ? ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendarIcon, { props: props, state: state })) : ((0, jsx_runtime_1.jsx)(DesktopCalendar_1.DesktopCalendarButton, { props: props, state: state })) }))] })));
|
|
37
|
+
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ className: (0, utils_1.b)(null, className) }, groupProps, { children: [isMobile ? ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendar, { props: props, state: state })) : ((0, jsx_runtime_1.jsx)("div", { ref: anchorRef, className: (0, utils_1.b)('popup-anchor'), children: (0, jsx_runtime_1.jsx)(uikit_1.Popup, Object.assign({ anchorRef: anchorRef }, popupProps, { children: (0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.b)('popup-content'), children: [typeof props.children === 'function' ? (props.children(calendarProps)) : ((0, jsx_runtime_1.jsx)(Calendar_1.Calendar, Object.assign({}, calendarProps))), state.hasTime && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.b)('time-field-wrapper'), children: (0, jsx_runtime_1.jsx)(DateField_1.DateField, Object.assign({}, timeInputProps)) }))] }) })) })), (0, jsx_runtime_1.jsx)(uikit_1.TextInput, Object.assign({}, fieldProps, { className: (0, utils_1.b)('field', { mobile: isMobile }), hasClear: !isMobile && fieldProps.hasClear, rightContent: isMobile ? ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendarIcon, { props: props, state: state })) : ((0, jsx_runtime_1.jsx)(uikit_1.Button, Object.assign({}, calendarButtonProps, { children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.Calendar }) }))) }))] })));
|
|
65
38
|
}
|
|
66
39
|
exports.DatePicker = DatePicker;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ButtonProps, PopupProps, TextInputProps } from '@gravity-ui/uikit';
|
|
3
|
+
import type { Calendar } from '../../Calendar';
|
|
4
|
+
import type { DateFieldProps } from '../../DateField';
|
|
5
|
+
import type { DatePickerProps } from '../DatePicker';
|
|
6
|
+
import type { DatePickerState } from './useDatePickerState';
|
|
7
|
+
interface InnerRelativeDatePickerProps {
|
|
8
|
+
groupProps: React.HTMLAttributes<unknown> & {
|
|
9
|
+
ref: React.Ref<any>;
|
|
10
|
+
};
|
|
11
|
+
fieldProps: TextInputProps;
|
|
12
|
+
calendarButtonProps: ButtonProps & {
|
|
13
|
+
ref: React.Ref<HTMLButtonElement>;
|
|
14
|
+
};
|
|
15
|
+
popupProps: PopupProps;
|
|
16
|
+
calendarProps: React.ComponentProps<typeof Calendar>;
|
|
17
|
+
timeInputProps: DateFieldProps;
|
|
18
|
+
}
|
|
19
|
+
export declare function useDatePickerProps(state: DatePickerState, { onFocus, onBlur, ...props }: DatePickerProps): InnerRelativeDatePickerProps;
|
|
20
|
+
export {};
|