fix(date-picker): open and close datepicker after pressing selector button (#3283)

* fix(date-picker): use trigger ref instead

* fix(date-input): add innerWrapperProps

* fix(date-picker): include popoverTriggerRef and add onPress to selector

* feat(date-picker): add test

* feat(changeset): add changeset

* refactor(date-input): merge innerWrapperPropsProp & props and add cn
This commit is contained in:
աӄա 2024-07-06 16:01:19 +08:00 committed by GitHub
parent b4c046fe8b
commit a164c26e96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 46 additions and 6 deletions

View File

@ -0,0 +1,6 @@
---
"@nextui-org/date-input": patch
"@nextui-org/date-picker": patch
---
Fixed date picker closing issue after pressing selector button (#3282)

View File

@ -15,7 +15,7 @@ import {useDOMRef} from "@nextui-org/react-utils";
import {useDateField as useAriaDateField} from "@react-aria/datepicker";
import {useDateFieldState} from "@react-stately/datepicker";
import {objectToDeps, clsx, dataAttr, getGregorianYearOffset} from "@nextui-org/shared-utils";
import {dateInput} from "@nextui-org/theme";
import {dateInput, cn} from "@nextui-org/theme";
import {useMemo} from "react";
type NextUIBaseProps<T extends DateValue> = Omit<
@ -34,6 +34,8 @@ interface Props<T extends DateValue> extends NextUIBaseProps<T> {
labelProps?: DOMAttributes;
/** Props for the date field. */
fieldProps?: DOMAttributes;
/** Props for the inner wrapper. */
innerWrapperProps?: DOMAttributes;
/** Props for the description element, if any. */
descriptionProps?: DOMAttributes;
/** Props for the error message element, if any. */
@ -138,6 +140,7 @@ export function useDateInput<T extends DateValue>(originalProps: UseDateInputPro
groupProps = {},
labelProps: labelPropsProp,
fieldProps: fieldPropsProp,
innerWrapperProps: innerWrapperPropsProp,
errorMessageProps: errorMessagePropsProp,
descriptionProps: descriptionPropsProp,
validationBehavior = globalContext?.validationBehavior ?? "aria",
@ -251,11 +254,13 @@ export function useDateInput<T extends DateValue>(originalProps: UseDateInputPro
};
const getInnerWrapperProps: PropGetter = (props) => {
const innerWrapperProps = mergeProps(innerWrapperPropsProp, props);
return {
...props,
...innerWrapperProps,
"data-slot": "inner-wrapper",
className: slots.innerWrapper({
class: classNames?.innerWrapper,
class: cn(classNames?.innerWrapper, innerWrapperProps?.className),
}),
};
};

View File

@ -675,5 +675,27 @@ describe("DatePicker", () => {
expect(month).toHaveAttribute("data-value", "6");
expect(year).toHaveAttribute("data-value", "2567");
});
it("should open and close popover after clicking selector button", () => {
const {getByRole} = render(<DatePicker data-testid="datepicker" label="Date" />);
const selectorButton = getByRole("button");
expect(selectorButton).not.toBeNull();
// open the datepicker dialog by clicking selector button
triggerPress(selectorButton);
let dialog = getByRole("dialog");
// assert that the datepicker dialog is open
expect(dialog).toBeVisible();
// click the selector button again
triggerPress(selectorButton);
// assert that the datepicker dialog is closed
expect(dialog).not.toBeVisible();
});
});
});

View File

@ -9,7 +9,7 @@ import type {DOMAttributes} from "@nextui-org/system";
import type {DatePickerSlots, SlotsToClasses} from "@nextui-org/theme";
import {useProviderContext} from "@nextui-org/system";
import {useMemo} from "react";
import {useMemo, useRef} from "react";
import {datePicker} from "@nextui-org/theme";
import {useDatePickerState} from "@react-stately/datepicker";
import {AriaDatePickerProps, useDatePicker as useAriaDatePicker} from "@react-aria/datepicker";
@ -101,6 +101,8 @@ export function useDatePicker<T extends DateValue>({
},
});
const popoverTriggerRef = useRef<HTMLDivElement>(null);
const baseStyles = clsx(classNames?.base, className);
const slots = useMemo(
@ -148,6 +150,9 @@ export function useDatePicker<T extends DateValue>({
disableAnimation,
}),
className: slots.base({class: baseStyles}),
innerWrapperProps: {
ref: popoverTriggerRef,
},
"data-open": dataAttr(state.isOpen),
} as DateInputProps;
};
@ -178,6 +183,7 @@ export function useDatePicker<T extends DateValue>({
state,
dialogProps,
...popoverProps,
triggerRef: popoverTriggerRef,
classNames: {
content: slots.popoverContent({
class: clsx(
@ -189,7 +195,7 @@ export function useDatePicker<T extends DateValue>({
},
shouldCloseOnInteractOutside: popoverProps?.shouldCloseOnInteractOutside
? popoverProps.shouldCloseOnInteractOutside
: (element: Element) => ariaShouldCloseOnInteractOutside(element, domRef, state),
: (element: Element) => ariaShouldCloseOnInteractOutside(element, popoverTriggerRef, state),
};
};
@ -208,6 +214,7 @@ export function useDatePicker<T extends DateValue>({
return {
...buttonProps,
...selectorButtonProps,
onPress: state.toggle,
className: slots.selectorButton({class: classNames?.selectorButton}),
};
};

View File

@ -218,7 +218,7 @@ export function useDateRangePicker<T extends DateValue>({
},
shouldCloseOnInteractOutside: popoverProps?.shouldCloseOnInteractOutside
? popoverProps.shouldCloseOnInteractOutside
: (element: Element) => ariaShouldCloseOnInteractOutside(element, domRef, state),
: (element: Element) => ariaShouldCloseOnInteractOutside(element, popoverTriggerRef, state),
} as PopoverProps;
};