diff --git a/packages/core/src/components/Menu/MenuItem/MenuItem.module.scss b/packages/core/src/components/Menu/MenuItem/MenuItem.module.scss index def371db39..417d86e18c 100644 --- a/packages/core/src/components/Menu/MenuItem/MenuItem.module.scss +++ b/packages/core/src/components/Menu/MenuItem/MenuItem.module.scss @@ -15,17 +15,6 @@ outline: none; } -.iconWrapper { - margin-right: var(--spacing-small); - display: flex; - align-items: center; - justify-content: center; - - .icon { - color: var(--icon-color); - } -} - .item.splitMenuItem { padding: 0 0 0 var(--spacing-small); } @@ -35,11 +24,6 @@ color: var(--disabled-text-color); } -.item.disabled .icon { - cursor: not-allowed; - color: var(--disabled-text-color); -} - .item:not(.disabled).focused { background-color: var(--primary-background-hover-color); } @@ -57,10 +41,6 @@ border-radius: var(--border-radius-small); } -.item:not(.disabled).selected .iconWrapper .icon { - color: var(--primary-color); -} - .title { white-space: nowrap; overflow: hidden; diff --git a/packages/core/src/components/Menu/MenuItem/MenuItem.tsx b/packages/core/src/components/Menu/MenuItem/MenuItem.tsx index f8f9249831..dc45d6486e 100644 --- a/packages/core/src/components/Menu/MenuItem/MenuItem.tsx +++ b/packages/core/src/components/Menu/MenuItem/MenuItem.tsx @@ -11,7 +11,6 @@ import React, { useRef } from "react"; import cx from "classnames"; -import { isFunction } from "lodash-es"; import { ComponentDefaultTestId, getTestId } from "../../../tests/test-ids-utils"; import { DialogPosition } from "../../../constants/positions"; import Text from "../../Text/Text"; @@ -31,6 +30,7 @@ import { CloseMenuOption, MenuChild } from "../Menu/MenuConstants"; import Label from "../../Label/Label"; import styles from "./MenuItem.module.scss"; import useIsMouseEnter from "../../../hooks/useIsMouseEnter"; +import MenuItemIcon from "./components/MenuItemIcon/MenuItemIcon"; import MenuItemSubMenuIcon from "./components/MenuItemSubMenuIcon/MenuItemSubMenuIcon"; export interface MenuItemProps extends VibeComponentProps { @@ -237,43 +237,6 @@ const MenuItem: VibeComponent & { // if "title" is a component ariaLabel is mandatory const iconLabel = ariaLabel ?? (title as string); - const [iconWrapperStyle, iconStyle] = useMemo(() => { - return iconBackgroundColor - ? [ - { - backgroundColor: iconBackgroundColor, - borderRadius: "4px", - opacity: disabled ? 0.4 : 1 - }, - { color: "var(--text-color-on-primary)" } - ] - : []; - }, [iconBackgroundColor, disabled]); - - const renderMenuItemIconIfNeeded = () => { - if (!icon) return null; - - let finalIconType = iconType; - if (!finalIconType) { - finalIconType = isFunction(icon) ? Icon.type.SVG : Icon.type.ICON_FONT; - } - - return ( -
- -
- ); - }; - const a11yProps = useMemo(() => { if (!children) return {}; return { @@ -314,7 +277,17 @@ const MenuItem: VibeComponent & { onMouseEnter={onMouseEnter} tabIndex={TAB_INDEX_FOCUS_WITH_JS_ONLY} > - {renderMenuItemIconIfNeeded()} + {Boolean(icon) && ( + + )}
( + + + +); + +export default MenuItemIcon; diff --git a/packages/core/src/components/Menu/MenuItem/components/MenuItemIcon/MenuItemIcon.types.ts b/packages/core/src/components/Menu/MenuItem/components/MenuItemIcon/MenuItemIcon.types.ts new file mode 100644 index 0000000000..c48fdb0768 --- /dev/null +++ b/packages/core/src/components/Menu/MenuItem/components/MenuItemIcon/MenuItemIcon.types.ts @@ -0,0 +1,33 @@ +import { SubIcon } from "../../../../../types"; +import { IconType } from "../../../../Icon/IconConstants"; + +export interface MenuItemIconProps { + /** + * Icon to be displayed. Can be a string or an icon component. + */ + icon?: SubIcon; + /** + * Icon type to be used. + */ + type?: IconType; + /** + * Label for the icon, used for accessibility. + */ + label?: string; + /** + * Indicates whether the icon is disabled. Disabled icons appear faded and do not respond to user interactions. + */ + disabled?: boolean; + /** + * Indicates whether the icon is selected. Selected icons have a different visual style. + */ + selected?: boolean; + /** + * Background color for the icon wrapper. + */ + backgroundColor?: string; + /** + * Additional class name for the icon wrapper. + */ + wrapperClassName?: string; +} diff --git a/packages/core/src/components/Menu/MenuItem/components/MenuItemIcon/__tests__/MenuItemIcon.jest.tsx b/packages/core/src/components/Menu/MenuItem/components/MenuItemIcon/__tests__/MenuItemIcon.jest.tsx new file mode 100644 index 0000000000..bf78dde516 --- /dev/null +++ b/packages/core/src/components/Menu/MenuItem/components/MenuItemIcon/__tests__/MenuItemIcon.jest.tsx @@ -0,0 +1,42 @@ +import { render, screen } from "@testing-library/react"; +import "@testing-library/jest-dom"; +import MenuItemIcon from "../MenuItemIcon"; +import { MenuItemIconProps } from "../MenuItemIcon.types"; + +function renderMenuItemIcon(props: Partial = {}) { + return render(); +} + +describe("MenuItemIcon", () => { + it("should render the icon correctly", () => { + const { getByLabelText } = renderMenuItemIcon(); + expect(getByLabelText("Test Icon")).toBeInTheDocument(); + }); + + it("should apply the disabled style if the disabled prop is true", () => { + const { getByLabelText } = renderMenuItemIcon({ disabled: true }); + const iconWrapper = getByLabelText("Test Icon").parentNode; + expect(iconWrapper).toHaveClass("disabled"); + }); + + it("should apply the selected style if the selected prop is true and not disabled", () => { + const { getByLabelText } = renderMenuItemIcon({ selected: true }); + screen.logTestingPlaygroundURL(); + expect(getByLabelText("Test Icon")).toHaveClass("selected"); + }); + + it("should not apply the selected style if the icon is disabled", () => { + const { getByLabelText } = renderMenuItemIcon({ + selected: true, + disabled: true + }); + expect(getByLabelText("Test Icon")).not.toHaveClass("selected"); + }); + + it("should set the background color if backgroundColor prop is provided", () => { + const { getByLabelText } = renderMenuItemIcon({ backgroundColor: "red" }); + const iconWrapper = getByLabelText("Test Icon").parentNode; + expect(iconWrapper).toHaveClass("withBackgroundColor"); + expect(iconWrapper).toHaveStyle("background-color: red"); + }); +});