diff --git a/components/animate/__docs__/demo/basic/index.tsx b/components/animate/__docs__/demo/basic/index.tsx index 0eee5e4a59..03420dfc59 100644 --- a/components/animate/__docs__/demo/basic/index.tsx +++ b/components/animate/__docs__/demo/basic/index.tsx @@ -2,18 +2,14 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Animate } from '@alifd/next'; -class Demo extends React.Component { - constructor(props: any) { - super(props); - this.state = { visible: true }; - this.handleToggle = this.handleToggle.bind(this); - } +class Demo extends React.Component { + state = { visible: true }; - handleToggle() { + handleToggle = () => { this.setState({ visible: !this.state.visible, }); - } + }; render() { return ( diff --git a/components/animate/__docs__/demo/expand/index.tsx b/components/animate/__docs__/demo/expand/index.tsx index 7e34370166..9641b9658b 100644 --- a/components/animate/__docs__/demo/expand/index.tsx +++ b/components/animate/__docs__/demo/expand/index.tsx @@ -2,55 +2,41 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Animate } from '@alifd/next'; -class Demo extends React.Component { - [key: string]: any; - constructor(props: any) { - super(props); - this.state = { expand: true }; - [ - 'beforeEnter', - 'onEnter', - 'afterEnter', - 'beforeLeave', - 'onLeave', - 'afterLeave', - 'handleToggle', - ].forEach(method => { - this[method] = this[method].bind(this); - }); - } +class Demo extends React.Component { + state = { expand: true }; + height: number | null; - handleToggle() { + handleToggle = () => { this.setState({ expand: !this.state.expand, }); - } + }; - beforeEnter(node: HTMLElement) { + beforeEnter = (node: HTMLElement) => { this.height = node.offsetHeight; node.style.height = '0px'; - } + }; - onEnter(node: HTMLElement) { + onEnter = (node: HTMLElement) => { node.style.height = `${this.height}px`; - } + }; - afterEnter(node: HTMLElement) { + afterEnter = (node: HTMLElement) => { this.height = null; node.style.setProperty('height', null); - } + }; - beforeLeave(node: HTMLElement) { + beforeLeave = (node: HTMLElement) => { node.style.height = `${this.height}px`; - } + }; - onLeave(node: HTMLElement) { + onLeave = (node: HTMLElement) => { node.style.height = '0px'; - } + }; - afterLeave(node: HTMLElement) { + afterLeave = (node: HTMLElement) => { node.style.setProperty('height', null); - } + }; render() { return ( diff --git a/components/animate/__docs__/demo/multiple/index.tsx b/components/animate/__docs__/demo/multiple/index.tsx index 02a005d5e5..8e9bee3c51 100644 --- a/components/animate/__docs__/demo/multiple/index.tsx +++ b/components/animate/__docs__/demo/multiple/index.tsx @@ -2,18 +2,15 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Animate } from '@alifd/next'; -class TodoList extends React.Component { - constructor(props: any) { - super(props); - this.state = { items: ['hello', 'world', 'click', 'me'] }; - } +class TodoList extends React.Component { + state = { items: ['hello', 'world', 'click', 'me'] }; handleAdd() { this.setState({ items: [ ...this.state.items, - // eslint-disable-next-line - prompt('Enter some text'), + // eslint-disable-next-line no-alert + window.prompt('Enter some text'), ], }); } diff --git a/components/animate/__docs__/index.en-us.md b/components/animate/__docs__/index.en-us.md index a46a9482e3..eec2b14336 100644 --- a/components/animate/__docs__/index.en-us.md +++ b/components/animate/__docs__/index.en-us.md @@ -16,51 +16,69 @@ Need to customize animation. ### Animate -| Param | Description | Type | Default Value | Required | -| --------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------------- | -------- | -| animation | The animation className | string \| Partial> | - | | -| animationAppear | Whether to execute animation on the first mount | boolean | true | | -| component | The tag of the wrapper | TransitionGroupProps['component'] | 'div' | | -| singleMode | Whether to only have a single child | boolean | true | | -| beforeAppear | Callback fired before the "entering" status of the first mount is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| onAppear | Callback fired after the "entering" status of the first mount is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| afterAppear | Callback fired after the "entered" status of the first mount is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| beforeEnter | Callback fired before the "entering" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| onEnter | Callback fired after the "entering" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| afterEnter | Callback fired after the "entered" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| beforeLeave | Callback fired before the "exiting" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| onLeave | Callback fired after the leave stage

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| afterLeave | Callback fired after the leave stage

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | +| Param | Description | Type | Default Value | Required | +| --------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------------- | -------- | +| animation | The animation className | string \| Partial> | - | | +| animationAppear | Whether to execute animation on the first mount | boolean | true | | +| component | The tag of the wrapper | React.ElementType | 'div' | | +| singleMode | Whether to only have a single child | boolean | true | | +| beforeAppear | Callback fired before the "entering" status of the first mount is applied | (node: HTMLElement) => void | - | | +| onAppear | Callback fired after the "entering" status of the first mount is applied | (node: HTMLElement) => void | - | | +| afterAppear | Callback fired after the "entered" status of the first mount is applied | (node: HTMLElement) => void | - | | +| beforeEnter | Callback fired before the "entering" status is applied | (node: HTMLElement) => void | - | | +| onEnter | Callback fired after the "entering" status is applied | (node: HTMLElement) => void | - | | +| afterEnter | Callback fired after the "entered" status is applied | (node: HTMLElement) => void | - | | +| beforeLeave | Callback fired before the "exiting" status is applied | (node: HTMLElement) => void | - | | +| onLeave | Callback fired after the leave stage | (node: HTMLElement) => void | - | | +| afterLeave | Callback fired after the leave stage | (node: HTMLElement) => void | - | | ### Animate.Expand -| Param | Description | Type | Default Value | Required | -| ----------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------------- | -------- | -| animation | The animation className | string \| Partial> | - | | -| beforeEnter | Callback fired before the "entering" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| onEnter | Callback fired after the "entering" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| afterEnter | Callback fired after the "entered" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| beforeLeave | Callback fired before the "exiting" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| onLeave | Callback fired after the "exiting" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| afterLeave | Callback fired after the "exited" status is applied

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | +| Param | Description | Type | Default Value | Required | +| ----------- | ------------------------------------------------------ | ----------------------------------------------------------------- | ------------- | -------- | +| animation | The animation className | string \| Partial> | - | | +| beforeEnter | Callback fired before the "entering" status is applied | (node: HTMLElement) => void | - | | +| onEnter | Callback fired after the "entering" status is applied | (node: HTMLElement) => void | - | | +| afterEnter | Callback fired after the "entered" status is applied | (node: HTMLElement) => void | - | | +| beforeLeave | Callback fired before the "exiting" status is applied | (node: HTMLElement) => void | - | | +| onLeave | Callback fired after the "exiting" status is applied | (node: HTMLElement) => void | - | | +| afterLeave | Callback fired after the "exited" status is applied | (node: HTMLElement) => void | - | | ### Animate.OverlayAnimate -| Param | Description | Type | Default Value | Required | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------- | -------- | -| animation | The animation className | string \| false \| Record<'in' \| 'out', string> | - | | -| visible | Show the component; triggers the enter or exit states | boolean | - | | -| children | The element to be wrapped | ReactElement | - | | -| timeout | The duration of the transition. | \| number
\| { appear?: number \| undefined; enter?: number \| undefined; exit?: number \| undefined } | - | | -| style | The style of the child element | CSSProperties | - | | -| mountOnEnter | By default the child component is mounted immediately along with the
parent OverlayAnimate component. If you want to "lazy mount" the component on
the first `in={true}` you can set `mountOnEnter`. After the first enter
OverlayAnimate the component will stay mounted, even on "exited", unless you
also specify `unmountOnExit`. | boolean | false | | -| unmountOnExit | By default the child component stays mounted after it reaches the
'exited' state. Set `unmountOnExit` if you'd prefer to unmount the
component after it finishes exiting. | boolean | false | | -| onEnter | Callback fired before the "entering" status is applied. An extra
parameter `isAppearing` is supplied to indicate if the enter stage is
occurring on the initial mount

**signature**:
**params**:
_node_: Node
_isAppearing_: IsAppearing | (node: HTMLElement, isAppearing: boolean) => void | - | | -| onEntering | Callback fired after the "entering" status is applied. An extra parameter
isAppearing is supplied to indicate if the enter stage is occurring on
the initial mount

**signature**:
**params**:
_node_: Node
_isAppearing_: IsAppearing | (node: HTMLElement, isAppearing: boolean) => void | - | | -| onEntered | Callback fired after the "entered" status is applied. An extra parameter
isAppearing is supplied to indicate if the enter stage is occurring on
the initial mount

**signature**:
**params**:
_node_: Node
_isAppearing_: IsAppearing | (node: HTMLElement, isAppearing: boolean) => void | - | | -| onExit | Callback fired before the "exiting" status is applied.

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| onExiting | Callback fired after the "exiting" status is applied.

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| onExited | Callback fired after the "exited" status is applied.

**signature**:
**params**:
_node_: Node | (node: HTMLElement) => void | - | | -| appear | Normally a component is not transitioned if it is shown when the
`` component mounts. If you want to transition on the first
mount set appear to true, and the component will transition in as soon
as the `` mounts. Note: there are no specific "appear" states.
appear only adds an additional enter transition. | boolean | - | | -| enter | Enable or disable enter transitions. | boolean | - | | -| exit | Enable or disable exit transitions. | boolean | - | | +| Param | Description | Type | Default Value | Required | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | ------------- | -------- | +| animation | The animation className | string \| false \| Record<'in' \| 'out', string> | - | | +| visible | Show the component; triggers the enter or exit states | boolean | - | | +| children | The element to be wrapped | ReactElement | - | yes | +| timeout | The duration of the transition. | \| number
\| { appear?: number \| undefined; enter?: number \| undefined; exit?: number \| undefined } | - | | +| style | The style of the child element | React.CSSProperties | - | | +| mountOnEnter | "lazy mount" the component on the first `in={true}` | boolean | false | | +| unmountOnExit | "lazy unmount" the component on the first `in={false}` | boolean | false | | +| onEnter | Callback fired before the "entering" status is applied.

**signature**:
**params**:
_isAppearing_: IsAppearing | (node: HTMLElement, isAppearing: boolean) => void | - | | +| onEntering | Callback fired after the "entering" status is applied.

**signature**:
**params**:
_isAppearing_: IsAppearing | (node: HTMLElement, isAppearing: boolean) => void | - | | +| onEntered | Callback fired after the "entered" status is applied.

**signature**:
**params**:
_isAppearing_: IsAppearing | (node: HTMLElement, isAppearing: boolean) => void | - | | +| onExit | Callback fired before the "exiting" status is applied. | (node: HTMLElement) => void | - | | +| onExiting | Callback fired after the "exiting" status is applied. | (node: HTMLElement) => void | - | | +| onExited | Callback fired after the "exited" status is applied. | (node: HTMLElement) => void | - | | +| appear | Transition on the first mount. | boolean | - | | +| enter | Enable or disable enter transitions. | boolean | - | | +| exit | Enable or disable exit transitions. | boolean | - | | + +## Animation List + +| In | Out | +| ------------ | ------------- | +| fadeIn | fadeOut | +| fadeInDown | fadeOutDown | +| fadeInLeft | fadeOutLeft | +| fadeInRight | fadeOutRight | +| fadeInUp | fadeOutUp | +| slideInDown | slideOutUp | +| slideInLeft | slideOutLeft | +| slideInRight | slideOutRight | +| slideInUp | slideOutDown | +| zoomIn | zoomOut | +| expandInDown | expandOutUp | +| expandInUp | expandOutDown | +| pulse | | diff --git a/components/animate/__docs__/index.md b/components/animate/__docs__/index.md index 23db8322e8..004280fa11 100644 --- a/components/animate/__docs__/index.md +++ b/components/animate/__docs__/index.md @@ -16,51 +16,69 @@ ### Animate -| 参数 | 说明 | 类型 | 默认值 | 是否必填 | -| --------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------ | -------- | -| animation | 动画 className | string \| Partial> | - | | -| animationAppear | 子元素第一次挂载时是否执行动画 | boolean | true | | -| component | 包裹子元素的标签 | TransitionGroupProps['component'] | 'div' | | -| singleMode | 是否只有单个子元素,如果有多个子元素,请设置为 false | boolean | true | | -| beforeAppear | 执行第一次挂载动画前触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| onAppear | 执行第一次挂载动画,添加 xxx-appear-active 类名后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| afterAppear | 执行完第一次挂载动画后触发的函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| beforeEnter | 执行进场动画前触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| onEnter | 执行进场动画,添加 xxx-enter-active 类名后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| afterEnter | 执行完进场动画后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| beforeLeave | 执行离场动画前触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| onLeave | 执行离场动画,添加 xxx-leave-active 类名后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| afterLeave | 执行完离场动画后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | +| 参数 | 说明 | 类型 | 默认值 | 是否必填 | +| --------------- | --------------------------------------------------------------- | ----------------------------------------------------------------- | ------ | -------- | +| animation | 动画 className | string \| Partial> | - | | +| animationAppear | 子元素第一次挂载时是否执行动画 | boolean | true | | +| component | 包裹子元素的标签 | React.ElementType | 'div' | | +| singleMode | 是否只有单个子元素,如果有多个子元素,请设置为 false | boolean | true | | +| beforeAppear | 执行第一次挂载动画前触发的回调函数 | (node: HTMLElement) => void | - | | +| onAppear | 执行第一次挂载动画,添加 xxx-appear-active 类名后触发的回调函数 | (node: HTMLElement) => void | - | | +| afterAppear | 执行完第一次挂载动画后触发的函数 | (node: HTMLElement) => void | - | | +| beforeEnter | 执行进场动画前触发的回调函数 | (node: HTMLElement) => void | - | | +| onEnter | 执行进场动画,添加 xxx-enter-active 类名后触发的回调函数 | (node: HTMLElement) => void | - | | +| afterEnter | 执行完进场动画后触发的回调函数 | (node: HTMLElement) => void | - | | +| beforeLeave | 执行离场动画前触发的回调函数 | (node: HTMLElement) => void | - | | +| onLeave | 执行离场动画,添加 xxx-leave-active 类名后触发的回调函数 | (node: HTMLElement) => void | - | | +| afterLeave | 执行完离场动画后触发的回调函数 | (node: HTMLElement) => void | - | | ### Animate.Expand -| 参数 | 说明 | 类型 | 默认值 | 是否必填 | -| ----------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------ | -------- | -| animation | 动画 className | string \| Partial> | - | | -| beforeEnter | 执行进场动画前触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| onEnter | 执行进场动画,添加 xxx-enter-active 类名后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| afterEnter | 执行完进场动画后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| beforeLeave | 执行离场动画前触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| onLeave | 执行离场动画,添加 xxx-leave-active 类名后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| afterLeave | 执行完离场动画后触发的回调函数

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | +| 参数 | 说明 | 类型 | 默认值 | 是否必填 | +| ----------- | -------------------------------------------------------- | ----------------------------------------------------------------- | ------ | -------- | +| animation | 动画 className | string \| Partial> | - | | +| beforeEnter | 执行进场动画前触发的回调函数 | (node: HTMLElement) => void | - | | +| onEnter | 执行进场动画,添加 xxx-enter-active 类名后触发的回调函数 | (node: HTMLElement) => void | - | | +| afterEnter | 执行完进场动画后触发的回调函数 | (node: HTMLElement) => void | - | | +| beforeLeave | 执行离场动画前触发的回调函数 | (node: HTMLElement) => void | - | | +| onLeave | 执行离场动画,添加 xxx-leave-active 类名后触发的回调函数 | (node: HTMLElement) => void | - | | +| afterLeave | 执行完离场动画后触发的回调函数 | (node: HTMLElement) => void | - | | ### Animate.OverlayAnimate -| 参数 | 说明 | 类型 | 默认值 | 是否必填 | -| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------ | -------- | -| animation | 动画 className | string \| false \| Record<'in' \| 'out', string> | - | | -| visible | 是否显示 | boolean | - | | -| children | 子元素 | ReactElement | - | | -| timeout | 过渡的超时时间。 | \| number
\| { appear?: number \| undefined; enter?: number \| undefined; exit?: number \| undefined } | - | | -| style | 子元素样式 | CSSProperties | - | | -| mountOnEnter | 默认情况下,子元素会在 OverlayAnimate 组件挂载时立即挂载。如果您想在第一次 `in={true}` 时“惰性”挂载组件,
可以设置 `mountOnEnter`。在第一次进入后 OverlayAnimate 组件将保持挂载,即使在“退出”状态下也是如此,除非您也指定了 `unmountOnExit`。 | boolean | false | | -| unmountOnExit | 默认情况下,子元素会在 OverlayAnimate 组件离开时立即卸载。如果您想在第一次 `in={false}` 时“惰性”卸载组件,
可以设置 `unmountOnExit`。在第一次离开后 OverlayAnimate 组件将保持卸载,即使在“进入”状态下也是如此,除非您也指定了 `mountOnEnter`。 | boolean | false | | -| onEnter | 在“进入”状态被应用前触发的回调。我们提供了一个额外的参数 isAppearing,用于标识进入阶段是否在初次挂载时发生。

**签名**:
**参数**:
_node_: 节点
_isAppearing_: 是否在初次挂载 | (node: HTMLElement, isAppearing: boolean) => void | - | | -| onEntering | 在“进入”状态被应用后触发的回调。我们提供了一个额外的参数 isAppearing,用于标识进入阶段是否在初次挂载时发生。

**签名**:
**参数**:
_node_: 节点
_isAppearing_: 是否在初次挂载 | (node: HTMLElement, isAppearing: boolean) => void | - | | -| onEntered | 在“已进入”状态被应用后触发的回调。我们提供了一个额外的参数 isAppearing,用于标识进入阶段是否在初次挂载时发生。

**签名**:
**参数**:
_node_: 节点
_isAppearing_: 是否在初次挂载 | (node: HTMLElement, isAppearing: boolean) => void | - | | -| onExit | 在“离开”状态被应用前触发的回调。

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| onExiting | 在“离开”状态被应用后触发的回调。

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| onExited | 在“已离开”状态被应用后触发的回调。

**签名**:
**参数**:
_node_: 节点 | (node: HTMLElement) => void | - | | -| appear | 正常情况下,如果组件在组件挂载时就已经显示,那么它不会进行过渡效果。
如果你想在初次挂载时实现过渡效果,请将 appear 属性设置为 true,这样当挂载时,组件会立即开始过渡过程。
请注意,并没有专门的“出现”状态。“出现”属性仅会在初始挂载时增加一次进入过渡效果。 | boolean | - | | -| enter | 启用或禁用进场动画 | boolean | - | | -| exit | 启用或禁用离场动画 | boolean | - | | +| 参数 | 说明 | 类型 | 默认值 | 是否必填 | +| ------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------ | -------- | +| animation | 动画 className | string \| false \| Record<'in' \| 'out', string> | - | | +| visible | 是否显示 | boolean | - | | +| children | 子元素 | ReactElement | - | 是 | +| timeout | 过渡的超时时间。 | \| number
\| { appear?: number \| undefined; enter?: number \| undefined; exit?: number \| undefined } | - | | +| style | 子元素样式 | React.CSSProperties | - | | +| mountOnEnter | 在第一次 `in={true}` 时“惰性”挂载组件 | boolean | false | | +| unmountOnExit | 在第一次 `in={false}` 时“惰性”卸载组件 | boolean | false | | +| onEnter | 在“进入”状态被应用前触发的回调。

**签名**:
**参数**:
_isAppearing_: 是否在初次挂载 | (node: HTMLElement, isAppearing: boolean) => void | - | | +| onEntering | 在“进入”状态被应用后触发的回调。

**签名**:
**参数**:
_isAppearing_: 是否在初次挂载 | (node: HTMLElement, isAppearing: boolean) => void | - | | +| onEntered | 在“已进入”状态被应用后触发的回调。

**签名**:
**参数**:
_isAppearing_: 是否在初次挂载 | (node: HTMLElement, isAppearing: boolean) => void | - | | +| onExit | 在“离开”状态被应用前触发的回调。 | (node: HTMLElement) => void | - | | +| onExiting | 在“离开”状态被应用后触发的回调。 | (node: HTMLElement) => void | - | | +| onExited | 在“已离开”状态被应用后触发的回调。 | (node: HTMLElement) => void | - | | +| appear | 初次挂载时实现过渡效果 | boolean | - | | +| enter | 启用或禁用进场动画 | boolean | - | | +| exit | 启用或禁用离场动画 | boolean | - | | + +## Animation List + +| In | Out | +| ------------ | ------------- | +| fadeIn | fadeOut | +| fadeInDown | fadeOutDown | +| fadeInLeft | fadeOutLeft | +| fadeInRight | fadeOutRight | +| fadeInUp | fadeOutUp | +| slideInDown | slideOutUp | +| slideInLeft | slideOutLeft | +| slideInRight | slideOutRight | +| slideInUp | slideOutDown | +| zoomIn | zoomOut | +| expandInDown | expandOutUp | +| expandInUp | expandOutDown | +| pulse | | diff --git a/components/animate/__tests__/index-spec.tsx b/components/animate/__tests__/index-spec.tsx index 69a1056477..8754f787f2 100644 --- a/components/animate/__tests__/index-spec.tsx +++ b/components/animate/__tests__/index-spec.tsx @@ -3,7 +3,12 @@ import PropTypes from 'prop-types'; import Animate from '../index'; import './index-spec.scss'; -class Demo extends React.Component { +interface DemoProps { + visible?: boolean; + expand?: boolean; +} + +class Demo extends React.Component { static propTypes = { visible: PropTypes.bool, expand: PropTypes.bool, @@ -14,17 +19,16 @@ class Demo extends React.Component { expand: false, }; - constructor(props: any) { + constructor(props: DemoProps) { super(props); - this.state = { visible: props.visible }; - this.handleToggle = this.handleToggle.bind(this); + this.state = { visible: props.visible! }; } - handleToggle() { + handleToggle = () => { this.setState({ visible: !this.state.visible, }); - } + }; render() { const { visible, expand, ...others } = this.props; @@ -96,8 +100,18 @@ describe('Animate', () => { it('should play expand animation', () => { cy.mount(); cy.get('button').click(); - cy.get('.demo-wrapper').should('have.css', 'height', '23.5px'); - cy.get('.demo-wrapper').should('have.css', 'height', '223.5px'); + cy.get('.demo-wrapper') + .invoke('height') + .should('satisfy', num => { + // 避免不同浏览器对 .5px 处理方式的不同造成的测试失败,下同 + return num < 24; + }); + cy.get('.demo-wrapper') + .invoke('height') + .should('satisfy', num => { + // 这里多考虑了一些不同运行环境下具体值的扰动问题 + return num >= 220 && num <= 224; + }); cy.get('button').click(); cy.get('.basic-demo').should('not.exist'); cy.get('button').click(); diff --git a/components/animate/animate.tsx b/components/animate/animate.tsx index 7b84364eee..12fc115008 100644 --- a/components/animate/animate.tsx +++ b/components/animate/animate.tsx @@ -3,8 +3,6 @@ import PropTypes from 'prop-types'; import { TransitionGroup } from 'react-transition-group'; import AnimateChild from './child'; import type { AnimateProps } from './types'; -import Expand from './expand'; -import OverlayAnimate from './overlay-animate'; const noop = () => {}; const FirstChild = (props: { children: ReactNode }) => { @@ -16,65 +14,21 @@ const FirstChild = (props: { children: ReactNode }) => { * Animate */ class Animate extends Component { - static Expand = Expand; - static OverlayAnimate = OverlayAnimate; static displayName = 'Animate'; static propTypes = { - /** - * 动画 className - */ animation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - /** - * 子元素第一次挂载时是否执行动画 - */ animationAppear: PropTypes.bool, - /** - * 包裹子元素的标签 - */ component: PropTypes.any, - /** - * 是否只有单个子元素,如果有多个子元素,请设置为 false - */ singleMode: PropTypes.bool, - /** - * 子元素 - */ children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]), - /** - * 执行第一次挂载动画前触发的回调函数 - */ beforeAppear: PropTypes.func, - /** - * 执行第一次挂载动画,添加 xxx-appear-active 类名后触发的回调函数 - */ onAppear: PropTypes.func, - /** - * 执行完第一次挂载动画后触发的函数 - */ afterAppear: PropTypes.func, - /** - * 执行进场动画前触发的回调函数 - */ beforeEnter: PropTypes.func, - /** - * 执行进场动画,添加 xxx-enter-active 类名后触发的回调函数 - */ onEnter: PropTypes.func, - /** - * 执行完进场动画后触发的回调函数 - */ afterEnter: PropTypes.func, - /** - * 执行离场动画前触发的回调函数 - */ beforeLeave: PropTypes.func, - /** - * 执行离场动画,添加 xxx-leave-active 类名后触发的回调函数 - */ onLeave: PropTypes.func, - /** - * 执行完离场动画后触发的回调函数 - */ afterLeave: PropTypes.func, }; @@ -161,7 +115,7 @@ class Animate extends Component { component={singleMode ? FirstChild : component} {...others} > - {animateChildren} + {animateChildren!} ); } diff --git a/components/animate/index.tsx b/components/animate/index.tsx index 48d362009c..5b796a41a0 100644 --- a/components/animate/index.tsx +++ b/components/animate/index.tsx @@ -1,5 +1,10 @@ +import { assignSubComponent } from '../util/component'; import Animate from './animate'; +import Expand from './expand'; +import OverlayAnimate from './overlay-animate'; + +const AnimateWithSubComponent = assignSubComponent(Animate, { Expand, OverlayAnimate }); export type { AnimateProps, ExpandProps, OverlayAnimateProps } from './types'; -export default Animate; +export default AnimateWithSubComponent; diff --git a/components/animate/overlay-animate.tsx b/components/animate/overlay-animate.tsx index 576c123a20..0742598c8b 100644 --- a/components/animate/overlay-animate.tsx +++ b/components/animate/overlay-animate.tsx @@ -49,10 +49,10 @@ const OverlayAnimate = (props: OverlayAnimateProps) => { const animationMap = typeof animation === 'string' ? { in: animation, out: animation } : animation; - const animateClsMap: Partial> = animation + const animateClsMap: Partial> = animationMap ? { - entering: (animationMap as Record<'in' | 'out', string>).in, - exiting: (animationMap as Record<'in' | 'out', string>).out, + entering: animationMap.in, + exiting: animationMap.out, } : {}; @@ -65,7 +65,7 @@ const OverlayAnimate = (props: OverlayAnimateProps) => { {state => { const cls = classNames({ - [children!.props.className]: !!children!.props.className, + [children.props.className]: !!children.props.className, [animateClsMap[state]!]: state in animateClsMap && animateClsMap[state], }); @@ -74,11 +74,11 @@ const OverlayAnimate = (props: OverlayAnimateProps) => { className: cls, }; - if (style && children!.props && children!.props.style) { - childProps.style = Object.assign({}, children!.props.style, style); + if (style && children.props && children.props.style) { + childProps.style = Object.assign({}, children.props.style, style); } - return React.cloneElement(children!, childProps); + return React.cloneElement(children, childProps); }} ); diff --git a/components/animate/types.ts b/components/animate/types.ts index 2405908fb7..7c2d6619ce 100644 --- a/components/animate/types.ts +++ b/components/animate/types.ts @@ -1,16 +1,15 @@ -import React, { type ReactElement, type CSSProperties } from 'react'; -import type { TransitionGroupProps } from 'react-transition-group/TransitionGroup'; +import React, { type ReactElement } from 'react'; import type { CommonProps } from '../util'; export interface AnimateChildProps { - names?: Partial<{ - appear: string; + names?: { + appear: string | undefined; appearActive: string; enter: string; enterActive: string; leave: string; leaveActive: string; - }>; + }; onAppear?: (node: HTMLElement) => void; onAppeared?: (node: HTMLElement) => void; onAppearing?: (node: HTMLElement) => void; @@ -44,7 +43,7 @@ export interface AnimateProps extends React.HTMLAttributes, CommonP * @en The tag of the wrapper * @defaultValue 'div' */ - component?: TransitionGroupProps['component']; + component?: React.ElementType; /** * 是否只有单个子元素,如果有多个子元素,请设置为 false @@ -56,63 +55,54 @@ export interface AnimateProps extends React.HTMLAttributes, CommonP /** * 执行第一次挂载动画前触发的回调函数 * @en Callback fired before the "entering" status of the first mount is applied - * @param node - 节点 - node */ beforeAppear?: (node: HTMLElement) => void; /** * 执行第一次挂载动画,添加 xxx-appear-active 类名后触发的回调函数 * @en Callback fired after the "entering" status of the first mount is applied - * @param node - 节点 - node */ onAppear?: (node: HTMLElement) => void; /** * 执行完第一次挂载动画后触发的函数 * @en Callback fired after the "entered" status of the first mount is applied - * @param node - 节点 - node */ afterAppear?: (node: HTMLElement) => void; /** * 执行进场动画前触发的回调函数 * @en Callback fired before the "entering" status is applied - * @param node - 节点 - node */ beforeEnter?: (node: HTMLElement) => void; /** * 执行进场动画,添加 xxx-enter-active 类名后触发的回调函数 * @en Callback fired after the "entering" status is applied - * @param node - 节点 - node */ onEnter?: (node: HTMLElement) => void; /** * 执行完进场动画后触发的回调函数 * @en Callback fired after the "entered" status is applied - * @param node - 节点 - node */ afterEnter?: (node: HTMLElement) => void; /** * 执行离场动画前触发的回调函数 * @en Callback fired before the "exiting" status is applied - * @param node - 节点 - node */ beforeLeave?: (node: HTMLElement) => void; /** * 执行离场动画,添加 xxx-leave-active 类名后触发的回调函数 * @en Callback fired after the leave stage - * @param node - 节点 - node */ onLeave?: (node: HTMLElement) => void; /** * 执行完离场动画后触发的回调函数 * @en Callback fired after the leave stage - * @param node - 节点 - node */ afterLeave?: (node: HTMLElement) => void; } @@ -129,40 +119,34 @@ export interface ExpandProps { /** * 执行进场动画前触发的回调函数 * @en Callback fired before the "entering" status is applied - * @param node - 节点 - node */ beforeEnter?: (node: HTMLElement) => void; /** * 执行进场动画,添加 xxx-enter-active 类名后触发的回调函数 * @en Callback fired after the "entering" status is applied - * @param node - 节点 - node */ onEnter?: (node: HTMLElement) => void; /** * 执行完进场动画后触发的回调函数 * @en Callback fired after the "entered" status is applied - * @param node - 节点 - node */ afterEnter?: (node: HTMLElement) => void; /** * 执行离场动画前触发的回调函数 * @en Callback fired before the "exiting" status is applied - * @param node - 节点 - node */ beforeLeave?: (node: HTMLElement) => void; /** * 执行离场动画,添加 xxx-leave-active 类名后触发的回调函数 * @en Callback fired after the "exiting" status is applied - * @param node - 节点 - node */ onLeave?: (node: HTMLElement) => void; /** * 执行完离场动画后触发的回调函数 * @en Callback fired after the "exited" status is applied - * @param node - 节点 - node */ afterLeave?: (node: HTMLElement) => void; } @@ -185,7 +169,7 @@ export interface OverlayAnimateProps { * 子元素 * @en The element to be wrapped */ - children?: ReactElement; + children: ReactElement; /** * 过渡的超时时间。 * @en The duration of the transition. @@ -229,11 +213,15 @@ export interface OverlayAnimateProps { * 子元素样式 * @en The style of the child element */ - style?: CSSProperties; + style?: React.CSSProperties; /** + * 在第一次 `in={true}` 时“惰性”挂载组件 + * @en "lazy mount" the component on the first `in={true}` + * @remarks * 默认情况下,子元素会在 OverlayAnimate 组件挂载时立即挂载。如果您想在第一次 `in={true}` 时“惰性”挂载组件, * 可以设置 `mountOnEnter`。在第一次进入后 OverlayAnimate 组件将保持挂载,即使在“退出”状态下也是如此,除非您也指定了 `unmountOnExit`。 - * @en By default the child component is mounted immediately along with the + * - + * By default the child component is mounted immediately along with the * parent OverlayAnimate component. If you want to "lazy mount" the component on * the first `in={true}` you can set `mountOnEnter`. After the first enter * OverlayAnimate the component will stay mounted, even on "exited", unless you @@ -242,64 +230,60 @@ export interface OverlayAnimateProps { */ mountOnEnter?: boolean; /** + * 在第一次 `in={false}` 时“惰性”卸载组件 + * @en "lazy unmount" the component on the first `in={false}` + * @remarks * 默认情况下,子元素会在 OverlayAnimate 组件离开时立即卸载。如果您想在第一次 `in={false}` 时“惰性”卸载组件, * 可以设置 `unmountOnExit`。在第一次离开后 OverlayAnimate 组件将保持卸载,即使在“进入”状态下也是如此,除非您也指定了 `mountOnEnter`。 - * @en By default the child component stays mounted after it reaches the + * - + * By default the child component stays mounted after it reaches the * 'exited' state. Set `unmountOnExit` if you'd prefer to unmount the * component after it finishes exiting. * @defaultValue false */ unmountOnExit?: boolean; /** - * 在“进入”状态被应用前触发的回调。我们提供了一个额外的参数 isAppearing,用于标识进入阶段是否在初次挂载时发生。 - * @en Callback fired before the "entering" status is applied. An extra - * parameter `isAppearing` is supplied to indicate if the enter stage is - * occurring on the initial mount - * @param node - 节点 - node + * 在“进入”状态被应用前触发的回调。 + * @en Callback fired before the "entering" status is applied. * @param isAppearing - 是否在初次挂载 - isAppearing */ onEnter?: (node: HTMLElement, isAppearing: boolean) => void; /** - * 在“进入”状态被应用后触发的回调。我们提供了一个额外的参数 isAppearing,用于标识进入阶段是否在初次挂载时发生。 - * @en Callback fired after the "entering" status is applied. An extra parameter - * isAppearing is supplied to indicate if the enter stage is occurring on - * the initial mount - * @param node - 节点 - node + * 在“进入”状态被应用后触发的回调。 + * @en Callback fired after the "entering" status is applied. * @param isAppearing - 是否在初次挂载 - isAppearing */ onEntering?: (node: HTMLElement, isAppearing: boolean) => void; /** - * 在“已进入”状态被应用后触发的回调。我们提供了一个额外的参数 isAppearing,用于标识进入阶段是否在初次挂载时发生。 - * @en Callback fired after the "entered" status is applied. An extra parameter - * isAppearing is supplied to indicate if the enter stage is occurring on - * the initial mount - * @param node - 节点 - node + * 在“已进入”状态被应用后触发的回调。 + * @en Callback fired after the "entered" status is applied. * @param isAppearing - 是否在初次挂载 - isAppearing */ onEntered?: (node: HTMLElement, isAppearing: boolean) => void; /** * 在“离开”状态被应用前触发的回调。 * @en Callback fired before the "exiting" status is applied. - * @param node - 节点 - node */ onExit?: (node: HTMLElement) => void; /** * 在“离开”状态被应用后触发的回调。 * @en Callback fired after the "exiting" status is applied. - * @param node - 节点 - node */ onExiting?: (node: HTMLElement) => void; /** * 在“已离开”状态被应用后触发的回调。 * @en Callback fired after the "exited" status is applied. - * @param node - 节点 - node */ onExited?: (node: HTMLElement) => void; /** + * 初次挂载时实现过渡效果 + * @en transition on the first mount. + * @remarks * 正常情况下,如果组件在组件挂载时就已经显示,那么它不会进行过渡效果。 * 如果你想在初次挂载时实现过渡效果,请将 appear 属性设置为 true,这样当挂载时,组件会立即开始过渡过程。 * 请注意,并没有专门的“出现”状态。“出现”属性仅会在初始挂载时增加一次进入过渡效果。 - * @en Normally a component is not transitioned if it is shown when the + * - + * Normally a component is not transitioned if it is shown when the * `` component mounts. If you want to transition on the first * mount set appear to true, and the component will transition in as soon * as the `` mounts. Note: there are no specific "appear" states. diff --git a/components/util/component.ts b/components/util/component.ts new file mode 100644 index 0000000000..3a093ee447 --- /dev/null +++ b/components/util/component.ts @@ -0,0 +1,13 @@ +import React from 'react'; + +export function assignSubComponent< + T extends React.ComponentType, + P extends Record, +>(Component: T, SubComponents: P): T & P { + for (const key in SubComponents) { + if (Object.hasOwn(SubComponents, key)) { + ((Component as T & P)[key] as unknown) = SubComponents[key]; + } + } + return Component as T & P; +}