@gravity-ui/date-components 1.0.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 (69) hide show
  1. package/dist/cjs/components/Calendar/Calendar.css +9 -1
  2. package/dist/cjs/components/Calendar/CalendarBase.js +9 -9
  3. package/dist/cjs/components/Calendar/hooks/types.d.ts +5 -2
  4. package/dist/cjs/components/Calendar/hooks/useCalendarCellProps.js +21 -16
  5. package/dist/cjs/components/Calendar/hooks/useCalendarGridProps.js +2 -7
  6. package/dist/cjs/components/Calendar/hooks/useCalendarProps.js +6 -3
  7. package/dist/cjs/components/Calendar/hooks/useCalendarState.js +69 -26
  8. package/dist/cjs/components/Calendar/hooks/useRangeCalendarState.js +16 -11
  9. package/dist/cjs/components/Calendar/utils.d.ts +3 -1
  10. package/dist/cjs/components/Calendar/utils.js +7 -1
  11. package/dist/cjs/components/DateField/hooks/useDateFieldProps.js +23 -16
  12. package/dist/cjs/components/DateField/hooks/useDateFieldState.d.ts +2 -0
  13. package/dist/cjs/components/DateField/hooks/useDateFieldState.js +49 -166
  14. package/dist/cjs/components/DateField/types.d.ts +1 -1
  15. package/dist/cjs/components/DateField/utils.d.ts +12 -9
  16. package/dist/cjs/components/DateField/utils.js +168 -25
  17. package/dist/cjs/components/DatePicker/DatePicker.css +6 -0
  18. package/dist/cjs/components/DatePicker/DatePicker.d.ts +4 -1
  19. package/dist/cjs/components/DatePicker/DatePicker.js +6 -33
  20. package/dist/cjs/components/DatePicker/MobileCalendar.js +4 -4
  21. package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
  22. package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.js +134 -0
  23. package/dist/cjs/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
  24. package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +18 -8
  25. package/dist/cjs/components/DatePicker/index.d.ts +1 -0
  26. package/dist/cjs/components/DatePicker/index.js +1 -0
  27. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
  28. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.d.ts +3 -0
  29. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.js +1 -1
  30. package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +35 -27
  31. package/dist/cjs/components/utils/dates.d.ts +9 -0
  32. package/dist/cjs/components/utils/dates.js +28 -0
  33. package/dist/esm/components/Calendar/Calendar.css +9 -1
  34. package/dist/esm/components/Calendar/CalendarBase.js +10 -10
  35. package/dist/esm/components/Calendar/hooks/types.d.ts +5 -2
  36. package/dist/esm/components/Calendar/hooks/useCalendarCellProps.js +21 -16
  37. package/dist/esm/components/Calendar/hooks/useCalendarGridProps.js +2 -7
  38. package/dist/esm/components/Calendar/hooks/useCalendarProps.js +6 -3
  39. package/dist/esm/components/Calendar/hooks/useCalendarState.js +70 -27
  40. package/dist/esm/components/Calendar/hooks/useRangeCalendarState.js +16 -11
  41. package/dist/esm/components/Calendar/utils.d.ts +3 -1
  42. package/dist/esm/components/Calendar/utils.js +6 -0
  43. package/dist/esm/components/DateField/hooks/useDateFieldProps.js +23 -16
  44. package/dist/esm/components/DateField/hooks/useDateFieldState.d.ts +2 -0
  45. package/dist/esm/components/DateField/hooks/useDateFieldState.js +41 -158
  46. package/dist/esm/components/DateField/types.d.ts +1 -1
  47. package/dist/esm/components/DateField/utils.d.ts +12 -9
  48. package/dist/esm/components/DateField/utils.js +162 -21
  49. package/dist/esm/components/DatePicker/DatePicker.css +6 -0
  50. package/dist/esm/components/DatePicker/DatePicker.d.ts +4 -1
  51. package/dist/esm/components/DatePicker/DatePicker.js +8 -35
  52. package/dist/esm/components/DatePicker/MobileCalendar.js +1 -1
  53. package/dist/esm/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
  54. package/dist/esm/components/DatePicker/hooks/useDatePickerProps.js +127 -0
  55. package/dist/esm/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
  56. package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +17 -7
  57. package/dist/esm/components/DatePicker/index.d.ts +1 -0
  58. package/dist/esm/components/DatePicker/index.js +1 -0
  59. package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
  60. package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.d.ts +3 -0
  61. package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.js +1 -1
  62. package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +35 -27
  63. package/dist/esm/components/utils/dates.d.ts +9 -0
  64. package/dist/esm/components/utils/dates.js +22 -0
  65. package/package.json +8 -7
  66. package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +0 -15
  67. package/dist/cjs/components/DatePicker/DesktopCalendar.js +0 -56
  68. package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +0 -15
  69. package/dist/esm/components/DatePicker/DesktopCalendar.js +0 -48
