@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
@@ -0,0 +1,134 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.useDatePickerProps = void 0;
18
+ const react_1 = __importDefault(require("react"));
19
+ const uikit_1 = require("@gravity-ui/uikit");
20
+ const DateField_1 = require("../../DateField");
21
+ const getButtonSizeForInput_1 = require("../../utils/getButtonSizeForInput");
22
+ const mergeProps_1 = require("../../utils/mergeProps");
23
+ const i18n_1 = require("../i18n");
24
+ function useDatePickerProps(state, _a) {
25
+ var _b;
26
+ var { onFocus, onBlur } = _a, props = __rest(_a, ["onFocus", "onBlur"]);
27
+ const [isActive, setActive] = react_1.default.useState(false);
28
+ const { focusWithinProps } = (0, uikit_1.useFocusWithin)({
29
+ onFocusWithin: onFocus,
30
+ onBlurWithin: onBlur,
31
+ onFocusWithinChange(isFocusWithin) {
32
+ setActive(isFocusWithin);
33
+ if (!isFocusWithin) {
34
+ state.setOpen(false);
35
+ }
36
+ },
37
+ });
38
+ const { inputProps } = (0, DateField_1.useDateFieldProps)(state.dateFieldState, props);
39
+ let error;
40
+ let validationState = props.validationState;
41
+ if (validationState) {
42
+ error = validationState === 'invalid' ? props.errorMessage || true : undefined;
43
+ }
44
+ else {
45
+ validationState = state.dateFieldState.validationState;
46
+ error = validationState === 'invalid';
47
+ }
48
+ const inputRef = react_1.default.useRef(null);
49
+ const handleRef = (0, uikit_1.useForkRef)(inputRef, inputProps.controlRef);
50
+ const calendarRef = react_1.default.useRef(null);
51
+ const calendarButtonRef = react_1.default.useRef(null);
52
+ const groupRef = react_1.default.useRef(null);
53
+ function focusInput() {
54
+ setTimeout(() => {
55
+ var _a;
56
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
57
+ });
58
+ }
59
+ return {
60
+ groupProps: Object.assign(Object.assign({ ref: groupRef, tabIndex: -1, role: 'group' }, focusWithinProps), { style: props.style, 'aria-disabled': state.disabled || undefined, onKeyDown: (e) => {
61
+ if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
62
+ e.preventDefault();
63
+ e.stopPropagation();
64
+ state.setOpen(true);
65
+ }
66
+ } }),
67
+ fieldProps: (0, mergeProps_1.mergeProps)(inputProps, state.dateFieldState.isEmpty && !isActive && props.placeholder
68
+ ? { value: '' }
69
+ : undefined, { controlRef: handleRef, error }),
70
+ calendarButtonProps: {
71
+ ref: calendarButtonRef,
72
+ size: (0, getButtonSizeForInput_1.getButtonSizeForInput)(props.size),
73
+ disabled: state.disabled,
74
+ extraProps: {
75
+ 'aria-label': (0, i18n_1.i18n)('Calendar'),
76
+ 'aria-haspopup': 'dialog',
77
+ 'aria-expanded': state.isOpen,
78
+ },
79
+ view: 'flat-secondary',
80
+ onClick: () => {
81
+ setActive(true);
82
+ state.setOpen(!state.isOpen);
83
+ },
84
+ },
85
+ popupProps: {
86
+ open: state.isOpen,
87
+ onEscapeKeyDown: () => {
88
+ state.setOpen(false);
89
+ focusInput();
90
+ },
91
+ onOutsideClick: (e) => {
92
+ var _a;
93
+ if (e.target !== calendarButtonRef.current) {
94
+ state.setOpen(false);
95
+ }
96
+ if (e.target && ((_a = groupRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
97
+ focusInput();
98
+ }
99
+ },
100
+ // @ts-expect-error focusTrap in popup was introduced in a newer version of uikit
101
+ focusTrap: true,
102
+ },
103
+ calendarProps: {
104
+ ref: calendarRef,
105
+ autoFocus: true,
106
+ size: props.size === 's' ? 'm' : props.size,
107
+ disabled: props.disabled,
108
+ readOnly: props.readOnly,
109
+ onUpdate: (d) => {
110
+ state.setDateValue(d);
111
+ if (!state.hasTime) {
112
+ focusInput();
113
+ }
114
+ },
115
+ defaultFocusedValue: (_b = state.dateValue) !== null && _b !== void 0 ? _b : undefined,
116
+ value: state.dateValue,
117
+ minValue: props.minValue,
118
+ maxValue: props.maxValue,
119
+ isDateUnavailable: props.isDateUnavailable,
120
+ timeZone: props.timeZone,
121
+ },
122
+ timeInputProps: {
123
+ value: state.timeValue,
124
+ onUpdate: state.setTimeValue,
125
+ format: state.timeFormat,
126
+ readOnly: state.readOnly,
127
+ disabled: state.disabled,
128
+ timeZone: props.timeZone,
129
+ hasClear: props.hasClear,
130
+ size: props.size,
131
+ },
132
+ };
133
+ }
134
+ exports.useDatePickerProps = useDatePickerProps;
@@ -1,5 +1,6 @@
1
1
  import type { DateTime } from '@gravity-ui/date-utils';
2
- import type { InputBase, ValueBase } from '../../types';
2
+ import type { DateFieldState } from '../../DateField';
3
+ import type { DateFieldBase } from '../../types';
3
4
  export type Granularity = 'day' | 'hour' | 'minute' | 'second';
4
5
  export interface DatePickerState {
5
6
  /** The currently selected date. */
@@ -36,10 +37,8 @@ export interface DatePickerState {
36
37
  isOpen: boolean;
37
38
  /** Sets whether the calendar popover is open. */
38
39
  setOpen(isOpen: boolean): void;
40
+ dateFieldState: DateFieldState;
39
41
  }
40
- export interface DatePickerStateOptions extends ValueBase<DateTime>, InputBase {
41
- placeholderValue?: DateTime;
42
- timeZone?: string;
43
- format?: string;
42
+ export interface DatePickerStateOptions extends DateFieldBase {
44
43
  }
45
44
  export declare function useDatePickerState(props: DatePickerStateOptions): DatePickerState;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.useDatePickerState = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
+ const DateField_1 = require("../../DateField");
8
9
  const utils_1 = require("../../DateField/utils");
9
10
  const useControlledState_1 = require("../../hooks/useControlledState");
10
11
  const dates_1 = require("../../utils/dates");
@@ -81,6 +82,19 @@ function useDatePickerState(props) {
81
82
  setSelectedTime(newValue);
82
83
  }
83
84
  };
85
+ const dateFieldState = (0, DateField_1.useDateFieldState)({
86
+ value: value !== null && value !== void 0 ? value : null,
87
+ onUpdate: setValue,
88
+ disabled,
89
+ readOnly,
90
+ validationState: props.validationState,
91
+ minValue: props.minValue,
92
+ maxValue: props.maxValue,
93
+ isDateUnavailable: props.isDateUnavailable,
94
+ format,
95
+ placeholderValue: props.placeholderValue,
96
+ timeZone: props.timeZone,
97
+ });
84
98
  return {
85
99
  value: value !== null && value !== void 0 ? value : null,
86
100
  setValue,
@@ -101,6 +115,7 @@ function useDatePickerState(props) {
101
115
  }
102
116
  setOpen(newIsOpen);
103
117
  },
118
+ dateFieldState,
104
119
  };
105
120
  }
