From 1b5f7a65b053088a4603d37fbf5fe732eb71a3e4 Mon Sep 17 00:00:00 2001 From: jljsj Date: Fri, 2 Jul 2021 20:58:14 +0800 Subject: [PATCH 1/6] publish 2.x --- .eslintrc.js | 20 + .fatherrc.js | 10 + .gitignore | 30 +- .jshintignore | 1 - .jshintrc | 10 - .npmignore | 29 + .prettierignore | 7 + .travis.yml | 34 -- .umirc.ts | 16 + README.md | 121 +--- assets/index.less | 1 - docs/demo/animating-class.md | 10 + docs/demo/appear.md | 10 + docs/demo/component.md | 10 + docs/demo/config.md | 10 + docs/demo/custom-anim.md | 10 + docs/demo/custom-ease.md | 10 + docs/demo/custom-enter-leave.md | 10 + docs/demo/custom-param-func.md | 10 + docs/demo/doubleUpdate.md | 10 + docs/demo/dynamic.md | 10 + docs/demo/monkey-click.md | 8 + docs/demo/nested.md | 8 + docs/demo/router.md | 9 + docs/demo/shortcut.md | 8 + docs/demo/simple.md | 8 + docs/demo/switch-forcedReplay.md | 8 + docs/demo/switch.md | 8 + docs/demo/timeline.md | 8 + docs/examples/animating-class.tsx | 50 ++ docs/examples/appear.tsx | 30 + docs/examples/assets/animating-class.less | 7 + .../examples}/assets/router.less | 2 +- .../examples}/assets/switch.less | 0 docs/examples/component.tsx | 35 ++ docs/examples/config.tsx | 13 + .../examples/custom-anim.tsx | 5 +- .../examples/custom-ease.tsx | 12 +- docs/examples/custom-enter-leave.tsx | 57 ++ docs/examples/custom-param-func.tsx | 63 ++ {examples => docs/examples}/dialog-style.html | 0 {examples => docs/examples}/dialog-style.js | 0 docs/examples/doubleUpdate.tsx | 98 +++ docs/examples/dynamic.tsx | 130 ++++ .../examples}/empty-children.html | 0 {examples => docs/examples}/empty-children.js | 0 docs/examples/monkey-click.tsx | 49 ++ docs/examples/nested.tsx | 23 + .../router.js => docs/examples/router.tsx | 93 +-- docs/examples/shortcut.tsx | 53 ++ docs/examples/simple.tsx | 15 + docs/examples/switch-forcedReplay.tsx | 34 ++ docs/examples/switch.tsx | 34 ++ docs/examples/timeline.tsx | 34 ++ docs/index.md | 120 ++++ examples/animating-class.html | 0 examples/animating-class.js | 53 -- examples/appear.html | 1 - examples/appear.js | 12 - examples/assets/animating-class.less | 7 - examples/component.html | 1 - examples/component.js | 45 -- examples/config.html | 1 - examples/config.js | 12 - examples/custom-ease.html | 1 - examples/custom.html | 1 - examples/doubleUpdate.html | 1 - examples/doubleUpdate.js | 103 ---- examples/dynamic.html | 1 - examples/dynamic.js | 120 ---- examples/enter-leave.html | 1 - examples/enter-leave.js | 55 -- examples/monkey-click.html | 1 - examples/monkey-click.js | 54 -- examples/nested.html | 1 - examples/nested.js | 22 - examples/param-func.html | 1 - examples/param-func.js | 61 -- examples/router.html | 1 - examples/shortcut.html | 1 - examples/shortcut.js | 79 --- examples/simple.html | 1 - examples/simple.js | 12 - examples/switch-forcedReplay.html | 1 - examples/switch-forcedReplay.js | 61 -- examples/switch.html | 1 - examples/switch.js | 60 -- examples/timeline.html | 1 - examples/timeline.js | 42 -- now.json | 11 + package.json | 97 ++- src/QueueAnim.jsx | 571 ------------------ src/QueueAnim.tsx | 439 ++++++++++++++ src/{animTypes.js => animTypes.ts} | 0 src/{index.js => index.tsx} | 2 + src/type.ts | 59 ++ src/{utils.js => utils.ts} | 33 +- tests/index.test.jsx | 324 ++++++++++ tsconfig.json | 43 +- tslint.json | 11 - typings/global/import.d.ts | 6 + typings/global/index.d.ts | 3 + 102 files changed, 2102 insertions(+), 1713 deletions(-) create mode 100644 .eslintrc.js create mode 100644 .fatherrc.js delete mode 100644 .jshintignore delete mode 100644 .jshintrc create mode 100644 .npmignore create mode 100644 .prettierignore delete mode 100644 .travis.yml create mode 100644 .umirc.ts create mode 100644 docs/demo/animating-class.md create mode 100644 docs/demo/appear.md create mode 100644 docs/demo/component.md create mode 100644 docs/demo/config.md create mode 100644 docs/demo/custom-anim.md create mode 100644 docs/demo/custom-ease.md create mode 100644 docs/demo/custom-enter-leave.md create mode 100644 docs/demo/custom-param-func.md create mode 100644 docs/demo/doubleUpdate.md create mode 100644 docs/demo/dynamic.md create mode 100644 docs/demo/monkey-click.md create mode 100644 docs/demo/nested.md create mode 100644 docs/demo/router.md create mode 100644 docs/demo/shortcut.md create mode 100644 docs/demo/simple.md create mode 100644 docs/demo/switch-forcedReplay.md create mode 100644 docs/demo/switch.md create mode 100644 docs/demo/timeline.md create mode 100644 docs/examples/animating-class.tsx create mode 100644 docs/examples/appear.tsx create mode 100644 docs/examples/assets/animating-class.less rename {examples => docs/examples}/assets/router.less (84%) rename {examples => docs/examples}/assets/switch.less (100%) create mode 100644 docs/examples/component.tsx create mode 100644 docs/examples/config.tsx rename examples/custom.js => docs/examples/custom-anim.tsx (77%) rename examples/custom-ease.js => docs/examples/custom-ease.tsx (77%) create mode 100644 docs/examples/custom-enter-leave.tsx create mode 100644 docs/examples/custom-param-func.tsx rename {examples => docs/examples}/dialog-style.html (100%) rename {examples => docs/examples}/dialog-style.js (100%) create mode 100755 docs/examples/doubleUpdate.tsx create mode 100755 docs/examples/dynamic.tsx rename {examples => docs/examples}/empty-children.html (100%) rename {examples => docs/examples}/empty-children.js (100%) create mode 100644 docs/examples/monkey-click.tsx create mode 100644 docs/examples/nested.tsx rename examples/router.js => docs/examples/router.tsx (64%) create mode 100644 docs/examples/shortcut.tsx create mode 100644 docs/examples/simple.tsx create mode 100644 docs/examples/switch-forcedReplay.tsx create mode 100644 docs/examples/switch.tsx create mode 100644 docs/examples/timeline.tsx create mode 100644 docs/index.md delete mode 100644 examples/animating-class.html delete mode 100644 examples/animating-class.js delete mode 100644 examples/appear.html delete mode 100644 examples/appear.js delete mode 100644 examples/assets/animating-class.less delete mode 100644 examples/component.html delete mode 100644 examples/component.js delete mode 100644 examples/config.html delete mode 100644 examples/config.js delete mode 100644 examples/custom-ease.html delete mode 100644 examples/custom.html delete mode 100644 examples/doubleUpdate.html delete mode 100755 examples/doubleUpdate.js delete mode 100644 examples/dynamic.html delete mode 100755 examples/dynamic.js delete mode 100644 examples/enter-leave.html delete mode 100644 examples/enter-leave.js delete mode 100644 examples/monkey-click.html delete mode 100644 examples/monkey-click.js delete mode 100644 examples/nested.html delete mode 100644 examples/nested.js delete mode 100644 examples/param-func.html delete mode 100644 examples/param-func.js delete mode 100644 examples/router.html delete mode 100644 examples/shortcut.html delete mode 100644 examples/shortcut.js delete mode 100644 examples/simple.html delete mode 100644 examples/simple.js delete mode 100644 examples/switch-forcedReplay.html delete mode 100644 examples/switch-forcedReplay.js delete mode 100644 examples/switch.html delete mode 100644 examples/switch.js delete mode 100644 examples/timeline.html delete mode 100644 examples/timeline.js create mode 100644 now.json delete mode 100644 src/QueueAnim.jsx create mode 100644 src/QueueAnim.tsx rename src/{animTypes.js => animTypes.ts} (100%) rename src/{index.js => index.tsx} (78%) create mode 100644 src/type.ts rename src/{utils.js => utils.ts} (70%) create mode 100644 tests/index.test.jsx delete mode 100644 tslint.json create mode 100644 typings/global/import.d.ts create mode 100644 typings/global/index.d.ts diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..6ade1bb --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,20 @@ +const base = require('@umijs/fabric/dist/eslint'); + +module.exports = { + ...base, + rules: { + ...base.rules, + 'import/no-extraneous-dependencies': 0, + 'import/no-named-as-default': 0, + 'no-template-curly-in-string': 0, + 'prefer-promise-reject-errors': 0, + 'react/no-array-index-key': 0, + 'react/require-default-props': 0, + 'react/sort-comp': 0, + 'react/no-find-dom-node': 1, + '@typescript-eslint/no-explicit-any': 0, + 'jsx-a11y/label-has-associated-control': 0, + 'jsx-a11y/label-has-for': 0, + 'no-param-reassign': 0 + }, +}; \ No newline at end of file diff --git a/.fatherrc.js b/.fatherrc.js new file mode 100644 index 0000000..e062744 --- /dev/null +++ b/.fatherrc.js @@ -0,0 +1,10 @@ + +export default { + cjs: 'babel', + esm: { type: 'babel', importLibToEs: true }, + runtimeHelpers: true, + preCommit: { + eslint: true, + prettier: true, + }, +}; \ No newline at end of file diff --git a/.gitignore b/.gitignore index 632123d..9de4c8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ +.storybook *.iml *.log -.idea +.idea/ .ipr .iws *~ @@ -12,17 +13,34 @@ Thumbs.db .project .*proj -.svn +.svn/ *.swp *.swo *.pyc *.pyo +.build node_modules .cache -*.css +dist +assets/**/*.css build lib -coverage -dist es -*.lock \ No newline at end of file +coverage +yarn.lock +package-lock.json +.vscode +.doc +# production +/dist +/docs-dist + +# misc +.DS_Store +# umi +.umi +.umi-production +.umi-test +.env.local +src/.umi +QueueAnim_1.jsx \ No newline at end of file diff --git a/.jshintignore b/.jshintignore deleted file mode 100644 index 3c3629e..0000000 --- a/.jshintignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 997b3f7..0000000 --- a/.jshintrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "node": true, - - "curly": true, - "latedef": true, - "quotmark": true, - "undef": true, - "unused": true, - "trailing": true -} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..8db6ebd --- /dev/null +++ b/.npmignore @@ -0,0 +1,29 @@ +build/ +*.cfg +nohup.out +*.iml +.idea/ +.ipr +.iws +*~ +~* +*.diff +*.log +*.patch +*.bak +.DS_Store +Thumbs.db +.project +.*proj +.svn/ +*.swp +out/ +.build +node_modules +.cache +examples +tests +src +/index.js +.* +assets/**/*.less \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b785a08 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +**/*.svg +**/*.ejs +**/*.html +package.json +.umi +.umi-production +.umi-test \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a2957c1..0000000 --- a/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -language: node_js - -sudo: false - -notifications: - email: - - 155259966@qq.com - -node_js: -- 10 - -before_install: -- | - if ! git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '(\.md$)|(^(docs|examples))/' - then - echo "Only docs were updated, stopping build process." - exit - fi -script: -- | - if [ "$TEST_TYPE" = test ]; then - npm test - else - npm run $TEST_TYPE - fi -env: - matrix: - - TEST_TYPE=lint - - TEST_TYPE=test - - TEST_TYPE=coverage - -matrix: - allow_failures: - - env: "TEST_TYPE=saucelabs" diff --git a/.umirc.ts b/.umirc.ts new file mode 100644 index 0000000..4dbd287 --- /dev/null +++ b/.umirc.ts @@ -0,0 +1,16 @@ +// more config: https://d.umijs.org/config +import { defineConfig } from 'dumi'; +const path = require('path'); + +export default defineConfig({ + title: 'rc-queue-anim', + favicon: + 'https://zos.alipayobjects.com/rmsportal/HzvPfCGNCtvGrdk.png', + logo: + 'https://zos.alipayobjects.com/rmsportal/TOXWfHIUGHvZIyb.svg', + outputPath: '.doc', + alias: { + 'rc-queue-anim/es': path.join(__dirname, 'src'), + 'rc-queue-anim/lib': path.join(__dirname, 'src'), + }, +}); \ No newline at end of file diff --git a/README.md b/README.md index 4691058..e892330 100644 --- a/README.md +++ b/README.md @@ -1,120 +1 @@ -# rc-queue-anim ---- - -Animate React Component in queue, thanks to [rc-animate](https://github.com/react-component/animate) and [enter-animation](https://github.com/jljsj33/enter-animation). - -[![NPM version][npm-image]][npm-url] -[![build status][travis-image]][travis-url] -[![Test coverage][coveralls-image]][coveralls-url] -[![Total alerts][lgtm-alerts-image]][lgtm-alerts-url] -[![Language grade: JavaScript][lgtm-grade-image]][lgtm-grade-url] -[![node version][node-image]][node-url] -[![npm download][download-image]][download-url] - -[npm-image]: http://img.shields.io/npm/v/rc-queue-anim.svg?style=flat-square -[npm-url]: http://npmjs.org/package/rc-queue-anim -[travis-image]: https://img.shields.io/travis/react-component/queue-anim.svg?style=flat-square -[travis-url]: https://travis-ci.org/react-component/queue-anim -[coveralls-image]: https://img.shields.io/coveralls/react-component/queue-anim.svg?style=flat-square -[coveralls-url]: https://coveralls.io/r/react-component/queue-anim?branch=master -[lgtm-alerts-image]: https://img.shields.io/lgtm/alerts/g/react-component/queue-anim.svg?logo=lgtm&logoWidth=18&style=flat-square -[lgtm-alerts-url]: https://lgtm.com/projects/g/react-component/queue-anim/alerts/ -[lgtm-grade-image]: https://img.shields.io/lgtm/grade/javascript/g/react-component/queue-anim.svg?logo=lgtm&logoWidth=18&style=flat-square -[lgtm-grade-url]: https://lgtm.com/projects/g/react-component/queue-anim/context:javascript -[node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square -[node-url]: http://nodejs.org/download/ -[download-image]: https://img.shields.io/npm/dm/rc-queue-anim.svg?style=flat-square -[download-url]: https://npmjs.org/package/rc-queue-anim - -## Example - -http://react-component.github.io/queue-anim/examples/ - -![](https://t.alipayobjects.com/images/rmsweb/T12PliXjXgXXXXXXXX.gif) - -## Usage - -```js -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -ReactDom.render( - -
enter in queue
-
enter in queue
-
enter in queue
-
-, mountNode); -``` - -## Install - -[![rc-queue-anim](https://nodei.co/npm/rc-queue-anim.png)](https://npmjs.org/package/rc-queue-anim) - -## Browser Support - -|![IE](https://github.com/alrra/browser-logos/blob/master/src/edge/edge_48x48.png?raw=true) | ![Chrome](https://github.com/alrra/browser-logos/blob/master/src/chrome/chrome_48x48.png?raw=true) | ![Firefox](https://github.com/alrra/browser-logos/blob/master/src/firefox/firefox_48x48.png?raw=true) | ![Opera](https://github.com/alrra/browser-logos/blob/master/src/opera/opera_48x48.png?raw=true) | ![Safari](https://github.com/alrra/browser-logos/blob/master/src/safari/safari_48x48.png?raw=true)| -| --- | --- | --- | --- | --- | -| IE 10+ ✔ | Chrome 31.0+ ✔ | Firefox 31.0+ ✔ | Opera 30.0+ ✔ | Safari 7.0+ ✔ | - -### 1.7.x add childRefs and currentRef; - -```jsx - { - this.ref = c; - }} - onEnd={() => { - // this..currentRef = - // this..childRefs.a = 1212 - }} -> - 1212 - -``` - -## API - -> You must provide the key attribute for all children of QueueAnim, children would not peform any animation without key. - -| props | type | default | description | -|------------|----------------|---------|----------------| -| type | string / array | `right` | Animation Styles
`alpha` `left` `right` `top` `bottom` `scale` `scaleBig` `scaleX` `scaleY`| -| animConfig | object / array | null | Custom config, See below for more details [animConfig](#animConfig) | -| delay | number / array | 0 | delay of animation | -| duration | number / array | 450 | duration of animation | -| interval | number / array | 100 | interval of duration | -| leaveReverse | boolean | false | reverse animation order at leave | -| ease | string / array | `easeOutQuart` | animation easing config like `'ease'`, `['easeIn', 'easeOut']`, `[[.42,0,.58,1]`, [.42,0,.58,1]]: [more](http://easings.net/en) | -| appear | boolean | true | whether support appear anim | -| component | string / React.Element | `div` | component tag | -| componentProps | Object | null | component is React.Element, component tag props | -| animatingClassName | array | `['queue-anim-entering', 'queue-anim-leaving']` | className to every element of animating | -| forcedReplay | boolean | false | `leave` animation moment trigger `enter`, forced replay. | -| onEnd | function | null | animation end callback({ key, type }), type: `enter` or `leave` | - -> Above props support array format, like `['left', 'top']`, the secord item is leave config. [Demo](http://react-component.github.io/queue-anim/examples/enter-leave.html) - -### animConfig - -**Data fall into three categories:** - -- Custom set start: `{ opacity:[1, 0] }` ; -
default; -
type: `{ opacity: Array }`; -
leave automatic reverse: `{ opacity: Array }`; - -- Custom: `{ opacity: 0 }`; -
Start position is not set。 - -- Array: `[{ opacity:[1, 0] }, { opacity:[1, 0] }]`; -
type: `[{ opacity: Array }, { opacity: Array}]` - -## Development - -``` -npm install -npm start -``` +docs/index.md \ No newline at end of file diff --git a/assets/index.less b/assets/index.less index baa8c77..e69de29 100644 --- a/assets/index.less +++ b/assets/index.less @@ -1 +0,0 @@ -@zero: 0; \ No newline at end of file diff --git a/docs/demo/animating-class.md b/docs/demo/animating-class.md new file mode 100644 index 0000000..77a029a --- /dev/null +++ b/docs/demo/animating-class.md @@ -0,0 +1,10 @@ +--- +title: animating-class +order: 1 +--- + +## animating-class + +进入时样式控制。 + + diff --git a/docs/demo/appear.md b/docs/demo/appear.md new file mode 100644 index 0000000..11abd64 --- /dev/null +++ b/docs/demo/appear.md @@ -0,0 +1,10 @@ +--- +title: appear +order: 1 +--- + +## appear + +进入不需要动画。 + + diff --git a/docs/demo/component.md b/docs/demo/component.md new file mode 100644 index 0000000..8a0ac36 --- /dev/null +++ b/docs/demo/component.md @@ -0,0 +1,10 @@ +--- +title: component +order: 6 +--- + +## component + +自定义 component + + diff --git a/docs/demo/config.md b/docs/demo/config.md new file mode 100644 index 0000000..7fa83f8 --- /dev/null +++ b/docs/demo/config.md @@ -0,0 +1,10 @@ +--- +title: custom-config +order: 4 +--- + +## custom-config + +自定义 interval、delay、duration。 + + diff --git a/docs/demo/custom-anim.md b/docs/demo/custom-anim.md new file mode 100644 index 0000000..a60f22b --- /dev/null +++ b/docs/demo/custom-anim.md @@ -0,0 +1,10 @@ +--- +title: custom-anim +order: 5 +--- + +## custom-ease + +自定义动画。 + + diff --git a/docs/demo/custom-ease.md b/docs/demo/custom-ease.md new file mode 100644 index 0000000..60a47d2 --- /dev/null +++ b/docs/demo/custom-ease.md @@ -0,0 +1,10 @@ +--- +title: custom-ease +order: 5 +--- + +## custom-ease + +自定义缓动。 + + diff --git a/docs/demo/custom-enter-leave.md b/docs/demo/custom-enter-leave.md new file mode 100644 index 0000000..dedf67a --- /dev/null +++ b/docs/demo/custom-enter-leave.md @@ -0,0 +1,10 @@ +--- +title: custom-enter-leave +order: 5 +--- + +## custom-enter-leave + +自定义进出场。 + + diff --git a/docs/demo/custom-param-func.md b/docs/demo/custom-param-func.md new file mode 100644 index 0000000..d48c940 --- /dev/null +++ b/docs/demo/custom-param-func.md @@ -0,0 +1,10 @@ +--- +title: custom-param-func +order: 5 +--- + +## custom-param-func + +自定义参数用 func。 + + diff --git a/docs/demo/doubleUpdate.md b/docs/demo/doubleUpdate.md new file mode 100644 index 0000000..bd1ec52 --- /dev/null +++ b/docs/demo/doubleUpdate.md @@ -0,0 +1,10 @@ +--- +title: doubleUpdate +order: 7 +--- + +## doubleUpdate + +多次刷新 + + diff --git a/docs/demo/dynamic.md b/docs/demo/dynamic.md new file mode 100644 index 0000000..21a038d --- /dev/null +++ b/docs/demo/dynamic.md @@ -0,0 +1,10 @@ +--- +title: dynamic +order: 7 +--- + +## dynamic + +自定义操作 + + diff --git a/docs/demo/monkey-click.md b/docs/demo/monkey-click.md new file mode 100644 index 0000000..45f4251 --- /dev/null +++ b/docs/demo/monkey-click.md @@ -0,0 +1,8 @@ +--- +title: monkey-click +order: 6 +--- + +## monkey-click + + diff --git a/docs/demo/nested.md b/docs/demo/nested.md new file mode 100644 index 0000000..a4c539d --- /dev/null +++ b/docs/demo/nested.md @@ -0,0 +1,8 @@ +--- +title: nested +order: 1 +--- + +## nested + + diff --git a/docs/demo/router.md b/docs/demo/router.md new file mode 100644 index 0000000..b98c9e9 --- /dev/null +++ b/docs/demo/router.md @@ -0,0 +1,9 @@ +--- +title: router +order: 10 +--- + +## router + + + diff --git a/docs/demo/shortcut.md b/docs/demo/shortcut.md new file mode 100644 index 0000000..00840ee --- /dev/null +++ b/docs/demo/shortcut.md @@ -0,0 +1,8 @@ +--- +title: shortcut +order: 1 +--- + +## shortcut + + diff --git a/docs/demo/simple.md b/docs/demo/simple.md new file mode 100644 index 0000000..983f4cb --- /dev/null +++ b/docs/demo/simple.md @@ -0,0 +1,8 @@ +--- +title: simple +order: 0 +--- + +## basic + + diff --git a/docs/demo/switch-forcedReplay.md b/docs/demo/switch-forcedReplay.md new file mode 100644 index 0000000..8f18e83 --- /dev/null +++ b/docs/demo/switch-forcedReplay.md @@ -0,0 +1,8 @@ +--- +title: switch-forcedReplay +order: 11 +--- + +## switch-forcedReplay + + diff --git a/docs/demo/switch.md b/docs/demo/switch.md new file mode 100644 index 0000000..d58aed7 --- /dev/null +++ b/docs/demo/switch.md @@ -0,0 +1,8 @@ +--- +title: switch +order: 11 +--- + +## switch + + diff --git a/docs/demo/timeline.md b/docs/demo/timeline.md new file mode 100644 index 0000000..d6cbb25 --- /dev/null +++ b/docs/demo/timeline.md @@ -0,0 +1,8 @@ +--- +title: timeline +order: 2 +--- + +## timeline + + diff --git a/docs/examples/animating-class.tsx b/docs/examples/animating-class.tsx new file mode 100644 index 0000000..b2c7340 --- /dev/null +++ b/docs/examples/animating-class.tsx @@ -0,0 +1,50 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; +import './assets/animating-class.less'; + +const data = [ + { + children: '依次进入1', + key: 1, + }, + { + children: '依次进入2', + key: 2, + }, + { + children: '依次进入3', + key: 3, + }, + { + children: '依次进入4', + key: 4, + }, + { + children: '依次进入5', + key: 5, + }, + { + children: '依次进入6', + key: 6, + }, +]; +export default () => { + const [items, setItems] = useState(data); + return ( +
+ + {items.map((item) => ( +
{item.children}
+ ))} +
+ +
+ ); +}; diff --git a/docs/examples/appear.tsx b/docs/examples/appear.tsx new file mode 100644 index 0000000..de52875 --- /dev/null +++ b/docs/examples/appear.tsx @@ -0,0 +1,30 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; + +const child = [ +
依次进入
, +
依次进入
, +
依次进入
, +
依次进入
, +
依次进入
, +]; +export default () => { + const [items, setItems] = useState(child); + return ( +
+ {items} + +
+ ); +}; diff --git a/docs/examples/assets/animating-class.less b/docs/examples/assets/animating-class.less new file mode 100644 index 0000000..3d46dd8 --- /dev/null +++ b/docs/examples/assets/animating-class.less @@ -0,0 +1,7 @@ +.animating .queue-anim-entering { + background: #2db7f5; +} + +.animating .queue-anim-leaving { + background: #f60; +} diff --git a/examples/assets/router.less b/docs/examples/assets/router.less similarity index 84% rename from examples/assets/router.less rename to docs/examples/assets/router.less index 97bb230..6ec6e6a 100644 --- a/examples/assets/router.less +++ b/docs/examples/assets/router.less @@ -1,4 +1,4 @@ -.queue-anim-leaving { +.router-wrapper .queue-anim-leaving { position: absolute; width: 100%; } diff --git a/examples/assets/switch.less b/docs/examples/assets/switch.less similarity index 100% rename from examples/assets/switch.less rename to docs/examples/assets/switch.less diff --git a/docs/examples/component.tsx b/docs/examples/component.tsx new file mode 100644 index 0000000..2c3b39e --- /dev/null +++ b/docs/examples/component.tsx @@ -0,0 +1,35 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React from 'react'; +import 'antd/lib/style/index.less'; +import 'antd/lib/menu/style/index.less'; + +const Comp = React.forwardRef((props: any, ref: any) => { + return ( +
    + {props.children} +
+ ); +}); + +const Child = React.forwardRef((props: any, ref: any) => { + return
  • {props.children}
  • ; +}); + + +export default () => { + return ( + + 依次进入 + 依次进入 + 依次进入 + 依次进入 + 依次进入 + + ); +}; diff --git a/docs/examples/config.tsx b/docs/examples/config.tsx new file mode 100644 index 0000000..aedef00 --- /dev/null +++ b/docs/examples/config.tsx @@ -0,0 +1,13 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React from 'react'; + +export default () => ( + +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    +); diff --git a/examples/custom.js b/docs/examples/custom-anim.tsx similarity index 77% rename from examples/custom.js rename to docs/examples/custom-anim.tsx index 734173f..cd34862 100644 --- a/examples/custom.js +++ b/docs/examples/custom-anim.tsx @@ -1,9 +1,8 @@ /* eslint-disable no-console,react/no-multi-comp */ import QueueAnim from 'rc-queue-anim'; import React from 'react'; -import ReactDom from 'react-dom'; -ReactDom.render(
    +export default () => (
    依次进入
    依次进入
    @@ -11,4 +10,4 @@ ReactDom.render(
    依次进入
    依次进入
    -
    , document.getElementById('__react-content')); +); diff --git a/examples/custom-ease.js b/docs/examples/custom-ease.tsx similarity index 77% rename from examples/custom-ease.js rename to docs/examples/custom-ease.tsx index 42c153c..d9d77e7 100644 --- a/examples/custom-ease.js +++ b/docs/examples/custom-ease.tsx @@ -1,9 +1,8 @@ /* eslint-disable no-console,react/no-multi-comp */ import QueueAnim from 'rc-queue-anim'; import React from 'react'; -import ReactDom from 'react-dom'; -ReactDom.render( +export default () => (
    div 1
    @@ -13,7 +12,12 @@ ReactDom.render(
    div 1

    - +
    div 2
    div 2
    div 2
    @@ -21,4 +25,4 @@ ReactDom.render(
    div 2
    - , document.getElementById('__react-content')); +); diff --git a/docs/examples/custom-enter-leave.tsx b/docs/examples/custom-enter-leave.tsx new file mode 100644 index 0000000..5d62043 --- /dev/null +++ b/docs/examples/custom-enter-leave.tsx @@ -0,0 +1,57 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; + +const data = [ + { + children: '依次进入1', + key: 1, + }, + { + children: '依次进入2', + key: 2, + }, + { + children: '依次进入3', + key: 3, + }, + { + children: '依次进入4', + key: 4, + }, + { + children: '依次进入5', + key: 5, + }, + { + children: '依次进入6', + key: 6, + }, +]; + +export default () => { + const [items, setItems] = useState(data); + return ( +
    + + {items.map((item) => ( +
    {item.children}
    + ))} +
    + +
    + ); +}; diff --git a/docs/examples/custom-param-func.tsx b/docs/examples/custom-param-func.tsx new file mode 100644 index 0000000..c8b5a31 --- /dev/null +++ b/docs/examples/custom-param-func.tsx @@ -0,0 +1,63 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; + +const animConfigFunc = (e: any) => { + if (e.key === '3') { + return { opacity: [1, 0], translateX: [0, 30] }; + } + return [ + { opacity: [1, 0], translateX: [0, -30] }, + { opacity: [1, 0], translateX: [0, 30] }, + ]; +}; +const durationFunc = (e: any) => { + if (e.key === '3') { + return [1500, 4000]; + } + return 500; +}; +const easeFunc = (e: any) => { + if (e.key === '3') { + return ['easeOutBack', 'easeInBack']; + } + return 'easeInOutQuart'; +}; +const delayFunc = (e: any) => { + if (e.index >= 3) { + return [1500, 0]; + } + return 0; +}; + +export default () => { + const [show, setShow] = useState(true); + return ( +
    + + + {show + ? [ +
    依次进入
    , +
    依次进入
    , +
    改变type
    , +
    依次进入
    , +
    依次进入
    , + ] + : null} +
    +
    + ); +}; diff --git a/examples/dialog-style.html b/docs/examples/dialog-style.html similarity index 100% rename from examples/dialog-style.html rename to docs/examples/dialog-style.html diff --git a/examples/dialog-style.js b/docs/examples/dialog-style.js similarity index 100% rename from examples/dialog-style.js rename to docs/examples/dialog-style.js diff --git a/docs/examples/doubleUpdate.tsx b/docs/examples/doubleUpdate.tsx new file mode 100755 index 0000000..1d5ade0 --- /dev/null +++ b/docs/examples/doubleUpdate.tsx @@ -0,0 +1,98 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; + +const data = [ + { + children: '依次进入1', + key: 1, + }, + { + children: '依次进入2', + key: 2, + }, + { + children: '依次进入3', + key: 3, + }, + { + children: '依次进入4', + key: 4, + }, + { + children: '依次进入5', + key: 5, + }, + { + children: '依次进入6', + key: 6, + }, +]; + +export default () => { + const [items, setItems] = useState(data); + + const onSwitch = () => { + if (items.length) { + setItems([]); + } else { + setItems(data); + } + }; + const onRemove = () => { + console.log('remove: 1'); + setItems([]); + setTimeout(() => { + console.log('remove: 2'); + setItems([]); + setTimeout(() => { + console.log('remove: 3'); + setItems([]); + }); + }); + }; + const onExchange = () => { + setItems([ + { + children: '依次进入1', + key: 1, + }, + { + children: '依次进入2', + key: 2, + }, + ]); + setItems([ + { + children: '依次进入1', + key: 1, + }, + { + children: '依次进入2', + key: 2, + }, + ]); + setItems([ + { + children: '依次进入1', + key: 1, + }, + { + children: '依次进入2', + key: 2, + }, + ]); + }; + return ( +
    + + + + + {items.map((item) => ( +
    {item.children}
    + ))} +
    +
    + ); +}; diff --git a/docs/examples/dynamic.tsx b/docs/examples/dynamic.tsx new file mode 100755 index 0000000..c9b651c --- /dev/null +++ b/docs/examples/dynamic.tsx @@ -0,0 +1,130 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim, { IQueueTypeOrArrayOrFunc } from 'rc-queue-anim'; +import React, { useState } from 'react'; + +let index = 7; + +export default () => { + const [items, setItems] = useState([ + { + children: '依次进入1', + key: 1, + }, + { + children: '依次进入2', + key: 2, + }, + { + children: '依次进入3', + key: 3, + }, + { + children: '依次进入4', + key: 4, + }, + { + children: '依次进入5', + key: 5, + }, + { + children: '依次进入6', + key: 6, + }, + ]); + const [type, setType] = useState('left'); + const add = () => { + const newItems = [...items]; + newItems.push({ + children: '新节点', + key: index, + }); + index++; + setItems(newItems); + }; + const addTwo = () => { + const newItems = [...items]; + newItems.push({ + children: '新节点', + key: index, + }); + index++; + newItems.push({ + children: '新节点', + key: index, + }); + index++; + setItems(newItems); + }; + const remove = (key: number, e: any) => { + e.preventDefault(); + const newItems = [...items]; + const target = newItems.filter((c) => c.key === key); + let i: number | undefined; + if (target && target[0]) { + i = newItems.indexOf(target[0]); + } + if (typeof i === 'number' && i >= 0) { + newItems.splice(i, 1); + } + setItems(newItems); + }; + const removeAll = () => { + setItems([]); + }; + const removeAndAdd = () => { + const newItems = [...items]; + newItems.splice(newItems.length - 1, 1); + newItems.push({ + children: `新节点${Date.now()}--${index}`, + key: index, + }); + index++; + setItems(newItems); + }; + const removeAndAddTow = () => { + const newItems = [...items]; + newItems.splice(newItems.length - 1, 1); + newItems.splice(newItems.length - 2, 1); + newItems.push({ + children: `新节点${Date.now()}`, + key: index, + }); + index++; + newItems.unshift({ + children: `新节点${Date.now()}-top`, + key: index, + }); + index++; + setItems(newItems); + }; + const removeTwo = () => { + const newItems = [...items]; + newItems.splice(1, 1); + setItems(newItems); + }; + return ( +
    + + + + + + + + {items.map((item) => ( + + ))} + +
    + ); +}; diff --git a/examples/empty-children.html b/docs/examples/empty-children.html similarity index 100% rename from examples/empty-children.html rename to docs/examples/empty-children.html diff --git a/examples/empty-children.js b/docs/examples/empty-children.js similarity index 100% rename from examples/empty-children.js rename to docs/examples/empty-children.js diff --git a/docs/examples/monkey-click.tsx b/docs/examples/monkey-click.tsx new file mode 100644 index 0000000..75180f5 --- /dev/null +++ b/docs/examples/monkey-click.tsx @@ -0,0 +1,49 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; + +const data = [ + { + children: '依次进入1', + key: 1, + }, + { + children: '依次进入2', + key: 2, + }, + { + children: '依次进入3', + key: 3, + }, + { + children: '依次进入4', + key: 4, + }, + { + children: '依次进入5', + key: 5, + }, + { + children: '依次进入6', + key: 6, + }, +]; + +export default () => { + const [show, setShow] = useState(true); + return ( +
    + + {show ? '显示' : '隐藏'} + + {show ? data.map((item) =>
    {item.children}
    ) : null} +
    +
    + ); +}; diff --git a/docs/examples/nested.tsx b/docs/examples/nested.tsx new file mode 100644 index 0000000..26ec228 --- /dev/null +++ b/docs/examples/nested.tsx @@ -0,0 +1,23 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React from 'react'; + +export default () => ( + +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    依次进入
    + +
    依次进入
    +
    依次进入
    +
    依次进入
    + +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    +
    +
    +); diff --git a/examples/router.js b/docs/examples/router.tsx similarity index 64% rename from examples/router.js rename to docs/examples/router.tsx index 3b42ad3..dc80047 100644 --- a/examples/router.js +++ b/docs/examples/router.tsx @@ -2,7 +2,7 @@ import { HashRouter as Router, Route, Link, Redirect } from 'react-router-dom'; import QueueAnim from 'rc-queue-anim'; import React from 'react'; -import ReactDom from 'react-dom'; + import './assets/router.less'; function Home() { @@ -13,9 +13,9 @@ function Home() { ); } -function Page3() { +const Page3 = React.forwardRef((props, ref) => { return ( - +

    A link to page 2 should be active Page3 @@ -42,35 +42,40 @@ function Page3() {

    ); -} +}); -function Page1() { +const Page1 = React.forwardRef((props, ref) => { return ( - +

    Page 1

    A link to page 2 should be active - 依次进场

    + 依次进场 +

    A link to page 2 should be active - 依次进场

    + 依次进场 +

    A link to page 2 should be active - 依次进场

    + 依次进场 +

    A link to page 2 should be active - 依次进场

    + 依次进场 +

    A link to page 2 should be active - 改变样式

    - 1 + 改变样式 +

    +
    ); -} +}); -function Page2() { +const Page2 = React.forwardRef((props, ref) => { return ( - +

    Page 2

    a link to page 1 @@ -90,49 +95,45 @@ function Page2() {

    ); -} +}); - - -class App extends React.Component { - - getChildren = (props) => { - const { location } = { ...props }; +export default class App extends React.Component { + getChildren = (props: any) => { + const { location } = props; const compArray = [ { to: '/home', component: Home, name: '首页' }, { to: '/page1', component: Page1, name: 'Page1' }, { to: '/page2', component: Page2, name: 'Page2' }, ]; - const component = compArray.map(item => { - if (location.pathname === item.to) { - return item.component; - } - return null; - }).filter(item => item)[0]; - const homeRoute = () => ( - - ); + const component = compArray + .map((item) => { + if (location.pathname === item.to) { + return item.component; + } + return null; + }) + .filter((item) => item)[0]; + const homeRoute = () => ; return ( -
    +
    - {compArray.map(item => ({item.name} ))} - - + {compArray.map((item) => ( + + {item.name}  + + ))} + +
    ); - } + }; render() { - return ( - - ); + return ( + + + + ); } } - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/docs/examples/shortcut.tsx b/docs/examples/shortcut.tsx new file mode 100644 index 0000000..e1ddc61 --- /dev/null +++ b/docs/examples/shortcut.tsx @@ -0,0 +1,53 @@ +import QueueAnim, { IQueueTypeOrArrayOrFunc } from 'rc-queue-anim'; +import React, { useState } from 'react'; + +const d = [ +
    + 依次进入 +
    , +
    + 依次进入 +
    , +
    + 依次进入 +
    , +
    + 依次进入 +
    , +
    + 依次进入 +
    , +]; +export default () => { + const [type, setType] = useState('left'); + const [child, setChild] = useState(d); + + return ( +
    + + + {child} + +
    + ); +}; diff --git a/docs/examples/simple.tsx b/docs/examples/simple.tsx new file mode 100644 index 0000000..b4cf450 --- /dev/null +++ b/docs/examples/simple.tsx @@ -0,0 +1,15 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React from 'react'; + +export default () => { + return ( + +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    依次进入
    +
    + ); +}; diff --git a/docs/examples/switch-forcedReplay.tsx b/docs/examples/switch-forcedReplay.tsx new file mode 100644 index 0000000..120100a --- /dev/null +++ b/docs/examples/switch-forcedReplay.tsx @@ -0,0 +1,34 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; +import './assets/switch.less'; + +const childrenKey = [{ key: 1 }, { key: 2 }, { key: 3 }, { key: 4 }, { key: 5 }, { key: 6 }]; +export default () => { + const [children, setChildren] = useState(childrenKey); + const onEnter = () => { + setChildren([]); + }; + const onLeave = () => { + setChildren(childrenKey); + }; + const childrenToRender = (children || []).map((item) => { + return
  • ; + }); + return ( +
    +

    鼠标经过当前区域,再移出区域查看

    +
    + + {childrenToRender} + + + {childrenToRender} + + + {childrenToRender} + +
    +
    + ); +}; diff --git a/docs/examples/switch.tsx b/docs/examples/switch.tsx new file mode 100644 index 0000000..82afe5a --- /dev/null +++ b/docs/examples/switch.tsx @@ -0,0 +1,34 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; +import './assets/switch.less'; + +const childrenKey = [{ key: 1 }, { key: 2 }, { key: 3 }, { key: 4 }, { key: 5 }, { key: 6 }]; +export default () => { + const [children, setChildren] = useState(childrenKey); + const onEnter = () => { + setChildren([]); + }; + const onLeave = () => { + setChildren(childrenKey); + }; + const childrenToRender = (children || []).map((item) => { + return
  • ; + }); + return ( +
    +

    鼠标经过当前区域,再移出区域查看

    +
    + + {childrenToRender} + + + {childrenToRender} + + + {childrenToRender} + +
    +
    + ); +}; diff --git a/docs/examples/timeline.tsx b/docs/examples/timeline.tsx new file mode 100644 index 0000000..77a5aa1 --- /dev/null +++ b/docs/examples/timeline.tsx @@ -0,0 +1,34 @@ +/* eslint-disable no-console,react/no-multi-comp */ +import QueueAnim from 'rc-queue-anim'; +import React, { useState } from 'react'; + +const children = [ +
    依次进入
    , +
    依次进入
    , +
    依次进入
    , +
    依次进入
    , +]; + +export default () => { + const [show, setShow] = useState(true); + return ( +
    + + + {show ? children : null} + +
    + ); +}; diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..a994ac5 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,120 @@ +# rc-queue-anim +--- + +Animate React Component in queue, thanks to [rc-animate](https://github.com/react-component/animate) and [enter-animation](https://github.com/jljsj33/enter-animation). + +[![NPM version][npm-image]][npm-url] +[![build status][github-actions-image]][github-actions-url] +[![Codecov][codecov-image]][codecov-url] +[![Total alerts][lgtm-alerts-image]][lgtm-alerts-url] +[![Language grade: JavaScript][lgtm-grade-image]][lgtm-grade-url] +[![node version][node-image]][node-url] +[![npm download][download-image]][download-url] + +[npm-image]: http://img.shields.io/npm/v/rc-queue-anim.svg?style=flat-square +[npm-url]: http://npmjs.org/package/rc-queue-anim +[github-actions-image]: https://github.com/react-component/queue-anim/workflows/CI/badge.svg +[github-actions-url]: https://github.com/react-component/queue-anim/actions +[codecov-image]: https://img.shields.io/codecov/c/github/react-component/queue-anim/master.svg?style=flat-square +[codecov-url]: https://codecov.io/gh/react-component/queue-anim/branch/master +[lgtm-alerts-image]: https://img.shields.io/lgtm/alerts/g/react-component/queue-anim.svg?logo=lgtm&logoWidth=18&style=flat-square +[lgtm-alerts-url]: https://lgtm.com/projects/g/react-component/queue-anim/alerts/ +[lgtm-grade-image]: https://img.shields.io/lgtm/grade/javascript/g/react-component/queue-anim.svg?logo=lgtm&logoWidth=18&style=flat-square +[lgtm-grade-url]: https://lgtm.com/projects/g/react-component/queue-anim/context:javascript +[node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square +[node-url]: http://nodejs.org/download/ +[download-image]: https://img.shields.io/npm/dm/rc-queue-anim.svg?style=flat-square +[download-url]: https://npmjs.org/package/rc-queue-anim + +## Example + +http://react-component.github.io/queue-anim/examples/ + +![](https://t.alipayobjects.com/images/rmsweb/T12PliXjXgXXXXXXXX.gif) + +## Usage + +```js +import QueueAnim from 'rc-queue-anim'; +import React from 'react'; +import ReactDom from 'react-dom'; + +ReactDom.render( + +
    enter in queue
    +
    enter in queue
    +
    enter in queue
    +
    +, mountNode); +``` + +## Install + +[![rc-queue-anim](https://nodei.co/npm/rc-queue-anim.png)](https://npmjs.org/package/rc-queue-anim) + +## Browser Support + +|![IE](https://github.com/alrra/browser-logos/blob/master/src/edge/edge_48x48.png?raw=true) | ![Chrome](https://github.com/alrra/browser-logos/blob/master/src/chrome/chrome_48x48.png?raw=true) | ![Firefox](https://github.com/alrra/browser-logos/blob/master/src/firefox/firefox_48x48.png?raw=true) | ![Opera](https://github.com/alrra/browser-logos/blob/master/src/opera/opera_48x48.png?raw=true) | ![Safari](https://github.com/alrra/browser-logos/blob/master/src/safari/safari_48x48.png?raw=true)| +| --- | --- | --- | --- | --- | +| IE 10+ ✔ | Chrome 31.0+ ✔ | Firefox 31.0+ ✔ | Opera 30.0+ ✔ | Safari 7.0+ ✔ | + +### 1.7.x add childRefs and currentRef; + +```js + { + this.ref = c; + }} + onEnd={() => { + // this..currentRef = + // this..childRefs.a = 1212 + }} +> + 1212 + +``` + +## API + +> You must provide the key attribute for all children of QueueAnim, children would not peform any animation without key. + +| props | type | default | description | +|------------|----------------|---------|----------------| +| type | string / array | `right` | Animation Styles
    `alpha` `left` `right` `top` `bottom` `scale` `scaleBig` `scaleX` `scaleY`| +| animConfig | object / array | null | Custom config, See below for more details [animConfig](#animConfig) | +| delay | number / array | 0 | delay of animation | +| duration | number / array | 450 | duration of animation | +| interval | number / array | 100 | interval of duration | +| leaveReverse | boolean | false | reverse animation order at leave | +| ease | string / array | `easeOutQuart` | animation easing config like `'ease'`, `['easeIn', 'easeOut']`, `[[.42,0,.58,1]`, [.42,0,.58,1]]: [more](http://easings.net/en) | +| appear | boolean | true | whether support appear anim | +| component | string / React.Element | `div` | component tag | +| componentProps | Object | null | component is React.Element, component tag props | +| animatingClassName | array | `['queue-anim-entering', 'queue-anim-leaving']` | className to every element of animating | +| forcedReplay | boolean | false | `leave` animation moment trigger `enter`, forced replay. | +| onEnd | function | null | animation end callback({ key, type }), type: `enter` or `leave` | + +> Above props support array format, like `['left', 'top']`, the secord item is leave config. [Demo](http://react-component.github.io/queue-anim/examples/enter-leave.html) + +### animConfig + +**Data fall into three categories:** + +- Custom set start: `{ opacity:[1, 0] }` ; +
    default; +
    type: `{ opacity: Array }`; +
    leave automatic reverse: `{ opacity: Array }`; + +- Custom: `{ opacity: 0 }`; +
    Start position is not set。 + +- Array: `[{ opacity:[1, 0] }, { opacity:[1, 0] }]`; +
    type: `[{ opacity: Array }, { opacity: Array}]` + +## Development + +``` +npm install +npm start +``` diff --git a/examples/animating-class.html b/examples/animating-class.html deleted file mode 100644 index e69de29..0000000 diff --git a/examples/animating-class.js b/examples/animating-class.js deleted file mode 100644 index d4f2a3e..0000000 --- a/examples/animating-class.js +++ /dev/null @@ -1,53 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; -import './assets/animating-class.less'; - -class App extends React.Component { - constructor(props) { - super(props); - this.state = { - items: [{ - children: '依次进入1', - key: 1, - }, { - children: '依次进入2', - key: 2, - }, { - children: '依次进入3', - key: 3, - }, { - children: '依次进入4', - key: 4, - }, { - children: '依次进入5', - key: 5, - }, { - children: '依次进入6', - key: 6, - }], - }; - } - - removeAll = () => { - this.setState({ - items: [], - }); - } - - render() { - return ( -
    - - {this.state.items.map((item) =>
    - {item.children} -
    )} -
    - -
    - ); - } -} - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/appear.html b/examples/appear.html deleted file mode 100644 index b3a4252..0000000 --- a/examples/appear.html +++ /dev/null @@ -1 +0,0 @@ -placeholder \ No newline at end of file diff --git a/examples/appear.js b/examples/appear.js deleted file mode 100644 index 5f746d6..0000000 --- a/examples/appear.js +++ /dev/null @@ -1,12 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -ReactDom.render( -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    , document.getElementById('__react-content')); diff --git a/examples/assets/animating-class.less b/examples/assets/animating-class.less deleted file mode 100644 index dee2562..0000000 --- a/examples/assets/animating-class.less +++ /dev/null @@ -1,7 +0,0 @@ -.queue-anim-entering { - background: #2db7f5; -} - -.queue-anim-leaving { - background: #f60; -} diff --git a/examples/component.html b/examples/component.html deleted file mode 100644 index b3a4252..0000000 --- a/examples/component.html +++ /dev/null @@ -1 +0,0 @@ -placeholder \ No newline at end of file diff --git a/examples/component.js b/examples/component.js deleted file mode 100644 index 29a6d8a..0000000 --- a/examples/component.js +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; -import Icon from 'antd/lib/icon'; -import Menu from 'antd/lib/menu'; -import 'antd/lib/style/index.less'; -import 'antd/lib/menu/style/index.less'; - -const SubMenu = Menu.SubMenu; -const MenuItemGroup = Menu.ItemGroup; -function Demo() { - return ( - Navigation One}> - - Option 1 - Option 2 - - - Option 3 - Option 4 - - - Navigation Two}> - Option 5 - Option 6 - - Option 7 - Option 8 - - - Navigation Three}> - Option 9 - Option 10 - Option 11 - Option 12 - - ); -} -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/config.html b/examples/config.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/config.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/config.js b/examples/config.js deleted file mode 100644 index 83e3730..0000000 --- a/examples/config.js +++ /dev/null @@ -1,12 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -ReactDom.render( -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    , document.getElementById('__react-content')); diff --git a/examples/custom-ease.html b/examples/custom-ease.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/custom-ease.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/custom.html b/examples/custom.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/custom.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/doubleUpdate.html b/examples/doubleUpdate.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/doubleUpdate.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/doubleUpdate.js b/examples/doubleUpdate.js deleted file mode 100755 index f8dbcce..0000000 --- a/examples/doubleUpdate.js +++ /dev/null @@ -1,103 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -class App extends React.Component { - constructor(props) { - super(props); - this.index = 100; - this.items = [ - { - children: '依次进入1', - key: 1, - }, { - children: '依次进入2', - key: 2, - }, { - children: '依次进入3', - key: 3, - }, { - children: '依次进入4', - key: 4, - }, { - children: '依次进入5', - key: 5, - }, { - children: '依次进入6', - key: 6, - }, - ]; - this.state = { - items: this.items, - type: 'left', - }; - } - - switch = () => { - this.setState(state => ({ - items: state.items.length ? [] : this.items, - })); - } - remove = () => { - console.log('remove: 1'); - this.setState({ items: [] }, () => { - console.log('remove: 2'); - this.setState({ items: [] }, () => { - console.log('remove: 3'); - this.setState({ items: [] }); - }); - }); - } - exchange = () => { - console.log('exchange: 1'); - this.setState({ - items: [{ - children: '依次进入1', - key: 1, - }, { - children: '依次进入2', - key: 2, - }], - }, () => { - console.log('exchange: 2'); - this.setState({ - items: [{ - children: '依次进入1', - key: 1, - }, { - children: '依次进入2', - key: 2, - }], - }, () => { - console.log('exchange: 3'); - this.setState({ - items: [{ - children: '依次进入1', - key: 1, - }, { - children: '依次进入2', - key: 2, - }], - }); - }); - }); - } - - render() { - return ( -
    - - - - - {this.state.items.map((item) => )} - -
    - ); - } -} - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/dynamic.html b/examples/dynamic.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/dynamic.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/dynamic.js b/examples/dynamic.js deleted file mode 100755 index ce3023d..0000000 --- a/examples/dynamic.js +++ /dev/null @@ -1,120 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -class App extends React.Component { - constructor(props) { - super(props); - this.index = 100; - this.state = { - items: [{ - children: '依次进入1', - key: 1, - }, { - children: '依次进入2', - key: 2, - }, { - children: '依次进入3', - key: 3, - }, { - children: '依次进入4', - key: 4, - }, { - children: '依次进入5', - key: 5, - }, { - children: '依次进入6', - key: 6, - }], - type: 'left', - }; - } - - add = () => { - const items = this.state.items; - items.push({ - children: '新节点', - key: this.index++, - }); - this.setState({ items }); - } - addTwo = () => { - const items = this.state.items; - items.push({ - children: '新节点', - key: this.index++, - }); - items.push({ - children: '新节点', - key: this.index++, - }); - this.setState({ items }); - } - remove = (key, e) => { - e.preventDefault(); - const items = this.state.items; - const target = items.filter(item => item.key === key); - let index; - if (target && target[0]) { - index = items.indexOf(target[0]); - } - if (index >= 0) { - items.splice(index, 1); - } - this.setState({ items }); - } - removeAll = () => { - this.setState({ - items: [], - }); - } - removeAndAdd = () => { - const items = this.state.items; - items.splice(items.length - 1, 1); - items.push({ - children: `新节点${Date.now()}`, - key: this.index++, - }); - this.setState({ items }); - } - removeAndAddTow = () => { - const items = this.state.items; - items.splice(items.length - 1, 1); - items.splice(items.length - 2, 1); - items.push({ - children: `新节点${Date.now()}`, - key: this.index++, - }); - items.unshift({ - children: `新节点${Date.now()}-top`, - key: this.index++, - }); - this.setState({ items }); - } - removeTwo = () => { - const items = this.state.items; - items.splice(1, 1); - this.setState({ items }); - } - - render() { - return ( -
    - - - - - - - - {this.state.items.map((item) => )} - -
    - ); - } -} - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/enter-leave.html b/examples/enter-leave.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/enter-leave.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/enter-leave.js b/examples/enter-leave.js deleted file mode 100644 index a907d2e..0000000 --- a/examples/enter-leave.js +++ /dev/null @@ -1,55 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -class App extends React.Component { - constructor(props) { - super(props); - this.state = { - items: [{ - children: '依次进入1', - key: 1, - }, { - children: '依次进入2', - key: 2, - }, { - children: '依次进入3', - key: 3, - }, { - children: '依次进入4', - key: 4, - }, { - children: '依次进入5', - key: 5, - }, { - children: '依次进入6', - key: 6, - }], - }; - } - - removeAll = () => { - this.setState({ - items: [], - }); - } - - render() { - return ( -
    - - {this.state.items.map((item) =>
    - {item.children} -
    )} -
    - -
    - ); - } -} - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/monkey-click.html b/examples/monkey-click.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/monkey-click.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/monkey-click.js b/examples/monkey-click.js deleted file mode 100644 index dcff407..0000000 --- a/examples/monkey-click.js +++ /dev/null @@ -1,54 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -class App extends React.Component { - constructor(props) { - super(props); - this.state = { - show: true, - items: [{ - children: '依次进入1', - key: 1, - }, { - children: '依次进入2', - key: 2, - }, { - children: '依次进入3', - key: 3, - }, { - children: '依次进入4', - key: 4, - }, { - children: '依次进入5', - key: 5, - }, { - children: '依次进入6', - key: 6, - }], - }; - } - - toggle = () => { - this.setState({ - show: !this.state.show, - }); - } - - render() { - return ( -
    - - {this.state.show ? '显示' : '隐藏'} - - {this.state.show ? this.state.items.map((item) =>
    - {item.children} -
    ) : null} -
    -
    - ); - } -} - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/nested.html b/examples/nested.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/nested.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/nested.js b/examples/nested.js deleted file mode 100644 index ec607f9..0000000 --- a/examples/nested.js +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -ReactDom.render( -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    - -
    依次进入
    -
    依次进入
    -
    依次进入
    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -
    -
    , document.getElementById('__react-content')); diff --git a/examples/param-func.html b/examples/param-func.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/param-func.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/param-func.js b/examples/param-func.js deleted file mode 100644 index 29311fa..0000000 --- a/examples/param-func.js +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -class Page1 extends React.Component { - constructor(props) { - super(props); - this.state = { - show: true, - }; - } - - onClick = () => { - this.setState({ - show: !this.state.show, - }); - } - animConfigFunc = (e) => { - if (e.key === '3') { - return { opacity: [1, 0], translateX: [0, 30] }; - } - return [{ opacity: [1, 0], translateX: [0, -30] }, { opacity: [1, 0], translateX: [0, 30] }]; - } - durationFunc = (e) => { - if (e.key === '3') { - return [1500, 4000]; - } - return 500; - } - easeFunc = (e) => { - if (e.key === '3') { - return ['easeOutBack', 'easeInBack']; - } - return 'easeInOutQuart'; - } - delayFunc = (e) => { - if (e.index >= 3) { - return [1500, 0]; - } - return 0; - } - render() { - return (
    - - - {this.state.show ? [
    依次进入
    , -
    依次进入
    , -
    改变type
    , -
    依次进入
    , -
    依次进入
    ] : null} -
    -
    - ); - } -} - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/router.html b/examples/router.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/router.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/shortcut.html b/examples/shortcut.html deleted file mode 100644 index 48cdce8..0000000 --- a/examples/shortcut.html +++ /dev/null @@ -1 +0,0 @@ -placeholder diff --git a/examples/shortcut.js b/examples/shortcut.js deleted file mode 100644 index 2a66d93..0000000 --- a/examples/shortcut.js +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -ReactDom.render(
    -

    left

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -

    top

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -

    right (default)

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -

    bottom

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -

    alpha

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -

    scale

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -

    scaleBig

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -

    scaleX

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -

    scaleY

    - -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    -
    , document.getElementById('__react-content')); diff --git a/examples/simple.html b/examples/simple.html deleted file mode 100644 index b3a4252..0000000 --- a/examples/simple.html +++ /dev/null @@ -1 +0,0 @@ -placeholder \ No newline at end of file diff --git a/examples/simple.js b/examples/simple.js deleted file mode 100644 index 4918f48..0000000 --- a/examples/simple.js +++ /dev/null @@ -1,12 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -ReactDom.render( -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    依次进入
    -
    , document.getElementById('__react-content')); diff --git a/examples/switch-forcedReplay.html b/examples/switch-forcedReplay.html deleted file mode 100644 index b3a4252..0000000 --- a/examples/switch-forcedReplay.html +++ /dev/null @@ -1 +0,0 @@ -placeholder \ No newline at end of file diff --git a/examples/switch-forcedReplay.js b/examples/switch-forcedReplay.js deleted file mode 100644 index ea8d815..0000000 --- a/examples/switch-forcedReplay.js +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; -import './assets/switch.less'; - -class Demo extends React.Component { - constructor(props) { - super(props); - this.childrenKey = [ - { key: 1 }, - { key: 2 }, - { key: 3 }, - { key: 4 }, - { key: 5 }, - { key: 6 }, - ]; - this.state = { - childrenKey: this.childrenKey, - }; - } - - onEnter = () => { - this.setState({ - childrenKey: null, - }); - }; - - onLeave = () => { - this.setState({ - childrenKey: this.childrenKey, - }); - }; - - getChildren = () => { - return (this.state.childrenKey || []).map(item => { - return (
  • ); - }); - }; - - render() { - const childrenToRender = this.getChildren(); - return (
    -

    鼠标经过当前区域,再移出区域查看

    -

    清除所有还在动画的参素并设置切换时的初始参数

    -
    - - {childrenToRender} - - - {childrenToRender} - - - {childrenToRender} - -
    -
    ); - } -} - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/switch.html b/examples/switch.html deleted file mode 100644 index b3a4252..0000000 --- a/examples/switch.html +++ /dev/null @@ -1 +0,0 @@ -placeholder \ No newline at end of file diff --git a/examples/switch.js b/examples/switch.js deleted file mode 100644 index 111de08..0000000 --- a/examples/switch.js +++ /dev/null @@ -1,60 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; -import './assets/switch.less'; - -class Demo extends React.Component { - constructor(props) { - super(props); - this.childrenKey = [ - { key: 1 }, - { key: 2 }, - { key: 3 }, - { key: 4 }, - { key: 5 }, - { key: 6 }, - ]; - this.state = { - childrenKey: this.childrenKey, - }; - } - - onEnter = () => { - this.setState({ - childrenKey: null, - }); - }; - - onLeave = () => { - this.setState({ - childrenKey: this.childrenKey, - }); - }; - - getChildren = () => { - return (this.state.childrenKey || []).map(item => { - return (
  • ); - }); - }; - - render() { - const childrenToRender = this.getChildren(); - return (
    -

    鼠标经过当前区域,再移出区域查看

    -
    - - {childrenToRender} - - - {childrenToRender} - - - {childrenToRender} - -
    -
    ); - } -} - -ReactDom.render(, document.getElementById('__react-content')); diff --git a/examples/timeline.html b/examples/timeline.html deleted file mode 100644 index b3a4252..0000000 --- a/examples/timeline.html +++ /dev/null @@ -1 +0,0 @@ -placeholder \ No newline at end of file diff --git a/examples/timeline.js b/examples/timeline.js deleted file mode 100644 index a7706dc..0000000 --- a/examples/timeline.js +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable no-console,react/no-multi-comp */ -import QueueAnim from 'rc-queue-anim'; -import React from 'react'; -import ReactDom from 'react-dom'; - -const children = [
    依次进入
    , -
    依次进入
    , -
    依次进入
    , -
    依次进入
    , -]; -class Demo extends React.Component { - constructor(props) { - super(props); - this.state = { - children, - }; - } - - onClick = () => { - if (this.state.children) { - this.setState({ children: null }); - } else { - this.setState({ children }); - } - } - - render() { - return (
    - - - {this.state.children} - -
    ); - } -} -ReactDom.render(, document.getElementById('__react-content')); diff --git a/now.json b/now.json new file mode 100644 index 0000000..d7e4fdb --- /dev/null +++ b/now.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "name": "rc-queue-anim", + "builds": [ + { + "src": "package.json", + "use": "@now/static-build", + "config": { "distDir": ".doc" } + } + ] +} diff --git a/package.json b/package.json index a9a864d..c2c917f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-queue-anim", - "version": "1.8.5", + "version": "2.0.0-beta.0", "description": "Queue animation component for react", "keywords": [ "react", @@ -19,7 +19,7 @@ "ant-motion" ], "homepage": "https://github.com/react-component/queue-anim", - "author": "afc163@gmail.com", + "author": "155259966@qq.com", "repository": { "type": "git", "url": "https://github.com/react-component/queue-anim.git" @@ -37,58 +37,55 @@ "licenses": "MIT", "main": "./lib/index", "module": "./es/index", - "config": { - "port": 8001, - "entry": { - "rc-queue-anim": [ - "./assets/index.less", - "./src/index.js" - ] - } - }, "scripts": { - "dist": "rc-tools run dist", - "build": "rc-tools run build", - "gh-pages": "rc-tools run gh-pages", - "start": "rc-tools run server", - "compile": "rc-tools run compile --babel-runtime", - "pub": "rc-tools run pub --babel-runtime", - "lint": "rc-tools run lint -fix", - "karma": "rc-test run karma", - "saucelabs": "rc-test run saucelabs", - "test": "rc-test run test", - "prettier": "rc-tools run prettier", - "chrome-test": "rc-test run chrome-test", - "coverage": "rc-test run coverage", - "validate": "npm ls" + "start": "dumi dev", + "docs:build": "dumi build", + "docs:deploy": "gh-pages -d docs-dist", + "compile": "father-build", + "deploy": "npm run docs:build && npm run docs:deploy", + "prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"", + "test": "umi-test test", + "test:coverage": "umi-test --coverage", + "prepublishOnly": "npm run compile && np --tag=beta --no-cleanup --yolo --no-publish --any-branch", + "lint": "eslint src/ --fix --ext .tsx,.ts", + "lint:tsc": "tsc -p tsconfig.json --noEmit", + "now-build": "npm run docs:build" }, "devDependencies": { - "@types/react": "^16.0.0", - "antd": "4.x", - "core-js": "^3.2.1", - "expect.js": "0.3.x", - "precommit-hook": "^3.0.0", - "rc-dialog": "~8.4.0", - "rc-test": "6.x", - "rc-tools": "8.x", - "react": "^16.0.0", - "react-dom": "^16.0.0", - "react-router": "~4.3.1", - "react-router-dom": "^4.1.0", - "react-test-renderer": "^16.0.0", - "tslint-config-prettier": "^1.17.0", - "tslint-react": "^5.0.0", - "typescript": "4.x" + "@ant-design/icons": "^4.3.0", + "@types/enzyme": "^3.10.5", + "@types/jest": "^25.2.1", + "@types/lodash": "^4.14.135", + "@types/react": "^16.8.19", + "@types/react-dom": "^16.8.4", + "@umijs/test": "^3.2.28", + "antd": "^4.8.4", + "dumi": "^1.1.19", + "eslint": "^7.14.0", + "father": "^2.22.6", + "father-build": "^1.18.6", + "gh-pages": "^3.1.0", + "husky": "^4.3.0", + "np": "^6.0.3", + "prettier": "^2.1.2", + "react": "^16.9.0", + "react-dom": "^16.9.0", + "regenerator-runtime": "^0.13.7", + "typescript": "^4.0.2" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" }, "dependencies": { - "babel-runtime": "6.x", - "prop-types": "^15.6.0", - "rc-tween-one": "^2.5.0", - "react-lifecycles-compat": "^3.0.4" + "@babel/runtime": "^7.11.1", + "rc-tween-one": "^3.0.0-beta.11" }, - "types": "index.d.ts", - "pre-commit": [ - "lint", - "test" - ] + "husky": { + "hooks": { + "pre-commit": [ + "npm run lint" + ] + } + } } diff --git a/src/QueueAnim.jsx b/src/QueueAnim.jsx deleted file mode 100644 index c54fab0..0000000 --- a/src/QueueAnim.jsx +++ /dev/null @@ -1,571 +0,0 @@ -import React, { createElement } from 'react'; -import PropTypes from 'prop-types'; -import TweenOne, { ticker } from 'rc-tween-one'; -import { polyfill } from 'react-lifecycles-compat'; - -import { - toArrayChildren, - findChildInChildrenByKey, - windowIsUndefined, - mergeChildren, - transformArguments, - getChildrenFromProps, -} from './utils'; -import AnimTypes from './animTypes'; - -const noop = () => {}; - -const typeDefault = [ - 'displayName', - 'propTypes', - 'getDefaultProps', - 'defaultProps', - 'childContextTypes', - 'contextTypes', - 'contextType', -]; - -class QueueAnim extends React.Component { - static propTypes = { - children: PropTypes.any, - component: PropTypes.any, - componentProps: PropTypes.object, - interval: PropTypes.any, - duration: PropTypes.any, - delay: PropTypes.any, - type: PropTypes.any, - animConfig: PropTypes.any, - ease: PropTypes.any, - leaveReverse: PropTypes.bool, - forcedReplay: PropTypes.bool, - animatingClassName: PropTypes.array, - onEnd: PropTypes.func, - appear: PropTypes.bool, - }; - - static defaultProps = { - component: 'div', - componentProps: {}, - interval: 100, - duration: 450, - delay: 0, - type: 'right', - animConfig: null, - ease: 'easeOutQuart', - leaveReverse: false, - forcedReplay: false, - animatingClassName: ['queue-anim-entering', 'queue-anim-leaving'], - onEnd: noop, - appear: true, - }; - - static getDerivedStateFromProps( - props, - { prevProps, children, childrenShow: prevChildShow, $self }, - ) { - const nextState = { - prevProps: props, - }; - if (prevProps && props !== prevProps) { - const nextChildren = toArrayChildren(props.children).filter(c => c); - let currentChildren = $self.originalChildren.filter(item => item); - if (children.length) { - /** - * 多次刷新处理 - * 如果 state.children 里还有元素,元素还在动画,当前子级加回在出场的子级; - */ - const leaveChild = children.filter( - item => item && $self.keysToLeave.indexOf(item.key) >= 0, - ); - $self.leaveUnfinishedChild = leaveChild - .map(item => { - if ($self.placeholderTimeoutIds[item.key]) { - return item.key; - } - return null; - }) - .filter(c => c); - /** - * 获取 leaveChild 在 state.children 里的序列,再将 leaveChild 和 currentChildren 的重新排序。 - * 避逸 state.children 在 leaveComplete 里没全部完成不触发, - * leaveComplete 里如果动画完成了是会删除 keyToLeave,但 state.children 是在全部出场后才触发清除, - * 所以这里需要处理出场完成的元素做清除。 - */ - const stateChildren = mergeChildren(currentChildren, children); - const currentChild = []; - const childReOrder = child => { - child.forEach(item => { - const order = stateChildren.findIndex(c => c.key === item.key); - if (currentChild.indexOf(item) !== -1) { - return; - } - // -1 不应该出现的情况,直接插入数组后面. - if (order === -1) { - currentChild.push(item); - } else { - currentChild.splice(order, 0, item); - } - }); - }; - childReOrder(leaveChild); - childReOrder(currentChildren); - currentChildren = currentChild.filter(c => c); - } - const newChildren = mergeChildren(currentChildren, nextChildren); - const childrenShow = !newChildren.length ? {} : prevChildShow; - $self.keysToEnterPaused = {}; - const emptyBool = !nextChildren.length && !currentChildren.length && children.length; - /** - * 在出场没结束时,childrenShow 里的值将不会清除。 - * 再触发进场时, childrenShow 里的值是保留着的, 设置了 forcedReplay 将重新播放进场。 - */ - if (!emptyBool) { - // 空子级状态下刷新不做处理 - const nextKeys = nextChildren.map(c => c.key); - $self.keysToLeave.forEach(key => { - // 将所有在出场里的停止掉。避免间隔性出现 - if (nextKeys.indexOf(key) >= 0) { - $self.keysToEnterPaused[key] = true; - currentChildren = currentChildren.filter(item => item.key !== key); - if (props.forcedReplay) { - // 清掉所有出场的。 - delete childrenShow[key]; - } - } - }); - } - - $self.keysToEnter = []; - $self.keysToLeave = []; - - // need render to avoid update - nextState.childrenShow = childrenShow; - nextState.children = newChildren; - - nextChildren.forEach(c => { - if (!c) { - return; - } - const key = c.key; - const hasPrev = findChildInChildrenByKey(currentChildren, key); - if (!hasPrev && key) { - $self.keysToEnter.push(key); - } - }); - - currentChildren.forEach(c => { - if (!c) { - return; - } - const key = c.key; - const hasNext = findChildInChildrenByKey(nextChildren, key); - if (!hasNext && key) { - $self.keysToLeave.push(key); - ticker.clear($self.placeholderTimeoutIds[key]); - delete $self.placeholderTimeoutIds[key]; - } - }); - } - return nextState; - } - constructor(props) { - super(props); - /** - * @param tweenToEnter; - * 记录强制切换时是否需要添加 animation; - * 如 enter 后, leave -> enter,样式是没有发生变化,就不需要添加 animation 属性。 - */ - this.tweenToEnter = {}; - /** - * @param leaveUnfinishedChild; - * 记录多次切换,出场没完成动画的 key。 - */ - this.leaveUnfinishedChild = []; - /** - * @param saveTweenOneTag; - * 记录 TweenOne 标签,在 leaveUnfinishedChild 里使用,残留的元素不需要考虑 props 的变更。 - */ - this.saveTweenOneTag = {}; - /** - * @param childrenShow; - * 记录 animation 里是否需要 startAnim; - * 当前元素是否处在显示状态 - * enterBegin 到 leaveComplete 之前都处于显示状态 - */ - this.childrenShow = {}; - /** - * @param keysToEnter; - * 记录进场的 key; - */ - this.keysToEnter = []; - /** - * @param keysToLeave; - * 记录出场的 key; - */ - this.keysToLeave = []; - /** - * @param keysToEnterPaused; - * 记录在进入时是否处理暂停状态 - */ - this.keysToEnterPaused = {}; - /** - * @param placeholderTimeoutIds; - * 进场时 deley 的 timeout 记录; - */ - this.placeholderTimeoutIds = {}; - /** - * @param childRefs; - * 储存 children 的 ref; - */ - this.childRefs = {}; - /** - * @param currentRef; - * 记录 component 是组件时的 ref; - */ - this.currentRef = null; - // 第一次进入,默认进场 - const children = toArrayChildren(getChildrenFromProps(props)); - const childrenShow = {}; - children.forEach(child => { - if (!child || !child.key) { - return; - } - if (this.props.appear) { - this.keysToEnter.push(child.key); - } else { - childrenShow[child.key] = true; - this.tweenToEnter[child.key] = true; - } - }); - this.originalChildren = toArrayChildren(getChildrenFromProps(props)); - this.state = { - children, - childrenShow, - $self: this, - }; - } - - componentDidMount() { - if (this.props.appear) { - this.componentDidUpdate(); - } - } - - componentDidUpdate() { - this.originalChildren = toArrayChildren(getChildrenFromProps(this.props)); - const keysToEnter = [...this.keysToEnter]; - const keysToLeave = [...this.keysToLeave]; - keysToEnter.forEach(this.performEnter); - keysToLeave.forEach(this.performLeave); - } - - componentWillUnmount() { - Object.keys(this.placeholderTimeoutIds).forEach(key => { - ticker.clear(this.placeholderTimeoutIds[key]); - }); - this.keysToEnter = []; - this.keysToLeave = []; - this.childrenShow = {}; - } - - getTweenType(type, num) { - const data = AnimTypes[type]; - return this.getTweenAnimConfig(data, num); - } - - getTweenSingleConfig = (data, num, enterOrLeave) => { - const obj = {}; - Object.keys(data).forEach(key => { - if (Array.isArray(data[key])) { - obj[key] = data[key][num]; - } else if ((!enterOrLeave && !num) || (enterOrLeave && num)) { - obj[key] = data[key]; - } - }); - return obj; - }; - - getTweenAnimConfig(data, num, enterOrLeave) { - if (Array.isArray(data)) { - return data.map(item => { - return this.getTweenSingleConfig(item, num, enterOrLeave); - }); - } - return this.getTweenSingleConfig(data, num, enterOrLeave); - } - - getTweenData = (key, i, type) => { - const props = this.props; - const enterOrLeave = type === 'enter' ? 0 : 1; - const start = type === 'enter' ? 1 : 0; - const end = type === 'enter' ? 0 : 1; - const animate = this.getAnimData(props, key, i, enterOrLeave, end); - const startAnim = - type === 'enter' && (props.forcedReplay || !this.childrenShow[key]) - ? this.getAnimData(props, key, i, enterOrLeave, start) - : null; - let ease = transformArguments(props.ease, key, i)[enterOrLeave]; - const duration = transformArguments(props.duration, key, i)[enterOrLeave]; - if (Array.isArray(ease)) { - ease = ease.map(num => num * 100); - ease = TweenOne.easing.path( - `M0,100C${ease[0]},${100 - ease[1]},${ease[2]},${100 - ease[3]},100,0`, - { lengthPixel: duration / 16.6667 }, - ); - } - return { startAnim, animate, ease, duration, isArray: Array.isArray(animate) }; - }; - - getTweenSingleData = (startAnim, animate, ease, duration, delay, onStart, onComplete) => { - const startLength = Object.keys(startAnim || {}).length; - const animation = { - onStart, - onComplete, - duration, - delay, - ease, - ...animate, - }; - const startAnimate = startLength ? { duration: 0, ...startAnim } : null; - return { animation, startAnimate }; - }; - - getTweenEnterOrLeaveData = (key, i, delay, type) => { - let animateData = this.getTweenData(key, i, type); - const startAnim = animateData.startAnim; - const animate = animateData.animate; - const onStart = (type === 'enter' ? this.enterBegin : this.leaveBegin).bind(this, key); - const onComplete = (type === 'enter' ? this.enterComplete : this.leaveComplete).bind(this, key); - if (animateData.isArray) { - const length = animate.length - 1; - const animation = []; - const startArray = []; - animate.forEach((leave, ii) => { - const start = startAnim && startAnim[ii]; - const animObj = this.getTweenSingleData( - start, - leave, - animateData.ease, - animateData.duration / length, - !ii ? delay : 0, - !ii ? onStart : null, - ii === length ? onComplete : null, - ); - animation.push(animObj.animation); - if (animObj.startAnimate) { - startArray.push(animObj.startAnimate); - } - }); - return startArray.concat(animation); - } - animateData = this.getTweenSingleData( - startAnim, - animate, - animateData.ease, - animateData.duration, - delay, - onStart, - onComplete, - ); - return [animateData.startAnimate, animateData.animation].filter(item => item); - }; - - getAnimData = (props, key, i, enterOrLeave, startOrEnd) => { - /** - * transformArguments 第一个为 enter, 第二个为 leave; - * getTweenAnimConfig or getTweenType 第一个为到达的位置, 第二个为开始的位置。 - * 用 tween-one 的数组来实现老的动画逻辑。。。 - */ - return props.animConfig - ? this.getTweenAnimConfig( - transformArguments(props.animConfig, key, i)[enterOrLeave], - startOrEnd, - enterOrLeave, - ) - : this.getTweenType(transformArguments(props.type, key, i)[enterOrLeave], startOrEnd); - }; - - getChildrenToRender = child => { - const { forcedReplay, leaveReverse, delay, interval, children } = this.props; - if (!child || !child.key) { - return child; - } - const key = child.key; - if (!this.state.childrenShow[key]) { - return null; - } - let i = this.keysToLeave.indexOf(key); - let animation; - const isFunc = typeof child.type === 'function'; - const forcedJudg = isFunc ? {} : null; - if (isFunc) { - Object.keys(child.type).forEach(name => { - if (typeDefault.indexOf(name) === -1) { - forcedJudg[name] = child.type[name]; - } - }); - } - let ref = () => { - delete this.childRefs[key]; - }; - // 处理出场 - if (i >= 0) { - if (this.leaveUnfinishedChild.indexOf(key) >= 0) { - return this.saveTweenOneTag[key]; - } - const $interval = transformArguments(interval, key, i)[1]; - let $delay = transformArguments(delay, key, i)[1]; - // 减掉 leaveUnfinishedChild 里的个数,因为 leaveUnfinishedChild 是旧的出场,不应该计录在队列里。 - const order = - (leaveReverse ? this.keysToLeave.length - i - 1 : i) - this.leaveUnfinishedChild.length; - $delay = $interval * order + $delay; - animation = this.getTweenEnterOrLeaveData(key, i, $delay, 'leave'); - } else { - // 处理进场; - i = toArrayChildren(children).findIndex(c => c && c.key === key); - ref = c => { - this.childRefs[key] = c && c.currentRef ? c.currentRef : c; - }; - // appear=false 时,设定 childrenShow 和 tweenToEnter 都为 true, 这里不渲染 animation; - if (this.tweenToEnter[key] && !forcedReplay) { - // 如果是已进入的,将直接返回标签。。 - return createElement(TweenOne, { - key, - component: child.type, - forcedJudg, - componentProps: child.props, - ref, - }); - } - if (!this.tweenToEnter[key] || forcedReplay) { - animation = this.getTweenEnterOrLeaveData(key, i, 0, 'enter'); - } - } - const paused = this.keysToEnterPaused[key] && this.keysToLeave.indexOf(key) === -1; - animation = paused ? null : animation; - const tag = createElement(TweenOne, { - key, - component: child.type, - forcedJudg, - componentProps: child.props, - animation, - ref, - }); - this.saveTweenOneTag[key] = tag; - return tag; - }; - - performEnter = (key, i) => { - const interval = transformArguments(this.props.interval, key, i)[0]; - const delay = transformArguments(this.props.delay, key, i)[0]; - this.placeholderTimeoutIds[key] = ticker.timeout( - this.performEnterBegin.bind(this, key), - interval * i + delay, - ); - if (this.keysToEnter.indexOf(key) >= 0) { - this.keysToEnter.splice(this.keysToEnter.indexOf(key), 1); - } - }; - - performEnterBegin = key => { - const childrenShow = this.state.childrenShow; - childrenShow[key] = true; - delete this.keysToEnterPaused[key]; - ticker.clear(this.placeholderTimeoutIds[key]); - delete this.placeholderTimeoutIds[key]; - this.setState({ childrenShow }); - }; - - performLeave = key => { - ticker.clear(this.placeholderTimeoutIds[key]); - delete this.placeholderTimeoutIds[key]; - }; - - enterBegin = (key, e) => { - const elem = e.target; - const animatingClassName = this.props.animatingClassName; - elem.className = elem.className.replace(animatingClassName[1], ''); - if (elem.className.indexOf(animatingClassName[0]) === -1) { - elem.className = `${elem.className} ${animatingClassName[0]}`.trim(); - } - this.childrenShow[key] = true; - }; - - enterComplete = (key, e) => { - if (this.keysToEnterPaused[key] || this.keysToLeave.indexOf(key) >= 0) { - return; - } - const elem = e.target; - elem.className = elem.className.replace(this.props.animatingClassName[0], '').trim(); - this.tweenToEnter[key] = true; - this.props.onEnd({ key, type: 'enter', target: elem }); - }; - - leaveBegin = (key, e) => { - const elem = e.target; - const animatingClassName = this.props.animatingClassName; - elem.className = elem.className.replace(animatingClassName[0], ''); - if (elem.className.indexOf(animatingClassName[1]) === -1) { - elem.className = `${elem.className} ${animatingClassName[1]}`.trim(); - } - delete this.tweenToEnter[key]; - }; - - leaveComplete = (key, e) => { - // 切换时同时触发 onComplete。 手动跳出。。。 - if (toArrayChildren(this.props.children).findIndex(c => c && c.key === key) >= 0) { - return; - } - const childrenShow = this.state.childrenShow; - delete childrenShow[key]; - delete this.saveTweenOneTag[key]; - delete this.childrenShow[key]; - if (this.keysToLeave.indexOf(key) >= 0) { - this.keysToLeave.splice(this.keysToLeave.indexOf(key), 1); - } - const needLeave = this.keysToLeave.some(c => childrenShow[c]); - if (!needLeave) { - const currentChildren = toArrayChildren(getChildrenFromProps(this.props)); - this.setState({ - children: currentChildren, - childrenShow, - }); - } - const elem = e.target; - elem.className = elem.className.replace(this.props.animatingClassName[1], '').trim(); - this.props.onEnd({ key, type: 'leave', target: elem }); - }; - - render() { - const { - component, - componentProps, - interval, - duration, - delay, - type, - animConfig, - ease, - leaveReverse, - animatingClassName, - forcedReplay, - onEnd, - appear, - ...tagProps - } = this.props; - if (windowIsUndefined) { - return createElement(component, { ...tagProps, ...componentProps }, this.props.children); - } - const childrenToRender = toArrayChildren(this.state.children).map(this.getChildrenToRender); - const props = { - ...tagProps, - ...this.props.componentProps, - ref: c => { - this.currentRef = c; - }, - }; - return createElement(this.props.component, props, childrenToRender); - } -} -QueueAnim.isQueueAnim = true; -export default polyfill(QueueAnim); diff --git a/src/QueueAnim.tsx b/src/QueueAnim.tsx new file mode 100644 index 0000000..3102f04 --- /dev/null +++ b/src/QueueAnim.tsx @@ -0,0 +1,439 @@ +import { + useRef, + useMemo, + useLayoutEffect, + useEffect, + useState, + createElement, + cloneElement, + forwardRef, +} from 'react'; +import { findDOMNode } from 'react-dom'; +import TweenOne, { Ticker } from 'tween-one'; + +import { + toArrayChildren, + findChildInChildrenByKey, + windowIsUndefined, + mergeChildren, + transformArguments, +} from './utils'; +import AnimTypes from './animTypes'; + +import { IObject, IProps, IKeys, IQueueType } from './type'; + +const noop = () => {}; + +export default forwardRef((props: IProps, ref: any) => { + const { + component = 'div', + componentProps = {}, + interval = 100, + duration = 450, + delay = 0, + type = 'right', + animConfig = null, + ease = 'easeOutQuart', + leaveReverse = false, + forcedReplay = false, + animatingClassName = ['queue-anim-entering', 'queue-anim-leaving'], + onEnd = noop, + appear = true, + ...tagProps + } = props; + + /** + * @param childrenShow; + * 记录 animation 里是否需要 startAnim; + * 当前元素是否处在显示状态 + * enterBegin 到 leaveComplete 之前都处于显示状态 + */ + const childrenShow = useRef({}); + + /** + * @param keysToEnter; + * 记录进场的 key; + */ + const keysToEnter = useRef([]); + const recordKeysToEnter = useRef([]); + /** + * @param keysToLeave; + * 记录出场的 key; + */ + const keysToLeave = useRef([]); + const recordKeysToLeave = useRef([]); + + /** + * @param placeholderTimeoutIds; + * 进场时 deley 的 timeout 记录; + */ + const placeholderTimeoutIds = useRef({}); + /** + * @param childRefs; + * 储存 children 的 ref; + */ + const childRefs = useRef({}); + /** + * @param recordAnimKeys; + * 记录启动动画 key + */ + const recordAnimKeys = useRef({}); + + /** + * @param recordAnimKeys; + * 记录启动动画 key + */ + const recordTweenKeys = useRef({}); + + /** + * @param oneEnterBool + * 记录第一次进入 + */ + const oneEnterBool = useRef(false); + + const originalChildren = useRef([]); + + const [child, setChild] = useState(); + const [childShow, setChildShow] = useState({}); + + const getTweenSingleConfig = (data: any, num: number, enterOrLeave?: 0 | 1) => { + const obj: IObject = {}; + Object.keys(data).forEach((key) => { + if (Array.isArray(data[key])) { + obj[key] = data[key][num]; + } else if ((!enterOrLeave && !num) || (enterOrLeave && num)) { + obj[key] = data[key]; + } + }); + return obj; + }; + + const getTweenAnimConfig = (data: any, num: number, enterOrLeave?: 0 | 1) => { + if (Array.isArray(data)) { + return data.map((item) => { + return getTweenSingleConfig(item, num, enterOrLeave); + }); + } + return getTweenSingleConfig(data, num, enterOrLeave); + }; + + const getTweenType = (type: IQueueType, num: number) => { + const data = AnimTypes[type]; + return getTweenAnimConfig(data, num); + }; + + const getAnimData = (key: string | number, i: number, enterOrLeave: 0 | 1, startOrEnd: 0 | 1) => + /** + * transformArguments 第一个为 enter, 第二个为 leave; + * getTweenAnimConfig or getTweenType 第一个为到达的位置, 第二个为开始的位置。 + * 用 tween-one 的数组来实现老的动画逻辑。。。 + */ + animConfig + ? getTweenAnimConfig( + transformArguments(animConfig, key, i)[enterOrLeave], + startOrEnd, + enterOrLeave, + ) + : getTweenType(transformArguments(type, key, i)[enterOrLeave], startOrEnd); + + const getTweenData = (key: string | number, i: number, type: string) => { + const enterOrLeave = type === 'enter' ? 0 : 1; + const start = type === 'enter' ? 1 : 0; + const end = type === 'enter' ? 0 : 1; + const animate = getAnimData(key, i, enterOrLeave, end); + const startAnim = + type === 'enter' && (forcedReplay || !childrenShow.current[key]) + ? getAnimData(key, i, enterOrLeave, start) + : null; + let $ease = transformArguments(ease, key, i)[enterOrLeave]; + const $duration = transformArguments(duration, key, i)[enterOrLeave]; + if (Array.isArray(ease) && (ease.length > 2 || Array.isArray(ease[0]))) { + $ease = $ease.map((num: number) => num * 100); + $ease = `M0,100C${$ease[0]},${100 - $ease[1]},${$ease[2]},${100 - $ease[3]},100,0`; + } + return { + startAnim, + animate, + ease: $ease, + duration: $duration, + }; + }; + + const enterBegin = (key: string | number, e: any) => { + const elem = e.targets; + elem.className = elem.className.replace(animatingClassName[1], ''); + if (elem.className.indexOf(animatingClassName[0]) === -1) { + elem.className = `${elem.className} ${animatingClassName[0]}`.trim(); + } + if (keysToEnter.current.indexOf(key) >= 0) { + keysToEnter.current.splice(keysToEnter.current.indexOf(key), 1); + } + childrenShow.current[key] = true; + }; + const enterComplete = (key: string | number, e: any) => { + if (keysToLeave.current.indexOf(key) >= 0) { + return; + } + const elem = e.targets; + elem.className = elem.className.replace(animatingClassName[0], '').trim(); + delete recordTweenKeys.current[key]; + onEnd({ key, type: 'enter', target: elem }); + }; + + const leaveBegin = (key: string | number, e: any) => { + const elem = e.targets; + elem.className = elem.className.replace(animatingClassName[0], ''); + if (elem.className.indexOf(animatingClassName[1]) === -1) { + elem.className = `${elem.className} ${animatingClassName[1]}`.trim(); + } + }; + + const leaveComplete = (key: string | number, e: any) => { + // 切换时同时触发 onComplete。 手动跳出。。。 + toArrayChildren(props.children).findIndex((c) => c && c.key === key); + if (toArrayChildren(props.children).findIndex((c) => c && c.key === key) >= 0) { + return; + } + delete childrenShow.current[key]; + delete recordTweenKeys.current[key]; + originalChildren.current = originalChildren.current.filter((c) => c.key !== key); + // 这里不用启动动画,,直接删; + if (keysToLeave.current.indexOf(key) >= 0) { + keysToLeave.current.splice(keysToLeave.current.indexOf(key), 1); + } + const needLeave = keysToLeave.current.some((c) => childShow[c]); + + if (!needLeave) { + const currentChildren = toArrayChildren(props.children); + setChild(currentChildren); + setChildShow({ ...childrenShow.current }); + recordKeysToLeave.current.forEach((k) => { + delete recordAnimKeys.current[k]; + }); + } + const elem = e.targets; + elem.className = elem.className.replace(animatingClassName[1], '').trim(); + onEnd({ key, type: 'leave', target: elem }); + }; + + const performEnterBegin = (key: string | number) => { + childShow[key] = true; + Ticker.clear(placeholderTimeoutIds.current[key]); + delete placeholderTimeoutIds.current[key]; + setChildShow({ ...childShow }); + }; + + const performEnter = (key: string | number, i: number) => { + const $interval = transformArguments(interval, key, i)[0]; + const $delay = transformArguments(delay, key, i)[0]; + placeholderTimeoutIds.current[key] = Ticker.timeout(() => { + performEnterBegin(key); + }, $interval * i + $delay); + }; + + const performLeave = (key: string | number, i: number) => { + Ticker.clear(placeholderTimeoutIds.current[key]); + delete placeholderTimeoutIds.current[key]; + }; + + const getTweenOneEnterOrLeave = ( + key: string | number, + i: number, + delay: number, + type: string, + ) => { + const animateData = getTweenData(key, i, type); + const onStart = (type === 'enter' ? enterBegin : leaveBegin).bind(this, key); + const onComplete = (type === 'enter' ? enterComplete : leaveComplete).bind(this, key); + if (Array.isArray(animateData.animate)) { + const length = animateData.animate.length - 1; + const animation = animateData.animate.map((item, ii) => { + return { + ...item, + startAt: animateData.startAnim ? animateData.startAnim[ii] : undefined, + duration: animateData.duration / length, + delay: !ii && type === 'leave' ? delay : 0, + onStart: !ii ? onStart : undefined, + onComplete: ii === length ? onComplete : undefined, + }; + }); + return animation; + } + return { + ...animateData.animate, + startAt: animateData.startAnim || undefined, + ease: animateData.ease, + duration: animateData.duration, + onStart, + onComplete, + delay, + }; + }; + useEffect( + () => () => { + Object.keys(recordTweenKeys.current).forEach((key) => { + const tween = recordTweenKeys.current[key]; + if (!tween) { + return; + } + tween.kill(); + }); + }, + [], + ); + useEffect(() => { + const nextChildren = toArrayChildren(props.children).filter((c) => c); + let currentChildren = originalChildren.current.filter((item) => item); + const newChildren = mergeChildren(currentChildren, nextChildren); + const $keysToEnter: IKeys = []; + const $keysToLeave: IKeys = []; + if (!appear && !oneEnterBool.current) { + const $childShow: IObject = {}; + newChildren.forEach((child: any) => { + if (!child || !child.key) { + return; + } + $childShow[child.key] = true; + }); + originalChildren.current = newChildren; + childrenShow.current = { ...$childShow }; + setChildShow($childShow); + } else { + currentChildren.forEach((c) => { + if (!c) { + return; + } + const key = c.key; + const hasNext = findChildInChildrenByKey(nextChildren, key); + if (!hasNext && key) { + $keysToLeave.push(key); + Ticker.clear(placeholderTimeoutIds.current[key]); + delete placeholderTimeoutIds.current[key]; + } + }); + nextChildren.forEach((c: any) => { + if (!c) { + return; + } + + const { key } = c; + const hasPrev = findChildInChildrenByKey(currentChildren, key); + // 如果 nextChildren 和当前的一致,且动画里是出场,改回进场; + if ( + (!hasPrev && key) || + ((recordAnimKeys.current[key] === 'leave' || keysToEnter.current.indexOf(key) >= 0) && + $keysToLeave.indexOf(key) === -1) + ) { + $keysToEnter.push(key); + } + }); + } + // console.log('child update', $keysToEnter, $keysToLeave, newChildren); + + keysToEnter.current = $keysToEnter; + // keysToEnter 在启动时就会删除; + recordKeysToEnter.current = [...$keysToEnter]; + keysToLeave.current = $keysToLeave; + recordKeysToLeave.current = [...$keysToLeave]; + + setChild(newChildren); + }, [props.children]); + useLayoutEffect(() => { + originalChildren.current = child || []; + if (appear || oneEnterBool.current) { + const $keysToEnter = [...keysToEnter.current]; + const $keysToLeave = [...keysToLeave.current]; + $keysToEnter.forEach(performEnter); + $keysToLeave.forEach(performLeave); + } + if (child) { + oneEnterBool.current = true; + } + }, [child]); + useLayoutEffect(() => { + if (child) { + child.forEach((item) => { + const { key } = item; + const dom = childRefs.current[key]; + if (!dom) { + return; + } + let animation; + let index = keysToLeave.current.indexOf(key); //children.findIndex(c => c.key === key); + const $interval = transformArguments(interval, key, index); + let $delay = transformArguments(delay, key, index); + + // 处理出场 + if (index >= 0) { + if (recordAnimKeys.current[key] == 'leave') { + return; + } + + const order = leaveReverse ? keysToLeave.current.length - index - 1 : index; + const d = $interval[1] * order + $delay[1]; + animation = getTweenOneEnterOrLeave(key, index, d, 'leave'); + recordAnimKeys.current[key] = 'leave'; + } else { + if (recordAnimKeys.current[key] === 'enter' || keysToEnter.current.indexOf(key) === -1) { + return; + } + index = recordKeysToEnter.current.indexOf(key); + const d = $interval[0] * index + $delay[0]; + // console.log(recordAnimKeys.current[key], dom); + animation = getTweenOneEnterOrLeave( + key, + index, + recordAnimKeys.current[key] === 'leave' ? d : 0, + 'enter', + ); + recordAnimKeys.current[key] = 'enter'; + } + if (recordTweenKeys.current[key]) { + recordTweenKeys.current[key].kill(); + } + + if (forcedReplay) { + const anim = { + ...(Array.isArray(animation) ? animation[0].startAt : animation.startAt), + type: 'set', + }; + TweenOne(dom, { animation: anim }); + } + recordTweenKeys.current[key] = TweenOne(dom, { + animation, + }); + + }); + } + }, [childShow, child]); + + return useMemo(() => { + // console.log('--------render--------', childShow); + if (windowIsUndefined) { + return createElement(component, { ...tagProps, ...componentProps, ref }); + } + const childrenToRender = toArrayChildren(child).map((item) => { + if (!item || !item.key) { + return item; + } + return ( + childShow[item.key] && + cloneElement(item, { + ref: (c: any) => { + childRefs.current[item.key] = c instanceof Element ? c : findDOMNode(c); + if (!c) { + delete childRefs.current[item.key]; + } + }, + key: item.key, + }) + ); + }); + const p = { + ...tagProps, + ...componentProps, + ref, + }; + return createElement(component, p, childrenToRender); + }, [childShow, child]); +}); diff --git a/src/animTypes.js b/src/animTypes.ts similarity index 100% rename from src/animTypes.js rename to src/animTypes.ts diff --git a/src/index.js b/src/index.tsx similarity index 78% rename from src/index.js rename to src/index.tsx index 8d9810a..df6b330 100644 --- a/src/index.js +++ b/src/index.tsx @@ -2,3 +2,5 @@ import QueueAnim from './QueueAnim'; export default QueueAnim; + +export * from './type'; diff --git a/src/type.ts b/src/type.ts new file mode 100644 index 0000000..2429672 --- /dev/null +++ b/src/type.ts @@ -0,0 +1,59 @@ +import { IObject as IObj } from 'tween-one/lib/typings'; +import { IEaseType as IEase } from 'tween-one/lib/typings/IAnimObject'; +import React from 'react'; + +export type IObject = IObj; + +export type IKeys = (string | number)[]; + +export type IQueueType = + | 'alpha' + | 'left' + | 'right' + | 'top' + | 'bottom' + | 'scale' + | 'scaleBig' + | 'scaleX' + | 'scaleY'; +export type INumberOrArrayOrFunc = + | number + | [number, number] + | ((e: { key: string; index: number }) => number | number[]); +export type IEaseType = IEase | [number, number, number, number]; + +export type IQueueTypeOrArrayOrFunc = + | IQueueType + | [IQueueType, IQueueType] + | ((e: { key: string; index: number }) => IQueueType | [IQueueType, IQueueType]); +export type IEaseTypeOrArrayOrFunc = + | IEaseType + | IEaseType[] + | ((e: { key: string; index: number }) => IEaseType | IEaseType[]); +export type IAnimConfigOrArrayOrFunc = + | {} + | [{}] + | ((e: { key: string; index: number }) => {} | {}[]); + +interface AllHTMLAttributes + extends Omit, 'crossOrigin'>, + React.AllHTMLAttributes {} +export interface IProps extends Omit { + type?: IQueueTypeOrArrayOrFunc; + animConfig?: IAnimConfigOrArrayOrFunc; + delay?: INumberOrArrayOrFunc; + duration?: INumberOrArrayOrFunc; + interval?: INumberOrArrayOrFunc; + leaveReverse?: boolean; + ease?: IEaseTypeOrArrayOrFunc; + appear?: boolean; + component?: + | string + | React.ClassType> + | React.ForwardRefExoticComponent }> + | undefined; + componentProps?: IObject; + animatingClassName?: string[]; + forcedReplay?: boolean; + onEnd?: (e: { key: string | number; type: string; target: HTMLElement }) => void; +} diff --git a/src/utils.js b/src/utils.ts similarity index 70% rename from src/utils.js rename to src/utils.ts index 1643704..829613e 100644 --- a/src/utils.js +++ b/src/utils.ts @@ -1,4 +1,5 @@ /* eslint no-prototype-builtins: 0 */ +import { IObject } from './type'; import React from 'react'; export const windowIsUndefined = !( @@ -7,18 +8,18 @@ export const windowIsUndefined = !( window.document.createElement ); -export function toArrayChildren(children) { - const ret = []; - React.Children.forEach(children, c => { +export function toArrayChildren(children: any) { + const ret: any[] = []; + React.Children.forEach(children, (c) => { ret.push(c); }); return ret; } -export function findChildInChildrenByKey(children, key) { - let ret = null; +export function findChildInChildrenByKey(children: any[], key: string) { + let ret: any = null; if (children) { - children.forEach(c => { + children.forEach((c) => { if (ret || !c) { return; } @@ -30,14 +31,14 @@ export function findChildInChildrenByKey(children, key) { return ret; } -export function mergeChildren(prev, next) { - let ret = []; +export function mergeChildren(prev: any, next: any) { + let ret: any = []; // For each key of `next`, the list of keys to insert before that key in // the combined list - const nextChildrenPending = {}; - let pendingChildren = []; - let followChildrenKey; - prev.forEach(c => { + const nextChildrenPending: IObject = {}; + let pendingChildren: any = []; + let followChildrenKey: any; + prev.forEach((c: any) => { if (!c) { return; } @@ -54,7 +55,7 @@ export function mergeChildren(prev, next) { if (!followChildrenKey) { ret = ret.concat(pendingChildren); } - next.forEach(c => { + next.forEach((c: any) => { if (!c) { return; } @@ -70,7 +71,7 @@ export function mergeChildren(prev, next) { return ret; } -export function transformArguments(arg, key, i) { +export function transformArguments(arg: any, key: string | number, i: number) { let result; if (typeof arg === 'function') { result = arg({ @@ -88,7 +89,3 @@ export function transformArguments(arg, key, i) { } return [result, result]; } - -export function getChildrenFromProps(props) { - return props && props.children; -} diff --git a/tests/index.test.jsx b/tests/index.test.jsx new file mode 100644 index 0000000..610f076 --- /dev/null +++ b/tests/index.test.jsx @@ -0,0 +1,324 @@ +import React, { useState } from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { act } from 'react-dom/test-utils'; + +import QueueAnim from '../src'; + +import TweenOne, { Ticker } from 'tween-one'; + +function getOpacity(node) { + if (!node) { + return NaN; + } + // console.log('node.style.opacity)', node.style) + return parseFloat(node.style.opacity); +} + +function getLeft(node) { + if (!node) { + return NaN; + } + return parseFloat(node.style.left); +} + +function getTop(node) { + if (!node) { + return NaN; + } + return parseFloat(node.style.top); +} + +let container = null; +beforeEach(() => { + // 创建一个 DOM 元素作为渲染目标 + container = document.createElement('div'); + document.body.appendChild(container); + + TweenOne({}, { x: 100, duration: 2000000 }); + //jest.useFakeTimers(); +}); + +afterEach(() => { + // 退出时进行清理 + unmountComponentAtNode(container); + container.remove(); + container = null; + //jest.useRealTimers(); +}); + +const items = [ + { + key: 1, + content: 'div', + }, + { + key: 2, + content: 'div', + }, + { + key: 3, + content: 'div', + }, +]; + +const child = items.map((item) => ( + + {item.content} + +)); + +const QueueAnimComp = (props) => { + const [children, setChildren] = useState(child); + const [unmount, setUnmount] = useState(false); + return ( +
    + {!unmount && ( + + {children} + + )} + + +
    + ); +}; + +const interval = 100; + +function shouldAnimatingThisOne(children, index) { + children.forEach((node, i) => { + console.log(index, i, getOpacity(node)); + if (i <= index) { + expect(getOpacity(node)).toBeGreaterThan(0); + } else { + // placeholder + // expect(node.innerHTML).to.be(''); + } + }); +} + +it('should render children', (done) => { + act(() => { + render({child}, container); + // jest.advanceTimersByTime(50); + }); /* Ticker.timeout 0 会直接返回 + let { children } = container.querySelector('[id=queue]'); + expect(children.length).toBe(0); */ + + const { children } = container.querySelector('[id=queue]'); + + Ticker.timeout(() => { + // shouldAnimatingThisOne(0); + expect(children.length).toBe(1); + done(); + }); +}); + +it('should render all children', () => { + act(() => { + render( + + {child} + , + container, + ); + }); + const { children } = container.querySelector('[id=queue]'); + console.log(children.length); + expect(children.length).toBe(3); +}); + +it('should have queue animation', (done) => { + act(() => { + render({child}, container); + }); + const { children } = container.querySelector('[id=queue]'); + Ticker.timeout(() => { + shouldAnimatingThisOne(children, 0); + Ticker.timeout(() => { + shouldAnimatingThisOne(children, 1); + Ticker.timeout(() => { + shouldAnimatingThisOne(children, 2); + done(); + }, interval); + }, interval); + }, 50); + /* act(() => { + jest.advanceTimersByTime(100); + }); + shouldAnimatingThisOne(1); +*/ +}); + +it('custom api queue animation', (done) => { + act(() => { + render( + + {child} + , + container, + ); + }); + const node = container.querySelector('[id=queue]'); + const { children } = node; + console.log('component style', getTop(node)); + expect(getTop(node)).toBe(10); + console.log('component tagName', node.tagName); + expect(node.tagName).toBe('P'); + Ticker.timeout(() => { + expect(children.length).toBe(0); + Ticker.timeout(() => { + expect(children.length).toBe(1); + done(); + }, 100); + }, 950); +}); + +it('custom animConfig queue animation', (done) => { + act(() => { + render( + + {child} + , + container, + ); + }); + const { children } = container.querySelector('[id=queue]'); + Ticker.timeout(() => { + expect(getLeft(children[0])).toBe(100); + done(); + }, 500); +}); + +it('custom forcedReplay queue animation', (done) => { + act(() => { + render( + , + container, + ); + }); + const { children } = container.querySelector('[id=queue]'); + const button = document.querySelector('[data-testId=toggle]'); + Ticker.timeout(() => { + // 出场 + act(() => { + button.dispatchEvent(new MouseEvent('click', { bubbles: true })); + }); + + Ticker.timeout(() => { + // 重新进入 + act(() => { + button.dispatchEvent(new MouseEvent('click', { bubbles: true })); + }); + + expect(getLeft(children[0])).toBe(0); + done(); + }, 500); + }, 500); +}); + +it('should support custom animation config array', (done) => { + act(() => { + render(, container); + }); + const { children } = container.querySelector('[id=queue]'); + const button = document.querySelector('[data-testId=toggle]'); + Ticker.timeout(() => { + expect(getLeft(children[0])).toBe(100); + act(() => { + button.dispatchEvent(new MouseEvent('click', { bubbles: true })); + }); + Ticker.timeout(() => { + console.log('top', getTop(children[0])); + expect(getTop(children[0])).toBe(0); + done(); + }, 500); + }, 500); +}); +it('should has animating config is func enter', (done) => { + act(() => { + render( + { + if (e.index === 1) { + return [[{ top: [100, 0] }, { left: [100, 0]}]]; + } + return { left: [100, 0] }; + }} + />, + container, + ); + }); + const { children } = container.querySelector('[id=queue]'); + const button = document.querySelector('[data-testId=toggle]'); + Ticker.timeout(() => { + expect(getLeft(children[0])).toBe(100); + expect(getTop(children[1])).toBe(100); + done(); + act(() => { + button.dispatchEvent(new MouseEvent('click', { bubbles: true })); + }); + Ticker.timeout(() => { + // expect(getLeft(children[0])).toBe(0); + // expect(getTop(children[1])).toBe(0); + done(); + }, 600); + }, 600); +}); +it('should have leave animation', (done) => { + act(() => { + render(, container); + }); + const { children } = container.querySelector('[id=queue]'); + const button = document.querySelector('[data-testId=toggle]'); + Ticker.timeout(() => { + expect(children.length).toBe(3); + act(() => { + button.dispatchEvent(new MouseEvent('click', { bubbles: true })); + }); + Ticker.timeout(() => { + expect(children.length).toBe(0); + done(); + }, 1000); + }, 1000); +}); + +it('should have unmount animation', (done) => { + act(() => { + render(, container); + + const button = document.querySelector('[data-testId=unmount]'); + Ticker.timeout(() => { + act(() => { + button.dispatchEvent(new MouseEvent('click', { bubbles: true })); + }); + const node = container.querySelector('[id=queue]'); + expect(node).toBe(null); + done(); + }, 1000); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index f5622bd..bb3518e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,31 +1,30 @@ { "compilerOptions": { - "outDir": "build/dist", + "target": "esnext", "module": "esnext", - "target": "es2016", - "lib": ["es6", "dom"], - "sourceMap": true, - "jsx": "react", - "allowSyntheticDefaultImports": true, "moduleResolution": "node", - "rootDirs": ["/src", "./typings"], - "forceConsistentCasingInFileNames": true, - "noImplicitReturns": true, - "suppressImplicitAnyIndexErrors": true, - "noUnusedLocals": true, - "allowJs": true, - "experimentalDecorators": true + "importHelpers": true, + "jsx": "react", + "typeRoots": ["./typings"], + "declaration": true, + "esModuleInterop": true, + "sourceMap": true, + "baseUrl": "./", + "strict": true, + "paths": { + "@/*": ["src/*"], + "@@/*": ["src/.umi/*"], + "rc-queue-anim": ["src/index.tsx"] + }, + "allowSyntheticDefaultImports": true }, - "include": ["./src"], "exclude": [ "node_modules", - "build", - "scripts", - "acceptance-tests", - "webpack", - "jest", - "src/setupTests.ts", - "tslint:latest", - "tslint-config-prettier" + "lib", + "es", + "dist", + "typings", + "**/__test__", + "test" ] } diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 125e217..0000000 --- a/tslint.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": ["tslint:latest", "tslint-react", "tslint-config-prettier"], - "rules": { - "no-var-requires": false, - "no-submodule-imports": false, - "object-literal-sort-keys": false, - "jsx-no-lambda": false, - "no-implicit-dependencies": false, - "no-console": false - } -} diff --git a/typings/global/import.d.ts b/typings/global/import.d.ts new file mode 100644 index 0000000..1b73c18 --- /dev/null +++ b/typings/global/import.d.ts @@ -0,0 +1,6 @@ +import * as CSS from 'csstype'; +declare module 'csstype' { + interface Properties { + [key: string]: any; + } +} \ No newline at end of file diff --git a/typings/global/index.d.ts b/typings/global/index.d.ts new file mode 100644 index 0000000..0b7d857 --- /dev/null +++ b/typings/global/index.d.ts @@ -0,0 +1,3 @@ +/// +declare module '*.css'; +declare module '*.less'; From 50323282981bd92d409a16920241fcfeab804a60 Mon Sep 17 00:00:00 2001 From: jljsj Date: Fri, 2 Jul 2021 21:22:50 +0800 Subject: [PATCH 2/6] add git --- .github/workflows/main.yml | 113 +++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..c3d6d5c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,113 @@ +name: CI + +on: + push: + branches: [master, 2.x] + pull_request: + branches: [master] + +jobs: + setup: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@master + + - uses: actions/setup-node@v1 + with: + node-version: '12' + + - name: cache package-lock.json + uses: actions/cache@v2 + with: + path: package-temp-dir + key: lock-${{ github.sha }} + + - name: create package-lock.json + run: npm i --package-lock-only + + - name: hack for singe file + run: | + if [ ! -d "package-temp-dir" ]; then + mkdir package-temp-dir + fi + cp package-lock.json package-temp-dir + - name: cache node_modules + id: node_modules_cache_id + uses: actions/cache@v2 + with: + path: node_modules + key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }} + + - name: install + if: steps.node_modules_cache_id.outputs.cache-hit != 'true' + run: npm ci + + lint: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@master + + - name: restore cache from package-lock.json + uses: actions/cache@v2 + with: + path: package-temp-dir + key: lock-${{ github.sha }} + + - name: restore cache from node_modules + uses: actions/cache@v2 + with: + path: node_modules + key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }} + + - name: lint + run: npm run lint + + needs: setup + + compile: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@master + + - name: restore cache from package-lock.json + uses: actions/cache@v2 + with: + path: package-temp-dir + key: lock-${{ github.sha }} + + - name: restore cache from node_modules + uses: actions/cache@v2 + with: + path: node_modules + key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }} + + - name: compile + run: npm run compile + + needs: setup + + coverage: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@master + + - name: restore cache from package-lock.json + uses: actions/cache@v2 + with: + path: package-temp-dir + key: lock-${{ github.sha }} + + - name: restore cache from node_modules + uses: actions/cache@v2 + with: + path: node_modules + key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }} + + - name: coverage + run: npm test -- --coverage && bash <(curl -s https://codecov.io/bash) + + needs: setup From 72050fc2cbb7a56487929e98ef5c221b18756360 Mon Sep 17 00:00:00 2001 From: jljsj Date: Fri, 2 Jul 2021 21:42:40 +0800 Subject: [PATCH 3/6] fix lint --- src/QueueAnim.tsx | 53 +++++++++++++++++++++++++---------------------- src/type.ts | 6 +++--- src/utils.ts | 2 +- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/QueueAnim.tsx b/src/QueueAnim.tsx index 3102f04..6254d22 100644 --- a/src/QueueAnim.tsx +++ b/src/QueueAnim.tsx @@ -20,7 +20,7 @@ import { } from './utils'; import AnimTypes from './animTypes'; -import { IObject, IProps, IKeys, IQueueType } from './type'; +import type { IObject, IProps, IKeys, IQueueType } from './type'; const noop = () => {}; @@ -117,8 +117,8 @@ export default forwardRef((props: IProps, ref: any) => { return getTweenSingleConfig(data, num, enterOrLeave); }; - const getTweenType = (type: IQueueType, num: number) => { - const data = AnimTypes[type]; + const getTweenType = ($type: IQueueType, num: number) => { + const data = AnimTypes[$type]; return getTweenAnimConfig(data, num); }; @@ -136,13 +136,13 @@ export default forwardRef((props: IProps, ref: any) => { ) : getTweenType(transformArguments(type, key, i)[enterOrLeave], startOrEnd); - const getTweenData = (key: string | number, i: number, type: string) => { - const enterOrLeave = type === 'enter' ? 0 : 1; - const start = type === 'enter' ? 1 : 0; - const end = type === 'enter' ? 0 : 1; + const getTweenData = (key: string | number, i: number, $type: string) => { + const enterOrLeave = $type === 'enter' ? 0 : 1; + const start = $type === 'enter' ? 1 : 0; + const end = $type === 'enter' ? 0 : 1; const animate = getAnimData(key, i, enterOrLeave, end); const startAnim = - type === 'enter' && (forcedReplay || !childrenShow.current[key]) + $type === 'enter' && (forcedReplay || !childrenShow.current[key]) ? getAnimData(key, i, enterOrLeave, start) : null; let $ease = transformArguments(ease, key, i)[enterOrLeave]; @@ -231,7 +231,7 @@ export default forwardRef((props: IProps, ref: any) => { }, $interval * i + $delay); }; - const performLeave = (key: string | number, i: number) => { + const performLeave = (key: string | number) => { Ticker.clear(placeholderTimeoutIds.current[key]); delete placeholderTimeoutIds.current[key]; }; @@ -239,12 +239,16 @@ export default forwardRef((props: IProps, ref: any) => { const getTweenOneEnterOrLeave = ( key: string | number, i: number, - delay: number, - type: string, + $delay: number, + $type: string, ) => { - const animateData = getTweenData(key, i, type); - const onStart = (type === 'enter' ? enterBegin : leaveBegin).bind(this, key); - const onComplete = (type === 'enter' ? enterComplete : leaveComplete).bind(this, key); + const animateData = getTweenData(key, i, $type); + const onStart = (e: any) => { + ($type === 'enter' ? enterBegin : leaveBegin)(key, e); + }; + const onComplete = (e: any) => { + ($type === 'enter' ? enterComplete : leaveComplete)(key, e); + }; if (Array.isArray(animateData.animate)) { const length = animateData.animate.length - 1; const animation = animateData.animate.map((item, ii) => { @@ -252,7 +256,7 @@ export default forwardRef((props: IProps, ref: any) => { ...item, startAt: animateData.startAnim ? animateData.startAnim[ii] : undefined, duration: animateData.duration / length, - delay: !ii && type === 'leave' ? delay : 0, + delay: !ii && $type === 'leave' ? $delay : 0, onStart: !ii ? onStart : undefined, onComplete: ii === length ? onComplete : undefined, }; @@ -266,7 +270,7 @@ export default forwardRef((props: IProps, ref: any) => { duration: animateData.duration, onStart, onComplete, - delay, + delay: $delay, }; }; useEffect( @@ -283,17 +287,17 @@ export default forwardRef((props: IProps, ref: any) => { ); useEffect(() => { const nextChildren = toArrayChildren(props.children).filter((c) => c); - let currentChildren = originalChildren.current.filter((item) => item); + const currentChildren = originalChildren.current.filter((item) => item); const newChildren = mergeChildren(currentChildren, nextChildren); const $keysToEnter: IKeys = []; const $keysToLeave: IKeys = []; if (!appear && !oneEnterBool.current) { const $childShow: IObject = {}; - newChildren.forEach((child: any) => { - if (!child || !child.key) { + newChildren.forEach((c: any) => { + if (!c || !c.key) { return; } - $childShow[child.key] = true; + $childShow[c.key] = true; }); originalChildren.current = newChildren; childrenShow.current = { ...$childShow }; @@ -303,7 +307,7 @@ export default forwardRef((props: IProps, ref: any) => { if (!c) { return; } - const key = c.key; + const { key } = c; const hasNext = findChildInChildrenByKey(nextChildren, key); if (!hasNext && key) { $keysToLeave.push(key); @@ -359,13 +363,13 @@ export default forwardRef((props: IProps, ref: any) => { return; } let animation; - let index = keysToLeave.current.indexOf(key); //children.findIndex(c => c.key === key); + let index = keysToLeave.current.indexOf(key); // children.findIndex(c => c.key === key); const $interval = transformArguments(interval, key, index); - let $delay = transformArguments(delay, key, index); + const $delay = transformArguments(delay, key, index); // 处理出场 if (index >= 0) { - if (recordAnimKeys.current[key] == 'leave') { + if (recordAnimKeys.current[key] === 'leave') { return; } @@ -402,7 +406,6 @@ export default forwardRef((props: IProps, ref: any) => { recordTweenKeys.current[key] = TweenOne(dom, { animation, }); - }); } }, [childShow, child]); diff --git a/src/type.ts b/src/type.ts index 2429672..3361153 100644 --- a/src/type.ts +++ b/src/type.ts @@ -1,6 +1,6 @@ -import { IObject as IObj } from 'tween-one/lib/typings'; -import { IEaseType as IEase } from 'tween-one/lib/typings/IAnimObject'; -import React from 'react'; +import type { IObject as IObj } from 'tween-one/lib/typings'; +import type { IEaseType as IEase } from 'tween-one/lib/typings/IAnimObject'; +import type React from 'react'; export type IObject = IObj; diff --git a/src/utils.ts b/src/utils.ts index 829613e..696798e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ /* eslint no-prototype-builtins: 0 */ -import { IObject } from './type'; +import type { IObject } from './type'; import React from 'react'; export const windowIsUndefined = !( From 53f17442b2b76a539296da9fd677c4602474086f Mon Sep 17 00:00:00 2001 From: jljsj Date: Fri, 2 Jul 2021 21:46:43 +0800 Subject: [PATCH 4/6] update index.d.ts --- typings/global/index.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/typings/global/index.d.ts b/typings/global/index.d.ts index 0b7d857..6c0343c 100644 --- a/typings/global/index.d.ts +++ b/typings/global/index.d.ts @@ -1,3 +1,7 @@ /// declare module '*.css'; declare module '*.less'; +declare module 'style-utils'; +declare module 'tween-functions'; +declare module 'raf'; +declare module 'flubber'; \ No newline at end of file From 39770279a6e9424c068d9a5e311ad12ae0fd0e2b Mon Sep 17 00:00:00 2001 From: jljsj Date: Fri, 2 Jul 2021 21:52:14 +0800 Subject: [PATCH 5/6] update dependencies --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c2c917f..d34b1b4 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ }, "dependencies": { "@babel/runtime": "^7.11.1", - "rc-tween-one": "^3.0.0-beta.11" + "tween-one": "^1.0.52" }, "husky": { "hooks": { From 9198bfa44aa15992ad807bd9c04d617744184f8f Mon Sep 17 00:00:00 2001 From: jljsj Date: Mon, 5 Jul 2021 14:25:22 +0800 Subject: [PATCH 6/6] fix monkey click --- src/QueueAnim.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/QueueAnim.tsx b/src/QueueAnim.tsx index 6254d22..2ce0b43 100644 --- a/src/QueueAnim.tsx +++ b/src/QueueAnim.tsx @@ -303,6 +303,7 @@ export default forwardRef((props: IProps, ref: any) => { childrenShow.current = { ...$childShow }; setChildShow($childShow); } else { + // console.log(nextChildren, recordAnimKeys.current, keysToEnter.current, keysToLeave.current); currentChildren.forEach((c) => { if (!c) { return; @@ -315,6 +316,7 @@ export default forwardRef((props: IProps, ref: any) => { delete placeholderTimeoutIds.current[key]; } }); + nextChildren.forEach((c: any) => { if (!c) { return; @@ -325,7 +327,9 @@ export default forwardRef((props: IProps, ref: any) => { // 如果 nextChildren 和当前的一致,且动画里是出场,改回进场; if ( (!hasPrev && key) || - ((recordAnimKeys.current[key] === 'leave' || keysToEnter.current.indexOf(key) >= 0) && + ((!recordAnimKeys.current[key] || + recordAnimKeys.current[key] === 'leave' || + keysToEnter.current.indexOf(key) >= 0) && $keysToLeave.indexOf(key) === -1) ) { $keysToEnter.push(key); @@ -340,6 +344,7 @@ export default forwardRef((props: IProps, ref: any) => { keysToLeave.current = $keysToLeave; recordKeysToLeave.current = [...$keysToLeave]; + // console.log($keysToEnter, $keysToLeave); setChild(newChildren); }, [props.children]); useLayoutEffect(() => {