UNPKG

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