UNPKG

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