From c0cdf642a1fe76e16eec00f0ed3fa9fca0991e15 Mon Sep 17 00:00:00 2001
From: winches <329487092@qq.com>
Date: Thu, 28 Nov 2024 09:28:12 +0800
Subject: [PATCH 1/5] fix: menu item classNames not work
---
.../components/menu/__tests__/menu.test.tsx | 22 +++++++++++++++++++
packages/components/menu/src/menu.tsx | 5 +++--
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/packages/components/menu/__tests__/menu.test.tsx b/packages/components/menu/__tests__/menu.test.tsx
index 98530665ee..14f4e77fb0 100644
--- a/packages/components/menu/__tests__/menu.test.tsx
+++ b/packages/components/menu/__tests__/menu.test.tsx
@@ -343,4 +343,26 @@ describe("Menu", () => {
expect(onPress).toHaveBeenCalledTimes(1);
expect(onClick).toHaveBeenCalledTimes(1);
});
+
+ it("should menuItem classNames work", () => {
+ const wrapper = render(
+
,
+ );
+ const menuItem = wrapper.getByText("New file");
+
+ expect(menuItem.classList.contains("test")).toBeTruthy();
+ });
+
+ it("should menuItem classNames override menu itemClasses", () => {
+ const wrapper = render(
+ ,
+ );
+ const menuItem = wrapper.getByText("New file");
+
+ expect(menuItem.classList.contains("test2")).toBeTruthy();
+ });
});
diff --git a/packages/components/menu/src/menu.tsx b/packages/components/menu/src/menu.tsx
index 318b86baa1..5ebef58dde 100644
--- a/packages/components/menu/src/menu.tsx
+++ b/packages/components/menu/src/menu.tsx
@@ -47,11 +47,12 @@ function Menu(props: Props, ref: ForwardedRef;
+ return ;
}
- let menuItem = ;
+ let menuItem = ;
if (item.wrapper) {
menuItem = item.wrapper(menuItem);
From 75470ec70eb331d6d4a9538d70d7733ba5ab304f Mon Sep 17 00:00:00 2001
From: winches <329487092@qq.com>
Date: Thu, 28 Nov 2024 09:28:59 +0800
Subject: [PATCH 2/5] feat: changeset
---
.changeset/brave-trains-wave.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .changeset/brave-trains-wave.md
diff --git a/.changeset/brave-trains-wave.md b/.changeset/brave-trains-wave.md
new file mode 100644
index 0000000000..80f4c73710
--- /dev/null
+++ b/.changeset/brave-trains-wave.md
@@ -0,0 +1,5 @@
+---
+"@nextui-org/menu": patch
+---
+
+Fix menu item classNames not work
From d17a1ca610c4ecea1a8af316a5f2c9e5471809a7 Mon Sep 17 00:00:00 2001
From: winches <329487092@qq.com>
Date: Thu, 28 Nov 2024 15:20:38 +0800
Subject: [PATCH 3/5] docs: update
---
.changeset/brave-trains-wave.md | 2 +-
apps/docs/content/docs/components/dropdown.mdx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.changeset/brave-trains-wave.md b/.changeset/brave-trains-wave.md
index 80f4c73710..02248deea1 100644
--- a/.changeset/brave-trains-wave.md
+++ b/.changeset/brave-trains-wave.md
@@ -2,4 +2,4 @@
"@nextui-org/menu": patch
---
-Fix menu item classNames not work
+Fix menu item classNames not work (#4119)
diff --git a/apps/docs/content/docs/components/dropdown.mdx b/apps/docs/content/docs/components/dropdown.mdx
index 24e48716d0..3ebad0239c 100644
--- a/apps/docs/content/docs/components/dropdown.mdx
+++ b/apps/docs/content/docs/components/dropdown.mdx
@@ -386,7 +386,7 @@ you to customize each item individually.
| isReadOnly | `boolean` | Whether the dropdown item press events should be ignored. | `false` |
| hideSelectedIcon | `boolean` | Whether to hide the check icon when the item is selected. | `false` |
| closeOnSelect | `boolean` | Whether the dropdown menu should be closed when the item is selected. | `true` |
-| classNames | `Record<"base"| "wrapper"| "title"| "description"| "shortcut" | "selectedIcon", string>` | Allows to set custom class names for the dropdown item slots. | - |
+| classNames | `Record<"base"| "wrapper"| "title"| "description"| "shortcut" | "selectedIcon", string>` | Allows to set custom class names for the dropdown item slots, which will override the menu `itemClasses`. | - |
### DropdownItem Events
From 77f22970b824905ebbd2f272051d1a50e304195c Mon Sep 17 00:00:00 2001
From: Junior Garcia
Date: Thu, 28 Nov 2024 10:15:14 -0300
Subject: [PATCH 4/5] feat: merge classes utility added
---
.../components/menu/__tests__/menu.test.tsx | 19 ++++++++++++++
packages/components/menu/src/menu.tsx | 4 ++-
packages/core/theme/src/utils/index.ts | 1 +
.../core/theme/src/utils/merge-classes.ts | 26 +++++++++++++++++++
4 files changed, 49 insertions(+), 1 deletion(-)
create mode 100644 packages/core/theme/src/utils/merge-classes.ts
diff --git a/packages/components/menu/__tests__/menu.test.tsx b/packages/components/menu/__tests__/menu.test.tsx
index d5771c3e93..eeaa3eb068 100644
--- a/packages/components/menu/__tests__/menu.test.tsx
+++ b/packages/components/menu/__tests__/menu.test.tsx
@@ -365,6 +365,25 @@ describe("Menu", () => {
expect(menuItem.classList.contains("test2")).toBeTruthy();
});
+ it("should merge menu item classNames with itemClasses", () => {
+ const wrapper = render(
+ ,
+ );
+
+ const menuItemWithBoth = wrapper.getByText("New file");
+ const menuItemWithDefault = wrapper.getByText("Delete file");
+
+ // Check first MenuItem has both classes
+ expect(menuItemWithBoth.classList.contains("test2")).toBeTruthy();
+ expect(menuItemWithBoth.classList.contains("test")).toBeTruthy();
+
+ // Check second MenuItem only has the default class
+ expect(menuItemWithDefault.classList.contains("test")).toBeTruthy();
+ expect(menuItemWithDefault.classList.contains("test2")).toBeFalsy();
+ });
it("should truncate the text if the child is not a string", () => {
const wrapper = render(
diff --git a/packages/components/menu/src/menu.tsx b/packages/components/menu/src/menu.tsx
index edced575b0..bff90fb8d1 100644
--- a/packages/components/menu/src/menu.tsx
+++ b/packages/components/menu/src/menu.tsx
@@ -1,5 +1,6 @@
import {forwardRef} from "@nextui-org/system";
import {ForwardedRef, ReactElement, Ref} from "react";
+import {mergeClasses} from "@nextui-org/theme";
import {UseMenuProps, useMenu} from "./use-menu";
import MenuSection from "./menu-section";
@@ -47,7 +48,8 @@ function Menu(props: Props, ref: ForwardedRef;
diff --git a/packages/core/theme/src/utils/index.ts b/packages/core/theme/src/utils/index.ts
index 262655a859..2a096ff86a 100644
--- a/packages/core/theme/src/utils/index.ts
+++ b/packages/core/theme/src/utils/index.ts
@@ -11,4 +11,5 @@ export {
export type {SlotsToClasses} from "./types";
export {colorVariants} from "./variants";
export {COMMON_UNITS, twMergeConfig} from "./tw-merge-config";
+export {mergeClasses} from "./merge-classes";
export {cn} from "./cn";
diff --git a/packages/core/theme/src/utils/merge-classes.ts b/packages/core/theme/src/utils/merge-classes.ts
new file mode 100644
index 0000000000..02ab8a914f
--- /dev/null
+++ b/packages/core/theme/src/utils/merge-classes.ts
@@ -0,0 +1,26 @@
+import type {SlotsToClasses} from "./types";
+
+import {clsx} from "@nextui-org/shared-utils";
+
+/**
+ * Merges two sets of class names for each slot in a component.
+ * @param itemClasses - Base classes for each slot
+ * @param itemPropsClasses - Additional classes from props for each slot
+ * @returns A merged object containing the combined classes for each slot
+ */
+export const mergeClasses = , P extends SlotsToClasses>(
+ itemClasses?: T,
+ itemPropsClasses?: P,
+): T => {
+ if (!itemClasses && !itemPropsClasses) return {} as T;
+
+ const keys = new Set([...Object.keys(itemClasses || {}), ...Object.keys(itemPropsClasses || {})]);
+
+ return Array.from(keys).reduce(
+ (acc, key) => ({
+ ...acc,
+ [key]: clsx(itemClasses?.[key], itemPropsClasses?.[key]),
+ }),
+ {} as T,
+ );
+};
From 965fc5debdeefd074140647a84f57780fa0d2427 Mon Sep 17 00:00:00 2001
From: Junior Garcia
Date: Thu, 28 Nov 2024 10:16:58 -0300
Subject: [PATCH 5/5] Update .changeset/brave-trains-wave.md
---
.changeset/brave-trains-wave.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/.changeset/brave-trains-wave.md b/.changeset/brave-trains-wave.md
index 02248deea1..c81facf5b1 100644
--- a/.changeset/brave-trains-wave.md
+++ b/.changeset/brave-trains-wave.md
@@ -1,5 +1,6 @@
---
"@nextui-org/menu": patch
+"@nextui-org/theme": patch
---
Fix menu item classNames not work (#4119)