@gravity-ui/date-components 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/Calendar/Calendar.css +9 -1
- package/dist/cjs/components/Calendar/CalendarBase.js +9 -9
- package/dist/cjs/components/Calendar/hooks/types.d.ts +5 -2
- package/dist/cjs/components/Calendar/hooks/useCalendarCellProps.js +21 -16
- package/dist/cjs/components/Calendar/hooks/useCalendarGridProps.js +2 -7
- package/dist/cjs/components/Calendar/hooks/useCalendarProps.js +6 -3
- package/dist/cjs/components/Calendar/hooks/useCalendarState.js +69 -26
- package/dist/cjs/components/Calendar/hooks/useRangeCalendarState.js +16 -11
- package/dist/cjs/components/Calendar/utils.d.ts +3 -1
- package/dist/cjs/components/Calendar/utils.js +7 -1
- package/dist/cjs/components/DateField/hooks/useDateFieldProps.js +23 -16
- package/dist/cjs/components/DateField/hooks/useDateFieldState.d.ts +2 -0
- package/dist/cjs/components/DateField/hooks/useDateFieldState.js +49 -166
- package/dist/cjs/components/DateField/types.d.ts +1 -1
- package/dist/cjs/components/DateField/utils.d.ts +12 -9
- package/dist/cjs/components/DateField/utils.js +168 -25
- package/dist/cjs/components/DatePicker/DatePicker.css +6 -0
- package/dist/cjs/components/DatePicker/DatePicker.d.ts +4 -1
- package/dist/cjs/components/DatePicker/DatePicker.js +6 -33
- package/dist/cjs/components/DatePicker/MobileCalendar.js +4 -4
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
- package/dist/cjs/components/DatePicker/hooks/useDatePickerProps.js +134 -0
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +18 -8
- package/dist/cjs/components/DatePicker/index.d.ts +1 -0
- package/dist/cjs/components/DatePicker/index.js +1 -0
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.css +1 -0
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.d.ts +3 -0
- package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.js +1 -1
- package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +35 -27
- package/dist/cjs/components/utils/dates.d.ts +9 -0
- package/dist/cjs/components/utils/dates.js +28 -0
- package/dist/esm/components/Calendar/Calendar.css +9 -1
- package/dist/esm/components/Calendar/CalendarBase.js +10 -10
- package/dist/esm/components/Calendar/hooks/types.d.ts +5 -2
- package/dist/esm/components/Calendar/hooks/useCalendarCellProps.js +21 -16
- package/dist/esm/components/Calendar/hooks/useCalendarGridProps.js +2 -7
- package/dist/esm/components/Calendar/hooks/useCalendarProps.js +6 -3
- package/dist/esm/components/Calendar/hooks/useCalendarState.js +70 -27
- package/dist/esm/components/Calendar/hooks/useRangeCalendarState.js +16 -11
- package/dist/esm/components/Calendar/utils.d.ts +3 -1
- package/dist/esm/components/Calendar/utils.js +6 -0
- package/dist/esm/components/DateField/hooks/useDateFieldProps.js +23 -16
- package/dist/esm/components/DateField/hooks/useDateFieldState.d.ts +2 -0
- package/dist/esm/components/DateField/hooks/useDateFieldState.js +41 -158
- package/dist/esm/components/DateField/types.d.ts +1 -1
- package/dist/esm/components/DateField/utils.d.ts +12 -9
- package/dist/esm/components/DateField/utils.js +162 -21
- package/dist/esm/components/DatePicker/DatePicker.css +6 -0
- package/dist/esm/components/DatePicker/DatePicker.d.ts +4 -1
- package/dist/esm/components/DatePicker/DatePicker.js +8 -35
- package/dist/esm/components/DatePicker/MobileCalendar.js +1 -1
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.d.ts +20 -0
- package/dist/esm/components/DatePicker/hooks/useDatePickerProps.js +127 -0
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.d.ts +4 -5
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +17 -7
- 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/RelativeDatePicker.d.ts +3 -0
- package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.js +1 -1
- package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +35 -27
- package/dist/esm/components/utils/dates.d.ts +9 -0
- package/dist/esm/components/utils/dates.js +22 -0
- package/package.json +8 -7
- package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +0 -15
- package/dist/cjs/components/DatePicker/DesktopCalendar.js +0 -56
- package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +0 -15
- package/dist/esm/components/DatePicker/DesktopCalendar.js +0 -48
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
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
|
+
};
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { useFocusWithin, useForkRef } from '@gravity-ui/uikit';
|
|
14
|
+
import { useDateFieldProps } from '../../DateField';
|
|
15
|
+
import { getButtonSizeForInput } from '../../utils/getButtonSizeForInput';
|
|
16
|
+
import { mergeProps } from '../../utils/mergeProps';
|
|
17
|
+
import { i18n } from '../i18n';
|
|
18
|
+
export function useDatePickerProps(state, _a) {
|
|
19
|
+
var _b;
|
|
20
|
+
var { onFocus, onBlur } = _a, props = __rest(_a, ["onFocus", "onBlur"]);
|
|
21
|
+
const [isActive, setActive] = React.useState(false);
|
|
22
|
+
const { focusWithinProps } = useFocusWithin({
|
|
23
|
+
onFocusWithin: onFocus,
|
|
24
|
+
onBlurWithin: onBlur,
|
|
25
|
+
onFocusWithinChange(isFocusWithin) {
|
|
26
|
+
setActive(isFocusWithin);
|
|
27
|
+
if (!isFocusWithin) {
|
|
28
|
+
state.setOpen(false);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const { inputProps } = useDateFieldProps(state.dateFieldState, props);
|
|
33
|
+
let error;
|
|
34
|
+
let validationState = props.validationState;
|
|
35
|
+
if (validationState) {
|
|
36
|
+
error = validationState === 'invalid' ? props.errorMessage || true : undefined;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
validationState = state.dateFieldState.validationState;
|
|
40
|
+
error = validationState === 'invalid';
|
|
41
|
+
}
|
|
42
|
+
const inputRef = React.useRef(null);
|
|
43
|
+
const handleRef = useForkRef(inputRef, inputProps.controlRef);
|
|
44
|
+
const calendarRef = React.useRef(null);
|
|
45
|
+
const calendarButtonRef = React.useRef(null);
|
|
46
|
+
const groupRef = React.useRef(null);
|
|
47
|
+
function focusInput() {
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
var _a;
|
|
50
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
groupProps: Object.assign(Object.assign({ ref: groupRef, tabIndex: -1, role: 'group' }, focusWithinProps), { style: props.style, 'aria-disabled': state.disabled || undefined, onKeyDown: (e) => {
|
|
55
|
+
if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
e.stopPropagation();
|
|
58
|
+
state.setOpen(true);
|
|
59
|
+
}
|
|
60
|
+
} }),
|
|
61
|
+
fieldProps: mergeProps(inputProps, state.dateFieldState.isEmpty && !isActive && props.placeholder
|
|
62
|
+
? { value: '' }
|
|
63
|
+
: undefined, { controlRef: handleRef, error }),
|
|
64
|
+
calendarButtonProps: {
|
|
65
|
+
ref: calendarButtonRef,
|
|
66
|
+
size: getButtonSizeForInput(props.size),
|
|
67
|
+
disabled: state.disabled,
|
|
68
|
+
extraProps: {
|
|
69
|
+
'aria-label': i18n('Calendar'),
|
|
70
|
+
'aria-haspopup': 'dialog',
|
|
71
|
+
'aria-expanded': state.isOpen,
|
|
72
|
+
},
|
|
73
|
+
view: 'flat-secondary',
|
|
74
|
+
onClick: () => {
|
|
75
|
+
setActive(true);
|
|
76
|
+
state.setOpen(!state.isOpen);
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
popupProps: {
|
|
80
|
+
open: state.isOpen,
|
|
81
|
+
onEscapeKeyDown: () => {
|
|
82
|
+
state.setOpen(false);
|
|
83
|
+
focusInput();
|
|
84
|
+
},
|
|
85
|
+
onOutsideClick: (e) => {
|
|
86
|
+
var _a;
|
|
87
|
+
if (e.target !== calendarButtonRef.current) {
|
|
88
|
+
state.setOpen(false);
|
|
89
|
+
}
|
|
90
|
+
if (e.target && ((_a = groupRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
|
|
91
|
+
focusInput();
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
// @ts-expect-error focusTrap in popup was introduced in a newer version of uikit
|
|
95
|
+
focusTrap: true,
|
|
96
|
+
},
|
|
97
|
+
calendarProps: {
|
|
98
|
+
ref: calendarRef,
|
|
99
|
+
autoFocus: true,
|
|
100
|
+
size: props.size === 's' ? 'm' : props.size,
|
|
101
|
+
disabled: props.disabled,
|
|
102
|
+
readOnly: props.readOnly,
|
|
103
|
+
onUpdate: (d) => {
|
|
104
|
+
state.setDateValue(d);
|
|
105
|
+
if (!state.hasTime) {
|
|
106
|
+
focusInput();
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
defaultFocusedValue: (_b = state.dateValue) !== null && _b !== void 0 ? _b : undefined,
|
|
110
|
+
value: state.dateValue,
|
|
111
|
+
minValue: props.minValue,
|
|
112
|
+
maxValue: props.maxValue,
|
|
113
|
+
isDateUnavailable: props.isDateUnavailable,
|
|
114
|
+
timeZone: props.timeZone,
|
|
115
|
+
},
|
|
116
|
+
timeInputProps: {
|
|
117
|
+
value: state.timeValue,
|
|
118
|
+
onUpdate: state.setTimeValue,
|
|
119
|
+
format: state.timeFormat,
|
|
120
|
+
readOnly: state.readOnly,
|
|
121
|
+
disabled: state.disabled,
|
|
122
|
+
timeZone: props.timeZone,
|
|
123
|
+
hasClear: props.hasClear,
|
|
124
|
+
size: props.size,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -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,6 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useDateFieldState } from '../../DateField';
|
|
3
|
+
import { splitFormatIntoSections } from '../../DateField/utils';
|
|
3
4
|
import { useControlledState } from '../../hooks/useControlledState';
|
|
5
|
+
import { createPlaceholderValue, mergeDateTime } from '../../utils/dates';
|
|
4
6
|
export function useDatePickerState(props) {
|
|
5
7
|
const { disabled, readOnly } = props;
|
|
6
8
|
const [isOpen, setOpen] = React.useState(false);
|
|
@@ -74,6 +76,19 @@ export function useDatePickerState(props) {
|
|
|
74
76
|
setSelectedTime(newValue);
|
|
75
77
|
}
|
|
76
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
|
+
});
|
|
77
92
|
return {
|
|
78
93
|
value: value !== null && value !== void 0 ? value : null,
|
|
79
94
|
setValue,
|
|
@@ -94,14 +109,9 @@ export function useDatePickerState(props) {
|
|
|
94
109
|
}
|
|
95
110
|
setOpen(newIsOpen);
|
|
96
111
|
},
|
|
112
|
+
dateFieldState,
|
|
97
113
|
};
|
|
98
114
|
}
|
|
99
|
-
function mergeDateTime(date, time) {
|
|
100
|
-
return date
|
|
101
|
-
.set('hours', time.hour())
|
|
102
|
-
.set('minutes', time.minute())
|
|
103
|
-
.set('seconds', time.second());
|
|
104
|
-
}
|
|
105
115
|
function getPlaceholderTime(placeholderValue, timeZone) {
|
|
106
116
|
return createPlaceholderValue({ placeholderValue, timeZone });
|
|
107
117
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { CalendarProps } from '../Calendar';
|
|
1
3
|
import type { AccessibilityProps, DomProps, FocusableProps, KeyboardEvents, StyleProps, TextInputProps } from '../types';
|
|
2
4
|
import type { RelativeDatePickerStateOptions } from './hooks/useRelativeDatePickerState';
|
|
3
5
|
import './RelativeDatePicker.css';
|
|
4
6
|
export interface RelativeDatePickerProps extends RelativeDatePickerStateOptions, TextInputProps, FocusableProps, KeyboardEvents, DomProps, StyleProps, AccessibilityProps {
|
|
7
|
+
children?: (props: CalendarProps) => React.ReactNode;
|
|
5
8
|
}
|
|
6
9
|
export declare function RelativeDatePicker(props: RelativeDatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -21,5 +21,5 @@ export function RelativeDatePicker(props) {
|
|
|
21
21
|
readOnly: props.readOnly,
|
|
22
22
|
placeholderValue: props.placeholderValue,
|
|
23
23
|
timeZone: props.timeZone,
|
|
24
|
-
} })), _jsx(TextInput, Object.assign({}, fieldProps, { leftContent: _jsx(Button, Object.assign({}, modeSwitcherProps, { children: _jsx(Icon, { data: FunctionIcon }) })), rightContent: _jsxs(React.Fragment, { children: [!isMobile && (_jsx(Button, Object.assign({}, calendarButtonProps, { children: _jsx(Icon, { data: CalendarIcon }) }))), isMobile && state.mode === 'absolute' && (_jsx(MobileCalendarIcon, { state: state.datePickerState, props: { size: props.size } }))] }) })), !isMobile && (_jsx(Popup, Object.assign({}, popupProps, { anchorRef: anchorRef, children: _jsxs("div", { className: b('popup-content'), children: [_jsx(Calendar, Object.assign({}, calendarProps)), state.datePickerState.hasTime && (_jsx("div", { className: b('time-field-wrapper'), children: _jsx(DateField, Object.assign({}, timeInputProps)) }))] }) })))] })));
|
|
24
|
+
} })), _jsx(TextInput, Object.assign({}, fieldProps, { leftContent: _jsx(Button, Object.assign({}, modeSwitcherProps, { children: _jsx(Icon, { data: FunctionIcon }) })), rightContent: _jsxs(React.Fragment, { children: [!isMobile && (_jsx(Button, Object.assign({}, calendarButtonProps, { children: _jsx(Icon, { data: CalendarIcon }) }))), isMobile && state.mode === 'absolute' && (_jsx(MobileCalendarIcon, { state: state.datePickerState, props: { size: props.size } }))] }) })), !isMobile && (_jsx(Popup, Object.assign({}, popupProps, { anchorRef: anchorRef, children: _jsxs("div", { className: b('popup-content'), children: [typeof props.children === 'function' ? (props.children(calendarProps)) : (_jsx(Calendar, Object.assign({}, calendarProps))), state.datePickerState.hasTime && (_jsx("div", { className: b('time-field-wrapper'), children: _jsx(DateField, Object.assign({}, timeInputProps)) }))] }) })))] })));
|
|
25
25
|
}
|
|
@@ -36,7 +36,7 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
36
36
|
onBlurWithin: onBlur,
|
|
37
37
|
onFocusWithinChange(isFocusWithin) {
|
|
38
38
|
if (!isFocusWithin) {
|
|
39
|
-
state.setActive(
|
|
39
|
+
state.setActive(false);
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
});
|
|
@@ -44,16 +44,12 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
44
44
|
if (!state.isActive && isOpen) {
|
|
45
45
|
setOpen(false);
|
|
46
46
|
}
|
|
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
47
|
const commonInputProps = {
|
|
55
48
|
onFocus: () => {
|
|
56
|
-
state.
|
|
49
|
+
if (!state.isActive) {
|
|
50
|
+
state.setActive(true);
|
|
51
|
+
setOpen(true);
|
|
52
|
+
}
|
|
57
53
|
},
|
|
58
54
|
};
|
|
59
55
|
const { inputProps } = useDateFieldProps(dateFieldState, Object.assign(Object.assign({}, props), { value: undefined, defaultValue: undefined, onUpdate: undefined }));
|
|
@@ -62,6 +58,7 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
62
58
|
value: relativeDateState.text,
|
|
63
59
|
onUpdate: relativeDateState.setText,
|
|
64
60
|
hasClear: props.hasClear && !relativeDateState.readOnly,
|
|
61
|
+
placeholder: props.placeholder,
|
|
65
62
|
size: props.size,
|
|
66
63
|
};
|
|
67
64
|
let error;
|
|
@@ -76,13 +73,33 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
76
73
|
: dateFieldState.validationState;
|
|
77
74
|
error = validationState === 'invalid';
|
|
78
75
|
}
|
|
79
|
-
const wasActiveBeforeClickRef = React.useRef(state.isActive);
|
|
80
76
|
const inputRef = React.useRef(null);
|
|
81
77
|
const handleRef = useForkRef(inputRef, mode === 'relative' ? relativeDateProps.controlRef : inputProps.controlRef);
|
|
82
78
|
const calendarRef = React.useRef(null);
|
|
79
|
+
function focusCalendar() {
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
var _a;
|
|
82
|
+
(_a = calendarRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function focusInput() {
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
var _a;
|
|
88
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
83
91
|
return {
|
|
84
|
-
groupProps: Object.assign({ role: 'group' }, focusWithinProps),
|
|
85
|
-
|
|
92
|
+
groupProps: Object.assign(Object.assign({ tabIndex: -1, role: 'group' }, focusWithinProps), { onKeyDown: (e) => {
|
|
93
|
+
if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
e.stopPropagation();
|
|
96
|
+
setOpen(true);
|
|
97
|
+
focusCalendar();
|
|
98
|
+
}
|
|
99
|
+
} }),
|
|
100
|
+
fieldProps: mergeProps(commonInputProps, mode === 'relative' ? relativeDateProps : inputProps, mode === 'absolute' && dateFieldState.isEmpty && !state.isActive && props.placeholder
|
|
101
|
+
? { value: '' }
|
|
102
|
+
: undefined, { controlRef: handleRef, error }),
|
|
86
103
|
modeSwitcherProps: {
|
|
87
104
|
size: getButtonSizeForInput(props.size),
|
|
88
105
|
disabled: state.readOnly || state.disabled,
|
|
@@ -103,7 +120,7 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
103
120
|
else if (relativeDateState.parsedDate) {
|
|
104
121
|
setFocusedDate(relativeDateState.parsedDate);
|
|
105
122
|
}
|
|
106
|
-
|
|
123
|
+
focusInput();
|
|
107
124
|
},
|
|
108
125
|
},
|
|
109
126
|
calendarButtonProps: {
|
|
@@ -115,29 +132,20 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
115
132
|
'aria-expanded': isOpen,
|
|
116
133
|
},
|
|
117
134
|
view: 'flat-secondary',
|
|
118
|
-
onFocus: () => {
|
|
119
|
-
wasActiveBeforeClickRef.current = state.isActive;
|
|
120
|
-
},
|
|
121
135
|
onClick: () => {
|
|
122
136
|
state.setActive(true);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
setTimeout(() => {
|
|
127
|
-
var _a;
|
|
128
|
-
(_a = calendarRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
129
|
-
});
|
|
130
|
-
}
|
|
137
|
+
setOpen(!isOpen);
|
|
138
|
+
if (!isOpen) {
|
|
139
|
+
focusCalendar();
|
|
131
140
|
}
|
|
132
|
-
wasActiveBeforeClickRef.current = state.isActive;
|
|
133
141
|
},
|
|
134
142
|
},
|
|
135
143
|
popupProps: {
|
|
136
144
|
open: isOpen,
|
|
137
145
|
onEscapeKeyDown: () => {
|
|
138
146
|
setOpen(false);
|
|
147
|
+
focusInput();
|
|
139
148
|
},
|
|
140
|
-
restoreFocus: true,
|
|
141
149
|
},
|
|
142
150
|
calendarProps: {
|
|
143
151
|
ref: calendarRef,
|
|
@@ -148,7 +156,7 @@ export function useRelativeDatePickerProps(state, _a) {
|
|
|
148
156
|
datePickerState.setDateValue(v);
|
|
149
157
|
if (!state.datePickerState.hasTime) {
|
|
150
158
|
setOpen(false);
|
|
151
|
-
|
|
159
|
+
focusInput();
|
|
152
160
|
}
|
|
153
161
|
},
|
|
154
162
|
focusedValue: focusedDate,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
|
+
interface PlaceholderValueOptions {
|
|
3
|
+
placeholderValue?: DateTime;
|
|
4
|
+
timeZone?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function createPlaceholderValue({ placeholderValue, timeZone }: PlaceholderValueOptions): DateTime;
|
|
7
|
+
export declare function isInvalid(value: DateTime | null | undefined, minValue: DateTime | undefined, maxValue: DateTime | undefined): boolean;
|
|
8
|
+
export declare function mergeDateTime(date: DateTime, time: DateTime): DateTime;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { dateTime } from '@gravity-ui/date-utils';
|
|
2
|
+
export function createPlaceholderValue({ placeholderValue, timeZone }) {
|
|
3
|
+
return (placeholderValue !== null && placeholderValue !== void 0 ? placeholderValue : dateTime({ timeZone }).set('hour', 0).set('minute', 0).set('second', 0));
|
|
4
|
+
}
|
|
5
|
+
export function isInvalid(value, minValue, maxValue) {
|
|
6
|
+
if (!value) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (minValue && value.isBefore(minValue)) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
if (maxValue && maxValue.isBefore(value)) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
export function mergeDateTime(date, time) {
|
|
18
|
+
return date
|
|
19
|
+
.set('hours', time.hour())
|
|
20
|
+
.set('minutes', time.minute())
|
|
21
|
+
.set('seconds', time.second());
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/date-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -60,12 +60,13 @@
|
|
|
60
60
|
"@gravity-ui/stylelint-config": "^2.0.0",
|
|
61
61
|
"@gravity-ui/tsconfig": "^1.0.0",
|
|
62
62
|
"@gravity-ui/uikit": "^5.0.0",
|
|
63
|
-
"@storybook/addon-a11y": "^7.
|
|
64
|
-
"@storybook/addon-essentials": "^7.
|
|
65
|
-
"@storybook/
|
|
63
|
+
"@storybook/addon-a11y": "^7.5.3",
|
|
64
|
+
"@storybook/addon-essentials": "^7.5.3",
|
|
65
|
+
"@storybook/addons": "^7.5.3",
|
|
66
|
+
"@storybook/api": "^7.5.3",
|
|
66
67
|
"@storybook/preset-scss": "^1.0.3",
|
|
67
|
-
"@storybook/react": "^7.
|
|
68
|
-
"@storybook/react-webpack5": "^7.
|
|
68
|
+
"@storybook/react": "^7.5.3",
|
|
69
|
+
"@storybook/react-webpack5": "^7.5.3",
|
|
69
70
|
"@testing-library/jest-dom": "^5.17.0",
|
|
70
71
|
"@testing-library/react": "^14.0.0",
|
|
71
72
|
"@testing-library/user-event": "^14.4.3",
|
|
@@ -91,7 +92,7 @@
|
|
|
91
92
|
"react-dom": "^18.2.0",
|
|
92
93
|
"sass": "^1.64.1",
|
|
93
94
|
"sass-loader": "^13.3.2",
|
|
94
|
-
"storybook": "^7.
|
|
95
|
+
"storybook": "^7.5.3",
|
|
95
96
|
"style-loader": "^3.3.3",
|
|
96
97
|
"stylelint": "^15.10.2",
|
|
97
98
|
"ts-jest": "^29.1.1",
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { DatePickerProps } from './DatePicker';
|
|
3
|
-
import type { DatePickerState } from './hooks/useDatePickerState';
|
|
4
|
-
interface DesktopCalendarProps {
|
|
5
|
-
anchorRef: React.RefObject<HTMLElement>;
|
|
6
|
-
props: DatePickerProps;
|
|
7
|
-
state: DatePickerState;
|
|
8
|
-
}
|
|
9
|
-
export declare function DesktopCalendar({ anchorRef, props, state }: DesktopCalendarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
-
interface DesktopCalendarButtonProps {
|
|
11
|
-
props: DatePickerProps;
|
|
12
|
-
state: DatePickerState;
|
|
13
|
-
}
|
|
14
|
-
export declare function DesktopCalendarButton({ props, state }: DesktopCalendarButtonProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
|
-
export {};
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.DesktopCalendarButton = exports.DesktopCalendar = void 0;
|
|
7
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
-
const react_1 = __importDefault(require("react"));
|
|
9
|
-
const icons_1 = require("@gravity-ui/icons");
|
|
10
|
-
const uikit_1 = require("@gravity-ui/uikit");
|
|
11
|
-
const Calendar_1 = require("../Calendar");
|
|
12
|
-
const DateField_1 = require("../DateField");
|
|
13
|
-
const getButtonSizeForInput_1 = require("../utils/getButtonSizeForInput");
|
|
14
|
-
const i18n_1 = require("./i18n");
|
|
15
|
-
const utils_1 = require("./utils");
|
|
16
|
-
function DesktopCalendar({ anchorRef, props, state }) {
|
|
17
|
-
var _a;
|
|
18
|
-
const { focusWithinProps } = (0, uikit_1.useFocusWithin)({
|
|
19
|
-
isDisabled: !state.isOpen,
|
|
20
|
-
onBlurWithin: () => {
|
|
21
|
-
state.setOpen(false);
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
if (!state.hasDate) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
return ((0, jsx_runtime_1.jsx)(uikit_1.Popup, { open: state.isOpen, anchorRef: anchorRef, onClose: () => {
|
|
28
|
-
state.setOpen(false);
|
|
29
|
-
}, restoreFocus: true, children: (0, jsx_runtime_1.jsxs)("div", Object.assign({}, focusWithinProps, { className: (0, utils_1.b)('popup-content'), children: [(0, jsx_runtime_1.jsx)(Calendar_1.Calendar
|
|
30
|
-
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
31
|
-
, {
|
|
32
|
-
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
33
|
-
autoFocus: true, size: props.size === 's' ? 'm' : props.size, disabled: props.disabled, readOnly: props.readOnly, onUpdate: (d) => {
|
|
34
|
-
state.setDateValue(d);
|
|
35
|
-
}, defaultFocusedValue: (_a = state.dateValue) !== null && _a !== void 0 ? _a : undefined, value: state.dateValue, minValue: props.minValue, maxValue: props.maxValue, isDateUnavailable: props.isDateUnavailable, timeZone: props.timeZone }), state.hasTime && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.b)('time-field-wrapper'), children: (0, jsx_runtime_1.jsx)(DateField_1.DateField, { className: (0, utils_1.b)('time-field'), size: props.size, readOnly: props.readOnly, value: state.timeValue, onUpdate: state.setTimeValue, placeholderValue: props.placeholderValue, minValue: props.minValue, maxValue: props.maxValue, timeZone: props.timeZone, format: state.timeFormat }) }))] })) }));
|
|
36
|
-
}
|
|
37
|
-
exports.DesktopCalendar = DesktopCalendar;
|
|
38
|
-
function DesktopCalendarButton({ props, state }) {
|
|
39
|
-
const wasOpenBeforeClickRef = react_1.default.useRef(false);
|
|
40
|
-
if (!state.hasDate) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
return ((0, jsx_runtime_1.jsx)(uikit_1.Button, { view: "flat", size: (0, getButtonSizeForInput_1.getButtonSizeForInput)(props.size), disabled: props.disabled, extraProps: {
|
|
44
|
-
'aria-label': (0, i18n_1.i18n)('Calendar'),
|
|
45
|
-
'aria-haspopup': 'dialog',
|
|
46
|
-
'aria-expanded': state.isOpen,
|
|
47
|
-
}, onFocus: () => {
|
|
48
|
-
wasOpenBeforeClickRef.current = state.isOpen;
|
|
49
|
-
}, onClick: () => {
|
|
50
|
-
if (!wasOpenBeforeClickRef.current) {
|
|
51
|
-
state.setOpen(true);
|
|
52
|
-
}
|
|
53
|
-
wasOpenBeforeClickRef.current = false;
|
|
54
|
-
}, children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.Calendar }) }));
|
|
55
|
-
}
|
|
56
|
-
exports.DesktopCalendarButton = DesktopCalendarButton;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { DatePickerProps } from './DatePicker';
|
|
3
|
-
import type { DatePickerState } from './hooks/useDatePickerState';
|
|
4
|
-
interface DesktopCalendarProps {
|
|
5
|
-
anchorRef: React.RefObject<HTMLElement>;
|
|
6
|
-
props: DatePickerProps;
|
|
7
|
-
state: DatePickerState;
|
|
8
|
-
}
|
|
9
|
-
export declare function DesktopCalendar({ anchorRef, props, state }: DesktopCalendarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
-
interface DesktopCalendarButtonProps {
|
|
11
|
-
props: DatePickerProps;
|
|
12
|
-
state: DatePickerState;
|
|
13
|
-
}
|
|
14
|
-
export declare function DesktopCalendarButton({ props, state }: DesktopCalendarButtonProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
|
-
export {};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { Calendar as CalendarIcon } from '@gravity-ui/icons';
|
|
4
|
-
import { Button, Icon, Popup, useFocusWithin } from '@gravity-ui/uikit';
|
|
5
|
-
import { Calendar } from '../Calendar';
|
|
6
|
-
import { DateField } from '../DateField';
|
|
7
|
-
import { getButtonSizeForInput } from '../utils/getButtonSizeForInput';
|
|
8
|
-
import { i18n } from './i18n';
|
|
9
|
-
import { b } from './utils';
|
|
10
|
-
export function DesktopCalendar({ anchorRef, props, state }) {
|
|
11
|
-
var _a;
|
|
12
|
-
const { focusWithinProps } = useFocusWithin({
|
|
13
|
-
isDisabled: !state.isOpen,
|
|
14
|
-
onBlurWithin: () => {
|
|
15
|
-
state.setOpen(false);
|
|
16
|
-
},
|
|
17
|
-
});
|
|
18
|
-
if (!state.hasDate) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
return (_jsx(Popup, { open: state.isOpen, anchorRef: anchorRef, onClose: () => {
|
|
22
|
-
state.setOpen(false);
|
|
23
|
-
}, restoreFocus: true, children: _jsxs("div", Object.assign({}, focusWithinProps, { className: b('popup-content'), children: [_jsx(Calendar
|
|
24
|
-
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
25
|
-
, {
|
|
26
|
-
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
27
|
-
autoFocus: true, size: props.size === 's' ? 'm' : props.size, disabled: props.disabled, readOnly: props.readOnly, onUpdate: (d) => {
|
|
28
|
-
state.setDateValue(d);
|
|
29
|
-
}, defaultFocusedValue: (_a = state.dateValue) !== null && _a !== void 0 ? _a : undefined, value: state.dateValue, minValue: props.minValue, maxValue: props.maxValue, isDateUnavailable: props.isDateUnavailable, timeZone: props.timeZone }), state.hasTime && (_jsx("div", { className: b('time-field-wrapper'), children: _jsx(DateField, { className: b('time-field'), size: props.size, readOnly: props.readOnly, value: state.timeValue, onUpdate: state.setTimeValue, placeholderValue: props.placeholderValue, minValue: props.minValue, maxValue: props.maxValue, timeZone: props.timeZone, format: state.timeFormat }) }))] })) }));
|
|
30
|
-
}
|
|
31
|
-
export function DesktopCalendarButton({ props, state }) {
|
|
32
|
-
const wasOpenBeforeClickRef = React.useRef(false);
|
|
33
|
-
if (!state.hasDate) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
return (_jsx(Button, { view: "flat", size: getButtonSizeForInput(props.size), disabled: props.disabled, extraProps: {
|
|
37
|
-
'aria-label': i18n('Calendar'),
|
|
38
|
-
'aria-haspopup': 'dialog',
|
|
39
|
-
'aria-expanded': state.isOpen,
|
|
40
|
-
}, onFocus: () => {
|
|
41
|
-
wasOpenBeforeClickRef.current = state.isOpen;
|
|
42
|
-
}, onClick: () => {
|
|
43
|
-
if (!wasOpenBeforeClickRef.current) {
|
|
44
|
-
state.setOpen(true);
|
|
45
|
-
}
|
|
46
|
-
wasOpenBeforeClickRef.current = false;
|
|
47
|
-
}, children: _jsx(Icon, { data: CalendarIcon }) }));
|
|
48
|
-
}
|