UNPKG

59.1 kBJavaScriptView Raw
1import _extends from '@babel/runtime/helpers/esm/extends';
2import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/esm/objectWithoutPropertiesLoose';
3import React, { useState, useCallback, forwardRef, useRef, useEffect, useImperativeHandle, useMemo } from 'react';
4
5let applyAnimatedValues;
6function injectApplyAnimatedValues(fn, transform) {
7 applyAnimatedValues = {
8 fn,
9 transform
10 };
11}
12let colorNames;
13function injectColorNames(names) {
14 colorNames = names;
15}
16let requestFrame = cb => typeof window !== 'undefined' ? window.requestAnimationFrame(cb) : -1;
17let cancelFrame = id => {
18 typeof window !== 'undefined' && window.cancelAnimationFrame(id);
19};
20function injectFrame(raf, caf) {
21 requestFrame = raf;
22 cancelFrame = caf;
23}
24let interpolation;
25function injectStringInterpolator(fn) {
26 interpolation = fn;
27}
28let now = () => Date.now();
29function injectNow(nowFn) {
30 now = nowFn;
31}
32let defaultElement;
33function injectDefaultElement(el) {
34 defaultElement = el;
35}
36let animatedApi = node => node.current;
37function injectAnimatedApi(fn) {
38 animatedApi = fn;
39}
40let createAnimatedStyle;
41function injectCreateAnimatedStyle(factory) {
42 createAnimatedStyle = factory;
43}
44let manualFrameloop = false;
45function injectManualFrameloop(manual) {
46 manualFrameloop = manual;
47}
48
49var Globals = /*#__PURE__*/Object.freeze({
50 get applyAnimatedValues () { return applyAnimatedValues; },
51 injectApplyAnimatedValues: injectApplyAnimatedValues,
52 get colorNames () { return colorNames; },
53 injectColorNames: injectColorNames,
54 get requestFrame () { return requestFrame; },
55 get cancelFrame () { return cancelFrame; },
56 injectFrame: injectFrame,
57 get interpolation () { return interpolation; },
58 injectStringInterpolator: injectStringInterpolator,
59 get now () { return now; },
60 injectNow: injectNow,
61 get defaultElement () { return defaultElement; },
62 injectDefaultElement: injectDefaultElement,
63 get animatedApi () { return animatedApi; },
64 injectAnimatedApi: injectAnimatedApi,
65 get createAnimatedStyle () { return createAnimatedStyle; },
66 injectCreateAnimatedStyle: injectCreateAnimatedStyle,
67 get manualFrameloop () { return manualFrameloop; },
68 injectManualFrameloop: injectManualFrameloop
69});
70
71class Animated {
72 constructor() {
73 this.payload = void 0;
74 this.children = [];
75 }
76
77 getAnimatedValue() {
78 return this.getValue();
79 }
80
81 getPayload() {
82 return this.payload || this;
83 }
84
85 attach() {}
86
87 detach() {}
88
89 getChildren() {
90 return this.children;
91 }
92
93 addChild(child) {
94 if (this.children.length === 0) this.attach();
95 this.children.push(child);
96 }
97
98 removeChild(child) {
99 const index = this.children.indexOf(child);
100 this.children.splice(index, 1);
101 if (this.children.length === 0) this.detach();
102 }
103
104}
105class AnimatedArray extends Animated {
106 constructor() {
107 super(...arguments);
108 this.payload = [];
109
110 this.attach = () => this.payload.forEach(p => p instanceof Animated && p.addChild(this));
111
112 this.detach = () => this.payload.forEach(p => p instanceof Animated && p.removeChild(this));
113 }
114
115}
116class AnimatedObject extends Animated {
117 constructor() {
118 super(...arguments);
119 this.payload = {};
120
121 this.attach = () => Object.values(this.payload).forEach(s => s instanceof Animated && s.addChild(this));
122
123 this.detach = () => Object.values(this.payload).forEach(s => s instanceof Animated && s.removeChild(this));
124 }
125
126 getValue(animated) {
127 if (animated === void 0) {
128 animated = false;
129 }
130
131 const payload = {};
132
133 for (const key in this.payload) {
134 const value = this.payload[key];
135 if (animated && !(value instanceof Animated)) continue;
136 payload[key] = value instanceof Animated ? value[animated ? 'getAnimatedValue' : 'getValue']() : value;
137 }
138
139 return payload;
140 }
141
142 getAnimatedValue() {
143 return this.getValue(true);
144 }
145
146}
147
148function createInterpolator(range, output, extrapolate) {
149 if (typeof range === 'function') {
150 return range;
151 }
152
153 if (Array.isArray(range)) {
154 return createInterpolator({
155 range,
156 output: output,
157 extrapolate
158 });
159 }
160
161 if (interpolation && typeof range.output[0] === 'string') {
162 return interpolation(range);
163 }
164
165 const config = range;
166 const outputRange = config.output;
167 const inputRange = config.range || [0, 1];
168 const extrapolateLeft = config.extrapolateLeft || config.extrapolate || 'extend';
169 const extrapolateRight = config.extrapolateRight || config.extrapolate || 'extend';
170
171 const easing = config.easing || (t => t);
172
173 return input => {
174 const range = findRange(input, inputRange);
175 return interpolate(input, inputRange[range], inputRange[range + 1], outputRange[range], outputRange[range + 1], easing, extrapolateLeft, extrapolateRight, config.map);
176 };
177}
178
179function interpolate(input, inputMin, inputMax, outputMin, outputMax, easing, extrapolateLeft, extrapolateRight, map) {
180 let result = map ? map(input) : input; // Extrapolate
181
182 if (result < inputMin) {
183 if (extrapolateLeft === 'identity') return result;else if (extrapolateLeft === 'clamp') result = inputMin;
184 }
185
186 if (result > inputMax) {
187 if (extrapolateRight === 'identity') return result;else if (extrapolateRight === 'clamp') result = inputMax;
188 }
189
190 if (outputMin === outputMax) return outputMin;
191 if (inputMin === inputMax) return input <= inputMin ? outputMin : outputMax; // Input Range
192
193 if (inputMin === -Infinity) result = -result;else if (inputMax === Infinity) result = result - inputMin;else result = (result - inputMin) / (inputMax - inputMin); // Easing
194
195 result = easing(result); // Output Range
196
197 if (outputMin === -Infinity) result = -result;else if (outputMax === Infinity) result = result + outputMin;else result = result * (outputMax - outputMin) + outputMin;
198 return result;
199}
200
201function findRange(input, inputRange) {
202 for (var i = 1; i < inputRange.length - 1; ++i) if (inputRange[i] >= input) break;
203
204 return i - 1;
205}
206
207class AnimatedInterpolation extends AnimatedArray {
208 constructor(parents, range, output) {
209 super();
210 this.calc = void 0;
211 this.payload = parents instanceof AnimatedArray && !(parents instanceof AnimatedInterpolation) ? parents.getPayload() : Array.isArray(parents) ? parents : [parents];
212 this.calc = createInterpolator(range, output);
213 }
214
215 getValue() {
216 return this.calc(...this.payload.map(value => value.getValue()));
217 }
218
219 updateConfig(range, output) {
220 this.calc = createInterpolator(range, output);
221 }
222
223 interpolate(range, output) {
224 return new AnimatedInterpolation(this, range, output);
225 }
226
227}
228
229const is = {
230 arr: Array.isArray,
231 obj: a => Object.prototype.toString.call(a) === '[object Object]',
232 fun: a => typeof a === 'function',
233 str: a => typeof a === 'string',
234 num: a => typeof a === 'number',
235 und: a => a === void 0,
236 nul: a => a === null,
237 set: a => a instanceof Set,
238 map: a => a instanceof Map,
239
240 equ(a, b) {
241 if (typeof a !== typeof b) return false;
242 if (is.str(a) || is.num(a)) return a === b;
243 if (is.obj(a) && is.obj(b) && Object.keys(a).length + Object.keys(b).length === 0) return true;
244 let i;
245
246 for (i in a) if (!(i in b)) return false;
247
248 for (i in b) if (a[i] !== b[i]) return false;
249
250 return is.und(i) ? a === b : true;
251 }
252
253};
254function merge(target, lowercase) {
255 if (lowercase === void 0) {
256 lowercase = true;
257 }
258
259 return object => (is.arr(object) ? object : Object.keys(object)).reduce((acc, element) => {
260 const key = lowercase ? element[0].toLowerCase() + element.substring(1) : element;
261 acc[key] = target(key);
262 return acc;
263 }, target);
264}
265function useForceUpdate() {
266 const _useState = useState(false),
267 f = _useState[1];
268
269 const forceUpdate = useCallback(() => f(v => !v), []);
270 return forceUpdate;
271}
272function withDefault(value, defaultValue) {
273 return is.und(value) || is.nul(value) ? defaultValue : value;
274}
275function toArray(a) {
276 return !is.und(a) ? is.arr(a) ? a : [a] : [];
277}
278function callProp(obj) {
279 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
280 args[_key - 1] = arguments[_key];
281 }
282
283 return is.fun(obj) ? obj(...args) : obj;
284}
285
286function getForwardProps(props) {
287 const to = props.to,
288 from = props.from,
289 config = props.config,
290 onStart = props.onStart,
291 onRest = props.onRest,
292 onFrame = props.onFrame,
293 children = props.children,
294 reset = props.reset,
295 reverse = props.reverse,
296 force = props.force,
297 immediate = props.immediate,
298 delay = props.delay,
299 attach = props.attach,
300 destroyed = props.destroyed,
301 interpolateTo = props.interpolateTo,
302 ref = props.ref,
303 lazy = props.lazy,
304 forward = _objectWithoutPropertiesLoose(props, ["to", "from", "config", "onStart", "onRest", "onFrame", "children", "reset", "reverse", "force", "immediate", "delay", "attach", "destroyed", "interpolateTo", "ref", "lazy"]);
305
306 return forward;
307}
308
309function interpolateTo(props) {
310 const forward = getForwardProps(props);
311 if (is.und(forward)) return _extends({
312 to: forward
313 }, props);
314 const rest = Object.keys(props).reduce((a, k) => !is.und(forward[k]) ? a : _extends({}, a, {
315 [k]: props[k]
316 }), {});
317 return _extends({
318 to: forward
319 }, rest);
320}
321function handleRef(ref, forward) {
322 if (forward) {
323 // If it's a function, assume it's a ref callback
324 if (is.fun(forward)) forward(ref);else if (is.obj(forward)) {
325 forward.current = ref;
326 }
327 }
328
329 return ref;
330}
331
332var helpers = /*#__PURE__*/Object.freeze({
333 is: is,
334 merge: merge,
335 useForceUpdate: useForceUpdate,
336 withDefault: withDefault,
337 toArray: toArray,
338 callProp: callProp,
339 interpolateTo: interpolateTo,
340 handleRef: handleRef
341});
342
343/**
344 * Wraps the `style` property with `AnimatedStyle`.
345 */
346
347class AnimatedProps extends AnimatedObject {
348 constructor(props, callback) {
349 super();
350 this.update = void 0;
351 this.payload = !props.style ? props : _extends({}, props, {
352 style: createAnimatedStyle(props.style)
353 });
354 this.update = callback;
355 this.attach();
356 }
357
358}
359
360const createAnimatedComponent = Component => {
361 const AnimatedComponent = forwardRef((props, _ref) => {
362 const forceUpdate = useForceUpdate();
363 const mounted = useRef(true);
364 const propsAnimated = useRef(null);
365 const node = useRef(null);
366 const attachProps = useCallback(props => {
367 const oldPropsAnimated = propsAnimated.current;
368
369 const callback = () => {
370 if (node.current) {
371 const didUpdate = applyAnimatedValues.fn(node.current, propsAnimated.current.getAnimatedValue());
372 if (didUpdate === false) forceUpdate();
373 }
374 };
375
376 propsAnimated.current = new AnimatedProps(props, callback);
377 oldPropsAnimated && oldPropsAnimated.detach();
378 }, []);
379 useEffect(() => () => {
380 mounted.current = false;
381 propsAnimated.current && propsAnimated.current.detach();
382 }, []);
383 useImperativeHandle(_ref, () => animatedApi(node, mounted, forceUpdate));
384 attachProps(props);
385
386 const _getValue = propsAnimated.current.getValue(),
387 scrollTop = _getValue.scrollTop,
388 scrollLeft = _getValue.scrollLeft,
389 animatedProps = _objectWithoutPropertiesLoose(_getValue, ["scrollTop", "scrollLeft"]);
390
391 return React.createElement(Component, _extends({}, animatedProps, {
392 ref: childRef => node.current = handleRef(childRef, _ref)
393 }));
394 });
395 return AnimatedComponent;
396};
397
398/**
399 * Animated works by building a directed acyclic graph of dependencies
400 * transparently when you render your Animated components.
401 *
402 * new Animated.Value(0)
403 * .interpolate() .interpolate() new Animated.Value(1)
404 * opacity translateY scale
405 * style transform
406 * View#234 style
407 * View#123
408 *
409 * A) Top Down phase
410 * When an AnimatedValue is updated, we recursively go down through this
411 * graph in order to find leaf nodes: the views that we flag as needing
412 * an update.
413 *
414 * B) Bottom Up phase
415 * When a view is flagged as needing an update, we recursively go back up
416 * in order to build the new value that it needs. The reason why we need
417 * this two-phases process is to deal with composite props such as
418 * transform which can receive values from multiple parents.
419 */
420function addAnimatedStyles(node, styles) {
421 if ('update' in node) {
422 styles.add(node);
423 } else {
424 node.getChildren().forEach(child => addAnimatedStyles(child, styles));
425 }
426}
427
428class AnimatedValue extends Animated {
429 constructor(_value) {
430 var _this;
431
432 super();
433 _this = this;
434 this.animatedStyles = new Set();
435 this.value = void 0;
436 this.startPosition = void 0;
437 this.lastPosition = void 0;
438 this.lastVelocity = void 0;
439 this.startTime = void 0;
440 this.lastTime = void 0;
441 this.done = false;
442
443 this.setValue = function (value, flush) {
444 if (flush === void 0) {
445 flush = true;
446 }
447
448 _this.value = value;
449 if (flush) _this.flush();
450 };
451
452 this.value = _value;
453 this.startPosition = _value;
454 this.lastPosition = _value;
455 }
456
457 flush() {
458 if (this.animatedStyles.size === 0) {
459 addAnimatedStyles(this, this.animatedStyles);
460 }
461
462 this.animatedStyles.forEach(animatedStyle => animatedStyle.update());
463 }
464
465 clearStyles() {
466 this.animatedStyles.clear();
467 }
468
469 getValue() {
470 return this.value;
471 }
472
473 interpolate(range, output) {
474 return new AnimatedInterpolation(this, range, output);
475 }
476
477}
478
479class AnimatedValueArray extends AnimatedArray {
480 constructor(values) {
481 super();
482 this.payload = values.map(n => new AnimatedValue(n));
483 }
484
485 setValue(value, flush) {
486 if (flush === void 0) {
487 flush = true;
488 }
489
490 if (Array.isArray(value)) {
491 if (value.length === this.payload.length) {
492 value.forEach((v, i) => this.payload[i].setValue(v, flush));
493 }
494 } else {
495 this.payload.forEach(p => p.setValue(value, flush));
496 }
497 }
498
499 getValue() {
500 return this.payload.map(v => v.getValue());
501 }
502
503 interpolate(range, output) {
504 return new AnimatedInterpolation(this, range, output);
505 }
506
507}
508
509class AnimatedStyle extends AnimatedObject {
510 constructor(style) {
511 if (style === void 0) {
512 style = {};
513 }
514
515 super();
516
517 if (style.transform && !(style.transform instanceof Animated)) {
518 style = applyAnimatedValues.transform(style);
519 }
520
521 this.payload = style;
522 }
523
524}
525
526let active = false;
527const controllers = new Set();
528
529const update = () => {
530 if (!active) return;
531 let time = now();
532
533 for (let controller of controllers) {
534 let isActive = false;
535
536 for (let configIdx = 0; configIdx < controller.configs.length; configIdx++) {
537 let config = controller.configs[configIdx];
538 let endOfAnimation, lastTime;
539
540 for (let valIdx = 0; valIdx < config.animatedValues.length; valIdx++) {
541 let animation = config.animatedValues[valIdx]; // If an animation is done, skip, until all of them conclude
542
543 if (animation.done) continue;
544 let from = config.fromValues[valIdx];
545 let to = config.toValues[valIdx];
546 let position = animation.lastPosition;
547 let isAnimated = to instanceof Animated;
548 let velocity = Array.isArray(config.initialVelocity) ? config.initialVelocity[valIdx] : config.initialVelocity;
549 if (isAnimated) to = to.getValue(); // Conclude animation if it's either immediate, or from-values match end-state
550
551 if (config.immediate) {
552 animation.setValue(to);
553 animation.done = true;
554 continue;
555 } // Break animation when string values are involved
556
557
558 if (typeof from === 'string' || typeof to === 'string') {
559 animation.setValue(to);
560 animation.done = true;
561 continue;
562 }
563
564 if (config.duration !== void 0) {
565 /** Duration easing */
566 position = from + config.easing((time - animation.startTime) / config.duration) * (to - from);
567 endOfAnimation = time >= animation.startTime + config.duration;
568 } else if (config.decay) {
569 /** Decay easing */
570 position = from + velocity / (1 - 0.998) * (1 - Math.exp(-(1 - 0.998) * (time - controller.startTime)));
571 endOfAnimation = Math.abs(animation.lastPosition - position) < 0.1;
572 if (endOfAnimation) to = position;
573 } else {
574 /** Spring easing */
575 lastTime = animation.lastTime !== void 0 ? animation.lastTime : time;
576 velocity = animation.lastVelocity !== void 0 ? animation.lastVelocity : config.initialVelocity; // If we lost a lot of frames just jump to the end.
577
578 if (time > lastTime + 64) lastTime = time; // http://gafferongames.com/game-physics/fix-your-timestep/
579
580 let numSteps = Math.floor(time - lastTime);
581
582 for (let i = 0; i < numSteps; ++i) {
583 let force = -config.tension * (position - to);
584 let damping = -config.friction * velocity;
585 let acceleration = (force + damping) / config.mass;
586 velocity = velocity + acceleration * 1 / 1000;
587 position = position + velocity * 1 / 1000;
588 } // Conditions for stopping the spring animation
589
590
591 let isOvershooting = config.clamp && config.tension !== 0 ? from < to ? position > to : position < to : false;
592 let isVelocity = Math.abs(velocity) <= config.precision;
593 let isDisplacement = config.tension !== 0 ? Math.abs(to - position) <= config.precision : true;
594 endOfAnimation = isOvershooting || isVelocity && isDisplacement;
595 animation.lastVelocity = velocity;
596 animation.lastTime = time;
597 } // Trails aren't done until their parents conclude
598
599
600 if (isAnimated && !config.toValues[valIdx].done) endOfAnimation = false;
601
602 if (endOfAnimation) {
603 // Ensure that we end up with a round value
604 if (animation.value !== to) position = to;
605 animation.done = true;
606 } else isActive = true;
607
608 animation.setValue(position);
609 animation.lastPosition = position;
610 } // Keep track of updated values only when necessary
611
612
613 if (controller.props.onFrame) controller.values[config.name] = config.interpolation.getValue();
614 } // Update callbacks in the end of the frame
615
616
617 if (controller.props.onFrame) controller.props.onFrame(controller.values); // Either call onEnd or next frame
618
619 if (!isActive) {
620 controllers.delete(controller);
621 controller.stop(true);
622 }
623 } // Loop over as long as there are controllers ...
624
625
626 if (controllers.size) {
627 if (!manualFrameloop) requestFrame(update);
628 } else active = false;
629};
630
631const start = controller => {
632 if (!controllers.has(controller)) {
633 controllers.add(controller);
634 if (!active && !manualFrameloop) requestFrame(update);
635 active = true;
636 }
637};
638
639const stop = controller => {
640 if (controllers.has(controller)) controllers.delete(controller);
641};
642
643var FrameLoop = /*#__PURE__*/Object.freeze({
644 start: start,
645 stop: stop,
646 update: update
647});
648
649let G = 0;
650
651class Controller {
652 constructor() {
653 this.id = void 0;
654 this.idle = true;
655 this.hasChanged = false;
656 this.guid = 0;
657 this.local = 0;
658 this.props = {};
659 this.merged = {};
660 this.animations = {};
661 this.interpolations = {};
662 this.values = {};
663 this.configs = [];
664 this.listeners = [];
665 this.queue = [];
666 this.localQueue = void 0;
667
668 this.getValues = () => this.interpolations;
669
670 this.id = G++;
671 }
672 /** update(props)
673 * This function filters input props and creates an array of tasks which are executed in .start()
674 * Each task is allowed to carry a delay, which means it can execute asnychroneously */
675
676
677 update(args) {
678 //this._id = n + this.id
679 if (!args) return this; // Extract delay and the to-prop from props
680
681 const _ref = interpolateTo(args),
682 _ref$delay = _ref.delay,
683 delay = _ref$delay === void 0 ? 0 : _ref$delay,
684 to = _ref.to,
685 props = _objectWithoutPropertiesLoose(_ref, ["delay", "to"]);
686
687 if (is.arr(to) || is.fun(to)) {
688 // If config is either a function or an array queue it up as is
689 this.queue.push(_extends({}, props, {
690 delay,
691 to
692 }));
693 } else if (to) {
694 // Otherwise go through each key since it could be delayed individually
695 let merge$$1 = {};
696 Object.entries(to).forEach((_ref2) => {
697 let k = _ref2[0],
698 v = _ref2[1];
699
700 // Fetch delay and create an entry, consisting of the to-props, the delay, and basic props
701 const entry = _extends({
702 to: {
703 [k]: v
704 },
705 delay: callProp(delay, k)
706 }, props); // If it doesn't have a delay, merge it, otherwise add it to the queue
707
708
709 if (!entry.delay) merge$$1 = _extends({}, merge$$1, entry, {
710 to: _extends({}, merge$$1.to, entry.to)
711 });else this.queue = [...this.queue, entry];
712 }); // Append merged props, if present
713
714 if (Object.keys(merge$$1).length > 0) this.queue = [...this.queue, merge$$1];
715 } // Sort queue, so that async calls go last
716
717
718 this.queue = this.queue.sort((a, b) => a.delay - b.delay); // Diff the reduced props immediately (they'll contain the from-prop and some config)
719
720 this.diff(props);
721 return this;
722 }
723 /** start(onEnd)
724 * This function either executes a queue, if present, or starts the frameloop, which animates */
725
726
727 start(onEnd) {
728 // If a queue is present we must excecute it
729 if (this.queue.length) {
730 this.idle = false; // Updates can interrupt trailing queues, in that case we just merge values
731
732 if (this.localQueue) {
733 this.localQueue.forEach((_ref3) => {
734 let _ref3$from = _ref3.from,
735 from = _ref3$from === void 0 ? {} : _ref3$from,
736 _ref3$to = _ref3.to,
737 to = _ref3$to === void 0 ? {} : _ref3$to;
738 if (is.obj(from)) this.merged = _extends({}, from, this.merged);
739 if (is.obj(to)) this.merged = _extends({}, this.merged, to);
740 });
741 } // The guid helps us tracking frames, a new queue over an old one means an override
742 // We discard async calls in that caseÍ
743
744
745 const local = this.local = ++this.guid;
746 const queue = this.localQueue = this.queue;
747 this.queue = []; // Go through each entry and execute it
748
749 queue.forEach((_ref4, index) => {
750 let delay = _ref4.delay,
751 props = _objectWithoutPropertiesLoose(_ref4, ["delay"]);
752
753 const cb = finished => {
754 if (index === queue.length - 1 && local === this.guid && finished) {
755 this.idle = true;
756 if (this.props.onRest) this.props.onRest(this.merged);
757 }
758
759 if (onEnd) onEnd();
760 }; // Entries can be delayed, ansyc or immediate
761
762
763 let async = is.arr(props.to) || is.fun(props.to);
764
765 if (delay) {
766 setTimeout(() => {
767 if (local === this.guid) {
768 if (async) this.runAsync(props, cb);else this.diff(props).start(cb);
769 }
770 }, delay);
771 } else if (async) this.runAsync(props, cb);else this.diff(props).start(cb);
772 });
773 } // Otherwise we kick of the frameloop
774 else {
775 if (is.fun(onEnd)) this.listeners.push(onEnd);
776 if (this.props.onStart) this.props.onStart();
777 start(this);
778 }
779
780 return this;
781 }
782
783 stop(finished) {
784 this.listeners.forEach(onEnd => onEnd(finished));
785 this.listeners = [];
786 return this;
787 }
788 /** Pause sets onEnd listeners free, but also removes the controller from the frameloop */
789
790
791 pause(finished) {
792 this.stop(true);
793 if (finished) stop(this);
794 return this;
795 }
796
797 runAsync(_ref5, onEnd) {
798 var _this = this;
799
800 let delay = _ref5.delay,
801 props = _objectWithoutPropertiesLoose(_ref5, ["delay"]);
802
803 const local = this.local; // If "to" is either a function or an array it will be processed async, therefor "to" should be empty right now
804 // If the view relies on certain values "from" has to be present
805
806 let queue = Promise.resolve(undefined);
807
808 if (is.arr(props.to)) {
809 for (let i = 0; i < props.to.length; i++) {
810 const index = i;
811
812 const fresh = _extends({}, props, {
813 to: props.to[index]
814 });
815
816 if (is.arr(fresh.config)) fresh.config = fresh.config[index];
817 queue = queue.then(() => {
818 //this.stop()
819 if (local === this.guid) return new Promise(r => this.diff(interpolateTo(fresh)).start(r));
820 });
821 }
822 } else if (is.fun(props.to)) {
823 let index = 0;
824 let last;
825 queue = queue.then(() => props.to( // next(props)
826 p => {
827 const fresh = _extends({}, props, interpolateTo(p));
828
829 if (is.arr(fresh.config)) fresh.config = fresh.config[index];
830 index++; //this.stop()
831
832 if (local === this.guid) return last = new Promise(r => this.diff(fresh).start(r));
833 return;
834 }, // cancel()
835 function (finished) {
836 if (finished === void 0) {
837 finished = true;
838 }
839
840 return _this.stop(finished);
841 }).then(() => last));
842 }
843
844 queue.then(onEnd);
845 }
846
847 diff(props) {
848 this.props = _extends({}, this.props, props);
849 let _this$props = this.props,
850 _this$props$from = _this$props.from,
851 from = _this$props$from === void 0 ? {} : _this$props$from,
852 _this$props$to = _this$props.to,
853 to = _this$props$to === void 0 ? {} : _this$props$to,
854 _this$props$config = _this$props.config,
855 config = _this$props$config === void 0 ? {} : _this$props$config,
856 reverse = _this$props.reverse,
857 attach = _this$props.attach,
858 reset = _this$props.reset,
859 immediate = _this$props.immediate; // Reverse values when requested
860
861 if (reverse) {
862 var _ref6 = [to, from];
863 from = _ref6[0];
864 to = _ref6[1];
865 } // This will collect all props that were ever set, reset merged props when necessary
866
867
868 this.merged = _extends({}, from, this.merged, to);
869 this.hasChanged = false; // Attachment handling, trailed springs can "attach" themselves to a previous spring
870
871 let target = attach && attach(this); // Reduces input { name: value } pairs into animated values
872
873 this.animations = Object.entries(this.merged).reduce((acc, _ref7) => {
874 let name = _ref7[0],
875 value = _ref7[1];
876 // Issue cached entries, except on reset
877 let entry = acc[name] || {}; // Figure out what the value is supposed to be
878
879 const isNumber = is.num(value);
880 const isString = is.str(value) && !value.startsWith('#') && !/\d/.test(value) && !colorNames[value];
881 const isArray = is.arr(value);
882 const isInterpolation = !isNumber && !isArray && !isString;
883 let fromValue = !is.und(from[name]) ? from[name] : value;
884 let toValue = isNumber || isArray ? value : isString ? value : 1;
885 let toConfig = callProp(config, name);
886 if (target) toValue = target.animations[name].parent;
887 let parent = entry.parent,
888 interpolation$$1 = entry.interpolation,
889 toValues = toArray(target ? toValue.getPayload() : toValue),
890 animatedValues;
891 let newValue = value;
892 if (isInterpolation) newValue = interpolation({
893 range: [0, 1],
894 output: [value, value]
895 })(1);
896 let currentValue = interpolation$$1 && interpolation$$1.getValue(); // Change detection flags
897
898 const isFirst = is.und(parent);
899 const isActive = !isFirst && entry.animatedValues.some(v => !v.done);
900 const currentValueDiffersFromGoal = !is.equ(newValue, currentValue);
901 const hasNewGoal = !is.equ(newValue, entry.previous);
902 const hasNewConfig = !is.equ(toConfig, entry.config); // Change animation props when props indicate a new goal (new value differs from previous one)
903 // and current values differ from it. Config changes trigger a new update as well (though probably shouldn't?)
904
905 if (reset || hasNewGoal && currentValueDiffersFromGoal || hasNewConfig) {
906 // Convert regular values into animated values, ALWAYS re-use if possible
907 if (isNumber || isString) parent = interpolation$$1 = entry.parent || new AnimatedValue(fromValue);else if (isArray) parent = interpolation$$1 = entry.parent || new AnimatedValueArray(fromValue);else if (isInterpolation) {
908 let prev = entry.interpolation && entry.interpolation.calc(entry.parent.value);
909 prev = prev !== void 0 && !reset ? prev : fromValue;
910
911 if (entry.parent) {
912 parent = entry.parent;
913 parent.setValue(0, false);
914 } else parent = new AnimatedValue(0);
915
916 const range = {
917 output: [prev, value]
918 };
919
920 if (entry.interpolation) {
921 interpolation$$1 = entry.interpolation;
922 entry.interpolation.updateConfig(range);
923 } else interpolation$$1 = parent.interpolate(range);
924 }
925 toValues = toArray(target ? toValue.getPayload() : toValue);
926 animatedValues = toArray(parent.getPayload());
927 if (reset && !isInterpolation) parent.setValue(fromValue, false);
928 this.hasChanged = true; // Reset animated values
929
930 animatedValues.forEach(value => {
931 value.startPosition = value.value;
932 value.lastPosition = value.value;
933 value.lastVelocity = isActive ? value.lastVelocity : undefined;
934 value.lastTime = isActive ? value.lastTime : undefined;
935 value.startTime = now();
936 value.done = false;
937 value.animatedStyles.clear();
938 }); // Set immediate values
939
940 if (callProp(immediate, name)) parent.setValue(value, false);
941 return _extends({}, acc, {
942 [name]: _extends({}, entry, {
943 name,
944 parent,
945 interpolation: interpolation$$1,
946 animatedValues,
947 toValues,
948 previous: newValue,
949 config: toConfig,
950 fromValues: toArray(parent.getValue()),
951 immediate: callProp(immediate, name),
952 initialVelocity: withDefault(toConfig.velocity, 0),
953 clamp: withDefault(toConfig.clamp, false),
954 precision: withDefault(toConfig.precision, 0.01),
955 tension: withDefault(toConfig.tension, 170),
956 friction: withDefault(toConfig.friction, 26),
957 mass: withDefault(toConfig.mass, 1),
958 duration: toConfig.duration,
959 easing: withDefault(toConfig.easing, t => t),
960 decay: toConfig.decay
961 })
962 });
963 } else {
964 if (!currentValueDiffersFromGoal) {
965 // So ... the current target value (newValue) appears to be different from the previous value,
966 // which normally constitutes an update, but the actual value (currentValue) matches the target!
967 // In order to resolve this without causing an animation update we silently flag the animation as done,
968 // which it technically is. Interpolations also needs a config update with their target set to 1.
969 if (isInterpolation) {
970 parent.setValue(1, false);
971 interpolation$$1.updateConfig({
972 output: [newValue, newValue]
973 });
974 }
975
976 parent.done = true;
977 this.hasChanged = true;
978 return _extends({}, acc, {
979 [name]: _extends({}, acc[name], {
980 previous: newValue
981 })
982 });
983 }
984
985 return acc;
986 }
987 }, this.animations);
988
989 if (this.hasChanged) {
990 // Make animations available to frameloop
991 this.configs = Object.values(this.animations);
992 this.values = {};
993 this.interpolations = {};
994
995 for (let key in this.animations) {
996 this.interpolations[key] = this.animations[key].interpolation;
997 this.values[key] = this.animations[key].interpolation.getValue();
998 }
999 }
1000
1001 return this;
1002 }
1003
1004 destroy() {
1005 this.stop();
1006 this.props = {};
1007 this.merged = {};
1008 this.animations = {};
1009 this.interpolations = {};
1010 this.values = {};
1011 this.configs = [];
1012 this.local = 0;
1013 }
1014
1015}
1016
1017// const INTEGER = '[-+]?\\d+';
1018const NUMBER = '[-+]?\\d*\\.?\\d+';
1019const PERCENTAGE = NUMBER + '%';
1020
1021function call() {
1022 for (var _len = arguments.length, parts = new Array(_len), _key = 0; _key < _len; _key++) {
1023 parts[_key] = arguments[_key];
1024 }
1025
1026 return '\\(\\s*(' + parts.join(')\\s*,\\s*(') + ')\\s*\\)';
1027}
1028
1029const rgb = new RegExp('rgb' + call(NUMBER, NUMBER, NUMBER));
1030const rgba = new RegExp('rgba' + call(NUMBER, NUMBER, NUMBER, NUMBER));
1031const hsl = new RegExp('hsl' + call(NUMBER, PERCENTAGE, PERCENTAGE));
1032const hsla = new RegExp('hsla' + call(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER));
1033const hex3 = /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
1034const hex4 = /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
1035const hex6 = /^#([0-9a-fA-F]{6})$/;
1036const hex8 = /^#([0-9a-fA-F]{8})$/;
1037
1038var colorMatchers = /*#__PURE__*/Object.freeze({
1039 rgb: rgb,
1040 rgba: rgba,
1041 hsl: hsl,
1042 hsla: hsla,
1043 hex3: hex3,
1044 hex4: hex4,
1045 hex6: hex6,
1046 hex8: hex8
1047});
1048
1049const config = {
1050 default: {
1051 tension: 170,
1052 friction: 26
1053 },
1054 gentle: {
1055 tension: 120,
1056 friction: 14
1057 },
1058 wobbly: {
1059 tension: 180,
1060 friction: 12
1061 },
1062 stiff: {
1063 tension: 210,
1064 friction: 20
1065 },
1066 slow: {
1067 tension: 280,
1068 friction: 60
1069 },
1070 molasses: {
1071 tension: 280,
1072 friction: 120
1073 }
1074};
1075
1076var constants = /*#__PURE__*/Object.freeze({
1077 config: config
1078});
1079
1080// http://www.w3.org/TR/css3-color/#svg-color
1081const colors = {
1082 transparent: 0x00000000,
1083 aliceblue: 0xf0f8ffff,
1084 antiquewhite: 0xfaebd7ff,
1085 aqua: 0x00ffffff,
1086 aquamarine: 0x7fffd4ff,
1087 azure: 0xf0ffffff,
1088 beige: 0xf5f5dcff,
1089 bisque: 0xffe4c4ff,
1090 black: 0x000000ff,
1091 blanchedalmond: 0xffebcdff,
1092 blue: 0x0000ffff,
1093 blueviolet: 0x8a2be2ff,
1094 brown: 0xa52a2aff,
1095 burlywood: 0xdeb887ff,
1096 burntsienna: 0xea7e5dff,
1097 cadetblue: 0x5f9ea0ff,
1098 chartreuse: 0x7fff00ff,
1099 chocolate: 0xd2691eff,
1100 coral: 0xff7f50ff,
1101 cornflowerblue: 0x6495edff,
1102 cornsilk: 0xfff8dcff,
1103 crimson: 0xdc143cff,
1104 cyan: 0x00ffffff,
1105 darkblue: 0x00008bff,
1106 darkcyan: 0x008b8bff,
1107 darkgoldenrod: 0xb8860bff,
1108 darkgray: 0xa9a9a9ff,
1109 darkgreen: 0x006400ff,
1110 darkgrey: 0xa9a9a9ff,
1111 darkkhaki: 0xbdb76bff,
1112 darkmagenta: 0x8b008bff,
1113 darkolivegreen: 0x556b2fff,
1114 darkorange: 0xff8c00ff,
1115 darkorchid: 0x9932ccff,
1116 darkred: 0x8b0000ff,
1117 darksalmon: 0xe9967aff,
1118 darkseagreen: 0x8fbc8fff,
1119 darkslateblue: 0x483d8bff,
1120 darkslategray: 0x2f4f4fff,
1121 darkslategrey: 0x2f4f4fff,
1122 darkturquoise: 0x00ced1ff,
1123 darkviolet: 0x9400d3ff,
1124 deeppink: 0xff1493ff,
1125 deepskyblue: 0x00bfffff,
1126 dimgray: 0x696969ff,
1127 dimgrey: 0x696969ff,
1128 dodgerblue: 0x1e90ffff,
1129 firebrick: 0xb22222ff,
1130 floralwhite: 0xfffaf0ff,
1131 forestgreen: 0x228b22ff,
1132 fuchsia: 0xff00ffff,
1133 gainsboro: 0xdcdcdcff,
1134 ghostwhite: 0xf8f8ffff,
1135 gold: 0xffd700ff,
1136 goldenrod: 0xdaa520ff,
1137 gray: 0x808080ff,
1138 green: 0x008000ff,
1139 greenyellow: 0xadff2fff,
1140 grey: 0x808080ff,
1141 honeydew: 0xf0fff0ff,
1142 hotpink: 0xff69b4ff,
1143 indianred: 0xcd5c5cff,
1144 indigo: 0x4b0082ff,
1145 ivory: 0xfffff0ff,
1146 khaki: 0xf0e68cff,
1147 lavender: 0xe6e6faff,
1148 lavenderblush: 0xfff0f5ff,
1149 lawngreen: 0x7cfc00ff,
1150 lemonchiffon: 0xfffacdff,
1151 lightblue: 0xadd8e6ff,
1152 lightcoral: 0xf08080ff,
1153 lightcyan: 0xe0ffffff,
1154 lightgoldenrodyellow: 0xfafad2ff,
1155 lightgray: 0xd3d3d3ff,
1156 lightgreen: 0x90ee90ff,
1157 lightgrey: 0xd3d3d3ff,
1158 lightpink: 0xffb6c1ff,
1159 lightsalmon: 0xffa07aff,
1160 lightseagreen: 0x20b2aaff,
1161 lightskyblue: 0x87cefaff,
1162 lightslategray: 0x778899ff,
1163 lightslategrey: 0x778899ff,
1164 lightsteelblue: 0xb0c4deff,
1165 lightyellow: 0xffffe0ff,
1166 lime: 0x00ff00ff,
1167 limegreen: 0x32cd32ff,
1168 linen: 0xfaf0e6ff,
1169 magenta: 0xff00ffff,
1170 maroon: 0x800000ff,
1171 mediumaquamarine: 0x66cdaaff,
1172 mediumblue: 0x0000cdff,
1173 mediumorchid: 0xba55d3ff,
1174 mediumpurple: 0x9370dbff,
1175 mediumseagreen: 0x3cb371ff,
1176 mediumslateblue: 0x7b68eeff,
1177 mediumspringgreen: 0x00fa9aff,
1178 mediumturquoise: 0x48d1ccff,
1179 mediumvioletred: 0xc71585ff,
1180 midnightblue: 0x191970ff,
1181 mintcream: 0xf5fffaff,
1182 mistyrose: 0xffe4e1ff,
1183 moccasin: 0xffe4b5ff,
1184 navajowhite: 0xffdeadff,
1185 navy: 0x000080ff,
1186 oldlace: 0xfdf5e6ff,
1187 olive: 0x808000ff,
1188 olivedrab: 0x6b8e23ff,
1189 orange: 0xffa500ff,
1190 orangered: 0xff4500ff,
1191 orchid: 0xda70d6ff,
1192 palegoldenrod: 0xeee8aaff,
1193 palegreen: 0x98fb98ff,
1194 paleturquoise: 0xafeeeeff,
1195 palevioletred: 0xdb7093ff,
1196 papayawhip: 0xffefd5ff,
1197 peachpuff: 0xffdab9ff,
1198 peru: 0xcd853fff,
1199 pink: 0xffc0cbff,
1200 plum: 0xdda0ddff,
1201 powderblue: 0xb0e0e6ff,
1202 purple: 0x800080ff,
1203 rebeccapurple: 0x663399ff,
1204 red: 0xff0000ff,
1205 rosybrown: 0xbc8f8fff,
1206 royalblue: 0x4169e1ff,
1207 saddlebrown: 0x8b4513ff,
1208 salmon: 0xfa8072ff,
1209 sandybrown: 0xf4a460ff,
1210 seagreen: 0x2e8b57ff,
1211 seashell: 0xfff5eeff,
1212 sienna: 0xa0522dff,
1213 silver: 0xc0c0c0ff,
1214 skyblue: 0x87ceebff,
1215 slateblue: 0x6a5acdff,
1216 slategray: 0x708090ff,
1217 slategrey: 0x708090ff,
1218 snow: 0xfffafaff,
1219 springgreen: 0x00ff7fff,
1220 steelblue: 0x4682b4ff,
1221 tan: 0xd2b48cff,
1222 teal: 0x008080ff,
1223 thistle: 0xd8bfd8ff,
1224 tomato: 0xff6347ff,
1225 turquoise: 0x40e0d0ff,
1226 violet: 0xee82eeff,
1227 wheat: 0xf5deb3ff,
1228 white: 0xffffffff,
1229 whitesmoke: 0xf5f5f5ff,
1230 yellow: 0xffff00ff,
1231 yellowgreen: 0x9acd32ff
1232};
1233
1234/*
1235https://github.com/react-community/normalize-css-color
1236
1237BSD 3-Clause License
1238
1239Copyright (c) 2016, React Community
1240All rights reserved.
1241
1242Redistribution and use in source and binary forms, with or without
1243modification, are permitted provided that the following conditions are met:
1244
1245* Redistributions of source code must retain the above copyright notice, this
1246 list of conditions and the following disclaimer.
1247
1248* Redistributions in binary form must reproduce the above copyright notice,
1249 this list of conditions and the following disclaimer in the documentation
1250 and/or other materials provided with the distribution.
1251
1252* Neither the name of the copyright holder nor the names of its
1253 contributors may be used to endorse or promote products derived from
1254 this software without specific prior written permission.
1255
1256THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1257AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1258IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1259DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1260FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1261DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1262SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1263CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1264OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1265OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1266*/
1267function normalizeColor(color) {
1268 let match;
1269
1270 if (typeof color === 'number') {
1271 return color >>> 0 === color && color >= 0 && color <= 0xffffffff ? color : null;
1272 } // Ordered based on occurrences on Facebook codebase
1273
1274
1275 if (match = hex6.exec(color)) return parseInt(match[1] + 'ff', 16) >>> 0;
1276 if (colors.hasOwnProperty(color)) return colors[color];
1277
1278 if (match = rgb.exec(color)) {
1279 return (parse255(match[1]) << 24 | // r
1280 parse255(match[2]) << 16 | // g
1281 parse255(match[3]) << 8 | // b
1282 0x000000ff) >>> // a
1283 0;
1284 }
1285
1286 if (match = rgba.exec(color)) {
1287 return (parse255(match[1]) << 24 | // r
1288 parse255(match[2]) << 16 | // g
1289 parse255(match[3]) << 8 | // b
1290 parse1(match[4])) >>> // a
1291 0;
1292 }
1293
1294 if (match = hex3.exec(color)) {
1295 return parseInt(match[1] + match[1] + // r
1296 match[2] + match[2] + // g
1297 match[3] + match[3] + // b
1298 'ff', // a
1299 16) >>> 0;
1300 } // https://drafts.csswg.org/css-color-4/#hex-notation
1301
1302
1303 if (match = hex8.exec(color)) return parseInt(match[1], 16) >>> 0;
1304
1305 if (match = hex4.exec(color)) {
1306 return parseInt(match[1] + match[1] + // r
1307 match[2] + match[2] + // g
1308 match[3] + match[3] + // b
1309 match[4] + match[4], // a
1310 16) >>> 0;
1311 }
1312
1313 if (match = hsl.exec(color)) {
1314 return (hslToRgb(parse360(match[1]), // h
1315 parsePercentage(match[2]), // s
1316 parsePercentage(match[3]) // l
1317 ) | 0x000000ff) >>> // a
1318 0;
1319 }
1320
1321 if (match = hsla.exec(color)) {
1322 return (hslToRgb(parse360(match[1]), // h
1323 parsePercentage(match[2]), // s
1324 parsePercentage(match[3]) // l
1325 ) | parse1(match[4])) >>> // a
1326 0;
1327 }
1328
1329 return null;
1330}
1331
1332function hue2rgb(p, q, t) {
1333 if (t < 0) t += 1;
1334 if (t > 1) t -= 1;
1335 if (t < 1 / 6) return p + (q - p) * 6 * t;
1336 if (t < 1 / 2) return q;
1337 if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
1338 return p;
1339}
1340
1341function hslToRgb(h, s, l) {
1342 const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1343 const p = 2 * l - q;
1344 const r = hue2rgb(p, q, h + 1 / 3);
1345 const g = hue2rgb(p, q, h);
1346 const b = hue2rgb(p, q, h - 1 / 3);
1347 return Math.round(r * 255) << 24 | Math.round(g * 255) << 16 | Math.round(b * 255) << 8;
1348}
1349
1350function parse255(str) {
1351 const int = parseInt(str, 10);
1352 if (int < 0) return 0;
1353 if (int > 255) return 255;
1354 return int;
1355}
1356
1357function parse360(str) {
1358 const int = parseFloat(str);
1359 return (int % 360 + 360) % 360 / 360;
1360}
1361
1362function parse1(str) {
1363 const num = parseFloat(str);
1364 if (num < 0) return 0;
1365 if (num > 1) return 255;
1366 return Math.round(num * 255);
1367}
1368
1369function parsePercentage(str) {
1370 // parseFloat conveniently ignores the final %
1371 const int = parseFloat(str);
1372 if (int < 0) return 0;
1373 if (int > 100) return 1;
1374 return int / 100;
1375}
1376
1377function colorToRgba(input) {
1378 let int32Color = normalizeColor(input);
1379 if (int32Color === null) return input;
1380 int32Color = int32Color || 0;
1381 let r = (int32Color & 0xff000000) >>> 24;
1382 let g = (int32Color & 0x00ff0000) >>> 16;
1383 let b = (int32Color & 0x0000ff00) >>> 8;
1384 let a = (int32Color & 0x000000ff) / 255;
1385 return `rgba(${r}, ${g}, ${b}, ${a})`;
1386} // Problem: https://github.com/animatedjs/animated/pull/102
1387// Solution: https://stackoverflow.com/questions/638565/parsing-scientific-notation-sensibly/658662
1388
1389
1390const stringShapeRegex = /[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; // Covers rgb, rgba, hsl, hsla
1391// Taken from https://gist.github.com/olmokramer/82ccce673f86db7cda5e
1392
1393const colorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d\.]+%?\))/gi; // Covers color names (transparent, blue, etc.)
1394
1395const colorNamesRegex = new RegExp(`(${Object.keys(colors).join('|')})`, 'g');
1396/**
1397 * Supports string shapes by extracting numbers so new values can be computed,
1398 * and recombines those values into new strings of the same shape. Supports
1399 * things like:
1400 *
1401 * rgba(123, 42, 99, 0.36) // colors
1402 * -45deg // values with units
1403 * 0 2px 2px 0px rgba(0, 0, 0, 0.12) // box shadows
1404 */
1405
1406const createStringInterpolator = config => {
1407 // Replace colors with rgba
1408 const outputRange = config.output.map(rangeValue => rangeValue.replace(colorRegex, colorToRgba)).map(rangeValue => rangeValue.replace(colorNamesRegex, colorToRgba));
1409 const outputRanges = outputRange[0].match(stringShapeRegex).map(() => []);
1410 outputRange.forEach(value => {
1411 value.match(stringShapeRegex).forEach((number, i) => outputRanges[i].push(+number));
1412 });
1413 const interpolations = outputRange[0].match(stringShapeRegex).map((_value, i) => createInterpolator(_extends({}, config, {
1414 output: outputRanges[i]
1415 })));
1416 return input => {
1417 let i = 0;
1418 return outputRange[0] // 'rgba(0, 100, 200, 0)'
1419 // ->
1420 // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...'
1421 .replace(stringShapeRegex, () => interpolations[i++](input)) // rgba requires that the r,g,b are integers.... so we want to round them, but we *dont* want to
1422 // round the opacity (4th column).
1423 .replace(/rgba\(([0-9\.-]+), ([0-9\.-]+), ([0-9\.-]+), ([0-9\.-]+)\)/gi, (_, p1, p2, p3, p4) => `rgba(${Math.round(p1)}, ${Math.round(p2)}, ${Math.round(p3)}, ${p4})`);
1424 };
1425};
1426
1427const interpolate$1 = (parents, range, output) => parents && new AnimatedInterpolation(parents, range, output);
1428
1429/** API
1430 * useChain(references, timeSteps, timeFrame)
1431 */
1432
1433function useChain(refs, timeSteps, timeFrame) {
1434 if (timeFrame === void 0) {
1435 timeFrame = 1000;
1436 }
1437
1438 const previous = useRef();
1439 useEffect(() => {
1440 if (is.equ(refs, previous.current)) refs.forEach((_ref) => {
1441 let current = _ref.current;
1442 return current && current.start();
1443 });else if (timeSteps) {
1444 refs.forEach((_ref2, index) => {
1445 let current = _ref2.current;
1446
1447 if (current) {
1448 const ctrls = current.controllers;
1449
1450 if (ctrls.length) {
1451 const t = timeFrame * timeSteps[index];
1452 ctrls.forEach(ctrl => {
1453 ctrl.queue = ctrl.queue.map(e => _extends({}, e, {
1454 delay: e.delay + t
1455 }));
1456 ctrl.start();
1457 });
1458 }
1459 }
1460 });
1461 } else refs.reduce((q, _ref3, rI) => {
1462 let current = _ref3.current;
1463 return q = q.then(() => current.start());
1464 }, Promise.resolve());
1465 previous.current = refs;
1466 });
1467}
1468
1469/** API
1470 * const props = useSprings(number, [{ ... }, { ... }, ...])
1471 * const [props, set] = useSprings(number, (i, controller) => ({ ... }))
1472 */
1473
1474const useSprings = (length, props) => {
1475 const mounted = useRef(false);
1476 const ctrl = useRef();
1477 const isFn = is.fun(props); // The controller maintains the animation values, starts and stops animations
1478
1479 const _useMemo = useMemo(() => {
1480 // Remove old controllers
1481 if (ctrl.current) {
1482 ctrl.current.map(c => c.destroy());
1483 ctrl.current = undefined;
1484 }
1485
1486 let ref;
1487 return [new Array(length).fill().map((_, i) => {
1488 const ctrl = new Controller();
1489 const newProps = isFn ? callProp(props, i, ctrl) : props[i];
1490 if (i === 0) ref = newProps.ref;
1491 ctrl.update(newProps);
1492 if (!ref) ctrl.start();
1493 return ctrl;
1494 }), ref];
1495 }, [length]),
1496 controllers = _useMemo[0],
1497 ref = _useMemo[1];
1498
1499 ctrl.current = controllers; // The hooks reference api gets defined here ...
1500
1501 const api = useImperativeHandle(ref, () => ({
1502 start: () => Promise.all(ctrl.current.map(c => new Promise(r => c.start(r)))),
1503 stop: finished => ctrl.current.forEach(c => c.stop(finished)),
1504
1505 get controllers() {
1506 return ctrl.current;
1507 }
1508
1509 })); // This function updates the controllers
1510
1511 const updateCtrl = useMemo(() => updateProps => ctrl.current.map((c, i) => {
1512 c.update(isFn ? callProp(updateProps, i, c) : updateProps[i]);
1513 if (!ref) c.start();
1514 }), [length]); // Update controller if props aren't functional
1515
1516 useEffect(() => {
1517 if (mounted.current) {
1518 if (!isFn) updateCtrl(props);
1519 } else if (!ref) ctrl.current.forEach(c => c.start());
1520 }); // Update mounted flag and destroy controller on unmount
1521
1522 useEffect(() => (mounted.current = true, () => ctrl.current.forEach(c => c.destroy())), []); // Return animated props, or, anim-props + the update-setter above
1523
1524 const propValues = ctrl.current.map(c => c.getValues());
1525 return isFn ? [propValues, updateCtrl, finished => ctrl.current.forEach(c => c.pause(finished))] : propValues;
1526};
1527
1528/** API
1529 * const props = useSpring({ ... })
1530 * const [props, set] = useSpring(() => ({ ... }))
1531 */
1532
1533const useSpring = props => {
1534 const isFn = is.fun(props);
1535
1536 const _useSprings = useSprings(1, isFn ? props : [props]),
1537 result = _useSprings[0],
1538 set = _useSprings[1],
1539 pause = _useSprings[2];
1540
1541 return isFn ? [result[0], set, pause] : result;
1542};
1543
1544/** API
1545 * const trails = useTrail(number, { ... })
1546 * const [trails, set] = useTrail(number, () => ({ ... }))
1547 */
1548
1549const useTrail = (length, props) => {
1550 const mounted = useRef(false);
1551 const isFn = is.fun(props);
1552 const updateProps = callProp(props);
1553 const instances = useRef();
1554
1555 const _useSprings = useSprings(length, (i, ctrl) => {
1556 if (i === 0) instances.current = [];
1557 instances.current.push(ctrl);
1558 return _extends({}, updateProps, {
1559 config: callProp(updateProps.config, i),
1560 attach: i > 0 && (() => instances.current[i - 1])
1561 });
1562 }),
1563 result = _useSprings[0],
1564 set = _useSprings[1],
1565 pause = _useSprings[2]; // Set up function to update controller
1566
1567
1568 const updateCtrl = useMemo(() => props => set((i, ctrl) => {
1569 const last = props.reverse ? i === 0 : length - 1 === i;
1570 const attachIdx = props.reverse ? i + 1 : i - 1;
1571 const attachController = instances.current[attachIdx];
1572 return _extends({}, props, {
1573 config: callProp(props.config || updateProps.config, i),
1574 attach: attachController && (() => attachController)
1575 });
1576 }), [length, updateProps.reverse]); // Update controller if props aren't functional
1577
1578 useEffect(() => void (mounted.current && !isFn && updateCtrl(props))); // Update mounted flag and destroy controller on unmount
1579
1580 useEffect(() => void (mounted.current = true), []);
1581 return isFn ? [result, updateCtrl, pause] : result;
1582};
1583
1584/** API
1585 * const transitions = useTransition(items, itemKeys, { ... })
1586 * const [transitions, update] = useTransition(items, itemKeys, () => ({ ... }))
1587 */
1588
1589let guid = 0;
1590const ENTER = 'enter';
1591const LEAVE = 'leave';
1592const UPDATE = 'update';
1593
1594const mapKeys = (items, keys) => (typeof keys === 'function' ? items.map(keys) : toArray(keys)).map(String);
1595
1596const get = props => {
1597 let items = props.items,
1598 _props$keys = props.keys,
1599 keys = _props$keys === void 0 ? item => item : _props$keys,
1600 rest = _objectWithoutPropertiesLoose(props, ["items", "keys"]);
1601
1602 items = toArray(items !== void 0 ? items : null);
1603 return _extends({
1604 items,
1605 keys: mapKeys(items, keys)
1606 }, rest);
1607};
1608
1609function useTransition(input, keyTransform, config) {
1610 const props = _extends({
1611 items: input,
1612 keys: keyTransform || (i => i)
1613 }, config);
1614
1615 const _get = get(props),
1616 _get$lazy = _get.lazy,
1617 lazy = _get$lazy === void 0 ? false : _get$lazy,
1618 _get$unique = _get.unique,
1619 _get$reset = _get.reset,
1620 reset = _get$reset === void 0 ? false : _get$reset,
1621 enter = _get.enter,
1622 leave = _get.leave,
1623 update = _get.update,
1624 onDestroyed = _get.onDestroyed,
1625 keys = _get.keys,
1626 items = _get.items,
1627 onFrame = _get.onFrame,
1628 _onRest = _get.onRest,
1629 onStart = _get.onStart,
1630 ref = _get.ref,
1631 extra = _objectWithoutPropertiesLoose(_get, ["lazy", "unique", "reset", "enter", "leave", "update", "onDestroyed", "keys", "items", "onFrame", "onRest", "onStart", "ref"]);
1632
1633 const forceUpdate = useForceUpdate();
1634 const mounted = useRef(false);
1635 const state = useRef({
1636 mounted: false,
1637 first: true,
1638 deleted: [],
1639 current: {},
1640 transitions: [],
1641 prevProps: {},
1642 paused: !!props.ref,
1643 instances: !mounted.current && new Map(),
1644 forceUpdate
1645 });
1646 useImperativeHandle(props.ref, () => ({
1647 start: () => Promise.all(Array.from(state.current.instances).map((_ref) => {
1648 let c = _ref[1];
1649 return new Promise(r => c.start(r));
1650 })),
1651 stop: finished => Array.from(state.current.instances).forEach((_ref2) => {
1652 let c = _ref2[1];
1653 return c.stop(finished);
1654 }),
1655
1656 get controllers() {
1657 return Array.from(state.current.instances).map((_ref3) => {
1658 let c = _ref3[1];
1659 return c;
1660 });
1661 }
1662
1663 })); // Update state
1664
1665 state.current = diffItems(state.current, props);
1666
1667 if (state.current.changed) {
1668 // Update state
1669 state.current.transitions.forEach(transition => {
1670 const slot = transition.slot,
1671 from = transition.from,
1672 to = transition.to,
1673 config = transition.config,
1674 trail = transition.trail,
1675 key = transition.key,
1676 item = transition.item;
1677 if (!state.current.instances.has(key)) state.current.instances.set(key, new Controller()); // update the map object
1678
1679 const ctrl = state.current.instances.get(key);
1680
1681 const newProps = _extends({}, extra, {
1682 to,
1683 from,
1684 config,
1685 ref,
1686 onRest: values => {
1687 if (state.current.mounted) {
1688 if (transition.destroyed) {
1689 // If no ref is given delete destroyed items immediately
1690 if (!ref && !lazy) cleanUp(state, key);
1691 if (onDestroyed) onDestroyed(item);
1692 } // A transition comes to rest once all its springs conclude
1693
1694
1695 const curInstances = Array.from(state.current.instances);
1696 const active = curInstances.some((_ref4) => {
1697 let c = _ref4[1];
1698 return !c.idle;
1699 });
1700 if (!active && (ref || lazy) && state.current.deleted.length > 0) cleanUp(state);
1701 if (_onRest) _onRest(item, slot, values);
1702 }
1703 },
1704 onStart: onStart && (() => onStart(item, slot)),
1705 onFrame: onFrame && (values => onFrame(item, slot, values)),
1706 delay: trail,
1707 reset: reset && slot === ENTER // Update controller
1708
1709 });
1710
1711 ctrl.update(newProps);
1712 if (!state.current.paused) ctrl.start();
1713 });
1714 }
1715
1716 useEffect(() => {
1717 state.current.mounted = mounted.current = true;
1718 return () => {
1719 state.current.mounted = mounted.current = false;
1720 Array.from(state.current.instances).map((_ref5) => {
1721 let c = _ref5[1];
1722 return c.destroy();
1723 });
1724 state.current.instances.clear();
1725 };
1726 }, []);
1727 return state.current.transitions.map((_ref6) => {
1728 let item = _ref6.item,
1729 slot = _ref6.slot,
1730 key = _ref6.key;
1731 return {
1732 item,
1733 key,
1734 state: slot,
1735 props: state.current.instances.get(key).getValues()
1736 };
1737 });
1738}
1739
1740function cleanUp(state, filterKey) {
1741 const deleted = state.current.deleted;
1742
1743 for (let _ref7 of deleted) {
1744 let key = _ref7.key;
1745
1746 const filter = t => t.key !== key;
1747
1748 if (is.und(filterKey) || filterKey === key) {
1749 state.current.instances.delete(key);
1750 state.current.transitions = state.current.transitions.filter(filter);
1751 state.current.deleted = state.current.deleted.filter(filter);
1752 }
1753 }
1754
1755 state.current.forceUpdate();
1756}
1757
1758function diffItems(_ref8, props) {
1759 let first = _ref8.first,
1760 prevProps = _ref8.prevProps,
1761 state = _objectWithoutPropertiesLoose(_ref8, ["first", "prevProps"]);
1762
1763 let _get2 = get(props),
1764 items = _get2.items,
1765 keys = _get2.keys,
1766 initial = _get2.initial,
1767 from = _get2.from,
1768 enter = _get2.enter,
1769 leave = _get2.leave,
1770 update = _get2.update,
1771 _get2$trail = _get2.trail,
1772 trail = _get2$trail === void 0 ? 0 : _get2$trail,
1773 unique = _get2.unique,
1774 config = _get2.config,
1775 _get2$order = _get2.order,
1776 order = _get2$order === void 0 ? [ENTER, LEAVE, UPDATE] : _get2$order;
1777
1778 let _get3 = get(prevProps),
1779 _keys = _get3.keys,
1780 _items = _get3.items;
1781
1782 let current = _extends({}, state.current);
1783
1784 let deleted = [...state.deleted]; // Compare next keys with current keys
1785
1786 let currentKeys = Object.keys(current);
1787 let currentSet = new Set(currentKeys);
1788 let nextSet = new Set(keys);
1789 let added = keys.filter(item => !currentSet.has(item));
1790 let removed = state.transitions.filter(item => !item.destroyed && !nextSet.has(item.originalKey)).map(i => i.originalKey);
1791 let updated = keys.filter(item => currentSet.has(item));
1792 let delay = -trail;
1793
1794 while (order.length) {
1795 const changeType = order.shift();
1796
1797 switch (changeType) {
1798 case ENTER:
1799 {
1800 added.forEach((key, index) => {
1801 // In unique mode, remove fading out transitions if their key comes in again
1802 if (unique && deleted.find(d => d.originalKey === key)) deleted = deleted.filter(t => t.originalKey !== key);
1803 const keyIndex = keys.indexOf(key);
1804 const item = items[keyIndex];
1805 const slot = first && initial !== void 0 ? 'initial' : ENTER;
1806 current[key] = {
1807 slot,
1808 originalKey: key,
1809 key: unique ? String(key) : guid++,
1810 item,
1811 trail: delay = delay + trail,
1812 config: callProp(config, item, slot),
1813 from: callProp(first ? initial !== void 0 ? initial || {} : from : from, item),
1814 to: callProp(enter, item)
1815 };
1816 });
1817 break;
1818 }
1819
1820 case LEAVE:
1821 {
1822 removed.forEach(key => {
1823 const keyIndex = _keys.indexOf(key);
1824
1825 const item = _items[keyIndex];
1826 const slot = LEAVE;
1827 deleted.unshift(_extends({}, current[key], {
1828 slot,
1829 destroyed: true,
1830 left: _keys[Math.max(0, keyIndex - 1)],
1831 right: _keys[Math.min(_keys.length, keyIndex + 1)],
1832 trail: delay = delay + trail,
1833 config: callProp(config, item, slot),
1834 to: callProp(leave, item)
1835 }));
1836 delete current[key];
1837 });
1838 break;
1839 }
1840
1841 case UPDATE:
1842 {
1843 updated.forEach(key => {
1844 const keyIndex = keys.indexOf(key);
1845 const item = items[keyIndex];
1846 const slot = UPDATE;
1847 current[key] = _extends({}, current[key], {
1848 item,
1849 slot,
1850 trail: delay = delay + trail,
1851 config: callProp(config, item, slot),
1852 to: callProp(update, item)
1853 });
1854 });
1855 break;
1856 }
1857 }
1858 }
1859
1860 let out = keys.map(key => current[key]); // This tries to restore order for deleted items by finding their last known siblings
1861 // only using the left sibling to keep order placement consistent for all deleted items
1862
1863 deleted.forEach((_ref9) => {
1864 let left = _ref9.left,
1865 right = _ref9.right,
1866 item = _objectWithoutPropertiesLoose(_ref9, ["left", "right"]);
1867
1868 let pos; // Was it the element on the left, if yes, move there ...
1869
1870 if ((pos = out.findIndex(t => t.originalKey === left)) !== -1) pos += 1; // And if nothing else helps, move it to the start ¯\_(ツ)_/¯
1871
1872 pos = Math.max(0, pos);
1873 out = [...out.slice(0, pos), item, ...out.slice(pos)];
1874 });
1875 return _extends({}, state, {
1876 changed: added.length || removed.length || updated.length,
1877 first: first && added.length === 0,
1878 transitions: out,
1879 current,
1880 deleted,
1881 prevProps: props
1882 });
1883}
1884
1885export { Globals, AnimatedInterpolation, interpolate$1 as interpolate, createAnimatedComponent as animated, createInterpolator, Animated, AnimatedValueArray, AnimatedProps, AnimatedStyle, AnimatedValue, Controller, FrameLoop as frameloop, colorMatchers, helpers, constants, config, colors as colorNames, normalizeColor, createStringInterpolator as createInterpolation, useSpring, useTrail, useTransition, useChain, useSprings };