Skip to content

Commit

Permalink
feat: CP support Menu expandIcon (ant-design#47561)
Browse files Browse the repository at this point in the history
* feat: CP support Menu expandIcon

* fix: test case fix

* fix: test case fix

* fix: fix

* fix: fix

* chore: rename

* type: add type

---------

Signed-off-by: lijianan <574980606@qq.com>
  • Loading branch information
li-jia-nan authored and tanzhenyun committed Mar 29, 2024
1 parent e550635 commit 66e09bb
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 35 deletions.
35 changes: 22 additions & 13 deletions components/config-provider/__tests__/style.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import Layout from '../../layout';
import List from '../../list';
import Mentions from '../../mentions';
import Menu from '../../menu';
import type { MenuProps } from '../../menu';
import message from '../../message';
import Modal from '../../modal';
import notification from '../../notification';
Expand Down Expand Up @@ -575,24 +576,32 @@ describe('ConfigProvider support style and className props', () => {
expect(container.querySelector('.ant-list')).toHaveStyle('color: red; font-size: 16px;');
});

it('Should Menu className works', () => {
const menuItems = [
it('Should Menu className & expandIcon works', () => {
const menuItems: MenuProps['items'] = [
{
label: 'Test Label',
label: <span>Test Label</span>,
key: 'test',
children: [
{
label: <span>Test Label children</span>,
key: 'test-children',
},
],
},
];
const { container } = render(
<ConfigProvider
menu={{
className: 'test-class',
}}
>
const App: React.FC<{ expand?: React.ReactNode }> = ({ expand }) => (
<ConfigProvider menu={{ className: 'test-class', expandIcon: expand }}>
<Menu items={menuItems} />
</ConfigProvider>,
);

expect(container.querySelector('.ant-menu')).toHaveClass('test-class');
</ConfigProvider>
);
const { container, rerender } = render(<App />);
expect(container.querySelector<HTMLElement>('.ant-menu')).toHaveClass('test-class');
rerender(<App expand={<span className="test-cp-icon">test-cp-icon</span>} />);
expect(container.querySelector<HTMLSpanElement>('.ant-menu .test-cp-icon')).toBeTruthy();
rerender(<App expand={null} />);
expect(container.querySelector<HTMLElement>('.ant-menu-submenu-arrow')).toBeFalsy();
rerender(<App expand={false} />);
expect(container.querySelector<HTMLElement>('.ant-menu-submenu-arrow')).toBeFalsy();
});

it('Should Menu style works', () => {
Expand Down
5 changes: 4 additions & 1 deletion components/config-provider/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { FlexProps } from '../flex/interface';
import type { FormProps } from '../form/Form';
import type { InputProps } from '../input';
import type { Locale } from '../locale';
import type { MenuProps } from '../menu';
import type { ModalProps } from '../modal';
import type { ArgsProps } from '../notification/interface';
import type { PaginationProps } from '../pagination';
Expand Down Expand Up @@ -85,6 +86,8 @@ export interface ImageConfig extends ComponentStyleConfig {

export type CollapseConfig = ComponentStyleConfig & Pick<CollapseProps, 'expandIcon'>;

export type MenuConfig = ComponentStyleConfig & Pick<MenuProps, 'expandIcon'>;

export type TourConfig = Pick<TourProps, 'closeIcon'>;

export type ModalConfig = ComponentStyleConfig &
Expand Down Expand Up @@ -167,7 +170,7 @@ export interface ConfigConsumerProps {
result?: ComponentStyleConfig;
slider?: ComponentStyleConfig;
breadcrumb?: ComponentStyleConfig;
menu?: ComponentStyleConfig;
menu?: MenuConfig;
checkbox?: ComponentStyleConfig;
descriptions?: ComponentStyleConfig;
empty?: ComponentStyleConfig;
Expand Down
2 changes: 1 addition & 1 deletion components/config-provider/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ const {
| input | Set Input common props | { autoComplete?: string, className?: string, style?: React.CSSProperties } | - | 4.2.0 |
| layout | Set Layout common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| list | Set List common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| menu | Set Menu common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| menu | Set Menu common props | { className?: string, style?: React.CSSProperties, expandIcon?: ReactNode \| props => ReactNode } | - | 5.7.0, expandIcon: 5.15.0 |
| mentions | Set Mentions common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| message | Set Message common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| modal | Set Modal common props | { className?: string, style?: React.CSSProperties, classNames?: [ModalProps\["classNames"\]](/components/modal-cn#api), styles?: [ModalProps\["styles"\]](/components/modal-cn#api), closeIcon?: React.ReactNode } | - | 5.7.0, `classNames` and `styles`: 5.10.0, `closeIcon`: 5.14.0 |
Expand Down
3 changes: 2 additions & 1 deletion components/config-provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import type {
DrawerConfig,
FlexConfig,
ImageConfig,
MenuConfig,
ModalConfig,
NotificationConfig,
PopupOverflow,
Expand Down Expand Up @@ -161,7 +162,7 @@ export interface ConfigProviderProps {
result?: ComponentStyleConfig;
slider?: ComponentStyleConfig;
breadcrumb?: ComponentStyleConfig;
menu?: ComponentStyleConfig;
menu?: MenuConfig;
checkbox?: ComponentStyleConfig;
descriptions?: ComponentStyleConfig;
empty?: ComponentStyleConfig;
Expand Down
2 changes: 1 addition & 1 deletion components/config-provider/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ const {
| input | 设置 Input 组件的通用属性 | { autoComplete?: string, className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| layout | 设置 Layout 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| list | 设置 List 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| menu | 设置 Menu 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| menu | 设置 Menu 组件的通用属性 | { className?: string, style?: React.CSSProperties, expandIcon?: ReactNode \| props => ReactNode } | - | 5.7.0, expandIcon: 5.15.0 |
| mentions | 设置 Mentions 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| message | 设置 Message 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| modal | 设置 Modal 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [ModalProps\["classNames"\]](/components/modal-cn#api), styles?: [ModalProps\["styles"\]](/components/modal-cn#api), closeIcon?: React.ReactNode } | - | 5.7.0, `classNames``styles`: 5.10.0, `closeIcon`: 5.14.0 |
Expand Down
9 changes: 5 additions & 4 deletions components/menu/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import React, { useMemo, useState } from 'react';
import {
AppstoreOutlined,
InboxOutlined,
MailOutlined,
PieChartOutlined,
UserOutlined,
} from '@ant-design/icons';
import React, { useMemo, useState } from 'react';

import type { MenuProps, MenuRef } from '..';
import Menu from '..';
import initCollapseMotion from '../../_util/motion';
import { noop } from '../../_util/warning';
import { TriggerMockContext } from '../../../tests/shared/demoTestContext';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { act, fireEvent, render } from '../../../tests/utils';
import initCollapseMotion from '../../_util/motion';
import { noop } from '../../_util/warning';
import Layout from '../../layout';
import OverrideContext from '../OverrideContext';

Expand Down Expand Up @@ -1126,7 +1127,7 @@ describe('Menu', () => {
});

it('hide expand icon when pass null or false into expandIcon', () => {
const App = ({ expand }: { expand?: React.ReactNode }) => (
const App: React.FC<{ expand?: React.ReactNode }> = ({ expand }) => (
<Menu
expandIcon={expand}
items={[
Expand Down
34 changes: 20 additions & 14 deletions components/menu/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import MenuContext from './MenuContext';
import OverrideContext from './OverrideContext';
import useStyle from './style';

function isEmptyIcon(icon?: React.ReactNode) {
return icon === null || icon === false;
}

export interface MenuProps extends Omit<RcMenuProps, 'items'> {
theme?: MenuTheme;
inlineIndent?: number;
Expand Down Expand Up @@ -114,7 +118,7 @@ const InternalMenu = forwardRef<RcMenuRef, InternalMenuProps>((props, ref) => {
return inlineCollapsed;
}, [inlineCollapsed, siderCollapsed]);

const defaultMotions = {
const defaultMotions: MenuProps['defaultMotions'] = {
horizontal: { motionName: `${rootPrefixCls}-slide-up` },
inline: initCollapseMotion(rootPrefixCls),
other: { motionName: `${rootPrefixCls}-zoom-big` },
Expand All @@ -125,23 +129,25 @@ const InternalMenu = forwardRef<RcMenuRef, InternalMenuProps>((props, ref) => {
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, rootCls, !override);
const menuClassName = classNames(`${prefixCls}-${theme}`, menu?.className, className);

// ====================== Expand Icon ========================
let mergedExpandIcon: MenuProps['expandIcon'];
if (typeof expandIcon === 'function') {
mergedExpandIcon = expandIcon;
} else if (expandIcon === null || expandIcon === false) {
mergedExpandIcon = null;
} else if (overrideObj.expandIcon === null || overrideObj.expandIcon === false) {
mergedExpandIcon = null;
} else {
const beClone: React.ReactNode = (expandIcon ?? overrideObj.expandIcon) as React.ReactNode;
mergedExpandIcon = cloneElement(beClone, {
// ====================== ExpandIcon ========================
const mergedExpandIcon = React.useMemo<MenuProps['expandIcon']>(() => {
if (typeof expandIcon === 'function' || isEmptyIcon(expandIcon)) {
return expandIcon || null;
}
if (typeof overrideObj.expandIcon === 'function' || isEmptyIcon(overrideObj.expandIcon)) {
return overrideObj.expandIcon || null;
}
if (typeof menu?.expandIcon === 'function' || isEmptyIcon(menu?.expandIcon)) {
return menu?.expandIcon || null;
}
const mergedIcon = expandIcon ?? overrideObj?.expandIcon ?? menu?.expandIcon;
return cloneElement(mergedIcon, {
className: classNames(
`${prefixCls}-submenu-expand-icon`,
React.isValidElement(beClone) ? beClone.props?.className : '',
React.isValidElement(mergedIcon) ? mergedIcon.props?.className : undefined,
),
});
}
}, [expandIcon, overrideObj?.expandIcon, menu?.expandIcon, prefixCls]);

// ======================== Context ==========================
const contextValue = React.useMemo<MenuContextProps>(
Expand Down

0 comments on commit 66e09bb

Please sign in to comment.