@gravity-ui/date-components 2.5.0 → 2.7.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/DatePicker/DatePicker.d.ts +5 -2
- package/dist/cjs/components/DatePicker/hooks/datePickerStateFactory.d.ts +7 -3
- package/dist/cjs/components/DatePicker/hooks/datePickerStateFactory.js +26 -9
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.js +33 -6
- package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +16 -12
- package/dist/cjs/components/RelativeRangeDatePicker/RelativeRangeDatePicker.css +3 -0
- package/dist/cjs/components/RelativeRangeDatePicker/RelativeRangeDatePicker.js +11 -5
- package/dist/cjs/components/RelativeRangeDatePicker/components/PickerDialog/PickerDialog.css +4 -0
- package/dist/cjs/components/RelativeRangeDatePicker/components/PickerDialog/PickerDialog.js +4 -1
- package/dist/cjs/components/RelativeRangeDatePicker/components/Presets/Presets.css +4 -0
- package/dist/cjs/components/RelativeRangeDatePicker/hooks/useRelativeRangeDatePickerState.d.ts +6 -5
- package/dist/cjs/components/RelativeRangeDatePicker/index.d.ts +4 -0
- package/dist/cjs/components/RelativeRangeDatePicker/index.js +7 -1
- package/dist/cjs/components/RelativeRangeDatePicker/utils.js +1 -1
- package/dist/cjs/components/types/datePicker.d.ts +8 -0
- package/dist/esm/components/DatePicker/DatePicker.d.ts +5 -2
- package/dist/esm/components/DatePicker/hooks/datePickerStateFactory.d.ts +7 -3
- package/dist/esm/components/DatePicker/hooks/datePickerStateFactory.js +26 -9
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.js +33 -6
- package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +16 -12
- package/dist/esm/components/RelativeRangeDatePicker/RelativeRangeDatePicker.css +3 -0
- package/dist/esm/components/RelativeRangeDatePicker/RelativeRangeDatePicker.js +11 -5
- package/dist/esm/components/RelativeRangeDatePicker/components/PickerDialog/PickerDialog.css +4 -0
- package/dist/esm/components/RelativeRangeDatePicker/components/PickerDialog/PickerDialog.js +4 -1
- package/dist/esm/components/RelativeRangeDatePicker/components/Presets/Presets.css +4 -0
- package/dist/esm/components/RelativeRangeDatePicker/hooks/useRelativeRangeDatePickerState.d.ts +6 -5
- package/dist/esm/components/RelativeRangeDatePicker/index.d.ts +4 -0
- package/dist/esm/components/RelativeRangeDatePicker/index.js +2 -0
- package/dist/esm/components/RelativeRangeDatePicker/utils.js +1 -1
- package/dist/esm/components/types/datePicker.d.ts +8 -0
- package/package.json +13 -11
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
3
3
|
import type { CalendarProps } from '../Calendar';
|
|
4
|
-
import type { AccessibilityProps,
|
|
4
|
+
import type { AccessibilityProps, DomProps, FocusableProps, InputDOMProps, KeyboardEvents, StyleProps, TextInputProps } from '../types';
|
|
5
|
+
import type { DatePickerStateOptions } from './hooks/datePickerStateFactory';
|
|
5
6
|
import './DatePicker.css';
|
|
6
|
-
export interface DatePickerProps<T = DateTime> extends
|
|
7
|
+
export interface DatePickerProps<T = DateTime> extends DatePickerStateOptions<T>, TextInputProps, FocusableProps, KeyboardEvents, DomProps, InputDOMProps, StyleProps, AccessibilityProps {
|
|
7
8
|
children?: (props: CalendarProps<T>) => React.ReactNode;
|
|
9
|
+
disablePortal?: boolean;
|
|
10
|
+
disableFocusTrap?: boolean;
|
|
8
11
|
}
|
|
9
12
|
export declare function DatePicker({ className, ...props }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
2
|
import type { DateFieldState } from '../../DateField';
|
|
3
|
-
import type { DateFieldBase } from '../../types';
|
|
3
|
+
import type { DateFieldBase, PopupTriggerProps } from '../../types';
|
|
4
|
+
type OpenChangeReason = 'EscapeKeyDown' | 'FocusOut' | 'ClickOutside' | 'ValueSelected' | 'TriggerButtonClick' | 'ShortcutKeyDown';
|
|
4
5
|
export interface DatePickerState<T = DateTime> {
|
|
5
6
|
/** The currently selected date. */
|
|
6
7
|
value: T | null;
|
|
@@ -36,7 +37,7 @@ export interface DatePickerState<T = DateTime> {
|
|
|
36
37
|
/** Whether the calendar popover is currently open. */
|
|
37
38
|
isOpen: boolean;
|
|
38
39
|
/** Sets whether the calendar popover is open. */
|
|
39
|
-
setOpen: (isOpen: boolean) => void;
|
|
40
|
+
setOpen: (isOpen: boolean, reason: OpenChangeReason) => void;
|
|
40
41
|
dateFieldState: DateFieldState<T>;
|
|
41
42
|
}
|
|
42
43
|
export interface DatePickerStateFactoryOptions<T, O extends DateFieldBase<T>> {
|
|
@@ -46,4 +47,7 @@ export interface DatePickerStateFactoryOptions<T, O extends DateFieldBase<T>> {
|
|
|
46
47
|
getDateTime: (date: T | null | undefined) => DateTime | undefined;
|
|
47
48
|
useDateFieldState: (props: O) => DateFieldState<T>;
|
|
48
49
|
}
|
|
49
|
-
export
|
|
50
|
+
export interface DatePickerStateOptions<T> extends DateFieldBase<T>, PopupTriggerProps<[OpenChangeReason]> {
|
|
51
|
+
}
|
|
52
|
+
export declare function datePickerStateFactory<T, O extends DatePickerStateOptions<T>>({ getPlaceholderTime, mergeDateTime, setTimezone, getDateTime, useDateFieldState, }: DatePickerStateFactoryOptions<T, O>): (props: O) => DatePickerState<T>;
|
|
53
|
+
export {};
|
|
@@ -7,10 +7,11 @@ const uikit_1 = require("@gravity-ui/uikit");
|
|
|
7
7
|
const useDefaultTimeZone_1 = require("../../utils/useDefaultTimeZone");
|
|
8
8
|
function datePickerStateFactory({ getPlaceholderTime, mergeDateTime, setTimezone, getDateTime, useDateFieldState, }) {
|
|
9
9
|
return function useDatePickerState(props) {
|
|
10
|
-
var _a;
|
|
10
|
+
var _a, _b;
|
|
11
11
|
const { disabled, readOnly } = props;
|
|
12
|
-
const [isOpen,
|
|
13
|
-
const
|
|
12
|
+
const [isOpen, _setOpen] = (0, uikit_1.useControlledState)(props.open, (_a = props.defaultOpen) !== null && _a !== void 0 ? _a : false, props.onOpenChange);
|
|
13
|
+
const setOpen = _setOpen;
|
|
14
|
+
const [value, setValue] = (0, uikit_1.useControlledState)(props.value, (_b = props.defaultValue) !== null && _b !== void 0 ? _b : null, props.onUpdate);
|
|
14
15
|
const [selectedDateInner, setSelectedDate] = react_1.default.useState(null);
|
|
15
16
|
const [selectedTimeInner, setSelectedTime] = react_1.default.useState(null);
|
|
16
17
|
const inputTimeZone = (0, useDefaultTimeZone_1.useDefaultTimeZone)(getDateTime(props.value) || getDateTime(props.defaultValue) || props.placeholderValue);
|
|
@@ -38,9 +39,25 @@ function datePickerStateFactory({ getPlaceholderTime, mergeDateTime, setTimezone
|
|
|
38
39
|
disabled,
|
|
39
40
|
readOnly, validationState: props.validationState, minValue: props.minValue, maxValue: props.maxValue, isDateUnavailable: props.isDateUnavailable, format, placeholderValue: props.placeholderValue, timeZone }));
|
|
40
41
|
const timeFormat = react_1.default.useMemo(() => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
if (!dateFieldState.hasTime) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const timeFormatParts = [];
|
|
46
|
+
const hours = dateFieldState.sections.find((s) => s.type === 'hour');
|
|
47
|
+
if (hours) {
|
|
48
|
+
timeFormatParts.push(hours.format);
|
|
49
|
+
}
|
|
50
|
+
const minutes = dateFieldState.sections.find((s) => s.type === 'minute');
|
|
51
|
+
if (minutes) {
|
|
52
|
+
timeFormatParts.push(minutes.format);
|
|
53
|
+
}
|
|
54
|
+
const seconds = dateFieldState.sections.find((s) => s.type === 'second');
|
|
55
|
+
if (seconds) {
|
|
56
|
+
timeFormatParts.push(seconds.format);
|
|
57
|
+
}
|
|
58
|
+
const dayPeriod = dateFieldState.sections.find((s) => s.type === 'dayPeriod');
|
|
59
|
+
return timeFormatParts.join(':') + (dayPeriod ? ` ${dayPeriod.format}` : '');
|
|
60
|
+
}, [dateFieldState.hasTime, dateFieldState.sections]);
|
|
44
61
|
if (value) {
|
|
45
62
|
selectedDate = setTimezone(value, timeZone);
|
|
46
63
|
if (dateFieldState.hasTime) {
|
|
@@ -65,7 +82,7 @@ function datePickerStateFactory({ getPlaceholderTime, mergeDateTime, setTimezone
|
|
|
65
82
|
commitValue(newValue, newValue);
|
|
66
83
|
}
|
|
67
84
|
if (shouldClose) {
|
|
68
|
-
setOpen(false);
|
|
85
|
+
setOpen(false, 'ValueSelected');
|
|
69
86
|
}
|
|
70
87
|
};
|
|
71
88
|
const selectTime = (newValue) => {
|
|
@@ -108,11 +125,11 @@ function datePickerStateFactory({ getPlaceholderTime, mergeDateTime, setTimezone
|
|
|
108
125
|
timeFormat,
|
|
109
126
|
timeZone,
|
|
110
127
|
isOpen,
|
|
111
|
-
setOpen(newIsOpen) {
|
|
128
|
+
setOpen(newIsOpen, reason) {
|
|
112
129
|
if (!newIsOpen && !value && selectedDate && dateFieldState.hasTime) {
|
|
113
130
|
commitValue(selectedDate, selectedTime || getPlaceholderTime(props.placeholderValue, props.timeZone));
|
|
114
131
|
}
|
|
115
|
-
setOpen(newIsOpen);
|
|
132
|
+
setOpen(newIsOpen, reason);
|
|
116
133
|
},
|
|
117
134
|
dateFieldState,
|
|
118
135
|
};
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.useDatePickerProps = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
|
+
const date_utils_1 = require("@gravity-ui/date-utils");
|
|
6
7
|
const uikit_1 = require("@gravity-ui/uikit");
|
|
7
8
|
const DateField_1 = require("../../DateField");
|
|
8
9
|
const getButtonSizeForInput_1 = require("../../utils/getButtonSizeForInput");
|
|
@@ -12,13 +13,31 @@ const utils_1 = require("../utils");
|
|
|
12
13
|
function useDatePickerProps(state, _a) {
|
|
13
14
|
var { onFocus, onBlur } = _a, props = tslib_1.__rest(_a, ["onFocus", "onBlur"]);
|
|
14
15
|
const [isActive, setActive] = react_1.default.useState(false);
|
|
16
|
+
const [focusedDate, setFocusedDate] = react_1.default.useState((0, date_utils_1.isDateTime)(state.dateFieldState.displayValue)
|
|
17
|
+
? state.dateFieldState.displayValue
|
|
18
|
+
: state.dateFieldState.displayValue.start);
|
|
19
|
+
const [prevDateValue, setPrevDateValue] = react_1.default.useState(state.dateFieldState.displayValue);
|
|
20
|
+
if ((0, date_utils_1.isDateTime)(state.dateFieldState.displayValue)) {
|
|
21
|
+
if (!state.dateFieldState.displayValue.isSame(prevDateValue, 'day')) {
|
|
22
|
+
setPrevDateValue(state.dateFieldState.displayValue);
|
|
23
|
+
setFocusedDate(state.dateFieldState.displayValue);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else if (!state.dateFieldState.displayValue.start.isSame(prevDateValue.start, 'day')) {
|
|
27
|
+
setPrevDateValue(state.dateFieldState.displayValue);
|
|
28
|
+
setFocusedDate(state.dateFieldState.displayValue.start);
|
|
29
|
+
}
|
|
30
|
+
else if (!state.dateFieldState.displayValue.end.isSame(prevDateValue.end, 'day')) {
|
|
31
|
+
setPrevDateValue(state.dateFieldState.displayValue);
|
|
32
|
+
setFocusedDate(state.dateFieldState.displayValue.end);
|
|
33
|
+
}
|
|
15
34
|
const { focusWithinProps } = (0, uikit_1.useFocusWithin)({
|
|
16
35
|
onFocusWithin: onFocus,
|
|
17
36
|
onBlurWithin: onBlur,
|
|
18
37
|
onFocusWithinChange(isFocusWithin) {
|
|
19
38
|
setActive(isFocusWithin);
|
|
20
39
|
if (!isFocusWithin) {
|
|
21
|
-
state.setOpen(false);
|
|
40
|
+
state.setOpen(false, 'FocusOut');
|
|
22
41
|
}
|
|
23
42
|
},
|
|
24
43
|
});
|
|
@@ -40,7 +59,7 @@ function useDatePickerProps(state, _a) {
|
|
|
40
59
|
if (!onlyTime && e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
41
60
|
e.preventDefault();
|
|
42
61
|
e.stopPropagation();
|
|
43
|
-
state.setOpen(true);
|
|
62
|
+
state.setOpen(true, 'ShortcutKeyDown');
|
|
44
63
|
}
|
|
45
64
|
} }),
|
|
46
65
|
fieldProps: (0, mergeProps_1.mergeProps)(inputProps, state.dateFieldState.isEmpty && !isActive && props.placeholder
|
|
@@ -58,25 +77,31 @@ function useDatePickerProps(state, _a) {
|
|
|
58
77
|
view: 'flat-secondary',
|
|
59
78
|
onClick: () => {
|
|
60
79
|
setActive(true);
|
|
61
|
-
state.setOpen(!state.isOpen);
|
|
80
|
+
state.setOpen(!state.isOpen, 'TriggerButtonClick');
|
|
62
81
|
},
|
|
63
82
|
},
|
|
64
83
|
popupProps: {
|
|
65
84
|
open: state.isOpen,
|
|
66
85
|
onEscapeKeyDown: () => {
|
|
67
|
-
state.setOpen(false);
|
|
86
|
+
state.setOpen(false, 'EscapeKeyDown');
|
|
68
87
|
focusInput();
|
|
69
88
|
},
|
|
70
89
|
onOutsideClick: (e) => {
|
|
71
90
|
var _a;
|
|
72
91
|
if (e.target !== calendarButtonRef.current) {
|
|
73
|
-
state.setOpen(false);
|
|
92
|
+
state.setOpen(false, 'ClickOutside');
|
|
74
93
|
}
|
|
75
94
|
if (e.target && ((_a = groupRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
|
|
76
95
|
focusInput();
|
|
77
96
|
}
|
|
78
97
|
},
|
|
79
|
-
|
|
98
|
+
onTransitionExited: () => {
|
|
99
|
+
setFocusedDate((0, date_utils_1.isDateTime)(state.dateFieldState.displayValue)
|
|
100
|
+
? state.dateFieldState.displayValue
|
|
101
|
+
: state.dateFieldState.displayValue.start);
|
|
102
|
+
},
|
|
103
|
+
focusTrap: !props.disableFocusTrap,
|
|
104
|
+
disablePortal: props.disablePortal,
|
|
80
105
|
},
|
|
81
106
|
calendarProps: {
|
|
82
107
|
ref: calendarRef,
|
|
@@ -95,6 +120,8 @@ function useDatePickerProps(state, _a) {
|
|
|
95
120
|
maxValue: props.maxValue,
|
|
96
121
|
isDateUnavailable: props.isDateUnavailable,
|
|
97
122
|
timeZone: state.timeZone,
|
|
123
|
+
focusedValue: focusedDate,
|
|
124
|
+
onFocusUpdate: setFocusedDate,
|
|
98
125
|
},
|
|
99
126
|
timeInputProps: {
|
|
100
127
|
value: state.timeValue,
|
|
@@ -38,18 +38,6 @@ function useRelativeDatePickerProps(state, _a) {
|
|
|
38
38
|
if (!state.isActive && isOpen) {
|
|
39
39
|
setOpen(false);
|
|
40
40
|
}
|
|
41
|
-
const [prevOpen, setPrevOpen] = react_1.default.useState(isOpen);
|
|
42
|
-
if (isOpen !== prevOpen) {
|
|
43
|
-
setPrevOpen(isOpen);
|
|
44
|
-
if (!isOpen) {
|
|
45
|
-
// FIXME: use popup afterOpenChange instead.
|
|
46
|
-
setTimeout(() => {
|
|
47
|
-
setFocusedDate(mode === 'relative'
|
|
48
|
-
? relativeDateState.lastCorrectDate
|
|
49
|
-
: datePickerState.dateFieldState.displayValue);
|
|
50
|
-
}, 200);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
41
|
const commonInputProps = {
|
|
54
42
|
onFocus: () => {
|
|
55
43
|
if (!state.isActive) {
|
|
@@ -59,6 +47,17 @@ function useRelativeDatePickerProps(state, _a) {
|
|
|
59
47
|
},
|
|
60
48
|
errorMessage: props.errorMessage,
|
|
61
49
|
errorPlacement: props.errorPlacement,
|
|
50
|
+
controlProps: {
|
|
51
|
+
onClick: () => {
|
|
52
|
+
if (state.disabled) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!isOpen) {
|
|
56
|
+
state.setActive(true);
|
|
57
|
+
setOpen(true);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
},
|
|
62
61
|
};
|
|
63
62
|
const { inputProps } = (0, DateField_1.useDateFieldProps)(datePickerState.dateFieldState, Object.assign(Object.assign({}, props), { value: undefined, defaultValue: undefined, onUpdate: undefined }));
|
|
64
63
|
const { inputProps: relativeDateProps } = (0, RelativeDateField_1.useRelativeDateFieldProps)(relativeDateState, Object.assign(Object.assign({}, props), { value: undefined, defaultValue: undefined, onUpdate: undefined }));
|
|
@@ -145,6 +144,11 @@ function useRelativeDatePickerProps(state, _a) {
|
|
|
145
144
|
setOpen(false);
|
|
146
145
|
focusInput();
|
|
147
146
|
},
|
|
147
|
+
onTransitionExited: () => {
|
|
148
|
+
setFocusedDate(mode === 'relative'
|
|
149
|
+
? relativeDateState.lastCorrectDate
|
|
150
|
+
: datePickerState.dateFieldState.displayValue);
|
|
151
|
+
},
|
|
148
152
|
},
|
|
149
153
|
calendarProps: {
|
|
150
154
|
ref: calendarRef,
|
|
@@ -33,10 +33,7 @@ function RelativeRangeDatePicker(props) {
|
|
|
33
33
|
},
|
|
34
34
|
onBlurWithin: (e) => {
|
|
35
35
|
var _a;
|
|
36
|
-
|
|
37
|
-
const seemsIsClickOutsideInEmptySpace = open &&
|
|
38
|
-
(document.activeElement === null || document.activeElement === document.body);
|
|
39
|
-
if (!seemsIsClickOutsideInEmptySpace) {
|
|
36
|
+
if (!open) {
|
|
40
37
|
setIsActive(false);
|
|
41
38
|
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
42
39
|
}
|
|
@@ -55,7 +52,7 @@ function RelativeRangeDatePicker(props) {
|
|
|
55
52
|
}), [alwaysShowAsAbsolute, format, getRangeTitle, presetTabs, state.timeZone, state.value]);
|
|
56
53
|
const validationState = props.validationState || (state.isInvalid ? 'invalid' : undefined);
|
|
57
54
|
const errorMessage = (_a = props.errorMessage) !== null && _a !== void 0 ? _a : state.errors.join('\n');
|
|
58
|
-
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: anchorRef }, focusWithinProps, { className: b(null, props.className), style: props.style, children: [(0, jsx_runtime_1.jsx)(uikit_1.TextInput, { autoFocus: props.autoFocus, controlRef: inputRef, value: text, placeholder: props.placeholder, onUpdate: (v) => {
|
|
55
|
+
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: anchorRef }, focusWithinProps, { className: b(null, props.className), style: props.style, children: [(0, jsx_runtime_1.jsx)(uikit_1.TextInput, { id: props.id, autoFocus: props.autoFocus, controlRef: inputRef, value: text, placeholder: props.placeholder, onUpdate: (v) => {
|
|
59
56
|
if (!props.readOnly && !v) {
|
|
60
57
|
state.setValue(null, 'default');
|
|
61
58
|
}
|
|
@@ -64,6 +61,15 @@ function RelativeRangeDatePicker(props) {
|
|
|
64
61
|
'aria-expanded': open,
|
|
65
62
|
disabled: isMobile,
|
|
66
63
|
className: b('input', { mobile: isMobile }),
|
|
64
|
+
onClick: () => {
|
|
65
|
+
if (props.disabled) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!open) {
|
|
69
|
+
setIsActive(true);
|
|
70
|
+
setOpen(true);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
67
73
|
}, onKeyDown: (e) => {
|
|
68
74
|
if (props.disabled) {
|
|
69
75
|
return;
|
package/dist/cjs/components/RelativeRangeDatePicker/components/PickerDialog/PickerDialog.css
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.g-date-relative-range-date-picker-dialog__content {
|
|
2
2
|
--_--popup-content-padding: var(--g-spacing-2);
|
|
3
|
+
--_--g-date-picker-presets-padding: var(--_--popup-content-padding);
|
|
3
4
|
padding: var(--_--popup-content-padding);
|
|
4
5
|
}
|
|
5
6
|
.g-date-relative-range-date-picker-dialog__content_mobile {
|
|
@@ -29,4 +30,7 @@
|
|
|
29
30
|
margin-block: var(--g-spacing-2) calc(-1 * var(--_--popup-content-padding));
|
|
30
31
|
margin-inline: calc(-1 * var(--_--popup-content-padding));
|
|
31
32
|
border-block-start: 1px solid var(--g-color-line-generic);
|
|
33
|
+
}
|
|
34
|
+
.g-date-relative-range-date-picker-dialog__presets {
|
|
35
|
+
margin-inline: calc(-1 * var(--_--popup-content-padding));
|
|
32
36
|
}
|
|
@@ -40,5 +40,8 @@ function DialogContent(props) {
|
|
|
40
40
|
props.onApply();
|
|
41
41
|
}, className: b('apply'), width: "max", children: (0, i18n_1.i18n)('Apply') })) : null, props.withPresets && !props.readOnly ? ((0, jsx_runtime_1.jsx)(Presets_1.Presets, { size: props.size, presetTabs: props.presetTabs, onChoosePreset: (start, end) => {
|
|
42
42
|
state.setRange({ type: 'relative', value: start }, { type: 'relative', value: end });
|
|
43
|
-
|
|
43
|
+
if (!props.withApplyButton) {
|
|
44
|
+
props.onApply();
|
|
45
|
+
}
|
|
46
|
+
}, minValue: props.minValue, docs: props.docs, className: b('presets') })) : null, props.withZonesList ? ((0, jsx_runtime_1.jsx)("div", { className: b('zone'), children: (0, jsx_runtime_1.jsx)(Zones_1.Zones, { value: state.timeZone, onUpdate: state.setTimeZone, disabled: props.readOnly, size: props.size }) })) : null] }));
|
|
44
47
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
.g-date-relative-range-date-picker-presets {
|
|
2
|
+
--g-list-item-padding: 0 var(--_--g-date-picker-presets-padding, 0);
|
|
3
|
+
}
|
|
1
4
|
.g-date-relative-range-date-picker-presets__tabs {
|
|
2
5
|
--g-tabs-border-width: 0;
|
|
3
6
|
display: flex;
|
|
4
7
|
align-items: center;
|
|
5
8
|
gap: var(--g-spacing-2);
|
|
9
|
+
padding-inline: var(--_--g-date-picker-presets-padding, 0);
|
|
6
10
|
box-shadow: inset 0 -1px var(--g-color-line-generic);
|
|
7
11
|
}
|
|
8
12
|
.g-date-relative-range-date-picker-presets__list-container {
|
package/dist/cjs/components/RelativeRangeDatePicker/hooks/useRelativeRangeDatePickerState.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
2
|
import type { Value } from '../../RelativeDatePicker';
|
|
3
3
|
import type { RangeValue } from '../../types';
|
|
4
|
+
export type RelativeRangeDatePickerValue = RangeValue<Value | null>;
|
|
4
5
|
export interface RelativeRangeDatePickerState {
|
|
5
|
-
value:
|
|
6
|
+
value: RelativeRangeDatePickerValue | null;
|
|
6
7
|
timeZone: string;
|
|
7
|
-
setValue: (value:
|
|
8
|
+
setValue: (value: RelativeRangeDatePickerValue | null, timeZone: string) => void;
|
|
8
9
|
isInvalid: boolean;
|
|
9
10
|
errors: string[];
|
|
10
11
|
}
|
|
11
12
|
export interface RelativeRangeDatePickerStateOptions {
|
|
12
|
-
value?:
|
|
13
|
-
defaultValue?:
|
|
14
|
-
onUpdate?: (value:
|
|
13
|
+
value?: RelativeRangeDatePickerValue | null;
|
|
14
|
+
defaultValue?: RelativeRangeDatePickerValue;
|
|
15
|
+
onUpdate?: (value: RelativeRangeDatePickerValue | null, timeZone: string) => void;
|
|
15
16
|
timeZone?: string;
|
|
16
17
|
defaultTimeZone?: string;
|
|
17
18
|
onUpdateTimeZone?: (timeZone: string) => void;
|
|
@@ -2,3 +2,7 @@ export * from './RelativeRangeDatePicker';
|
|
|
2
2
|
export { PickerDialog as RelativeRangeDatePickerDialog } from './components/PickerDialog/PickerDialog';
|
|
3
3
|
export type { PickerDialogProps as RelativeRangeDatePickerDialogProps } from './components/PickerDialog/PickerDialog';
|
|
4
4
|
export * from './hooks/useRelativeRangeDatePickerState';
|
|
5
|
+
export { DEFAULT_DATE_PRESETS, DEFAULT_TIME_PRESETS, DEFAULT_OTHERS_PRESETS, } from './components/Presets/defaultPresets';
|
|
6
|
+
export { getDefaultPresetTabs } from './components/Presets/utils';
|
|
7
|
+
export type { Preset as RelativeRangeDatePickerPreset } from './components/Presets/defaultPresets';
|
|
8
|
+
export type { PresetTab as RelativeRangeDatePickerPresetTab } from './components/Presets/utils';
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RelativeRangeDatePickerDialog = void 0;
|
|
3
|
+
exports.getDefaultPresetTabs = exports.DEFAULT_OTHERS_PRESETS = exports.DEFAULT_TIME_PRESETS = exports.DEFAULT_DATE_PRESETS = exports.RelativeRangeDatePickerDialog = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
tslib_1.__exportStar(require("./RelativeRangeDatePicker"), exports);
|
|
6
6
|
var PickerDialog_1 = require("./components/PickerDialog/PickerDialog");
|
|
7
7
|
Object.defineProperty(exports, "RelativeRangeDatePickerDialog", { enumerable: true, get: function () { return PickerDialog_1.PickerDialog; } });
|
|
8
8
|
tslib_1.__exportStar(require("./hooks/useRelativeRangeDatePickerState"), exports);
|
|
9
|
+
var defaultPresets_1 = require("./components/Presets/defaultPresets");
|
|
10
|
+
Object.defineProperty(exports, "DEFAULT_DATE_PRESETS", { enumerable: true, get: function () { return defaultPresets_1.DEFAULT_DATE_PRESETS; } });
|
|
11
|
+
Object.defineProperty(exports, "DEFAULT_TIME_PRESETS", { enumerable: true, get: function () { return defaultPresets_1.DEFAULT_TIME_PRESETS; } });
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_OTHERS_PRESETS", { enumerable: true, get: function () { return defaultPresets_1.DEFAULT_OTHERS_PRESETS; } });
|
|
13
|
+
var utils_1 = require("./components/Presets/utils");
|
|
14
|
+
Object.defineProperty(exports, "getDefaultPresetTabs", { enumerable: true, get: function () { return utils_1.getDefaultPresetTabs; } });
|
|
@@ -27,7 +27,7 @@ function getDefaultTitle({ value, timeZone, alwaysShowAsAbsolute, format = 'L',
|
|
|
27
27
|
if (!value) {
|
|
28
28
|
return '';
|
|
29
29
|
}
|
|
30
|
-
const tz = timeZone === '
|
|
30
|
+
const tz = timeZone === 'default' ? '' : ` (${getTimeZoneOffset(timeZone)})`;
|
|
31
31
|
let from = '';
|
|
32
32
|
if (value.start) {
|
|
33
33
|
from =
|
|
@@ -17,3 +17,11 @@ export interface DateFieldBase<T = DateTime> extends ValueBase<T | null>, InputB
|
|
|
17
17
|
*/
|
|
18
18
|
timeZone?: string;
|
|
19
19
|
}
|
|
20
|
+
export interface PopupTriggerProps<Args extends unknown[] = []> {
|
|
21
|
+
/** Whether the popup is open (controlled). */
|
|
22
|
+
open?: boolean;
|
|
23
|
+
/** Whether the popup is open by default (uncontrolled). */
|
|
24
|
+
defaultOpen?: boolean;
|
|
25
|
+
/** Handler that is called when the popup's open state changes. */
|
|
26
|
+
onOpenChange?: (open: boolean, ...args: Args) => void;
|
|
27
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
3
3
|
import type { CalendarProps } from '../Calendar';
|
|
4
|
-
import type { AccessibilityProps,
|
|
4
|
+
import type { AccessibilityProps, DomProps, FocusableProps, InputDOMProps, KeyboardEvents, StyleProps, TextInputProps } from '../types';
|
|
5
|
+
import type { DatePickerStateOptions } from './hooks/datePickerStateFactory';
|
|
5
6
|
import './DatePicker.css';
|
|
6
|
-
export interface DatePickerProps<T = DateTime> extends
|
|
7
|
+
export interface DatePickerProps<T = DateTime> extends DatePickerStateOptions<T>, TextInputProps, FocusableProps, KeyboardEvents, DomProps, InputDOMProps, StyleProps, AccessibilityProps {
|
|
7
8
|
children?: (props: CalendarProps<T>) => React.ReactNode;
|
|
9
|
+
disablePortal?: boolean;
|
|
10
|
+
disableFocusTrap?: boolean;
|
|
8
11
|
}
|
|
9
12
|
export declare function DatePicker({ className, ...props }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
2
|
import type { DateFieldState } from '../../DateField';
|
|
3
|
-
import type { DateFieldBase } from '../../types';
|
|
3
|
+
import type { DateFieldBase, PopupTriggerProps } from '../../types';
|
|
4
|
+
type OpenChangeReason = 'EscapeKeyDown' | 'FocusOut' | 'ClickOutside' | 'ValueSelected' | 'TriggerButtonClick' | 'ShortcutKeyDown';
|
|
4
5
|
export interface DatePickerState<T = DateTime> {
|
|
5
6
|
/** The currently selected date. */
|
|
6
7
|
value: T | null;
|
|
@@ -36,7 +37,7 @@ export interface DatePickerState<T = DateTime> {
|
|
|
36
37
|
/** Whether the calendar popover is currently open. */
|
|
37
38
|
isOpen: boolean;
|
|
38
39
|
/** Sets whether the calendar popover is open. */
|
|
39
|
-
setOpen: (isOpen: boolean) => void;
|
|
40
|
+
setOpen: (isOpen: boolean, reason: OpenChangeReason) => void;
|
|
40
41
|
dateFieldState: DateFieldState<T>;
|
|
41
42
|
}
|
|
42
43
|
export interface DatePickerStateFactoryOptions<T, O extends DateFieldBase<T>> {
|
|
@@ -46,4 +47,7 @@ export interface DatePickerStateFactoryOptions<T, O extends DateFieldBase<T>> {
|
|
|
46
47
|
getDateTime: (date: T | null | undefined) => DateTime | undefined;
|
|
47
48
|
useDateFieldState: (props: O) => DateFieldState<T>;
|
|
48
49
|
}
|
|
49
|
-
export
|
|
50
|
+
export interface DatePickerStateOptions<T> extends DateFieldBase<T>, PopupTriggerProps<[OpenChangeReason]> {
|
|
51
|
+
}
|
|
52
|
+
export declare function datePickerStateFactory<T, O extends DatePickerStateOptions<T>>({ getPlaceholderTime, mergeDateTime, setTimezone, getDateTime, useDateFieldState, }: DatePickerStateFactoryOptions<T, O>): (props: O) => DatePickerState<T>;
|
|
53
|
+
export {};
|
|
@@ -3,10 +3,11 @@ import { useControlledState } from '@gravity-ui/uikit';
|
|
|
3
3
|
import { useDefaultTimeZone } from '../../utils/useDefaultTimeZone';
|
|
4
4
|
export function datePickerStateFactory({ getPlaceholderTime, mergeDateTime, setTimezone, getDateTime, useDateFieldState, }) {
|
|
5
5
|
return function useDatePickerState(props) {
|
|
6
|
-
var _a;
|
|
6
|
+
var _a, _b;
|
|
7
7
|
const { disabled, readOnly } = props;
|
|
8
|
-
const [isOpen,
|
|
9
|
-
const
|
|
8
|
+
const [isOpen, _setOpen] = useControlledState(props.open, (_a = props.defaultOpen) !== null && _a !== void 0 ? _a : false, props.onOpenChange);
|
|
9
|
+
const setOpen = _setOpen;
|
|
10
|
+
const [value, setValue] = useControlledState(props.value, (_b = props.defaultValue) !== null && _b !== void 0 ? _b : null, props.onUpdate);
|
|
10
11
|
const [selectedDateInner, setSelectedDate] = React.useState(null);
|
|
11
12
|
const [selectedTimeInner, setSelectedTime] = React.useState(null);
|
|
12
13
|
const inputTimeZone = useDefaultTimeZone(getDateTime(props.value) || getDateTime(props.defaultValue) || props.placeholderValue);
|
|
@@ -34,9 +35,25 @@ export function datePickerStateFactory({ getPlaceholderTime, mergeDateTime, setT
|
|
|
34
35
|
disabled,
|
|
35
36
|
readOnly, validationState: props.validationState, minValue: props.minValue, maxValue: props.maxValue, isDateUnavailable: props.isDateUnavailable, format, placeholderValue: props.placeholderValue, timeZone }));
|
|
36
37
|
const timeFormat = React.useMemo(() => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
if (!dateFieldState.hasTime) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const timeFormatParts = [];
|
|
42
|
+
const hours = dateFieldState.sections.find((s) => s.type === 'hour');
|
|
43
|
+
if (hours) {
|
|
44
|
+
timeFormatParts.push(hours.format);
|
|
45
|
+
}
|
|
46
|
+
const minutes = dateFieldState.sections.find((s) => s.type === 'minute');
|
|
47
|
+
if (minutes) {
|
|
48
|
+
timeFormatParts.push(minutes.format);
|
|
49
|
+
}
|
|
50
|
+
const seconds = dateFieldState.sections.find((s) => s.type === 'second');
|
|
51
|
+
if (seconds) {
|
|
52
|
+
timeFormatParts.push(seconds.format);
|
|
53
|
+
}
|
|
54
|
+
const dayPeriod = dateFieldState.sections.find((s) => s.type === 'dayPeriod');
|
|
55
|
+
return timeFormatParts.join(':') + (dayPeriod ? ` ${dayPeriod.format}` : '');
|
|
56
|
+
}, [dateFieldState.hasTime, dateFieldState.sections]);
|
|
40
57
|
if (value) {
|
|
41
58
|
selectedDate = setTimezone(value, timeZone);
|
|
42
59
|
if (dateFieldState.hasTime) {
|
|
@@ -61,7 +78,7 @@ export function datePickerStateFactory({ getPlaceholderTime, mergeDateTime, setT
|
|
|
61
78
|
commitValue(newValue, newValue);
|
|
62
79
|
}
|
|
63
80
|
if (shouldClose) {
|
|
64
|
-
setOpen(false);
|
|
81
|
+
setOpen(false, 'ValueSelected');
|
|
65
82
|
}
|
|
66
83
|
};
|
|
67
84
|
const selectTime = (newValue) => {
|
|
@@ -104,11 +121,11 @@ export function datePickerStateFactory({ getPlaceholderTime, mergeDateTime, setT
|
|
|
104
121
|
timeFormat,
|
|
105
122
|
timeZone,
|
|
106
123
|
isOpen,
|
|
107
|
-
setOpen(newIsOpen) {
|
|
124
|
+
setOpen(newIsOpen, reason) {
|
|
108
125
|
if (!newIsOpen && !value && selectedDate && dateFieldState.hasTime) {
|
|
109
126
|
commitValue(selectedDate, selectedTime || getPlaceholderTime(props.placeholderValue, props.timeZone));
|
|
110
127
|
}
|
|
111
|
-
setOpen(newIsOpen);
|
|
128
|
+
setOpen(newIsOpen, reason);
|
|
112
129
|
},
|
|
113
130
|
dateFieldState,
|
|
114
131
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { __rest } from "tslib";
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { isDateTime } from '@gravity-ui/date-utils';
|
|
3
4
|
import { useFocusWithin, useForkRef } from '@gravity-ui/uikit';
|
|
4
5
|
import { useDateFieldProps } from '../../DateField';
|
|
5
6
|
import { getButtonSizeForInput } from '../../utils/getButtonSizeForInput';
|
|
@@ -9,13 +10,31 @@ import { getDateTimeValue } from '../utils';
|
|
|
9
10
|
export function useDatePickerProps(state, _a) {
|
|
10
11
|
var { onFocus, onBlur } = _a, props = __rest(_a, ["onFocus", "onBlur"]);
|
|
11
12
|
const [isActive, setActive] = React.useState(false);
|
|
13
|
+
const [focusedDate, setFocusedDate] = React.useState(isDateTime(state.dateFieldState.displayValue)
|
|
14
|
+
? state.dateFieldState.displayValue
|
|
15
|
+
: state.dateFieldState.displayValue.start);
|
|
16
|
+
const [prevDateValue, setPrevDateValue] = React.useState(state.dateFieldState.displayValue);
|
|
17
|
+
if (isDateTime(state.dateFieldState.displayValue)) {
|
|
18
|
+
if (!state.dateFieldState.displayValue.isSame(prevDateValue, 'day')) {
|
|
19
|
+
setPrevDateValue(state.dateFieldState.displayValue);
|
|
20
|
+
setFocusedDate(state.dateFieldState.displayValue);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else if (!state.dateFieldState.displayValue.start.isSame(prevDateValue.start, 'day')) {
|
|
24
|
+
setPrevDateValue(state.dateFieldState.displayValue);
|
|
25
|
+
setFocusedDate(state.dateFieldState.displayValue.start);
|
|
26
|
+
}
|
|
27
|
+
else if (!state.dateFieldState.displayValue.end.isSame(prevDateValue.end, 'day')) {
|
|
28
|
+
setPrevDateValue(state.dateFieldState.displayValue);
|
|
29
|
+
setFocusedDate(state.dateFieldState.displayValue.end);
|
|
30
|
+
}
|
|
12
31
|
const { focusWithinProps } = useFocusWithin({
|
|
13
32
|
onFocusWithin: onFocus,
|
|
14
33
|
onBlurWithin: onBlur,
|
|
15
34
|
onFocusWithinChange(isFocusWithin) {
|
|
16
35
|
setActive(isFocusWithin);
|
|
17
36
|
if (!isFocusWithin) {
|
|
18
|
-
state.setOpen(false);
|
|
37
|
+
state.setOpen(false, 'FocusOut');
|
|
19
38
|
}
|
|
20
39
|
},
|
|
21
40
|
});
|
|
@@ -37,7 +56,7 @@ export function useDatePickerProps(state, _a) {
|
|
|
37
56
|
if (!onlyTime && e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
38
57
|
e.preventDefault();
|
|
39
58
|
e.stopPropagation();
|
|
40
|
-
state.setOpen(true);
|
|
59
|
+
state.setOpen(true, 'ShortcutKeyDown');
|
|
41
60
|
}
|
|
42
61
|
} }),
|
|
43
62
|
fieldProps: mergeProps(inputProps, state.dateFieldState.isEmpty && !isActive && props.placeholder
|
|
@@ -55,25 +74,31 @@ export function useDatePickerProps(state, _a) {
|
|
|
55
74
|
view: 'flat-secondary',
|
|
56
75
|
onClick: () => {
|
|
57
76
|
setActive(true);
|
|
58
|
-
state.setOpen(!state.isOpen);
|
|
77
|
+
state.setOpen(!state.isOpen, 'TriggerButtonClick');
|
|
59
78
|
},
|
|
60
79
|
},
|
|
61
80
|
popupProps: {
|
|
62
81
|
open: state.isOpen,
|
|
63
82
|
onEscapeKeyDown: () => {
|
|
64
|
-
state.setOpen(false);
|
|
83
|
+
state.setOpen(false, 'EscapeKeyDown');
|
|
65
84
|
focusInput();
|
|
66
85
|
},
|
|
67
86
|
onOutsideClick: (e) => {
|
|
68
87
|
var _a;
|
|
69
88
|
if (e.target !== calendarButtonRef.current) {
|
|
70
|
-
state.setOpen(false);
|
|
89
|
+
state.setOpen(false, 'ClickOutside');
|
|
71
90
|
}
|
|
72
91
|
if (e.target && ((_a = groupRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
|
|
73
92
|
focusInput();
|
|
74
93
|
}
|
|
75
94
|
},
|
|
76
|
-
|
|
95
|
+
onTransitionExited: () => {
|
|
96
|
+
setFocusedDate(isDateTime(state.dateFieldState.displayValue)
|
|
97
|
+
? state.dateFieldState.displayValue
|
|
98
|
+
: state.dateFieldState.displayValue.start);
|
|
99
|
+
},
|
|
100
|
+
focusTrap: !props.disableFocusTrap,
|
|
101
|
+
disablePortal: props.disablePortal,
|
|
77
102
|
},
|
|
78
103
|
calendarProps: {
|
|
79
104
|
ref: calendarRef,
|
|
@@ -92,6 +117,8 @@ export function useDatePickerProps(state, _a) {
|
|
|
92
117
|
maxValue: props.maxValue,
|
|
93
118
|
isDateUnavailable: props.isDateUnavailable,
|
|
94
119
|
timeZone: state.timeZone,
|
|
120
|
+
focusedValue: focusedDate,
|
|
121
|
+
onFocusUpdate: setFocusedDate,
|
|
95
122
|
},
|
|
96
123
|
timeInputProps: {
|
|
97
124
|
value: state.timeValue,
|
|
@@ -35,18 +35,6 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
35
35
|
if (!state.isActive && isOpen) {
|
|
36
36
|
setOpen(false);
|
|
37
37
|
}
|
|
38
|
-
const [prevOpen, setPrevOpen] = React.useState(isOpen);
|
|
39
|
-
if (isOpen !== prevOpen) {
|
|
40
|
-
setPrevOpen(isOpen);
|
|
41
|
-
if (!isOpen) {
|
|
42
|
-
// FIXME: use popup afterOpenChange instead.
|
|
43
|
-
setTimeout(() => {
|
|
44
|
-
setFocusedDate(mode === 'relative'
|
|
45
|
-
? relativeDateState.lastCorrectDate
|
|
46
|
-
: datePickerState.dateFieldState.displayValue);
|
|
47
|
-
}, 200);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
38
|
const commonInputProps = {
|
|
51
39
|
onFocus: () => {
|
|
52
40
|
if (!state.isActive) {
|
|
@@ -56,6 +44,17 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
56
44
|
},
|
|
57
45
|
errorMessage: props.errorMessage,
|
|
58
46
|
errorPlacement: props.errorPlacement,
|
|
47
|
+
controlProps: {
|
|
48
|
+
onClick: () => {
|
|
49
|
+
if (state.disabled) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (!isOpen) {
|
|
53
|
+
state.setActive(true);
|
|
54
|
+
setOpen(true);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
},
|
|
59
58
|
};
|
|
60
59
|
const { inputProps } = useDateFieldProps(datePickerState.dateFieldState, Object.assign(Object.assign({}, props), { value: undefined, defaultValue: undefined, onUpdate: undefined }));
|
|
61
60
|
const { inputProps: relativeDateProps } = useRelativeDateFieldProps(relativeDateState, Object.assign(Object.assign({}, props), { value: undefined, defaultValue: undefined, onUpdate: undefined }));
|
|
@@ -142,6 +141,11 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
142
141
|
setOpen(false);
|
|
143
142
|
focusInput();
|
|
144
143
|
},
|
|
144
|
+
onTransitionExited: () => {
|
|
145
|
+
setFocusedDate(mode === 'relative'
|
|
146
|
+
? relativeDateState.lastCorrectDate
|
|
147
|
+
: datePickerState.dateFieldState.displayValue);
|
|
148
|
+
},
|
|
145
149
|
},
|
|
146
150
|
calendarProps: {
|
|
147
151
|
ref: calendarRef,
|
|
@@ -29,10 +29,7 @@ export function RelativeRangeDatePicker(props) {
|
|
|
29
29
|
},
|
|
30
30
|
onBlurWithin: (e) => {
|
|
31
31
|
var _a;
|
|
32
|
-
|
|
33
|
-
const seemsIsClickOutsideInEmptySpace = open &&
|
|
34
|
-
(document.activeElement === null || document.activeElement === document.body);
|
|
35
|
-
if (!seemsIsClickOutsideInEmptySpace) {
|
|
32
|
+
if (!open) {
|
|
36
33
|
setIsActive(false);
|
|
37
34
|
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
38
35
|
}
|
|
@@ -51,7 +48,7 @@ export function RelativeRangeDatePicker(props) {
|
|
|
51
48
|
}), [alwaysShowAsAbsolute, format, getRangeTitle, presetTabs, state.timeZone, state.value]);
|
|
52
49
|
const validationState = props.validationState || (state.isInvalid ? 'invalid' : undefined);
|
|
53
50
|
const errorMessage = (_a = props.errorMessage) !== null && _a !== void 0 ? _a : state.errors.join('\n');
|
|
54
|
-
return (_jsxs("div", Object.assign({ ref: anchorRef }, focusWithinProps, { className: b(null, props.className), style: props.style, children: [_jsx(TextInput, { autoFocus: props.autoFocus, controlRef: inputRef, value: text, placeholder: props.placeholder, onUpdate: (v) => {
|
|
51
|
+
return (_jsxs("div", Object.assign({ ref: anchorRef }, focusWithinProps, { className: b(null, props.className), style: props.style, children: [_jsx(TextInput, { id: props.id, autoFocus: props.autoFocus, controlRef: inputRef, value: text, placeholder: props.placeholder, onUpdate: (v) => {
|
|
55
52
|
if (!props.readOnly && !v) {
|
|
56
53
|
state.setValue(null, 'default');
|
|
57
54
|
}
|
|
@@ -60,6 +57,15 @@ export function RelativeRangeDatePicker(props) {
|
|
|
60
57
|
'aria-expanded': open,
|
|
61
58
|
disabled: isMobile,
|
|
62
59
|
className: b('input', { mobile: isMobile }),
|
|
60
|
+
onClick: () => {
|
|
61
|
+
if (props.disabled) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!open) {
|
|
65
|
+
setIsActive(true);
|
|
66
|
+
setOpen(true);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
63
69
|
}, onKeyDown: (e) => {
|
|
64
70
|
if (props.disabled) {
|
|
65
71
|
return;
|
package/dist/esm/components/RelativeRangeDatePicker/components/PickerDialog/PickerDialog.css
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.g-date-relative-range-date-picker-dialog__content {
|
|
2
2
|
--_--popup-content-padding: var(--g-spacing-2);
|
|
3
|
+
--_--g-date-picker-presets-padding: var(--_--popup-content-padding);
|
|
3
4
|
padding: var(--_--popup-content-padding);
|
|
4
5
|
}
|
|
5
6
|
.g-date-relative-range-date-picker-dialog__content_mobile {
|
|
@@ -29,4 +30,7 @@
|
|
|
29
30
|
margin-block: var(--g-spacing-2) calc(-1 * var(--_--popup-content-padding));
|
|
30
31
|
margin-inline: calc(-1 * var(--_--popup-content-padding));
|
|
31
32
|
border-block-start: 1px solid var(--g-color-line-generic);
|
|
33
|
+
}
|
|
34
|
+
.g-date-relative-range-date-picker-dialog__presets {
|
|
35
|
+
margin-inline: calc(-1 * var(--_--popup-content-padding));
|
|
32
36
|
}
|
|
@@ -36,5 +36,8 @@ function DialogContent(props) {
|
|
|
36
36
|
props.onApply();
|
|
37
37
|
}, className: b('apply'), width: "max", children: i18n('Apply') })) : null, props.withPresets && !props.readOnly ? (_jsx(Presets, { size: props.size, presetTabs: props.presetTabs, onChoosePreset: (start, end) => {
|
|
38
38
|
state.setRange({ type: 'relative', value: start }, { type: 'relative', value: end });
|
|
39
|
-
|
|
39
|
+
if (!props.withApplyButton) {
|
|
40
|
+
props.onApply();
|
|
41
|
+
}
|
|
42
|
+
}, minValue: props.minValue, docs: props.docs, className: b('presets') })) : null, props.withZonesList ? (_jsx("div", { className: b('zone'), children: _jsx(Zones, { value: state.timeZone, onUpdate: state.setTimeZone, disabled: props.readOnly, size: props.size }) })) : null] }));
|
|
40
43
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
.g-date-relative-range-date-picker-presets {
|
|
2
|
+
--g-list-item-padding: 0 var(--_--g-date-picker-presets-padding, 0);
|
|
3
|
+
}
|
|
1
4
|
.g-date-relative-range-date-picker-presets__tabs {
|
|
2
5
|
--g-tabs-border-width: 0;
|
|
3
6
|
display: flex;
|
|
4
7
|
align-items: center;
|
|
5
8
|
gap: var(--g-spacing-2);
|
|
9
|
+
padding-inline: var(--_--g-date-picker-presets-padding, 0);
|
|
6
10
|
box-shadow: inset 0 -1px var(--g-color-line-generic);
|
|
7
11
|
}
|
|
8
12
|
.g-date-relative-range-date-picker-presets__list-container {
|
package/dist/esm/components/RelativeRangeDatePicker/hooks/useRelativeRangeDatePickerState.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
2
|
import type { Value } from '../../RelativeDatePicker';
|
|
3
3
|
import type { RangeValue } from '../../types';
|
|
4
|
+
export type RelativeRangeDatePickerValue = RangeValue<Value | null>;
|
|
4
5
|
export interface RelativeRangeDatePickerState {
|
|
5
|
-
value:
|
|
6
|
+
value: RelativeRangeDatePickerValue | null;
|
|
6
7
|
timeZone: string;
|
|
7
|
-
setValue: (value:
|
|
8
|
+
setValue: (value: RelativeRangeDatePickerValue | null, timeZone: string) => void;
|
|
8
9
|
isInvalid: boolean;
|
|
9
10
|
errors: string[];
|
|
10
11
|
}
|
|
11
12
|
export interface RelativeRangeDatePickerStateOptions {
|
|
12
|
-
value?:
|
|
13
|
-
defaultValue?:
|
|
14
|
-
onUpdate?: (value:
|
|
13
|
+
value?: RelativeRangeDatePickerValue | null;
|
|
14
|
+
defaultValue?: RelativeRangeDatePickerValue;
|
|
15
|
+
onUpdate?: (value: RelativeRangeDatePickerValue | null, timeZone: string) => void;
|
|
15
16
|
timeZone?: string;
|
|
16
17
|
defaultTimeZone?: string;
|
|
17
18
|
onUpdateTimeZone?: (timeZone: string) => void;
|
|
@@ -2,3 +2,7 @@ export * from './RelativeRangeDatePicker';
|
|
|
2
2
|
export { PickerDialog as RelativeRangeDatePickerDialog } from './components/PickerDialog/PickerDialog';
|
|
3
3
|
export type { PickerDialogProps as RelativeRangeDatePickerDialogProps } from './components/PickerDialog/PickerDialog';
|
|
4
4
|
export * from './hooks/useRelativeRangeDatePickerState';
|
|
5
|
+
export { DEFAULT_DATE_PRESETS, DEFAULT_TIME_PRESETS, DEFAULT_OTHERS_PRESETS, } from './components/Presets/defaultPresets';
|
|
6
|
+
export { getDefaultPresetTabs } from './components/Presets/utils';
|
|
7
|
+
export type { Preset as RelativeRangeDatePickerPreset } from './components/Presets/defaultPresets';
|
|
8
|
+
export type { PresetTab as RelativeRangeDatePickerPresetTab } from './components/Presets/utils';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export * from './RelativeRangeDatePicker';
|
|
2
2
|
export { PickerDialog as RelativeRangeDatePickerDialog } from './components/PickerDialog/PickerDialog';
|
|
3
3
|
export * from './hooks/useRelativeRangeDatePickerState';
|
|
4
|
+
export { DEFAULT_DATE_PRESETS, DEFAULT_TIME_PRESETS, DEFAULT_OTHERS_PRESETS, } from './components/Presets/defaultPresets';
|
|
5
|
+
export { getDefaultPresetTabs } from './components/Presets/utils';
|
|
@@ -21,7 +21,7 @@ export function getDefaultTitle({ value, timeZone, alwaysShowAsAbsolute, format
|
|
|
21
21
|
if (!value) {
|
|
22
22
|
return '';
|
|
23
23
|
}
|
|
24
|
-
const tz = timeZone === '
|
|
24
|
+
const tz = timeZone === 'default' ? '' : ` (${getTimeZoneOffset(timeZone)})`;
|
|
25
25
|
let from = '';
|
|
26
26
|
if (value.start) {
|
|
27
27
|
from =
|
|
@@ -17,3 +17,11 @@ export interface DateFieldBase<T = DateTime> extends ValueBase<T | null>, InputB
|
|
|
17
17
|
*/
|
|
18
18
|
timeZone?: string;
|
|
19
19
|
}
|
|
20
|
+
export interface PopupTriggerProps<Args extends unknown[] = []> {
|
|
21
|
+
/** Whether the popup is open (controlled). */
|
|
22
|
+
open?: boolean;
|
|
23
|
+
/** Whether the popup is open by default (uncontrolled). */
|
|
24
|
+
defaultOpen?: boolean;
|
|
25
|
+
/** Handler that is called when the popup's open state changes. */
|
|
26
|
+
onOpenChange?: (open: boolean, ...args: Args) => void;
|
|
27
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/date-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -61,17 +61,19 @@
|
|
|
61
61
|
"@gravity-ui/stylelint-config": "^4.0.1",
|
|
62
62
|
"@gravity-ui/tsconfig": "^1.0.0",
|
|
63
63
|
"@gravity-ui/uikit": "^6.15.0",
|
|
64
|
-
"@storybook/addon-a11y": "^8.1.
|
|
65
|
-
"@storybook/addon-
|
|
66
|
-
"@storybook/addon-
|
|
64
|
+
"@storybook/addon-a11y": "^8.1.10",
|
|
65
|
+
"@storybook/addon-actions": "^8.1.10",
|
|
66
|
+
"@storybook/addon-essentials": "^8.1.10",
|
|
67
|
+
"@storybook/addon-storysource": "^8.1.10",
|
|
68
|
+
"@storybook/addon-viewport": "^8.1.10",
|
|
67
69
|
"@storybook/addon-webpack5-compiler-babel": "^3.0.3",
|
|
68
|
-
"@storybook/blocks": "^8.1.
|
|
69
|
-
"@storybook/manager-api": "^8.1.
|
|
70
|
+
"@storybook/blocks": "^8.1.10",
|
|
71
|
+
"@storybook/manager-api": "^8.1.10",
|
|
70
72
|
"@storybook/preset-scss": "^1.0.3",
|
|
71
|
-
"@storybook/react": "^8.1.
|
|
72
|
-
"@storybook/react-webpack5": "^8.1.
|
|
73
|
-
"@storybook/theming": "^8.1.
|
|
74
|
-
"@storybook/types": "^8.1.
|
|
73
|
+
"@storybook/react": "^8.1.10",
|
|
74
|
+
"@storybook/react-webpack5": "^8.1.10",
|
|
75
|
+
"@storybook/theming": "^8.1.10",
|
|
76
|
+
"@storybook/types": "^8.1.10",
|
|
75
77
|
"@testing-library/dom": "^10.1.0",
|
|
76
78
|
"@testing-library/jest-dom": "^6.4.6",
|
|
77
79
|
"@testing-library/react": "^16.0.0",
|
|
@@ -98,7 +100,7 @@
|
|
|
98
100
|
"react-dom": "^18.3.1",
|
|
99
101
|
"rimraf": "^5.0.7",
|
|
100
102
|
"sass": "^1.77.1",
|
|
101
|
-
"storybook": "^8.1.
|
|
103
|
+
"storybook": "^8.1.10",
|
|
102
104
|
"stylelint": "^15.11.0",
|
|
103
105
|
"stylelint-use-logical": "^2.1.2",
|
|
104
106
|
"ts-jest": "^29.1.5",
|