UNPKG

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