@@ -7,6 +7,7 @@ exports.useDateFieldState = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const date_utils_1 = require("@gravity-ui/date-utils");
9
9
  const useControlledState_1 = require("../../hooks/useControlledState");
10
+ const dates_1 = require("../../utils/dates");
10
11
  const utils_1 = require("../utils");
11
12
  const EDITABLE_SEGMENTS = {
12
13
  year: true,
@@ -18,11 +19,6 @@ const EDITABLE_SEGMENTS = {
18
19
  dayPeriod: true,
19
20
  weekday: true,
20
21
  };
21
- const TYPE_MAPPING = {
22
- weekday: 'day',
23
- day: 'date',
24
- dayPeriod: 'hour',
25
- };
26
22
  const PAGE_STEP = {
27
23
  year: 5,
28
24
  month: 2,
@@ -36,7 +32,7 @@ function useDateFieldState(props) {
36
32
  var _a;
37
33
  const [value, setDate] = (0, useControlledState_1.useControlledState)(props.value, props.defaultValue, props.onUpdate);
38
34
  const [placeholderDate, setPlaceholderDate] = react_1.default.useState(() => {
39
- return (0, utils_1.createPlaceholderValue)({
35
+ return (0, dates_1.createPlaceholderValue)({
40
36
  placeholderValue: props.placeholderValue,
41
37
  timeZone: props.timeZone,
42
38
  });
@@ -60,7 +56,7 @@ function useDateFieldState(props) {
60
56
  Object.keys(validSegments).length === Object.keys(allSegments).length) {
61
57
  validSegments = {};
62
58
  setValidSegments(validSegments);
63
- setPlaceholderDate((0, utils_1.createPlaceholderValue)({ timeZone: props.timeZone }));
59
+ setPlaceholderDate((0, dates_1.createPlaceholderValue)({ timeZone: props.timeZone }));
64
60
  }
65
61
  const displayValue = value &&
66
62
  (0, date_utils_1.isValid)(value) &&
@@ -68,10 +64,7 @@ function useDateFieldState(props) {
68
64
  ? value
69
65
  : placeholderDate;
70
66
  const sectionsState = useSectionsState(sections, displayValue, validSegments);
71
- const [selectedSections, setSelectedSections] = react_1.default.useState(() => {
72
- var _a, _b;
73
- return (_b = (_a = sectionsState.editableSections[0]) === null || _a === void 0 ? void 0 : _a.previousEditableSection) !== null && _b !== void 0 ? _b : -1;
74
- });
67
+ const [selectedSections, setSelectedSections] = react_1.default.useState(-1);
75
68
  const selectedSectionIndexes = react_1.default.useMemo(() => {
76
69
  if (selectedSections === -1) {
77
70
  return null;
@@ -96,9 +89,14 @@ function useDateFieldState(props) {
96
89
  return;
97
90
  }
98
91
  if (Object.keys(validSegments).length >= Object.keys(allSegments).length) {
99
- setDate(newValue);
92
+ if (!value || !newValue.isSame(value)) {
93
+ setDate(newValue);
94
+ }
100
95
  }
101
96
  else {
97
+ if (value) {
98
+ setDate(null);
99
+ }
102
100
  setPlaceholderDate(newValue);
103
101
  }
104
102
  }
@@ -114,12 +112,12 @@ function useDateFieldState(props) {
114
112
  }
115
113
  function setSection(section, amount) {
116
114
  markValid(section.type);
117
- setValue(setSegment(section, displayValue, amount));
115
+ setValue((0, utils_1.setSegment)(section, displayValue, amount));
118
116
  }
119
117
  function adjustSection(sectionIndex, amount) {
120
118
  const section = sectionsState.editableSections[sectionIndex];
121
119
  if (validSegments[section.type]) {
122
- setValue(addSegment(section, displayValue, amount));
120
+ setValue((0, utils_1.addSegment)(section, displayValue, amount));
123
121
  }
124
122
  else {
125
123
  markValid(section.type);
@@ -130,7 +128,7 @@ function useDateFieldState(props) {
130
128
  }
131
129
  const enteredKeys = react_1.default.useRef('');
132
130
  const validationState = props.validationState ||
133
- ((0, utils_1.isInvalid)(value, props.minValue, props.maxValue) ? 'invalid' : undefined) ||
131
+ ((0, dates_1.isInvalid)(value, props.minValue, props.maxValue) ? 'invalid' : undefined) ||
134
132
  (value && ((_a = props.isDateUnavailable) === null || _a === void 0 ? void 0 : _a.call(props, value)) ? 'invalid' : undefined);
135
133
  return {
136
134
  value: value !== null && value !== void 0 ? value : null,
@@ -225,6 +223,32 @@ function useDateFieldState(props) {
225
223
  adjustSection(sectionIndex, -(PAGE_STEP[this.sections[sectionIndex].type] || 1));
226
224
  }
227
225
  },
226
+ incrementToMax() {
227
+ if (this.readOnly || this.disabled) {
228
+ return;
229
+ }
230
+ enteredKeys.current = '';
231
+ const sectionIndex = getCurrentEditableSectionIndex(this.sections, selectedSections);
232
+ if (sectionIndex !== -1) {
233
+ const section = this.sections[sectionIndex];
234
+ if (typeof section.maxValue === 'number') {
235
+ setSection(section, section.maxValue);
236
+ }
237
+ }
238
+ },
239
+ decrementToMin() {
240
+ if (this.readOnly || this.disabled) {
241
+ return;
242
+ }
243
+ enteredKeys.current = '';
244
+ const sectionIndex = getCurrentEditableSectionIndex(this.sections, selectedSections);
245
+ if (sectionIndex !== -1) {
246
+ const section = this.sections[sectionIndex];
247
+ if (typeof section.minValue === 'number') {
248
+ setSection(section, section.minValue);
249
+ }
250
+ }
251
+ },
228
252
  clearSection() {
229
253
  if (this.readOnly || this.disabled) {
230
254
  return;
@@ -241,7 +265,7 @@ function useDateFieldState(props) {
241
265
  const section = this.sections[sectionIndex];
242
266
  delete validSegments[section.type];
243
267
  setValidSegments(Object.assign({}, validSegments));
244
- const placeholder = (0, utils_1.createPlaceholderValue)({
268
+ const placeholder = (0, dates_1.createPlaceholderValue)({
245
269
  placeholderValue: props.placeholderValue,
246
270
  timeZone: props.timeZone,
247
271
  });
@@ -258,12 +282,9 @@ function useDateFieldState(props) {
258
282
  }
259
283
  }
260
284
  else {
261
- const type = getDurationUnitFromSectionType(section.type);
285
+ const type = (0, utils_1.getDurationUnitFromSectionType)(section.type);
262
286
  currentValue = displayValue.set(type, placeholder[type]());
263
287
  }
264
- if (value) {
265
- setDate(null);
266
- }
267
288
  setValue(currentValue);
268
289
  },
269
290
  clearAll() {
@@ -276,7 +297,7 @@ function useDateFieldState(props) {
276
297
  if (value !== null) {
277
298
  setDate(null);
278
299
  }
279
- setValue((0, utils_1.createPlaceholderValue)({
300
+ setValue((0, dates_1.createPlaceholderValue)({
280
301
  placeholderValue: props.placeholderValue,
281
302
  timeZone: props.timeZone,
282
303
  }));
@@ -390,11 +411,12 @@ function useDateFieldState(props) {
390
411
  }
391
412
  },
392
413
  setValueFromString(str) {
414
+ enteredKeys.current = '';
393
415
  let date = parseDate({ input: str, format, timeZone: props.timeZone });
394
416
  if ((0, date_utils_1.isValid)(date)) {
395
417
  if (props.timeZone && !isDateStringWithTimeZone(str)) {
396
418
  const time = parseDate({ input: str, format });
397
- date = (0, utils_1.mergeDateTime)(date, time);
419
+ date = (0, dates_1.mergeDateTime)(date, time);
398
420
  }
399
421
  setDate(date);
400
422
  return true;
@@ -414,64 +436,6 @@ function parseDate(options) {
414
436
  function isDateStringWithTimeZone(str) {
415
437
  return /z$/i.test(str) || /[+-]\d\d:\d\d$/.test(str);
416
438
  }
417
- function addSegment(section, date, amount) {
418
- var _a;
419
- let val = (_a = section.value) !== null && _a !== void 0 ? _a : 0;
420
- if (section.type === 'dayPeriod') {
421
- val = date.hour() + (date.hour() > 12 ? -12 : 12);
422
- }
423
- else {
424
- val = val + amount;
425
- const min = section.minValue;
426
- const max = section.maxValue;
427
- if (typeof min === 'number' && typeof max === 'number') {
428
- const length = max - min + 1;
429
- val = ((val - min + length) % length) + min;
430
- }
431
- }
432
- const type = getDurationUnitFromSectionType(section.type);
433
- return date.set(type, val);
434
- }
435
- function setSegment(section, date, amount) {
436
- const type = section.type;
437
- switch (type) {
438
- case 'day':
439
- case 'weekday':
440
- case 'month':
441
- case 'year': {
442
- return date.set(getDurationUnitFromSectionType(type), amount);
443
- }
444
- case 'dayPeriod': {
445
- const hours = date.hour();
446
- const wasPM = hours >= 12;
447
- const isPM = amount >= 12;
448
- if (isPM === wasPM) {
449
- return date;
450
- }
451
- return date.set('hour', wasPM ? hours - 12 : hours + 12);
452
- }
453
- case 'hour': {
454
- // In 12 hour time, ensure that AM/PM does not change
455
- let sectionAmount = amount;
456
- if (section.minValue === 12 || section.maxValue === 11) {
457
- const hours = date.hour();
458
- const wasPM = hours >= 12;
459
- if (!wasPM && sectionAmount === 12) {
460
- sectionAmount = 0;
461
- }
462
- if (wasPM && sectionAmount < 12) {
463
- sectionAmount += 12;
464
- }
465
- }
466
- return date.set('hour', sectionAmount);
467
- }
468
- case 'minute':
469
- case 'second': {
470
- return date.set(type, amount);
471
- }
472
- }
473
- return date;
474
- }
475
439
  function getCurrentEditableSectionIndex(sections, selectedSections) {
476
440
  const currentIndex = selectedSections === 'all' || selectedSections === -1 ? 0 : selectedSections;
477
441
  const section = sections[currentIndex];
@@ -521,9 +485,13 @@ function getEditableSections(sections, value, validSegments) {
521
485
  let renderedValue = section.placeholder;
522
486
  if ((isEditable && validSegments[section.type]) || section.type === 'timeZoneName') {
523
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
+ }
524
492
  }
525
493
  const sectionLength = renderedValue.length;
526
- 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));
527
495
  newSections.push(newSection);
528
496
  if (isEditable) {
529
497
  for (let j = Math.max(0, previousEditableSection); j <= i; j++) {
@@ -541,88 +509,3 @@ function getEditableSections(sections, value, validSegments) {
541
509
  }
542
510
  return newSections;
543
511
  }
544
- function getValue(date, type) {
545
- switch (type) {
546
- case 'year':
547
- case 'month':
548
- case 'hour':
549
- case 'minute':
550
- case 'second': {
551
- return date[type]();
552
- }
553
- case 'day': {
554
- return date.date();
555
- }
556
- case 'weekday': {
557
- return date.day();
558
- }
559
- case 'dayPeriod': {
560
- return date.hour() >= 12 ? 12 : 0;
561
- }
562
- }
563
- return undefined;
564
- }
565
- function isHour12(section) {
566
- if (section.type === 'hour') {
567
- return (0, date_utils_1.dateTime)().set('hour', 15).format(section.format) !== '15';
568
- }
569
- return false;
570
- }
571
- function getSectionLimits(date, type, options) {
572
- switch (type) {
573
- case 'year': {
574
- return {
575
- minValue: 1,
576
- maxValue: 9999,
577
- };
578
- }
579
- case 'month': {
580
- return {
581
- minValue: 0,
582
- maxValue: 11,
583
- };
584
- }
585
- case 'weekday': {
586
- return {
587
- minValue: 0,
588
- maxValue: 6,
589
- };
590
- }
591
- case 'day': {
592
- return {
593
- minValue: 1,
594
- maxValue: date ? date.daysInMonth() : 31,
595
- };
596
- }
597
- case 'hour': {
598
- if (options.hour12) {
599
- const isPM = date.hour() >= 12;
600
- return {
601
- minValue: isPM ? 12 : 0,
602
- maxValue: isPM ? 23 : 11,
603
- };
604
- }
605
- return {
606
- minValue: 0,
607
- maxValue: 23,
608
- };
609
- }
610
- case 'minute':
611
- case 'second': {
612
- return {
613
- minValue: 0,
614
- maxValue: 59,
615
- };
616
- }
617
- }
618
- return {};
619
- }
620
- function getDurationUnitFromSectionType(type) {
621
- if (type === 'literal' || type === 'timeZoneName' || type === 'unknown') {
622
- throw new Error(`${type} section does not have duration unit.`);
623
- }
624
- if (type in TYPE_MAPPING) {
625
- return TYPE_MAPPING[type];
626
- }
627
- return type;
628
- }
@@ -1,4 +1,4 @@
1
- export type DateFieldSectionType = Exclude<Intl.DateTimeFormatPartTypes, 'era'>;
1
+ export type DateFieldSectionType = Extract<Intl.DateTimeFormatPartTypes, 'day' | 'dayPeriod' | 'hour' | 'literal' | 'minute' | 'month' | 'second' | 'timeZoneName' | 'weekday' | 'year' | 'unknown'>;
2
2
  export type DateFormatTokenMap = {
3
3
  [formatToken: string]: DateFieldSectionType | {
4
4
  sectionType: DateFieldSectionType;
@@ -1,14 +1,17 @@
1
1
  import type { DateTime } from '@gravity-ui/date-utils';
2
- import type { DateFieldSectionWithoutPosition } from './types';
2
+ import type { DateFieldSection, DateFieldSectionType, DateFieldSectionWithoutPosition } from './types';
3
3
  export declare const isMac: boolean;
4
4
  export declare const CtrlCmd: string;
5
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;
6
17
  export declare function splitFormatIntoSections(format: string): DateFieldSectionWithoutPosition[];
7
- interface PlaceholderValueOptions {
8
- placeholderValue?: DateTime;
9
- timeZone?: string;
10
- }
11
- export declare function createPlaceholderValue({ placeholderValue, timeZone }: PlaceholderValueOptions): DateTime;
12
- export declare function isInvalid(value: DateTime | null | undefined, minValue: DateTime | undefined, maxValue: DateTime | undefined): boolean;
13
- export declare function mergeDateTime(date: DateTime, time: DateTime): DateTime;
14
- export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mergeDateTime = exports.isInvalid = exports.createPlaceholderValue = 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;
@@ -250,27 +417,3 @@ function getSectionOptions(section, token) {
250
417
  }
251
418
  return undefined;
252
419
  }
253
- function createPlaceholderValue({ placeholderValue, timeZone }) {
254
- return (placeholderValue !== null && placeholderValue !== void 0 ? placeholderValue : (0, date_utils_1.dateTime)({ timeZone }).set('hour', 0).set('minute', 0).set('second', 0));
255
- }
256
- exports.createPlaceholderValue = createPlaceholderValue;
257
- function isInvalid(value, minValue, maxValue) {
258
- if (!value) {
259
- return false;
260
- }
261
- if (minValue && value.isBefore(minValue)) {
262
- return true;
263
- }
264
- if (maxValue && maxValue.isBefore(value)) {
265
- return true;
266
- }
267
- return false;
268
- }
269
- exports.isInvalid = isInvalid;
270
- function mergeDateTime(date, time) {
271
- return date
272
- .set('hours', time.hour())
273
- .set('minutes', time.minute())
274
- .set('seconds', time.second());
275
- }
276
- exports.mergeDateTime = mergeDateTime;
@@ -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,5 +1,8 @@
1
+ import React from 'react';
2
+ import { type CalendarProps } from '../Calendar';
1
3
  import type { AccessibilityProps, DateFieldBase, DomProps, FocusableProps, KeyboardEvents, StyleProps, TextInputProps } from '../types';
2
4
  import './DatePicker.css';
3
5
  export interface DatePickerProps extends DateFieldBase, TextInputProps, FocusableProps, KeyboardEvents, DomProps, StyleProps, AccessibilityProps {
6
+ children?: (props: CalendarProps) => React.ReactNode;
4
7
  }
5
- export declare function DatePicker({ value, defaultValue, onUpdate, className, onFocus, onBlur, ...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 } = _a, props = __rest(_a, ["value", "defaultValue", "onUpdate", "className", "onFocus", "onBlur"]);
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 })), (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;