mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
fix(dropdown): _a2.find is not a function (#3762)
* feat(dropdown): add "should respect closeOnSelect setting of DropdownItem (dynamic)" * chore(changeset): add changeset * fix(dropdown): find is not function error when click dropdown item (#3763) * fix: find is not function error when click dropdown item * fix: find is not function error when click dropdown item * fix: type error * fix: optimization * refactor(dropdown): must have return value * chore(changeset): revise changeset --------- Co-authored-by: winches <329487092@qq.com>
This commit is contained in:
parent
2293884229
commit
8fecb5afa9
6
.changeset/serious-panthers-beg.md
Normal file
6
.changeset/serious-panthers-beg.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@nextui-org/dropdown": patch
|
||||
"@nextui-org/use-aria-menu": patch
|
||||
---
|
||||
|
||||
fixed `_a2.find` is not a function (#3761)
|
||||
@ -796,7 +796,7 @@ describe("Keyboard interactions", () => {
|
||||
logSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("should respect closeOnSelect setting of DropdownItem", async () => {
|
||||
it("should respect closeOnSelect setting of DropdownItem (static)", async () => {
|
||||
const onOpenChange = jest.fn();
|
||||
const wrapper = render(
|
||||
<Dropdown onOpenChange={onOpenChange}>
|
||||
@ -831,4 +831,51 @@ describe("Keyboard interactions", () => {
|
||||
expect(onOpenChange).toBeCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
it("should respect closeOnSelect setting of DropdownItem (dynamic)", async () => {
|
||||
const onOpenChange = jest.fn();
|
||||
const items = [
|
||||
{
|
||||
key: "new",
|
||||
label: "New file",
|
||||
},
|
||||
{
|
||||
key: "copy",
|
||||
label: "Copy link",
|
||||
},
|
||||
];
|
||||
const wrapper = render(
|
||||
<Dropdown onOpenChange={onOpenChange}>
|
||||
<DropdownTrigger>
|
||||
<Button data-testid="trigger-test">Trigger</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Actions" items={items}>
|
||||
{(item) => (
|
||||
<DropdownItem key={item.key} closeOnSelect={item.key !== "new"}>
|
||||
{item.label}
|
||||
</DropdownItem>
|
||||
)}
|
||||
</DropdownMenu>
|
||||
</Dropdown>,
|
||||
);
|
||||
|
||||
let triggerButton = wrapper.getByTestId("trigger-test");
|
||||
|
||||
act(() => {
|
||||
triggerButton.click();
|
||||
});
|
||||
expect(onOpenChange).toBeCalledTimes(1);
|
||||
|
||||
let menuItems = wrapper.getAllByRole("menuitem");
|
||||
|
||||
await act(async () => {
|
||||
await userEvent.click(menuItems[0]);
|
||||
expect(onOpenChange).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await userEvent.click(menuItems[1]);
|
||||
expect(onOpenChange).toBeCalledTimes(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -13,6 +13,7 @@ import {ariaShouldCloseOnInteractOutside} from "@nextui-org/aria-utils";
|
||||
import {useMemo, useRef} from "react";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {MenuProps} from "@nextui-org/menu";
|
||||
import {CollectionElement} from "@react-types/shared";
|
||||
|
||||
interface Props extends HTMLNextUIProps<"div"> {
|
||||
/**
|
||||
@ -42,6 +43,40 @@ interface Props extends HTMLNextUIProps<"div"> {
|
||||
|
||||
export type UseDropdownProps = Props & Omit<PopoverProps, "children" | "color" | "variant">;
|
||||
|
||||
const getMenuItem = <T extends object>(props: Partial<MenuProps<T>> | undefined, key: string) => {
|
||||
if (props) {
|
||||
const mergedChildren = Array.isArray(props.children)
|
||||
? props.children
|
||||
: [...(props?.items || [])];
|
||||
|
||||
if (mergedChildren && mergedChildren.length) {
|
||||
const item = ((mergedChildren as CollectionElement<T>[]).find((item) => {
|
||||
if (item.key === key) {
|
||||
return item;
|
||||
}
|
||||
}) || {}) as {props: MenuProps};
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const getCloseOnSelect = <T extends object>(
|
||||
props: Partial<MenuProps<T>> | undefined,
|
||||
key: string,
|
||||
item?: any,
|
||||
) => {
|
||||
const mergedItem = item || getMenuItem(props, key);
|
||||
|
||||
if (mergedItem && mergedItem.props && "closeOnSelect" in mergedItem.props) {
|
||||
return mergedItem.props.closeOnSelect;
|
||||
}
|
||||
|
||||
return props?.closeOnSelect;
|
||||
};
|
||||
|
||||
export function useDropdown(props: UseDropdownProps) {
|
||||
const globalContext = useProviderContext();
|
||||
|
||||
@ -152,16 +187,10 @@ export function useDropdown(props: UseDropdownProps) {
|
||||
menuProps,
|
||||
closeOnSelect,
|
||||
...mergeProps(props, {
|
||||
onAction: (key: any) => {
|
||||
// @ts-ignore
|
||||
const item = props?.children?.find((item) => item.key === key);
|
||||
onAction: (key: any, item?: any) => {
|
||||
const closeOnSelect = getCloseOnSelect(props, key, item);
|
||||
|
||||
if (item?.props?.closeOnSelect === false) {
|
||||
onMenuAction(false);
|
||||
|
||||
return;
|
||||
}
|
||||
onMenuAction(props?.closeOnSelect);
|
||||
onMenuAction(closeOnSelect);
|
||||
},
|
||||
onClose: state.close,
|
||||
}),
|
||||
|
||||
@ -94,7 +94,7 @@ export interface AriaMenuItemProps
|
||||
* Handler that is called when the user activates the item.
|
||||
* @deprecated - pass to the menu instead.
|
||||
*/
|
||||
onAction?: (key: Key) => void;
|
||||
onAction?: (key: Key, item: any) => void;
|
||||
|
||||
/**
|
||||
* The native button click event handler
|
||||
@ -167,11 +167,11 @@ export function useMenuItem<T>(
|
||||
|
||||
if (props.onAction) {
|
||||
// @ts-ignore
|
||||
props.onAction(key);
|
||||
props.onAction(key, item);
|
||||
// @ts-ignore
|
||||
} else if (data.onAction) {
|
||||
// @ts-ignore
|
||||
data.onAction(key);
|
||||
data.onAction(key, item);
|
||||
}
|
||||
|
||||
if (e.target instanceof HTMLAnchorElement) {
|
||||
|
||||
@ -24,7 +24,7 @@ export interface AriaMenuOptions<T> extends Omit<AriaMenuProps<T>, "children">,
|
||||
|
||||
interface MenuData {
|
||||
onClose?: () => void;
|
||||
onAction?: (key: Key) => void;
|
||||
onAction?: (key: Key, item: any) => void;
|
||||
}
|
||||
|
||||
export const menuData = new WeakMap<TreeState<unknown>, MenuData>();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user