UNPKG

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