@gravity-ui/date-components 2.2.1 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (17) hide show
  1. package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldState.js +3 -0
  2. package/dist/cjs/components/RelativeRangeDatePicker/RelativeRangeDatePicker.d.ts +5 -2
  3. package/dist/cjs/components/RelativeRangeDatePicker/RelativeRangeDatePicker.js +18 -7
  4. package/dist/cjs/components/RelativeRangeDatePicker/components/PickerDialog/PickerDialog.js +2 -2
  5. package/dist/cjs/components/RelativeRangeDatePicker/components/Presets/Presets.d.ts +3 -1
  6. package/dist/cjs/components/RelativeRangeDatePicker/components/Presets/Presets.js +2 -2
  7. package/dist/cjs/components/RelativeRangeDatePicker/components/Presets/PresetsDoc.d.ts +3 -1
  8. package/dist/cjs/components/RelativeRangeDatePicker/components/Presets/PresetsDoc.js +12 -9
  9. package/dist/esm/components/RelativeDateField/hooks/useRelativeDateFieldState.js +6 -1
  10. package/dist/esm/components/RelativeRangeDatePicker/RelativeRangeDatePicker.d.ts +5 -2
  11. package/dist/esm/components/RelativeRangeDatePicker/RelativeRangeDatePicker.js +18 -7
  12. package/dist/esm/components/RelativeRangeDatePicker/components/PickerDialog/PickerDialog.js +2 -2
  13. package/dist/esm/components/RelativeRangeDatePicker/components/Presets/Presets.d.ts +3 -1
  14. package/dist/esm/components/RelativeRangeDatePicker/components/Presets/Presets.js +2 -2
  15. package/dist/esm/components/RelativeRangeDatePicker/components/Presets/PresetsDoc.d.ts +3 -1
  16. package/dist/esm/components/RelativeRangeDatePicker/components/Presets/PresetsDoc.js +12 -9
  17. package/package.json +31 -33
@@ -61,5 +61,8 @@ function useRelativeDateFieldState(props) {
61
61
  }
62
62
  exports.useRelativeDateFieldState = useRelativeDateFieldState;
63
63
  function isLikeRelativeDate(text) {
64
+ if (typeof date_utils_1.isLikeRelative === 'function') {
65
+ return (0, date_utils_1.isLikeRelative)(text);
66
+ }
64
67
  return /^now/i.test(text);
65
68
  }
@@ -1,10 +1,11 @@
1
1
  import type { DateTime } from '@gravity-ui/date-utils';
2
2
  import type { Value } from '../RelativeDatePicker';
3
- import type { DomProps, InputBase, RangeValue, StyleProps, TextInputProps, Validation } from '../types';
3
+ import type { DomProps, FocusableProps, InputBase, RangeValue, StyleProps, TextInputProps, Validation } from '../types';
4
+ import type { Preset } from './components/Presets/defaultPresets';
4
5
  import type { PresetTab } from './components/Presets/utils';
5
6
  import type { RelativeRangeDatePickerStateOptions } from './hooks/useRelativeRangeDatePickerState';
6
7
  import './RelativeRangeDatePicker.css';
