Skip to content

Commit

Permalink
refactor: Use rc-trigger v4 (#291)
Browse files Browse the repository at this point in the history
* remove shim

* clean up

* fix trigger logic
  • Loading branch information
zombieJ committed Oct 14, 2019
1 parent 2f3cf12 commit 70ab693
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 84 deletions.
3 changes: 1 addition & 2 deletions package.json
Expand Up @@ -48,9 +48,8 @@
"classnames": "2.x",
"dom-scroll-into-view": "1.x",
"mini-store": "^2.0.0",
"mutationobserver-shim": "^0.3.2",
"rc-animate": "^2.10.1",
"rc-trigger": "^2.3.0",
"rc-trigger": "^4.0.0-alpha.4",
"rc-util": "^4.13.0",
"resize-observer-polyfill": "^1.5.0",
"shallowequal": "^1.1.0"
Expand Down
12 changes: 0 additions & 12 deletions src/DOMWrap.tsx
Expand Up @@ -5,21 +5,9 @@ import SubMenu from './SubMenu';
import { getWidth, setStyle, menuAllProps } from './util';
import { MenuMode } from './interface';

const canUseDOM = !!(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
);

const MENUITEM_OVERFLOWED_CLASSNAME = 'menuitem-overflowed';
const FLOAT_PRECISION_ADJUST = 0.5;

// Fix ssr
if (canUseDOM) {
// eslint-disable-next-line global-require
require('mutationobserver-shim');
}

interface DOMWrapProps {
className?: string;
children?: React.ReactElement[];
Expand Down
46 changes: 31 additions & 15 deletions src/SubMenu.tsx
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import ReactDOM from 'react-dom';
import Trigger from 'rc-trigger';
import KeyCode from 'rc-util/lib/KeyCode';
// import Animate from 'rc-animate';
import CSSMotion from 'rc-animate/lib/CSSMotion';
import classNames from 'classnames';
import { connect } from 'mini-store';
Expand Down Expand Up @@ -388,9 +387,9 @@ export class SubMenu extends React.Component<SubMenuProps> {
this.subMenuTitle = subMenuTitle;
};

renderChildren(children: React.ReactNode) {
getBaseProps = (): SubPopupMenuProps => {
const { props } = this;
const baseProps: SubPopupMenuProps = {
return {
mode: props.mode === 'horizontal' ? 'vertical' : props.mode,
visible: this.props.isOpen,
level: props.level + 1,
Expand Down Expand Up @@ -421,8 +420,31 @@ export class SubMenu extends React.Component<SubMenuProps> {
itemIcon: props.itemIcon,
expandIcon: props.expandIcon,
};
};

getMotion = (mode: MenuMode, visible: boolean) => {
const { haveRendered } = this;
const { motion, rootPrefixCls } = this.props;

// don't show transition on first rendering (no animation for opened menu)
// show appear transition if it's not visible (not sure why)
// show appear transition if it's not inline mode
const mergedMotion: MotionType = {
...motion,
leavedClassName: `${rootPrefixCls}-hidden`,
removeOnLeave: false,
motionAppear: haveRendered || !visible || mode !== 'inline',
};

return mergedMotion;
};

renderChildren(children: React.ReactNode) {
const baseProps = this.getBaseProps();

// [Legacy] getMotion must be called before `haveRendered`
const mergedMotion = this.getMotion(baseProps.mode, baseProps.visible);

this.haveRendered = true;

this.haveOpened =
Expand All @@ -432,18 +454,6 @@ export class SubMenu extends React.Component<SubMenuProps> {
return <div />;
}

// ================== Motion ==================
// don't show transition on first rendering (no animation for opened menu)
// show appear transition if it's not visible (not sure why)
// show appear transition if it's not inline mode
const mergedMotion: MotionType = {
...props.motion,
leavedClassName: `${props.rootPrefixCls}-hidden`,
removeOnLeave: false,
motionAppear:
haveRendered || !baseProps.visible || baseProps.mode !== 'inline',
};

return (
<CSSMotion visible={baseProps.visible} {...mergedMotion}>
{({ className, style }) => {
Expand Down Expand Up @@ -550,6 +560,11 @@ export class SubMenu extends React.Component<SubMenuProps> {
{icon || <i className={`${prefixCls}-arrow`} />}
</div>
);

// [Legacy] `getMotion` should call before `renderChildren`
const baseProps = this.getBaseProps();
const motion = this.getMotion(baseProps.mode, baseProps.visible);

const children = this.renderChildren(props.children);

const getPopupContainer = props.parentMenu.isRootMenu
Expand Down Expand Up @@ -594,6 +609,7 @@ export class SubMenu extends React.Component<SubMenuProps> {
mouseLeaveDelay={subMenuCloseDelay}
onPopupVisibleChange={this.onPopupVisibleChange}
forceRender={forceSubMenuRender}
popupMotion={motion}
>
{title}
</Trigger>
Expand Down
49 changes: 7 additions & 42 deletions src/interface.ts
@@ -1,3 +1,9 @@
import {
AnimationType,
TransitionNameType,
MotionType,
} from 'rc-trigger/lib/interface';

export type RenderIconType =
| React.ReactNode
| ((props: any) => React.ReactNode);
Expand Down Expand Up @@ -60,45 +66,4 @@ export type BuiltinPlacements = Record<string, any>;
export type TriggerSubMenuAction = 'click' | 'hover';

// =================================== Motion ===================================
export type AnimationType = string | Record<string, any>;

export type TransitionNameType = string;

/**
* Follow Motion definition is copied from `rc-trigger@latest`.
* These code can be removed when `rc-trigger` updated.
*/
// TODO: Use define by `rc-trigger@latest`
type MotionStatus = 'none' | 'appear' | 'enter' | 'leave';

type MotionActiveStatus = 'appear-active' | 'enter-active' | 'leave-active';

type MotionNameObject = {
[key in MotionStatus | MotionActiveStatus]?: string;
};

type MotionEventHandler = (
element: HTMLElement,
event:
| React.TransitionEvent<HTMLElement>
| React.AnimationEvent<HTMLElement>
| undefined,
) => React.CSSProperties | false | null | undefined | void;
export interface MotionType {
motionName?: string | MotionNameObject;
motionAppear?: boolean;
motionEnter?: boolean;
motionLeave?: boolean;
motionLeaveImmediately?: boolean; // Trigger leave motion immediately
removeOnLeave?: boolean;
leavedClassName?: string;
onAppearStart?: MotionEventHandler;
onAppearActive?: MotionEventHandler;
onAppearEnd?: MotionEventHandler;
onEnterStart?: MotionEventHandler;
onEnterActive?: MotionEventHandler;
onEnterEnd?: MotionEventHandler;
onLeaveStart?: MotionEventHandler;
onLeaveActive?: MotionEventHandler;
onLeaveEnd?: MotionEventHandler;
}
export { AnimationType, TransitionNameType, MotionType };
22 changes: 13 additions & 9 deletions tests/Menu.spec.js
@@ -1,13 +1,10 @@
jest.mock('mutationobserver-shim');

const mockedUtil = require('../src/util');

/* eslint-disable no-undef, react/no-multi-comp */
/* eslint-disable no-undef, react/no-multi-comp, react/jsx-curly-brace-presence */
import React from 'react';
import { render, mount } from 'enzyme';
import { renderToJson } from 'enzyme-to-json';
import KeyCode from 'rc-util/lib/KeyCode';
import Menu, { MenuItem, MenuItemGroup, SubMenu, Divider } from '../src';
import * as mockedUtil from '../src/util';

describe('Menu', () => {
describe('should render', () => {
Expand Down Expand Up @@ -76,7 +73,7 @@ describe('Menu', () => {
);
}

it(`renders menu correctly`, () => {
it('renders menu correctly', () => {
const wrapper = render(createMenu());
expect(renderToJson(wrapper)).toMatchSnapshot();
});
Expand Down Expand Up @@ -477,7 +474,9 @@ describe('Menu', () => {
const widths = [...liWidths, indicatorWidth, availableWidth];
let i = 0;
mockedUtil.getWidth = () => {
return widths[i++];
const id = i;
i += 1;
return widths[id];
};
wrapper = mount(createMenu());

Expand Down Expand Up @@ -535,7 +534,9 @@ describe('Menu', () => {
const widths = [...liWidths, indicatorWidth, availableWidth];
let i = 0;
mockedUtil.getWidth = () => {
return widths[i++];
const id = i;
i += 1;
return widths[id];
};
wrapper = mount(createMenu());

Expand Down Expand Up @@ -589,7 +590,9 @@ describe('Menu', () => {
let i = 0;

mockedUtil.getWidth = () => {
return widths[i++];
const id = i;
i += 1;
return widths[id];
};

wrapper = mount(createMenu());
Expand Down Expand Up @@ -626,3 +629,4 @@ describe('Menu', () => {
});
});
});
/* eslint-enable */
4 changes: 0 additions & 4 deletions tests/__mocks__/mutationobserver-shim.js

This file was deleted.

1 comment on commit 70ab693

@vercel
Copy link

@vercel vercel bot commented on 70ab693 Oct 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.