@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.
Files changed (37) hide show
  1. package/dist/cjs/components/Calendar/hooks/useRangeCalendarState.js +10 -5
  2. package/dist/cjs/components/DateField/hooks/useDateFieldProps.js +21 -14
  3. package/dist/cjs/components/DateField/hooks/useDateFieldState.js +16 -160
  4. package/dist/cjs/components/DateField/utils.d.ts +13 -1
  5. package/dist/cjs/components/DateField/utils.js +168 -1
  6. package/dist/cjs/components/DatePicker/DatePicker.css +6 -0
  7. package/dist/cjs/components/DatePicker/DatePicker.d.ts +2 -2
  8. package/dist/cjs/components/DatePicker/DatePicker.js +6 -33
  9. package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
  10. package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.js +134 -0
  11. package/dist/cjs/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
  12. package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +15 -0
  13. package/dist/cjs/components/DatePicker/index.d.ts +1 -0
  14. package/dist/cjs/components/DatePicker/index.js +1 -0
  15. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
  16. package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +29 -27
  17. package/dist/esm/components/Calendar/hooks/useRangeCalendarState.js +10 -5
  18. package/dist/esm/components/DateField/hooks/useDateFieldProps.js +21 -14
  19. package/dist/esm/components/DateField/hooks/useDateFieldState.js +14 -158
  20. package/dist/esm/components/DateField/utils.d.ts +13 -1
  21. package/dist/esm/components/DateField/utils.js +162 -0
  22. package/dist/esm/components/DatePicker/DatePicker.css +6 -0
  23. package/dist/esm/components/DatePicker/DatePicker.d.ts +2 -2
  24. package/dist/esm/components/DatePicker/DatePicker.js +8 -35
  25. package/dist/esm/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
  26. package/dist/esm/components/DatePicker/hooks/useDatePickerProps.js +127 -0
  27. package/dist/esm/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
  28. package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +15 -0
  29. package/dist/esm/components/DatePicker/index.d.ts +1 -0
  30. package/dist/esm/components/DatePicker/index.js +1 -0
  31. package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
  32. package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +29 -27
  33. package/package.json +8 -7
  34. package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +0 -17
  35. package/dist/cjs/components/DatePicker/DesktopCalendar.js +0 -65
  36. package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +0 -17
  37. 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 selectDate = (date) => {
32
- if (props.disabled || props.readOnly) {
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 = inputRef.current;
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.nativeEvent.data;
173
- // eslint-disable-next-line no-eq-null, eqeqeq
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.setValueFromString(pastedValue)) {
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' && /^\d+$/.test(pastedValue)) ||
193
- activeSection.contentType === 'letter');
194
- if (!isValidValue) {
195
- e.preventDefault();
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
- setDate(newValue);
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: getValue(value, section.type), textValue: renderedValue, start: position, end: position + sectionLength, modified: false, previousEditableSection, nextEditableSection: previousEditableSection }), getSectionLimits(value, section.type, { hour12: isHour12(section) }));
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 { DateFieldSectionWithoutPosition } from './types';
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 { CalendarProps } from '../Calendar';
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, onFocus, onBlur, children, ...props }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
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, onFocus, onBlur, children } = _a, props = __rest(_a, ["value", "defaultValue", "onUpdate", "className", "onFocus", "onBlur", "children"]);
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
- const [isActive, setActive] = react_1.default.useState(false);
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 {};