diff --git a/packages/vkui/src/components/DateInput/DateInput.test.tsx b/packages/vkui/src/components/DateInput/DateInput.test.tsx
index 01b4650de5..a77be4e24e 100644
--- a/packages/vkui/src/components/DateInput/DateInput.test.tsx
+++ b/packages/vkui/src/components/DateInput/DateInput.test.tsx
@@ -123,4 +123,27 @@ describe('DateInput', () => {
expect(container.contains(document.activeElement)).toBeFalsy();
});
+
+ it('should call onCloseCalendar calendar was closed', async () => {
+ jest.useFakeTimers();
+ const onCalendarOpenChanged = jest.fn();
+ const { container } = render(
+ ,
+ );
+ const inputLikes = getInputsLike(container);
+
+ const [dates] = inputLikes;
+
+ await userEvent.click(dates);
+ expect(onCalendarOpenChanged).toHaveBeenCalledTimes(1);
+ expect(onCalendarOpenChanged.mock.calls[0][0]).toBeTruthy();
+
+ expect(container.contains(document.activeElement)).toBeTruthy();
+ await userEvent.click(screen.getByText(`${date.getDate() - 1}`));
+
+ expect(onCalendarOpenChanged).toHaveBeenCalledTimes(2);
+ expect(onCalendarOpenChanged.mock.calls[1][0]).toBeFalsy();
+
+ expect(container.contains(document.activeElement)).toBeFalsy();
+ });
});
diff --git a/packages/vkui/src/components/DateInput/DateInput.tsx b/packages/vkui/src/components/DateInput/DateInput.tsx
index 9c2b1674c2..85b23db213 100644
--- a/packages/vkui/src/components/DateInput/DateInput.tsx
+++ b/packages/vkui/src/components/DateInput/DateInput.tsx
@@ -62,6 +62,7 @@ export interface DateInputProps
clearFieldLabel?: string;
showCalendarLabel?: string;
disableCalendar?: boolean;
+ onCalendarOpenChanged?: (opened: boolean) => void;
}
const elementsConfig = (index: number) => {
@@ -147,6 +148,7 @@ export const DateInput = ({
nextMonthIcon,
disableCalendar = false,
renderDayContent,
+ onCalendarOpenChanged,
...props
}: DateInputProps): React.ReactNode => {
const daysRef = React.useRef(null);
@@ -205,6 +207,7 @@ export const DateInput = ({
onInternalValueChange,
getInternalValue,
value,
+ onCalendarOpenChanged,
});
const { sizeY = 'none' } = useAdaptivity();
diff --git a/packages/vkui/src/components/DateRangeInput/DateRangeInput.test.tsx b/packages/vkui/src/components/DateRangeInput/DateRangeInput.test.tsx
index 61b16432d6..b30571b360 100644
--- a/packages/vkui/src/components/DateRangeInput/DateRangeInput.test.tsx
+++ b/packages/vkui/src/components/DateRangeInput/DateRangeInput.test.tsx
@@ -138,4 +138,27 @@ describe('DateRangeInput', () => {
expect(onChange).toBeCalledTimes(0);
});
+
+ it('should call onCalendarClose callback when calendar was closed', async () => {
+ jest.useFakeTimers();
+ const onCalendarOpenChanged = jest.fn();
+ const { container } = render(
+ ,
+ );
+ const inputLikes = getInputsLike(container);
+ const [dates] = inputLikes;
+
+ await userEvent.click(dates);
+
+ expect(onCalendarOpenChanged).toHaveBeenCalledTimes(1);
+ expect(onCalendarOpenChanged.mock.calls[0][0]).toBeTruthy();
+
+ expect(container.contains(document.activeElement)).toBeTruthy();
+ await userEvent.click(screen.getAllByText('15')[1]);
+
+ expect(onCalendarOpenChanged).toHaveBeenCalledTimes(2);
+ expect(onCalendarOpenChanged.mock.calls[1][0]).toBeFalsy();
+
+ expect(container.contains(document.activeElement)).toBeFalsy();
+ });
});
diff --git a/packages/vkui/src/components/DateRangeInput/DateRangeInput.tsx b/packages/vkui/src/components/DateRangeInput/DateRangeInput.tsx
index 537a269b14..f1be9e347a 100644
--- a/packages/vkui/src/components/DateRangeInput/DateRangeInput.tsx
+++ b/packages/vkui/src/components/DateRangeInput/DateRangeInput.tsx
@@ -53,6 +53,7 @@ export interface DateRangeInputProps
Omit {
calendarPlacement?: PlacementWithAuto;
closeOnChange?: boolean;
+ onCalendarOpenChanged?: (opened: boolean) => void;
clearFieldLabel?: string;
showCalendarLabel?: string;
changeStartDayLabel?: string;
@@ -140,6 +141,7 @@ export const DateRangeInput = ({
prevMonthIcon,
nextMonthIcon,
disableCalendar = false,
+ onCalendarOpenChanged,
renderDayContent,
...props
}: DateRangeInputProps): React.ReactNode => {
@@ -221,6 +223,7 @@ export const DateRangeInput = ({
onInternalValueChange,
getInternalValue,
value,
+ onCalendarOpenChanged,
});
const { sizeY = 'none' } = useAdaptivity();
diff --git a/packages/vkui/src/hooks/useDateInput.ts b/packages/vkui/src/hooks/useDateInput.ts
index d6ff9befe9..33565cc36d 100644
--- a/packages/vkui/src/hooks/useDateInput.ts
+++ b/packages/vkui/src/hooks/useDateInput.ts
@@ -1,3 +1,4 @@
+import { useCallback } from 'react';
import * as React from 'react';
import { useDOM } from '../lib/dom';
import { useBooleanState } from './useBooleanState';
@@ -17,6 +18,7 @@ export interface UseDateInputDependencies {
onInternalValueChange: (value: string[]) => void;
getInternalValue: (value?: D | undefined) => string[];
onChange?: (value?: D | undefined) => void;
+ onCalendarOpenChanged?: (opened: boolean) => void;
}
export function useDateInput({
@@ -29,6 +31,7 @@ export function useDateInput({
onInternalValueChange,
getInternalValue,
value,
+ onCalendarOpenChanged,
}: UseDateInputDependencies): {
rootRef: React.RefObject;
calendarRef: React.RefObject;
@@ -51,14 +54,28 @@ export function useDateInput({
const [focusedElement, setFocusedElement] = React.useState(null);
const { window } = useDOM();
+ const _onCalendarClose = useCallback(() => {
+ if (open) {
+ closeCalendar();
+ onCalendarOpenChanged?.(false);
+ }
+ }, [closeCalendar, onCalendarOpenChanged, open]);
+
+ const _onCalendarOpen = useCallback(() => {
+ if (!open) {
+ openCalendar();
+ onCalendarOpenChanged?.(true);
+ }
+ }, [onCalendarOpenChanged, open, openCalendar]);
+
const removeFocusFromField = React.useCallback(() => {
if (focusedElement !== null) {
setFocusedElement(null);
- closeCalendar();
+ _onCalendarClose();
window!.getSelection()?.removeAllRanges();
setInternalValue(getInternalValue(value));
}
- }, [focusedElement, closeCalendar, getInternalValue, value, window]);
+ }, [focusedElement, _onCalendarClose, window, getInternalValue, value]);
const handleClickOutside = React.useCallback(
(e: MouseEvent) => {
@@ -101,14 +118,14 @@ export function useDateInput({
if (element) {
element.focus();
- openCalendar();
+ _onCalendarOpen();
range.selectNodeContents(element as Node);
const selection = window!.getSelection();
selection?.removeAllRanges();
selection?.addRange(range);
}
- }, [disabled, focusedElement, openCalendar, refs, window]);
+ }, [disabled, focusedElement, _onCalendarOpen, refs, window]);
const clear = React.useCallback(() => {
onChange?.(undefined);
@@ -190,8 +207,8 @@ export function useDateInput({
rootRef,
calendarRef,
open,
- openCalendar,
- closeCalendar,
+ openCalendar: _onCalendarOpen,
+ closeCalendar: _onCalendarClose,
internalValue,
focusedElement,
setFocusedElement,