|
| 1 | +<div align="center"> |
| 2 | + <h1>@rc-component/motion</h1> |
| 3 | + <p><sub>Ant Design 生态的一部分。</sub></p> |
| 4 | + <img alt="Ant Design" height="32" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" /> |
| 5 | + <p>🎞️ React 动效基础组件,封装 CSS 动画、过渡和生命周期状态。</p> |
| 6 | +</div> |
| 7 | + |
| 8 | +<p align="center"><a href="./README.md">English</a> | 简体中文</p> |
| 9 | + |
| 10 | + |
| 11 | +<div align="center"> |
| 12 | + |
| 13 | +[![NPM version][npm-image]][npm-url] [![npm download][download-image]][download-url] [![build status][github-actions-image]][github-actions-url] [![Codecov][codecov-image]][codecov-url] [![bundle size][bundlephobia-image]][bundlephobia-url] [![dumi][dumi-image]][dumi-url] |
| 14 | + |
| 15 | +</div> |
| 16 | + |
| 17 | + |
| 18 | +## 特性 |
| 19 | + |
| 20 | +- Declarative `CSSMotion` component for appear, enter, and leave states. |
| 21 | +- `CSSMotionList` for keyed list transitions. |
| 22 | +- CSS class lifecycle hooks and inline style patching callbacks. |
| 23 | +- Optional deadline fallback when transition or animation events do not fire. |
| 24 | +- TypeScript definitions and React ref support. |
| 25 | +- 被 Ant Design 使用 components that need predictable motion lifecycles. |
| 26 | + |
| 27 | +## 安装 |
| 28 | + |
| 29 | +```bash |
| 30 | +npm install @rc-component/motion |
| 31 | +``` |
| 32 | + |
| 33 | +## 使用 |
| 34 | + |
| 35 | +```tsx | pure |
| 36 | +import CSSMotion from '@rc-component/motion'; |
| 37 | + |
| 38 | +export default ({ visible }: { visible: boolean }) => ( |
| 39 | + <CSSMotion visible={visible} motionName="fade"> |
| 40 | + {({ className, style }, ref) => ( |
| 41 | + <div ref={ref} className={className} style={style}> |
| 42 | + Content |
| 43 | + </div> |
| 44 | + )} |
| 45 | + </CSSMotion> |
| 46 | +); |
| 47 | +``` |
| 48 | + |
| 49 | +```tsx | pure |
| 50 | +import { CSSMotionList } from '@rc-component/motion'; |
| 51 | + |
| 52 | +export default ({ keys }: { keys: string[] }) => ( |
| 53 | + <CSSMotionList keys={keys} motionName="fade"> |
| 54 | + {({ key, className, style }, ref) => ( |
| 55 | + <div ref={ref} key={key} className={className} style={style}> |
| 56 | + {key} |
| 57 | + </div> |
| 58 | + )} |
| 59 | + </CSSMotionList> |
| 60 | +); |
| 61 | +``` |
| 62 | + |
| 63 | +## 示例 |
| 64 | + |
| 65 | +本地运行示例: |
| 66 | + |
| 67 | +```bash |
| 68 | +npm install |
| 69 | +npm start |
| 70 | +``` |
| 71 | + |
| 72 | +然后在浏览器中打开 dumi 开发服务地址。 |
| 73 | + |
| 74 | +## API |
| 75 | + |
| 76 | +### CSSMotion |
| 77 | + |
| 78 | +| 参数 | 类型 | 默认值 | 说明 | |
| 79 | +| --- | --- | --- | --- | |
| 80 | +| children | `(props, ref) => ReactElement` | - | Render function that receives motion class, style, and ref. | |
| 81 | +| forceRender | `boolean` | `false` | Keep the element rendered even when invisible. | |
| 82 | +| leavedClassName | `string` | - | Class name applied after leave when the element remains. | |
| 83 | +| motionAppear | `boolean` | `true` | Enable appear motion. | |
| 84 | +| motionDeadline | `number` | - | Fallback timeout in milliseconds for motion completion. | |
| 85 | +| motionEnter | `boolean` | `true` | Enable enter motion. | |
| 86 | +| motionLeave | `boolean` | `true` | Enable leave motion. | |
| 87 | +| motionLeaveImmediately | `boolean` | - | Trigger leave immediately after mount. | |
| 88 | +| motionName | `string \| MotionName` | - | CSS class name prefix or per-phase class names. | |
| 89 | +| removeOnLeave | `boolean` | `true` | Remove the element after leave. Ignored when `forceRender` is set. | |
| 90 | +| visible | `boolean` | `true` | Controls whether the element is visible. | |
| 91 | +| onAppearActive | `MotionEventHandler` | - | Triggered during appear active phase. | |
| 92 | +| onAppearEnd | `MotionEndEventHandler` | - | Triggered when appear finishes. Return `false` to keep waiting. | |
| 93 | +| onAppearPrepare | `MotionPrepareEventHandler` | - | Prepare callback before appear starts. | |
| 94 | +| onAppearStart | `MotionEventHandler` | - | Triggered when appear starts. | |
| 95 | +| onEnterActive | `MotionEventHandler` | - | Triggered during enter active phase. | |
| 96 | +| onEnterEnd | `MotionEndEventHandler` | - | Triggered when enter finishes. Return `false` to keep waiting. | |
| 97 | +| onEnterPrepare | `MotionPrepareEventHandler` | - | Prepare callback before enter starts. | |
| 98 | +| onEnterStart | `MotionEventHandler` | - | Triggered when enter starts. | |
| 99 | +| onLeaveActive | `MotionEventHandler` | - | Triggered during leave active phase. | |
| 100 | +| onLeaveEnd | `MotionEndEventHandler` | - | Triggered when leave finishes. Return `false` to keep waiting. | |
| 101 | +| onLeavePrepare | `MotionPrepareEventHandler` | - | Prepare callback before leave starts. | |
| 102 | +| onLeaveStart | `MotionEventHandler` | - | Triggered when leave starts. | |
| 103 | +| onVisibleChanged | `(visible: boolean) => void` | - | Triggered after the final visible state changes. | |
| 104 | + |
| 105 | +### CSSMotionList |
| 106 | + |
| 107 | +`CSSMotionList` accepts the motion props above, except `children` is a list render function. |
| 108 | + |
| 109 | +| 参数 | 类型 | 默认值 | 说明 | |
| 110 | +| --- | --- | --- | --- | |
| 111 | +| children | `(props, ref) => ReactElement` | - | Render function for each keyed item. | |
| 112 | +| component | `string \| ComponentType \| false` | `div` | Wrapper component. Use `false` for no wrapper. | |
| 113 | +| keys | `(React.Key \| { key: React.Key })[]` | - | Keys to animate. | |
| 114 | +| onAllRemoved | `() => void` | - | Triggered after every leaving item is removed. | |
| 115 | +| onVisibleChanged | `(visible, info: { key: React.Key }) => void` | - | Triggered after an item visibility changes. | |
| 116 | + |
| 117 | +### Ref |
| 118 | + |
| 119 | +| Ref method | 类型 | 说明 | |
| 120 | +| --- | --- | --- | |
| 121 | +| `enableMotion` | `() => boolean` | Whether motion is currently enabled. | |
| 122 | +| `inMotion` | `() => boolean` | Whether the element is in a motion lifecycle. | |
| 123 | +| `nativeElement` | `HTMLElement` | Current DOM element. | |
| 124 | + |
| 125 | +## 本地开发 |
| 126 | + |
| 127 | +```bash |
| 128 | +npm install |
| 129 | +npm start |
| 130 | +npm test |
| 131 | +npm run tsc |
| 132 | +npm run compile |
| 133 | +npm run build |
| 134 | +``` |
| 135 | + |
| 136 | +## 发布 |
| 137 | + |
| 138 | +```bash |
| 139 | +npm run prepublishOnly |
| 140 | +``` |
| 141 | + |
| 142 | +The release flow is handled by `@rc-component/np` through the `rc-np` command after the package build. |
| 143 | + |
| 144 | +## 许可证 |
| 145 | + |
| 146 | +@rc-component/motion is released under the [MIT](./LICENSE.md) license. |
| 147 | + |
| 148 | +[npm-image]: https://img.shields.io/npm/v/@rc-component/motion.svg?style=flat-square |
| 149 | +[npm-url]: https://npmjs.org/package/@rc-component/motion |
| 150 | +[github-actions-image]: https://github.com/react-component/motion/actions/workflows/react-component-ci.yml/badge.svg |
| 151 | +[github-actions-url]: https://github.com/react-component/motion/actions/workflows/react-component-ci.yml |
| 152 | +[codecov-image]: https://img.shields.io/codecov/c/github/react-component/motion/master.svg?style=flat-square |
| 153 | +[codecov-url]: https://app.codecov.io/gh/react-component/motion |
| 154 | +[download-image]: https://img.shields.io/npm/dm/@rc-component/motion.svg?style=flat-square |
| 155 | +[download-url]: https://npmjs.org/package/@rc-component/motion |
| 156 | +[bundlephobia-url]: https://bundlephobia.com/package/@rc-component/motion |
| 157 | +[bundlephobia-image]: https://img.shields.io/bundlephobia/minzip/@rc-component/motion?style=flat-square |
| 158 | +[dumi-url]: https://github.com/umijs/dumi |
| 159 | +[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square |
0 commit comments