From 77e692f239d209ff59c21a7920df646a65f5098b Mon Sep 17 00:00:00 2001 From: WK Wong Date: Sun, 15 Sep 2024 17:53:08 +0800 Subject: [PATCH 1/9] feat(dropdown): add "should respect closeOnSelect setting of DropdownItem (dynamic)" --- .../dropdown/__tests__/dropdown.test.tsx | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/components/dropdown/__tests__/dropdown.test.tsx b/packages/components/dropdown/__tests__/dropdown.test.tsx index b719db3c0c..359e337116 100644 --- a/packages/components/dropdown/__tests__/dropdown.test.tsx +++ b/packages/components/dropdown/__tests__/dropdown.test.tsx @@ -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( @@ -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( + + + + + + {(item) => ( + + {item.label} + + )} + + , + ); + + 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); + }); + }); }); From 30e79c827f2d7ff25ebb23f67ce17f0788fc35db Mon Sep 17 00:00:00 2001 From: WK Wong Date: Sun, 15 Sep 2024 17:54:38 +0800 Subject: [PATCH 2/9] chore(changeset): add changeset --- .changeset/serious-panthers-beg.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/serious-panthers-beg.md diff --git a/.changeset/serious-panthers-beg.md b/.changeset/serious-panthers-beg.md new file mode 100644 index 0000000000..a04e04ddb5 --- /dev/null +++ b/.changeset/serious-panthers-beg.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/dropdown": patch +--- + +fixed \_a2.find is not a function (#3761) From 94a9f2b200fd9866a44a526ef13343b8d1044c2b Mon Sep 17 00:00:00 2001 From: winches <329487092@qq.com> Date: Sun, 15 Sep 2024 18:18:03 +0800 Subject: [PATCH 3/9] fix(dropdown): find is not function error when click dropdown item (#3763) --- .../components/dropdown/src/use-dropdown.ts | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/components/dropdown/src/use-dropdown.ts b/packages/components/dropdown/src/use-dropdown.ts index 74294a4032..417a0275bb 100644 --- a/packages/components/dropdown/src/use-dropdown.ts +++ b/packages/components/dropdown/src/use-dropdown.ts @@ -42,6 +42,37 @@ interface Props extends HTMLNextUIProps<"div"> { export type UseDropdownProps = Props & Omit; +const getMenuItem = (props: Partial> | undefined, key: string) => { + if (props) { + const mergedChildren = Array.isArray(props.children) + ? props.children + : [...(props?.items || [])]; + + if (mergedChildren && mergedChildren.length) { + const item = (mergedChildren.find((item) => { + if ("key" in item && item.key === key) { + return item; + } + }) || {}) as {props: MenuProps}; + + return item; + } + } +}; + +const getCloseOnSelect = ( + props: Partial> | undefined, + key: string, +) => { + const item = getMenuItem(props, key); + + if (item && item.props && "closeOnSelect" in item.props) { + return item.props.closeOnSelect; + } + + return props?.closeOnSelect; +}; + export function useDropdown(props: UseDropdownProps) { const globalContext = useProviderContext(); @@ -153,15 +184,9 @@ export function useDropdown(props: UseDropdownProps) { closeOnSelect, ...mergeProps(props, { onAction: (key: any) => { - // @ts-ignore - const item = props?.children?.find((item) => item.key === key); - - if (item?.props?.closeOnSelect === false) { - onMenuAction(false); + const closeOnSelect = getCloseOnSelect(props, key); - return; - } - onMenuAction(props?.closeOnSelect); + onMenuAction(closeOnSelect); }, onClose: state.close, }), From dbb1002b32fb48d8d850cbcb31b3dbb0ff3232e0 Mon Sep 17 00:00:00 2001 From: winches <329487092@qq.com> Date: Sun, 15 Sep 2024 18:47:09 +0800 Subject: [PATCH 4/9] fix: find is not function error when click dropdown item --- packages/components/dropdown/src/use-dropdown.ts | 4 ++-- packages/hooks/use-aria-menu/src/use-menu-item.ts | 6 +++--- packages/hooks/use-aria-menu/src/use-menu.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/components/dropdown/src/use-dropdown.ts b/packages/components/dropdown/src/use-dropdown.ts index 417a0275bb..9fd3f69c3a 100644 --- a/packages/components/dropdown/src/use-dropdown.ts +++ b/packages/components/dropdown/src/use-dropdown.ts @@ -183,8 +183,8 @@ export function useDropdown(props: UseDropdownProps) { menuProps, closeOnSelect, ...mergeProps(props, { - onAction: (key: any) => { - const closeOnSelect = getCloseOnSelect(props, key); + onAction: (key: any, item?: any) => { + const closeOnSelect = item ? item.props?.closeOnSelect : getCloseOnSelect(props, key); onMenuAction(closeOnSelect); }, diff --git a/packages/hooks/use-aria-menu/src/use-menu-item.ts b/packages/hooks/use-aria-menu/src/use-menu-item.ts index 4696f8ea6a..ccc346c767 100644 --- a/packages/hooks/use-aria-menu/src/use-menu-item.ts +++ b/packages/hooks/use-aria-menu/src/use-menu-item.ts @@ -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( 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) { diff --git a/packages/hooks/use-aria-menu/src/use-menu.ts b/packages/hooks/use-aria-menu/src/use-menu.ts index ff551c1341..220b4fae05 100644 --- a/packages/hooks/use-aria-menu/src/use-menu.ts +++ b/packages/hooks/use-aria-menu/src/use-menu.ts @@ -24,7 +24,7 @@ export interface AriaMenuOptions extends Omit, "children">, interface MenuData { onClose?: () => void; - onAction?: (key: Key) => void; + onAction?: (key: Key, item: any) => void; } export const menuData = new WeakMap, MenuData>(); From d4d34eb75c7dcd13febf01c9ee23be1e77f98ae2 Mon Sep 17 00:00:00 2001 From: winches <329487092@qq.com> Date: Sun, 15 Sep 2024 18:56:03 +0800 Subject: [PATCH 5/9] fix: find is not function error when click dropdown item --- packages/components/dropdown/src/use-dropdown.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/components/dropdown/src/use-dropdown.ts b/packages/components/dropdown/src/use-dropdown.ts index 9fd3f69c3a..fe716f5bb3 100644 --- a/packages/components/dropdown/src/use-dropdown.ts +++ b/packages/components/dropdown/src/use-dropdown.ts @@ -63,11 +63,12 @@ const getMenuItem = (props: Partial> | undefined, const getCloseOnSelect = ( props: Partial> | undefined, key: string, + item?: any, ) => { - const item = getMenuItem(props, key); + const mergedItem = item || getMenuItem(props, key); - if (item && item.props && "closeOnSelect" in item.props) { - return item.props.closeOnSelect; + if (mergedItem && mergedItem.props && "closeOnSelect" in mergedItem.props) { + return mergedItem.props.closeOnSelect; } return props?.closeOnSelect; @@ -184,7 +185,7 @@ export function useDropdown(props: UseDropdownProps) { closeOnSelect, ...mergeProps(props, { onAction: (key: any, item?: any) => { - const closeOnSelect = item ? item.props?.closeOnSelect : getCloseOnSelect(props, key); + const closeOnSelect = getCloseOnSelect(props, key, item); onMenuAction(closeOnSelect); }, From 756202f2edf7b3a56cbe9da28d5d22c723cc6a4d Mon Sep 17 00:00:00 2001 From: winches <329487092@qq.com> Date: Sun, 15 Sep 2024 19:00:08 +0800 Subject: [PATCH 6/9] fix: type error --- packages/components/dropdown/src/use-dropdown.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/components/dropdown/src/use-dropdown.ts b/packages/components/dropdown/src/use-dropdown.ts index fe716f5bb3..0ff16bfab3 100644 --- a/packages/components/dropdown/src/use-dropdown.ts +++ b/packages/components/dropdown/src/use-dropdown.ts @@ -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"> { /** @@ -49,8 +50,8 @@ const getMenuItem = (props: Partial> | undefined, : [...(props?.items || [])]; if (mergedChildren && mergedChildren.length) { - const item = (mergedChildren.find((item) => { - if ("key" in item && item.key === key) { + const item = ((mergedChildren as CollectionElement[]).find((item) => { + if (item.key === key) { return item; } }) || {}) as {props: MenuProps}; From ba94ebc50584c8531498810c474791e0e04084a0 Mon Sep 17 00:00:00 2001 From: winches <329487092@qq.com> Date: Sun, 15 Sep 2024 19:06:13 +0800 Subject: [PATCH 7/9] fix: optimization --- .../components/dropdown/src/use-dropdown.ts | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/components/dropdown/src/use-dropdown.ts b/packages/components/dropdown/src/use-dropdown.ts index 0ff16bfab3..4a0c8cbf7f 100644 --- a/packages/components/dropdown/src/use-dropdown.ts +++ b/packages/components/dropdown/src/use-dropdown.ts @@ -44,20 +44,19 @@ interface Props extends HTMLNextUIProps<"div"> { export type UseDropdownProps = Props & Omit; const getMenuItem = (props: Partial> | undefined, key: string) => { - if (props) { - const mergedChildren = Array.isArray(props.children) - ? props.children - : [...(props?.items || [])]; - - if (mergedChildren && mergedChildren.length) { - const item = ((mergedChildren as CollectionElement[]).find((item) => { - if (item.key === key) { - return item; - } - }) || {}) as {props: MenuProps}; - - return item; - } + if (!props) { + return null; + } + const mergedChildren = Array.isArray(props.children) ? props.children : [...(props?.items || [])]; + + if (mergedChildren && mergedChildren.length) { + const item = ((mergedChildren as CollectionElement[]).find((item) => { + if (item.key === key) { + return item; + } + }) || {}) as {props: MenuProps}; + + return item; } }; From 891fcf5e3a09edd33137e9bde90f7e4bbde3a857 Mon Sep 17 00:00:00 2001 From: WK Wong Date: Sun, 15 Sep 2024 19:10:13 +0800 Subject: [PATCH 8/9] refactor(dropdown): must have return value --- .../components/dropdown/src/use-dropdown.ts | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/components/dropdown/src/use-dropdown.ts b/packages/components/dropdown/src/use-dropdown.ts index 4a0c8cbf7f..cff1cc1b9e 100644 --- a/packages/components/dropdown/src/use-dropdown.ts +++ b/packages/components/dropdown/src/use-dropdown.ts @@ -44,20 +44,23 @@ interface Props extends HTMLNextUIProps<"div"> { export type UseDropdownProps = Props & Omit; const getMenuItem = (props: Partial> | undefined, key: string) => { - if (!props) { - return null; + if (props) { + const mergedChildren = Array.isArray(props.children) + ? props.children + : [...(props?.items || [])]; + + if (mergedChildren && mergedChildren.length) { + const item = ((mergedChildren as CollectionElement[]).find((item) => { + if (item.key === key) { + return item; + } + }) || {}) as {props: MenuProps}; + + return item; + } } - const mergedChildren = Array.isArray(props.children) ? props.children : [...(props?.items || [])]; - - if (mergedChildren && mergedChildren.length) { - const item = ((mergedChildren as CollectionElement[]).find((item) => { - if (item.key === key) { - return item; - } - }) || {}) as {props: MenuProps}; - return item; - } + return null; }; const getCloseOnSelect = ( From cf564ce11681b892b3d030659bb2997f6864281b Mon Sep 17 00:00:00 2001 From: WK Wong Date: Sun, 15 Sep 2024 19:10:28 +0800 Subject: [PATCH 9/9] chore(changeset): revise changeset --- .changeset/serious-panthers-beg.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.changeset/serious-panthers-beg.md b/.changeset/serious-panthers-beg.md index a04e04ddb5..34b1ee0a71 100644 --- a/.changeset/serious-panthers-beg.md +++ b/.changeset/serious-panthers-beg.md @@ -1,5 +1,6 @@ --- "@nextui-org/dropdown": patch +"@nextui-org/use-aria-menu": patch --- -fixed \_a2.find is not a function (#3761) +fixed `_a2.find` is not a function (#3761)