@gravity-ui/date-components 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/cjs/components/Calendar/Calendar.css +37 -37
  2. package/dist/cjs/components/Calendar/Calendar.js +2 -4
  3. package/dist/cjs/components/Calendar/CalendarBase.js +2 -4
  4. package/dist/cjs/components/Calendar/RangeCalendar.js +2 -4
  5. package/dist/cjs/components/Calendar/hooks/useCalendarCellProps.js +2 -4
  6. package/dist/cjs/components/Calendar/hooks/useCalendarGridProps.js +11 -0
  7. package/dist/cjs/components/Calendar/hooks/useCalendarProps.js +2 -4
  8. package/dist/cjs/components/Calendar/hooks/useCalendarState.js +2 -4
  9. package/dist/cjs/components/Calendar/hooks/useRangeCalendarState.js +13 -21
  10. package/dist/cjs/components/Calendar/i18n/index.js +3 -5
  11. package/dist/cjs/components/Calendar/index.js +8 -21
  12. package/dist/cjs/components/DateField/DateField.js +3 -16
  13. package/dist/cjs/components/DateField/hooks/useDateFieldProps.js +25 -20
  14. package/dist/cjs/components/DateField/hooks/useDateFieldState.js +23 -167
  15. package/dist/cjs/components/DateField/i18n/index.js +3 -5
  16. package/dist/cjs/components/DateField/index.js +4 -17
  17. package/dist/cjs/components/DateField/utils.d.ts +14 -3
  18. package/dist/cjs/components/DateField/utils.js +172 -3
  19. package/dist/cjs/components/DatePicker/DatePicker.css +6 -0
  20. package/dist/cjs/components/DatePicker/DatePicker.d.ts +2 -2
  21. package/dist/cjs/components/DatePicker/DatePicker.js +8 -48
  22. package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
  23. package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.js +121 -0
  24. package/dist/cjs/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
  25. package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +17 -4
  26. package/dist/cjs/components/DatePicker/i18n/index.js +3 -5
  27. package/dist/cjs/components/DatePicker/index.d.ts +1 -0
  28. package/dist/cjs/components/DatePicker/index.js +4 -16
  29. package/dist/cjs/components/RelativeDateField/RelativeDateField.js +2 -4
  30. package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldProps.js +2 -4
  31. package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldState.js +2 -4
  32. package/dist/cjs/components/RelativeDateField/index.js +4 -17
  33. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
  34. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.js +2 -4
  35. package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +32 -43
  36. package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerState.js +2 -4
  37. package/dist/cjs/components/RelativeDatePicker/i18n/index.js +3 -5
  38. package/dist/cjs/components/RelativeDatePicker/index.js +4 -17
  39. package/dist/cjs/components/hooks/useControlledState.js +2 -4
  40. package/dist/cjs/components/index.js +6 -19
  41. package/dist/cjs/index.js +2 -15
  42. package/dist/esm/components/Calendar/Calendar.css +37 -37
  43. package/dist/esm/components/Calendar/hooks/useCalendarGridProps.js +11 -0
  44. package/dist/esm/components/Calendar/hooks/useRangeCalendarState.js +11 -16
  45. package/dist/esm/components/DateField/DateField.js +1 -11
  46. package/dist/esm/components/DateField/hooks/useDateFieldProps.js +24 -17
  47. package/dist/esm/components/DateField/hooks/useDateFieldState.js +19 -161
  48. package/dist/esm/components/DateField/utils.d.ts +14 -3
  49. package/dist/esm/components/DateField/utils.js +165 -2
  50. package/dist/esm/components/DatePicker/DatePicker.css +6 -0
  51. package/dist/esm/components/DatePicker/DatePicker.d.ts +2 -2
  52. package/dist/esm/components/DatePicker/DatePicker.js +9 -46
  53. package/dist/esm/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
  54. package/dist/esm/components/DatePicker/hooks/useDatePickerProps.js +117 -0
  55. package/dist/esm/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
  56. package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +15 -0
  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/hooks/useRelativeDatePickerProps.js +30 -38
  61. package/package.json +37 -33
  62. package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +0 -17
  63. package/dist/cjs/components/DatePicker/DesktopCalendar.js +0 -65
  64. package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +0 -17
  65. package/dist/esm/components/DatePicker/DesktopCalendar.js +0 -57
@@ -1,10 +1,8 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.useDateFieldState = void 0;
7
- const react_1 = __importDefault(require("react"));
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
8
6
  const date_utils_1 = require("@gravity-ui/date-utils");
