mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 12:39:49 +08:00
refactor: Use CSSMotion (#19205)
* refactor: Use CSSMotion * fix lint * update rc-menu deps * fix test case * clean up * more test case * fix lint
This commit is contained in:
parent
8bb4613bff
commit
e75fa039ef
@ -8018,7 +8018,7 @@ exports[`ConfigProvider components Menu configProvider 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="config-menu config-menu-sub config-menu-inline"
|
||||
class="config-menu config-menu-sub config-menu-inline"
|
||||
id="bamboo$Menu"
|
||||
role="menu"
|
||||
>
|
||||
@ -8071,7 +8071,7 @@ exports[`ConfigProvider components Menu normal 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
id="bamboo$Menu"
|
||||
role="menu"
|
||||
>
|
||||
@ -8124,7 +8124,7 @@ exports[`ConfigProvider components Menu prefixCls 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="prefix-Menu prefix-Menu-sub prefix-Menu-inline"
|
||||
class="prefix-Menu prefix-Menu-sub prefix-Menu-inline"
|
||||
id="bamboo$Menu"
|
||||
role="menu"
|
||||
>
|
||||
|
@ -1624,7 +1624,7 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
id="sub1$Menu"
|
||||
role="menu"
|
||||
>
|
||||
@ -1914,7 +1914,7 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
id="sub1$Menu"
|
||||
role="menu"
|
||||
>
|
||||
|
@ -245,7 +245,7 @@ exports[`renders ./components/menu/demo/inline.md correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
id="sub1$Menu"
|
||||
role="menu"
|
||||
>
|
||||
@ -547,7 +547,7 @@ exports[`renders ./components/menu/demo/inline-collapsed.md correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
id="sub1$Menu"
|
||||
role="menu"
|
||||
>
|
||||
@ -671,7 +671,7 @@ exports[`renders ./components/menu/demo/sider-current.md correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
id="sub1$Menu"
|
||||
role="menu"
|
||||
>
|
||||
@ -915,7 +915,7 @@ exports[`renders ./components/menu/demo/switch-mode.md correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
id="sub1$Menu"
|
||||
role="menu"
|
||||
>
|
||||
@ -1059,7 +1059,7 @@ exports[`renders ./components/menu/demo/theme.md correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
class="ant-menu ant-menu-sub ant-menu-inline"
|
||||
id="sub1$Menu"
|
||||
role="menu"
|
||||
>
|
||||
|
@ -3,8 +3,8 @@ import { mount } from 'enzyme';
|
||||
import Menu from '..';
|
||||
import Icon from '../../icon';
|
||||
import Layout from '../../layout';
|
||||
import raf from '../../_util/raf';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
|
||||
jest.mock('mutationobserver-shim', () => {
|
||||
global.MutationObserver = function MutationObserver() {
|
||||
@ -83,10 +83,6 @@ describe('Menu', () => {
|
||||
.at(0)
|
||||
.hasClass('ant-menu-hidden'),
|
||||
).not.toBe(true);
|
||||
|
||||
const rafCount = Object.keys(raf.ids).length;
|
||||
wrapper.unmount();
|
||||
expect(Object.keys(raf.ids).length).toBe(rafCount - 1);
|
||||
});
|
||||
|
||||
it('should accept defaultOpenKeys in mode vertical', () => {
|
||||
@ -569,15 +565,49 @@ describe('Menu', () => {
|
||||
expect(onMouseEnter).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('get correct animation type when switched from inline', () => {
|
||||
const wrapper = mount(<Menu mode="inline" />);
|
||||
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(<Menu mode="inline" />);
|
||||
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(<Menu openAnimation={{}} />);
|
||||
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(<Menu motion={motion} />);
|
||||
expect(
|
||||
wrapper
|
||||
.find('InternalMenu')
|
||||
.instance()
|
||||
.getOpenMotionProps(''),
|
||||
).toEqual({ motion });
|
||||
});
|
||||
|
||||
it('legacy openTransitionName', () => {
|
||||
const wrapper = mount(<Menu openTransitionName="legacy" />);
|
||||
expect(
|
||||
wrapper
|
||||
.find('InternalMenu')
|
||||
.instance()
|
||||
.getOpenMotionProps(''),
|
||||
).toEqual({ openTransitionName: 'legacy' });
|
||||
});
|
||||
});
|
||||
|
||||
it('MenuItem should not render Tooltip when inlineCollapsed is false', () => {
|
||||
|
@ -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<InternalMenuProps, MenuState> {
|
||||
@ -150,21 +150,9 @@ class InternalMenu extends React.Component<InternalMenuProps, MenuState> {
|
||||
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<InternalMenuProps, MenuState> {
|
||||
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 };
|
||||
}
|
||||
return menuOpenAnimation;
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
// 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<InternalMenuProps, MenuState> {
|
||||
}
|
||||
|
||||
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<InternalMenuProps, MenuState> {
|
||||
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
|
||||
|
@ -98,8 +98,8 @@ class FilterMenu<T> extends React.Component<FilterMenuProps<T>, 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<T> extends React.Component<FilterMenuProps<T>, 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;
|
||||
|
@ -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<T> {
|
||||
locale: TableLocale;
|
||||
selectedKeys: string[];
|
||||
column: ColumnProps<T>;
|
||||
confirmFilter: (column: ColumnProps<T>, selectedKeys: string[]) => any;
|
||||
confirmFilter: (column: ColumnProps<T>, selectedKeys: React.Key[]) => any;
|
||||
prefixCls: string;
|
||||
dropdownPrefixCls: string;
|
||||
getPopupContainer?: GetPopupContainer;
|
||||
}
|
||||
|
||||
export interface FilterMenuState<T> {
|
||||
selectedKeys: string[];
|
||||
selectedKeys: React.Key[];
|
||||
valueKeys: { [name: string]: string };
|
||||
keyPathOfSelectedItem: { [key: string]: string };
|
||||
keyPathOfSelectedItem: { [key: string]: React.Key[] };
|
||||
visible?: boolean;
|
||||
prevProps: FilterMenuProps<T>;
|
||||
}
|
||||
|
@ -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",
|
||||
|
2
typings/custom-typings.d.ts
vendored
2
typings/custom-typings.d.ts
vendored
@ -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*';
|
||||
|
Loading…
Reference in New Issue
Block a user