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:
二货机器人 2019-10-14 15:01:16 +08:00 committed by GitHub
parent 8bb4613bff
commit e75fa039ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 69 deletions

View File

@ -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"
>

View File

@ -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"
>

View File

@ -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"
>

View File

@ -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', () => {

View File

@ -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

View File

@ -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;

View File

@ -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>;
}

View File

@ -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",

View File

@ -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*';