7
- export interface RelativeRangeDatePickerProps extends RelativeRangeDatePickerStateOptions, DomProps, InputBase, TextInputProps, Validation, StyleProps {
8
+ export interface RelativeRangeDatePickerProps extends RelativeRangeDatePickerStateOptions, DomProps, InputBase, TextInputProps, Validation, FocusableProps, StyleProps {
8
9
  /** Format of the date when rendered in the input. [Available formats](https://day.js.org/docs/en/display/format) */
9
10
  format?: string;
10
11
  /** A placeholder date that controls the default values of each segment when the user first interacts with them. Defaults to today's date at midnight. */
@@ -17,6 +18,8 @@ export interface RelativeRangeDatePickerProps extends RelativeRangeDatePickerSta
17
18
  withPresets?: boolean;
18
19
  /** Custom preset tabs */
19
20
  presetTabs?: PresetTab[];
21
+ /** Custom docs for presets, if empty array docs will be hidden */
22
+ docs?: Preset[];
20
23
  /** Show selected relative values as absolute dates */
21
24
  alwaysShowAsAbsolute?: boolean;
22
25
  /** */
@@ -16,7 +16,7 @@ const utils_1 = require("./utils");
16
16
  require("./RelativeRangeDatePicker.css");
17
17
  const b = (0, cn_1.block)('relative-range-date-picker');
18
18
  function RelativeRangeDatePicker(props) {
19
- var _a, _b;
19
+ var _a;
20
20
  const state = (0, useRelativeRangeDatePickerState_1.useRelativeRangeDatePickerState)(props);
21
21
  const isMobile = (0, uikit_1.useMobile)();
22
22
  const anchorRef = react_1.default.useRef(null);
@@ -24,15 +24,26 @@ function RelativeRangeDatePicker(props) {
24
24
  const [isActive, setIsActive] = react_1.default.useState(false);
25
25
  const [open, setOpen] = react_1.default.useState(false);
26
26
  const { focusWithinProps } = (0, uikit_1.useFocusWithin)({
27
- isDisabled: props.disabled || isMobile,
28
- onFocusWithinChange: (isFocusedWithin) => {
29
- if (!isFocusedWithin) {
27
+ isDisabled: props.disabled,
28
+ onFocusWithin: (e) => {
29
+ var _a;
30
+ if (!isActive) {
31
+ (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
32
+ }
33
+ },
34
+ onBlurWithin: (e) => {
35
+ var _a;
36
+ // when the popup is open and an user clicks outside, focus will be returned to the input
37
+ const seemsIsClickOutsideInEmptySpace = open &&
38
+ (document.activeElement === null || document.activeElement === document.body);
39
+ if (!seemsIsClickOutsideInEmptySpace) {
30
40
  setIsActive(false);
41
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
31
42
  }
32
43
  },
33
44
  });
34
45
  const { alwaysShowAsAbsolute, presetTabs, getRangeTitle } = props;
35
- const format = (_a = props.format) !== null && _a !== void 0 ? _a : 'L';
46
+ const format = props.format || 'L';
36
47
  const text = react_1.default.useMemo(() => typeof getRangeTitle === 'function'
37
48
  ? getRangeTitle(state.value, state.timeZone)
38
49
  : (0, utils_1.getDefaultTitle)({
@@ -43,8 +54,8 @@ function RelativeRangeDatePicker(props) {
43
54
  presets: presetTabs === null || presetTabs === void 0 ? void 0 : presetTabs.flatMap(({ presets }) => presets),
44
55
  }), [alwaysShowAsAbsolute, format, getRangeTitle, presetTabs, state.timeZone, state.value]);
45
56
  const validationState = props.validationState || (state.isInvalid ? 'invalid' : undefined);
46
- const errorMessage = (_b = props.errorMessage) !== null && _b !== void 0 ? _b : state.errors.join('\n');
47
- 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.Popover, { className: b('value-label'), tooltipContentClassName: b('value-label-tooltip'), disabled: isMobile || open || !state.value, delayOpening: 500, placement: ['right', 'right-start', 'right-end', 'auto'], hasArrow: false, content: (0, jsx_runtime_1.jsx)(ValueLabel, { value: state.value, format: format, timeZone: state.timeZone }), children: (0, jsx_runtime_1.jsx)(uikit_1.TextInput, { controlRef: inputRef, value: text, placeholder: props.placeholder, onUpdate: (v) => {
57
+ 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.Popover, { className: b('value-label'), tooltipContentClassName: b('value-label-tooltip'), disabled: isMobile || open || !state.value, delayOpening: 500, placement: ['right', 'right-start', 'right-end', 'auto'], hasArrow: false, content: (0, jsx_runtime_1.jsx)(ValueLabel, { value: state.value, format: format, timeZone: state.timeZone }), children: (0, jsx_runtime_1.jsx)(uikit_1.TextInput, { autoFocus: props.autoFocus, controlRef: inputRef, value: text, placeholder: props.placeholder, onUpdate: (v) => {
48
59
  if (!props.readOnly && !v) {
49
60
  state.setValue(null, 'default');
50
61
  }
@@ -16,7 +16,7 @@ function PickerDialog({ props, state, open, onClose, isMobile, anchorRef, classN
16
16
  if (isMobile) {
17
17
  return ((0, jsx_runtime_1.jsx)(uikit_1.Sheet, { visible: open, onClose: onClose, contentClassName: b('content', { mobile: true, size: 'xl' }, className), children: (0, jsx_runtime_1.jsx)(DialogContent, Object.assign({}, props, { size: "xl", state: state, onApply: onClose })) }));
18
18
  }
19
- return ((0, jsx_runtime_1.jsx)(uikit_1.Popup, { open: open, onClose: onClose, role: "dialog", anchorRef: anchorRef, contentClassName: b('content', { size: props.size }, className), focusTrap: true, restoreFocus: true, children: (0, jsx_runtime_1.jsx)(DialogContent, Object.assign({}, props, { state: state, onApply: onClose })) }));
19
+ return ((0, jsx_runtime_1.jsx)(uikit_1.Popup, { open: open, onClose: onClose, role: "dialog", anchorRef: anchorRef, contentClassName: b('content', { size: props.size }, className), autoFocus: true, focusTrap: true, restoreFocus: true, children: (0, jsx_runtime_1.jsx)(DialogContent, Object.assign({}, props, { state: state, onApply: onClose })) }));
20
20
  }
21
21
  exports.PickerDialog = PickerDialog;
22
22
  function DialogContent(props) {
@@ -39,5 +39,5 @@ function DialogContent(props) {
39
39
  props.onApply();
40
40
  }, 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) => {
41
41
  state.setRange({ type: 'relative', value: start }, { type: 'relative', value: end });
42
- }, minValue: props.minValue })) : 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] }));
42
+ }, minValue: props.minValue, docs: props.docs })) : 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] }));
43
43
  }
@@ -1,4 +1,5 @@
1
1
  import type { DateTime } from '@gravity-ui/date-utils';
2
+ import type { Preset } from './defaultPresets';
2
3
  import type { PresetTab } from './utils';
3
4
  import './Presets.css';
4
5
  export interface PresetProps {
@@ -8,8 +9,9 @@ export interface PresetProps {
8
9
  minValue?: DateTime;
9
10
  size?: 's' | 'm' | 'l' | 'xl';
10
11
  presetTabs?: PresetTab[];
12
+ docs?: Preset[];
11
13
  }
12
- export declare function Presets({ className, size, minValue, withTime, onChoosePreset, presetTabs, }: PresetProps): import("react/jsx-runtime").JSX.Element | null;
14
+ export declare function Presets({ className, size, minValue, withTime, onChoosePreset, presetTabs, docs, }: PresetProps): import("react/jsx-runtime").JSX.Element | null;
13
15
  export declare const SIZE_TO_ITEM_HEIGHT: {
14
16
  s: number;
15
17
  m: number;
@@ -10,7 +10,7 @@ const PresetsDoc_1 = require("./PresetsDoc");
10
10
  const utils_1 = require("./utils");
11
11
  require("./Presets.css");
12
12
  const b = (0, cn_1.block)('relative-range-date-picker-presets');
13
- function Presets({ className, size = 'm', minValue, withTime, onChoosePreset, presetTabs, }) {
13
+ function Presets({ className, size = 'm', minValue, withTime, onChoosePreset, presetTabs, docs, }) {
14
14
  var _a, _b;
15
15
  const tabs = react_1.default.useMemo(() => {
16
16
  return (0, utils_1.filterPresetTabs)(presetTabs !== null && presetTabs !== void 0 ? presetTabs : (0, utils_1.getDefaultPresetTabs)({ withTime }), { minValue });
@@ -26,7 +26,7 @@ function Presets({ className, size = 'm', minValue, withTime, onChoosePreset, pr
26
26
  if (activeTab.id !== activeTabId) {
27
27
  setActiveTab(activeTab.id);
28
28
  }
29
- return ((0, jsx_runtime_1.jsxs)("div", { className: b({ size }, className), children: [(0, jsx_runtime_1.jsxs)("div", { className: b('tabs'), children: [(0, jsx_runtime_1.jsx)(uikit_1.Tabs, { activeTab: activeTabId, onSelectTab: setActiveTab, items: tabs, size: size === 's' ? 'm' : size }), (0, jsx_runtime_1.jsx)(PresetsDoc_1.PresetsDoc, { className: b('doc'), size: size })] }), (0, jsx_runtime_1.jsx)("div", { className: b('content'), children: (0, jsx_runtime_1.jsx)(PresetsList, { presets: activeTab.presets, onChoosePreset: onChoosePreset, size: size }) })] }));
29
+ return ((0, jsx_runtime_1.jsxs)("div", { className: b({ size }, className), children: [(0, jsx_runtime_1.jsxs)("div", { className: b('tabs'), children: [(0, jsx_runtime_1.jsx)(uikit_1.Tabs, { activeTab: activeTabId, onSelectTab: setActiveTab, items: tabs, size: size === 's' ? 'm' : size }), (0, jsx_runtime_1.jsx)(PresetsDoc_1.PresetsDoc, { className: b('doc'), size: size, docs: docs })] }), (0, jsx_runtime_1.jsx)("div", { className: b('content'), children: (0, jsx_runtime_1.jsx)(PresetsList, { presets: activeTab.presets, onChoosePreset: onChoosePreset, size: size }) })] }));
30
30
  }
31
31
  exports.Presets = Presets;
32
32
  exports.SIZE_TO_ITEM_HEIGHT = {
@@ -1,7 +1,9 @@
1
+ import type { Preset } from './defaultPresets';
1
2
  import './PresetsDoc.css';
2
3
  interface PresetsDocProps {
3
4
  className?: string;
4
5
  size?: 's' | 'm' | 'l' | 'xl';
6
+ docs?: Preset[];
5
7
  }
6
- export declare function PresetsDoc({ className, size }: PresetsDocProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function PresetsDoc({ className, size, docs }: PresetsDocProps): import("react/jsx-runtime").JSX.Element | null;
7
9
  export {};
@@ -68,23 +68,26 @@ const data = [
68
68
  to: 'now - 1M/M',
69
69
  },
70
70
  ];
71
- function PresetsExamples({ size }) {
72
- return (0, jsx_runtime_1.jsx)(uikit_1.Table, { columns: columns, data: data, className: b('table', { size }) });
71
+ function PresetsExamples({ size, docs }) {
72
+ return (0, jsx_runtime_1.jsx)(uikit_1.Table, { columns: columns, data: docs, className: b('table', { size }) });
73
73
  }
74
- function DesktopDoc({ className, size }) {
75
- return ((0, jsx_runtime_1.jsx)(uikit_1.Popover, { className: b(null, className), tooltipContentClassName: b('content'), hasArrow: false, content: (0, jsx_runtime_1.jsx)(PresetsExamples, { size: size }), children: (0, jsx_runtime_1.jsx)(uikit_1.Button, { className: b('button'), view: "flat-secondary", size: (0, getButtonSizeForInput_1.getButtonSizeForInput)(size), children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.CircleQuestion }) }) }));
74
+ function DesktopDoc({ className, size, docs }) {
75
+ return ((0, jsx_runtime_1.jsx)(uikit_1.Popover, { className: b(null, className), tooltipContentClassName: b('content'), hasArrow: false, content: (0, jsx_runtime_1.jsx)(PresetsExamples, { size: size, docs: docs }), children: (0, jsx_runtime_1.jsx)(uikit_1.Button, { className: b('button'), view: "flat-secondary", size: (0, getButtonSizeForInput_1.getButtonSizeForInput)(size), children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.CircleQuestion }) }) }));
76
76
  }
77
- function MobileDoc({ className, size }) {
77
+ function MobileDoc({ className, size, docs }) {
78
78
  const [open, setOpen] = react_1.default.useState(false);
79
79
  return ((0, jsx_runtime_1.jsxs)("div", { className: b(null, className), children: [(0, jsx_runtime_1.jsx)(uikit_1.Button, { className: b('button'), view: "flat-secondary", size: "l", onClick: () => {
80
80
  setOpen(true);
81
- }, children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.CircleQuestion }) }), (0, jsx_runtime_1.jsx)(uikit_1.Sheet, { visible: open, onClose: () => setOpen(false), children: (0, jsx_runtime_1.jsx)(PresetsExamples, { size: size }) })] }));
81
+ }, children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.CircleQuestion }) }), (0, jsx_runtime_1.jsx)(uikit_1.Sheet, { visible: open, onClose: () => setOpen(false), children: (0, jsx_runtime_1.jsx)(PresetsExamples, { size: size, docs: docs }) })] }));
82
82
  }
