@gravity-ui/date-components 1.0.0 → 1.1.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 +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 +6 -6
- 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 +2 -2
- package/dist/cjs/components/DateField/hooks/useDateFieldState.d.ts +2 -0
- package/dist/cjs/components/DateField/hooks/useDateFieldState.js +33 -6
- package/dist/cjs/components/DateField/types.d.ts +1 -1
- package/dist/cjs/components/DateField/utils.d.ts +0 -9
- package/dist/cjs/components/DateField/utils.js +1 -25
- package/dist/cjs/components/DatePicker/DatePicker.d.ts +4 -1
- package/dist/cjs/components/DatePicker/DatePicker.js +2 -2
- package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +3 -1
- package/dist/cjs/components/DatePicker/DesktopCalendar.js +17 -8
- package/dist/cjs/components/DatePicker/MobileCalendar.js +4 -4
- package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +3 -8
- 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 +7 -1
- 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 +6 -6
- 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 +2 -2
- package/dist/esm/components/DateField/hooks/useDateFieldState.d.ts +2 -0
- package/dist/esm/components/DateField/hooks/useDateFieldState.js +28 -1
- package/dist/esm/components/DateField/types.d.ts +1 -1
- package/dist/esm/components/DateField/utils.d.ts +0 -9
- package/dist/esm/components/DateField/utils.js +0 -21
- package/dist/esm/components/DatePicker/DatePicker.d.ts +4 -1
- package/dist/esm/components/DatePicker/DatePicker.js +2 -2
- package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +3 -1
- package/dist/esm/components/DatePicker/DesktopCalendar.js +17 -8
- package/dist/esm/components/DatePicker/MobileCalendar.js +1 -1
- package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +2 -7
- 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 +7 -1
- package/dist/esm/components/utils/dates.d.ts +9 -0
- package/dist/esm/components/utils/dates.js +22 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.splitFormatIntoSections = exports.expandFormat = exports.CtrlCmd = exports.isMac = void 0;
|
|
4
4
|
const date_utils_1 = require("@gravity-ui/date-utils");
|
|
5
5
|
const i18n_1 = require("./i18n");
|
|
6
6
|
exports.isMac = window.navigator.userAgent.indexOf('Macintosh') >= 0;
|
|
@@ -250,27 +250,3 @@ function getSectionOptions(section, token) {
|
|
|
250
250
|
}
|
|
251
251
|
return undefined;
|
|
252
252
|
}
|
|
253
|
-
function createPlaceholderValue({ placeholderValue, timeZone }) {
|
|
254
|
-
return (placeholderValue !== null && placeholderValue !== void 0 ? placeholderValue : (0, date_utils_1.dateTime)({ timeZone }).set('hour', 0).set('minute', 0).set('second', 0));
|
|
255
|
-
}
|
|
256
|
-
exports.createPlaceholderValue = createPlaceholderValue;
|
|
257
|
-
function isInvalid(value, minValue, maxValue) {
|
|
258
|
-
if (!value) {
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
if (minValue && value.isBefore(minValue)) {
|
|
262
|
-
return true;
|
|
263
|
-
}
|
|
264
|
-
if (maxValue && maxValue.isBefore(value)) {
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
267
|
-
return false;
|
|
268
|
-
}
|
|
269
|
-
exports.isInvalid = isInvalid;
|
|
270
|
-
function mergeDateTime(date, time) {
|
|
271
|
-
return date
|
|
272
|
-
.set('hours', time.hour())
|
|
273
|
-
.set('minutes', time.minute())
|
|
274
|
-
.set('seconds', time.second());
|
|
275
|
-
}
|
|
276
|
-
exports.mergeDateTime = mergeDateTime;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { CalendarProps } from '../Calendar';
|
|
1
3
|
import type { AccessibilityProps, DateFieldBase, DomProps, FocusableProps, KeyboardEvents, StyleProps, TextInputProps } from '../types';
|
|
2
4
|
import './DatePicker.css';
|
|
3
5
|
export interface DatePickerProps extends DateFieldBase, TextInputProps, FocusableProps, KeyboardEvents, DomProps, StyleProps, AccessibilityProps {
|
|
6
|
+
children?: (props: CalendarProps) => React.ReactNode;
|
|
4
7
|
}
|
|
5
|
-
export declare function DatePicker({ value, defaultValue, onUpdate, className, onFocus, onBlur, ...props }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function DatePicker({ value, defaultValue, onUpdate, className, onFocus, onBlur, children, ...props }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -25,7 +25,7 @@ const useDatePickerState_1 = require("./hooks/useDatePickerState");
|
|
|
25
25
|
const utils_1 = require("./utils");
|
|
26
26
|
require("./DatePicker.css");
|
|
27
27
|
function DatePicker(_a) {
|
|
28
|
-
var { value, defaultValue, onUpdate, className, onFocus, onBlur } = _a, props = __rest(_a, ["value", "defaultValue", "onUpdate", "className", "onFocus", "onBlur"]);
|
|
28
|
+
var { value, defaultValue, onUpdate, className, onFocus, onBlur, children } = _a, props = __rest(_a, ["value", "defaultValue", "onUpdate", "className", "onFocus", "onBlur", "children"]);
|
|
29
29
|
const anchorRef = react_1.default.useRef(null);
|
|
30
30
|
const state = (0, useDatePickerState_1.useDatePickerState)(Object.assign(Object.assign({}, props), { value,
|
|
31
31
|
defaultValue,
|
|
@@ -61,6 +61,6 @@ function DatePicker(_a) {
|
|
|
61
61
|
e.stopPropagation();
|
|
62
62
|
state.setOpen(true);
|
|
63
63
|
}
|
|
64
|
-
}, children: [isMobile ? ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendar, { props: props, state: state })) : ((0, jsx_runtime_1.jsx)(DesktopCalendar_1.DesktopCalendar, { anchorRef: anchorRef, props: props, state: state })), (0, jsx_runtime_1.jsx)(uikit_1.TextInput, Object.assign({}, inputProps, { value: fieldState.isEmpty && !isActive && props.placeholder ? '' : inputProps.value, className: (0, utils_1.b)('field', { mobile: isMobile }), hasClear: !isMobile && inputProps.hasClear, rightContent: isMobile ? ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendarIcon, { props: props, state: state })) : ((0, jsx_runtime_1.jsx)(DesktopCalendar_1.DesktopCalendarButton, { props: props, state: state })) }))] })));
|
|
64
|
+
}, children: [isMobile ? ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendar, { props: props, state: state })) : ((0, jsx_runtime_1.jsx)(DesktopCalendar_1.DesktopCalendar, { anchorRef: anchorRef, props: props, state: state, renderCalendar: children })), (0, jsx_runtime_1.jsx)(uikit_1.TextInput, Object.assign({}, inputProps, { value: fieldState.isEmpty && !isActive && props.placeholder ? '' : inputProps.value, className: (0, utils_1.b)('field', { mobile: isMobile }), hasClear: !isMobile && inputProps.hasClear, rightContent: isMobile ? ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendarIcon, { props: props, state: state })) : ((0, jsx_runtime_1.jsx)(DesktopCalendar_1.DesktopCalendarButton, { props: props, state: state })) }))] })));
|
|
65
65
|
}
|
|
66
66
|
exports.DatePicker = DatePicker;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { type CalendarProps } from '../Calendar';
|
|
2
3
|
import type { DatePickerProps } from './DatePicker';
|
|
3
4
|
import type { DatePickerState } from './hooks/useDatePickerState';
|
|
4
5
|
interface DesktopCalendarProps {
|
|
5
6
|
anchorRef: React.RefObject<HTMLElement>;
|
|
6
7
|
props: DatePickerProps;
|
|
7
8
|
state: DatePickerState;
|
|
9
|
+
renderCalendar?: (props: CalendarProps) => React.ReactNode;
|
|
8
10
|
}
|
|
9
|
-
export declare function DesktopCalendar({ anchorRef, props, state }: DesktopCalendarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
11
|
+
export declare function DesktopCalendar({ anchorRef, props, state, renderCalendar }: DesktopCalendarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
12
|
interface DesktopCalendarButtonProps {
|
|
11
13
|
props: DatePickerProps;
|
|
12
14
|
state: DatePickerState;
|
|
@@ -13,7 +13,7 @@ const DateField_1 = require("../DateField");
|
|
|
13
13
|
const getButtonSizeForInput_1 = require("../utils/getButtonSizeForInput");
|
|
14
14
|
const i18n_1 = require("./i18n");
|
|
15
15
|
const utils_1 = require("./utils");
|
|
16
|
-
function DesktopCalendar({ anchorRef, props, state }) {
|
|
16
|
+
function DesktopCalendar({ anchorRef, props, state, renderCalendar }) {
|
|
17
17
|
var _a;
|
|
18
18
|
const { focusWithinProps } = (0, uikit_1.useFocusWithin)({
|
|
19
19
|
isDisabled: !state.isOpen,
|
|
@@ -24,15 +24,24 @@ function DesktopCalendar({ anchorRef, props, state }) {
|
|
|
24
24
|
if (!state.hasDate) {
|
|
25
25
|
return null;
|
|
26
26
|
}
|
|
27
|
+
const calendarProps = {
|
|
28
|
+
autoFocus: true,
|
|
29
|
+
size: props.size === 's' ? 'm' : props.size,
|
|
30
|
+
disabled: props.disabled,
|
|
31
|
+
readOnly: props.readOnly,
|
|
32
|
+
onUpdate: (d) => {
|
|
33
|
+
state.setDateValue(d);
|
|
34
|
+
},
|
|
35
|
+
defaultFocusedValue: (_a = state.dateValue) !== null && _a !== void 0 ? _a : undefined,
|
|
36
|
+
value: state.dateValue,
|
|
37
|
+
minValue: props.minValue,
|
|
38
|
+
maxValue: props.maxValue,
|
|
39
|
+
isDateUnavailable: props.isDateUnavailable,
|
|
40
|
+
timeZone: props.timeZone,
|
|
41
|
+
};
|
|
27
42
|
return ((0, jsx_runtime_1.jsx)(uikit_1.Popup, { open: state.isOpen, anchorRef: anchorRef, onClose: () => {
|
|
28
43
|
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 }) }))] })) }));
|
|
44
|
+
}, restoreFocus: true, children: (0, jsx_runtime_1.jsxs)("div", Object.assign({}, focusWithinProps, { className: (0, utils_1.b)('popup-content'), tabIndex: -1, children: [typeof renderCalendar === 'function' ? (renderCalendar(calendarProps)) : ((0, jsx_runtime_1.jsx)(Calendar_1.Calendar, Object.assign({}, calendarProps))), state.hasTime && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.b)('time-field-wrapper'), children: (0, jsx_runtime_1.jsx)(DateField_1.DateField, { 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
45
|
}
|
|
37
46
|
exports.DesktopCalendar = DesktopCalendar;
|
|
38
47
|
function DesktopCalendarButton({ props, state }) {
|
|
@@ -6,7 +6,7 @@ const date_utils_1 = require("@gravity-ui/date-utils");
|
|
|
6
6
|
const icons_1 = require("@gravity-ui/icons");
|
|
7
7
|
const uikit_1 = require("@gravity-ui/uikit");
|
|
8
8
|
const cn_1 = require("../../utils/cn");
|
|
9
|
-
const
|
|
9
|
+
const dates_1 = require("../utils/dates");
|
|
10
10
|
const getButtonSizeForInput_1 = require("../utils/getButtonSizeForInput");
|
|
11
11
|
require("./MobileCalendar.css");
|
|
12
12
|
const b = (0, cn_1.block)('mobile-calendar');
|
|
@@ -31,15 +31,15 @@ function MobileCalendar({ props, state }) {
|
|
|
31
31
|
format: getDateFormat(type),
|
|
32
32
|
timeZone: props.timeZone,
|
|
33
33
|
})
|
|
34
|
-
: (0,
|
|
34
|
+
: (0, dates_1.createPlaceholderValue)({
|
|
35
35
|
placeholderValue: props.placeholderValue,
|
|
36
36
|
timeZone: props.timeZone,
|
|
37
37
|
});
|
|
38
38
|
if (state.hasTime) {
|
|
39
|
-
newDate = (0,
|
|
39
|
+
newDate = (0, dates_1.mergeDateTime)(newDate, localDate);
|
|
40
40
|
}
|
|
41
41
|
else if (state.dateValue) {
|
|
42
|
-
newDate = (0,
|
|
42
|
+
newDate = (0, dates_1.mergeDateTime)(newDate, state.dateValue);
|
|
43
43
|
}
|
|
44
44
|
else {
|
|
45
45
|
newDate = newDate.set('hours', 0).set('minutes', 0).set('seconds', 0);
|
|
@@ -7,6 +7,7 @@ exports.useDatePickerState = void 0;
|
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const utils_1 = require("../../DateField/utils");
|
|
9
9
|
const useControlledState_1 = require("../../hooks/useControlledState");
|
|
10
|
+
const dates_1 = require("../../utils/dates");
|
|
10
11
|
function useDatePickerState(props) {
|
|
11
12
|
const { disabled, readOnly } = props;
|
|
12
13
|
const [isOpen, setOpen] = react_1.default.useState(false);
|
|
@@ -44,7 +45,7 @@ function useDatePickerState(props) {
|
|
|
44
45
|
if (disabled || readOnly) {
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
|
-
setValue(mergeDateTime(date, time));
|
|
48
|
+
setValue((0, dates_1.mergeDateTime)(date, time));
|
|
48
49
|
setSelectedDate(null);
|
|
49
50
|
setSelectedTime(null);
|
|
50
51
|
};
|
|
@@ -103,12 +104,6 @@ function useDatePickerState(props) {
|
|
|
103
104
|
};
|
|
104
105
|
}
|
|
105
106
|
exports.useDatePickerState = useDatePickerState;
|
|
106
|
-
function mergeDateTime(date, time) {
|
|
107
|
-
return date
|
|
108
|
-
.set('hours', time.hour())
|
|
109
|
-
.set('minutes', time.minute())
|
|
110
|
-
.set('seconds', time.second());
|
|
111
|
-
}
|
|
112
107
|
function getPlaceholderTime(placeholderValue, timeZone) {
|
|
113
|
-
return (0,
|
|
108
|
+
return (0, dates_1.createPlaceholderValue)({ placeholderValue, timeZone });
|
|
114
109
|
}
|
|
@@ -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;
|
|
@@ -27,6 +27,6 @@ function RelativeDatePicker(props) {
|
|
|
27
27
|
readOnly: props.readOnly,
|
|
28
28
|
placeholderValue: props.placeholderValue,
|
|
29
29
|
timeZone: props.timeZone,
|
|
30
|
-
} })), (0, jsx_runtime_1.jsx)(uikit_1.TextInput, Object.assign({}, fieldProps, { leftContent: (0, jsx_runtime_1.jsx)(uikit_1.Button, Object.assign({}, modeSwitcherProps, { children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.Function }) })), rightContent: (0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [!isMobile && ((0, jsx_runtime_1.jsx)(uikit_1.Button, Object.assign({}, calendarButtonProps, { children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.Calendar }) }))), isMobile && state.mode === 'absolute' && ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendarIcon, { state: state.datePickerState, props: { size: props.size } }))] }) })), !isMobile && ((0, jsx_runtime_1.jsx)(uikit_1.Popup, Object.assign({}, popupProps, { anchorRef: anchorRef, children: (0, jsx_runtime_1.jsxs)("div", { className: b('popup-content'), children: [(0, jsx_runtime_1.jsx)(Calendar_1.Calendar, Object.assign({}, calendarProps)), state.datePickerState.hasTime && ((0, jsx_runtime_1.jsx)("div", { className: b('time-field-wrapper'), children: (0, jsx_runtime_1.jsx)(DateField_1.DateField, Object.assign({}, timeInputProps)) }))] }) })))] })));
|
|
30
|
+
} })), (0, jsx_runtime_1.jsx)(uikit_1.TextInput, Object.assign({}, fieldProps, { leftContent: (0, jsx_runtime_1.jsx)(uikit_1.Button, Object.assign({}, modeSwitcherProps, { children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.Function }) })), rightContent: (0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [!isMobile && ((0, jsx_runtime_1.jsx)(uikit_1.Button, Object.assign({}, calendarButtonProps, { children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.Calendar }) }))), isMobile && state.mode === 'absolute' && ((0, jsx_runtime_1.jsx)(MobileCalendar_1.MobileCalendarIcon, { state: state.datePickerState, props: { size: props.size } }))] }) })), !isMobile && ((0, jsx_runtime_1.jsx)(uikit_1.Popup, Object.assign({}, popupProps, { anchorRef: anchorRef, children: (0, jsx_runtime_1.jsxs)("div", { className: b('popup-content'), children: [typeof props.children === 'function' ? (props.children(calendarProps)) : ((0, jsx_runtime_1.jsx)(Calendar_1.Calendar, Object.assign({}, calendarProps))), state.datePickerState.hasTime && ((0, jsx_runtime_1.jsx)("div", { className: b('time-field-wrapper'), children: (0, jsx_runtime_1.jsx)(DateField_1.DateField, Object.assign({}, timeInputProps)) }))] }) })))] })));
|
|
31
31
|
}
|
|
32
32
|
exports.RelativeDatePicker = RelativeDatePicker;
|
|
@@ -87,7 +87,13 @@ function useRelativeDatePickerProps(state, _a) {
|
|
|
87
87
|
const handleRef = (0, uikit_1.useForkRef)(inputRef, mode === 'relative' ? relativeDateProps.controlRef : inputProps.controlRef);
|
|
88
88
|
const calendarRef = react_1.default.useRef(null);
|
|
89
89
|
return {
|
|
90
|
-
groupProps: Object.assign({ role: 'group' }, focusWithinProps),
|
|
90
|
+
groupProps: Object.assign(Object.assign({ role: 'group' }, focusWithinProps), { onKeyDown: (e) => {
|
|
91
|
+
if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
e.stopPropagation();
|
|
94
|
+
setOpen(true);
|
|
95
|
+
}
|
|
96
|
+
} }),
|
|
91
97
|
fieldProps: (0, mergeProps_1.mergeProps)(commonInputProps, mode === 'relative' ? relativeDateProps : inputProps, { controlRef: handleRef, error }),
|
|
92
98
|
modeSwitcherProps: {
|
|
93
99
|
size: (0, getButtonSizeForInput_1.getButtonSizeForInput)(props.size),
|
|
@@ -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,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeDateTime = exports.isInvalid = exports.createPlaceholderValue = void 0;
|
|
4
|
+
const date_utils_1 = require("@gravity-ui/date-utils");
|
|
5
|
+
function createPlaceholderValue({ placeholderValue, timeZone }) {
|
|
6
|
+
return (placeholderValue !== null && placeholderValue !== void 0 ? placeholderValue : (0, date_utils_1.dateTime)({ timeZone }).set('hour', 0).set('minute', 0).set('second', 0));
|
|
7
|
+
}
|
|
8
|
+
exports.createPlaceholderValue = createPlaceholderValue;
|
|
9
|
+
function isInvalid(value, minValue, maxValue) {
|
|
10
|
+
if (!value) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
if (minValue && value.isBefore(minValue)) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (maxValue && maxValue.isBefore(value)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
exports.isInvalid = isInvalid;
|
|
22
|
+
function mergeDateTime(date, time) {
|
|
23
|
+
return date
|
|
24
|
+
.set('hours', time.hour())
|
|
25
|
+
.set('minutes', time.minute())
|
|
26
|
+
.set('seconds', time.second());
|
|
27
|
+
}
|
|
28
|
+
exports.mergeDateTime = mergeDateTime;
|
|
@@ -82,6 +82,11 @@
|
|
|
82
82
|
.g-date-calendar__content_animation_zoom-out.g-date-calendar__previous-state {
|
|
83
83
|
animation: calendar-zoom-out-hiding 0.25s ease forwards;
|
|
84
84
|
}
|
|
85
|
+
@media screen and (prefers-reduced-motion: reduce), (update: slow) {
|
|
86
|
+
.g-date-calendar__content[class] {
|
|
87
|
+
animation-duration: 0.001ms;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
85
90
|
@keyframes calendar-forward {
|
|
86
91
|
from {
|
|
87
92
|
transform: translateX(0);
|
|
@@ -142,10 +147,13 @@
|
|
|
142
147
|
display: grid;
|
|
143
148
|
gap: var(--_--calendar-days-gap);
|
|
144
149
|
}
|
|
145
|
-
.g-date-calendar__grid-rowgroup_mode_months, .g-date-calendar__grid-rowgroup_mode_years {
|
|
150
|
+
.g-date-calendar__grid-rowgroup_mode_months, .g-date-calendar__grid-rowgroup_mode_quarters, .g-date-calendar__grid-rowgroup_mode_years {
|
|
146
151
|
grid-row: 1/-1;
|
|
147
152
|
padding: 12px 0 0;
|
|
148
153
|
}
|
|
154
|
+
.g-date-calendar__grid-rowgroup-header {
|
|
155
|
+
align-self: center;
|
|
156
|
+
}
|
|
149
157
|
.g-date-calendar__grid-row {
|
|
150
158
|
display: grid;
|
|
151
159
|
grid-auto-columns: 1fr;
|
|
@@ -5,7 +5,7 @@ import { block } from '../../utils/cn';
|
|
|
5
5
|
import { useCalendarCellProps } from './hooks/useCalendarCellProps';
|
|
6
6
|
import { useCalendarGridProps } from './hooks/useCalendarGridProps';
|
|
7
7
|
import { useCalendarProps } from './hooks/useCalendarProps';
|
|
8
|
-
import { getDaysInPeriod, getWeekDays } from './utils';
|
|
8
|
+
import { calendarLayouts, getDaysInPeriod, getWeekDays } from './utils';
|
|
9
9
|
import './Calendar.css';
|
|
10
10
|
const b = block('calendar');
|
|
11
11
|
export const CalendarBase = React.forwardRef(function Calendar(props, ref) {
|
|
@@ -16,7 +16,8 @@ export const CalendarBase = React.forwardRef(function Calendar(props, ref) {
|
|
|
16
16
|
state.setFocused(true);
|
|
17
17
|
},
|
|
18
18
|
}));
|
|
19
|
-
return (_jsxs("div", Object.assign({}, calendarProps, { className: b({ size: props.size }), children: [_jsxs("div", { className: b('header'), children: [_jsx(Button, Object.assign({}, modeButtonProps, { view: "flat", size: props.size, children: state.
|
|
19
|
+
return (_jsxs("div", Object.assign({}, calendarProps, { className: b({ size: props.size }), children: [_jsxs("div", { className: b('header'), children: [_jsx(Button, Object.assign({}, modeButtonProps, { view: "flat", size: props.size, children: state.availableModes.indexOf(state.mode) + 1 ===
|
|
20
|
+
state.availableModes.length ? (_jsx("span", { className: b('mode-label', b(`years-label`)), children: modeButtonProps.children }, "label")) : ([
|
|
20
21
|
_jsx("span", { className: b('mode-label'), children: modeButtonProps.children }, "label"),
|
|
21
22
|
_jsx(Button.Icon, { children: _jsx(ArrowToggle, { direction: "bottom" }) }, "icon"),
|
|
22
23
|
]) })), _jsxs("div", { className: b('controls'), children: [_jsx(Button, Object.assign({}, previousButtonProps, { view: "flat", size: props.size, children: _jsx(Button.Icon, { children: _jsx(ArrowToggle, { direction: "left" }) }) })), _jsx(Button, Object.assign({}, nextButtonProps, { view: "flat", size: props.size, children: _jsx(Button.Icon, { children: _jsx(ArrowToggle, { direction: "right" }) }) }))] })] }), _jsx(CalendarGrid, { state: state })] })));
|
|
@@ -27,8 +28,7 @@ function CalendarGrid({ state }) {
|
|
|
27
28
|
const startDateChanged = !state.startDate.isSame(prevState.startDate, 'days');
|
|
28
29
|
let animation;
|
|
29
30
|
if (modeChanged) {
|
|
30
|
-
if ((
|
|
31
|
-
(state.mode === 'months' && prevState.mode === 'years')) {
|
|
31
|
+
if (calendarLayouts.indexOf(prevState.mode) > calendarLayouts.indexOf(state.mode)) {
|
|
32
32
|
animation = 'zoom-out';
|
|
33
33
|
}
|
|
34
34
|
else {
|
|
@@ -59,13 +59,13 @@ function Weekdays({ state }) {
|
|
|
59
59
|
}
|
|
60
60
|
function CalendarGridCells({ state }) {
|
|
61
61
|
const rowsInPeriod = state.mode === 'days' ? 6 : 4;
|
|
62
|
-
const columnsInRow = state.mode === 'days' ? 7 : 3;
|
|
62
|
+
const columnsInRow = state.mode === 'days' ? 7 : 3 + (state.mode === 'quarters' ? 1 : 0);
|
|
63
63
|
const days = getDaysInPeriod(state.startDate, state.endDate, state.mode);
|
|
64
|
-
return (_jsx("div", { className: b('grid-rowgroup', { mode: state.mode }), role: "rowgroup", children: [...new Array(rowsInPeriod).keys()].map((rowIndex) => (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
return (_jsx("div", { className: b('grid-rowgroup', { mode: state.mode }), role: "rowgroup", children: [...new Array(rowsInPeriod).keys()].map((rowIndex) => (_jsxs("div", { className: b('grid-row'), role: "row", children: [state.mode === 'quarters' ? (_jsx("span", { role: "rowheader", className: b('grid-rowgroup-header'), children: days[rowIndex * columnsInRow].format('YYYY') })) : null, days
|
|
65
|
+
.slice(rowIndex * columnsInRow, (rowIndex + 1) * columnsInRow)
|
|
66
|
+
.map((date) => {
|
|
67
|
+
return _jsx(CalendarCell, { date: date, state: state }, date.unix());
|
|
68
|
+
})] }, rowIndex))) }));
|
|
69
69
|
}
|
|
70
70
|
function CalendarCell({ date, state }) {
|
|
71
71
|
const { cellProps, buttonProps, formattedDate, isDisabled, isSelected, isRangeSelection, isSelectionStart, isSelectionEnd, isOutsideCurrentRange, isUnavailable, isCurrent, isWeekend, } = useCalendarCellProps(date, state);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
2
|
import type { InputBase, RangeValue } from '../../types';
|
|
3
|
-
export type CalendarLayout = 'days' | 'months' | 'years';
|
|
3
|
+
export type CalendarLayout = 'days' | 'months' | 'quarters' | 'years';
|
|
4
4
|
export interface CalendarStateOptionsBase extends InputBase {
|
|
5
5
|
/** The minimum allowed date that a user may select. */
|
|
6
6
|
minValue?: DateTime;
|
|
@@ -27,6 +27,8 @@ export interface CalendarStateOptionsBase extends InputBase {
|
|
|
27
27
|
defaultMode?: CalendarLayout;
|
|
28
28
|
/** Handler that is called when the mode changes */
|
|
29
29
|
onUpdateMode?: (mode: CalendarLayout) => void;
|
|
30
|
+
/** Controls which modes to use */
|
|
31
|
+
modes?: Partial<Record<CalendarLayout, boolean>>;
|
|
30
32
|
}
|
|
31
33
|
interface CalendarStateBase {
|
|
32
34
|
/** Whether the calendar is disabled. */
|
|
@@ -45,7 +47,7 @@ interface CalendarStateBase {
|
|
|
45
47
|
/** Selects the currently focused date. */
|
|
46
48
|
selectFocusedDate(): void;
|
|
47
49
|
/** Selects the given date. */
|
|
48
|
-
selectDate(date: DateTime): void;
|
|
50
|
+
selectDate(date: DateTime, force?: boolean): void;
|
|
49
51
|
/** Moves focus to the next calendar date. */
|
|
50
52
|
focusNextCell(): void;
|
|
51
53
|
/** Moves focus to the previous calendar date. */
|
|
@@ -98,6 +100,7 @@ interface CalendarStateBase {
|
|
|
98
100
|
readonly mode: CalendarLayout;
|
|
99
101
|
/** Sets calendar layout */
|
|
100
102
|
setMode(mode: CalendarLayout): void;
|
|
103
|
+
readonly availableModes: CalendarLayout[];
|
|
101
104
|
readonly startDate: DateTime;
|
|
102
105
|
readonly endDate: DateTime;
|
|
103
106
|
}
|
|
@@ -21,16 +21,7 @@ export function useCalendarCellProps(date, state) {
|
|
|
21
21
|
const isSelectable = !isDisabled && !isUnavailable;
|
|
22
22
|
const isCurrent = dateTime().isSame(date, state.mode);
|
|
23
23
|
const isWeekend = state.isWeekend(date);
|
|
24
|
-
|
|
25
|
-
if (state.mode === 'days') {
|
|
26
|
-
label = `${date.format('dddd')}, ${date.format('LL')}`;
|
|
27
|
-
}
|
|
28
|
-
else if (state.mode === 'months') {
|
|
29
|
-
label = `${date.format('MMMM YYYY')}`;
|
|
30
|
-
}
|
|
31
|
-
else if (state.mode === 'years') {
|
|
32
|
-
label = `${date.format('YYYY')}`;
|
|
33
|
-
}
|
|
24
|
+
const label = getDateLabel(date, state.mode);
|
|
34
25
|
const cellProps = {
|
|
35
26
|
role: 'gridcell',
|
|
36
27
|
'aria-selected': isSelected ? 'true' : undefined,
|
|
@@ -45,12 +36,7 @@ export function useCalendarCellProps(date, state) {
|
|
|
45
36
|
onClick: isSelectable
|
|
46
37
|
? () => {
|
|
47
38
|
state.setFocusedDate(date);
|
|
48
|
-
|
|
49
|
-
state.selectDate(date);
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
state.zoomIn();
|
|
53
|
-
}
|
|
39
|
+
state.selectDate(date);
|
|
54
40
|
}
|
|
55
41
|
: undefined,
|
|
56
42
|
onPointerEnter() {
|
|
@@ -71,6 +57,9 @@ export function useCalendarCellProps(date, state) {
|
|
|
71
57
|
if (state.mode === 'months') {
|
|
72
58
|
formattedDate = date.format('MMM');
|
|
73
59
|
}
|
|
60
|
+
else if (state.mode === 'quarters') {
|
|
61
|
+
formattedDate = date.format('[Q]Q');
|
|
62
|
+
}
|
|
74
63
|
else if (state.mode === 'years') {
|
|
75
64
|
formattedDate = date.format('YYYY');
|
|
76
65
|
}
|
|
@@ -89,3 +78,19 @@ export function useCalendarCellProps(date, state) {
|
|
|
89
78
|
isWeekend,
|
|
90
79
|
};
|
|
91
80
|
}
|
|
81
|
+
function getDateLabel(date, mode) {
|
|
82
|
+
let label = '';
|
|
83
|
+
if (mode === 'days') {
|
|
84
|
+
label = `${date.format('dddd')}, ${date.format('LL')}`;
|
|
85
|
+
}
|
|
86
|
+
else if (mode === 'months') {
|
|
87
|
+
label = `${date.format('MMMM YYYY')}`;
|
|
88
|
+
}
|
|
89
|
+
else if (mode === 'quarters') {
|
|
90
|
+
label = `${date.format('[Q]Q YYYY')}`;
|
|
91
|
+
}
|
|
92
|
+
else if (mode === 'years') {
|
|
93
|
+
label = `${date.format('YYYY')}`;
|
|
94
|
+
}
|
|
95
|
+
return label;
|
|
96
|
+
}
|
|
@@ -6,7 +6,7 @@ export function useCalendarGridProps(state) {
|
|
|
6
6
|
state.setFocused(isFocused);
|
|
7
7
|
},
|
|
8
8
|
});
|
|
9
|
-
const gridProps = Object.assign(Object.assign({ role: 'grid', 'aria-label': state.mode === 'years'
|
|
9
|
+
const gridProps = Object.assign(Object.assign({ role: 'grid', 'aria-label': state.mode === 'years' || state.mode === 'quarters'
|
|
10
10
|
? `${state.startDate.year()} — ${state.endDate.year()}`
|
|
11
11
|
: state.focusedDate.format(state.mode === 'days' ? 'MMMM YYYY' : 'YYYY'), 'aria-disabled': state.disabled ? 'true' : undefined, 'aria-readonly': state.readOnly ? 'true' : undefined }, focusWithinProps), { onKeyDown: (e) => {
|
|
12
12
|
if (e.key === 'ArrowRight') {
|
|
@@ -40,12 +40,7 @@ export function useCalendarGridProps(state) {
|
|
|
40
40
|
state.zoomIn();
|
|
41
41
|
}
|
|
42
42
|
else if (e.key === 'Enter' || e.key === ' ') {
|
|
43
|
-
|
|
44
|
-
state.selectFocusedDate();
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
state.setMode(state.mode === 'months' ? 'days' : 'months');
|
|
48
|
-
}
|
|
43
|
+
state.selectDate(state.focusedDate);
|
|
49
44
|
}
|
|
50
45
|
} });
|
|
51
46
|
return {
|
|
@@ -4,7 +4,7 @@ import { i18n } from '../i18n';
|
|
|
4
4
|
const buttonDisabledClassName = 'yc-button_disabled g-button_disabled';
|
|
5
5
|
// eslint-disable-next-line complexity
|
|
6
6
|
export function useCalendarProps(props, state) {
|
|
7
|
-
const title = state.mode === 'years'
|
|
7
|
+
const title = state.mode === 'years' || state.mode === 'quarters'
|
|
8
8
|
? `${state.startDate.year()} — ${state.endDate.year()}`
|
|
9
9
|
: state.focusedDate.format(state.mode === 'days' ? 'MMMM YYYY' : 'YYYY');
|
|
10
10
|
const { focusWithinProps } = useFocusWithin({
|
|
@@ -12,7 +12,10 @@ export function useCalendarProps(props, state) {
|
|
|
12
12
|
onBlurWithin: props.onBlur,
|
|
13
13
|
});
|
|
14
14
|
const calendarProps = Object.assign({ role: 'group', id: props.id, 'aria-label': [props['aria-label'], title].filter(Boolean).join(', '), 'aria-labelledby': props['aria-labelledby'] || undefined, 'aria-describedby': props['aria-describedby'] || undefined, 'aria-details': props['aria-details'] || undefined, 'aria-disabled': state.disabled || undefined }, focusWithinProps);
|
|
15
|
-
const
|
|
15
|
+
const modeIndex = state.availableModes.indexOf(state.mode);
|
|
16
|
+
const isModeLast = modeIndex + 1 === state.availableModes.length;
|
|
17
|
+
const isNextModeLast = modeIndex + 2 === state.availableModes.length;
|
|
18
|
+
const modeDisabled = state.disabled || isModeLast;
|
|
16
19
|
const modeButtonProps = {
|
|
17
20
|
disabled: state.disabled,
|
|
18
21
|
// FIXME: do not use button class name
|
|
@@ -21,7 +24,7 @@ export function useCalendarProps(props, state) {
|
|
|
21
24
|
? undefined
|
|
22
25
|
: () => {
|
|
23
26
|
state.zoomOut();
|
|
24
|
-
if (
|
|
27
|
+
if (isNextModeLast) {
|
|
25
28
|
state.setFocused(true);
|
|
26
29
|
}
|
|
27
30
|
},
|