9
7
  const useControlledState_1 = require("../../hooks/useControlledState");
10
8
  const dates_1 = require("../../utils/dates");
@@ -19,11 +17,6 @@ const EDITABLE_SEGMENTS = {
19
17
  dayPeriod: true,
20
18
  weekday: true,
21
19
  };
22
- const TYPE_MAPPING = {
23
- weekday: 'day',
24
- day: 'date',
25
- dayPeriod: 'hour',
26
- };
27
20
  const PAGE_STEP = {
28
21
  year: 5,
29
22
  month: 2,
@@ -69,10 +62,7 @@ function useDateFieldState(props) {
69
62
  ? value
70
63
  : placeholderDate;
71
64
  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
- });
65
+ const [selectedSections, setSelectedSections] = react_1.default.useState(-1);
76
66
  const selectedSectionIndexes = react_1.default.useMemo(() => {
77
67
  if (selectedSections === -1) {
78
68
  return null;
@@ -97,9 +87,14 @@ function useDateFieldState(props) {
97
87
  return;
98
88
  }
99
89
  if (Object.keys(validSegments).length >= Object.keys(allSegments).length) {
100
- setDate(newValue);
90
+ if (!value || !newValue.isSame(value)) {
91
+ setDate(newValue);
92
+ }
101
93
  }
102
94
  else {
95
+ if (value) {
96
+ setDate(null);
97
+ }
103
98
  setPlaceholderDate(newValue);
104
99
  }
105
100
  }
@@ -115,12 +110,12 @@ function useDateFieldState(props) {
115
110
  }
116
111
  function setSection(section, amount) {
117
112
  markValid(section.type);
118
- setValue(setSegment(section, displayValue, amount));
113
+ setValue((0, utils_1.setSegment)(section, displayValue, amount));
119
114
  }
120
115
  function adjustSection(sectionIndex, amount) {
121
116
  const section = sectionsState.editableSections[sectionIndex];
122
117
  if (validSegments[section.type]) {
123
- setValue(addSegment(section, displayValue, amount));
118
+ setValue((0, utils_1.addSegment)(section, displayValue, amount));
124
119
  }
125
120
  else {
126
121
  markValid(section.type);
@@ -138,7 +133,8 @@ function useDateFieldState(props) {
138
133
  isEmpty: Object.keys(validSegments).length === 0,
139
134
  displayValue,
140
135
  setValue,
141
- text: sectionsState.editableSections.map((s) => s.textValue).join(''),
136
+ // use ltr direction context to get predictable navigation inside input
137
+ text: '\u2066' + sectionsState.editableSections.map((s) => s.textValue).join('') + '\u2069',
142
138
  readOnly: props.readOnly,
143
139
  disabled: props.disabled,
144
140
  sections: sectionsState.editableSections,
@@ -285,12 +281,9 @@ function useDateFieldState(props) {
285
281
  }
286
282
  }
287
283
  else {
288
- const type = getDurationUnitFromSectionType(section.type);
284
+ const type = (0, utils_1.getDurationUnitFromSectionType)(section.type);
289
285
  currentValue = displayValue.set(type, placeholder[type]());
290
286
  }
291
- if (value) {
292
- setDate(null);
293
- }
294
287
  setValue(currentValue);
295
288
  },
296
289
  clearAll() {
@@ -308,7 +301,6 @@ function useDateFieldState(props) {
308
301
  timeZone: props.timeZone,
309
302
  }));
310
303
  },
311
- // eslint-disable-next-line complexity
312
304
  onInput(key) {
313
305
  if (this.readOnly || this.disabled) {
314
306
  return;
@@ -417,6 +409,7 @@ function useDateFieldState(props) {
417
409
  }
418
410
  },
419
411
  setValueFromString(str) {
412
+ enteredKeys.current = '';
420
413
  let date = parseDate({ input: str, format, timeZone: props.timeZone });
421
414
  if ((0, date_utils_1.isValid)(date)) {
422
415
  if (props.timeZone && !isDateStringWithTimeZone(str)) {
@@ -441,64 +434,6 @@ function parseDate(options) {
441
434
  function isDateStringWithTimeZone(str) {
442
435
  return /z$/i.test(str) || /[+-]\d\d:\d\d$/.test(str);
443
436
  }
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
437
  function getCurrentEditableSectionIndex(sections, selectedSections) {
503
438
  const currentIndex = selectedSections === 'all' || selectedSections === -1 ? 0 : selectedSections;
504
439
  const section = sections[currentIndex];
@@ -539,7 +474,7 @@ function useSectionsState(sections, value, validSegments) {
539
474
  return state;
540
475
  }
541
476
  function getEditableSections(sections, value, validSegments) {
542
- let position = 0;
477
+ let position = 1;
543
478
  const newSections = [];
544
479
  let previousEditableSection = -1;
545
480
  for (let i = 0; i < sections.length; i++) {
@@ -548,9 +483,15 @@ function getEditableSections(sections, value, validSegments) {
548
483
  let renderedValue = section.placeholder;
549
484
  if ((isEditable && validSegments[section.type]) || section.type === 'timeZoneName') {
550
485
  renderedValue = value.format(section.format);
486
+ if (section.contentType === 'digit' &&
487
+ renderedValue.length < section.placeholder.length) {
488
+ renderedValue = renderedValue.padStart(section.placeholder.length, '0');
489
+ }
551
490
  }
491
+ // use bidirectional context to allow the browser autodetect text direction
492
+ renderedValue = '\u2068' + renderedValue + '\u2069';
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,11 +1,9 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.i18n = void 0;
4
+ const tslib_1 = require("tslib");
7
5
  const i18n_1 = require("@gravity-ui/uikit/i18n");
8
6
  const cn_1 = require("../../../utils/cn");
9
- const en_json_1 = __importDefault(require("./en.json"));
10
- const ru_json_1 = __importDefault(require("./ru.json"));
7
+ const en_json_1 = tslib_1.__importDefault(require("./en.json"));
8
+ const ru_json_1 = tslib_1.__importDefault(require("./ru.json"));
11
9
  exports.i18n = (0, i18n_1.addComponentKeysets)({ en: en_json_1.default, ru: ru_json_1.default }, `${cn_1.NAMESPACE}date-field`);
@@ -1,19 +1,6 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
2
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./DateField"), exports);
18
- __exportStar(require("./hooks/useDateFieldState"), exports);
19
- __exportStar(require("./hooks/useDateFieldProps"), exports);
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./DateField"), exports);
5
+ tslib_1.__exportStar(require("./hooks/useDateFieldState"), exports);
6
+ tslib_1.__exportStar(require("./hooks/useDateFieldProps"), exports);
@@ -1,5 +1,16 @@
1
- import type { DateFieldSectionWithoutPosition } from './types';
2
- export declare const isMac: boolean;
3
- export declare const CtrlCmd: string;
1
+ import type { DateTime } from '@gravity-ui/date-utils';
2
+ import type { DateFieldSection, DateFieldSectionType, DateFieldSectionWithoutPosition } from './types';
4
3
  export declare function expandFormat(format: string): string;
4
+ export declare function getSectionLimits(section: DateFieldSectionWithoutPosition, date: DateTime): {
5
+ minValue: number;
6
+ maxValue: number;
7
+ } | {
8
+ minValue?: undefined;
9
+ maxValue?: undefined;
10
+ };
11
+ export declare function getSectionValue(sections: DateFieldSectionWithoutPosition, date: DateTime): number | undefined;
12
+ export declare function getDurationUnitFromSectionType(type: DateFieldSectionType): "year" | "month" | "day" | "date" | "hour" | "minute" | "second";
13
+ export declare function addSegment(section: DateFieldSection, date: DateTime, amount: number): DateTime;
14
+ export declare function setSegment(section: DateFieldSection, date: DateTime, amount: number): DateTime;
5
15
  export declare function splitFormatIntoSections(format: string): DateFieldSectionWithoutPosition[];
16
+ export declare function cleanString(dirtyString: string): string;
@@ -1,10 +1,8 @@
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.cleanString = exports.splitFormatIntoSections = exports.setSegment = exports.addSegment = exports.getDurationUnitFromSectionType = exports.getSectionValue = exports.getSectionLimits = exports.expandFormat = void 0;
4
4
  const date_utils_1 = require("@gravity-ui/date-utils");
5
5
  const i18n_1 = require("./i18n");
6
- exports.isMac = window.navigator.userAgent.indexOf('Macintosh') >= 0;
7
- exports.CtrlCmd = exports.isMac ? 'metaKey' : 'ctrlKey';
8
6
  function expandFormat(format) {
9
7
  const localeFormats = date_utils_1.settings.getLocaleData().formats;
10
8
  const getShortLocalizedFormatFromLongLocalizedFormat = (formatBis) => formatBis.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, escapeSequence, localizedFormat) => escapeSequence || localizedFormat.slice(1));
@@ -81,6 +79,173 @@ function getDateSectionConfigFromFormatToken(formatToken) {
81
79
  function isFourDigitYearFormat(format) {
82
80
  return (0, date_utils_1.dateTime)().format(format).length === 4;
83
81
  }
82
+ function isHour12(format) {
83
+ return (0, date_utils_1.dateTime)().set('hour', 15).format(format) !== '15';
84
+ }
85
+ function getSectionLimits(section, date) {
86
+ const { type, format } = section;
87
+ switch (type) {
88
+ case 'year': {
89
+ const isFourDigit = isFourDigitYearFormat(format);
90
+ return {
91
+ minValue: isFourDigit ? 1 : 0,
92
+ maxValue: isFourDigit ? 9999 : 99,
93
+ };
94
+ }
95
+ case 'month': {
96
+ return {
97
+ minValue: 0,
98
+ maxValue: 11,
99
+ };
100
+ }
101
+ case 'weekday': {
102
+ return {
103
+ minValue: 0,
104
+ maxValue: 6,
105
+ };
106
+ }
107
+ case 'day': {
108
+ return {
109
+ minValue: 1,
110
+ maxValue: date ? date.daysInMonth() : 31,
111
+ };
112
+ }
113
+ case 'hour': {
114
+ if (isHour12(format)) {
115
+ const isPM = date.hour() >= 12;
116
+ return {
117
+ minValue: isPM ? 12 : 0,
118
+ maxValue: isPM ? 23 : 11,
119
+ };
120
+ }
121
+ return {
122
+ minValue: 0,
123
+ maxValue: 23,
124
+ };
125
+ }
126
+ case 'minute':
127
+ case 'second': {
128
+ return {
129
+ minValue: 0,
130
+ maxValue: 59,
131
+ };
132
+ }
133
+ }
134
+ return {};
135
+ }
136
+ exports.getSectionLimits = getSectionLimits;
137
+ function getSectionValue(sections, date) {
138
+ const type = sections.type;
139
+ switch (type) {
140
+ case 'year': {
141
+ return isFourDigitYearFormat(sections.format)
142
+ ? date.year()
143
+ : Number(date.format(sections.format));
144
+ }
145
+ case 'month':
146
+ case 'hour':
147
+ case 'minute':
148
+ case 'second': {
149
+ return date[type]();
150
+ }
151
+ case 'day': {
152
+ return date.date();
153
+ }
154
+ case 'weekday': {
155
+ return date.day();
156
+ }
157
+ case 'dayPeriod': {
158
+ return date.hour() >= 12 ? 12 : 0;
159
+ }
160
+ }
161
+ return undefined;
162
+ }
163
+ exports.getSectionValue = getSectionValue;
164
+ const TYPE_MAPPING = {
165
+ weekday: 'day',
166
+ day: 'date',
167
+ dayPeriod: 'hour',
168
+ };
169
+ function getDurationUnitFromSectionType(type) {
170
+ if (type === 'literal' || type === 'timeZoneName' || type === 'unknown') {
171
+ throw new Error(`${type} section does not have duration unit.`);
172
+ }
173
+ if (type in TYPE_MAPPING) {
174
+ return TYPE_MAPPING[type];
175
+ }
176
+ return type;
177
+ }
178
+ exports.getDurationUnitFromSectionType = getDurationUnitFromSectionType;
179
+ function addSegment(section, date, amount) {
180
+ var _a;
181
+ let val = (_a = section.value) !== null && _a !== void 0 ? _a : 0;
182
+ if (section.type === 'dayPeriod') {
183
+ val = date.hour() + (date.hour() > 12 ? -12 : 12);
184
+ }
185
+ else {
186
+ val = val + amount;
187
+ const min = section.minValue;
188
+ const max = section.maxValue;
189
+ if (typeof min === 'number' && typeof max === 'number') {
190
+ const length = max - min + 1;
191
+ val = ((val - min + length) % length) + min;
192
+ }
193
+ }
194
+ if (section.type === 'year' && !isFourDigitYearFormat(section.format)) {
195
+ val = (0, date_utils_1.dateTime)({ input: `${val}`.padStart(2, '0'), format: section.format }).year();
196
+ }
197
+ const type = getDurationUnitFromSectionType(section.type);
198
+ return date.set(type, val);
199
+ }
200
+ exports.addSegment = addSegment;
201
+ function setSegment(section, date, amount) {
202
+ const type = section.type;
203
+ switch (type) {
204
+ case 'year': {
205
+ return date.set('year', isFourDigitYearFormat(section.format)
206
+ ? amount
207
+ : (0, date_utils_1.dateTime)({
208
+ input: `${amount}`.padStart(2, '0'),
209
+ format: section.format,
210
+ }).year());
211
+ }
212
+ case 'day':
213
+ case 'weekday':
214
+ case 'month': {
215
+ return date.set(getDurationUnitFromSectionType(type), amount);
216
+ }
217
+ case 'dayPeriod': {
218
+ const hours = date.hour();
219
+ const wasPM = hours >= 12;
220
+ const isPM = amount >= 12;
221
+ if (isPM === wasPM) {
222
+ return date;
223
+ }
224
+ return date.set('hour', wasPM ? hours - 12 : hours + 12);
225
+ }
226
+ case 'hour': {
227
+ // In 12 hour time, ensure that AM/PM does not change
228
+ let sectionAmount = amount;
229
+ if (section.minValue === 12 || section.maxValue === 11) {
230
+ const hours = date.hour();
231
+ const wasPM = hours >= 12;
232
+ if (!wasPM && sectionAmount === 12) {
233
+ sectionAmount = 0;
234
+ }
235
+ if (wasPM && sectionAmount < 12) {
236
+ sectionAmount += 12;
237
+ }
238
+ }
239
+ return date.set('hour', sectionAmount);
240
+ }
241
+ case 'minute':
242
+ case 'second': {
243
+ return date.set(type, amount);
244
+ }
245
+ }
246
+ return date;
247
+ }
248
+ exports.setSegment = setSegment;
84
249
  function doesSectionHaveLeadingZeros(contentType, sectionType, format) {
85
250
  if (contentType !== 'digit') {
86
251
  return false;
@@ -250,3 +415,7 @@ function getSectionOptions(section, token) {
250
415
  }
251
416
  return undefined;
252
417
  }
418
+ function cleanString(dirtyString) {
419
+ return dirtyString.replace(/[\u2066\u2067\u2068\u2069]/g, '');
420
+ }
421
+ exports.cleanString = cleanString;
@@ -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;
@@ -1,66 +1,26 @@
1
1
  "use strict";
2
- var __rest = (this && this.__rest) || function (s, e) {
3
- var t = {};
4
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
- t[p] = s[p];
6
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
- t[p[i]] = s[p[i]];
10
- }
11
- return t;
12
- };
13
- var __importDefault = (this && this.__importDefault) || function (mod) {
14
- return (mod && mod.__esModule) ? mod : { "default": mod };
15
- };
16
2
  Object.defineProperty(exports, "__esModule", { value: true });
17
3
  exports.DatePicker = void 0;
4
+ const tslib_1 = require("tslib");
18
5
  const jsx_runtime_1 = require("react/jsx-runtime");
19
- const react_1 = __importDefault(require("react"));
6
+ const react_1 = tslib_1.__importDefault(require("react"));
7
+ const icons_1 = require("@gravity-ui/icons");
20
8
  const uikit_1 = require("@gravity-ui/uikit");
9
+ const Calendar_1 = require("../Calendar");
21
10
  const DateField_1 = require("../DateField");
22
- const DesktopCalendar_1 = require("./DesktopCalendar");
23
11
  const MobileCalendar_1 = require("./MobileCalendar");
12
+ const useDatePickerProps_1 = require("./hooks/useDatePickerProps");
24
13
  const useDatePickerState_1 = require("./hooks/useDatePickerState");
25
14
  const utils_1 = require("./utils");
26
15
  require("./DatePicker.css");
27
16
  function DatePicker(_a) {
28
- var { value, defaultValue, onUpdate, className, onFocus, onBlur, children } = _a, props = __rest(_a, ["value", "defaultValue", "onUpdate", "className", "onFocus", "onBlur", "children"]);
17
+ var { value, defaultValue, onUpdate, className } = _a, props = tslib_1.__rest(_a, ["value", "defaultValue", "onUpdate", "className"]);
29
18
  const anchorRef = react_1.default.useRef(null);
30
19
  const state = (0, useDatePickerState_1.useDatePickerState)(Object.assign(Object.assign({}, props), { value,
31
20
  defaultValue,
32
21
  onUpdate }));
22
+ const { groupProps, fieldProps, calendarButtonProps, popupProps, calendarProps, timeInputProps } = (0, useDatePickerProps_1.useDatePickerProps)(state, props);
33
23
  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 })) }))] })));
24
+ 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
25
  }
66
26
  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 {};