UNPKG

9.67 kBJavaScriptView Raw
1import _typeof from "@babel/runtime/helpers/esm/typeof";
2import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
3import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
4import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
5var _excluded = ["component", "componentProps", "leave", "enter", "appear", "resetStyle", "animatingClassName", "onEnd", "exclusive"];
6import { cloneElement } from 'react';
7import React, { useRef, useEffect, useState, createElement } from 'react';
8import { getChildrenFromProps, toArrayChildren, transformArguments, mergeChildren, findChildInChildrenByKey } from './utils/group';
9import { useIsomorphicLayoutEffect, windowIsUndefined } from './utils/common';
10import TweenOne from './TweenOne';
11var TweenOneGroup = /*#__PURE__*/React.forwardRef(function (props, ref) {
12 var _props$component = props.component,
13 component = _props$component === void 0 ? 'div' : _props$component,
14 _props$componentProps = props.componentProps,
15 componentProps = _props$componentProps === void 0 ? {} : _props$componentProps,
16 _props$leave = props.leave,
17 leaveAnim = _props$leave === void 0 ? {
18 x: -50,
19 opacity: 0
20 } : _props$leave,
21 _props$enter = props.enter,
22 enterAnim = _props$enter === void 0 ? {
23 x: 50,
24 opacity: 0,
25 type: 'from'
26 } : _props$enter,
27 _props$appear = props.appear,
28 appearBool = _props$appear === void 0 ? true : _props$appear,
29 _props$resetStyle = props.resetStyle,
30 resetStyle = _props$resetStyle === void 0 ? true : _props$resetStyle,
31 _props$animatingClass = props.animatingClassName,
32 animatingClassName = _props$animatingClass === void 0 ? ['tween-one-entering', 'tween-one-leaving'] : _props$animatingClass,
33 _props$onEnd = props.onEnd,
34 onEnd = _props$onEnd === void 0 ? function () {} : _props$onEnd,
35 _props$exclusive = props.exclusive,
36 exclusive = _props$exclusive === void 0 ? false : _props$exclusive,
37 tagProps = _objectWithoutProperties(props, _excluded);
38
39 var keysToEnter = useRef([]);
40 var keysToLeave = useRef([]);
41 var saveTweenTag = useRef({});
42 var oneEnter = useRef(false);
43 var animQueue = useRef([]);
44 var isTween = useRef({});
45 var cChild = toArrayChildren(getChildrenFromProps(props));
46 var currentChildren = useRef(cChild);
47
48 var _useState = useState(cChild),
49 _useState2 = _slicedToArray(_useState, 2),
50 children = _useState2[0],
51 setChild = _useState2[1];
52
53 var getTweenChild = function getTweenChild(child) {
54 var p = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
55 var key = child.key;
56 saveTweenTag.current[key] = /*#__PURE__*/React.createElement(TweenOne, _objectSpread(_objectSpread({}, p), {}, {
57 key: key,
58 component: null
59 }), child);
60 return saveTweenTag.current[key];
61 };
62
63 var setClassName = function setClassName(name, isEnter) {
64 var className = name.replace(animatingClassName[isEnter ? 1 : 0], '').trim();
65
66 if (className.indexOf(animatingClassName[isEnter ? 0 : 1]) === -1) {
67 className = "".concat(className, " ").concat(animatingClassName[isEnter ? 0 : 1]).trim();
68 }
69
70 return className;
71 };
72
73 var changeChildren = function changeChildren(nextChildren, currentChild) {
74 var newChildren = mergeChildren(currentChild, nextChildren);
75 keysToEnter.current = [];
76 keysToLeave.current = [];
77 nextChildren.forEach(function (c) {
78 if (!c) {
79 return;
80 }
81
82 var key = c.key;
83 var hasPrev = findChildInChildrenByKey(currentChild, key); // 如果当前 key 已存在 saveTweenTag 里,,刷新 child;
84
85 if (key && saveTweenTag.current[key]) {
86 saveTweenTag.current[key] = /*#__PURE__*/React.cloneElement(saveTweenTag.current[key], {}, c);
87 }
88
89 if (!hasPrev && key) {
90 keysToEnter.current.push(key);
91 }
92 });
93 currentChild.forEach(function (c) {
94 if (!c) {
95 return;
96 }
97
98 var key = c.key;
99 var hasNext = findChildInChildrenByKey(nextChildren, key);
100
101 if (!hasNext && key) {
102 keysToLeave.current.push(key);
103 delete saveTweenTag.current[key];
104 }
105 });
106 return newChildren;
107 };
108
109 var reAnimQueue = function reAnimQueue() {
110 if (!Object.keys(isTween.current).length && animQueue.current.length) {
111 // 取最后一个继续动画;
112 var child = changeChildren(animQueue.current[animQueue.current.length - 1], currentChildren.current);
113 setChild(child);
114 animQueue.current = [];
115 }
116 };
117
118 var onChange = function onChange(key, type, obj) {
119 var tag = obj.targets;
120 var classIsSvg = _typeof(tag.className) === 'object' && 'baseVal' in tag.className;
121 var isEnter = type === 'enter' || type === 'appear';
122
123 if (key && obj.mode === 'onTimelineComplete') {
124 delete isTween.current[key];
125
126 if (classIsSvg) {
127 tag.className.baseVal = tag.className.baseVal.replace(animatingClassName[isEnter ? 0 : 1], '').trim();
128 } else {
129 tag.className = tag.className.replace(animatingClassName[isEnter ? 0 : 1], '').trim();
130 }
131
132 if (isEnter) {
133 keysToEnter.current.splice(keysToEnter.current.indexOf(key), 1);
134
135 if (!keysToEnter.current.length) {
136 // enter 不会触发 did update, 手动触发一次;
137 reAnimQueue();
138 }
139 } else if (type === 'leave') {
140 keysToLeave.current.splice(keysToLeave.current.indexOf(key), 1);
141 currentChildren.current = currentChildren.current.filter(function (child) {
142 return key !== child.key;
143 });
144
145 if (!keysToLeave.current.length) {
146 var currentChildrenKeys = currentChildren.current.map(function (item) {
147 return item.key;
148 });
149 Object.keys(saveTweenTag.current).forEach(function ($key) {
150 if (currentChildrenKeys.indexOf($key) === -1) {
151 delete saveTweenTag.current[$key];
152 }
153 });
154 setChild(currentChildren.current);
155 }
156 }
157
158 onEnd({
159 key: key,
160 type: type,
161 target: obj.targets
162 });
163 }
164 };
165
166 var getCoverAnimation = function getCoverAnimation(child, i, type) {
167 var animation = type === 'leave' ? leaveAnim : enterAnim;
168
169 if (type === 'appear') {
170 var appear = transformArguments(appearBool, child.key, i);
171 animation = appear && enterAnim || null;
172 }
173
174 var animate = transformArguments(animation, child.key, i);
175
176 var onChangeCb = function onChangeCb(obj) {
177 onChange(child.key, type, obj);
178 };
179
180 var className = type === 'appear' && !appearBool ? child.props.className : setClassName(child.props.className || '', type === 'enter' || type === 'appear') || undefined;
181 var p = {
182 key: child.key,
183 animation: animate,
184 onChangeTimeline: onChangeCb,
185 resetStyle: resetStyle,
186 className: className
187 };
188
189 if (child.key && keysToEnter.current.concat(keysToLeave.current).indexOf(child.key) >= 0 || !oneEnter.current && animation) {
190 if (child.key && !saveTweenTag.current[child.key]) {
191 isTween.current[child.key] = type;
192 }
193 }
194
195 return getTweenChild(child, p);
196 };
197
198 useIsomorphicLayoutEffect(function () {
199 if (oneEnter.current) {
200 var nextChild = toArrayChildren(props.children).filter(function (c) {
201 return c;
202 });
203 var currentChild = toArrayChildren(currentChildren.current); // 如果还在动画,暂存动画队列里,等前一次动画结束后再启动最后次的更新动画
204
205 if (Object.keys(isTween.current).length && !exclusive) {
206 animQueue.current.push(nextChild);
207 } else {
208 setChild(changeChildren(nextChild, currentChild));
209 }
210 }
211 }, [props.children]);
212 useIsomorphicLayoutEffect(function () {
213 reAnimQueue();
214 });
215 useEffect(function () {
216 oneEnter.current = true;
217 }, []);
218 currentChildren.current = children;
219 var childrenToRender = children.map(function (child, i) {
220 if (!child || !child.key) {
221 return child;
222 }
223
224 var key = child.key;
225
226 if (keysToLeave.current.indexOf(key) >= 0) {
227 return getCoverAnimation(child, keysToLeave.current.indexOf(key), 'leave');
228 }
229
230 if ((keysToEnter.current.indexOf(key) >= 0 || isTween.current[key] && keysToLeave.current.indexOf(key) === -1) && !(isTween.current[key] === 'enter' && saveTweenTag.current[key])) {
231 /**
232 * 1. 在 key 在 enter 里。
233 * 2. 出场未结束,触发进场, this.isTween[key] 为 leave, key 在 enter 里。
234 * 3. 状态为 enter 且 tweenTag 里有值时,不执行重载动画属性,直接调用 tweenTag 里的。
235 */
236 return getCoverAnimation(child, keysToEnter.current.indexOf(key), 'enter');
237 }
238
239 if (!oneEnter.current) {
240 return getCoverAnimation(child, i, 'appear');
241 }
242
243 return saveTweenTag.current[key];
244 });
245
246 if (windowIsUndefined) {
247 if (!component) {
248 return /*#__PURE__*/React.createElement(React.Fragment, null, props.children);
249 }
250
251 return /*#__PURE__*/createElement(component, _objectSpread(_objectSpread(_objectSpread({}, tagProps), componentProps), {}, {
252 ref: ref
253 }), props.children);
254 }
255
256 if (!component) {
257 return childrenToRender[0] ? /*#__PURE__*/cloneElement(childrenToRender[0], {
258 ref: ref
259 }) : null;
260 }
261
262 return /*#__PURE__*/createElement(component, _objectSpread(_objectSpread(_objectSpread({}, tagProps), componentProps), {}, {
263 ref: ref
264 }), childrenToRender);
265});
266TweenOneGroup.displayName = 'TweenOneGroup';
267TweenOneGroup.isTweenOneGroup = true;
268export default TweenOneGroup;
\No newline at end of file