diff --git a/components/config-provider/__tests__/__snapshots__/components.test.js.snap b/components/config-provider/__tests__/__snapshots__/components.test.js.snap
index c54ac067b349..aa65056d65b6 100644
--- a/components/config-provider/__tests__/__snapshots__/components.test.js.snap
+++ b/components/config-provider/__tests__/__snapshots__/components.test.js.snap
@@ -8018,7 +8018,7 @@ exports[`ConfigProvider components Menu configProvider 1`] = `
/>
);
- wrapper.setProps({ mode: 'horizontal' });
- expect(
- wrapper
- .find('InternalMenu')
- .instance()
- .getMenuOpenAnimation(''),
- ).toBe('');
+ describe('motion', () => {
+ it('get correct animation type when switched from inline', () => {
+ const wrapper = mount();
+ wrapper.setProps({ mode: 'horizontal' });
+ expect(
+ wrapper
+ .find('InternalMenu')
+ .instance()
+ .getOpenMotionProps(''),
+ ).toEqual({ motion: { motionName: '' } });
+ });
+
+ it('warning if use `openAnimation` as object', () => {
+ resetWarned();
+
+ const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
+ mount();
+ expect(warnSpy).toHaveBeenCalledWith(
+ 'Warning: [antd: Menu] `openAnimation` do not support object. Please use `motion` instead.',
+ );
+ warnSpy.mockRestore();
+ });
+
+ it('motion object', () => {
+ const motion = { test: true };
+ const wrapper = mount();
+ expect(
+ wrapper
+ .find('InternalMenu')
+ .instance()
+ .getOpenMotionProps(''),
+ ).toEqual({ motion });
+ });
+
+ it('legacy openTransitionName', () => {
+ const wrapper = mount();
+ expect(
+ wrapper
+ .find('InternalMenu')
+ .instance()
+ .getOpenMotionProps(''),
+ ).toEqual({ openTransitionName: 'legacy' });
+ });
});
it('MenuItem should not render Tooltip when inlineCollapsed is false', () => {
diff --git a/components/menu/index.tsx b/components/menu/index.tsx
index fb51b3a04c8f..24ec27eed190 100644
--- a/components/menu/index.tsx
+++ b/components/menu/index.tsx
@@ -6,10 +6,10 @@ import { polyfill } from 'react-lifecycles-compat';
import SubMenu from './SubMenu';
import Item from './MenuItem';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
-import animation from '../_util/openAnimation';
import warning from '../_util/warning';
import { SiderContext, SiderContextProps } from '../layout/Sider';
import raf from '../_util/raf';
+import collapseMotion from '../_util/motion';
import MenuContext, { MenuTheme } from './MenuContext';
export interface SelectParam {
@@ -43,8 +43,9 @@ export interface MenuProps {
onDeselect?: (param: SelectParam) => void;
onClick?: (param: ClickParam) => void;
style?: React.CSSProperties;
- openAnimation?: string | Object;
- openTransitionName?: string | Object;
+ openAnimation?: string;
+ openTransitionName?: string;
+ motion?: Object;
className?: string;
prefixCls?: string;
multiple?: boolean;
@@ -69,7 +70,6 @@ export interface MenuState {
switchingModeFromInline: boolean;
inlineOpenKeys: string[];
prevProps: InternalMenuProps;
- mounted: boolean;
}
class InternalMenu extends React.Component {
@@ -150,21 +150,9 @@ class InternalMenu extends React.Component {
switchingModeFromInline: false,
inlineOpenKeys: [],
prevProps: props,
- mounted: false,
};
}
- // [Legacy] Origin code can render full defaultOpenKeys is caused by `rc-animate` bug.
- // We have to workaround this to prevent animation on first render.
- // https://github.com/ant-design/ant-design/issues/15966
- componentDidMount() {
- this.mountRafId = raf(() => {
- this.setState({
- mounted: true,
- });
- }, 10);
- }
-
componentWillUnmount() {
raf.cancel(this.mountRafId);
}
@@ -192,21 +180,45 @@ class InternalMenu extends React.Component {
return inlineCollapsed;
}
- getMenuOpenAnimation(menuMode: MenuMode) {
- const { openAnimation, openTransitionName } = this.props;
- let menuOpenAnimation = openAnimation || openTransitionName;
- if (openAnimation === undefined && openTransitionName === undefined) {
- if (menuMode === 'horizontal') {
- menuOpenAnimation = 'slide-up';
- } else if (menuMode === 'inline') {
- menuOpenAnimation = animation;
- } else {
- // When mode switch from inline
- // submenu should hide without animation
- menuOpenAnimation = this.state.switchingModeFromInline ? '' : 'zoom-big';
- }
+ getOpenMotionProps(
+ menuMode: MenuMode,
+ ): { openTransitionName?: any; openAnimation?: any; motion?: Object } {
+ const { openTransitionName, openAnimation, motion } = this.props;
+
+ // Provides by user
+ if (motion) {
+ return { motion };
+ }
+
+ if (openAnimation) {
+ warning(
+ typeof openAnimation === 'string',
+ 'Menu',
+ '`openAnimation` do not support object. Please use `motion` instead.',
+ );
+ return { openAnimation };
+ }
+
+ if (openTransitionName) {
+ return { openTransitionName };
+ }
+
+ // Default logic
+ if (menuMode === 'horizontal') {
+ return { motion: { motionName: 'slide-up' } };
+ }
+
+ if (menuMode === 'inline') {
+ return { motion: collapseMotion };
}
- return menuOpenAnimation;
+
+ // When mode switch from inline
+ // submenu should hide without animation
+ return {
+ motion: {
+ motionName: this.state.switchingModeFromInline ? '' : 'zoom-big',
+ },
+ };
}
// Restore vertical mode when menu is collapsed responsively when mounted
@@ -270,11 +282,10 @@ class InternalMenu extends React.Component {
}
renderMenu = ({ getPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
- const { mounted } = this.state;
const { prefixCls: customizePrefixCls, className, theme, collapsedWidth } = this.props;
const passProps = omit(this.props, ['collapsedWidth', 'siderCollapsed']);
const menuMode = this.getRealMenuMode();
- const menuOpenAnimation = this.getMenuOpenAnimation(menuMode!);
+ const menuOpenMotion = this.getOpenMotionProps(menuMode!);
const prefixCls = getPrefixCls('menu', customizePrefixCls);
const menuClassName = classNames(className, `${prefixCls}-${theme}`, {
@@ -286,14 +297,14 @@ class InternalMenu extends React.Component {
onOpenChange: this.handleOpenChange,
className: menuClassName,
mode: menuMode,
+
+ // Motion
+ ...menuOpenMotion,
};
if (menuMode !== 'inline') {
// closing vertical popup submenu after click it
menuProps.onClick = this.handleClick;
- menuProps.openTransitionName = mounted ? menuOpenAnimation : '';
- } else {
- menuProps.openAnimation = mounted ? menuOpenAnimation : {};
}
// https://github.com/ant-design/ant-design/issues/8587
diff --git a/components/table/filterDropdown.tsx b/components/table/filterDropdown.tsx
index 472373d707df..8dcd55c01fd6 100755
--- a/components/table/filterDropdown.tsx
+++ b/components/table/filterDropdown.tsx
@@ -98,8 +98,8 @@ class FilterMenu extends React.Component, FilterMenuState<
}
};
- setSelectedKeys = ({ selectedKeys }: { selectedKeys: string[] }) => {
- this.setState({ selectedKeys });
+ setSelectedKeys = ({ selectedKeys }: { selectedKeys?: React.Key[] }) => {
+ this.setState({ selectedKeys: selectedKeys! });
};
setVisible(visible: boolean) {
@@ -138,7 +138,7 @@ class FilterMenu extends React.Component, FilterMenuState<
}
};
- handleMenuItemClick = (info: { keyPath: string; key: string }) => {
+ handleMenuItemClick = (info: { keyPath: React.Key[]; key: React.Key }) => {
const { selectedKeys } = this.state;
if (!info.keyPath || info.keyPath.length <= 1) {
return;
diff --git a/components/table/interface.tsx b/components/table/interface.tsx
index 7dc20e4822e2..9a92511f27ed 100644
--- a/components/table/interface.tsx
+++ b/components/table/interface.tsx
@@ -18,7 +18,7 @@ export type ColumnFilterItem = {
export interface FilterDropdownProps {
prefixCls?: string;
setSelectedKeys?: (selectedKeys: string[]) => void;
- selectedKeys?: string[];
+ selectedKeys?: React.Key[];
confirm?: () => void;
clearFilters?: (selectedKeys: string[]) => void;
filters?: ColumnFilterItem[];
@@ -285,16 +285,16 @@ export interface FilterMenuProps {
locale: TableLocale;
selectedKeys: string[];
column: ColumnProps;
- confirmFilter: (column: ColumnProps, selectedKeys: string[]) => any;
+ confirmFilter: (column: ColumnProps, selectedKeys: React.Key[]) => any;
prefixCls: string;
dropdownPrefixCls: string;
getPopupContainer?: GetPopupContainer;
}
export interface FilterMenuState {
- selectedKeys: string[];
+ selectedKeys: React.Key[];
valueKeys: { [name: string]: string };
- keyPathOfSelectedItem: { [key: string]: string };
+ keyPathOfSelectedItem: { [key: string]: React.Key[] };
visible?: boolean;
prevProps: FilterMenuProps;
}
diff --git a/package.json b/package.json
index 979f3ad7dd6c..e1cf14cb3272 100644
--- a/package.json
+++ b/package.json
@@ -115,7 +115,7 @@
"rc-form": "^2.4.5",
"rc-input-number": "~4.5.0",
"rc-mentions": "~0.4.0",
- "rc-menu": "~7.4.23",
+ "rc-menu": "~7.5.1",
"rc-notification": "~3.3.1",
"rc-pagination": "~1.20.5",
"rc-progress": "~2.5.0",
diff --git a/typings/custom-typings.d.ts b/typings/custom-typings.d.ts
index 2c4890a49f56..fc2e3f0ee1ec 100644
--- a/typings/custom-typings.d.ts
+++ b/typings/custom-typings.d.ts
@@ -28,8 +28,6 @@ declare module 'rc-editor-mention';
declare module 'rc-progress';
-declare module 'rc-menu';
-
declare module 'rc-drawer';
declare module 'rc-tabs*';