@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.
- package/dist/cjs/components/Calendar/Calendar.css +37 -37
- package/dist/cjs/components/Calendar/Calendar.js +2 -4
- package/dist/cjs/components/Calendar/CalendarBase.js +2 -4
- package/dist/cjs/components/Calendar/RangeCalendar.js +2 -4
- package/dist/cjs/components/Calendar/hooks/useCalendarCellProps.js +2 -4
- package/dist/cjs/components/Calendar/hooks/useCalendarGridProps.js +11 -0
- package/dist/cjs/components/Calendar/hooks/useCalendarProps.js +2 -4
- package/dist/cjs/components/Calendar/hooks/useCalendarState.js +2 -4
- package/dist/cjs/components/Calendar/hooks/useRangeCalendarState.js +13 -21
- package/dist/cjs/components/Calendar/i18n/index.js +3 -5
- package/dist/cjs/components/Calendar/index.js +8 -21
- package/dist/cjs/components/DateField/DateField.js +3 -16
- package/dist/cjs/components/DateField/hooks/useDateFieldProps.js +25 -20
- package/dist/cjs/components/DateField/hooks/useDateFieldState.js +23 -167
- package/dist/cjs/components/DateField/i18n/index.js +3 -5
- package/dist/cjs/components/DateField/index.js +4 -17
- package/dist/cjs/components/DateField/utils.d.ts +14 -3
- package/dist/cjs/components/DateField/utils.js +172 -3
- package/dist/cjs/components/DatePicker/DatePicker.css +6 -0
- package/dist/cjs/components/DatePicker/DatePicker.d.ts +2 -2
- package/dist/cjs/components/DatePicker/DatePicker.js +8 -48
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.js +121 -0
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +17 -4
- package/dist/cjs/components/DatePicker/i18n/index.js +3 -5
- package/dist/cjs/components/DatePicker/index.d.ts +1 -0
- package/dist/cjs/components/DatePicker/index.js +4 -16
- package/dist/cjs/components/RelativeDateField/RelativeDateField.js +2 -4
- package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldProps.js +2 -4
- package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldState.js +2 -4
- package/dist/cjs/components/RelativeDateField/index.js +4 -17
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.js +2 -4
- package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +32 -43
- package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerState.js +2 -4
- package/dist/cjs/components/RelativeDatePicker/i18n/index.js +3 -5
- package/dist/cjs/components/RelativeDatePicker/index.js +4 -17
- package/dist/cjs/components/hooks/useControlledState.js +2 -4
- package/dist/cjs/components/index.js +6 -19
- package/dist/cjs/index.js +2 -15
- package/dist/esm/components/Calendar/Calendar.css +37 -37
- package/dist/esm/components/Calendar/hooks/useCalendarGridProps.js +11 -0
- package/dist/esm/components/Calendar/hooks/useRangeCalendarState.js +11 -16
- package/dist/esm/components/DateField/DateField.js +1 -11
- package/dist/esm/components/DateField/hooks/useDateFieldProps.js +24 -17
- package/dist/esm/components/DateField/hooks/useDateFieldState.js +19 -161
- package/dist/esm/components/DateField/utils.d.ts +14 -3
- package/dist/esm/components/DateField/utils.js +165 -2
- package/dist/esm/components/DatePicker/DatePicker.css +6 -0
- package/dist/esm/components/DatePicker/DatePicker.d.ts +2 -2
- package/dist/esm/components/DatePicker/DatePicker.js +9 -46
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.js +117 -0
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +15 -0
- package/dist/esm/components/DatePicker/index.d.ts +1 -0
- package/dist/esm/components/DatePicker/index.js +1 -0
- package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
- package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +30 -38
- package/package.json +37 -33
- package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +0 -17
- package/dist/cjs/components/DatePicker/DesktopCalendar.js +0 -65
- package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +0 -17
- package/dist/esm/components/DatePicker/DesktopCalendar.js +0 -57
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { dateTime, settings } from '@gravity-ui/date-utils';
|
|
2
2
|
import { i18n } from './i18n';
|
|
3
|
-
export const isMac = window.navigator.userAgent.indexOf('Macintosh') >= 0;
|
|
4
|
-
export const CtrlCmd = isMac ? 'metaKey' : 'ctrlKey';
|
|
5
3
|
export function expandFormat(format) {
|
|
6
4
|
const localeFormats = settings.getLocaleData().formats;
|
|
7
5
|
const getShortLocalizedFormatFromLongLocalizedFormat = (formatBis) => formatBis.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, escapeSequence, localizedFormat) => escapeSequence || localizedFormat.slice(1));
|
|
@@ -77,6 +75,168 @@ function getDateSectionConfigFromFormatToken(formatToken) {
|
|
|
77
75
|
function isFourDigitYearFormat(format) {
|
|
78
76
|
return dateTime().format(format).length === 4;
|
|
79
77
|
}
|
|
78
|
+
function isHour12(format) {
|
|
79
|
+
return dateTime().set('hour', 15).format(format) !== '15';
|
|
80
|
+
}
|
|
81
|
+
export function getSectionLimits(section, date) {
|
|
82
|
+
const { type, format } = section;
|
|
83
|
+
switch (type) {
|
|
84
|
+
case 'year': {
|
|
85
|
+
const isFourDigit = isFourDigitYearFormat(format);
|
|
86
|
+
return {
|
|
87
|
+
minValue: isFourDigit ? 1 : 0,
|
|
88
|
+
maxValue: isFourDigit ? 9999 : 99,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
case 'month': {
|
|
92
|
+
return {
|
|
93
|
+
minValue: 0,
|
|
94
|
+
maxValue: 11,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
case 'weekday': {
|
|
98
|
+
return {
|
|
99
|
+
minValue: 0,
|
|
100
|
+
maxValue: 6,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
case 'day': {
|
|
104
|
+
return {
|
|
105
|
+
minValue: 1,
|
|
106
|
+
maxValue: date ? date.daysInMonth() : 31,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
case 'hour': {
|
|
110
|
+
if (isHour12(format)) {
|
|
111
|
+
const isPM = date.hour() >= 12;
|
|
112
|
+
return {
|
|
113
|
+
minValue: isPM ? 12 : 0,
|
|
114
|
+
maxValue: isPM ? 23 : 11,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
minValue: 0,
|
|
119
|
+
maxValue: 23,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
case 'minute':
|
|
123
|
+
case 'second': {
|
|
124
|
+
return {
|
|
125
|
+
minValue: 0,
|
|
126
|
+
maxValue: 59,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
export function getSectionValue(sections, date) {
|
|
133
|
+
const type = sections.type;
|
|
134
|
+
switch (type) {
|
|
135
|
+
case 'year': {
|
|
136
|
+
return isFourDigitYearFormat(sections.format)
|
|
137
|
+
? date.year()
|
|
138
|
+
: Number(date.format(sections.format));
|
|
139
|
+
}
|
|
140
|
+
case 'month':
|
|
141
|
+
case 'hour':
|
|
142
|
+
case 'minute':
|
|
143
|
+
case 'second': {
|
|
144
|
+
return date[type]();
|
|
145
|
+
}
|
|
146
|
+
case 'day': {
|
|
147
|
+
return date.date();
|
|
148
|
+
}
|
|
149
|
+
case 'weekday': {
|
|
150
|
+
return date.day();
|
|
151
|
+
}
|
|
152
|
+
case 'dayPeriod': {
|
|
153
|
+
return date.hour() >= 12 ? 12 : 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
const TYPE_MAPPING = {
|
|
159
|
+
weekday: 'day',
|
|
160
|
+
day: 'date',
|
|
161
|
+
dayPeriod: 'hour',
|
|
162
|
+
};
|
|
163
|
+
export function getDurationUnitFromSectionType(type) {
|
|
164
|
+
if (type === 'literal' || type === 'timeZoneName' || type === 'unknown') {
|
|
165
|
+
throw new Error(`${type} section does not have duration unit.`);
|
|
166
|
+
}
|
|
167
|
+
if (type in TYPE_MAPPING) {
|
|
168
|
+
return TYPE_MAPPING[type];
|
|
169
|
+
}
|
|
170
|
+
return type;
|
|
171
|
+
}
|
|
172
|
+
export function addSegment(section, date, amount) {
|
|
173
|
+
var _a;
|
|
174
|
+
let val = (_a = section.value) !== null && _a !== void 0 ? _a : 0;
|
|
175
|
+
if (section.type === 'dayPeriod') {
|
|
176
|
+
val = date.hour() + (date.hour() > 12 ? -12 : 12);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
val = val + amount;
|
|
180
|
+
const min = section.minValue;
|
|
181
|
+
const max = section.maxValue;
|
|
182
|
+
if (typeof min === 'number' && typeof max === 'number') {
|
|
183
|
+
const length = max - min + 1;
|
|
184
|
+
val = ((val - min + length) % length) + min;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (section.type === 'year' && !isFourDigitYearFormat(section.format)) {
|
|
188
|
+
val = dateTime({ input: `${val}`.padStart(2, '0'), format: section.format }).year();
|
|
189
|
+
}
|
|
190
|
+
const type = getDurationUnitFromSectionType(section.type);
|
|
191
|
+
return date.set(type, val);
|
|
192
|
+
}
|
|
193
|
+
export function setSegment(section, date, amount) {
|
|
194
|
+
const type = section.type;
|
|
195
|
+
switch (type) {
|
|
196
|
+
case 'year': {
|
|
197
|
+
return date.set('year', isFourDigitYearFormat(section.format)
|
|
198
|
+
? amount
|
|
199
|
+
: dateTime({
|
|
200
|
+
input: `${amount}`.padStart(2, '0'),
|
|
201
|
+
format: section.format,
|
|
202
|
+
}).year());
|
|
203
|
+
}
|
|
204
|
+
case 'day':
|
|
205
|
+
case 'weekday':
|
|
206
|
+
case 'month': {
|
|
207
|
+
return date.set(getDurationUnitFromSectionType(type), amount);
|
|
208
|
+
}
|
|
209
|
+
case 'dayPeriod': {
|
|
210
|
+
const hours = date.hour();
|
|
211
|
+
const wasPM = hours >= 12;
|
|
212
|
+
const isPM = amount >= 12;
|
|
213
|
+
if (isPM === wasPM) {
|
|
214
|
+
return date;
|
|
215
|
+
}
|
|
216
|
+
return date.set('hour', wasPM ? hours - 12 : hours + 12);
|
|
217
|
+
}
|
|
218
|
+
case 'hour': {
|
|
219
|
+
// In 12 hour time, ensure that AM/PM does not change
|
|
220
|
+
let sectionAmount = amount;
|
|
221
|
+
if (section.minValue === 12 || section.maxValue === 11) {
|
|
222
|
+
const hours = date.hour();
|
|
223
|
+
const wasPM = hours >= 12;
|
|
224
|
+
if (!wasPM && sectionAmount === 12) {
|
|
225
|
+
sectionAmount = 0;
|
|
226
|
+
}
|
|
227
|
+
if (wasPM && sectionAmount < 12) {
|
|
228
|
+
sectionAmount += 12;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return date.set('hour', sectionAmount);
|
|
232
|
+
}
|
|
233
|
+
case 'minute':
|
|
234
|
+
case 'second': {
|
|
235
|
+
return date.set(type, amount);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return date;
|
|
239
|
+
}
|
|
80
240
|
function doesSectionHaveLeadingZeros(contentType, sectionType, format) {
|
|
81
241
|
if (contentType !== 'digit') {
|
|
82
242
|
return false;
|
|
@@ -245,3 +405,6 @@ function getSectionOptions(section, token) {
|
|
|
245
405
|
}
|
|
246
406
|
return undefined;
|
|
247
407
|
}
|
|
408
|
+
export function cleanString(dirtyString) {
|
|
409
|
+
return dirtyString.replace(/[\u2066\u2067\u2068\u2069]/g, '');
|
|
410
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
.g-date-date-picker {
|
|
2
2
|
position: relative;
|
|
3
3
|
display: inline-block;
|
|
4
|
+
outline: none;
|
|
4
5
|
}
|
|
5
6
|
.g-date-date-picker__field {
|
|
6
7
|
width: 100%;
|
|
@@ -8,6 +9,11 @@
|
|
|
8
9
|
.g-date-date-picker__field_mobile {
|
|
9
10
|
pointer-events: none;
|
|
10
11
|
}
|
|
12
|
+
.g-date-date-picker__popup-anchor {
|
|
13
|
+
position: absolute;
|
|
14
|
+
z-index: -1;
|
|
15
|
+
inset: 0;
|
|
16
|
+
}
|
|
11
17
|
.g-date-date-picker__popup-content {
|
|
12
18
|
outline: none;
|
|
13
19
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type
|
|
2
|
+
import { type CalendarProps } from '../Calendar';
|
|
3
3
|
import type { AccessibilityProps, DateFieldBase, DomProps, FocusableProps, KeyboardEvents, StyleProps, TextInputProps } from '../types';
|
|
4
4
|
import './DatePicker.css';
|
|
5
5
|
export interface DatePickerProps extends DateFieldBase, TextInputProps, FocusableProps, KeyboardEvents, DomProps, StyleProps, AccessibilityProps {
|
|
6
6
|
children?: (props: CalendarProps) => React.ReactNode;
|
|
7
7
|
}
|
|
8
|
-
export declare function DatePicker({ value, defaultValue, onUpdate, className,
|
|
8
|
+
export declare function DatePicker({ value, defaultValue, onUpdate, className, ...props }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,59 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
var t = {};
|
|
3
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
-
t[p] = s[p];
|
|
5
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
-
t[p[i]] = s[p[i]];
|
|
9
|
-
}
|
|
10
|
-
return t;
|
|
11
|
-
};
|
|
1
|
+
import { __rest } from "tslib";
|
|
12
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
3
|
import React from 'react';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
4
|
+
import { Calendar as CalendarIcon } from '@gravity-ui/icons';
|
|
5
|
+
import { Button, Icon, Popup, TextInput, useMobile } from '@gravity-ui/uikit';
|
|
6
|
+
import { Calendar } from '../Calendar';
|
|
7
|
+
import { DateField } from '../DateField';
|
|
17
8
|
import { MobileCalendar, MobileCalendarIcon } from './MobileCalendar';
|
|
9
|
+
import { useDatePickerProps } from './hooks/useDatePickerProps';
|
|
18
10
|
import { useDatePickerState } from './hooks/useDatePickerState';
|
|
19
11
|
import { b } from './utils';
|
|
20
12
|
import './DatePicker.css';
|
|
21
13
|
export function DatePicker(_a) {
|
|
22
|
-
var { value, defaultValue, onUpdate, className
|
|
14
|
+
var { value, defaultValue, onUpdate, className } = _a, props = __rest(_a, ["value", "defaultValue", "onUpdate", "className"]);
|
|
23
15
|
const anchorRef = React.useRef(null);
|
|
24
16
|
const state = useDatePickerState(Object.assign(Object.assign({}, props), { value,
|
|
25
17
|
defaultValue,
|
|
26
18
|
onUpdate }));
|
|
19
|
+
const { groupProps, fieldProps, calendarButtonProps, popupProps, calendarProps, timeInputProps } = useDatePickerProps(state, props);
|
|
27
20
|
const [isMobile] = useMobile();
|
|
28
|
-
|
|
29
|
-
const { focusWithinProps } = useFocusWithin({
|
|
30
|
-
onFocusWithin: onFocus,
|
|
31
|
-
onBlurWithin: onBlur,
|
|
32
|
-
onFocusWithinChange(isFocusWithin) {
|
|
33
|
-
setActive(isFocusWithin);
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
const fieldState = useDateFieldState({
|
|
37
|
-
value: state.value,
|
|
38
|
-
onUpdate: state.setValue,
|
|
39
|
-
disabled: state.disabled,
|
|
40
|
-
readOnly: state.readOnly,
|
|
41
|
-
validationState: props.validationState,
|
|
42
|
-
minValue: props.minValue,
|
|
43
|
-
maxValue: props.maxValue,
|
|
44
|
-
isDateUnavailable: props.isDateUnavailable,
|
|
45
|
-
format: state.format,
|
|
46
|
-
placeholderValue: props.placeholderValue,
|
|
47
|
-
timeZone: props.timeZone,
|
|
48
|
-
});
|
|
49
|
-
const { inputProps } = useDateFieldProps(fieldState, props);
|
|
50
|
-
return (
|
|
51
|
-
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
|
|
52
|
-
_jsxs("div", Object.assign({ ref: anchorRef, className: b(null, className), style: props.style }, focusWithinProps, { role: "group", "aria-disabled": state.disabled || undefined, onKeyDown: (e) => {
|
|
53
|
-
if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
54
|
-
e.preventDefault();
|
|
55
|
-
e.stopPropagation();
|
|
56
|
-
state.setOpen(true);
|
|
57
|
-
}
|
|
58
|
-
}, children: [isMobile ? (_jsx(MobileCalendar, { props: props, state: state })) : (_jsx(DesktopCalendar, { anchorRef: anchorRef, props: props, state: state, renderCalendar: children })), _jsx(TextInput, Object.assign({}, inputProps, { value: fieldState.isEmpty && !isActive && props.placeholder ? '' : inputProps.value, className: b('field', { mobile: isMobile }), hasClear: !isMobile && inputProps.hasClear, rightContent: isMobile ? (_jsx(MobileCalendarIcon, { props: props, state: state })) : (_jsx(DesktopCalendarButton, { props: props, state: state })) }))] })));
|
|
21
|
+
return (_jsxs("div", Object.assign({ className: b(null, className) }, groupProps, { children: [isMobile ? (_jsx(MobileCalendar, { props: props, state: state })) : (_jsx("div", { ref: anchorRef, className: b('popup-anchor'), children: _jsx(Popup, Object.assign({ anchorRef: anchorRef }, popupProps, { children: _jsxs("div", { className: b('popup-content'), children: [typeof props.children === 'function' ? (props.children(calendarProps)) : (_jsx(Calendar, Object.assign({}, calendarProps))), state.hasTime && (_jsx("div", { className: b('time-field-wrapper'), children: _jsx(DateField, Object.assign({}, timeInputProps)) }))] }) })) })), _jsx(TextInput, Object.assign({}, fieldProps, { className: b('field', { mobile: isMobile }), hasClear: !isMobile && fieldProps.hasClear, rightContent: isMobile ? (_jsx(MobileCalendarIcon, { props: props, state: state })) : (_jsx(Button, Object.assign({}, calendarButtonProps, { children: _jsx(Icon, { data: CalendarIcon }) }))) }))] })));
|
|
59
22
|
}
|
|
@@ -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 {};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { __rest } from "tslib";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useFocusWithin, useForkRef } from '@gravity-ui/uikit';
|
|
4
|
+
import { useDateFieldProps } from '../../DateField';
|
|
5
|
+
import { getButtonSizeForInput } from '../../utils/getButtonSizeForInput';
|
|
6
|
+
import { mergeProps } from '../../utils/mergeProps';
|
|
7
|
+
import { i18n } from '../i18n';
|
|
8
|
+
export function useDatePickerProps(state, _a) {
|
|
9
|
+
var _b;
|
|
10
|
+
var { onFocus, onBlur } = _a, props = __rest(_a, ["onFocus", "onBlur"]);
|
|
11
|
+
const [isActive, setActive] = React.useState(false);
|
|
12
|
+
const { focusWithinProps } = useFocusWithin({
|
|
13
|
+
onFocusWithin: onFocus,
|
|
14
|
+
onBlurWithin: onBlur,
|
|
15
|
+
onFocusWithinChange(isFocusWithin) {
|
|
16
|
+
setActive(isFocusWithin);
|
|
17
|
+
if (!isFocusWithin) {
|
|
18
|
+
state.setOpen(false);
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const { inputProps } = useDateFieldProps(state.dateFieldState, props);
|
|
23
|
+
let error;
|
|
24
|
+
let validationState = props.validationState;
|
|
25
|
+
if (validationState) {
|
|
26
|
+
error = validationState === 'invalid' ? props.errorMessage || true : undefined;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
validationState = state.dateFieldState.validationState;
|
|
30
|
+
error = validationState === 'invalid';
|
|
31
|
+
}
|
|
32
|
+
const inputRef = React.useRef(null);
|
|
33
|
+
const handleRef = useForkRef(inputRef, inputProps.controlRef);
|
|
34
|
+
const calendarRef = React.useRef(null);
|
|
35
|
+
const calendarButtonRef = React.useRef(null);
|
|
36
|
+
const groupRef = React.useRef(null);
|
|
37
|
+
function focusInput() {
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
var _a;
|
|
40
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
groupProps: Object.assign(Object.assign({ ref: groupRef, tabIndex: -1, role: 'group' }, focusWithinProps), { style: props.style, 'aria-disabled': state.disabled || undefined, onKeyDown: (e) => {
|
|
45
|
+
if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
state.setOpen(true);
|
|
49
|
+
}
|
|
50
|
+
} }),
|
|
51
|
+
fieldProps: mergeProps(inputProps, state.dateFieldState.isEmpty && !isActive && props.placeholder
|
|
52
|
+
? { value: '' }
|
|
53
|
+
: undefined, { controlRef: handleRef, error }),
|
|
54
|
+
calendarButtonProps: {
|
|
55
|
+
ref: calendarButtonRef,
|
|
56
|
+
size: getButtonSizeForInput(props.size),
|
|
57
|
+
disabled: state.disabled,
|
|
58
|
+
extraProps: {
|
|
59
|
+
'aria-label': i18n('Calendar'),
|
|
60
|
+
'aria-haspopup': 'dialog',
|
|
61
|
+
'aria-expanded': state.isOpen,
|
|
62
|
+
},
|
|
63
|
+
view: 'flat-secondary',
|
|
64
|
+
onClick: () => {
|
|
65
|
+
setActive(true);
|
|
66
|
+
state.setOpen(!state.isOpen);
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
popupProps: {
|
|
70
|
+
open: state.isOpen,
|
|
71
|
+
onEscapeKeyDown: () => {
|
|
72
|
+
state.setOpen(false);
|
|
73
|
+
focusInput();
|
|
74
|
+
},
|
|
75
|
+
onOutsideClick: (e) => {
|
|
76
|
+
var _a;
|
|
77
|
+
if (e.target !== calendarButtonRef.current) {
|
|
78
|
+
state.setOpen(false);
|
|
79
|
+
}
|
|
80
|
+
if (e.target && ((_a = groupRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
|
|
81
|
+
focusInput();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
// @ts-expect-error focusTrap in popup was introduced in a newer version of uikit
|
|
85
|
+
focusTrap: true,
|
|
86
|
+
},
|
|
87
|
+
calendarProps: {
|
|
88
|
+
ref: calendarRef,
|
|
89
|
+
autoFocus: true,
|
|
90
|
+
size: props.size === 's' ? 'm' : props.size,
|
|
91
|
+
disabled: props.disabled,
|
|
92
|
+
readOnly: props.readOnly,
|
|
93
|
+
onUpdate: (d) => {
|
|
94
|
+
state.setDateValue(d);
|
|
95
|
+
if (!state.hasTime) {
|
|
96
|
+
focusInput();
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
defaultFocusedValue: (_b = state.dateValue) !== null && _b !== void 0 ? _b : undefined,
|
|
100
|
+
value: state.dateValue,
|
|
101
|
+
minValue: props.minValue,
|
|
102
|
+
maxValue: props.maxValue,
|
|
103
|
+
isDateUnavailable: props.isDateUnavailable,
|
|
104
|
+
timeZone: props.timeZone,
|
|
105
|
+
},
|
|
106
|
+
timeInputProps: {
|
|
107
|
+
value: state.timeValue,
|
|
108
|
+
onUpdate: state.setTimeValue,
|
|
109
|
+
format: state.timeFormat,
|
|
110
|
+
readOnly: state.readOnly,
|
|
111
|
+
disabled: state.disabled,
|
|
112
|
+
timeZone: props.timeZone,
|
|
113
|
+
hasClear: props.hasClear,
|
|
114
|
+
size: props.size,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
|
-
import type {
|
|
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
|
|
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;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { useDateFieldState } from '../../DateField';
|
|
2
3
|
import { splitFormatIntoSections } from '../../DateField/utils';
|
|
3
4
|
import { useControlledState } from '../../hooks/useControlledState';
|
|
4
5
|
import { createPlaceholderValue, mergeDateTime } from '../../utils/dates';
|
|
@@ -75,6 +76,19 @@ export function useDatePickerState(props) {
|
|
|
75
76
|
setSelectedTime(newValue);
|
|
76
77
|
}
|
|
77
78
|
};
|
|
79
|
+
const dateFieldState = useDateFieldState({
|
|
80
|
+
value: value !== null && value !== void 0 ? value : null,
|
|
81
|
+
onUpdate: setValue,
|
|
82
|
+
disabled,
|
|
83
|
+
readOnly,
|
|
84
|
+
validationState: props.validationState,
|
|
85
|
+
minValue: props.minValue,
|
|
86
|
+
maxValue: props.maxValue,
|
|
87
|
+
isDateUnavailable: props.isDateUnavailable,
|
|
88
|
+
format,
|
|
89
|
+
placeholderValue: props.placeholderValue,
|
|
90
|
+
timeZone: props.timeZone,
|
|
91
|
+
});
|
|
78
92
|
return {
|
|
79
93
|
value: value !== null && value !== void 0 ? value : null,
|
|
80
94
|
setValue,
|
|
@@ -95,6 +109,7 @@ export function useDatePickerState(props) {
|
|
|
95
109
|
}
|
|
96
110
|
setOpen(newIsOpen);
|
|
97
111
|
},
|
|
112
|
+
dateFieldState,
|
|
98
113
|
};
|
|
99
114
|
}
|
|
100
115
|
function getPlaceholderTime(placeholderValue, timeZone) {
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
var t = {};
|
|
3
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
-
t[p] = s[p];
|
|
5
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
-
t[p[i]] = s[p[i]];
|
|
9
|
-
}
|
|
10
|
-
return t;
|
|
11
|
-
};
|
|
1
|
+
import { __rest } from "tslib";
|
|
12
2
|
import React from 'react';
|
|
13
3
|
import { useFocusWithin, useForkRef } from '@gravity-ui/uikit';
|
|
14
4
|
import { useDateFieldProps } from '../../DateField';
|
|
@@ -36,7 +26,7 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
36
26
|
onBlurWithin: onBlur,
|
|
37
27
|
onFocusWithinChange(isFocusWithin) {
|
|
38
28
|
if (!isFocusWithin) {
|
|
39
|
-
state.setActive(
|
|
29
|
+
state.setActive(false);
|
|
40
30
|
}
|
|
41
31
|
},
|
|
42
32
|
});
|
|
@@ -44,16 +34,12 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
44
34
|
if (!state.isActive && isOpen) {
|
|
45
35
|
setOpen(false);
|
|
46
36
|
}
|
|
47
|
-
const [prevActive, setPrevActive] = React.useState(state.isActive);
|
|
48
|
-
if (prevActive !== state.isActive) {
|
|
49
|
-
setPrevActive(state.isActive);
|
|
50
|
-
if (state.isActive && !isOpen) {
|
|
51
|
-
setOpen(true);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
37
|
const commonInputProps = {
|
|
55
38
|
onFocus: () => {
|
|
56
|
-
state.
|
|
39
|
+
if (!state.isActive) {
|
|
40
|
+
state.setActive(true);
|
|
41
|
+
setOpen(true);
|
|
42
|
+
}
|
|
57
43
|
},
|
|
58
44
|
};
|
|
59
45
|
const { inputProps } = useDateFieldProps(dateFieldState, Object.assign(Object.assign({}, props), { value: undefined, defaultValue: undefined, onUpdate: undefined }));
|
|
@@ -62,6 +48,7 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
62
48
|
value: relativeDateState.text,
|
|
63
49
|
onUpdate: relativeDateState.setText,
|
|
64
50
|
hasClear: props.hasClear && !relativeDateState.readOnly,
|
|
51
|
+
placeholder: props.placeholder,
|
|
65
52
|
size: props.size,
|
|
66
53
|
};
|
|
67
54
|
let error;
|
|
@@ -76,19 +63,33 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
76
63
|
: dateFieldState.validationState;
|
|
77
64
|
error = validationState === 'invalid';
|
|
78
65
|
}
|
|
79
|
-
const wasActiveBeforeClickRef = React.useRef(state.isActive);
|
|
80
66
|
const inputRef = React.useRef(null);
|
|
81
67
|
const handleRef = useForkRef(inputRef, mode === 'relative' ? relativeDateProps.controlRef : inputProps.controlRef);
|
|
82
68
|
const calendarRef = React.useRef(null);
|
|
69
|
+
function focusCalendar() {
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
var _a;
|
|
72
|
+
(_a = calendarRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function focusInput() {
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
var _a;
|
|
78
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
83
81
|
return {
|
|
84
|
-
groupProps: Object.assign(Object.assign({ role: 'group' }, focusWithinProps), { onKeyDown: (e) => {
|
|
82
|
+
groupProps: Object.assign(Object.assign({ tabIndex: -1, role: 'group' }, focusWithinProps), { onKeyDown: (e) => {
|
|
85
83
|
if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
86
84
|
e.preventDefault();
|
|
87
85
|
e.stopPropagation();
|
|
88
86
|
setOpen(true);
|
|
87
|
+
focusCalendar();
|
|
89
88
|
}
|
|
90
89
|
} }),
|
|
91
|
-
fieldProps: mergeProps(commonInputProps, mode === 'relative' ? relativeDateProps : inputProps,
|
|
90
|
+
fieldProps: mergeProps(commonInputProps, mode === 'relative' ? relativeDateProps : inputProps, mode === 'absolute' && dateFieldState.isEmpty && !state.isActive && props.placeholder
|
|
91
|
+
? { value: '' }
|
|
92
|
+
: undefined, { controlRef: handleRef, error }),
|
|
92
93
|
modeSwitcherProps: {
|
|
93
94
|
size: getButtonSizeForInput(props.size),
|
|
94
95
|
disabled: state.readOnly || state.disabled,
|
|
@@ -109,7 +110,7 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
109
110
|
else if (relativeDateState.parsedDate) {
|
|
110
111
|
setFocusedDate(relativeDateState.parsedDate);
|
|
111
112
|
}
|
|
112
|
-
|
|
113
|
+
focusInput();
|
|
113
114
|
},
|
|
114
115
|
},
|
|
115
116
|
calendarButtonProps: {
|
|
@@ -121,29 +122,20 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
121
122
|
'aria-expanded': isOpen,
|
|
122
123
|
},
|
|
123
124
|
view: 'flat-secondary',
|
|
124
|
-
onFocus: () => {
|
|
125
|
-
wasActiveBeforeClickRef.current = state.isActive;
|
|
126
|
-
},
|
|
127
125
|
onClick: () => {
|
|
128
126
|
state.setActive(true);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
setTimeout(() => {
|
|
133
|
-
var _a;
|
|
134
|
-
(_a = calendarRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
135
|
-
});
|
|
136
|
-
}
|
|
127
|
+
setOpen(!isOpen);
|
|
128
|
+
if (!isOpen) {
|
|
129
|
+
focusCalendar();
|
|
137
130
|
}
|
|
138
|
-
wasActiveBeforeClickRef.current = state.isActive;
|
|
139
131
|
},
|
|
140
132
|
},
|
|
141
133
|
popupProps: {
|
|
142
134
|
open: isOpen,
|
|
143
135
|
onEscapeKeyDown: () => {
|
|
144
136
|
setOpen(false);
|
|
137
|
+
focusInput();
|
|
145
138
|
},
|
|
146
|
-
restoreFocus: true,
|
|
147
139
|
},
|
|
148
140
|
calendarProps: {
|
|
149
141
|
ref: calendarRef,
|
|
@@ -154,7 +146,7 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
154
146
|
datePickerState.setDateValue(v);
|
|
155
147
|
if (!state.datePickerState.hasTime) {
|
|
156
148
|
setOpen(false);
|
|
157
|
-
|
|
149
|
+
focusInput();
|
|
158
150
|
}
|
|
159
151
|
},
|
|
160
152
|
focusedValue: focusedDate,
|