106
121
  exports.useDatePickerState = useDatePickerState;
@@ -1,2 +1,3 @@
1
1
  export * from './DatePicker';
2
2
  export * from './hooks/useDatePickerState';
3
+ export * from './hooks/useDatePickerProps';
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./DatePicker"), exports);
18
18
  __exportStar(require("./hooks/useDatePickerState"), exports);
19
+ __exportStar(require("./hooks/useDatePickerProps"), exports);
@@ -1,6 +1,7 @@
1
1
  .g-date-relative-date-picker {
2
2
  position: relative;
3
3
  display: inline-flex;
4
+ outline: none;
4
5
  }
5
6
  .g-date-relative-date-picker__field {
6
7
  width: 100%;
@@ -42,7 +42,7 @@ function useRelativeDatePickerProps(state, _a) {
42
42
  onBlurWithin: onBlur,
43
43
  onFocusWithinChange(isFocusWithin) {
44
44
  if (!isFocusWithin) {
45
- state.setActive(isFocusWithin);
45
+ state.setActive(false);
46
46
  }
47
47
  },
48
48
  });
@@ -50,16 +50,12 @@ function useRelativeDatePickerProps(state, _a) {
50
50
  if (!state.isActive && isOpen) {
51
51
  setOpen(false);
52
52
  }
53
- const [prevActive, setPrevActive] = react_1.default.useState(state.isActive);
54
- if (prevActive !== state.isActive) {
55
- setPrevActive(state.isActive);
56
- if (state.isActive && !isOpen) {
57
- setOpen(true);
58
- }
59
- }
60
53
  const commonInputProps = {
61
54
  onFocus: () => {
62
- state.setActive(true);
55
+ if (!state.isActive) {
56
+ state.setActive(true);
57
+ setOpen(true);
58
+ }
63
59
  },
64
60
  };
65
61
  const { inputProps } = (0, DateField_1.useDateFieldProps)(dateFieldState, Object.assign(Object.assign({}, props), { value: undefined, defaultValue: undefined, onUpdate: undefined }));
@@ -68,6 +64,7 @@ function useRelativeDatePickerProps(state, _a) {
68
64
  value: relativeDateState.text,
69
65
  onUpdate: relativeDateState.setText,
70
66
  hasClear: props.hasClear && !relativeDateState.readOnly,
67
+ placeholder: props.placeholder,
71
68
  size: props.size,
72
69
  };
73
70
  let error;
@@ -82,19 +79,33 @@ function useRelativeDatePickerProps(state, _a) {
82
79
  : dateFieldState.validationState;
83
80
  error = validationState === 'invalid';
84
81
  }
85
- const wasActiveBeforeClickRef = react_1.default.useRef(state.isActive);
86
82
  const inputRef = react_1.default.useRef(null);
87
83
  const handleRef = (0, uikit_1.useForkRef)(inputRef, mode === 'relative' ? relativeDateProps.controlRef : inputProps.controlRef);
88
84
  const calendarRef = react_1.default.useRef(null);
85
+ function focusCalendar() {
86
+ setTimeout(() => {
87
+ var _a;
88
+ (_a = calendarRef.current) === null || _a === void 0 ? void 0 : _a.focus();
89
+ });
90
+ }
91
+ function focusInput() {
92
+ setTimeout(() => {
93
+ var _a;
94
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
95
+ });
96
+ }
89
97
  return {
90
- groupProps: Object.assign(Object.assign({ role: 'group' }, focusWithinProps), { onKeyDown: (e) => {
98
+ groupProps: Object.assign(Object.assign({ tabIndex: -1, role: 'group' }, focusWithinProps), { onKeyDown: (e) => {
91
99
  if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
92
100
  e.preventDefault();
93
101
  e.stopPropagation();
94
102
  setOpen(true);
103
+ focusCalendar();
95
104
  }
96
105
  } }),
97
- fieldProps: (0, mergeProps_1.mergeProps)(commonInputProps, mode === 'relative' ? relativeDateProps : inputProps, { controlRef: handleRef, error }),
106
+ fieldProps: (0, mergeProps_1.mergeProps)(commonInputProps, mode === 'relative' ? relativeDateProps : inputProps, mode === 'absolute' && dateFieldState.isEmpty && !state.isActive && props.placeholder
107
+ ? { value: '' }
108
+ : undefined, { controlRef: handleRef, error }),
98
109
  modeSwitcherProps: {
99
110
  size: (0, getButtonSizeForInput_1.getButtonSizeForInput)(props.size),
100
111
  disabled: state.readOnly || state.disabled,
@@ -115,7 +126,7 @@ function useRelativeDatePickerProps(state, _a) {
115
126
  else if (relativeDateState.parsedDate) {
116
127
  setFocusedDate(relativeDateState.parsedDate);
117
128
  }
118
- setTimeout(() => { var _a; return (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); });
129
+ focusInput();
119
130
  },
120
131
  },
121
132
  calendarButtonProps: {
@@ -127,29 +138,20 @@ function useRelativeDatePickerProps(state, _a) {
127
138
  'aria-expanded': isOpen,
128
139
  },
129
140
  view: 'flat-secondary',
130
- onFocus: () => {
131
- wasActiveBeforeClickRef.current = state.isActive;
132
- },
133
141
  onClick: () => {
134
142
  state.setActive(true);
135
- if (wasActiveBeforeClickRef.current) {
136
- setOpen(!isOpen);
137
- if (!isOpen) {
138
- setTimeout(() => {
139
- var _a;
140
- (_a = calendarRef.current) === null || _a === void 0 ? void 0 : _a.focus();
141
- });
142
- }
143
+ setOpen(!isOpen);
144
+ if (!isOpen) {
145
+ focusCalendar();
143
146
  }
144
- wasActiveBeforeClickRef.current = state.isActive;
145
147
  },
146
148
  },
147
149
  popupProps: {
148
150
  open: isOpen,
149
151
  onEscapeKeyDown: () => {
150
152
  setOpen(false);
153
+ focusInput();
151
154
  },
152
- restoreFocus: true,
153
155
  },
154
156
  calendarProps: {
155
157
  ref: calendarRef,
@@ -160,7 +162,7 @@ function useRelativeDatePickerProps(state, _a) {
160
162
  datePickerState.setDateValue(v);
161
163
  if (!state.datePickerState.hasTime) {
162
164
  setOpen(false);
163
- setTimeout(() => { var _a; return (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); });
165
+ focusInput();
164
166
  }
165
167
  },
166
168
  focusedValue: focusedDate,
@@ -22,8 +22,16 @@ export function useRangeCalendarState(props) {
22
22
  const highlightedRange = anchorDate
23
23
  ? makeRange(anchorDate, calendar.focusedDate, calendar.mode)
24
24
  : (_b = (value && makeRange(value.start, value.end, calendar.mode))) !== null && _b !== void 0 ? _b : undefined;
25
- const selectDate = (date) => {
26
- if (props.disabled || props.readOnly) {
25
+ const minMode = calendar.availableModes[0];
26
+ const selectDate = (date, force = false) => {
27
+ if (props.disabled) {
28
+ return;
29
+ }
30
+ if (!force && calendar.mode !== minMode) {
31
+ calendar.zoomIn();
32
+ return;
33
+ }
34
+ if (props.readOnly) {
27
35
  return;
28
36
  }
29
37
  date = constrainValue(date, props.minValue, props.maxValue);
@@ -43,9 +51,6 @@ export function useRangeCalendarState(props) {
43
51
  setValue,
44
52
  selectDate,
45
53
  anchorDate, setAnchorDate: setAnchorDateState, highlightedRange,
46
- selectFocusedDate() {
47
- selectDate(calendar.focusedDate);
48
- },
49
54
  isSelected(date) {
50
55
  if (!highlightedRange) {
51
56
  return false;
@@ -80,12 +80,16 @@ export function useDateFieldProps(state, props) {
80
80
  if (state.selectedSectionIndexes !== null) {
81
81
  return;
82
82
  }
83
- const input = inputRef.current;
83
+ const input = e.target;
84
+ const isAutofocus = !inputRef.current;
84
85
  setTimeout(() => {
85
86
  if (!input || input !== inputRef.current) {
86
87
  return;
87
88
  }
88
- if (
89
+ if (isAutofocus) {
90
+ state.focusSectionInPosition(0);
91
+ }
92
+ else if (
89
93
  // avoid selecting all sections when focusing empty field without value
90
94
  input.value.length &&
91
95
  Number(input.selectionEnd) - Number(input.selectionStart) ===
@@ -163,32 +167,35 @@ export function useDateFieldProps(state, props) {
163
167
  onBeforeInput(e) {
164
168
  e.preventDefault();
165
169
  // @ts-expect-error
166
- const key = e.nativeEvent.data;
167
- // eslint-disable-next-line no-eq-null, eqeqeq
168
- if (key != null) {
170
+ const key = e.data;
171
+ if (key !== undefined && key !== null) {
169
172
  state.onInput(key);
170
173
  }
171
174
  },
172
175
  onPaste(e) {
176
+ e.preventDefault();
173
177
  if (state.readOnly) {
174
- e.preventDefault();
175
178
  return;
176
179
  }
177
180
  const pastedValue = e.clipboardData.getData('text');
178
- if (state.setValueFromString(pastedValue)) {
179
- e.preventDefault();
180
- }
181
- else if (state.selectedSectionIndexes &&
181
+ if (state.selectedSectionIndexes &&
182
182
  state.selectedSectionIndexes.startIndex ===
183
183
  state.selectedSectionIndexes.endIndex) {
184
184
  const activeSection = state.sections[state.selectedSectionIndexes.startIndex];
185
+ const digitsOnly = /^\d+$/.test(pastedValue);
186
+ const lettersOnly = /^[a-zA-Z]+$/.test(pastedValue);
185
187
  const isValidValue = Boolean(activeSection) &&
186
- ((activeSection.contentType === 'digit' && /^\d+$/.test(pastedValue)) ||
187
- activeSection.contentType === 'letter');
188
- if (!isValidValue) {
189
- e.preventDefault();
188
+ ((activeSection.contentType === 'digit' && digitsOnly) ||
189
+ (activeSection.contentType === 'letter' && lettersOnly));
190
+ if (isValidValue) {
191
+ state.onInput(pastedValue);
192
+ return;
193
+ }
194
+ if (digitsOnly || lettersOnly) {
195
+ return;
190
196
  }
191
197
  }
198
+ state.setValueFromString(pastedValue);
192
199
  },
193
200
  },
194
201
  },
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { dateTime, isValid } from '@gravity-ui/date-utils';
3
3
  import { useControlledState } from '../../hooks/useControlledState';
4
4
  import { createPlaceholderValue, isInvalid, mergeDateTime } from '../../utils/dates';
5
- import { splitFormatIntoSections } from '../utils';
5
+ import { addSegment, getDurationUnitFromSectionType, getSectionLimits, getSectionValue, setSegment, splitFormatIntoSections, } from '../utils';
6
6
  const EDITABLE_SEGMENTS = {
7
7
  year: true,
8
8
  month: true,
@@ -13,11 +13,6 @@ const EDITABLE_SEGMENTS = {
13
13
  dayPeriod: true,
14
14
  weekday: true,
15
15
  };
16
- const TYPE_MAPPING = {
17
- weekday: 'day',
18
- day: 'date',
19
- dayPeriod: 'hour',
20
- };
21
16
  const PAGE_STEP = {
22
17
  year: 5,
23
18
  month: 2,
@@ -63,10 +58,7 @@ export function useDateFieldState(props) {
63
58
  ? value
64
59
  : placeholderDate;
65
60
  const sectionsState = useSectionsState(sections, displayValue, validSegments);
66
- const [selectedSections, setSelectedSections] = React.useState(() => {
67
- var _a, _b;
68
- return (_b = (_a = sectionsState.editableSections[0]) === null || _a === void 0 ? void 0 : _a.previousEditableSection) !== null && _b !== void 0 ? _b : -1;
69
- });
61
+ const [selectedSections, setSelectedSections] = React.useState(-1);
70
62
  const selectedSectionIndexes = React.useMemo(() => {
71
63
  if (selectedSections === -1) {
72
64
  return null;
@@ -91,9 +83,14 @@ export function useDateFieldState(props) {
91
83
  return;
92
84
  }
93
85
  if (Object.keys(validSegments).length >= Object.keys(allSegments).length) {
94
- setDate(newValue);
86
+ if (!value || !newValue.isSame(value)) {
87
+ setDate(newValue);
88
+ }
95
89
  }
96
90
  else {
91
+ if (value) {
92
+ setDate(null);
93
+ }
97
94
  setPlaceholderDate(newValue);
98
95
  }
99
96
  }
@@ -282,9 +279,6 @@ export function useDateFieldState(props) {
282
279
  const type = getDurationUnitFromSectionType(section.type);
283
280
  currentValue = displayValue.set(type, placeholder[type]());
284
281
  }
285
- if (value) {
286
- setDate(null);
287
- }
288
282
  setValue(currentValue);
289
283
  },
290
284
  clearAll() {
@@ -411,6 +405,7 @@ export function useDateFieldState(props) {
411
405
  }
412
406
  },
413
407
  setValueFromString(str) {
408
+ enteredKeys.current = '';
414
409
  let date = parseDate({ input: str, format, timeZone: props.timeZone });
415
410
  if (isValid(date)) {
416
411
  if (props.timeZone && !isDateStringWithTimeZone(str)) {
@@ -434,64 +429,6 @@ function parseDate(options) {
434
429
  function isDateStringWithTimeZone(str) {
435
430
  return /z$/i.test(str) || /[+-]\d\d:\d\d$/.test(str);
436
431
  }
437
- function addSegment(section, date, amount) {
438
- var _a;
439
- let val = (_a = section.value) !== null && _a !== void 0 ? _a : 0;
440
- if (section.type === 'dayPeriod') {
441
- val = date.hour() + (date.hour() > 12 ? -12 : 12);
442
- }
443
- else {
444
- val = val + amount;
445
- const min = section.minValue;
446
- const max = section.maxValue;
447
- if (typeof min === 'number' && typeof max === 'number') {
448
- const length = max - min + 1;
449
- val = ((val - min + length) % length) + min;
450
- }
451
- }
452
- const type = getDurationUnitFromSectionType(section.type);
453
- return date.set(type, val);
454
- }
455
- function setSegment(section, date, amount) {
456
- const type = section.type;
457
- switch (type) {
458
- case 'day':
459
- case 'weekday':
460
- case 'month':
461
- case 'year': {
462
- return date.set(getDurationUnitFromSectionType(type), amount);
463
- }
464
- case 'dayPeriod': {
465
- const hours = date.hour();
466
- const wasPM = hours >= 12;
467
- const isPM = amount >= 12;
468
- if (isPM === wasPM) {
469
- return date;
470
- }
471
- return date.set('hour', wasPM ? hours - 12 : hours + 12);
472
- }
473
- case 'hour': {
474
- // In 12 hour time, ensure that AM/PM does not change
475
- let sectionAmount = amount;
476
- if (section.minValue === 12 || section.maxValue === 11) {
477
- const hours = date.hour();
478
- const wasPM = hours >= 12;
479
- if (!wasPM && sectionAmount === 12) {
480
- sectionAmount = 0;
481
- }
482
- if (wasPM && sectionAmount < 12) {
483
- sectionAmount += 12;
484
- }
485
- }
486
- return date.set('hour', sectionAmount);
487
- }
488
- case 'minute':
489
- case 'second': {
490
- return date.set(type, amount);
491
- }
492
- }
493
- return date;
494
- }
495
432
  function getCurrentEditableSectionIndex(sections, selectedSections) {
496
433
  const currentIndex = selectedSections === 'all' || selectedSections === -1 ? 0 : selectedSections;
497
434
  const section = sections[currentIndex];
@@ -541,9 +478,13 @@ function getEditableSections(sections, value, validSegments) {
541
478
  let renderedValue = section.placeholder;
542
479
  if ((isEditable && validSegments[section.type]) || section.type === 'timeZoneName') {
543
480
  renderedValue = value.format(section.format);
481
+ if (section.contentType === 'digit' &&
482
+ renderedValue.length < section.placeholder.length) {
483
+ renderedValue = renderedValue.padStart(section.placeholder.length, '0');
484
+ }
544
485
  }
545
486
  const sectionLength = renderedValue.length;
546
- 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) }));
487
+ const newSection = Object.assign(Object.assign(Object.assign({}, section), { value: getSectionValue(section, value), textValue: renderedValue, start: position, end: position + sectionLength, modified: false, previousEditableSection, nextEditableSection: previousEditableSection }), getSectionLimits(section, value));
547
488
  newSections.push(newSection);
548
489
  if (isEditable) {
549
490
  for (let j = Math.max(0, previousEditableSection); j <= i; j++) {
@@ -561,88 +502,3 @@ function getEditableSections(sections, value, validSegments) {
561
502
  }
562
503
  return newSections;
563
504
  }
564
- function getValue(date, type) {
565
- switch (type) {
566
- case 'year':
567
- case 'month':
568
- case 'hour':
569
- case 'minute':
570
- case 'second': {
571
- return date[type]();
572
- }
573
- case 'day': {
574
- return date.date();
575
- }
576
- case 'weekday': {
577
- return date.day();
578
- }
579
- case 'dayPeriod': {
580
- return date.hour() >= 12 ? 12 : 0;
581
- }
582
- }
583
- return undefined;
584
- }
585
- function isHour12(section) {
586
- if (section.type === 'hour') {
587
- return dateTime().set('hour', 15).format(section.format) !== '15';
588
- }
589
- return false;
590
- }
591
- function getSectionLimits(date, type, options) {
592
- switch (type) {
593
- case 'year': {
594
- return {
595
- minValue: 1,
596
- maxValue: 9999,
597
- };
598
- }
599
- case 'month': {
600
- return {
601
- minValue: 0,
602
- maxValue: 11,
603
- };
604
- }
605
- case 'weekday': {
606
- return {
607
- minValue: 0,
608
- maxValue: 6,
609
- };
610
- }
611
- case 'day': {
612
- return {
613
- minValue: 1,
614
- maxValue: date ? date.daysInMonth() : 31,
615
- };
616
- }
617
- case 'hour': {
618
- if (options.hour12) {
619
- const isPM = date.hour() >= 12;
620
- return {
621
- minValue: isPM ? 12 : 0,
622
- maxValue: isPM ? 23 : 11,
623
- };
624
- }
625
- return {
626
- minValue: 0,
627
- maxValue: 23,
628
- };
629
- }
630
- case 'minute':
631
- case 'second': {
632
- return {
633
- minValue: 0,
634
- maxValue: 59,
635
- };
636
- }
637
- }
638
- return {};
639
- }
640
- function getDurationUnitFromSectionType(type) {
641
- if (type === 'literal' || type === 'timeZoneName' || type === 'unknown') {
642
- throw new Error(`${type} section does not have duration unit.`);
643
- }
644
- if (type in TYPE_MAPPING) {
645
- return TYPE_MAPPING[type];
646
- }
647
- return type;
648
- }