From 256d462771c19d6ca5b969d0ec44419fb560f0ac Mon Sep 17 00:00:00 2001 From: winches <329487092@qq.com> Date: Thu, 28 Nov 2024 02:31:42 +0800 Subject: [PATCH] fix(theme): add truncate class to the list item to avoid overflow the wrapper (#4105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(docs): invalid canary storybook link (#4030) * fix: menu item hidden overflow text * feat: changeset * Merge branch 'beta/release-next' into fix/menu-item-hidden * fix: truncate list item * feat: update changeset * fix(menu): omit internal props --------- Co-authored-by: աӄա Co-authored-by: Junior Garcia --- .changeset/lazy-buttons-exercise.md | 7 +++++ .../listbox/__tests__/listbox.test.tsx | 26 +++++++++++++++++++ .../listbox/src/use-listbox-item.ts | 4 ++- .../components/menu/__tests__/menu.test.tsx | 26 +++++++++++++++++++ packages/components/menu/src/menu.tsx | 5 +++- packages/components/menu/src/use-menu-item.ts | 4 ++- packages/core/theme/src/components/menu.ts | 13 +++++++++- 7 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 .changeset/lazy-buttons-exercise.md diff --git a/.changeset/lazy-buttons-exercise.md b/.changeset/lazy-buttons-exercise.md new file mode 100644 index 0000000000..5cdc25373d --- /dev/null +++ b/.changeset/lazy-buttons-exercise.md @@ -0,0 +1,7 @@ +--- +"@nextui-org/listbox": patch +"@nextui-org/menu": patch +"@nextui-org/theme": patch +--- + +Add truncate class to the list item to avoid overflow the wrapper diff --git a/packages/components/listbox/__tests__/listbox.test.tsx b/packages/components/listbox/__tests__/listbox.test.tsx index 36bc7ebca3..60614536bf 100644 --- a/packages/components/listbox/__tests__/listbox.test.tsx +++ b/packages/components/listbox/__tests__/listbox.test.tsx @@ -273,4 +273,30 @@ describe("Listbox", () => { expect(checkmark1).toBeFalsy(); }); + + it("should truncate the text if the child is not a string", () => { + const wrapper = render( + + New file + , + ); + + const menuItem = wrapper.getByText("New file"); + + expect(menuItem).toHaveProperty("className", expect.stringContaining("truncate")); + }); + + it("should not truncate the text if the child is a string", () => { + const wrapper = render( + + +
New file
+
+
, + ); + + const menuItem = wrapper.getByText("New file").parentElement; + + expect(menuItem).not.toHaveProperty("className", expect.stringContaining("truncate")); + }); }); diff --git a/packages/components/listbox/src/use-listbox-item.ts b/packages/components/listbox/src/use-listbox-item.ts index f4e0781644..37103f2107 100644 --- a/packages/components/listbox/src/use-listbox-item.ts +++ b/packages/components/listbox/src/use-listbox-item.ts @@ -99,8 +99,10 @@ export function useListboxItem(originalProps: UseListboxItemPr ...variantProps, isDisabled, disableAnimation, + hasTitleTextChild: typeof rendered === "string", + hasDescriptionTextChild: typeof description === "string", }), - [objectToDeps(variantProps), isDisabled, disableAnimation], + [objectToDeps(variantProps), isDisabled, disableAnimation, rendered, description], ); const baseStyles = clsx(classNames?.base, className); diff --git a/packages/components/menu/__tests__/menu.test.tsx b/packages/components/menu/__tests__/menu.test.tsx index 98530665ee..d8a9a53ddd 100644 --- a/packages/components/menu/__tests__/menu.test.tsx +++ b/packages/components/menu/__tests__/menu.test.tsx @@ -343,4 +343,30 @@ describe("Menu", () => { expect(onPress).toHaveBeenCalledTimes(1); expect(onClick).toHaveBeenCalledTimes(1); }); + + it("should truncate the text if the child is not a string", () => { + const wrapper = render( + + New file + , + ); + + const menuItem = wrapper.getByText("New file"); + + expect(menuItem).toHaveProperty("className", expect.stringContaining("truncate")); + }); + + it("should not truncate the text if the child is a string", () => { + const wrapper = render( + + +
New file
+
+
, + ); + + const menuItem = wrapper.getByText("New file").parentElement; + + expect(menuItem).not.toHaveProperty("className", expect.stringContaining("truncate")); + }); }); diff --git a/packages/components/menu/src/menu.tsx b/packages/components/menu/src/menu.tsx index 318b86baa1..a4658b4f28 100644 --- a/packages/components/menu/src/menu.tsx +++ b/packages/components/menu/src/menu.tsx @@ -71,7 +71,10 @@ function Menu(props: Props, ref: ForwardedRef = Props & {ref?: Ref}; +export type MenuProps = Omit< + Props, + "hasChildItems" | "hasTitleTextChild" | "hasDescriptionTextChild" +> & {ref?: Ref}; // forwardRef doesn't support generic parameters, so cast the result to the correct type export default forwardRef(Menu) as (props: MenuProps) => ReactElement; diff --git a/packages/components/menu/src/use-menu-item.ts b/packages/components/menu/src/use-menu-item.ts index 5a4806ce74..4d40050d00 100644 --- a/packages/components/menu/src/use-menu-item.ts +++ b/packages/components/menu/src/use-menu-item.ts @@ -130,8 +130,10 @@ export function useMenuItem(originalProps: UseMenuItemProps ...variantProps, isDisabled, disableAnimation, + hasTitleTextChild: typeof rendered === "string", + hasDescriptionTextChild: typeof description === "string", }), - [objectToDeps(variantProps), isDisabled, disableAnimation], + [objectToDeps(variantProps), isDisabled, disableAnimation, rendered, description], ); const baseStyles = clsx(classNames?.base, className); diff --git a/packages/core/theme/src/components/menu.ts b/packages/core/theme/src/components/menu.ts index b5abf8f83e..2e4fb7bb4b 100644 --- a/packages/core/theme/src/components/menu.ts +++ b/packages/core/theme/src/components/menu.ts @@ -11,7 +11,7 @@ import {dataFocusVisibleClasses} from "../utils"; */ const menu = tv({ slots: { - base: "w-full relative flex flex-col gap-1 p-1", + base: "w-full relative flex flex-col gap-1 p-1 overflow-hidden", list: "w-full flex flex-col gap-0.5 outline-none", emptyContent: [ "h-10", @@ -144,6 +144,17 @@ const menuItem = tv({ base: "data-[hover=true]:transition-colors", }, }, + // If the child isn't a string, the truncate such as `overflow, white-space, text-overflow` css won't be extended to the child, so we remove the truncate class here + hasTitleTextChild: { + true: { + title: "truncate", + }, + }, + hasDescriptionTextChild: { + true: { + description: "truncate", + }, + }, }, defaultVariants: { variant: "solid",