@astral/ui 1.47.0 → 1.47.2

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.
@@ -1,4 +1,4 @@
1
- import { FocusEvent, SyntheticEvent } from 'react';
1
+ import { SyntheticEvent } from 'react';
2
2
  import { TextFieldProps } from '../TextField';
3
3
  import { DateMask } from '../utils/date';
4
4
  import { Reason } from '../types';
@@ -14,7 +14,7 @@ export type DatePickerProps = MondayFirst & Partial<MinMaxDate> & {
14
14
  * @description Обработчик изменения состояния. Передает только Date object, если дата невалидна, то будет Invalid date
15
15
  * */
16
16
  onChange?: (date?: Date) => void;
17
- onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
17
+ onBlur?: () => void;
18
18
  onOpen?: () => void;
19
19
  onClose?: (event?: SyntheticEvent<Element, Event> | Event, reason?: Reason) => void;
20
20
  inputProps?: Omit<TextFieldProps, 'ref' | 'value' | 'onChange'>;
@@ -34,7 +34,7 @@ export declare const DatePicker: import("react").ForwardRefExoticComponent<Monda
34
34
  * @description Обработчик изменения состояния. Передает только Date object, если дата невалидна, то будет Invalid date
35
35
  * */
36
36
  onChange?: ((date?: Date) => void) | undefined;
37
- onBlur?: ((e: FocusEvent<HTMLInputElement>) => void) | undefined;
37
+ onBlur?: (() => void) | undefined;
38
38
  onOpen?: (() => void) | undefined;
39
39
  onClose?: ((event?: SyntheticEvent<Element, Event> | Event, reason?: Reason) => void) | undefined;
40
40
  inputProps?: Omit<TextFieldProps, "ref" | "value" | "onChange"> | undefined;
@@ -24,10 +24,15 @@ const hooks_2 = require("./hooks");
24
24
  const DatePickerInner = (0, react_1.forwardRef)(({ onChange, onOpen, onBlur, onClose, mask = 'DD.MM.YYYY', isMondayFirst, inputProps, disabled, value, }, forwardedRef) => {
25
25
  const { maxDate, minDate } = (0, react_1.useContext)(MinMaxDateContext_1.MinMaxDateContext);
26
26
  const ref = (0, hooks_1.useForwardedRef)(forwardedRef);
27
- const [isActive, openPopper, closePopper] = (0, hooks_1.useToggle)({
27
+ const [isOpenPopper, openPopper, closePopper] = (0, hooks_1.useToggle)({
28
28
  onActive: onOpen,
29
29
  onInactive: onClose,
30
30
  });
31
+ const handleClosePopper = () => {
32
+ // для данного компонента onBlur должен срабатывать после закрытия popover, а не во время выбора даты
33
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur();
34
+ closePopper(undefined, 'selectOption');
35
+ };
31
36
  const { maskedValue, onChangeMaskedValue, onChangeMaskedDate } = (0, hooks_2.useMaskedValue)({
32
37
  currentValue: value,
33
38
  mask,
@@ -37,16 +42,12 @@ const DatePickerInner = (0, react_1.forwardRef)(({ onChange, onOpen, onBlur, onC
37
42
  const selectedBaseDate = (0, hooks_2.useSelectedBaseDate)(value);
38
43
  const handleDayPick = (date) => {
39
44
  onChangeMaskedDate(date);
40
- closePopper(undefined, 'selectOption');
41
- };
42
- const handleBlurMaskInput = (e) => {
43
- onChangeMaskedValue(e.target.value);
44
- onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
45
+ handleClosePopper();
45
46
  };
46
47
  const handleChangeMaskInput = (e) => {
47
48
  onChangeMaskedValue(e.target.value);
48
49
  };
49
- return ((0, jsx_runtime_1.jsxs)(DatePickerClickAwayListener_1.DatePickerClickAwayListener, Object.assign({ onClickAway: closePopper }, { children: [(0, jsx_runtime_1.jsx)(DatePickerInput_1.DatePickerInput, Object.assign({}, inputProps, { mask: mask, onNativeChange: handleChangeMaskInput, onBlur: handleBlurMaskInput, disabled: disabled, value: maskedValue, ref: ref, onFocus: openPopper })), (0, jsx_runtime_1.jsx)(DatePickerPopper_1.DatePickerPopper, Object.assign({ open: isActive, onClose: closePopper, anchorEl: ref === null || ref === void 0 ? void 0 : ref.current }, { children: (0, jsx_runtime_1.jsx)(YearMonthDayPicker_1.YearMonthDayPicker, { isMondayFirst: isMondayFirst, selectedDate: selectedBaseDate, onChange: handleDayPick, date: selectedBaseDate || baseDate }) }))] })));
50
+ return ((0, jsx_runtime_1.jsxs)(DatePickerClickAwayListener_1.DatePickerClickAwayListener, Object.assign({ onClickAway: handleClosePopper }, { children: [(0, jsx_runtime_1.jsx)(DatePickerInput_1.DatePickerInput, Object.assign({}, inputProps, { mask: mask, onNativeChange: handleChangeMaskInput, disabled: disabled, value: maskedValue, ref: ref, onFocus: openPopper })), (0, jsx_runtime_1.jsx)(DatePickerPopper_1.DatePickerPopper, Object.assign({ open: isOpenPopper, onClose: handleClosePopper, anchorEl: ref === null || ref === void 0 ? void 0 : ref.current }, { children: (0, jsx_runtime_1.jsx)(YearMonthDayPicker_1.YearMonthDayPicker, { isMondayFirst: isMondayFirst, selectedDate: selectedBaseDate, onChange: handleDayPick, date: selectedBaseDate || baseDate }) }))] })));
50
51
  });
51
52
  exports.DatePicker = (0, react_1.forwardRef)((_a, forwardedRef) => {
52
53
  var { minDate, maxDate } = _a, props = __rest(_a, ["minDate", "maxDate"]);
@@ -74,4 +74,19 @@ describe('DatePicker', () => {
74
74
  const selected = tests_1.screen.getAllByText('9')[0].getAttribute('aria-selected');
75
75
  expect(selected).toBeTruthy();
76
76
  }));
77
+ it('Props:onBlur: вызывается при закрытии popover', () => __awaiter(void 0, void 0, void 0, function* () {
78
+ const onBlur = vitest_1.vi.fn();
79
+ (0, tests_1.renderWithTheme)((0, jsx_runtime_1.jsx)(DatePicker_1.DatePicker, { onBlur: onBlur }));
80
+ tests_1.fireEvent.focus(tests_1.screen.getByRole('textbox'));
81
+ // клик вне инпута с поповером
82
+ yield tests_1.userEvents.click(document.body);
83
+ expect(onBlur).toBeCalled();
84
+ }));
85
+ it('Props:onBlur: не вызывается при потере фокуса на инпуте', () => __awaiter(void 0, void 0, void 0, function* () {
86
+ const onBlur = vitest_1.vi.fn();
87
+ (0, tests_1.renderWithTheme)((0, jsx_runtime_1.jsx)(DatePicker_1.DatePicker, { onBlur: onBlur }));
88
+ tests_1.fireEvent.focus(tests_1.screen.getByRole('textbox'));
89
+ yield tests_1.userEvents.tab();
90
+ expect(onBlur).not.toBeCalled();
91
+ }));
77
92
  });
@@ -10,7 +10,13 @@ const useMaskedValue = ({ currentValue, mask, onChangeValue, }) => {
10
10
  const [maskedValue, setMaskedValue] = (0, react_1.useState)(() => currentValue ? (0, date_1.formatDate)(currentValue, mask) : '');
11
11
  const handleChangeMaskedValue = (value) => {
12
12
  setMaskedValue(value);
13
- onChangeValue === null || onChangeValue === void 0 ? void 0 : onChangeValue((0, date_1.parseDate)(value, mask));
13
+ // parseDate вернет Invalid Date при undefined. А нам надо undefined
14
+ if (!value) {
15
+ onChangeValue === null || onChangeValue === void 0 ? void 0 : onChangeValue(undefined);
16
+ }
17
+ else {
18
+ onChangeValue === null || onChangeValue === void 0 ? void 0 : onChangeValue((0, date_1.parseDate)(value, mask));
19
+ }
14
20
  };
15
21
  const handleChangeMaskedDate = (date) => {
16
22
  setMaskedValue((0, date_1.formatDate)(date, mask));
@@ -1,4 +1,4 @@
1
- import { FocusEvent, SyntheticEvent } from 'react';
1
+ import { SyntheticEvent } from 'react';
2
2
  import { TextFieldProps } from '../TextField';
3
3
  import { DateMask } from '../utils/date';
4
4
  import { Reason } from '../types';
@@ -14,7 +14,7 @@ export type DatePickerProps = MondayFirst & Partial<MinMaxDate> & {
14
14
  * @description Обработчик изменения состояния. Передает только Date object, если дата невалидна, то будет Invalid date
15
15
  * */
16
16
  onChange?: (date?: Date) => void;
17
- onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
17
+ onBlur?: () => void;
18
18
  onOpen?: () => void;
19
19
  onClose?: (event?: SyntheticEvent<Element, Event> | Event, reason?: Reason) => void;
20
20
  inputProps?: Omit<TextFieldProps, 'ref' | 'value' | 'onChange'>;
@@ -34,7 +34,7 @@ export declare const DatePicker: import("react").ForwardRefExoticComponent<Monda
34
34
  * @description Обработчик изменения состояния. Передает только Date object, если дата невалидна, то будет Invalid date
35
35
  * */
36
36
  onChange?: ((date?: Date) => void) | undefined;
37
- onBlur?: ((e: FocusEvent<HTMLInputElement>) => void) | undefined;
37
+ onBlur?: (() => void) | undefined;
38
38
  onOpen?: (() => void) | undefined;
39
39
  onClose?: ((event?: SyntheticEvent<Element, Event> | Event, reason?: Reason) => void) | undefined;
40
40
  inputProps?: Omit<TextFieldProps, "ref" | "value" | "onChange"> | undefined;
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
- import { forwardRef, useContext, } from 'react';
13
+ import { forwardRef, useContext } from 'react';
14
14
  import { useForwardedRef, useToggle } from '../hooks';
15
15
  import { DatePickerClickAwayListener } from './DatePickerClickAwayListener';
16
16
  import { DatePickerInput } from './DatePickerInput';
@@ -21,10 +21,15 @@ import { useBaseDateInRange, useMaskedValue, useSelectedBaseDate, } from './hook
21
21
  const DatePickerInner = forwardRef(({ onChange, onOpen, onBlur, onClose, mask = 'DD.MM.YYYY', isMondayFirst, inputProps, disabled, value, }, forwardedRef) => {
22
22
  const { maxDate, minDate } = useContext(MinMaxDateContext);
23
23
  const ref = useForwardedRef(forwardedRef);
24
- const [isActive, openPopper, closePopper] = useToggle({
24
+ const [isOpenPopper, openPopper, closePopper] = useToggle({
25
25
  onActive: onOpen,
26
26
  onInactive: onClose,
27
27
  });
28
+ const handleClosePopper = () => {
29
+ // для данного компонента onBlur должен срабатывать после закрытия popover, а не во время выбора даты
30
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur();
31
+ closePopper(undefined, 'selectOption');
32
+ };
28
33
  const { maskedValue, onChangeMaskedValue, onChangeMaskedDate } = useMaskedValue({
29
34
  currentValue: value,
30
35
  mask,
@@ -34,16 +39,12 @@ const DatePickerInner = forwardRef(({ onChange, onOpen, onBlur, onClose, mask =
34
39
  const selectedBaseDate = useSelectedBaseDate(value);
35
40
  const handleDayPick = (date) => {
36
41
  onChangeMaskedDate(date);
37
- closePopper(undefined, 'selectOption');
38
- };
39
- const handleBlurMaskInput = (e) => {
40
- onChangeMaskedValue(e.target.value);
41
- onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
42
+ handleClosePopper();
42
43
  };
43
44
  const handleChangeMaskInput = (e) => {
44
45
  onChangeMaskedValue(e.target.value);
45
46
  };
46
- return (_jsxs(DatePickerClickAwayListener, Object.assign({ onClickAway: closePopper }, { children: [_jsx(DatePickerInput, Object.assign({}, inputProps, { mask: mask, onNativeChange: handleChangeMaskInput, onBlur: handleBlurMaskInput, disabled: disabled, value: maskedValue, ref: ref, onFocus: openPopper })), _jsx(DatePickerPopper, Object.assign({ open: isActive, onClose: closePopper, anchorEl: ref === null || ref === void 0 ? void 0 : ref.current }, { children: _jsx(YearMonthDayPicker, { isMondayFirst: isMondayFirst, selectedDate: selectedBaseDate, onChange: handleDayPick, date: selectedBaseDate || baseDate }) }))] })));
47
+ return (_jsxs(DatePickerClickAwayListener, Object.assign({ onClickAway: handleClosePopper }, { children: [_jsx(DatePickerInput, Object.assign({}, inputProps, { mask: mask, onNativeChange: handleChangeMaskInput, disabled: disabled, value: maskedValue, ref: ref, onFocus: openPopper })), _jsx(DatePickerPopper, Object.assign({ open: isOpenPopper, onClose: handleClosePopper, anchorEl: ref === null || ref === void 0 ? void 0 : ref.current }, { children: _jsx(YearMonthDayPicker, { isMondayFirst: isMondayFirst, selectedDate: selectedBaseDate, onChange: handleDayPick, date: selectedBaseDate || baseDate }) }))] })));
47
48
  });
48
49
  export const DatePicker = forwardRef((_a, forwardedRef) => {
49
50
  var { minDate, maxDate } = _a, props = __rest(_a, ["minDate", "maxDate"]);
@@ -72,4 +72,19 @@ describe('DatePicker', () => {
72
72
  const selected = screen.getAllByText('9')[0].getAttribute('aria-selected');
73
73
  expect(selected).toBeTruthy();
74
74
  }));
75
+ it('Props:onBlur: вызывается при закрытии popover', () => __awaiter(void 0, void 0, void 0, function* () {
76
+ const onBlur = vi.fn();
77
+ renderWithTheme(_jsx(DatePicker, { onBlur: onBlur }));
78
+ fireEvent.focus(screen.getByRole('textbox'));
79
+ // клик вне инпута с поповером
80
+ yield userEvents.click(document.body);
81
+ expect(onBlur).toBeCalled();
82
+ }));
83
+ it('Props:onBlur: не вызывается при потере фокуса на инпуте', () => __awaiter(void 0, void 0, void 0, function* () {
84
+ const onBlur = vi.fn();
85
+ renderWithTheme(_jsx(DatePicker, { onBlur: onBlur }));
86
+ fireEvent.focus(screen.getByRole('textbox'));
87
+ yield userEvents.tab();
88
+ expect(onBlur).not.toBeCalled();
89
+ }));
75
90
  });
@@ -7,7 +7,13 @@ export const useMaskedValue = ({ currentValue, mask, onChangeValue, }) => {
7
7
  const [maskedValue, setMaskedValue] = useState(() => currentValue ? formatDate(currentValue, mask) : '');
8
8
  const handleChangeMaskedValue = (value) => {
9
9
  setMaskedValue(value);
10
- onChangeValue === null || onChangeValue === void 0 ? void 0 : onChangeValue(parseDate(value, mask));
10
+ // parseDate вернет Invalid Date при undefined. А нам надо undefined
11
+ if (!value) {
12
+ onChangeValue === null || onChangeValue === void 0 ? void 0 : onChangeValue(undefined);
13
+ }
14
+ else {
15
+ onChangeValue === null || onChangeValue === void 0 ? void 0 : onChangeValue(parseDate(value, mask));
16
+ }
11
17
  };
12
18
  const handleChangeMaskedDate = (date) => {
13
19
  setMaskedValue(formatDate(date, mask));
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@astral/ui",
3
- "version": "1.47.0",
3
+ "version": "1.47.2",
4
4
  "browser": "./esm/index.js",
5
5
  "main": "./index.js",
6
6
  "dependencies": {
7
- "@astral/icons": "^1.47.0",
7
+ "@astral/icons": "^1.47.2",
8
8
  "@emotion/cache": "11.7.1",
9
9
  "@emotion/react": "11.9.0",
10
10
  "@emotion/server": "11.4.0",