83
- function PresetsDoc({ className, size }) {
83
+ function PresetsDoc({ className, size, docs = data }) {
84
84
  const isMobile = (0, uikit_1.useMobile)();
85
+ if (!Array.isArray(docs) || docs.length === 0) {
86
+ return null;
87
+ }
85
88
  if (isMobile) {
86
- return (0, jsx_runtime_1.jsx)(MobileDoc, { className: className, size: size });
89
+ return (0, jsx_runtime_1.jsx)(MobileDoc, { className: className, size: size, docs: docs });
87
90
  }
88
- return (0, jsx_runtime_1.jsx)(DesktopDoc, { className: className, size: size });
91
+ return (0, jsx_runtime_1.jsx)(DesktopDoc, { className: className, size: size, docs: docs });
89
92
  }
90
93
  exports.PresetsDoc = PresetsDoc;
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
- import { dateTimeParse, isValid } from '@gravity-ui/date-utils';
2
+ import { dateTimeParse,
3
+ // @ts-expect-error added in new version of date-utils
4
+ isLikeRelative, isValid, } from '@gravity-ui/date-utils';
3
5
  import { useControlledState } from '@gravity-ui/uikit';
4
6
  export function useRelativeDateFieldState(props) {
5
7
  var _a;
@@ -56,5 +58,8 @@ export function useRelativeDateFieldState(props) {
56
58
  };
57
59
  }
58
60
  function isLikeRelativeDate(text) {
61
+ if (typeof isLikeRelative === 'function') {
62
+ return isLikeRelative(text);
63
+ }
59
64
  return /^now/i.test(text);
60
65
  }
@@ -1,10 +1,11 @@
1
1
  import type { DateTime } from '@gravity-ui/date-utils';
2
2
  import type { Value } from '../RelativeDatePicker';
3
- import type { DomProps, InputBase, RangeValue, StyleProps, TextInputProps, Validation } from '../types';
3
+ import type { DomProps, FocusableProps, InputBase, RangeValue, StyleProps, TextInputProps, Validation } from '../types';
4
+ import type { Preset } from './components/Presets/defaultPresets';
4
5
  import type { PresetTab } from './components/Presets/utils';
5
6
  import type { RelativeRangeDatePickerStateOptions } from './hooks/useRelativeRangeDatePickerState';
6
7
  import './RelativeRangeDatePicker.css';
7
- export interface RelativeRangeDatePickerProps extends RelativeRangeDatePickerStateOptions, DomProps, InputBase, TextInputProps, Validation, StyleProps {
8
+ export interface RelativeRangeDatePickerProps extends RelativeRangeDatePickerStateOptions, DomProps, InputBase, TextInputProps, Validation, FocusableProps, StyleProps {
8
9
  /** Format of the date when rendered in the input. [Available formats](https://day.js.org/docs/en/display/format) */
9
10
  format?: string;
10
11
  /** A placeholder date that controls the default values of each segment when the user first interacts with them. Defaults to today's date at midnight. */
@@ -17,6 +18,8 @@ export interface RelativeRangeDatePickerProps extends RelativeRangeDatePickerSta
17
18
  withPresets?: boolean;
18
19
  /** Custom preset tabs */
19
20
  presetTabs?: PresetTab[];
21
+ /** Custom docs for presets, if empty array docs will be hidden */
22
+ docs?: Preset[];
20
23
  /** Show selected relative values as absolute dates */
21
24
  alwaysShowAsAbsolute?: boolean;
22
25
  /** */
@@ -12,7 +12,7 @@ import { getDefaultTitle } from './utils';
12
12
  import './RelativeRangeDatePicker.css';
13
13
  const b = block('relative-range-date-picker');
14
14
  export function RelativeRangeDatePicker(props) {
15
- var _a, _b;
15
+ var _a;
16
16
  const state = useRelativeRangeDatePickerState(props);
17
17
  const isMobile = useMobile();
18
18
  const anchorRef = React.useRef(null);
@@ -20,15 +20,26 @@ export function RelativeRangeDatePicker(props) {
20
20
  const [isActive, setIsActive] = React.useState(false);
21
21
  const [open, setOpen] = React.useState(false);
22
22
  const { focusWithinProps } = useFocusWithin({
23
- isDisabled: props.disabled || isMobile,
24
- onFocusWithinChange: (isFocusedWithin) => {
25
- if (!isFocusedWithin) {
23
+ isDisabled: props.disabled,
24
+ onFocusWithin: (e) => {
25
+ var _a;
26
+ if (!isActive) {
27
+ (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
28
+ }
29
+ },
30
+ onBlurWithin: (e) => {
31
+ var _a;
32
+ // when the popup is open and an user clicks outside, focus will be returned to the input
33
+ const seemsIsClickOutsideInEmptySpace = open &&
34
+ (document.activeElement === null || document.activeElement === document.body);
35
+ if (!seemsIsClickOutsideInEmptySpace) {
26
36
  setIsActive(false);
37
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
27
38
  }
28
39
  },
29
40
  });
30
41
  const { alwaysShowAsAbsolute, presetTabs, getRangeTitle } = props;
31
- const format = (_a = props.format) !== null && _a !== void 0 ? _a : 'L';
42
+ const format = props.format || 'L';
32
43
  const text = React.useMemo(() => typeof getRangeTitle === 'function'
33
44
  ? getRangeTitle(state.value, state.timeZone)
34
45
  : getDefaultTitle({
@@ -39,8 +50,8 @@ export function RelativeRangeDatePicker(props) {
39
50
  presets: presetTabs === null || presetTabs === void 0 ? void 0 : presetTabs.flatMap(({ presets }) => presets),
40
51
  }), [alwaysShowAsAbsolute, format, getRangeTitle, presetTabs, state.timeZone, state.value]);
41
52
  const validationState = props.validationState || (state.isInvalid ? 'invalid' : undefined);
42
- const errorMessage = (_b = props.errorMessage) !== null && _b !== void 0 ? _b : state.errors.join('\n');
43
- return (_jsxs("div", Object.assign({ ref: anchorRef }, focusWithinProps, { className: b(null, props.className), style: props.style, children: [_jsx(Popover, { className: b('value-label'), tooltipContentClassName: b('value-label-tooltip'), disabled: isMobile || open || !state.value, delayOpening: 500, placement: ['right', 'right-start', 'right-end', 'auto'], hasArrow: false, content: _jsx(ValueLabel, { value: state.value, format: format, timeZone: state.timeZone }), children: _jsx(TextInput, { controlRef: inputRef, value: text, placeholder: props.placeholder, onUpdate: (v) => {
53
+ 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(Popover, { className: b('value-label'), tooltipContentClassName: b('value-label-tooltip'), disabled: isMobile || open || !state.value, delayOpening: 500, placement: ['right', 'right-start', 'right-end', 'auto'], hasArrow: false, content: _jsx(ValueLabel, { value: state.value, format: format, timeZone: state.timeZone }), children: _jsx(TextInput, { autoFocus: props.autoFocus, controlRef: inputRef, value: text, placeholder: props.placeholder, onUpdate: (v) => {
44
55
  if (!props.readOnly && !v) {
45
56
  state.setValue(null, 'default');
46
57
  }
@@ -13,7 +13,7 @@ export function PickerDialog({ props, state, open, onClose, isMobile, anchorRef,
13
13
  if (isMobile) {
14
14
  return (_jsx(Sheet, { visible: open, onClose: onClose, contentClassName: b('content', { mobile: true, size: 'xl' }, className), children: _jsx(DialogContent, Object.assign({}, props, { size: "xl", state: state, onApply: onClose })) }));
15
15
  }
16
- return (_jsx(Popup, { open: open, onClose: onClose, role: "dialog", anchorRef: anchorRef, contentClassName: b('content', { size: props.size }, className), focusTrap: true, restoreFocus: true, children: _jsx(DialogContent, Object.assign({}, props, { state: state, onApply: onClose })) }));
16
+ return (_jsx(Popup, { open: open, onClose: onClose, role: "dialog", anchorRef: anchorRef, contentClassName: b('content', { size: props.size }, className), autoFocus: true, focusTrap: true, restoreFocus: true, children: _jsx(DialogContent, Object.assign({}, props, { state: state, onApply: onClose })) }));
17
17
  }
18
18
  function DialogContent(props) {
19
19
  var _a, _b, _c, _d, _e, _f, _g;
@@ -35,5 +35,5 @@ function DialogContent(props) {
35
35
  props.onApply();
36
36
  }, className: b('apply'), width: "max", children: i18n('Apply') })) : null, props.withPresets && !props.readOnly ? (_jsx(Presets, { size: props.size, presetTabs: props.presetTabs, onChoosePreset: (start, end) => {
37
37
  state.setRange({ type: 'relative', value: start }, { type: 'relative', value: end });
38
- }, minValue: props.minValue })) : null, props.withZonesList ? (_jsx("div", { className: b('zone'), children: _jsx(Zones, { value: state.timeZone, onUpdate: state.setTimeZone, disabled: props.readOnly, size: props.size }) })) : null] }));
38
+ }, minValue: props.minValue, docs: props.docs })) : null, props.withZonesList ? (_jsx("div", { className: b('zone'), children: _jsx(Zones, { value: state.timeZone, onUpdate: state.setTimeZone, disabled: props.readOnly, size: props.size }) })) : null] }));
39
39
  }
@@ -1,4 +1,5 @@
1
1
  import type { DateTime } from '@gravity-ui/date-utils';
2
+ import type { Preset } from './defaultPresets';
2
3
  import type { PresetTab } from './utils';
3
4
  import './Presets.css';
4
5
  export interface PresetProps {
@@ -8,8 +9,9 @@ export interface PresetProps {
8
9
  minValue?: DateTime;
9
10
  size?: 's' | 'm' | 'l' | 'xl';
10
11
  presetTabs?: PresetTab[];
12
+ docs?: Preset[];
11
13
  }
12
- export declare function Presets({ className, size, minValue, withTime, onChoosePreset, presetTabs, }: PresetProps): import("react/jsx-runtime").JSX.Element | null;
14
+ export declare function Presets({ className, size, minValue, withTime, onChoosePreset, presetTabs, docs, }: PresetProps): import("react/jsx-runtime").JSX.Element | null;
13
15
  export declare const SIZE_TO_ITEM_HEIGHT: {
14
16
  s: number;
15
17
  m: number;
@@ -6,7 +6,7 @@ import { PresetsDoc } from './PresetsDoc';
6
6
  import { filterPresetTabs, getDefaultPresetTabs } from './utils';
7
7
  import './Presets.css';
8
8
  const b = block('relative-range-date-picker-presets');
9
- export function Presets({ className, size = 'm', minValue, withTime, onChoosePreset, presetTabs, }) {
9
+ export function Presets({ className, size = 'm', minValue, withTime, onChoosePreset, presetTabs, docs, }) {
10
10
  var _a, _b;
11
11
  const tabs = React.useMemo(() => {
12
12
  return filterPresetTabs(presetTabs !== null && presetTabs !== void 0 ? presetTabs : getDefaultPresetTabs({ withTime }), { minValue });
@@ -22,7 +22,7 @@ export function Presets({ className, size = 'm', minValue, withTime, onChoosePre
22
22
  if (activeTab.id !== activeTabId) {
23
23
  setActiveTab(activeTab.id);
24
24
  }
25
- return (_jsxs("div", { className: b({ size }, className), children: [_jsxs("div", { className: b('tabs'), children: [_jsx(Tabs, { activeTab: activeTabId, onSelectTab: setActiveTab, items: tabs, size: size === 's' ? 'm' : size }), _jsx(PresetsDoc, { className: b('doc'), size: size })] }), _jsx("div", { className: b('content'), children: _jsx(PresetsList, { presets: activeTab.presets, onChoosePreset: onChoosePreset, size: size }) })] }));
25
+ return (_jsxs("div", { className: b({ size }, className), children: [_jsxs("div", { className: b('tabs'), children: [_jsx(Tabs, { activeTab: activeTabId, onSelectTab: setActiveTab, items: tabs, size: size === 's' ? 'm' : size }), _jsx(PresetsDoc, { className: b('doc'), size: size, docs: docs })] }), _jsx("div", { className: b('content'), children: _jsx(PresetsList, { presets: activeTab.presets, onChoosePreset: onChoosePreset, size: size }) })] }));
26
26
  }
27
27
  export const SIZE_TO_ITEM_HEIGHT = {
28
28
  s: 28,
@@ -1,7 +1,9 @@
1
+ import type { Preset } from './defaultPresets';
1
2
  import './PresetsDoc.css';
2
3
  interface PresetsDocProps {
3
4
  className?: string;
4
5
  size?: 's' | 'm' | 'l' | 'xl';
6
+ docs?: Preset[];
5
7
  }
6
- export declare function PresetsDoc({ className, size }: PresetsDocProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function PresetsDoc({ className, size, docs }: PresetsDocProps): import("react/jsx-runtime").JSX.Element | null;
7
9
  export {};
@@ -64,22 +64,25 @@ const data = [
64
64
  to: 'now - 1M/M',
65
65
  },
66
66
  ];
67
- function PresetsExamples({ size }) {
68
- return _jsx(Table, { columns: columns, data: data, className: b('table', { size }) });
67
+ function PresetsExamples({ size, docs }) {
68
+ return _jsx(Table, { columns: columns, data: docs, className: b('table', { size }) });
69
69
  }
70
- function DesktopDoc({ className, size }) {
71
- return (_jsx(Popover, { className: b(null, className), tooltipContentClassName: b('content'), hasArrow: false, content: _jsx(PresetsExamples, { size: size }), children: _jsx(Button, { className: b('button'), view: "flat-secondary", size: getButtonSizeForInput(size), children: _jsx(Icon, { data: CircleQuestion }) }) }));
70
+ function DesktopDoc({ className, size, docs }) {
71
+ return (_jsx(Popover, { className: b(null, className), tooltipContentClassName: b('content'), hasArrow: false, content: _jsx(PresetsExamples, { size: size, docs: docs }), children: _jsx(Button, { className: b('button'), view: "flat-secondary", size: getButtonSizeForInput(size), children: _jsx(Icon, { data: CircleQuestion }) }) }));
72
72
  }
73
- function MobileDoc({ className, size }) {
73
+ function MobileDoc({ className, size, docs }) {
74
74
  const [open, setOpen] = React.useState(false);
75
75
  return (_jsxs("div", { className: b(null, className), children: [_jsx(Button, { className: b('button'), view: "flat-secondary", size: "l", onClick: () => {
76
76
  setOpen(true);
77
- }, children: _jsx(Icon, { data: CircleQuestion }) }), _jsx(Sheet, { visible: open, onClose: () => setOpen(false), children: _jsx(PresetsExamples, { size: size }) })] }));
77
+ }, children: _jsx(Icon, { data: CircleQuestion }) }), _jsx(Sheet, { visible: open, onClose: () => setOpen(false), children: _jsx(PresetsExamples, { size: size, docs: docs }) })] }));
78
78
  }
79
- export function PresetsDoc({ className, size }) {
79
+ export function PresetsDoc({ className, size, docs = data }) {
80
80
  const isMobile = useMobile();
81
+ if (!Array.isArray(docs) || docs.length === 0) {
82
+ return null;
83
+ }
81
84
  if (isMobile) {
82
- return _jsx(MobileDoc, { className: className, size: size });
85
+ return _jsx(MobileDoc, { className: className, size: size, docs: docs });
83
86
  }
84
- return _jsx(DesktopDoc, { className: className, size: size });
87
+ return _jsx(DesktopDoc, { className: className, size: size, docs: docs });
85
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/date-components",
3
- "version": "2.2.1",
3
+ "version": "2.3.1",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",
@@ -51,36 +51,36 @@
51
51
  "tslib": "^2.6.2"
52
52
  },
53
53
  "devDependencies": {
54
- "@babel/preset-env": "^7.22.9",
55
- "@babel/preset-react": "^7.22.5",
56
- "@babel/preset-typescript": "^7.22.5",
57
- "@commitlint/cli": "^18.4.3",
58
- "@commitlint/config-conventional": "^18.4.3",
59
- "@gravity-ui/eslint-config": "^3.1.1",
54
+ "@babel/preset-env": "^7.24.5",
55
+ "@babel/preset-react": "^7.24.1",
56
+ "@babel/preset-typescript": "^7.24.1",
57
+ "@commitlint/cli": "^19.3.0",
58
+ "@commitlint/config-conventional": "^19.2.2",
59
+ "@gravity-ui/eslint-config": "^3.2.0",
60
60
  "@gravity-ui/prettier-config": "^1.1.0",
61
61
  "@gravity-ui/stylelint-config": "^4.0.1",
62
62
  "@gravity-ui/tsconfig": "^1.0.0",
63
63
  "@gravity-ui/uikit": "^6.1.1",
64
- "@storybook/addon-a11y": "^7.6.15",
65
- "@storybook/addon-essentials": "^7.6.15",
66
- "@storybook/addon-viewport": "^7.6.15",
67
- "@storybook/addons": "^7.6.15",
68
- "@storybook/api": "^7.6.15",
69
- "@storybook/blocks": "^7.6.15",
64
+ "@storybook/addon-a11y": "^8.0.10",
65
+ "@storybook/addon-essentials": "^8.0.10",
66
+ "@storybook/addon-viewport": "^8.0.10",
67
+ "@storybook/addon-webpack5-compiler-babel": "^3.0.3",
68
+ "@storybook/blocks": "^8.0.10",
69
+ "@storybook/manager-api": "^8.0.10",
70
70
  "@storybook/preset-scss": "^1.0.3",
71
- "@storybook/react": "^7.6.15",
72
- "@storybook/react-webpack5": "^7.6.15",
73
- "@storybook/theming": "^7.6.15",
74
- "@testing-library/jest-dom": "^6.4.2",
75
- "@testing-library/react": "^14.2.1",
71
+ "@storybook/react": "^8.0.10",
72
+ "@storybook/react-webpack5": "^8.0.10",
73
+ "@storybook/theming": "^8.0.10",
74
+ "@testing-library/jest-dom": "^6.4.5",
75
+ "@testing-library/react": "^15.0.7",
76
76
  "@testing-library/user-event": "^14.5.2",
77
77
  "@types/jest": "^29.5.12",
78
- "@types/react": "^18.2.55",
79
- "@types/react-dom": "^18.2.19",
80
- "eslint": "^8.56.0",
81
- "eslint-plugin-testing-library": "^6.2.0",
82
- "gulp": "^4.0.2",
83
- "gulp-cli": "^2.3.0",
78
+ "@types/react": "^18.3.2",
79
+ "@types/react-dom": "^18.3.0",
80
+ "eslint": "^8.57.0",
81
+ "eslint-plugin-testing-library": "^6.2.2",
82
+ "gulp": "^5.0.0",
83
+ "gulp-cli": "^3.0.0",
84
84
  "gulp-dart-sass": "^1.1.0",
85
85
  "gulp-replace": "^1.1.4",
86
86
  "gulp-typescript": "^5.0.1",
@@ -91,18 +91,16 @@
91
91
  "nano-staged": "^0.8.0",
92
92
  "npm-run-all": "^4.1.5",
93
93
  "prettier": "^3.2.5",
94
- "react": "^18.2.0",
95
- "react-dom": "^18.2.0",
96
- "rimraf": "5.0.5",
97
- "sass": "^1.70.0",
98
- "sass-loader": "^13.3.3",
99
- "storybook": "^7.6.15",
100
- "style-loader": "^3.3.4",
94
+ "react": "^18.3.1",
95
+ "react-dom": "^18.3.1",
96
+ "rimraf": "^5.0.7",
97
+ "sass": "^1.77.1",
98
+ "storybook": "^8.0.10",
101
99
  "stylelint": "^15.11.0",
102
- "stylelint-use-logical": "^2.1.0",
100
+ "stylelint-use-logical": "^2.1.2",
103
101
  "ts-jest": "^29.1.2",
104
102
  "ts-node": "^10.9.2",
105
- "typescript": "^5.3.3"
103
+ "typescript": "^5.4.5"
106
104
  },
107
105
  "peerDependencies": {
108
106
  "@gravity-ui/uikit": "^6.0.0",