UNPKG

265 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 tslib = require('tslib');
8var sync = require('framesync');
9var sync__default = _interopDefault(sync);
10var popcorn = require('@popmotion/popcorn');
11var heyListen = require('hey-listen');
12var styleValueTypes = require('style-value-types');
13var popmotion = require('popmotion');
14var easingLookup = require('@popmotion/easing');
15var React = require('react');
16var React__default = _interopDefault(React);
17
18var isRefObject = function (ref) {
19 return typeof ref === "object" && ref.hasOwnProperty("current");
20};
21
22var isFloat = function (value) {
23 return !isNaN(parseFloat(value));
24};
25/**
26 * `MotionValue` is used to track the state and velocity of motion values.
27 *
28 * @public
29 */
30var MotionValue = /** @class */ (function () {
31 /**
32 * @param init - The initiating value
33 * @param config - Optional configuration options
34 *
35 * - `transformer`: A function to transform incoming values with.
36 *
37 * @internal
38 */
39 function MotionValue(init) {
40 var _this = this;
41 /**
42 * Duration, in milliseconds, since last updating frame.
43 *
44 * @internal
45 */
46 this.timeDelta = 0;
47 /**
48 * Timestamp of the last time this `MotionValue` was updated.
49 *
50 * @internal
51 */
52 this.lastUpdated = 0;
53 /**
54 * Tracks whether this value can output a velocity. Currently this is only true
55 * if the value is numerical, but we might be able to widen the scope here and support
56 * other value types.
57 *
58 * @internal
59 */
60 this.canTrackVelocity = false;
61 this.updateAndNotify = function (v, render) {
62 if (render === void 0) { render = true; }
63 _this.prev = _this.current;
64 _this.current = v;
65 if (_this.updateSubscribers && _this.prev !== _this.current) {
66 _this.updateSubscribers.forEach(_this.notifySubscriber);
67 }
68 if (render && _this.renderSubscribers) {
69 _this.renderSubscribers.forEach(_this.notifySubscriber);
70 }
71 // Update timestamp
72 var _a = sync.getFrameData(), delta = _a.delta, timestamp = _a.timestamp;
73 if (_this.lastUpdated !== timestamp) {
74 _this.timeDelta = delta;
75 _this.lastUpdated = timestamp;
76 sync__default.postRender(_this.scheduleVelocityCheck);
77 }
78 };
79 /**
80 * Notify a subscriber with the latest value.
81 *
82 * This is an instanced and bound function to prevent generating a new
83 * function once per frame.
84 *
85 * @param subscriber - The subscriber to notify.
86 *
87 * @internal
88 */
89 this.notifySubscriber = function (subscriber) {
90 subscriber(_this.current);
91 };
92 /**
93 * Schedule a velocity check for the next frame.
94 *
95 * This is an instanced and bound function to prevent generating a new
96 * function once per frame.
97 *
98 * @internal
99 */
100 this.scheduleVelocityCheck = function () { return sync__default.postRender(_this.velocityCheck); };
101 /**
102 * Updates `prev` with `current` if the value hasn't been updated this frame.
103 * This ensures velocity calculations return `0`.
104 *
105 * This is an instanced and bound function to prevent generating a new
106 * function once per frame.
107 *
108 * @internal
109 */
110 this.velocityCheck = function (_a) {
111 var timestamp = _a.timestamp;
112 if (timestamp !== _this.lastUpdated) {
113 _this.prev = _this.current;
114 }
115 };
116 this.set(init, false);
117 this.canTrackVelocity = isFloat(this.current);
118 }
119 /**
120 * Subscribes a subscriber function to a subscription list.
121 *
122 * @param subscriptions - A `Set` of subscribers.
123 * @param subscription - A subscriber function.
124 */
125 MotionValue.prototype.subscribeTo = function (subscriptions, subscription) {
126 var _this = this;
127 var updateSubscriber = function () { return subscription(_this.current); };
128 subscriptions.add(updateSubscriber);
129 return function () { return subscriptions.delete(updateSubscriber); };
130 };
131 /**
132 * Adds a function that will be notified when the `MotionValue` is updated.
133 *
134 * It returns a function that, when called, will cancel the subscription.
135 *
136 * When calling `onChange` inside a React component, it should be wrapped with the
137 * `useEffect` hook. As it returns an unsubscribe function, this should be returned
138 * from the `useEffect` function to ensure you don't add duplicate subscribers..
139 *
140 * @library
141 *
142 * ```jsx
143 * function MyComponent() {
144 * const x = useMotionValue(0)
145 * const y = useMotionValue(0)
146 * const opacity = useMotionValue(1)
147 *
148 * useEffect(() => {
149 * function updateOpacity() {
150 * const maxXY = Math.max(x.get(), y.get())
151 * const newOpacity = transform(maxXY, [0, 100], [1, 0])
152 * opacity.set(newOpacity)
153 * }
154 *
155 * const unsubscribeX = x.onChange(updateOpacity)
156 * const unsubscribeY = y.onChange(updateOpacity)
157 *
158 * return () => {
159 * unsubscribeX()
160 * unsubscribeY()
161 * }
162 * }, [])
163 *
164 * return <Frame x={x} />
165 * }
166 * ```
167 *
168 * @motion
169 *
170 * ```jsx
171 * export const MyComponent = () => {
172 * const x = useMotionValue(0)
173 * const y = useMotionValue(0)
174 * const opacity = useMotionValue(1)
175 *
176 * useEffect(() => {
177 * function updateOpacity() {
178 * const maxXY = Math.max(x.get(), y.get())
179 * const newOpacity = transform(maxXY, [0, 100], [1, 0])
180 * opacity.set(newOpacity)
181 * }
182 *
183 * const unsubscribeX = x.onChange(updateOpacity)
184 * const unsubscribeY = y.onChange(updateOpacity)
185 *
186 * return () => {
187 * unsubscribeX()
188 * unsubscribeY()
189 * }
190 * }, [])
191 *
192 * return <motion.div style={{ x }} />
193 * }
194 * ```
195 *
196 * @internalremarks
197 *
198 * We could look into a `useOnChange` hook if the above lifecycle management proves confusing.
199 *
200 * ```jsx
201 * useOnChange(x, () => {})
202 * ```
203 *
204 * @param subscriber - A function that receives the latest value.
205 * @returns A function that, when called, will cancel this subscription.
206 *
207 * @public
208 */
209 MotionValue.prototype.onChange = function (subscription) {
210 if (!this.updateSubscribers)
211 this.updateSubscribers = new Set();
212 return this.subscribeTo(this.updateSubscribers, subscription);
213 };
214 MotionValue.prototype.clearListeners = function () {
215 var _a;
216 (_a = this.updateSubscribers) === null || _a === void 0 ? void 0 : _a.clear();
217 };
218 /**
219 * Adds a function that will be notified when the `MotionValue` requests a render.
220 *
221 * @param subscriber - A function that's provided the latest value.
222 * @returns A function that, when called, will cancel this subscription.
223 *
224 * @internal
225 */
226 MotionValue.prototype.onRenderRequest = function (subscription) {
227 if (!this.renderSubscribers)
228 this.renderSubscribers = new Set();
229 // Render immediately
230 this.notifySubscriber(subscription);
231 return this.subscribeTo(this.renderSubscribers, subscription);
232 };
233 /**
234 * Attaches a passive effect to the `MotionValue`.
235 *
236 * @internal
237 */
238 MotionValue.prototype.attach = function (passiveEffect) {
239 this.passiveEffect = passiveEffect;
240 };
241 /**
242 * Sets the state of the `MotionValue`.
243 *
244 * @remarks
245 *
246 * ```jsx
247 * const x = useMotionValue(0)
248 * x.set(10)
249 * ```
250 *
251 * @param latest - Latest value to set.
252 * @param render - Whether to notify render subscribers. Defaults to `true`
253 *
254 * @public
255 */
256 MotionValue.prototype.set = function (v, render) {
257 if (render === void 0) { render = true; }
258 if (!render || !this.passiveEffect) {
259 this.updateAndNotify(v, render);
260 }
261 else {
262 this.passiveEffect(v, this.updateAndNotify);
263 }
264 };
265 /**
266 * Returns the latest state of `MotionValue`
267 *
268 * @returns - The latest state of `MotionValue`
269 *
270 * @public
271 */
272 MotionValue.prototype.get = function () {
273 return this.current;
274 };
275 /**
276 * @public
277 */
278 MotionValue.prototype.getPrevious = function () {
279 return this.prev;
280 };
281 /**
282 * Returns the latest velocity of `MotionValue`
283 *
284 * @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical.
285 *
286 * @public
287 */
288 MotionValue.prototype.getVelocity = function () {
289 // This could be isFloat(this.prev) && isFloat(this.current), but that would be wasteful
290 return this.canTrackVelocity
291 ? // These casts could be avoided if parseFloat would be typed better
292 popcorn.velocityPerSecond(parseFloat(this.current) -
293 parseFloat(this.prev), this.timeDelta)
294 : 0;
295 };
296 /**
297 * Registers a new animation to control this `MotionValue`. Only one
298 * animation can drive a `MotionValue` at one time.
299 *
300 * ```jsx
301 * value.start()
302 * ```
303 *
304 * @param animation - A function that starts the provided animation
305 *
306 * @internal
307 */
308 MotionValue.prototype.start = function (animation) {
309 var _this = this;
310 this.stop();
311 return new Promise(function (resolve) {
312 _this.stopAnimation = animation(resolve);
313 }).then(function () { return _this.clearAnimation(); });
314 };
315 /**
316 * Stop the currently active animation.
317 *
318 * @public
319 */
320 MotionValue.prototype.stop = function () {
321 if (this.stopAnimation)
322 this.stopAnimation();
323 this.clearAnimation();
324 };
325 /**
326 * Returns `true` if this value is currently animating.
327 *
328 * @public
329 */
330 MotionValue.prototype.isAnimating = function () {
331 return !!this.stopAnimation;
332 };
333 MotionValue.prototype.clearAnimation = function () {
334 this.stopAnimation = null;
335 };
336 /**
337 * Destroy and clean up subscribers to this `MotionValue`.
338 *
339 * The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically
340 * handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually
341 * created a `MotionValue` via the `motionValue` function.
342 *
343 * @public
344 */
345 MotionValue.prototype.destroy = function () {
346 this.updateSubscribers && this.updateSubscribers.clear();
347 this.renderSubscribers && this.renderSubscribers.clear();
348 this.stop();
349 };
350 return MotionValue;
351}());
352/**
353 * @internal
354 */
355function motionValue(init) {
356 return new MotionValue(init);
357}
358
359/**
360 * VisualElement is an abstract class that provides a generic animation-optimised interface to the
361 * underlying renderer.
362 *
363 * Currently many features interact directly with HTMLVisualElement/SVGVisualElement
364 * but the idea is we can create, for instance, a ThreeVisualElement that extends
365 * VisualElement and we can quickly offer all the same features.
366 */
367var VisualElement = /** @class */ (function () {
368 function VisualElement(parent, ref) {
369 var _this = this;
370 // An iterable list of current children
371 this.children = new Set();
372 // The latest resolved MotionValues
373 this.latest = {};
374 // A map of MotionValues used to animate this element
375 this.values = new Map();
376 // Unsubscription callbacks for each MotionValue
377 this.valueSubscriptions = new Map();
378 // A configuration for this VisualElement, each derived class can extend this.
379 this.config = {};
380 // A pre-bound call to the user-provided `onUpdate` callback. This won't
381 // be called more than once per frame.
382 this.update = function () { return _this.config.onUpdate(_this.latest); };
383 // Pre-bound version of render
384 this.triggerRender = function () { return _this.render(); };
385 this.scheduleRender = function () { return sync__default.render(_this.triggerRender, false, true); };
386 // This function gets passed to the rendered component's `ref` prop
387 // and is used to mount/unmount the VisualElement
388 this.ref = function (element) {
389 element ? _this.mount(element) : _this.unmount();
390 if (!_this.externalRef)
391 return;
392 if (typeof _this.externalRef === "function") {
393 _this.externalRef(element);
394 }
395 else if (isRefObject(_this.externalRef)) {
396 _this.externalRef.current = element;
397 }
398 };
399 // Create a relationship with the provided parent.
400 this.parent = parent;
401 this.rootParent = parent ? parent.rootParent : this;
402 this.treePath = parent ? tslib.__spreadArrays(parent.treePath, [parent]) : [];
403 // Calculate the depth of this node in the VisualElement graph
404 this.depth = parent ? parent.depth + 1 : 0;
405 // A reference to any externally-defined React ref. This might live better
406 // outside the VisualElement and be handled in a hook.
407 this.externalRef = ref;
408 }
409 VisualElement.prototype.subscribe = function (child) {
410 var _this = this;
411 this.children.add(child);
412 return function () { return _this.children.delete(child); };
413 };
414 // Check whether this element has a MotionValue of the provided key
415 VisualElement.prototype.hasValue = function (key) {
416 return this.values.has(key);
417 };
418 // Add a MotionValue
419 VisualElement.prototype.addValue = function (key, value) {
420 if (this.hasValue(key))
421 this.removeValue(key);
422 this.values.set(key, value);
423 this.latest[key] = value.get();
424 if (this.element)
425 this.subscribeToValue(key, value);
426 };
427 // Remove a MotionValue
428 VisualElement.prototype.removeValue = function (key) {
429 var unsubscribe = this.valueSubscriptions.get(key);
430 unsubscribe && unsubscribe();
431 this.values.delete(key);
432 delete this.latest[key];
433 this.valueSubscriptions.delete(key);
434 };
435 VisualElement.prototype.getValue = function (key, defaultValue) {
436 var value = this.values.get(key);
437 if (value === undefined && defaultValue !== undefined) {
438 value = new MotionValue(defaultValue);
439 this.addValue(key, value);
440 }
441 return value;
442 };
443 // Iterate over all MotionValues
444 VisualElement.prototype.forEachValue = function (callback) {
445 this.values.forEach(callback);
446 };
447 // Get the underlying rendered instance of this VisualElement. For instance in
448 // HTMLVisualElement this will be a HTMLElement.
449 VisualElement.prototype.getInstance = function () {
450 return this.element;
451 };
452 VisualElement.prototype.updateConfig = function (config) {
453 if (config === void 0) { config = {}; }
454 this.config = tslib.__assign({}, config);
455 };
456 // Set a single `latest` value
457 VisualElement.prototype.setSingleStaticValue = function (key, value) {
458 this.latest[key] = value;
459 };
460 // Statically set values to `latest` without needing a MotionValue
461 VisualElement.prototype.setStaticValues = function (values, value) {
462 if (typeof values === "string") {
463 this.setSingleStaticValue(values, value);
464 }
465 else {
466 for (var key in values) {
467 this.setSingleStaticValue(key, values[key]);
468 }
469 }
470 };
471 VisualElement.prototype.scheduleUpdateLayoutDelta = function () {
472 sync__default.update(this.rootParent.updateLayoutDelta, false, true);
473 };
474 // Subscribe to changes in a MotionValue
475 VisualElement.prototype.subscribeToValue = function (key, value) {
476 var _this = this;
477 var onChange = function (latest) {
478 _this.setSingleStaticValue(key, latest);
479 _this.latest[key] = latest;
480 _this.config.onUpdate && sync__default.update(_this.update, false, true);
481 };
482 var unsubscribeOnChange = value.onChange(onChange);
483 var unsubscribeOnRender = value.onRenderRequest(this.scheduleRender);
484 this.valueSubscriptions.set(key, function () {
485 unsubscribeOnChange();
486 unsubscribeOnRender();
487 });
488 };
489 // Mount the VisualElement with the actual DOM element
490 VisualElement.prototype.mount = function (element) {
491 var _this = this;
492 heyListen.invariant(!!element, "No ref found. Ensure components created with motion.custom forward refs using React.forwardRef");
493 if (this.parent) {
494 this.removeFromParent = this.parent.subscribe(this);
495 }
496 /**
497 * Save the element to this.element as a semantic API, this.current to the VisualElement
498 * is compatible with existing RefObject APIs.
499 */
500 this.element = this.current = element;
501 // Subscribe to any pre-existing MotionValues
502 this.forEachValue(function (value, key) { return _this.subscribeToValue(key, value); });
503 };
504 // Unmount the VisualElement and cancel any scheduled updates
505 VisualElement.prototype.unmount = function () {
506 var _this = this;
507 this.forEachValue(function (_, key) { return _this.removeValue(key); });
508 sync.cancelSync.update(this.update);
509 sync.cancelSync.render(this.render);
510 this.removeFromParent && this.removeFromParent();
511 };
512 return VisualElement;
513}());
514
515function noop(any) {
516 return any;
517}
518
519/**
520 * Bounding boxes tend to be defined as top, left, right, bottom. For various operations
521 * it's easier to consider each axis individually. This function returns a bounding box
522 * as a map of single-axis min/max values.
523 */
524function convertBoundingBoxToAxisBox(_a) {
525 var top = _a.top, left = _a.left, right = _a.right, bottom = _a.bottom;
526 return {
527 x: { min: left, max: right },
528 y: { min: top, max: bottom },
529 };
530}
531function convertAxisBoxToBoundingBox(_a) {
532 var x = _a.x, y = _a.y;
533 return {
534 top: y.min,
535 bottom: y.max,
536 left: x.min,
537 right: x.max,
538 };
539}
540/**
541 * Applies a TransformPoint function to a bounding box. TransformPoint is usually a function
542 * provided by Framer to allow measured points to be corrected for device scaling. This is used
543 * when measuring DOM elements and DOM event points.
544 */
545function transformBoundingBox(_a, transformPoint) {
546 var top = _a.top, left = _a.left, bottom = _a.bottom, right = _a.right;
547 if (transformPoint === void 0) { transformPoint = noop; }
548 var topLeft = transformPoint({ x: left, y: top });
549 var bottomRight = transformPoint({ x: right, y: bottom });
550 return {
551 top: topLeft.y,
552 left: topLeft.x,
553 bottom: bottomRight.y,
554 right: bottomRight.x,
555 };
556}
557/**
558 * Create an empty axis box of zero size
559 */
560function axisBox() {
561 return { x: { min: 0, max: 1 }, y: { min: 0, max: 1 } };
562}
563function copyAxisBox(box) {
564 return {
565 x: tslib.__assign({}, box.x),
566 y: tslib.__assign({}, box.y),
567 };
568}
569/**
570 * Create an empty box delta
571 */
572var zeroDelta = {
573 translate: 0,
574 scale: 1,
575 origin: 0,
576 originPoint: 0,
577};
578function delta() {
579 return {
580 x: tslib.__assign({}, zeroDelta),
581 y: tslib.__assign({}, zeroDelta),
582 };
583}
584
585/**
586 * ValueType for "auto"
587 */
588var auto = {
589 test: function (v) { return v === "auto"; },
590 parse: function (v) { return v; },
591};
592/**
593 * ValueType for ints
594 */
595var int = tslib.__assign(tslib.__assign({}, styleValueTypes.number), { transform: Math.round });
596/**
597 * A map of default value types for common values
598 */
599var defaultValueTypes = {
600 // Color props
601 color: styleValueTypes.color,
602 backgroundColor: styleValueTypes.color,
603 outlineColor: styleValueTypes.color,
604 fill: styleValueTypes.color,
605 stroke: styleValueTypes.color,
606 // Border props
607 borderColor: styleValueTypes.color,
608 borderTopColor: styleValueTypes.color,
609 borderRightColor: styleValueTypes.color,
610 borderBottomColor: styleValueTypes.color,
611 borderLeftColor: styleValueTypes.color,
612 borderWidth: styleValueTypes.px,
613 borderTopWidth: styleValueTypes.px,
614 borderRightWidth: styleValueTypes.px,
615 borderBottomWidth: styleValueTypes.px,
616 borderLeftWidth: styleValueTypes.px,
617 borderRadius: styleValueTypes.px,
618 radius: styleValueTypes.px,
619 borderTopLeftRadius: styleValueTypes.px,
620 borderTopRightRadius: styleValueTypes.px,
621 borderBottomRightRadius: styleValueTypes.px,
622 borderBottomLeftRadius: styleValueTypes.px,
623 // Positioning props
624 width: styleValueTypes.px,
625 maxWidth: styleValueTypes.px,
626 height: styleValueTypes.px,
627 maxHeight: styleValueTypes.px,
628 size: styleValueTypes.px,
629 top: styleValueTypes.px,
630 right: styleValueTypes.px,
631 bottom: styleValueTypes.px,
632 left: styleValueTypes.px,
633 // Spacing props
634 padding: styleValueTypes.px,
635 paddingTop: styleValueTypes.px,
636 paddingRight: styleValueTypes.px,
637 paddingBottom: styleValueTypes.px,
638 paddingLeft: styleValueTypes.px,
639 margin: styleValueTypes.px,
640 marginTop: styleValueTypes.px,
641 marginRight: styleValueTypes.px,
642 marginBottom: styleValueTypes.px,
643 marginLeft: styleValueTypes.px,
644 // Transform props
645 rotate: styleValueTypes.degrees,
646 rotateX: styleValueTypes.degrees,
647 rotateY: styleValueTypes.degrees,
648 rotateZ: styleValueTypes.degrees,
649 scale: styleValueTypes.scale,
650 scaleX: styleValueTypes.scale,
651 scaleY: styleValueTypes.scale,
652 scaleZ: styleValueTypes.scale,
653 skew: styleValueTypes.degrees,
654 skewX: styleValueTypes.degrees,
655 skewY: styleValueTypes.degrees,
656 distance: styleValueTypes.px,
657 translateX: styleValueTypes.px,
658 translateY: styleValueTypes.px,
659 translateZ: styleValueTypes.px,
660 x: styleValueTypes.px,
661 y: styleValueTypes.px,
662 z: styleValueTypes.px,
663 perspective: styleValueTypes.px,
664 opacity: styleValueTypes.alpha,
665 originX: styleValueTypes.progressPercentage,
666 originY: styleValueTypes.progressPercentage,
667 originZ: styleValueTypes.px,
668 // Misc
669 zIndex: int,
670 // SVG
671 fillOpacity: styleValueTypes.alpha,
672 strokeOpacity: styleValueTypes.alpha,
673 numOctaves: int,
674};
675/**
676 * A list of value types commonly used for dimensions
677 */
678var dimensionValueTypes = [styleValueTypes.number, styleValueTypes.px, styleValueTypes.percent, styleValueTypes.degrees, styleValueTypes.vw, styleValueTypes.vh, auto];
679/**
680 * Tests a provided value against a ValueType
681 */
682var testValueType = function (v) { return function (type) { return type.test(v); }; };
683/**
684 * Tests a dimensional value against the list of dimension ValueTypes
685 */
686var findDimensionValueType = function (v) {
687 return dimensionValueTypes.find(testValueType(v));
688};
689/**
690 * A list of all ValueTypes
691 */
692var valueTypes = tslib.__spreadArrays(dimensionValueTypes, [styleValueTypes.color, styleValueTypes.complex]);
693/**
694 * Tests a value against the list of ValueTypes
695 */
696var findValueType = function (v) { return valueTypes.find(testValueType(v)); };
697/**
698 * Gets the default ValueType for the provided value key
699 */
700var getDefaultValueType = function (key) { return defaultValueTypes[key]; };
701/**
702 * Provided a value and a ValueType, returns the value as that value type.
703 */
704var getValueAsType = function (value, type) {
705 return type && typeof value === "number"
706 ? type.transform(value)
707 : value;
708};
709
710/**
711 * A list of all transformable axes. We'll use this list to generated a version
712 * of each axes for each transform.
713 */
714var axes = ["", "X", "Y", "Z"];
715/**
716 * An ordered array of each transformable value. By default, transform values
717 * will be sorted to this order.
718 */
719var order = ["translate", "scale", "rotate", "skew", "transformPerspective"];
720/**
721 * Generate a list of every possible transform key.
722 */
723var transformProps = ["x", "y", "z"];
724order.forEach(function (operationKey) {
725 axes.forEach(function (axesKey) { return transformProps.push(operationKey + axesKey); });
726});
727/**
728 * A function to use with Array.sort to sort transform keys by their default order.
729 */
730function sortTransformProps(a, b) {
731 return transformProps.indexOf(a) - transformProps.indexOf(b);
732}
733/**
734 * A quick lookup for transform props.
735 */
736var transformPropSet = new Set(transformProps);
737function isTransformProp(key) {
738 return transformPropSet.has(key);
739}
740/**
741 * A quick lookup for transform origin props
742 */
743var transformOriginProps = new Set(["originX", "originY", "originZ"]);
744function isTransformOriginProp(key) {
745 return transformOriginProps.has(key);
746}
747
748var translateAlias = {
749 x: "translateX",
750 y: "translateY",
751 z: "translateZ",
752};
753/**
754 * Build a CSS transform style from individual x/y/scale etc properties.
755 *
756 * This outputs with a default order of transforms/scales/rotations, this can be customised by
757 * providing a transformTemplate function.
758 */
759function buildTransform(transform, transformKeys, transformTemplate, transformIsDefault, enableHardwareAcceleration, allowTransformNone) {
760 if (enableHardwareAcceleration === void 0) { enableHardwareAcceleration = true; }
761 if (allowTransformNone === void 0) { allowTransformNone = true; }
762 // The transform string we're going to build into
763 var transformString = "";
764 // Track whether the defined transform has a defined z so we don't add a
765 // second to enable hardware acceleration
766 var transformHasZ = false;
767 // Transform keys into their default order - this will determine the output order.
768 transformKeys.sort(sortTransformProps);
769 // Loop over each transform and build them into transformString
770 var numTransformKeys = transformKeys.length;
771 for (var i = 0; i < numTransformKeys; i++) {
772 var key = transformKeys[i];
773 transformString += (translateAlias[key] || key) + "(" + transform[key] + ") ";
774 if (key === "z")
775 transformHasZ = true;
776 }
777 if (!transformHasZ && enableHardwareAcceleration) {
778 transformString += "translateZ(0)";
779 }
780 else {
781 transformString = transformString.trim();
782 }
783 // If we have a custom `transform` template, pass our transform values and
784 // generated transformString to that before returning
785 if (transformTemplate) {
786 transformString = transformTemplate(transform, transformIsDefault ? "" : transformString);
787 }
788 else if (allowTransformNone && transformIsDefault) {
789 transformString = "none";
790 }
791 return transformString;
792}
793
794/**
795 * Returns true if the provided key is a CSS variable
796 */
797function isCSSVariable(key) {
798 return key.startsWith("--");
799}
800
801function pixelsToPercent(pixels, axis) {
802 return (pixels / (axis.max - axis.min)) * 100;
803}
804/**
805 * We always correct borderRadius as a percentage rather than pixels to reduce paints.
806 * For example, if you are projecting a box that is 100px wide with a 10px borderRadius
807 * into a box that is 200px wide with a 20px borderRadius, that is actually a 10%
808 * borderRadius in both states. If we animate between the two in pixels that will trigger
809 * a paint each time. If we animate between the two in percentage we'll avoid a paint.
810 */
811function correctBorderRadius(latest, viewportBox) {
812 /**
813 * If latest is a string, we either presume it's already a percentage, in which case it'll
814 * already be stretched appropriately, or it's another value type which we don't support.
815 */
816 if (typeof latest !== "number")
817 return latest;
818 /**
819 * If latest is a number, it's a pixel value. We use the current viewportBox to calculate that
820 * pixel value as a percentage of each axis
821 */
822 var x = pixelsToPercent(latest, viewportBox.x);
823 var y = pixelsToPercent(latest, viewportBox.y);
824 return x + "% " + y + "%";
825}
826function correctBoxShadow(latest, _viewportBox, delta, treeScale) {
827 // GC Warning - this creates a function and object every frame
828 var shadow = styleValueTypes.complex.parse(latest);
829 var template = styleValueTypes.complex.createTransformer(latest);
830 // Calculate the overall context scale
831 var xScale = delta.x.scale * treeScale.x;
832 var yScale = delta.y.scale * treeScale.y;
833 // Scale x/y
834 shadow[1] /= xScale;
835 shadow[2] /= yScale;
836 /**
837 * Ideally we'd correct x and y scales individually, but because blur and
838 * spread apply to both we have to take a scale average and apply that instead.
839 * We could potentially improve the outcome of this by incorporating the ratio between
840 * the two scales.
841 */
842 var averageScale = popcorn.mix(xScale, yScale, 0.5);
843 // Blur
844 if (typeof shadow[3] === "number")
845 shadow[3] /= averageScale;
846 // Spread
847 if (typeof shadow[4] === "number")
848 shadow[4] /= averageScale;
849 return template(shadow);
850}
851var borderCorrectionDefinition = {
852 process: correctBorderRadius,
853};
854var valueScaleCorrection = {
855 borderRadius: tslib.__assign(tslib.__assign({}, borderCorrectionDefinition), { applyTo: [
856 "borderTopLeftRadius",
857 "borderTopRightRadius",
858 "borderBottomLeftRadius",
859 "borderBottomRightRadius",
860 ] }),
861 borderTopLeftRadius: borderCorrectionDefinition,
862 borderTopRightRadius: borderCorrectionDefinition,
863 borderBottomLeftRadius: borderCorrectionDefinition,
864 borderBottomRightRadius: borderCorrectionDefinition,
865 boxShadow: {
866 process: correctBoxShadow,
867 },
868};
869/**
870 * @internal
871 */
872function addScaleCorrection(correctors) {
873 for (var key in correctors) {
874 valueScaleCorrection[key] = correctors[key];
875 }
876}
877
878function createDeltaTransform(delta, treeScale) {
879 var x = delta.x.translate / treeScale.x;
880 var y = delta.y.translate / treeScale.y;
881 var scaleX = delta.x.scale;
882 var scaleY = delta.y.scale;
883 return "translate3d(" + x + "px, " + y + "px, 0) scale(" + scaleX + ", " + scaleY + ")";
884}
885
886/**
887 * Build style and CSS variables
888 *
889 * This function converts a Motion style prop:
890 *
891 * { x: 100, width: 100, originX: 0.5 }
892 *
893 * Into an object with default value types applied and default
894 * transform order set:
895 *
896 * {
897 * transform: 'translateX(100px) translateZ(0)`,
898 * width: '100px',
899 * transformOrigin: '50% 50%'
900 * }
901 *
902 * Styles are saved to `style` and CSS vars to `vars`.
903 *
904 * This function works with mutative data structures.
905 */
906function buildHTMLStyles(latest, style, vars, transform, transformOrigin, transformKeys, _a, isLayoutProjectionEnabled, delta, deltaFinal, treeScale, targetBox) {
907 var enableHardwareAcceleration = _a.enableHardwareAcceleration, transformTemplate = _a.transformTemplate, allowTransformNone = _a.allowTransformNone;
908 // Empty the transformKeys array. As we're throwing out refs to its items
909 // this might not be as cheap as suspected. Maybe using the array as a buffer
910 // with a manual incrementation would be better.
911 transformKeys.length = 0;
912 // Track whether we encounter any transform or transformOrigin values.
913 var hasTransform = !!isLayoutProjectionEnabled;
914 var hasTransformOrigin = !!isLayoutProjectionEnabled;
915 // Does the calculated transform essentially equal "none"?
916 var transformIsNone = true;
917 /**
918 * Loop over all our latest animated values and decide whether to handle them
919 * as a style or CSS variable. Transforms and transform origins are kept seperately
920 * for further processing
921 */
922 for (var key in latest) {
923 var value = latest[key];
924 // Convert the value to its default value type, ie 0 -> "0px"
925 var valueType = getDefaultValueType(key);
926 var valueAsType = getValueAsType(value, valueType);
927 if (isTransformProp(key)) {
928 // If this is a transform, flag and enable further transform processing
929 hasTransform = true;
930 transform[key] = valueAsType;
931 transformKeys.push(key);
932 if (!transformIsNone)
933 continue;
934 // If all the transform keys we've so far encountered are their default value
935 // then check to see if this one isn't
936 var defaultValue = valueType.default !== undefined ? valueType.default : 0;
937 if (value !== defaultValue)
938 transformIsNone = false;
939 }
940 else if (isTransformOriginProp(key)) {
941 // If this is a transform origin, flag and enable further transform-origin processing
942 transformOrigin[key] = valueAsType;
943 hasTransformOrigin = true;
944 }
945 else if (key !== "transform" || typeof value !== "function") {
946 // Handle all remaining values. Decide which map to save to depending
947 // on whether this is a CSS variable
948 var bucket = isCSSVariable(key) ? vars : style;
949 // If we need to perform scale correction, and we have a handler for this
950 // value type (ie borderRadius), perform it
951 if (isLayoutProjectionEnabled && valueScaleCorrection[key]) {
952 var corrected = valueScaleCorrection[key].process(value, targetBox, delta, treeScale);
953 /**
954 * Scale-correctable values can define a number of other values to break
955 * down into. For instance borderRadius needs applying to borderBottomLeftRadius etc
956 */
957 var applyTo = valueScaleCorrection[key].applyTo;
958 if (applyTo) {
959 var num = applyTo.length;
960 for (var i = 0; i < num; i++) {
961 bucket[applyTo[i]] = corrected;
962 }
963 }
964 else {
965 bucket[key] = corrected;
966 }
967 }
968 else {
969 bucket[key] = valueAsType;
970 }
971 }
972 }
973 // Only process transform if values aren't defaults
974 if (hasTransform || transformTemplate) {
975 if (!isLayoutProjectionEnabled) {
976 style.transform = buildTransform(transform, transformKeys, transformTemplate, transformIsNone, enableHardwareAcceleration, allowTransformNone);
977 }
978 else {
979 style.transform = createDeltaTransform(deltaFinal, treeScale);
980 if (transformTemplate)
981 style.transform = transformTemplate(transform, style.transform);
982 }
983 }
984 // Only process transform origin if values aren't default
985 if (hasTransformOrigin) {
986 var originX = isLayoutProjectionEnabled
987 ? deltaFinal.x.origin * 100 + "%"
988 : transformOrigin.originX || "50%";
989 var originY = isLayoutProjectionEnabled
990 ? deltaFinal.y.origin * 100 + "%"
991 : transformOrigin.originY || "50%";
992 var originZ = transformOrigin.originZ || "0";
993 style.transformOrigin = originX + " " + originY + " " + originZ;
994 }
995}
996
997/**
998 * Reset an axis to the provided origin box.
999 *
1000 * This is a mutative operation.
1001 */
1002function resetAxis(axis, originAxis) {
1003 axis.min = originAxis.min;
1004 axis.max = originAxis.max;
1005}
1006/**
1007 * Reset a box to the provided origin box.
1008 *
1009 * This is a mutative operation.
1010 */
1011function resetBox(box, originBox) {
1012 resetAxis(box.x, originBox.x);
1013 resetAxis(box.y, originBox.y);
1014}
1015/**
1016 * Scales a point based on a factor and an originPoint
1017 */
1018function scalePoint(point, scale, originPoint) {
1019 var distanceFromOrigin = point - originPoint;
1020 var scaled = scale * distanceFromOrigin;
1021 return originPoint + scaled;
1022}
1023/**
1024 * Applies a translate/scale delta to a point
1025 */
1026function applyPointDelta(point, translate, scale, originPoint, boxScale) {
1027 if (boxScale !== undefined) {
1028 point = scalePoint(point, boxScale, originPoint);
1029 }
1030 return scalePoint(point, scale, originPoint) + translate;
1031}
1032/**
1033 * Applies a translate/scale delta to an axis
1034 */
1035function applyAxisDelta(axis, translate, scale, originPoint, boxScale) {
1036 if (translate === void 0) { translate = 0; }
1037 if (scale === void 0) { scale = 1; }
1038 axis.min = applyPointDelta(axis.min, translate, scale, originPoint, boxScale);
1039 axis.max = applyPointDelta(axis.max, translate, scale, originPoint, boxScale);
1040}
1041/**
1042 * Applies a translate/scale delta to a box
1043 */
1044function applyBoxDelta(box, _a) {
1045 var x = _a.x, y = _a.y;
1046 applyAxisDelta(box.x, x.translate, x.scale, x.originPoint);
1047 applyAxisDelta(box.y, y.translate, y.scale, y.originPoint);
1048}
1049/**
1050 * Apply a transform to an axis from the latest resolved motion values.
1051 * This function basically acts as a bridge between a flat motion value map
1052 * and applyAxisDelta
1053 */
1054function applyAxisTransforms(final, axis, transforms, _a) {
1055 var key = _a[0], scaleKey = _a[1], originKey = _a[2];
1056 // Copy the current axis to the final axis before mutation
1057 final.min = axis.min;
1058 final.max = axis.max;
1059 var originPoint = popcorn.mix(axis.min, axis.max, transforms[originKey] || 0.5);
1060 // Apply the axis delta to the final axis
1061 applyAxisDelta(final, transforms[key], transforms[scaleKey], originPoint, transforms.scale);
1062}
1063/**
1064 * The names of the motion values we want to apply as translation, scale and origin.
1065 */
1066var xKeys = ["x", "scaleX", "originX"];
1067var yKeys = ["y", "scaleY", "originY"];
1068/**
1069 * Apply a transform to a box from the latest resolved motion values.
1070 */
1071function applyBoxTransforms(finalBox, box, transforms) {
1072 applyAxisTransforms(finalBox.x, box.x, transforms, xKeys);
1073 applyAxisTransforms(finalBox.y, box.y, transforms, yKeys);
1074}
1075/**
1076 * Remove a delta from a point. This is essentially the steps of applyPointDelta in reverse
1077 */
1078function removePointDelta(point, translate, scale, originPoint, boxScale) {
1079 point -= translate;
1080 point = scalePoint(point, 1 / scale, originPoint);
1081 if (boxScale !== undefined) {
1082 point = scalePoint(point, 1 / boxScale, originPoint);
1083 }
1084 return point;
1085}
1086/**
1087 * Remove a delta from an axis. This is essentially the steps of applyAxisDelta in reverse
1088 */
1089function removeAxisDelta(axis, translate, scale, origin, boxScale) {
1090 if (translate === void 0) { translate = 0; }
1091 if (scale === void 0) { scale = 1; }
1092 if (origin === void 0) { origin = 0.5; }
1093 var originPoint = popcorn.mix(axis.min, axis.max, origin) - translate;
1094 axis.min = removePointDelta(axis.min, translate, scale, originPoint, boxScale);
1095 axis.max = removePointDelta(axis.max, translate, scale, originPoint, boxScale);
1096}
1097/**
1098 * Remove a transforms from an axis. This is essentially the steps of applyAxisTransforms in reverse
1099 * and acts as a bridge between motion values and removeAxisDelta
1100 */
1101function removeAxisTransforms(axis, transforms, _a) {
1102 var key = _a[0], scaleKey = _a[1], originKey = _a[2];
1103 removeAxisDelta(axis, transforms[key], transforms[scaleKey], transforms[originKey], transforms.scale);
1104}
1105/**
1106 * Remove a transforms from an box. This is essentially the steps of applyAxisBox in reverse
1107 * and acts as a bridge between motion values and removeAxisDelta
1108 */
1109function removeBoxTransforms(box, transforms) {
1110 removeAxisTransforms(box.x, transforms, xKeys);
1111 removeAxisTransforms(box.y, transforms, yKeys);
1112}
1113/**
1114 * Apply a tree of deltas to a box. We do this to calculate the effect of all the transforms
1115 * in a tree upon our box before then calculating how to project it into our desired viewport-relative box
1116 *
1117 * This is the final nested loop within HTMLVisualElement.updateLayoutDelta
1118 */
1119function applyTreeDeltas(box, treePath) {
1120 var treeLength = treePath.length;
1121 for (var i = 0; i < treeLength; i++) {
1122 applyBoxDelta(box, treePath[i].delta);
1123 }
1124}
1125
1126var clampProgress = popcorn.clamp(0, 1);
1127/**
1128 * Returns true if the provided value is within maxDistance of the provided target
1129 */
1130function isNear(value, target, maxDistance) {
1131 if (target === void 0) { target = 0; }
1132 if (maxDistance === void 0) { maxDistance = 0.01; }
1133 return popcorn.distance(value, target) < maxDistance;
1134}
1135/**
1136 * Calculate the translate needed to be applied to source to get target
1137 */
1138function calcTranslate(source, target, origin) {
1139 var sourcePoint = popcorn.mix(source.min, source.max, origin);
1140 var targetPoint = popcorn.mix(target.min, target.max, origin);
1141 return targetPoint - sourcePoint;
1142}
1143/**
1144 * Calculate a transform origin relative to the source axis, between 0-1, that results
1145 * in an asthetically pleasing scale/transform needed to project from source to target.
1146 */
1147function calcOrigin(source, target) {
1148 var origin = 0.5;
1149 var sourceLength = source.max - source.min;
1150 var targetLength = target.max - target.min;
1151 if (targetLength > sourceLength) {
1152 origin = popcorn.progress(target.min, target.max - sourceLength, source.min);
1153 }
1154 else if (sourceLength > targetLength) {
1155 origin = popcorn.progress(source.min, source.max - targetLength, target.min);
1156 }
1157 return clampProgress(origin);
1158}
1159/**
1160 * Update the AxisDelta with a transform that projects source into target.
1161 *
1162 * The transform `origin` is optional. If not provided, it'll be automatically
1163 * calculated based on the relative positions of the two bounding boxes.
1164 */
1165function updateAxisDelta(delta, source, target, origin) {
1166 var sourceLength = source.max - source.min;
1167 var targetLength = target.max - target.min;
1168 delta.origin = origin === undefined ? calcOrigin(source, target) : origin;
1169 delta.originPoint = popcorn.mix(source.min, source.max, delta.origin);
1170 delta.scale = targetLength / sourceLength;
1171 if (isNear(delta.scale, 1, 0.0001))
1172 delta.scale = 1;
1173 delta.translate = calcTranslate(source, target, delta.origin);
1174 if (isNear(delta.translate))
1175 delta.translate = 0;
1176}
1177/**
1178 * Update the BoxDelta with a transform that projects the source into the target.
1179 *
1180 * The transform `origin` is optional. If not provided, it'll be automatically
1181 * calculated based on the relative positions of the two bounding boxes.
1182 */
1183function updateBoxDelta(delta, source, target, origin) {
1184 updateAxisDelta(delta.x, source.x, target.x, origin);
1185 updateAxisDelta(delta.y, source.y, target.y, origin);
1186}
1187/**
1188 * Update the treeScale by incorporating the parent's latest scale into its treeScale.
1189 */
1190function updateTreeScale(treeScale, parentTreeScale, parentDelta) {
1191 treeScale.x = parentTreeScale.x * parentDelta.x.scale;
1192 treeScale.y = parentTreeScale.y * parentDelta.y.scale;
1193}
1194
1195// Call a handler once for each axis
1196function eachAxis(handler) {
1197 return [handler("x"), handler("y")];
1198}
1199
1200var isKeyframesTarget = function (v) {
1201 return Array.isArray(v);
1202};
1203
1204var underDampedSpring = function () { return ({
1205 type: "spring",
1206 stiffness: 500,
1207 damping: 25,
1208 restDelta: 0.5,
1209 restSpeed: 10,
1210}); };
1211var overDampedSpring = function (to) { return ({
1212 type: "spring",
1213 stiffness: 700,
1214 damping: to === 0 ? 100 : 35,
1215}); };
1216var linearTween = function () { return ({
1217 ease: "linear",
1218 duration: 0.3,
1219}); };
1220var keyframes = function (values) { return ({
1221 type: "keyframes",
1222 duration: 0.8,
1223 values: values,
1224}); };
1225var defaultTransitions = {
1226 x: underDampedSpring,
1227 y: underDampedSpring,
1228 z: underDampedSpring,
1229 rotate: underDampedSpring,
1230 rotateX: underDampedSpring,
1231 rotateY: underDampedSpring,
1232 rotateZ: underDampedSpring,
1233 scaleX: overDampedSpring,
1234 scaleY: overDampedSpring,
1235 scale: overDampedSpring,
1236 opacity: linearTween,
1237 backgroundColor: linearTween,
1238 color: linearTween,
1239 default: overDampedSpring,
1240};
1241var getDefaultTransition = function (valueKey, to) {
1242 var transitionFactory;
1243 if (isKeyframesTarget(to)) {
1244 transitionFactory = keyframes;
1245 }
1246 else {
1247 transitionFactory =
1248 defaultTransitions[valueKey] || defaultTransitions.default;
1249 }
1250 return tslib.__assign({ to: to }, transitionFactory(to));
1251};
1252
1253/**
1254 * A Popmotion action that accepts a single `to` prop. When it starts, it immediately
1255 * updates with `to` and then completes. By using this we can compose instant transitions
1256 * in with the same logic that applies `delay` or returns a `Promise` etc.
1257 *
1258 * Accepting `duration` is a little bit of a hack that simply defers the completetion of
1259 * the animation until after the duration finishes. This is for situations when you're **only**
1260 * animating non-animatable values and then setting something on `transitionEnd`. Really
1261 * you want this to fire after the "animation" finishes, rather than instantly.
1262 *
1263 * ```
1264 * animate={{
1265 * display: 'block',
1266 * transitionEnd: { display: 'none' }
1267 * }}
1268 * ```
1269 */
1270var just = function (_a) {
1271 var to = _a.to, duration = _a.duration;
1272 return popmotion.action(function (_a) {
1273 var update = _a.update, complete = _a.complete;
1274 update(to);
1275 duration ? popmotion.delay(duration).start({ complete: complete }) : complete();
1276 });
1277};
1278
1279var easingDefinitionToFunction = function (definition) {
1280 if (Array.isArray(definition)) {
1281 // If cubic bezier definition, create bezier curve
1282 heyListen.invariant(definition.length === 4, "Cubic bezier arrays must contain four numerical values.");
1283 var x1 = definition[0], y1 = definition[1], x2 = definition[2], y2 = definition[3];
1284 return easingLookup.cubicBezier(x1, y1, x2, y2);
1285 }
1286 else if (typeof definition === "string") {
1287 // Else lookup from table
1288 heyListen.invariant(easingLookup[definition] !== undefined, "Invalid easing type '" + definition + "'");
1289 return easingLookup[definition];
1290 }
1291 return definition;
1292};
1293var isEasingArray = function (ease) {
1294 return Array.isArray(ease) && typeof ease[0] !== "number";
1295};
1296
1297var isDurationAnimation = function (v) {
1298 return v.hasOwnProperty("duration") || v.hasOwnProperty("repeatDelay");
1299};
1300
1301/**
1302 * Check if a value is animatable. Examples:
1303 *
1304 * ✅: 100, "100px", "#fff"
1305 * ❌: "block", "url(2.jpg)"
1306 * @param value
1307 *
1308 * @internal
1309 */
1310var isAnimatable = function (key, value) {
1311 // If the list of keys tat might be non-animatable grows, replace with Set
1312 if (key === "zIndex")
1313 return false;
1314 // If it's a number or a keyframes array, we can animate it. We might at some point
1315 // need to do a deep isAnimatable check of keyframes, or let Popmotion handle this,
1316 // but for now lets leave it like this for performance reasons
1317 if (typeof value === "number" || Array.isArray(value))
1318 return true;
1319 if (typeof value === "string" && // It's animatable if we have a string
1320 styleValueTypes.complex.test(value) && // And it contains numbers and/or colors
1321 !value.startsWith("url(") // Unless it starts with "url("
1322 ) {
1323 return true;
1324 }
1325 return false;
1326};
1327
1328/**
1329 * Converts seconds to milliseconds
1330 *
1331 * @param seconds - Time in seconds.
1332 * @return milliseconds - Converted time in milliseconds.
1333 */
1334var secondsToMilliseconds = function (seconds) { return seconds * 1000; };
1335
1336var transitions = { tween: popmotion.tween, spring: popmotion.spring, keyframes: popmotion.keyframes, inertia: popmotion.inertia, just: just };
1337var transitionOptionParser = {
1338 tween: function (opts) {
1339 if (opts.ease) {
1340 var ease = isEasingArray(opts.ease) ? opts.ease[0] : opts.ease;
1341 opts.ease = easingDefinitionToFunction(ease);
1342 }
1343 return opts;
1344 },
1345 keyframes: function (_a) {
1346 var from = _a.from, to = _a.to, velocity = _a.velocity, opts = tslib.__rest(_a, ["from", "to", "velocity"]);
1347 if (opts.values && opts.values[0] === null) {
1348 var values = tslib.__spreadArrays(opts.values);
1349 values[0] = from;
1350 opts.values = values;
1351 }
1352 if (opts.ease) {
1353 opts.easings = isEasingArray(opts.ease)
1354 ? opts.ease.map(easingDefinitionToFunction)
1355 : easingDefinitionToFunction(opts.ease);
1356 }
1357 opts.ease = easingLookup.linear;
1358 return opts;
1359 },
1360};
1361var isTransitionDefined = function (_a) {
1362 var when = _a.when, delay = _a.delay, delayChildren = _a.delayChildren, staggerChildren = _a.staggerChildren, staggerDirection = _a.staggerDirection, transition = tslib.__rest(_a, ["when", "delay", "delayChildren", "staggerChildren", "staggerDirection"]);
1363 return Object.keys(transition).length;
1364};
1365var getTransitionDefinition = function (key, to, transitionDefinition) {
1366 var delay = transitionDefinition ? transitionDefinition.delay : 0;
1367 // If no object, return default transition
1368 // A better way to handle this would be to deconstruct out all the shared Orchestration props
1369 // and see if there's any props remaining
1370 if (transitionDefinition === undefined ||
1371 !isTransitionDefined(transitionDefinition)) {
1372 return tslib.__assign({ delay: delay }, getDefaultTransition(key, to));
1373 }
1374 var valueTransitionDefinition = transitionDefinition[key] ||
1375 transitionDefinition.default ||
1376 transitionDefinition;
1377 if (valueTransitionDefinition.type === false) {
1378 return {
1379 delay: valueTransitionDefinition.hasOwnProperty("delay")
1380 ? valueTransitionDefinition.delay
1381 : delay,
1382 to: isKeyframesTarget(to)
1383 ? to[to.length - 1]
1384 : to,
1385 type: "just",
1386 };
1387 }
1388 else if (isKeyframesTarget(to)) {
1389 return tslib.__assign(tslib.__assign({ values: to, duration: 0.8, delay: delay, ease: "linear" }, valueTransitionDefinition), {
1390 // This animation must be keyframes if we're animating through an array
1391 type: "keyframes" });
1392 }
1393 else {
1394 return tslib.__assign({ type: "tween", to: to,
1395 delay: delay }, valueTransitionDefinition);
1396 }
1397};
1398var preprocessOptions = function (type, opts) {
1399 return transitionOptionParser[type]
1400 ? transitionOptionParser[type](opts)
1401 : opts;
1402};
1403var getAnimation = function (key, value, target, transition) {
1404 var origin = value.get();
1405 var isOriginAnimatable = isAnimatable(key, origin);
1406 var isTargetAnimatable = isAnimatable(key, target);
1407 // TODO we could probably improve this check to ensure both values are of the same type -
1408 // for instance 100 to #fff. This might live better in Popmotion.
1409 heyListen.warning(isOriginAnimatable === isTargetAnimatable, "You are trying to animate " + key + " from \"" + origin + "\" to \"" + target + "\". " + origin + " is not an animatable value - to enable this animation set " + origin + " to a value animatable to " + target + " via the `style` property.");
1410 // Parse the `transition` prop and return options for the Popmotion animation
1411 var _a = getTransitionDefinition(key, target, transition), _b = _a.type, type = _b === void 0 ? "tween" : _b, transitionDefinition = tslib.__rest(_a, ["type"]);
1412 // If this is an animatable pair of values, return an animation, otherwise use `just`
1413 var actionFactory = isOriginAnimatable && isTargetAnimatable
1414 ? transitions[type]
1415 : just;
1416 var opts = preprocessOptions(type, tslib.__assign({ from: origin, velocity: value.getVelocity() }, transitionDefinition));
1417 // Convert duration from Framer Motion's seconds into Popmotion's milliseconds
1418 if (isDurationAnimation(opts)) {
1419 if (opts.duration) {
1420 opts.duration = secondsToMilliseconds(opts.duration);
1421 }
1422 if (opts.repeatDelay) {
1423 opts.repeatDelay = secondsToMilliseconds(opts.repeatDelay);
1424 }
1425 }
1426 return [actionFactory, opts];
1427};
1428/**
1429 * Start animation on a value. This function completely encapsulates Popmotion-specific logic.
1430 *
1431 * @internal
1432 */
1433function startAnimation(key, value, target, _a) {
1434 if (_a === void 0) { _a = {}; }
1435 var _b = _a.delay, delay = _b === void 0 ? 0 : _b, transition = tslib.__rest(_a, ["delay"]);
1436 return value.start(function (complete) {
1437 var activeAnimation;
1438 var _a = getAnimation(key, value, target, transition), animationFactory = _a[0], _b = _a[1], valueDelay = _b.delay, options = tslib.__rest(_b, ["delay"]);
1439 if (valueDelay !== undefined) {
1440 delay = valueDelay;
1441 }
1442 var animate = function () {
1443 var animation = animationFactory(options);
1444 // Bind animation opts to animation
1445 activeAnimation = animation.start({
1446 update: function (v) { return value.set(v); },
1447 complete: complete,
1448 });
1449 };
1450 // If we're delaying this animation, only resolve it **after** the delay to
1451 // ensure the value's resolve velocity is up-to-date.
1452 if (delay) {
1453 activeAnimation = popmotion.delay(secondsToMilliseconds(delay)).start({
1454 complete: animate,
1455 });
1456 }
1457 else {
1458 animate();
1459 }
1460 return function () {
1461 if (activeAnimation)
1462 activeAnimation.stop();
1463 };
1464 });
1465}
1466
1467/**
1468 * Measure and return the element bounding box.
1469 *
1470 * We convert the box into an AxisBox2D to make it easier to work with each axis
1471 * individually and programmatically.
1472 *
1473 * This function optionally accepts a transformPagePoint function which allows us to compensate
1474 * for, for instance, measuring the element within a scaled plane like a Framer devivce preview component.
1475 */
1476function getBoundingBox(element, transformPagePoint) {
1477 var box = element.getBoundingClientRect();
1478 return convertBoundingBoxToAxisBox(transformBoundingBox(box, transformPagePoint));
1479}
1480
1481/**
1482 * A VisualElement for HTMLElements
1483 */
1484var HTMLVisualElement = /** @class */ (function (_super) {
1485 tslib.__extends(HTMLVisualElement, _super);
1486 function HTMLVisualElement() {
1487 var _this = _super !== null && _super.apply(this, arguments) || this;
1488 /**
1489 *
1490 */
1491 _this.defaultConfig = {
1492 enableHardwareAcceleration: true,
1493 allowTransformNone: true,
1494 };
1495 /**
1496 * A mutable record of styles we want to apply directly to the rendered Element
1497 * every frame. We use a mutable data structure to reduce GC during animations.
1498 */
1499 _this.style = {};
1500 /**
1501 * A record of styles we only want to apply via React. This gets set in useMotionValues
1502 * and applied in the render function. I'd prefer this to live somewhere else to decouple
1503 * VisualElement from React but works for now.
1504 */
1505 _this.reactStyle = {};
1506 /**
1507 * A mutable record of CSS variables we want to apply directly to the rendered Element
1508 * every frame. We use a mutable data structure to reduce GC during animations.
1509 */
1510 _this.vars = {};
1511 /**
1512 * A mutable record of transforms we want to apply directly to the rendered Element
1513 * every frame. We use a mutable data structure to reduce GC during animations.
1514 */
1515 _this.transform = {};
1516 /**
1517 * A mutable record of transform origins we want to apply directly to the rendered Element
1518 * every frame. We use a mutable data structure to reduce GC during animations.
1519 */
1520 _this.transformOrigin = {};
1521 /**
1522 * A mutable record of transform keys we want to apply to the rendered Element. We order
1523 * this to order transforms in the desired order. We use a mutable data structure to reduce GC during animations.
1524 */
1525 _this.transformKeys = [];
1526 _this.config = _this.defaultConfig;
1527 /**
1528 * ========================================
1529 * Layout
1530 * ========================================
1531 */
1532 _this.isLayoutProjectionEnabled = false;
1533 /**
1534 * A set of layout update event handlers. These are only called once all layouts have been read,
1535 * making it safe to perform DOM write operations.
1536 */
1537 _this.layoutUpdateListeners = new Set();
1538 /**
1539 * Keep track of whether the viewport box has been updated since the last render.
1540 * If it has, we want to fire the onViewportBoxUpdate listener.
1541 */
1542 _this.hasViewportBoxUpdated = false;
1543 /**
1544 * The visual target we want to project our component into on a given frame
1545 * before applying transforms defined in `animate` or `style`.
1546 *
1547 * This is considered mutable to avoid object creation on each frame.
1548 */
1549 _this.targetBoxFinal = axisBox();
1550 /**
1551 * The overall scale of the local coordinate system as transformed by all parents
1552 * of this component. We use this for scale correction on our calculated layouts
1553 * and scale-affected values like `boxShadow`.
1554 *
1555 * This is considered mutable to avoid object creation on each frame.
1556 */
1557 _this.treeScale = { x: 1, y: 1 };
1558 /**
1559 * The delta between the boxCorrected and the desired
1560 * targetBox (before user-set transforms are applied). The calculated output will be
1561 * handed to the renderer and used as part of the style correction calculations, for
1562 * instance calculating how to display the desired border-radius correctly.
1563 *
1564 * This is considered mutable to avoid object creation on each frame.
1565 */
1566 _this.delta = delta();
1567 /**
1568 * The delta between the boxCorrected and the desired targetBoxFinal. The calculated
1569 * output will be handed to the renderer and used to project the boxCorrected into
1570 * the targetBoxFinal.
1571 *
1572 * This is considered mutable to avoid object creation on each frame.
1573 */
1574 _this.deltaFinal = delta();
1575 /**
1576 *
1577 */
1578 _this.stopLayoutAxisAnimation = {
1579 x: function () { },
1580 y: function () { },
1581 };
1582 _this.isTargetBoxLocked = false;
1583 /**
1584 *
1585 */
1586 _this.axisProgress = {
1587 x: motionValue(0),
1588 y: motionValue(0),
1589 };
1590 _this.updateLayoutDelta = function () {
1591 _this.isLayoutProjectionEnabled && _this.box && _this.updateLayoutDeltas();
1592 /**
1593 * Ensure all children layouts are also updated.
1594 *
1595 * This uses a pre-bound function executor rather than a lamda to avoid creating a new function
1596 * multiple times per frame (source of mid-animation GC)
1597 */
1598 _this.children.forEach(fireUpdateLayoutDelta);
1599 };
1600 return _this;
1601 }
1602 /**
1603 * When a value is removed, we want to make sure it's removed from all rendered data structures.
1604 */
1605 HTMLVisualElement.prototype.removeValue = function (key) {
1606 _super.prototype.removeValue.call(this, key);
1607 delete this.vars[key];
1608 delete this.style[key];
1609 };
1610 /**
1611 * Empty the mutable data structures by re-creating them. We can do this every React render
1612 * as the comparative workload to the rest of the render is very low and this is also when
1613 * we want to reflect values that might have been removed by the render.
1614 */
1615 HTMLVisualElement.prototype.clean = function () {
1616 this.style = {};
1617 this.vars = {};
1618 this.transform = {};
1619 };
1620 HTMLVisualElement.prototype.updateConfig = function (config) {
1621 if (config === void 0) { config = {}; }
1622 this.config = tslib.__assign(tslib.__assign({}, this.defaultConfig), config);
1623 };
1624 /**
1625 * Read a value directly from the HTMLElement style.
1626 */
1627 HTMLVisualElement.prototype.read = function (key) {
1628 return this.getComputedStyle()[key] || 0;
1629 };
1630 /**
1631 * Read a value directly from the HTMLElement in case it's not defined by a Motion
1632 * prop. If it's a transform, we just return a pre-defined default value as reading these
1633 * out of a matrix is either error-prone or can incur a big payload for little benefit.
1634 */
1635 HTMLVisualElement.prototype.readNativeValue = function (key) {
1636 if (isTransformProp(key)) {
1637 var defaultValueType = getDefaultValueType(key);
1638 return defaultValueType ? defaultValueType.default || 0 : 0;
1639 }
1640 else {
1641 return this.read(key);
1642 }
1643 };
1644 HTMLVisualElement.prototype.enableLayoutProjection = function () {
1645 this.isLayoutProjectionEnabled = true;
1646 };
1647 HTMLVisualElement.prototype.hide = function () {
1648 if (this.isVisible === false)
1649 return;
1650 this.isVisible = false;
1651 this.scheduleRender();
1652 };
1653 HTMLVisualElement.prototype.show = function () {
1654 if (this.isVisible === true)
1655 return;
1656 this.isVisible = true;
1657 this.scheduleRender();
1658 };
1659 /**
1660 * Register an event listener to fire when the layout is updated. We might want to expose support
1661 * for this via a `motion` prop.
1662 */
1663 HTMLVisualElement.prototype.onLayoutUpdate = function (callback) {
1664 var _this = this;
1665 this.layoutUpdateListeners.add(callback);
1666 return function () { return _this.layoutUpdateListeners.delete(callback); };
1667 };
1668 /**
1669 * To be called when all layouts are successfully updated. In turn we can notify layoutUpdate
1670 * subscribers.
1671 */
1672 HTMLVisualElement.prototype.layoutReady = function (config) {
1673 var _this = this;
1674 this.layoutUpdateListeners.forEach(function (listener) {
1675 listener(_this.box, _this.prevViewportBox || _this.box, config);
1676 });
1677 };
1678 /**
1679 * Measure and return the Element's bounding box. We convert it to a AxisBox2D
1680 * structure to make it easier to work on each individual axis generically.
1681 */
1682 HTMLVisualElement.prototype.getBoundingBox = function () {
1683 var transformPagePoint = this.config.transformPagePoint;
1684 return getBoundingBox(this.element, transformPagePoint);
1685 };
1686 HTMLVisualElement.prototype.getBoundingBoxWithoutTransforms = function () {
1687 var bbox = this.getBoundingBox();
1688 removeBoxTransforms(bbox, this.latest);
1689 return bbox;
1690 };
1691 /**
1692 * Return the computed style after a render.
1693 */
1694 HTMLVisualElement.prototype.getComputedStyle = function () {
1695 return window.getComputedStyle(this.element);
1696 };
1697 /**
1698 *
1699 */
1700 HTMLVisualElement.prototype.snapshotBoundingBox = function () {
1701 this.prevViewportBox = this.getBoundingBoxWithoutTransforms();
1702 /**
1703 * Update targetBox to match the prevViewportBox. This is just to ensure
1704 * that targetBox is affected by scroll in the same way as the measured box
1705 */
1706 var _a = this.axisProgress, x = _a.x, y = _a.y;
1707 if (!this.isTargetBoxLocked && !x.isAnimating() && !y.isAnimating()) {
1708 this.targetBox = copyAxisBox(this.prevViewportBox);
1709 }
1710 };
1711 HTMLVisualElement.prototype.measureLayout = function () {
1712 this.box = this.getBoundingBox();
1713 this.boxCorrected = copyAxisBox(this.box);
1714 if (!this.targetBox)
1715 this.targetBox = copyAxisBox(this.box);
1716 };
1717 /**
1718 * Ensure the targetBox reflects the latest visual box on screen
1719 */
1720 HTMLVisualElement.prototype.refreshTargetBox = function () {
1721 this.targetBox = this.getBoundingBoxWithoutTransforms();
1722 };
1723 HTMLVisualElement.prototype.lockTargetBox = function () {
1724 this.isTargetBoxLocked = true;
1725 };
1726 HTMLVisualElement.prototype.unlockTargetBox = function () {
1727 this.stopLayoutAnimation();
1728 this.isTargetBoxLocked = false;
1729 };
1730 /**
1731 * Reset the transform on the current Element. This is called as part
1732 * of a batched process across the entire layout tree. To remove this write
1733 * cycle it'd be interesting to see if it's possible to "undo" all the current
1734 * layout transforms up the tree in the same way this.getBoundingBoxWithoutTransforms
1735 * works
1736 */
1737 HTMLVisualElement.prototype.resetTransform = function () {
1738 var transformTemplate = this.config.transformTemplate;
1739 this.element.style.transform = transformTemplate
1740 ? transformTemplate({}, "")
1741 : "none";
1742 // Ensure that whatever happens next, we restore our transform
1743 this.scheduleRender();
1744 };
1745 /**
1746 * Set new min/max boundaries to project an axis into
1747 */
1748 HTMLVisualElement.prototype.setAxisTarget = function (axis, min, max) {
1749 var targetAxis = this.targetBox[axis];
1750 targetAxis.min = min;
1751 targetAxis.max = max;
1752 // Flag that we want to fire the onViewportBoxUpdate event handler
1753 this.hasViewportBoxUpdated = true;
1754 this.rootParent.scheduleUpdateLayoutDelta();
1755 };
1756 /**
1757 *
1758 */
1759 HTMLVisualElement.prototype.startLayoutAxisAnimation = function (axis, transition) {
1760 var _this = this;
1761 var progress = this.axisProgress[axis];
1762 var _a = this.targetBox[axis], min = _a.min, max = _a.max;
1763 var length = max - min;
1764 progress.clearListeners();
1765 progress.set(min);
1766 progress.set(min); // Set twice to hard-reset velocity
1767 progress.onChange(function (v) { return _this.setAxisTarget(axis, v, v + length); });
1768 return startAnimation(axis, progress, 0, transition);
1769 };
1770 HTMLVisualElement.prototype.stopLayoutAnimation = function () {
1771 var _this = this;
1772 eachAxis(function (axis) { return _this.axisProgress[axis].stop(); });
1773 };
1774 /**
1775 * Update the layout deltas to reflect the relative positions of the layout
1776 * and the desired target box
1777 */
1778 HTMLVisualElement.prototype.updateLayoutDeltas = function () {
1779 var _a, _b;
1780 /**
1781 * Reset the corrected box with the latest values from box, as we're then going
1782 * to perform mutative operations on it.
1783 */
1784 resetBox(this.boxCorrected, this.box);
1785 /**
1786 * If this component has a parent, update this treeScale by incorporating the parent's
1787 * delta into its treeScale.
1788 */
1789 if (this.parent) {
1790 updateTreeScale(this.treeScale, this.parent.treeScale, this.parent.delta);
1791 }
1792 /**
1793 * Apply all the parent deltas to this box to produce the corrected box. This
1794 * is the layout box, as it will appear on screen as a result of the transforms of its parents.
1795 */
1796 applyTreeDeltas(this.boxCorrected, this.treePath);
1797 /**
1798 * Update the delta between the corrected box and the target box before user-set transforms were applied.
1799 * This will allow us to calculate the corrected borderRadius and boxShadow to compensate
1800 * for our layout reprojection, but still allow them to be scaled correctly by the user.
1801 * It might be that to simplify this we may want to accept that user-set scale is also corrected
1802 * and we wouldn't have to keep and calc both deltas, OR we could support a user setting
1803 * to allow people to choose whether these styles are corrected based on just the
1804 * layout reprojection or the final bounding box.
1805 */
1806 updateBoxDelta(this.delta, this.boxCorrected, this.targetBox);
1807 /**
1808 * If we have a listener for the viewport box, fire it.
1809 */
1810 this.hasViewportBoxUpdated && ((_b = (_a = this.config).onViewportBoxUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, this.targetBox, this.delta));
1811 this.hasViewportBoxUpdated = false;
1812 /**
1813 * Ensure this element renders on the next frame if the projection transform has changed.
1814 */
1815 var deltaTransform = createDeltaTransform(this.delta, this.treeScale);
1816 deltaTransform !== this.deltaTransform && this.scheduleRender();
1817 this.deltaTransform = deltaTransform;
1818 };
1819 HTMLVisualElement.prototype.updateTransformDeltas = function () {
1820 if (!this.isLayoutProjectionEnabled || !this.box)
1821 return;
1822 /**
1823 * Apply the latest user-set transforms to the targetBox to produce the targetBoxFinal.
1824 * This is the final box that we will then project into by calculating a transform delta and
1825 * applying it to the corrected box.
1826 */
1827 applyBoxTransforms(this.targetBoxFinal, this.targetBox, this.latest);
1828 /**
1829 * Update the delta between the corrected box and the final target box, after
1830 * user-set transforms are applied to it. This will be used by the renderer to
1831 * create a transform style that will reproject the element from its actual layout
1832 * into the desired bounding box.
1833 */
1834 updateBoxDelta(this.deltaFinal, this.boxCorrected, this.targetBoxFinal);
1835 };
1836 /**
1837 * ========================================
1838 * Build & render
1839 * ========================================
1840 */
1841 /**
1842 * Build a style prop using the latest resolved MotionValues
1843 */
1844 HTMLVisualElement.prototype.build = function () {
1845 this.updateTransformDeltas();
1846 if (this.isVisible !== undefined) {
1847 this.style.visibility = this.isVisible ? "visible" : "hidden";
1848 }
1849 buildHTMLStyles(this.latest, this.style, this.vars, this.transform, this.transformOrigin, this.transformKeys, this.config, this.isLayoutProjectionEnabled && !!this.box, this.delta, this.deltaFinal, this.treeScale, this.targetBoxFinal);
1850 };
1851 /**
1852 * Render the Element by rebuilding and applying the latest styles and vars.
1853 */
1854 HTMLVisualElement.prototype.render = function () {
1855 // Rebuild the latest animated values into style and vars caches.
1856 this.build();
1857 // Directly assign style into the Element's style prop. In tests Object.assign is the
1858 // fastest way to assign styles.
1859 Object.assign(this.element.style, this.style);
1860 // Loop over any CSS variables and assign those.
1861 for (var key in this.vars) {
1862 this.element.style.setProperty(key, this.vars[key]);
1863 }
1864 };
1865 return HTMLVisualElement;
1866}(VisualElement));
1867/**
1868 * Pre-bound version of updateLayoutDelta so we're not creating a new function multiple
1869 * times per frame.
1870 */
1871var fireUpdateLayoutDelta = function (child) {
1872 return child.updateLayoutDelta();
1873};
1874
1875/**
1876 * Creates a constant value over the lifecycle of a component.
1877 *
1878 * Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
1879 * a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
1880 * you can ensure that initialisers don't execute twice or more.
1881 */
1882function useConstant(init) {
1883 var ref = React.useRef(null);
1884 if (ref.current === null) {
1885 ref.current = init();
1886 }
1887 return ref.current;
1888}
1889
1890function calcOrigin$1(origin, offset, size) {
1891 return typeof origin === "string"
1892 ? origin
1893 : styleValueTypes.px.transform(offset + size * origin);
1894}
1895/**
1896 * The SVG transform origin defaults are different to CSS and is less intuitive,
1897 * so we use the measured dimensions of the SVG to reconcile these.
1898 */
1899function calcSVGTransformOrigin(dimensions, originX, originY) {
1900 var pxOriginX = calcOrigin$1(originX, dimensions.x, dimensions.width);
1901 var pxOriginY = calcOrigin$1(originY, dimensions.y, dimensions.height);
1902 return pxOriginX + " " + pxOriginY;
1903}
1904
1905// Convert a progress 0-1 to a pixels value based on the provided length
1906var progressToPixels = function (progress, length) {
1907 return styleValueTypes.px.transform(progress * length);
1908};
1909var dashKeys = {
1910 offset: "stroke-dashoffset",
1911 array: "stroke-dasharray",
1912};
1913var camelKeys = {
1914 offset: "strokeDashoffset",
1915 array: "strokeDasharray",
1916};
1917/**
1918 * Build SVG path properties. Uses the path's measured length to convert
1919 * our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset
1920 * and stroke-dasharray attributes.
1921 *
1922 * This function is mutative to reduce per-frame GC.
1923 */
1924function buildSVGPath(attrs, totalLength, length, spacing, offset, useDashCase) {
1925 if (spacing === void 0) { spacing = 1; }
1926 if (offset === void 0) { offset = 0; }
1927 if (useDashCase === void 0) { useDashCase = true; }
1928 // We use dash case when setting attributes directly to the DOM node and camel case
1929 // when defining props on a React component.
1930 var keys = useDashCase ? dashKeys : camelKeys;
1931 // Build the dash offset
1932 attrs[keys.offset] = progressToPixels(-offset, totalLength);
1933 // Build the dash array
1934 var pathLength = progressToPixels(length, totalLength);
1935 var pathSpacing = progressToPixels(spacing, totalLength);
1936 attrs[keys.array] = pathLength + " " + pathSpacing;
1937}
1938
1939var unmeasured = { x: 0, y: 0, width: 0, height: 0 };
1940/**
1941 * Build SVG visual attrbutes, like cx and style.transform
1942 */
1943function buildSVGAttrs(_a, style, vars, attrs, transform, transformOrigin, transformKeys, config, dimensions, totalPathLength, isLayoutProjectionEnabled, delta, deltaFinal, treeScale, targetBox) {
1944 var attrX = _a.attrX, attrY = _a.attrY, originX = _a.originX, originY = _a.originY, pathLength = _a.pathLength, _b = _a.pathSpacing, pathSpacing = _b === void 0 ? 1 : _b, _c = _a.pathOffset, pathOffset = _c === void 0 ? 0 : _c,
1945 // This is object creation, which we try to avoid per-frame.
1946 latest = tslib.__rest(_a, ["attrX", "attrY", "originX", "originY", "pathLength", "pathSpacing", "pathOffset"]);
1947 /**
1948 * With SVG we treat all animated values as attributes rather than CSS, so we build into attrs
1949 */
1950 buildHTMLStyles(latest, attrs, vars, transform, transformOrigin, transformKeys, config, isLayoutProjectionEnabled, delta, deltaFinal, treeScale, targetBox);
1951 /**
1952 * However, we apply transforms as CSS transforms. So if we detect a transform we take it from attrs
1953 * and copy it into style.
1954 */
1955 if (attrs.transform) {
1956 style.transform = attrs.transform;
1957 delete attrs.transform;
1958 }
1959 // Parse transformOrigin
1960 if (originX !== undefined || originY !== undefined || style.transform) {
1961 style.transformOrigin = calcSVGTransformOrigin(dimensions || unmeasured, originX !== undefined ? originX : 0.5, originY !== undefined ? originY : 0.5);
1962 }
1963 // Treat x/y not as shortcuts but as actual attributes
1964 if (attrX !== undefined)
1965 attrs.x = attrX;
1966 if (attrY !== undefined)
1967 attrs.y = attrY;
1968 // Build SVG path if one has been measured
1969 if (totalPathLength !== undefined && pathLength !== undefined) {
1970 buildSVGPath(attrs, totalPathLength, pathLength, pathSpacing, pathOffset, false);
1971 }
1972 return attrs;
1973}
1974
1975/**
1976 * A set of attribute names that are always read/written as camel case.
1977 */
1978var camelCaseAttributes = new Set([
1979 "baseFrequency",
1980 "diffuseConstant",
1981 "kernelMatrix",
1982 "kernelUnitLength",
1983 "keySplines",
1984 "keyTimes",
1985 "limitingConeAngle",
1986 "markerHeight",
1987 "markerWidth",
1988 "numOctaves",
1989 "targetX",
1990 "targetY",
1991 "surfaceScale",
1992 "specularConstant",
1993 "specularExponent",
1994 "stdDeviation",
1995 "tableValues",
1996]);
1997
1998var CAMEL_CASE_PATTERN = /([a-z])([A-Z])/g;
1999var REPLACE_TEMPLATE = "$1-$2";
2000/**
2001 * Convert camelCase to dash-case properties.
2002 */
2003var camelToDash = function (str) {
2004 return str.replace(CAMEL_CASE_PATTERN, REPLACE_TEMPLATE).toLowerCase();
2005};
2006
2007/**
2008 * A VisualElement for SVGElements. Inherits from and extends HTMLVisualElement as the two
2009 * share data structures.
2010 */
2011var SVGVisualElement = /** @class */ (function (_super) {
2012 tslib.__extends(SVGVisualElement, _super);
2013 function SVGVisualElement() {
2014 var _this = _super !== null && _super.apply(this, arguments) || this;
2015 /**
2016 * A mutable record of attributes we want to apply directly to the rendered Element
2017 * every frame. We use a mutable data structure to reduce GC during animations.
2018 */
2019 _this.attrs = {};
2020 /**
2021 * We disable hardware acceleration for SVG transforms as they're not currently able to be accelerated.
2022 */
2023 _this.defaultConfig = {
2024 enableHardwareAcceleration: false,
2025 };
2026 /**
2027 * Without duplicating this call from HTMLVisualElement we end up with HTMLVisualElement.defaultConfig
2028 * being assigned to config
2029 */
2030 _this.config = _this.defaultConfig;
2031 return _this;
2032 }
2033 /**
2034 * Measure the SVG element on mount. This can affect page rendering so there might be a
2035 * better time to perform this - for instance dynamically only if there's a transform-origin dependent
2036 * transform being set (like rotate)
2037 */
2038 SVGVisualElement.prototype.mount = function (element) {
2039 _super.prototype.mount.call(this, element);
2040 this.measure();
2041 };
2042 /**
2043 * Update the SVG dimensions and path length
2044 */
2045 SVGVisualElement.prototype.measure = function () {
2046 try {
2047 this.dimensions =
2048 typeof this.element.getBBox ===
2049 "function"
2050 ? this.element.getBBox()
2051 : this.element.getBoundingClientRect();
2052 }
2053 catch (e) {
2054 // Most likely trying to measure an unrendered element under Firefox
2055 this.dimensions = { x: 0, y: 0, width: 0, height: 0 };
2056 }
2057 if (isPath(this.element)) {
2058 this.totalPathLength = this.element.getTotalLength();
2059 }
2060 };
2061 /**
2062 * Empty the mutable data structures in case attrs have been removed between renders.
2063 */
2064 SVGVisualElement.prototype.clean = function () {
2065 _super.prototype.clean.call(this);
2066 this.attrs = {};
2067 };
2068 /**
2069 * Read an attribute directly from the SVGElement
2070 */
2071 SVGVisualElement.prototype.read = function (key) {
2072 key = !camelCaseAttributes.has(key) ? camelToDash(key) : key;
2073 return this.element.getAttribute(key);
2074 };
2075 SVGVisualElement.prototype.build = function () {
2076 this.updateTransformDeltas();
2077 buildSVGAttrs(this.latest, this.style, this.vars, this.attrs, this.transform, this.transformOrigin, this.transformKeys, this.config, this.dimensions, this.totalPathLength, this.isLayoutProjectionEnabled && !!this.box, this.delta, this.deltaFinal, this.treeScale, this.targetBoxFinal);
2078 };
2079 SVGVisualElement.prototype.render = function () {
2080 // Update HTML styles and CSS variables
2081 _super.prototype.render.call(this);
2082 // Loop through attributes and apply them to the SVGElement
2083 for (var key in this.attrs) {
2084 this.element.setAttribute(camelToDash(key), this.attrs[key]);
2085 }
2086 };
2087 return SVGVisualElement;
2088}(HTMLVisualElement));
2089function isPath(element) {
2090 return element.tagName === "path";
2091}
2092
2093/**
2094 * @internal
2095 */
2096/**
2097 * @internal
2098 */
2099var svgElements = [
2100 "animate",
2101 "circle",
2102 "clipPath",
2103 "defs",
2104 "desc",
2105 "ellipse",
2106 "feBlend",
2107 "feColorMatrix",
2108 "feComponentTransfer",
2109 "feComposite",
2110 "feConvolveMatrix",
2111 "feDiffuseLighting",
2112 "feDisplacementMap",
2113 "feDistantLight",
2114 "feDropShadow",
2115 "feFlood",
2116 "feFuncA",
2117 "feFuncB",
2118 "feFuncG",
2119 "feFuncR",
2120 "feGaussianBlur",
2121 "feImage",
2122 "feMerge",
2123 "feMergeNode",
2124 "feMorphology",
2125 "feOffset",
2126 "fePointLight",
2127 "feSpecularLighting",
2128 "feSpotLight",
2129 "feTile",
2130 "feTurbulence",
2131 "filter",
2132 "foreignObject",
2133 "g",
2134 "image",
2135 "line",
2136 "linearGradient",
2137 "marker",
2138 "mask",
2139 "metadata",
2140 "path",
2141 "pattern",
2142 "polygon",
2143 "polyline",
2144 "radialGradient",
2145 "rect",
2146 "stop",
2147 "svg",
2148 "switch",
2149 "symbol",
2150 "text",
2151 "textPath",
2152 "tspan",
2153 "use",
2154 "view",
2155];
2156
2157var svgTagNames = new Set(svgElements);
2158/**
2159 * Determine whether this is a HTML or SVG component based on if the provided
2160 * Component is a string and a recognised SVG tag. A potentially better way to
2161 * do this would be to offer a `motion.customSVG` function and determine this
2162 * when we generate the `motion.circle` etc components.
2163 */
2164function isSVGComponent(Component) {
2165 return typeof Component === "string" && svgTagNames.has(Component);
2166}
2167
2168/**
2169 * @public
2170 */
2171var PresenceContext = React.createContext(null);
2172
2173/**
2174 * When a component is the child of `AnimatePresence`, it can use `usePresence`
2175 * to access information about whether it's still present in the React tree.
2176 *
2177 * ```jsx
2178 * import { usePresence } from "framer-motion"
2179 *
2180 * export const Component = () => {
2181 * const [isPresent, safeToRemove] = usePresence()
2182 *
2183 * useEffect(() => {
2184 * !isPresent setTimeout(safeToRemove, 1000)
2185 * }, [isPresent])
2186 *
2187 * return <div />
2188 * }
2189 * ```
2190 *
2191 * If `isPresent` is `false`, it means that a component has been removed the tree, but
2192 * `AnimatePresence` won't really remove it until `safeToRemove` has been called.
2193 *
2194 * @public
2195 */
2196function usePresence() {
2197 var context = React.useContext(PresenceContext);
2198 if (context === null)
2199 return [true, null];
2200 var isPresent = context.isPresent, onExitComplete = context.onExitComplete, register = context.register;
2201 // It's safe to call the following hooks conditionally (after an early return) because the context will always
2202 // either be null or non-null for the lifespan of the component.
2203 // Replace with useOpaqueId when released in React
2204 var id = useUniqueId();
2205 React.useEffect(function () { return register(id); }, []);
2206 var safeToRemove = function () { return onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete(id); };
2207 return !isPresent && onExitComplete ? [false, safeToRemove] : [true];
2208}
2209/**
2210 * @public
2211 */
2212function useIsPresent() {
2213 var context = React.useContext(PresenceContext);
2214 return context === null ? true : context.isPresent;
2215}
2216var counter = 0;
2217var incrementId = function () { return counter++; };
2218var useUniqueId = function () { return useConstant(incrementId); };
2219
2220/**
2221 * DOM-flavoured variation of the useVisualElement hook. Used to create either a HTMLVisualElement
2222 * or SVGVisualElement for the component.
2223 */
2224var useDomVisualElement = function (Component, props, parent, isStatic, ref) {
2225 var visualElement = useConstant(function () {
2226 var DOMVisualElement = isSVGComponent(Component)
2227 ? SVGVisualElement
2228 : HTMLVisualElement;
2229 return new DOMVisualElement(parent, ref);
2230 });
2231 visualElement.updateConfig(tslib.__assign({ enableHardwareAcceleration: !isStatic }, props));
2232 visualElement.layoutId = props.layoutId;
2233 var isPresent = useIsPresent();
2234 visualElement.isPresent =
2235 props.isPresent !== undefined ? props.isPresent : isPresent;
2236 return visualElement;
2237};
2238
2239/**
2240 * A list of all valid MotionProps.
2241 *
2242 * @internalremarks
2243 * This doesn't throw if a `MotionProp` name is missing - it should.
2244 */
2245var validMotionProps = new Set([
2246 "initial",
2247 "animate",
2248 "exit",
2249 "style",
2250 "variants",
2251 "transition",
2252 "transformTemplate",
2253 "transformValues",
2254 "custom",
2255 "inherit",
2256 "static",
2257 "layout",
2258 "layoutId",
2259 "onLayoutAnimationComplete",
2260 "onViewportBoxUpdate",
2261 "onAnimationStart",
2262 "onAnimationComplete",
2263 "onUpdate",
2264 "onDragStart",
2265 "onDrag",
2266 "onDragEnd",
2267 "onMeasureDragConstraints",
2268 "onDirectionLock",
2269 "onDragTransitionEnd",
2270 "drag",
2271 "dragControls",
2272 "dragListener",
2273 "dragConstraints",
2274 "dragDirectionLock",
2275 "dragElastic",
2276 "dragMomentum",
2277 "dragPropagation",
2278 "dragTransition",
2279 "onPan",
2280 "onPanStart",
2281 "onPanEnd",
2282 "onPanSessionStart",
2283 "onTap",
2284 "onTapStart",
2285 "onTapCancel",
2286 "whileHover",
2287 "whileTap",
2288 "onHoverEnd",
2289 "onHoverStart",
2290]);
2291/**
2292 * Check whether a prop name is a valid `MotionProp` key.
2293 *
2294 * @param key - Name of the property to check
2295 * @returns `true` is key is a valid `MotionProp`.
2296 *
2297 * @public
2298 */
2299function isValidMotionProp(key) {
2300 return validMotionProps.has(key);
2301}
2302
2303var isPropValid = function (key) { return !isValidMotionProp(key); };
2304/**
2305 * Emotion and Styled Components both allow users to pass through arbitrary props to their components
2306 * to dynamically generate CSS. They both use the `@emotion/is-prop-valid` package to determine which
2307 * of these should be passed to the underlying DOM node.
2308 *
2309 * However, when styling a Motion component `styled(motion.div)`, both packages pass through *all* props
2310 * as it's seen as an arbitrary component rather than a DOM node. Motion only allows arbitrary props
2311 * passed through the `custom` prop so it doesn't *need* the payload or computational overhead of
2312 * `@emotion/is-prop-valid`, however to fix this problem we need to use it.
2313 *
2314 * By making it an optionalDependency we can offer this functionality only in the situations where it's
2315 * actually required.
2316 */
2317try {
2318 var emotionIsPropValid_1 = require("@emotion/is-prop-valid").default;
2319 isPropValid = function (key) {
2320 // Handle events explicitly as Emotion validates them all as true
2321 if (key.startsWith("on")) {
2322 return !isValidMotionProp(key);
2323 }
2324 else {
2325 return emotionIsPropValid_1(key);
2326 }
2327 };
2328}
2329catch (_a) {
2330 // We don't need to actually do anything here - the fallback is the existing `isPropValid`.
2331}
2332function filterProps(props) {
2333 var domProps = {};
2334 for (var key in props) {
2335 if (isPropValid(key))
2336 domProps[key] = props[key];
2337 }
2338 return domProps;
2339}
2340
2341function buildHTMLProps(visualElement, _a) {
2342 var drag = _a.drag;
2343 // The `any` isn't ideal but it is the type of createElement props argument
2344 var htmlProps = {
2345 style: tslib.__assign(tslib.__assign(tslib.__assign({}, visualElement.reactStyle), visualElement.style), visualElement.vars),
2346 };
2347 if (!!drag) {
2348 // Disable text selection
2349 htmlProps.style.userSelect = "none";
2350 // Disable the ghost element when a user drags
2351 htmlProps.draggable = false;
2352 }
2353 return htmlProps;
2354}
2355
2356/**
2357 * Build React props for SVG elements
2358 */
2359function buildSVGProps(visualElement) {
2360 return tslib.__assign(tslib.__assign({}, visualElement.attrs), { style: tslib.__assign({}, visualElement.reactStyle) });
2361}
2362
2363function render(Component, props, visualElement) {
2364 // Only filter props from components we control, ie `motion.div`. If this
2365 // is a custom component pass along everything provided to it.
2366 var forwardedProps = typeof Component === "string" ? filterProps(props) : props;
2367 /**
2368 * Every render, empty and rebuild the animated values to be applied to our Element.
2369 * During animation these data structures are used in a mutable fashion to reduce
2370 * garbage collection, but between renders we can flush them to remove values
2371 * that might have been taken out of the provided props.
2372 */
2373 visualElement.clean();
2374 visualElement.build();
2375 // Generate props to visually render this component
2376 var visualProps = isSVGComponent(Component)
2377 ? buildSVGProps(visualElement)
2378 : buildHTMLProps(visualElement, props);
2379 return React.createElement(Component, tslib.__assign(tslib.__assign(tslib.__assign({}, forwardedProps), { ref: visualElement.ref }), visualProps));
2380}
2381
2382function isCSSVariable$1(value) {
2383 return typeof value === "string" && value.startsWith("var(--");
2384}
2385/**
2386 * Parse Framer's special CSS variable format into a CSS token and a fallback.
2387 *
2388 * ```
2389 * `var(--foo, #fff)` => [`--foo`, '#fff']
2390 * ```
2391 *
2392 * @param current
2393 */
2394var cssVariableRegex = /var\((--[a-zA-Z0-9-_]+),? ?([a-zA-Z0-9 ()%#.,-]+)?\)/;
2395function parseCSSVariable(current) {
2396 var match = cssVariableRegex.exec(current);
2397 if (!match)
2398 return [,];
2399 var token = match[1], fallback = match[2];
2400 return [token, fallback];
2401}
2402var maxDepth = 4;
2403function getVariableValue(current, element, depth) {
2404 if (depth === void 0) { depth = 1; }
2405 heyListen.invariant(depth <= maxDepth, "Max CSS variable fallback depth detected in property \"" + current + "\". This may indicate a circular fallback dependency.");
2406 var _a = parseCSSVariable(current), token = _a[0], fallback = _a[1];
2407 // No CSS variable detected
2408 if (!token)
2409 return;
2410 // Attempt to read this CSS variable off the element
2411 var resolved = window.getComputedStyle(element).getPropertyValue(token);
2412 if (resolved) {
2413 return resolved;
2414 }
2415 else if (isCSSVariable$1(fallback)) {
2416 // The fallback might itself be a CSS variable, in which case we attempt to resolve it too.
2417 return getVariableValue(fallback, element, depth + 1);
2418 }
2419 else {
2420 return fallback;
2421 }
2422}
2423/**
2424 * Resolve CSS variables from
2425 *
2426 * @internal
2427 */
2428function resolveCSSVariables(visualElement, _a, transitionEnd) {
2429 var target = tslib.__rest(_a, []);
2430 var element = visualElement.getInstance();
2431 if (!(element instanceof HTMLElement))
2432 return { target: target, transitionEnd: transitionEnd };
2433 // If `transitionEnd` isn't `undefined`, clone it. We could clone `target` and `transitionEnd`
2434 // only if they change but I think this reads clearer and this isn't a performance-critical path.
2435 if (transitionEnd) {
2436 transitionEnd = tslib.__assign({}, transitionEnd);
2437 }
2438 // Go through existing `MotionValue`s and ensure any existing CSS variables are resolved
2439 visualElement.forEachValue(function (value) {
2440 var current = value.get();
2441 if (!isCSSVariable$1(current))
2442 return;
2443 var resolved = getVariableValue(current, element);
2444 if (resolved)
2445 value.set(resolved);
2446 });
2447 // Cycle through every target property and resolve CSS variables. Currently
2448 // we only read single-var properties like `var(--foo)`, not `calc(var(--foo) + 20px)`
2449 for (var key in target) {
2450 var current = target[key];
2451 if (!isCSSVariable$1(current))
2452 continue;
2453 var resolved = getVariableValue(current, element);
2454 if (!resolved)
2455 continue;
2456 // Clone target if it hasn't already been
2457 target[key] = resolved;
2458 // If the user hasn't already set this key on `transitionEnd`, set it to the unresolved
2459 // CSS variable. This will ensure that after the animation the component will reflect
2460 // changes in the value of the CSS variable.
2461 if (transitionEnd && transitionEnd[key] === undefined) {
2462 transitionEnd[key] = current;
2463 }
2464 }
2465 return { target: target, transitionEnd: transitionEnd };
2466}
2467
2468var positionalKeys = new Set([
2469 "width",
2470 "height",
2471 "top",
2472 "left",
2473 "right",
2474 "bottom",
2475 "x",
2476 "y",
2477]);
2478var isPositionalKey = function (key) { return positionalKeys.has(key); };
2479var hasPositionalKey = function (target) {
2480 return Object.keys(target).some(isPositionalKey);
2481};
2482var setAndResetVelocity = function (value, to) {
2483 // Looks odd but setting it twice doesn't render, it'll just
2484 // set both prev and current to the latest value
2485 value.set(to, false);
2486 value.set(to);
2487};
2488var isNumOrPxType = function (v) {
2489 return v === styleValueTypes.number || v === styleValueTypes.px;
2490};
2491var BoundingBoxDimension;
2492(function (BoundingBoxDimension) {
2493 BoundingBoxDimension["width"] = "width";
2494 BoundingBoxDimension["height"] = "height";
2495 BoundingBoxDimension["left"] = "left";
2496 BoundingBoxDimension["right"] = "right";
2497 BoundingBoxDimension["top"] = "top";
2498 BoundingBoxDimension["bottom"] = "bottom";
2499})(BoundingBoxDimension || (BoundingBoxDimension = {}));
2500var getPosFromMatrix = function (matrix, pos) {
2501 return parseFloat(matrix.split(", ")[pos]);
2502};
2503var getTranslateFromMatrix = function (pos2, pos3) { return function (_bbox, _a) {
2504 var transform = _a.transform;
2505 if (transform === "none" || !transform)
2506 return 0;
2507 var matrix3d = transform.match(/^matrix3d\((.+)\)$/);
2508 if (matrix3d) {
2509 return getPosFromMatrix(matrix3d[1], pos3);
2510 }
2511 else {
2512 var matrix = transform.match(/^matrix\((.+)\)$/);
2513 if (matrix) {
2514 return getPosFromMatrix(matrix[1], pos2);
2515 }
2516 else {
2517 return 0;
2518 }
2519 }
2520}; };
2521var transformKeys = new Set(["x", "y", "z"]);
2522var nonTranslationalTransformKeys = transformProps.filter(function (key) { return !transformKeys.has(key); });
2523function removeNonTranslationalTransform(visualElement) {
2524 var removedTransforms = [];
2525 nonTranslationalTransformKeys.forEach(function (key) {
2526 var value = visualElement.getValue(key);
2527 if (value !== undefined) {
2528 removedTransforms.push([key, value.get()]);
2529 value.set(key.startsWith("scale") ? 1 : 0);
2530 }
2531 });
2532 // Apply changes to element before measurement
2533 if (removedTransforms.length)
2534 visualElement.render();
2535 return removedTransforms;
2536}
2537var positionalValues = {
2538 // Dimensions
2539 width: function (_a) {
2540 var x = _a.x;
2541 return x.max - x.min;
2542 },
2543 height: function (_a) {
2544 var y = _a.y;
2545 return y.max - y.min;
2546 },
2547 top: function (_bbox, _a) {
2548 var top = _a.top;
2549 return parseFloat(top);
2550 },
2551 left: function (_bbox, _a) {
2552 var left = _a.left;
2553 return parseFloat(left);
2554 },
2555 bottom: function (_a, _b) {
2556 var y = _a.y;
2557 var top = _b.top;
2558 return parseFloat(top) + (y.max - y.min);
2559 },
2560 right: function (_a, _b) {
2561 var x = _a.x;
2562 var left = _b.left;
2563 return parseFloat(left) + (x.max - x.min);
2564 },
2565 // Transform
2566 x: getTranslateFromMatrix(4, 13),
2567 y: getTranslateFromMatrix(5, 14),
2568};
2569var convertChangedValueTypes = function (target, visualElement, changedKeys) {
2570 var originBbox = visualElement.getBoundingBox();
2571 var elementComputedStyle = visualElement.getComputedStyle();
2572 var display = elementComputedStyle.display, top = elementComputedStyle.top, left = elementComputedStyle.left, bottom = elementComputedStyle.bottom, right = elementComputedStyle.right, transform = elementComputedStyle.transform;
2573 var originComputedStyle = { top: top, left: left, bottom: bottom, right: right, transform: transform };
2574 // If the element is currently set to display: "none", make it visible before
2575 // measuring the target bounding box
2576 if (display === "none") {
2577 visualElement.setStaticValues("display", target.display || "block");
2578 }
2579 // Apply the latest values (as set in checkAndConvertChangedValueTypes)
2580 visualElement.render();
2581 var targetBbox = visualElement.getBoundingBox();
2582 changedKeys.forEach(function (key) {
2583 // Restore styles to their **calculated computed style**, not their actual
2584 // originally set style. This allows us to animate between equivalent pixel units.
2585 var value = visualElement.getValue(key);
2586 setAndResetVelocity(value, positionalValues[key](originBbox, originComputedStyle));
2587 target[key] = positionalValues[key](targetBbox, elementComputedStyle);
2588 });
2589 return target;
2590};
2591var checkAndConvertChangedValueTypes = function (visualElement, target, origin, transitionEnd) {
2592 if (origin === void 0) { origin = {}; }
2593 if (transitionEnd === void 0) { transitionEnd = {}; }
2594 target = tslib.__assign({}, target);
2595 transitionEnd = tslib.__assign({}, transitionEnd);
2596 var targetPositionalKeys = Object.keys(target).filter(isPositionalKey);
2597 // We want to remove any transform values that could affect the element's bounding box before
2598 // it's measured. We'll reapply these later.
2599 var removedTransformValues = [];
2600 var hasAttemptedToRemoveTransformValues = false;
2601 var changedValueTypeKeys = [];
2602 targetPositionalKeys.forEach(function (key) {
2603 var value = visualElement.getValue(key);
2604 if (!visualElement.hasValue(key))
2605 return;
2606 var from = origin[key];
2607 var to = target[key];
2608 var fromType = findDimensionValueType(from);
2609 var toType;
2610 // TODO: The current implementation of this basically throws an error
2611 // if you try and do value conversion via keyframes. There's probably
2612 // a way of doing this but the performance implications would need greater scrutiny,
2613 // as it'd be doing multiple resize-remeasure operations.
2614 if (isKeyframesTarget(to)) {
2615 var numKeyframes = to.length;
2616 for (var i = to[0] === null ? 1 : 0; i < numKeyframes; i++) {
2617 if (!toType) {
2618 toType = findDimensionValueType(to[i]);
2619 heyListen.invariant(toType === fromType ||
2620 (isNumOrPxType(fromType) && isNumOrPxType(toType)), "Keyframes must be of the same dimension as the current value");
2621 }
2622 else {
2623 heyListen.invariant(findDimensionValueType(to[i]) === toType, "All keyframes must be of the same type");
2624 }
2625 }
2626 }
2627 else {
2628 toType = findDimensionValueType(to);
2629 }
2630 if (fromType !== toType) {
2631 // If they're both just number or px, convert them both to numbers rather than
2632 // relying on resize/remeasure to convert (which is wasteful in this situation)
2633 if (isNumOrPxType(fromType) && isNumOrPxType(toType)) {
2634 var current = value.get();
2635 if (typeof current === "string") {
2636 value.set(parseFloat(current));
2637 }
2638 if (typeof to === "string") {
2639 target[key] = parseFloat(to);
2640 }
2641 else if (Array.isArray(to) && toType === styleValueTypes.px) {
2642 target[key] = to.map(parseFloat);
2643 }
2644 }
2645 else {
2646 // If we're going to do value conversion via DOM measurements, we first
2647 // need to remove non-positional transform values that could affect the bbox measurements.
2648 if (!hasAttemptedToRemoveTransformValues) {
2649 removedTransformValues = removeNonTranslationalTransform(visualElement);
2650 hasAttemptedToRemoveTransformValues = true;
2651 }
2652 changedValueTypeKeys.push(key);
2653 transitionEnd[key] =
2654 transitionEnd[key] !== undefined
2655 ? transitionEnd[key]
2656 : target[key];
2657 setAndResetVelocity(value, to);
2658 }
2659 }
2660 });
2661 if (changedValueTypeKeys.length) {
2662 var convertedTarget = convertChangedValueTypes(target, visualElement, changedValueTypeKeys);
2663 // If we removed transform values, reapply them before the next render
2664 if (removedTransformValues.length) {
2665 removedTransformValues.forEach(function (_a) {
2666 var key = _a[0], value = _a[1];
2667 visualElement.getValue(key).set(value);
2668 });
2669 }
2670 // Reapply original values
2671 visualElement.render();
2672 return { target: convertedTarget, transitionEnd: transitionEnd };
2673 }
2674 else {
2675 return { target: target, transitionEnd: transitionEnd };
2676 }
2677};
2678/**
2679 * Convert value types for x/y/width/height/top/left/bottom/right
2680 *
2681 * Allows animation between `'auto'` -> `'100%'` or `0` -> `'calc(50% - 10vw)'`
2682 *
2683 * @internal
2684 */
2685function unitConversion(visualElement, target, origin, transitionEnd) {
2686 return hasPositionalKey(target)
2687 ? checkAndConvertChangedValueTypes(visualElement, target, origin, transitionEnd)
2688 : { target: target, transitionEnd: transitionEnd };
2689}
2690
2691/**
2692 * Parse a DOM variant to make it animatable. This involves resolving CSS variables
2693 * and ensuring animations like "20%" => "calc(50vw)" are performed in pixels.
2694 */
2695var parseDomVariant = function (visualElement, target, origin, transitionEnd) {
2696 var resolved = resolveCSSVariables(visualElement, target, transitionEnd);
2697 target = resolved.target;
2698 transitionEnd = resolved.transitionEnd;
2699 return unitConversion(visualElement, target, origin, transitionEnd);
2700};
2701
2702/**
2703 * Use callback either only on the initial render or on all renders. In concurrent mode
2704 * the "initial" render might run multiple times
2705 *
2706 * @param callback - Callback to run
2707 * @param isInitialOnly - Set to `true` to only run on initial render, or `false` for all renders. Defaults to `false`.
2708 *
2709 * @public
2710 */
2711function useInitialOrEveryRender(callback, isInitialOnly) {
2712 if (isInitialOnly === void 0) { isInitialOnly = false; }
2713 var isInitialRender = React.useRef(true);
2714 if (!isInitialOnly || (isInitialOnly && isInitialRender.current)) {
2715 callback();
2716 }
2717 isInitialRender.current = false;
2718}
2719
2720/**
2721 * Control animations on one or more components.
2722 *
2723 * @public
2724 */
2725var AnimationControls = /** @class */ (function () {
2726 function AnimationControls() {
2727 /**
2728 * Track whether the host component has mounted.
2729 *
2730 * @internal
2731 */
2732 this.hasMounted = false;
2733 /**
2734 * Pending animations that are started before a component is mounted.
2735 *
2736 * @internal
2737 */
2738 this.pendingAnimations = [];
2739 /**
2740 * A collection of linked component animation controls.
2741 *
2742 * @internal
2743 */
2744 this.componentControls = new Set();
2745 }
2746 /**
2747 * Set variants on this and all child components.
2748 *
2749 * @param variants - The variants to set
2750 *
2751 * @internal
2752 */
2753 AnimationControls.prototype.setVariants = function (variants) {
2754 this.variants = variants;
2755 this.componentControls.forEach(function (controls) {
2756 return controls.setVariants(variants);
2757 });
2758 };
2759 /**
2760 * Set a default transition on this and all child components
2761 *
2762 * @param transition - The default transition to set
2763 *
2764 * @internal
2765 */
2766 AnimationControls.prototype.setDefaultTransition = function (transition) {
2767 this.defaultTransition = transition;
2768 this.componentControls.forEach(function (controls) {
2769 return controls.setDefaultTransition(transition);
2770 });
2771 };
2772 /**
2773 * Subscribes a component's animation controls to this.
2774 *
2775 * @param controls - The controls to subscribe
2776 * @returns An unsubscribe function.
2777 *
2778 * @internal
2779 */
2780 AnimationControls.prototype.subscribe = function (controls) {
2781 var _this = this;
2782 this.componentControls.add(controls);
2783 if (this.variants)
2784 controls.setVariants(this.variants);
2785 if (this.defaultTransition)
2786 controls.setDefaultTransition(this.defaultTransition);
2787 return function () { return _this.componentControls.delete(controls); };
2788 };
2789 /**
2790 * Starts an animation on all linked components.
2791 *
2792 * @remarks
2793 *
2794 * ```jsx
2795 * controls.start("variantLabel")
2796 * controls.start({
2797 * x: 0,
2798 * transition: { duration: 1 }
2799 * })
2800 * ```
2801 *
2802 * @param definition - Properties or variant label to animate to
2803 * @param transition - Optional `transtion` to apply to a variant
2804 * @returns - A `Promise` that resolves when all animations have completed.
2805 *
2806 * @public
2807 */
2808 AnimationControls.prototype.start = function (definition, transitionOverride) {
2809 var _this = this;
2810 if (this.hasMounted) {
2811 var animations_1 = [];
2812 this.componentControls.forEach(function (controls) {
2813 var animation = controls.start(definition, {
2814 transitionOverride: transitionOverride,
2815 });
2816 animations_1.push(animation);
2817 });
2818 return Promise.all(animations_1);
2819 }
2820 else {
2821 return new Promise(function (resolve) {
2822 _this.pendingAnimations.push({
2823 animation: [definition, transitionOverride],
2824 resolve: resolve,
2825 });
2826 });
2827 }
2828 };
2829 /**
2830 * Instantly set to a set of properties or a variant.
2831 *
2832 * ```jsx
2833 * // With properties
2834 * controls.set({ opacity: 0 })
2835 *
2836 * // With variants
2837 * controls.set("hidden")
2838 * ```
2839 *
2840 * @internalremarks
2841 * We could perform a similar trick to `.start` where this can be called before mount
2842 * and we maintain a list of of pending actions that get applied on mount. But the
2843 * expectation of `set` is that it happens synchronously and this would be difficult
2844 * to do before any children have even attached themselves. It's also poor practise
2845 * and we should discourage render-synchronous `.start` calls rather than lean into this.
2846 *
2847 * @public
2848 */
2849 AnimationControls.prototype.set = function (definition) {
2850 heyListen.invariant(this.hasMounted, "controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook.");
2851 return this.componentControls.forEach(function (controls) {
2852 return controls.apply(definition);
2853 });
2854 };
2855 /**
2856 * Stops animations on all linked components.
2857 *
2858 * ```jsx
2859 * controls.stop()
2860 * ```
2861 *
2862 * @public
2863 */
2864 AnimationControls.prototype.stop = function () {
2865 this.componentControls.forEach(function (controls) { return controls.stop(); });
2866 };
2867 /**
2868 * Initialises the animation controls.
2869 *
2870 * @internal
2871 */
2872 AnimationControls.prototype.mount = function () {
2873 var _this = this;
2874 this.hasMounted = true;
2875 this.pendingAnimations.forEach(function (_a) {
2876 var animation = _a.animation, resolve = _a.resolve;
2877 return _this.start.apply(_this, animation).then(resolve);
2878 });
2879 };
2880 /**
2881 * Stops all child animations when the host component unmounts.
2882 *
2883 * @internal
2884 */
2885 AnimationControls.prototype.unmount = function () {
2886 this.hasMounted = false;
2887 this.stop();
2888 };
2889 return AnimationControls;
2890}());
2891/**
2892 * @internal
2893 */
2894var animationControls = function () { return new AnimationControls(); };
2895
2896/**
2897 * @internal
2898 */
2899var MotionContext = React.createContext({
2900 static: false,
2901});
2902var isVariantLabel = function (v) {
2903 return typeof v === "string" || Array.isArray(v);
2904};
2905var isAnimationControls = function (v) {
2906 return v instanceof AnimationControls;
2907};
2908/**
2909 * Set up the context for children motion components.
2910 *
2911 * We also use this opportunity to apply `initial` values
2912 */
2913var useMotionContext = function (parentContext, controls, visualElement, isStatic, _a) {
2914 if (isStatic === void 0) { isStatic = false; }
2915 var initial = _a.initial, animate = _a.animate, variants = _a.variants, whileTap = _a.whileTap, whileHover = _a.whileHover, layoutId = _a.layoutId;
2916 // Determine whether this is a root element of an AnimatePresence component
2917 var presenceContext = React.useContext(PresenceContext);
2918 var presenceId = presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.id;
2919 visualElement.isPresenceRoot = parentContext.presenceId !== presenceId;
2920 // Override initial with that from a parent context, if defined
2921 if ((presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.initial) !== undefined) {
2922 initial = presenceContext.initial;
2923 }
2924 var initialState;
2925 if (initial === false && !isAnimationControls(animate)) {
2926 initialState = animate;
2927 }
2928 else if (typeof initial !== "boolean") {
2929 initialState = initial;
2930 }
2931 // Track mounted status so children can detect whether they were present during their
2932 // parent's first render
2933 var hasMounted = React.useRef(false);
2934 // We propagate this component's VisualElementAnimationControls *if* we're being provided variants,
2935 // if we're being used to control variants, or if we're being passed animation controls.
2936 // Otherwise this component should be "invisible" to variant propagation. This is a slight concession
2937 // to Framer X where every `Frame` is a `motion` component and it might be if we change that in the future
2938 // that this restriction is removed.
2939 var shouldPropagateControls = variants ||
2940 isVariantLabel(animate) ||
2941 isVariantLabel(whileTap) ||
2942 isVariantLabel(whileHover) ||
2943 isAnimationControls(animate);
2944 // If this component's `initial` prop is a variant label, propagate it. Otherwise pass the parent's.
2945 var targetInitial = isVariantLabel(initialState)
2946 ? initialState
2947 : parentContext.initial;
2948 // If this is a variant tree we need to propagate the `animate` prop in case new children are added after
2949 // the tree initially animates.
2950 var targetAnimate = isVariantLabel(animate)
2951 ? animate
2952 : parentContext.animate;
2953 // Only allow `initial` to trigger context re-renders if this is a `static` component (ie we're on the Framer canvas)
2954 // or in another non-animation/interaction environment.
2955 var initialDependency = isStatic ? targetInitial : null;
2956 // Only allow `animate` to trigger context re-renders if it's a variant label. If this is an array of
2957 // variant labels there's probably an optimisation to deep-compare but it might be an over-optimisation.
2958 // We want to do this as we rely on React's component rendering order each render cycle to determine
2959 // the new order of any child components for the `staggerChildren` functionality.
2960 var animateDependency = shouldPropagateControls && isVariantLabel(targetAnimate)
2961 ? targetAnimate
2962 : null;
2963 // The context to provide to the child. We `useMemo` because although `controls` and `initial` are
2964 // unlikely to change, by making the context an object it'll be considered a new value every render.
2965 // So all child motion components will re-render as a result.
2966 var context = React.useMemo(function () { return ({
2967 controls: shouldPropagateControls
2968 ? controls
2969 : parentContext.controls,
2970 initial: targetInitial,
2971 animate: targetAnimate,
2972 visualElement: visualElement,
2973 hasMounted: hasMounted,
2974 isReducedMotion: parentContext.isReducedMotion,
2975 presenceId: presenceId,
2976 }); }, [
2977 initialDependency,
2978 animateDependency,
2979 parentContext.isReducedMotion,
2980 animate,
2981 layoutId,
2982 presenceId,
2983 ]);
2984 // Update the `static` property every render. This is unlikely to change but also essentially free.
2985 context.static = isStatic;
2986 // Set initial state. If this is a static component (ie in Framer canvas), respond to updates
2987 // in `initial`.
2988 useInitialOrEveryRender(function () {
2989 var initialToApply = initialState || parentContext.initial;
2990 initialToApply && controls.apply(initialToApply);
2991 }, !isStatic);
2992 React.useEffect(function () {
2993 hasMounted.current = true;
2994 }, []);
2995 return context;
2996};
2997
2998var checkShouldInheritVariant = function (_a) {
2999 var animate = _a.animate, variants = _a.variants, _b = _a.inherit, inherit = _b === void 0 ? true : _b;
3000 return (inherit &&
3001 !!variants &&
3002 (!animate || animate instanceof AnimationControls));
3003};
3004
3005var isMotionValue = function (value) {
3006 return value instanceof MotionValue;
3007};
3008
3009/**
3010 * Scrape props for MotionValues and add/remove them to this component's
3011 * VisualElement
3012 */
3013function useMotionValues(visualElement, props) {
3014 var prev = useConstant(empty);
3015 /**
3016 * Remove MotionValues that are no longer present
3017 */
3018 for (var key in prev) {
3019 var isTransform = isTransformProp(key) || isTransformOriginProp(key);
3020 var existsAsProp = props[key];
3021 var existsAsStyle = props.style && props.style[key];
3022 var propIsMotionValue = existsAsProp && isMotionValue(props[key]);
3023 var styleIsMotionValue = existsAsStyle && isMotionValue(props.style[key]);
3024 var transformRemoved = isTransform && !existsAsProp && !existsAsStyle;
3025 var motionValueRemoved = !isTransform && !propIsMotionValue && !styleIsMotionValue;
3026 if (transformRemoved || motionValueRemoved) {
3027 visualElement.removeValue(key);
3028 delete prev[key];
3029 }
3030 }
3031 /**
3032 * Add incoming MotionValues
3033 */
3034 addMotionValues(visualElement, prev, props);
3035 if (props.style)
3036 addMotionValues(visualElement, prev, props.style, true);
3037 /**
3038 * Transform custom values if provided a handler, ie size -> width/height
3039 * Ideally we'd ditch this by removing support for size and other custom values from Framer.
3040 */
3041 if (props.transformValues) {
3042 visualElement.reactStyle = props.transformValues(visualElement.reactStyle);
3043 }
3044}
3045/**
3046 * Add incoming MotionValues
3047 *
3048 * TODO: Type the VisualElements properly
3049 */
3050function addMotionValues(visualElement, prev, source, isStyle) {
3051 if (isStyle === void 0) { isStyle = false; }
3052 if (isStyle)
3053 visualElement.reactStyle = {};
3054 for (var key in source) {
3055 var value = source[key];
3056 var foundMotionValue = false;
3057 if (isMotionValue(value)) {
3058 // If this is a MotionValue, add it if it isn't a reserved key
3059 if (!reservedNames.has(key)) {
3060 visualElement.addValue(key, value);
3061 foundMotionValue = true;
3062 }
3063 }
3064 else if (isTransformProp(key) || isTransformOriginProp(key)) {
3065 // If this is a transform prop, always create a MotionValue
3066 // to ensure we can reconcile them all together.
3067 if (!visualElement.hasValue(key)) {
3068 visualElement.addValue(key, motionValue(value));
3069 }
3070 else if (value !== prev[key]) {
3071 // If the MotionValue already exists, update it with the
3072 // latest incoming value
3073 var motion = visualElement.getValue(key);
3074 motion.set(value);
3075 }
3076 foundMotionValue = true;
3077 }
3078 else if (isStyle) {
3079 visualElement.reactStyle[key] = value;
3080 }
3081 if (foundMotionValue)
3082 prev[key] = value;
3083 }
3084}
3085/**
3086 * These are props we accept as MotionValues but don't want to add
3087 * to the VisualElement
3088 */
3089var reservedNames = new Set([]);
3090var empty = function () { return ({}); };
3091
3092var isCustomValue = function (v) {
3093 return Boolean(v && typeof v === "object" && v.mix && v.toValue);
3094};
3095var resolveFinalValueInKeyframes = function (v) {
3096 // TODO maybe throw if v.length - 1 is placeholder token?
3097 return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
3098};
3099
3100/**
3101 * Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
3102 */
3103var isNumericalString = function (v) { return /^\-?\d*\.?\d+$/.test(v); };
3104
3105/**
3106 * Get the current value of every `MotionValue` in a `VisualElement`
3107 */
3108var getCurrent = function (visualElement) {
3109 var current = {};
3110 visualElement.forEachValue(function (value, key) { return (current[key] = value.get()); });
3111 return current;
3112};
3113/**
3114 * Get the current velocity of every `MotionValue` in a `VisualElement`
3115 */
3116var getVelocity = function (visualElement) {
3117 var velocity = {};
3118 visualElement.forEachValue(function (value, key) { return (velocity[key] = value.getVelocity()); });
3119 return velocity;
3120};
3121/**
3122 * Check if value is a function that returns a `Target`. A generic typeof === 'function'
3123 * check, just helps with typing.
3124 */
3125var isTargetResolver = function (p) {
3126 return typeof p === "function";
3127};
3128/**
3129 * Check if value is a list of variant labels
3130 */
3131var isVariantLabels = function (v) { return Array.isArray(v); };
3132/**
3133 * Control animations for a single component
3134 *
3135 * @internal
3136 */
3137var VisualElementAnimationControls = /** @class */ (function () {
3138 function VisualElementAnimationControls(visualElement, _a) {
3139 var _this = this;
3140 var makeTargetAnimatable = _a.makeTargetAnimatable;
3141 /**
3142 * A reference to the component's latest props. We could probably ditch this in
3143 * favour to a reference to the `custom` prop now we don't send all props through
3144 * to target resolvers.
3145 */
3146 this.props = {};
3147 /**
3148 * The component's variants, as provided by `variants`
3149 */
3150 this.variants = {};
3151 /**
3152 * A set of values that we animate back to when a value is cleared of all overrides.
3153 */
3154 this.baseTarget = {};
3155 /**
3156 * A series of target overrides that we can animate to/from when overrides are set/cleared.
3157 */
3158 this.overrides = [];
3159 /**
3160 * A series of target overrides as they were originally resolved.
3161 */
3162 this.resolvedOverrides = [];
3163 /**
3164 * A Set of currently active override indexes
3165 */
3166 this.activeOverrides = new Set();
3167 /**
3168 * A Set of value keys that are currently animating.
3169 */
3170 this.isAnimating = new Set();
3171 /**
3172 * Check if the associated `VisualElement` has a key with the provided string.
3173 * Pre-bound to the class so we can provide directly to the `filter` in `checkForNewValues`.
3174 */
3175 this.hasValue = function (key) { return !_this.visualElement.hasValue(key); };
3176 this.visualElement = visualElement;
3177 this.makeTargetAnimatable = makeTargetAnimatable;
3178 this.visualElement.forEachValue(function (value, key) { return (_this.baseTarget[key] = value.get()); });
3179 }
3180 /**
3181 * Set the reference to the component's props.
3182 * @param props -
3183 */
3184 VisualElementAnimationControls.prototype.setProps = function (props) {
3185 this.props = props;
3186 };
3187 /**
3188 * Set the reference to the component's variants
3189 * @param variants -
3190 */
3191 VisualElementAnimationControls.prototype.setVariants = function (variants) {
3192 if (variants)
3193 this.variants = variants;
3194 };
3195 /**
3196 * Set the component's default transition
3197 * @param transition -
3198 */
3199 VisualElementAnimationControls.prototype.setDefaultTransition = function (transition) {
3200 if (transition)
3201 this.defaultTransition = transition;
3202 };
3203 /**
3204 * Set motion values without animation.
3205 *
3206 * @param definition -
3207 * @param isActive -
3208 */
3209 VisualElementAnimationControls.prototype.setValues = function (definition, _a) {
3210 var _b = _a === void 0 ? {} : _a, _c = _b.isActive, isActive = _c === void 0 ? new Set() : _c, priority = _b.priority;
3211 var _d = this.resolveVariant(definition), target = _d.target, transitionEnd = _d.transitionEnd;
3212 target = this.transformValues(tslib.__assign(tslib.__assign({}, target), transitionEnd));
3213 for (var key in target) {
3214 if (isActive.has(key))
3215 return;
3216 isActive.add(key);
3217 if (target) {
3218 var targetValue = resolveFinalValueInKeyframes(target[key]);
3219 if (this.visualElement.hasValue(key)) {
3220 var value = this.visualElement.getValue(key);
3221 value && value.set(targetValue);
3222 }
3223 else {
3224 this.visualElement.addValue(key, motionValue(targetValue));
3225 }
3226 if (!priority)
3227 this.baseTarget[key] = targetValue;
3228 }
3229 }
3230 };
3231 /**
3232 * Allows `transformValues` to be set by a component that allows us to
3233 * transform the values in a given `Target`. This allows Framer Library
3234 * to extend Framer Motion to animate `Color` variables etc. Currently we have
3235 * to manually support these extended types here in Framer Motion.
3236 *
3237 * @param values -
3238 */
3239 VisualElementAnimationControls.prototype.transformValues = function (values) {
3240 var transformValues = this.props.transformValues;
3241 return transformValues ? transformValues(values) : values;
3242 };
3243 /**
3244 * Check a `Target` for new values we haven't animated yet, and add them
3245 * to the `MotionValueMap`.
3246 *
3247 * Currently there's functionality here that is DOM-specific, we should allow
3248 * this functionality to be injected by the factory that creates DOM-specific
3249 * components.
3250 *
3251 * @param target -
3252 */
3253 VisualElementAnimationControls.prototype.checkForNewValues = function (target) {
3254 var newValueKeys = Object.keys(target).filter(this.hasValue);
3255 var numNewValues = newValueKeys.length;
3256 if (!numNewValues)
3257 return;
3258 for (var i = 0; i < numNewValues; i++) {
3259 var key = newValueKeys[i];
3260 var targetValue = target[key];
3261 var value = null;
3262 // If this is a keyframes value, we can attempt to use the first value in the
3263 // array as that's going to be the first value of the animation anyway
3264 if (Array.isArray(targetValue)) {
3265 value = targetValue[0];
3266 }
3267 // If it isn't a keyframes or the first keyframes value was set as `null`, read the
3268 // value from the DOM. It might be worth investigating whether to check props (for SVG)
3269 // or props.style (for HTML) if the value exists there before attempting to read.
3270 if (value === null) {
3271 var readValue = this.visualElement.readNativeValue(key);
3272 value = readValue !== undefined ? readValue : target[key];
3273 heyListen.invariant(value !== null, "No initial value for \"" + key + "\" can be inferred. Ensure an initial value for \"" + key + "\" is defined on the component.");
3274 }
3275 if (typeof value === "string" && isNumericalString(value)) {
3276 // If this is a number read as a string, ie "0" or "200", convert it to a number
3277 value = parseFloat(value);
3278 }
3279 else if (!findValueType(value) && styleValueTypes.complex.test(targetValue)) {
3280 // If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
3281 value = styleValueTypes.complex.getAnimatableNone(targetValue);
3282 }
3283 this.visualElement.addValue(key, motionValue(value));
3284 this.baseTarget[key] = value;
3285 }
3286 };
3287 /**
3288 * Resolve a variant from its label or resolver into an actual `Target` we can animate to.
3289 * @param variant -
3290 */
3291 VisualElementAnimationControls.prototype.resolveVariant = function (variant) {
3292 if (!variant) {
3293 return {
3294 target: undefined,
3295 transition: undefined,
3296 transitionEnd: undefined,
3297 };
3298 }
3299 if (isTargetResolver(variant)) {
3300 // resolve current and velocity
3301 variant = variant(this.props.custom, getCurrent(this.visualElement), getVelocity(this.visualElement));
3302 }
3303 var _a = variant.transition, transition = _a === void 0 ? this.defaultTransition : _a, transitionEnd = variant.transitionEnd, target = tslib.__rest(variant, ["transition", "transitionEnd"]);
3304 return { transition: transition, transitionEnd: transitionEnd, target: target };
3305 };
3306 /**
3307 * Get the highest active override priority index
3308 */
3309 VisualElementAnimationControls.prototype.getHighestPriority = function () {
3310 if (!this.activeOverrides.size)
3311 return 0;
3312 return Math.max.apply(Math, Array.from(this.activeOverrides));
3313 };
3314 /**
3315 * Set an override. We add this layer of indirection so if, for instance, a tap gesture
3316 * starts and overrides a hover gesture, when we clear the tap gesture and fallback to the
3317 * hover gesture, if that hover gesture has changed in the meantime we can go to that rather
3318 * than the one that was resolved when the hover gesture animation started.
3319 *
3320 * @param definition -
3321 * @param overrideIndex -
3322 */
3323 VisualElementAnimationControls.prototype.setOverride = function (definition, overrideIndex) {
3324 this.overrides[overrideIndex] = definition;
3325 if (this.children) {
3326 this.children.forEach(function (child) {
3327 return child.setOverride(definition, overrideIndex);
3328 });
3329 }
3330 };
3331 /**
3332 * Start an override animation.
3333 * @param overrideIndex -
3334 */
3335 VisualElementAnimationControls.prototype.startOverride = function (overrideIndex) {
3336 var override = this.overrides[overrideIndex];
3337 if (override) {
3338 return this.start(override, { priority: overrideIndex });
3339 }
3340 };
3341 /**
3342 * Clear an override. We check every value we animated to in this override to see if
3343 * its present on any lower-priority overrides. If not, we animate it back to its base target.
3344 * @param overrideIndex -
3345 */
3346 VisualElementAnimationControls.prototype.clearOverride = function (overrideIndex) {
3347 var _this = this;
3348 if (this.children) {
3349 this.children.forEach(function (child) { return child.clearOverride(overrideIndex); });
3350 }
3351 var override = this.overrides[overrideIndex];
3352 if (!override)
3353 return;
3354 this.activeOverrides.delete(overrideIndex);
3355 var highest = this.getHighestPriority();
3356 this.resetIsAnimating();
3357 if (highest) {
3358 var highestOverride = this.overrides[highest];
3359 highestOverride && this.startOverride(highest);
3360 }
3361 // Figure out which remaining values were affected by the override and animate those
3362 var overrideTarget = this.resolvedOverrides[overrideIndex];
3363 if (!overrideTarget)
3364 return;
3365 var remainingValues = {};
3366 for (var key in this.baseTarget) {
3367 if (overrideTarget[key] !== undefined) {
3368 remainingValues[key] = this.baseTarget[key];
3369 }
3370 }
3371 this.onStart();
3372 this.animate(remainingValues).then(function () { return _this.onComplete(); });
3373 };
3374 /**
3375 * Apply a target/variant without any animation
3376 */
3377 VisualElementAnimationControls.prototype.apply = function (definition) {
3378 if (Array.isArray(definition)) {
3379 return this.applyVariantLabels(definition);
3380 }
3381 else if (typeof definition === "string") {
3382 return this.applyVariantLabels([definition]);
3383 }
3384 else {
3385 this.setValues(definition);
3386 }
3387 };
3388 /**
3389 * Apply variant labels without animation
3390 */
3391 VisualElementAnimationControls.prototype.applyVariantLabels = function (variantLabelList) {
3392 var _this = this;
3393 var isActive = new Set();
3394 var reversedList = tslib.__spreadArrays(variantLabelList).reverse();
3395 reversedList.forEach(function (key) {
3396 var _a = _this.resolveVariant(_this.variants[key]), target = _a.target, transitionEnd = _a.transitionEnd;
3397 if (transitionEnd) {
3398 _this.setValues(transitionEnd, { isActive: isActive });
3399 }
3400 if (target) {
3401 _this.setValues(target, { isActive: isActive });
3402 }
3403 if (_this.children && _this.children.size) {
3404 _this.children.forEach(function (child) {
3405 return child.applyVariantLabels(variantLabelList);
3406 });
3407 }
3408 });
3409 };
3410 VisualElementAnimationControls.prototype.start = function (definition, opts) {
3411 var _this = this;
3412 if (opts === void 0) { opts = {}; }
3413 if (opts.priority) {
3414 this.activeOverrides.add(opts.priority);
3415 }
3416 this.resetIsAnimating(opts.priority);
3417 var animation;
3418 if (isVariantLabels(definition)) {
3419 animation = this.animateVariantLabels(definition, opts);
3420 }
3421 else if (typeof definition === "string") {
3422 animation = this.animateVariant(definition, opts);
3423 }
3424 else {
3425 animation = this.animate(definition, opts);
3426 }
3427 this.onStart();
3428 return animation.then(function () { return _this.onComplete(); });
3429 };
3430 VisualElementAnimationControls.prototype.animate = function (animationDefinition, _a) {
3431 var _this = this;
3432 var _b = _a === void 0 ? {} : _a, _c = _b.delay, delay = _c === void 0 ? 0 : _c, _d = _b.priority, priority = _d === void 0 ? 0 : _d, transitionOverride = _b.transitionOverride;
3433 var _e = this.resolveVariant(animationDefinition), target = _e.target, transition = _e.transition, transitionEnd = _e.transitionEnd;
3434 if (transitionOverride) {
3435 transition = transitionOverride;
3436 }
3437 if (!target)
3438 return Promise.resolve();
3439 target = this.transformValues(target);
3440 if (transitionEnd) {
3441 transitionEnd = this.transformValues(transitionEnd);
3442 }
3443 this.checkForNewValues(target);
3444 var origin = this.transformValues(getOrigin(target, transition, this.visualElement));
3445 if (this.makeTargetAnimatable) {
3446 var animatable = this.makeTargetAnimatable(this.visualElement, target, origin, transitionEnd);
3447 target = animatable.target;
3448 transitionEnd = animatable.transitionEnd;
3449 }
3450 if (priority) {
3451 this.resolvedOverrides[priority] = target;
3452 }
3453 this.checkForNewValues(target);
3454 var animations = [];
3455 for (var key in target) {
3456 var value = this.visualElement.getValue(key);
3457 if (!value || !target || target[key] === undefined)
3458 continue;
3459 var valueTarget = target[key];
3460 if (!priority) {
3461 this.baseTarget[key] = resolveFinalValueInKeyframes(valueTarget);
3462 }
3463 if (this.isAnimating.has(key))
3464 continue;
3465 this.isAnimating.add(key);
3466 animations.push(startAnimation(key, value, valueTarget, tslib.__assign({ delay: delay }, transition)));
3467 }
3468 var allAnimations = Promise.all(animations);
3469 return transitionEnd
3470 ? allAnimations.then(function () {
3471 _this.setValues(transitionEnd, { priority: priority });
3472 })
3473 : allAnimations;
3474 };
3475 VisualElementAnimationControls.prototype.animateVariantLabels = function (variantLabels, opts) {
3476 var _this = this;
3477 var animations = tslib.__spreadArrays(variantLabels).reverse()
3478 .map(function (label) { return _this.animateVariant(label, opts); });
3479 return Promise.all(animations);
3480 };
3481 VisualElementAnimationControls.prototype.animateVariant = function (variantLabel, opts) {
3482 var _this = this;
3483 var when = false;
3484 var delayChildren = 0;
3485 var staggerChildren = 0;
3486 var staggerDirection = 1;
3487 var priority = (opts && opts.priority) || 0;
3488 var variant = this.variants[variantLabel];
3489 var getAnimations = variant
3490 ? function () { return _this.animate(variant, opts); }
3491 : function () { return Promise.resolve(); };
3492 var getChildrenAnimations = this.children
3493 ? function () {
3494 return _this.animateChildren(variantLabel, delayChildren, staggerChildren, staggerDirection, priority);
3495 }
3496 : function () { return Promise.resolve(); };
3497 if (variant && this.children) {
3498 var transition = this.resolveVariant(variant).transition;
3499 if (transition) {
3500 when = transition.when || when;
3501 delayChildren = transition.delayChildren || delayChildren;
3502 staggerChildren = transition.staggerChildren || staggerChildren;
3503 staggerDirection =
3504 transition.staggerDirection || staggerDirection;
3505 }
3506 }
3507 if (when) {
3508 var _a = when === "beforeChildren"
3509 ? [getAnimations, getChildrenAnimations]
3510 : [getChildrenAnimations, getAnimations], first = _a[0], last = _a[1];
3511 return first().then(last);
3512 }
3513 else {
3514 return Promise.all([getAnimations(), getChildrenAnimations()]);
3515 }
3516 };
3517 VisualElementAnimationControls.prototype.animateChildren = function (variantLabel, delayChildren, staggerChildren, staggerDirection, priority) {
3518 if (delayChildren === void 0) { delayChildren = 0; }
3519 if (staggerChildren === void 0) { staggerChildren = 0; }
3520 if (staggerDirection === void 0) { staggerDirection = 1; }
3521 if (priority === void 0) { priority = 0; }
3522 if (!this.children) {
3523 return Promise.resolve();
3524 }
3525 var animations = [];
3526 var maxStaggerDuration = (this.children.size - 1) * staggerChildren;
3527 var generateStaggerDuration = staggerDirection === 1
3528 ? function (i) { return i * staggerChildren; }
3529 : function (i) { return maxStaggerDuration - i * staggerChildren; };
3530 Array.from(this.children).forEach(function (childControls, i) {
3531 var animation = childControls.animateVariant(variantLabel, {
3532 priority: priority,
3533 delay: delayChildren + generateStaggerDuration(i),
3534 });
3535 animations.push(animation);
3536 });
3537 return Promise.all(animations);
3538 };
3539 VisualElementAnimationControls.prototype.onStart = function () {
3540 var onAnimationStart = this.props.onAnimationStart;
3541 onAnimationStart && onAnimationStart();
3542 };
3543 VisualElementAnimationControls.prototype.onComplete = function () {
3544 var onAnimationComplete = this.props.onAnimationComplete;
3545 onAnimationComplete && onAnimationComplete();
3546 };
3547 VisualElementAnimationControls.prototype.checkOverrideIsAnimating = function (priority) {
3548 var numOverrides = this.overrides.length;
3549 for (var i = priority + 1; i < numOverrides; i++) {
3550 var resolvedOverride = this.resolvedOverrides[i];
3551 if (resolvedOverride) {
3552 for (var key in resolvedOverride) {
3553 this.isAnimating.add(key);
3554 }
3555 }
3556 }
3557 };
3558 VisualElementAnimationControls.prototype.resetIsAnimating = function (priority) {
3559 if (priority === void 0) { priority = 0; }
3560 this.isAnimating.clear();
3561 // If this isn't the highest priority gesture, block the animation
3562 // of anything that's currently being animated
3563 if (priority < this.getHighestPriority()) {
3564 this.checkOverrideIsAnimating(priority);
3565 }
3566 if (this.children) {
3567 this.children.forEach(function (child) { return child.resetIsAnimating(priority); });
3568 }
3569 };
3570 VisualElementAnimationControls.prototype.stop = function () {
3571 this.visualElement.forEachValue(function (value) { return value.stop(); });
3572 };
3573 /**
3574 * Add the controls of a child component.
3575 * @param controls -
3576 */
3577 VisualElementAnimationControls.prototype.addChild = function (controls) {
3578 if (!this.children) {
3579 this.children = new Set();
3580 }
3581 this.children.add(controls);
3582 // We set child overrides when `setOverride` is called, but also have to do it here
3583 // as the first time `setOverride` is called all the children might not have been added yet.
3584 this.overrides.forEach(function (override, i) {
3585 override && controls.setOverride(override, i);
3586 });
3587 };
3588 VisualElementAnimationControls.prototype.removeChild = function (controls) {
3589 if (!this.children) {
3590 return;
3591 }
3592 this.children.delete(controls);
3593 };
3594 VisualElementAnimationControls.prototype.resetChildren = function () {
3595 if (this.children)
3596 this.children.clear();
3597 };
3598 return VisualElementAnimationControls;
3599}());
3600function getOriginFromTransition(key, transition) {
3601 if (!transition)
3602 return;
3603 var valueTransition = transition[key] || transition["default"] || transition;
3604 return valueTransition.from;
3605}
3606function getOrigin(target, transition, visualElement) {
3607 var _a, _b;
3608 var origin = {};
3609 for (var key in target) {
3610 origin[key] = (_a = getOriginFromTransition(key, transition)) !== null && _a !== void 0 ? _a : (_b = visualElement.getValue(key)) === null || _b === void 0 ? void 0 : _b.get();
3611 }
3612 return origin;
3613}
3614
3615/**
3616 * Creates an imperative set of controls to trigger animations.
3617 *
3618 * This allows a consolidated, uniform API for animations, to be triggered by other APIs like the `animate` prop, or the gesture handlers.
3619 *
3620 * @internal
3621 */
3622function useVisualElementAnimation(visualElement, props, config) {
3623 var subscribeToParentControls = checkShouldInheritVariant(props);
3624 var variants = props.variants, transition = props.transition;
3625 var parentControls = React.useContext(MotionContext).controls;
3626 var presenceContext = React.useContext(PresenceContext);
3627 var controls = useConstant(function () { return new VisualElementAnimationControls(visualElement, config); });
3628 // Reset and resubscribe children every render to ensure stagger order is correct
3629 if (!presenceContext || presenceContext.isPresent) {
3630 controls.resetChildren();
3631 controls.setProps(props);
3632 controls.setVariants(variants);
3633 controls.setDefaultTransition(transition);
3634 }
3635 // We have to subscribe to the parent controls within a useEffect rather than during render,
3636 // as
3637 React.useEffect(function () {
3638 if (subscribeToParentControls && parentControls) {
3639 parentControls.addChild(controls);
3640 }
3641 });
3642 React.useEffect(function () {
3643 return function () {
3644 // Remove reference to onAnimationComplete from controls. All the MotionValues
3645 // are unsubscribed from this component separately. We let animations run out
3646 // as they might be animating other components.
3647 var onAnimationComplete = props.onAnimationComplete, unmountProps = tslib.__rest(props, ["onAnimationComplete"]);
3648 controls.setProps(unmountProps);
3649 parentControls && parentControls.removeChild(controls);
3650 };
3651 }, []);
3652 return controls;
3653}
3654
3655/**
3656 * @public
3657 */
3658var MotionConfigContext = React.createContext({
3659 transformPagePoint: function (p) { return p; },
3660 features: [],
3661});
3662/**
3663 * MotionConfig can be used in combination with the `m` component to cut bundle size
3664 * and dynamically load only the features you use.
3665 *
3666 * ```jsx
3667 * import {
3668 * m as motion,
3669 * AnimationFeature,
3670 * MotionConfig
3671 * } from "framer-motion"
3672 *
3673 * export function App() {
3674 * return (
3675 * <MotionConfig features={[AnimationFeature]}>
3676 * <motion.div animate={{ x: 100 }} />
3677 * </MotionConfig>
3678 * )
3679 * }
3680 * ```
3681 *
3682 * @public
3683 */
3684function MotionConfig(_a) {
3685 var children = _a.children, _b = _a.features, features = _b === void 0 ? [] : _b, props = tslib.__rest(_a, ["children", "features"]);
3686 var pluginContext = React.useContext(MotionConfigContext);
3687 var loadedFeatures = tslib.__spreadArrays(pluginContext.features, features);
3688 // We do want to rerender children when the number of loaded features changes
3689 var value = React.useMemo(function () { return ({ features: loadedFeatures }); }, [
3690 loadedFeatures.length,
3691 ]);
3692 // Mutative to prevent triggering rerenders in all listening
3693 // components every time this component renders
3694 for (var key in props) {
3695 value[key] = props[key];
3696 }
3697 return (React.createElement(MotionConfigContext.Provider, { value: value }, children));
3698}
3699
3700/**
3701 * Load features via renderless components based on the provided MotionProps
3702 */
3703function useFeatures(defaultFeatures, isStatic, visualElement, controls, props, context, parentContext, shouldInheritVariant) {
3704 var plugins = React.useContext(MotionConfigContext);
3705 // If this is a static component, or we're rendering on the server, we don't load
3706 // any feature components
3707 if (isStatic || typeof window === "undefined")
3708 return null;
3709 var allFeatures = tslib.__spreadArrays(defaultFeatures, plugins.features);
3710 var numFeatures = allFeatures.length;
3711 var features = [];
3712 // Decide which features we should render and add them to the returned array
3713 for (var i = 0; i < numFeatures; i++) {
3714 var _a = allFeatures[i], shouldRender = _a.shouldRender, key = _a.key, getComponent = _a.getComponent;
3715 if (shouldRender(props, parentContext)) {
3716 var Component = getComponent(props);
3717 Component &&
3718 features.push(React.createElement(Component, tslib.__assign({ key: key }, props, { localContext: context, parentContext: parentContext, visualElement: visualElement, controls: controls, inherit: shouldInheritVariant })));
3719 }
3720 }
3721 return features;
3722}
3723
3724var Presence;
3725(function (Presence) {
3726 Presence[Presence["Entering"] = 0] = "Entering";
3727 Presence[Presence["Present"] = 1] = "Present";
3728 Presence[Presence["Exiting"] = 2] = "Exiting";
3729})(Presence || (Presence = {}));
3730var VisibilityAction;
3731(function (VisibilityAction) {
3732 VisibilityAction[VisibilityAction["Hide"] = 0] = "Hide";
3733 VisibilityAction[VisibilityAction["Show"] = 1] = "Show";
3734})(VisibilityAction || (VisibilityAction = {}));
3735
3736/**
3737 * Default handlers for batching VisualElements
3738 */
3739var defaultHandler = {
3740 measureLayout: function (child) { return child.measureLayout(); },
3741 layoutReady: function (child) { return child.layoutReady(); },
3742};
3743/**
3744 * Sort VisualElements by tree depth, so we process the highest elements first.
3745 */
3746var sortByDepth = function (a, b) {
3747 return a.depth - b.depth;
3748};
3749/**
3750 * Create a batcher to process VisualElements
3751 */
3752function createBatcher() {
3753 var queue = new Set();
3754 var add = function (child) { return queue.add(child); };
3755 var flush = function (_a) {
3756 var _b = _a === void 0 ? defaultHandler : _a, measureLayout = _b.measureLayout, layoutReady = _b.layoutReady;
3757 var order = Array.from(queue).sort(sortByDepth);
3758 /**
3759 * Write: Reset any transforms on children elements so we can read their actual layout
3760 */
3761 order.forEach(function (child) { return child.resetTransform(); });
3762 /**
3763 * Read: Measure the actual layout
3764 */
3765 order.forEach(measureLayout);
3766 /**
3767 * Write: Notify the VisualElements they're ready for further write operations.
3768 */
3769 order.forEach(layoutReady);
3770 /**
3771 * After all children have started animating, ensure any Entering components are set to Present.
3772 * If we add deferred animations (set up all animations and then start them in two loops) this
3773 * could be moved to the start loop. But it needs to happen after all the animations configs
3774 * are generated in AnimateSharedLayout as this relies on presence data
3775 */
3776 order.forEach(function (child) {
3777 if (child.isPresent)
3778 child.presence = Presence.Present;
3779 });
3780 queue.clear();
3781 };
3782 return { add: add, flush: flush };
3783}
3784function isSharedLayout(context) {
3785 return !!context.forceUpdate;
3786}
3787var SharedLayoutContext = React.createContext(createBatcher());
3788
3789function useUnmountEffect(callback) {
3790 return React.useEffect(function () { return function () { return callback(); }; }, []);
3791}
3792
3793function useSnapshotOnUnmount(visualElement) {
3794 var syncLayout = React.useContext(SharedLayoutContext);
3795 useUnmountEffect(function () {
3796 if (isSharedLayout(syncLayout))
3797 syncLayout.remove(visualElement);
3798 });
3799}
3800
3801/**
3802 * Create a `motion` component.
3803 *
3804 * This function accepts a Component argument, which can be either a string (ie "div"
3805 * for `motion.div`), or an actual React component.
3806 *
3807 * Alongside this is a config option which provides a way of rendering the provided
3808 * component "offline", or outside the React render cycle.
3809 *
3810 * @internal
3811 */
3812function createMotionComponent(Component, _a) {
3813 var defaultFeatures = _a.defaultFeatures, useVisualElement = _a.useVisualElement, render = _a.render, animationControlsConfig = _a.animationControlsConfig;
3814 function MotionComponent(props, externalRef) {
3815 var parentContext = React.useContext(MotionContext);
3816 var shouldInheritVariant = checkShouldInheritVariant(props);
3817 /**
3818 * If a component isStatic, we only visually update it as a
3819 * result of a React re-render, rather than any interactions or animations.
3820 * If this component or any ancestor isStatic, we disable hardware acceleration
3821 * and don't load any additional functionality.
3822 */
3823 var isStatic = parentContext.static || props.static || false;
3824 /**
3825 * Create a VisualElement for this component. A VisualElement provides a common
3826 * interface to renderer-specific APIs (ie DOM/Three.js etc) as well as
3827 * providing a way of rendering to these APIs outside of the React render loop
3828 * for more performant animations and interactions
3829 */
3830 var visualElement = useVisualElement(Component, props, parentContext.visualElement, isStatic, externalRef);
3831 /**
3832 * Scrape MotionValues from props and add/remove them to/from
3833 * the VisualElement as necessary.
3834 */
3835 useMotionValues(visualElement, props);
3836 /**
3837 * Create animation controls for the VisualElement. It might be
3838 * interesting to try and combine this with VisualElement itself in a further refactor.
3839 */
3840 var controls = useVisualElementAnimation(visualElement, props, animationControlsConfig);
3841 /**
3842 * Build the MotionContext to pass on to the next `motion` component.
3843 */
3844 var context = useMotionContext(parentContext, controls, visualElement, isStatic, props);
3845 /**
3846 * Load features as renderless components unless the component isStatic
3847 */
3848 var features = useFeatures(defaultFeatures, isStatic, visualElement, controls, props, context, parentContext, shouldInheritVariant);
3849 var component = render(Component, props, visualElement);
3850 /**
3851 *
3852 */
3853 useSnapshotOnUnmount(visualElement);
3854 // The mount order and hierarchy is specific to ensure our element ref is hydrated by the time
3855 // all plugins and features has to execute.
3856 return (React.createElement(React.Fragment, null,
3857 React.createElement(MotionContext.Provider, { value: context }, component),
3858 features));
3859 }
3860 return React.forwardRef(MotionComponent);
3861}
3862
3863function createLock(name) {
3864 var lock = null;
3865 return function () {
3866 var openLock = function () {
3867 lock = null;
3868 };
3869 if (lock === null) {
3870 lock = name;
3871 return openLock;
3872 }
3873 return false;
3874 };
3875}
3876var globalHorizontalLock = createLock("dragHorizontal");
3877var globalVerticalLock = createLock("dragVertical");
3878function getGlobalLock(drag) {
3879 var lock = false;
3880 if (drag === "y") {
3881 lock = globalVerticalLock();
3882 }
3883 else if (drag === "x") {
3884 lock = globalHorizontalLock();
3885 }
3886 else {
3887 var openHorizontal_1 = globalHorizontalLock();
3888 var openVertical_1 = globalVerticalLock();
3889 if (openHorizontal_1 && openVertical_1) {
3890 lock = function () {
3891 openHorizontal_1();
3892 openVertical_1();
3893 };
3894 }
3895 else {
3896 // Release the locks because we don't use them
3897 if (openHorizontal_1)
3898 openHorizontal_1();
3899 if (openVertical_1)
3900 openVertical_1();
3901 }
3902 }
3903 return lock;
3904}
3905
3906var isViewportScrollBlocked = false;
3907var isBrowser = typeof window !== "undefined";
3908if (isBrowser) {
3909 document.addEventListener("touchmove", function (event) {
3910 if (isViewportScrollBlocked) {
3911 event.preventDefault();
3912 }
3913 }, { passive: false });
3914}
3915var blockViewportScroll = function () { return (isViewportScrollBlocked = true); };
3916var unblockViewportScroll = function () { return (isViewportScrollBlocked = false); };
3917
3918function addDomEvent(target, eventName, handler, options) {
3919 if (!handler)
3920 return;
3921 target.addEventListener(eventName, handler, options);
3922 return function () { return target.removeEventListener(eventName, handler, options); };
3923}
3924/**
3925 * Attaches an event listener directly to the provided DOM element.
3926 *
3927 * Bypassing React's event system can be desirable, for instance when attaching non-passive
3928 * event handlers.
3929 *
3930 * ```jsx
3931 * const ref = useRef(null)
3932 *
3933 * useDomEvent(ref, 'wheel', onWheel, { passive: false })
3934 *
3935 * return <div ref={ref} />
3936 * ```
3937 *
3938 * @param ref - React.RefObject that's been provided to the element you want to bind the listener to.
3939 * @param eventName - Name of the event you want listen for.
3940 * @param handler - Function to fire when receiving the event.
3941 * @param options - Options to pass to `Event.addEventListener`.
3942 *
3943 * @public
3944 */
3945function useDomEvent(ref, eventName, handler, options) {
3946 React.useEffect(function () {
3947 var element = ref.current;
3948 if (handler && element) {
3949 return addDomEvent(element, eventName, handler, options);
3950 }
3951 }, [ref, eventName, handler, options]);
3952}
3953
3954function isMouseEvent(event) {
3955 // PointerEvent inherits from MouseEvent so we can't use a straight instanceof check.
3956 if (typeof PointerEvent !== "undefined" && event instanceof PointerEvent) {
3957 return !!(event.pointerType === "mouse");
3958 }
3959 return event instanceof MouseEvent;
3960}
3961function isTouchEvent(event) {
3962 var hasTouches = !!event.touches;
3963 return hasTouches;
3964}
3965
3966/**
3967 * Filters out events not attached to the primary pointer (currently left mouse button)
3968 * @param eventHandler
3969 */
3970function filterPrimaryPointer(eventHandler) {
3971 if (!eventHandler)
3972 return undefined;
3973 return function (event) {
3974 var isMouseEvent = event instanceof MouseEvent;
3975 var isPrimaryPointer = !isMouseEvent ||
3976 (isMouseEvent && event.button === 0);
3977 if (isPrimaryPointer) {
3978 eventHandler(event);
3979 }
3980 };
3981}
3982var defaultPagePoint = { pageX: 0, pageY: 0 };
3983function pointFromTouch(e, pointType) {
3984 if (pointType === void 0) { pointType = "page"; }
3985 var primaryTouch = e.touches[0] || e.changedTouches[0];
3986 var point = primaryTouch || defaultPagePoint;
3987 return {
3988 x: point[pointType + "X"],
3989 y: point[pointType + "Y"],
3990 };
3991}
3992function pointFromMouse(point, pointType) {
3993 if (pointType === void 0) { pointType = "page"; }
3994 return {
3995 x: point[pointType + "X"],
3996 y: point[pointType + "Y"],
3997 };
3998}
3999function extractEventInfo(event, pointType) {
4000 if (pointType === void 0) { pointType = "page"; }
4001 return {
4002 point: isTouchEvent(event)
4003 ? pointFromTouch(event, pointType)
4004 : pointFromMouse(event, pointType),
4005 };
4006}
4007function getViewportPointFromEvent(event) {
4008 return extractEventInfo(event, "client");
4009}
4010var wrapHandler = function (handler, shouldFilterPrimaryPointer) {
4011 if (shouldFilterPrimaryPointer === void 0) { shouldFilterPrimaryPointer = false; }
4012 if (!handler)
4013 return;
4014 var listener = function (event) { return handler(event, extractEventInfo(event)); };
4015 return shouldFilterPrimaryPointer
4016 ? filterPrimaryPointer(listener)
4017 : listener;
4018};
4019
4020var isBrowser$1 = typeof window !== "undefined";
4021// We check for event support via functions in case they've been mocked by a testing suite.
4022var supportsPointerEvents = function () {
4023 return isBrowser$1 && window.onpointerdown === null;
4024};
4025var supportsTouchEvents = function () {
4026 return isBrowser$1 && window.ontouchstart === null;
4027};
4028var supportsMouseEvents = function () {
4029 return isBrowser$1 && window.onmousedown === null;
4030};
4031
4032var mouseEventNames = {
4033 pointerdown: "mousedown",
4034 pointermove: "mousemove",
4035 pointerup: "mouseup",
4036 pointercancel: "mousecancel",
4037 pointerover: "mouseover",
4038 pointerout: "mouseout",
4039 pointerenter: "mouseenter",
4040 pointerleave: "mouseleave",
4041};
4042var touchEventNames = {
4043 pointerdown: "touchstart",
4044 pointermove: "touchmove",
4045 pointerup: "touchend",
4046 pointercancel: "touchcancel",
4047};
4048function getPointerEventName(name) {
4049 if (supportsPointerEvents()) {
4050 return name;
4051 }
4052 else if (supportsTouchEvents()) {
4053 return touchEventNames[name];
4054 }
4055 else if (supportsMouseEvents()) {
4056 return mouseEventNames[name];
4057 }
4058 return name;
4059}
4060function addPointerEvent(target, eventName, handler, options) {
4061 return addDomEvent(target, getPointerEventName(eventName), wrapHandler(handler, eventName === "pointerdown"), options);
4062}
4063function usePointerEvent(ref, eventName, handler, options) {
4064 return useDomEvent(ref, getPointerEventName(eventName), wrapHandler(handler, eventName === "pointerdown"), options);
4065}
4066
4067/** @public */
4068var Point;
4069(function (Point) {
4070 /** @beta */
4071 Point.subtract = function (a, b) {
4072 return { x: a.x - b.x, y: a.y - b.y };
4073 };
4074 /** @beta */
4075 Point.relativeTo = function (idOrElem) {
4076 var elem;
4077 var getElem = function () {
4078 // Caching element here could be leaky because of React lifecycle
4079 if (elem !== undefined)
4080 return elem;
4081 if (typeof idOrElem === "string") {
4082 elem = document.getElementById(idOrElem);
4083 }
4084 else {
4085 elem = idOrElem;
4086 }
4087 return elem;
4088 };
4089 return function (_a) {
4090 var x = _a.x, y = _a.y;
4091 var localElem = getElem();
4092 if (!localElem)
4093 return undefined;
4094 var rect = localElem.getBoundingClientRect();
4095 return {
4096 x: x - rect.left - window.scrollX,
4097 y: y - rect.top - window.scrollY,
4098 };
4099 };
4100 };
4101})(Point || (Point = {}));
4102
4103/**
4104 * @internal
4105 */
4106var PanSession = /** @class */ (function () {
4107 function PanSession(event, handlers, _a) {
4108 var _this = this;
4109 var transformPagePoint = (_a === void 0 ? {} : _a).transformPagePoint;
4110 /**
4111 * @internal
4112 */
4113 this.startEvent = null;
4114 /**
4115 * @internal
4116 */
4117 this.lastMoveEvent = null;
4118 /**
4119 * @internal
4120 */
4121 this.lastMoveEventInfo = null;
4122 /**
4123 * @internal
4124 */
4125 this.handlers = {};
4126 this.updatePoint = function () {
4127 if (!(_this.lastMoveEvent && _this.lastMoveEventInfo))
4128 return;
4129 var info = getPanInfo(_this.lastMoveEventInfo, _this.history);
4130 var isPanStarted = _this.startEvent !== null;
4131 // Only start panning if the offset is larger than 3 pixels. If we make it
4132 // any larger than this we'll want to reset the pointer history
4133 // on the first update to avoid visual snapping to the cursoe.
4134 var isDistancePastThreshold = popcorn.distance(info.offset, { x: 0, y: 0 }) >= 3;
4135 if (!isPanStarted && !isDistancePastThreshold)
4136 return;
4137 var point = info.point;
4138 var timestamp = sync.getFrameData().timestamp;
4139 _this.history.push(tslib.__assign(tslib.__assign({}, point), { timestamp: timestamp }));
4140 var _a = _this.handlers, onStart = _a.onStart, onMove = _a.onMove;
4141 if (!isPanStarted) {
4142 onStart && onStart(_this.lastMoveEvent, info);
4143 _this.startEvent = _this.lastMoveEvent;
4144 }
4145 onMove && onMove(_this.lastMoveEvent, info);
4146 };
4147 // If we have more than one touch, don't start detecting this gesture
4148 if (isTouchEvent(event) && event.touches.length > 1)
4149 return;
4150 this.handlers = handlers;
4151 this.transformPagePoint = transformPagePoint;
4152 var info = extractEventInfo(event);
4153 var initialInfo = transformPoint(info, this.transformPagePoint);
4154 var point = initialInfo.point;
4155 var timestamp = sync.getFrameData().timestamp;
4156 this.history = [tslib.__assign(tslib.__assign({}, point), { timestamp: timestamp })];
4157 var onSessionStart = handlers.onSessionStart;
4158 onSessionStart &&
4159 onSessionStart(event, getPanInfo(initialInfo, this.history));
4160 var removeOnPointerMove = addPointerEvent(window, "pointermove", function (event, info) { return _this.handlePointerMove(event, info); });
4161 var removeOnPointerUp = addPointerEvent(window, "pointerup", function (event, info) { return _this.handlePointerUp(event, info); });
4162 this.removeListeners = function () {
4163 removeOnPointerMove && removeOnPointerMove();
4164 removeOnPointerUp && removeOnPointerUp();
4165 };
4166 }
4167 PanSession.prototype.handlePointerMove = function (event, info) {
4168 this.lastMoveEvent = event;
4169 this.lastMoveEventInfo = transformPoint(info, this.transformPagePoint);
4170 // Because Safari doesn't trigger mouseup events when it's above a `<select>`
4171 if (isMouseEvent(event) && event.buttons === 0) {
4172 this.handlePointerUp(event, info);
4173 return;
4174 }
4175 // Throttle mouse move event to once per frame
4176 sync__default.update(this.updatePoint, true);
4177 };
4178 PanSession.prototype.handlePointerUp = function (event, info) {
4179 this.end();
4180 var onEnd = this.handlers.onEnd;
4181 if (!onEnd)
4182 return;
4183 var panInfo = getPanInfo(transformPoint(info, this.transformPagePoint), this.history);
4184 onEnd && onEnd(event, panInfo);
4185 };
4186 PanSession.prototype.updateHandlers = function (handlers) {
4187 this.handlers = handlers;
4188 };
4189 PanSession.prototype.end = function () {
4190 this.removeListeners && this.removeListeners();
4191 sync.cancelSync.update(this.updatePoint);
4192 unblockViewportScroll();
4193 };
4194 return PanSession;
4195}());
4196function transformPoint(info, transformPagePoint) {
4197 return transformPagePoint ? { point: transformPagePoint(info.point) } : info;
4198}
4199function getPanInfo(_a, history) {
4200 var point = _a.point;
4201 return {
4202 point: point,
4203 delta: Point.subtract(point, lastDevicePoint(history)),
4204 offset: Point.subtract(point, startDevicePoint(history)),
4205 velocity: getVelocity$1(history, 0.1),
4206 };
4207}
4208function startDevicePoint(history) {
4209 return history[0];
4210}
4211function lastDevicePoint(history) {
4212 return history[history.length - 1];
4213}
4214function getVelocity$1(history, timeDelta) {
4215 if (history.length < 2) {
4216 return { x: 0, y: 0 };
4217 }
4218 var i = history.length - 1;
4219 var timestampedPoint = null;
4220 var lastPoint = lastDevicePoint(history);
4221 while (i >= 0) {
4222 timestampedPoint = history[i];
4223 if (lastPoint.timestamp - timestampedPoint.timestamp >
4224 secondsToMilliseconds(timeDelta)) {
4225 break;
4226 }
4227 i--;
4228 }
4229 if (!timestampedPoint) {
4230 return { x: 0, y: 0 };
4231 }
4232 var time = (lastPoint.timestamp - timestampedPoint.timestamp) / 1000;
4233 if (time === 0) {
4234 return { x: 0, y: 0 };
4235 }
4236 var currentVelocity = {
4237 x: (lastPoint.x - timestampedPoint.x) / time,
4238 y: (lastPoint.y - timestampedPoint.y) / time,
4239 };
4240 if (currentVelocity.x === Infinity) {
4241 currentVelocity.x = 0;
4242 }
4243 if (currentVelocity.y === Infinity) {
4244 currentVelocity.y = 0;
4245 }
4246 return currentVelocity;
4247}
4248
4249/**
4250 * Apply constraints to a point. These constraints are both physical along an
4251 * axis, and an elastic factor that determines how much to constrain the point
4252 * by if it does lie outside the defined parameters.
4253 */
4254function applyConstraints(point, _a, elastic) {
4255 var min = _a.min, max = _a.max;
4256 if (min !== undefined && point < min) {
4257 // If we have a min point defined, and this is outside of that, constrain
4258 point = elastic ? popcorn.mix(min, point, elastic) : Math.max(point, min);
4259 }
4260 else if (max !== undefined && point > max) {
4261 // If we have a max point defined, and this is outside of that, constrain
4262 point = elastic ? popcorn.mix(max, point, elastic) : Math.min(point, max);
4263 }
4264 return point;
4265}
4266/**
4267 * Calculates a min projection point based on a pointer, pointer progress
4268 * within the drag target, and constraints.
4269 *
4270 * For instance if an element was 100px width, we were dragging from 0.25
4271 * along this axis, the pointer is at 200px, and there were no constraints,
4272 * we would calculate a min projection point of 175px.
4273 */
4274function calcConstrainedMinPoint(point, length, progress, constraints, elastic) {
4275 // Calculate a min point for this axis and apply it to the current pointer
4276 var min = point - length * progress;
4277 return constraints ? applyConstraints(min, constraints, elastic) : min;
4278}
4279/**
4280 * Calculate constraints in terms of the viewport when
4281 * defined relatively to the measured axis.
4282 */
4283function calcRelativeAxisConstraints(axis, min, max) {
4284 var constraints = {};
4285 var length = axis.max - axis.min;
4286 if (min !== undefined) {
4287 constraints.min = axis.min + min;
4288 }
4289 if (max !== undefined) {
4290 constraints.max = Math.max(axis.min + max - length, axis.min);
4291 }
4292 return constraints;
4293}
4294/**
4295 * Calculate constraints in terms of the viewport when
4296 * defined relatively to the measured bounding box.
4297 */
4298function calcRelativeConstraints(layoutBox, _a) {
4299 var top = _a.top, left = _a.left, bottom = _a.bottom, right = _a.right;
4300 return {
4301 x: calcRelativeAxisConstraints(layoutBox.x, left, right),
4302 y: calcRelativeAxisConstraints(layoutBox.y, top, bottom),
4303 };
4304}
4305/**
4306 * Calculate viewport constraints when defined as another viewport-relative axis
4307 */
4308function calcViewportAxisConstraints(layoutAxis, constraintsAxis) {
4309 var _a;
4310 var min = constraintsAxis.min - layoutAxis.min;
4311 var max = constraintsAxis.max - layoutAxis.max;
4312 // If the constraints axis is actually smaller than the layout axis then we can
4313 // flip the constraints
4314 if (constraintsAxis.max - constraintsAxis.min <
4315 layoutAxis.max - layoutAxis.min) {
4316 _a = [max, min], min = _a[0], max = _a[1];
4317 }
4318 return {
4319 min: layoutAxis.min + min,
4320 max: layoutAxis.min + max,
4321 };
4322}
4323/**
4324 * Calculate viewport constraints when defined as another viewport-relative box
4325 */
4326function calcViewportConstraints(layoutBox, constraintsBox) {
4327 return {
4328 x: calcViewportAxisConstraints(layoutBox.x, constraintsBox.x),
4329 y: calcViewportAxisConstraints(layoutBox.y, constraintsBox.y),
4330 };
4331}
4332/**
4333 * Calculate the an axis position based on two axes and a progress value.
4334 */
4335function calcPositionFromProgress(axis, constraints, progress) {
4336 var axisLength = axis.max - axis.min;
4337 var min = popcorn.mix(constraints.min, constraints.max - axisLength, progress);
4338 return { min: min, max: min + axisLength };
4339}
4340
4341var elementDragControls = new WeakMap();
4342/**
4343 *
4344 */
4345var lastPointerEvent;
4346var VisualElementDragControls = /** @class */ (function () {
4347 function VisualElementDragControls(_a) {
4348 var visualElement = _a.visualElement;
4349 /**
4350 * Track whether we're currently dragging.
4351 *
4352 * @internal
4353 */
4354 this.isDragging = false;
4355 /**
4356 * The current direction of drag, or `null` if both.
4357 *
4358 * @internal
4359 */
4360 this.currentDirection = null;
4361 /**
4362 * The permitted boundaries of travel, in pixels.
4363 *
4364 * @internal
4365 */
4366 this.constraints = false;
4367 /**
4368 * A reference to the host component's latest props.
4369 *
4370 * @internal
4371 */
4372 this.props = {};
4373 /**
4374 * Track the initial position of the cursor relative to the dragging element
4375 * when dragging starts as a value of 0-1 on each axis. We then use this to calculate
4376 * an ideal bounding box for the VisualElement renderer to project into every frame.
4377 *
4378 * @internal
4379 */
4380 this.cursorProgress = {
4381 x: 0.5,
4382 y: 0.5,
4383 };
4384 // This is a reference to the global drag gesture lock, ensuring only one component
4385 // can "capture" the drag of one or both axes.
4386 // TODO: Look into moving this into pansession?
4387 this.openGlobalLock = null;
4388 /**
4389 * @internal
4390 */
4391 this.panSession = null;
4392 this.visualElement = visualElement;
4393 this.visualElement.enableLayoutProjection();
4394 elementDragControls.set(visualElement, this);
4395 }
4396 /**
4397 * Instantiate a PanSession for the drag gesture
4398 *
4399 * @public
4400 */
4401 VisualElementDragControls.prototype.start = function (originEvent, _a) {
4402 var _this = this;
4403 var _b = _a === void 0 ? {} : _a, _c = _b.snapToCursor, snapToCursor = _c === void 0 ? false : _c, cursorProgress = _b.cursorProgress;
4404 /**
4405 * If this drag session has been manually triggered by the user, it might be from an event
4406 * outside the draggable element. If snapToCursor is set to true, we need to measure the position
4407 * of the element and snap it to the cursor.
4408 */
4409 snapToCursor && this.snapToCursor(originEvent);
4410 var onSessionStart = function () {
4411 // Initiate viewport scroll blocking on touch start. This is a very aggressive approach
4412 // which has come out of the difficulty in us being able to do this once a scroll gesture
4413 // has initiated in mobile browsers. This means if there's a horizontally-scrolling carousel
4414 // on a page we can't let a user scroll the page itself from it. Ideally what we'd do is
4415 // trigger this once we've got a scroll direction determined. This approach sort-of worked
4416 // but if the component was dragged too far in a single frame page scrolling would initiate.
4417 blockViewportScroll();
4418 // Stop any animations on both axis values immediately. This allows the user to throw and catch
4419 // the component.
4420 _this.stopMotion();
4421 };
4422 var onStart = function (event, info) {
4423 var _a, _b;
4424 // Attempt to grab the global drag gesture lock - maybe make this part of PanSession
4425 var _c = _this.props, drag = _c.drag, dragPropagation = _c.dragPropagation;
4426 if (drag && !dragPropagation) {
4427 if (_this.openGlobalLock)
4428 _this.openGlobalLock();
4429 _this.openGlobalLock = getGlobalLock(drag);
4430 // If we don 't have the lock, don't start dragging
4431 if (!_this.openGlobalLock)
4432 return;
4433 }
4434 /**
4435 * Record the progress of the mouse within the draggable element on each axis.
4436 * onPan, we're going to use this to calculate a new bounding box for the element to
4437 * project into. This will ensure that even if the DOM element moves via a relayout, it'll
4438 * stick to the correct place under the pointer.
4439 */
4440 _this.prepareBoundingBox();
4441 _this.visualElement.lockTargetBox();
4442 /**
4443 * Resolve the drag constraints. These are either set as top/right/bottom/left constraints
4444 * relative to the element's layout, or a ref to another element. Both need converting to
4445 * viewport coordinates.
4446 */
4447 _this.resolveDragConstraints();
4448 /**
4449 * When dragging starts, we want to find where the cursor is relative to the bounding box
4450 * of the element. Every frame, we calculate a new bounding box using this relative position
4451 * and let the visualElement renderer figure out how to reproject the element into this bounding
4452 * box.
4453 *
4454 * By doing it this way, rather than applying an x/y transform directly to the element,
4455 * we can ensure the component always visually sticks to the cursor as we'd expect, even
4456 * if the DOM element itself changes layout as a result of React updates the user might
4457 * make based on the drag position.
4458 */
4459 var point = getViewportPointFromEvent(event).point;
4460 eachAxis(function (axis) {
4461 var _a = _this.visualElement.targetBox[axis], min = _a.min, max = _a.max;
4462 _this.cursorProgress[axis] = cursorProgress
4463 ? cursorProgress[axis]
4464 : popcorn.progress(min, max, point[axis]);
4465 });
4466 // Set current drag status
4467 _this.isDragging = true;
4468 _this.currentDirection = null;
4469 // Fire onDragStart event
4470 (_b = (_a = _this.props).onDragStart) === null || _b === void 0 ? void 0 : _b.call(_a, event, info);
4471 };
4472 var onMove = function (event, info) {
4473 var _a, _b, _c, _d;
4474 var _e = _this.props, dragPropagation = _e.dragPropagation, dragDirectionLock = _e.dragDirectionLock;
4475 // If we didn't successfully receive the gesture lock, early return.
4476 if (!dragPropagation && !_this.openGlobalLock)
4477 return;
4478 var offset = info.offset;
4479 // Attempt to detect drag direction if directionLock is true
4480 if (dragDirectionLock && _this.currentDirection === null) {
4481 _this.currentDirection = getCurrentDirection(offset);
4482 // If we've successfully set a direction, notify listener
4483 if (_this.currentDirection !== null) {
4484 (_b = (_a = _this.props).onDirectionLock) === null || _b === void 0 ? void 0 : _b.call(_a, _this.currentDirection);
4485 }
4486 return;
4487 }
4488 // Update each point with the latest position
4489 _this.updateAxis("x", event);
4490 _this.updateAxis("y", event);
4491 // Fire onDrag event
4492 (_d = (_c = _this.props).onDrag) === null || _d === void 0 ? void 0 : _d.call(_c, event, info);
4493 // Update the last pointer event
4494 lastPointerEvent = event;
4495 };
4496 var onEnd = function (event, info) { return _this.stop(event, info); };
4497 var transformPagePoint = this.props.transformPagePoint;
4498 this.panSession = new PanSession(originEvent, {
4499 onSessionStart: onSessionStart,
4500 onStart: onStart,
4501 onMove: onMove,
4502 onEnd: onEnd,
4503 }, { transformPagePoint: transformPagePoint });
4504 };
4505 /**
4506 * Ensure the component's layout and target bounding boxes are up-to-date.
4507 */
4508 VisualElementDragControls.prototype.prepareBoundingBox = function () {
4509 var element = this.visualElement.getInstance();
4510 var transform = element.style.transform;
4511 this.visualElement.resetTransform();
4512 this.visualElement.measureLayout();
4513 element.style.transform = transform;
4514 this.visualElement.refreshTargetBox();
4515 };
4516 VisualElementDragControls.prototype.resolveDragConstraints = function () {
4517 var dragConstraints = this.props.dragConstraints;
4518 if (dragConstraints) {
4519 this.constraints = isRefObject(dragConstraints)
4520 ? this.resolveRefConstraints(this.visualElement.box, dragConstraints)
4521 : calcRelativeConstraints(this.visualElement.box, dragConstraints);
4522 }
4523 else {
4524 this.constraints = false;
4525 }
4526 };
4527 VisualElementDragControls.prototype.resolveRefConstraints = function (layoutBox, constraints) {
4528 var _a = this.props, onMeasureDragConstraints = _a.onMeasureDragConstraints, transformPagePoint = _a.transformPagePoint;
4529 var constraintsElement = constraints.current;
4530 heyListen.invariant(constraintsElement !== null, "If `dragConstraints` is set as a React ref, that ref must be passed to another component's `ref` prop.");
4531 this.constraintsBox = getBoundingBox(constraintsElement, transformPagePoint);
4532 var measuredConstraints = calcViewportConstraints(layoutBox, this.constraintsBox);
4533 /**
4534 * If there's an onMeasureDragConstraints listener we call it and
4535 * if different constraints are returned, set constraints to that
4536 */
4537 if (onMeasureDragConstraints) {
4538 var userConstraints = onMeasureDragConstraints(convertAxisBoxToBoundingBox(measuredConstraints));
4539 if (userConstraints) {
4540 measuredConstraints = convertBoundingBoxToAxisBox(userConstraints);
4541 }
4542 }
4543 return measuredConstraints;
4544 };
4545 VisualElementDragControls.prototype.cancelDrag = function () {
4546 unblockViewportScroll();
4547 this.isDragging = false;
4548 this.panSession && this.panSession.end();
4549 this.panSession = null;
4550 if (!this.props.dragPropagation && this.openGlobalLock) {
4551 this.openGlobalLock();
4552 this.openGlobalLock = null;
4553 }
4554 };
4555 VisualElementDragControls.prototype.stop = function (event, info) {
4556 var _a;
4557 this.visualElement.unlockTargetBox();
4558 (_a = this.panSession) === null || _a === void 0 ? void 0 : _a.end();
4559 this.panSession = null;
4560 var isDragging = this.isDragging;
4561 this.cancelDrag();
4562 if (!isDragging)
4563 return;
4564 var _b = this.props, dragMomentum = _b.dragMomentum, dragElastic = _b.dragElastic, onDragEnd = _b.onDragEnd;
4565 if (dragMomentum || dragElastic) {
4566 var velocity = info.velocity;
4567 this.animateDragEnd(velocity);
4568 }
4569 onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(event, info);
4570 };
4571 VisualElementDragControls.prototype.snapToCursor = function (event) {
4572 this.prepareBoundingBox();
4573 this.cursorProgress.x = 0.5;
4574 this.cursorProgress.y = 0.5;
4575 this.updateAxis("x", event);
4576 this.updateAxis("y", event);
4577 };
4578 /**
4579 * Update the specified axis with the latest pointer information.
4580 */
4581 VisualElementDragControls.prototype.updateAxis = function (axis, event) {
4582 var _a;
4583 var _b = this.props, drag = _b.drag, dragElastic = _b.dragElastic;
4584 // If we're not dragging this axis, do an early return.
4585 if (!shouldDrag(axis, drag, this.currentDirection))
4586 return;
4587 // Get the actual layout bounding box of the element
4588 var axisLayout = this.visualElement.box[axis];
4589 // Calculate its current length. In the future we might want to lerp this to animate
4590 // between lengths if the layout changes as we change the DOM
4591 var axisLength = axisLayout.max - axisLayout.min;
4592 // Get the initial progress that the pointer sat on this axis on gesture start.
4593 var axisProgress = this.cursorProgress[axis];
4594 var point = getViewportPointFromEvent(event).point;
4595 // Calculate a new min point based on the latest pointer position, constraints and elastic
4596 var min = calcConstrainedMinPoint(point[axis], axisLength, axisProgress, (_a = this.constraints) === null || _a === void 0 ? void 0 : _a[axis], dragElastic);
4597 // Update the axis viewport target with this new min and the length
4598 this.visualElement.setAxisTarget(axis, min, min + axisLength);
4599 };
4600 VisualElementDragControls.prototype.updateProps = function (_a) {
4601 var _b = _a.drag, drag = _b === void 0 ? false : _b, _c = _a.dragDirectionLock, dragDirectionLock = _c === void 0 ? false : _c, _d = _a.dragPropagation, dragPropagation = _d === void 0 ? false : _d, _e = _a.dragConstraints, dragConstraints = _e === void 0 ? false : _e, _f = _a.dragElastic, dragElastic = _f === void 0 ? 0.35 : _f, _g = _a.dragMomentum, dragMomentum = _g === void 0 ? true : _g, remainingProps = tslib.__rest(_a, ["drag", "dragDirectionLock", "dragPropagation", "dragConstraints", "dragElastic", "dragMomentum"]);
4602 this.props = tslib.__assign({ drag: drag,
4603 dragDirectionLock: dragDirectionLock,
4604 dragPropagation: dragPropagation,
4605 dragConstraints: dragConstraints,
4606 dragElastic: dragElastic,
4607 dragMomentum: dragMomentum }, remainingProps);
4608 };
4609 VisualElementDragControls.prototype.animateDragEnd = function (velocity) {
4610 var _this = this;
4611 var _a = this.props, drag = _a.drag, dragMomentum = _a.dragMomentum, dragElastic = _a.dragElastic, dragTransition = _a.dragTransition;
4612 var momentumAnimations = eachAxis(function (axis) {
4613 if (!shouldDrag(axis, drag, _this.currentDirection)) {
4614 return;
4615 }
4616 var transition = _this.constraints ? _this.constraints[axis] : {};
4617 /**
4618 * Overdamp the boundary spring if `dragElastic` is disabled. There's still a frame
4619 * of spring animations so we should look into adding a disable spring option to `inertia`.
4620 * We could do something here where we affect the `bounceStiffness` and `bounceDamping`
4621 * using the value of `dragElastic`.
4622 */
4623 var bounceStiffness = dragElastic ? 200 : 1000000;
4624 var bounceDamping = dragElastic ? 40 : 10000000;
4625 var inertia = tslib.__assign(tslib.__assign({ type: "inertia", velocity: dragMomentum ? velocity[axis] : 0, bounceStiffness: bounceStiffness,
4626 bounceDamping: bounceDamping, timeConstant: 750, restDelta: 1, restSpeed: 10 }, dragTransition), transition);
4627 // If we're not animating on an externally-provided `MotionValue` we can use the
4628 // component's animation controls which will handle interactions with whileHover (etc),
4629 // otherwise we just have to animate the `MotionValue` itself.
4630 return _this.visualElement.startLayoutAxisAnimation(axis, inertia);
4631 });
4632 // Run all animations and then resolve the new drag constraints.
4633 return Promise.all(momentumAnimations).then(function () {
4634 var _a, _b;
4635 (_b = (_a = _this.props).onDragTransitionEnd) === null || _b === void 0 ? void 0 : _b.call(_a);
4636 });
4637 };
4638 VisualElementDragControls.prototype.stopMotion = function () {
4639 this.visualElement.stopLayoutAnimation();
4640 };
4641 VisualElementDragControls.prototype.scalePoint = function () {
4642 var _this = this;
4643 var _a = this.props, drag = _a.drag, dragConstraints = _a.dragConstraints;
4644 if (!isRefObject(dragConstraints) || !this.constraintsBox)
4645 return;
4646 // Stop any current animations as there can be some visual glitching if we resize mid animation
4647 this.stopMotion();
4648 // Record the relative progress of the targetBox relative to the constraintsBox
4649 var boxProgress = { x: 0, y: 0 };
4650 eachAxis(function (axis) {
4651 boxProgress[axis] = calcOrigin(_this.visualElement.targetBox[axis], _this.constraintsBox[axis]);
4652 });
4653 /**
4654 * For each axis, calculate the current progress of the layout axis within the constraints.
4655 * Then, using the latest layout and constraints measurements, reposition the new layout axis
4656 * proportionally within the constraints.
4657 */
4658 this.prepareBoundingBox();
4659 this.resolveDragConstraints();
4660 eachAxis(function (axis) {
4661 if (!shouldDrag(axis, drag, null))
4662 return;
4663 // Calculate the position of the targetBox relative to the constraintsBox using the
4664 // previously calculated progress
4665 var _a = calcPositionFromProgress(_this.visualElement.targetBox[axis], _this.constraintsBox[axis], boxProgress[axis]), min = _a.min, max = _a.max;
4666 _this.visualElement.setAxisTarget(axis, min, max);
4667 });
4668 };
4669 VisualElementDragControls.prototype.mount = function (visualElement) {
4670 var _this = this;
4671 var element = visualElement.getInstance();
4672 /**
4673 * Attach a pointerdown event listener on this DOM element to initiate drag tracking.
4674 */
4675 var stopPointerListener = addPointerEvent(element, "pointerdown", function (event) {
4676 var _a = _this.props, drag = _a.drag, _b = _a.dragListener, dragListener = _b === void 0 ? true : _b;
4677 drag && dragListener && _this.start(event);
4678 });
4679 /**
4680 * Attach a window resize listener to scale the draggable target within its defined
4681 * constraints as the window resizes.
4682 */
4683 var stopResizeListener = addDomEvent(window, "resize", function () {
4684 _this.scalePoint();
4685 });
4686 /**
4687 * Ensure drag constraints are resolved correctly relative to the dragging element
4688 * whenever its layout changes.
4689 */
4690 var stopLayoutUpdateListener = visualElement.onLayoutUpdate(function () {
4691 if (_this.isDragging)
4692 _this.resolveDragConstraints();
4693 });
4694 /**
4695 * If the previous component with this same layoutId was dragging at the time
4696 * it was unmounted, we want to continue the same gesture on this component.
4697 */
4698 var prevSnapshot = visualElement.prevSnapshot;
4699 (prevSnapshot === null || prevSnapshot === void 0 ? void 0 : prevSnapshot.isDragging) &&
4700 this.start(lastPointerEvent, {
4701 cursorProgress: prevSnapshot.cursorProgress,
4702 });
4703 /**
4704 * Return a function that will teardown the drag gesture
4705 */
4706 return function () {
4707 stopPointerListener === null || stopPointerListener === void 0 ? void 0 : stopPointerListener();
4708 stopResizeListener === null || stopResizeListener === void 0 ? void 0 : stopResizeListener();
4709 stopLayoutUpdateListener === null || stopLayoutUpdateListener === void 0 ? void 0 : stopLayoutUpdateListener();
4710 _this.cancelDrag();
4711 };
4712 };
4713 return VisualElementDragControls;
4714}());
4715function shouldDrag(direction, drag, currentDirection) {
4716 return ((drag === true || drag === direction) &&
4717 (currentDirection === null || currentDirection === direction));
4718}
4719/**
4720 * Based on an x/y offset determine the current drag direction. If both axis' offsets are lower
4721 * than the provided threshold, return `null`.
4722 *
4723 * @param offset - The x/y offset from origin.
4724 * @param lockThreshold - (Optional) - the minimum absolute offset before we can determine a drag direction.
4725 */
4726function getCurrentDirection(offset, lockThreshold) {
4727 if (lockThreshold === void 0) { lockThreshold = 10; }
4728 var direction = null;
4729 if (Math.abs(offset.y) > lockThreshold) {
4730 direction = "y";
4731 }
4732 else if (Math.abs(offset.x) > lockThreshold) {
4733 direction = "x";
4734 }
4735 return direction;
4736}
4737
4738/**
4739 * A hook that allows an element to be dragged.
4740 *
4741 * @internal
4742 */
4743function useDrag(props, visualElement) {
4744 var groupDragControls = props.dragControls;
4745 var transformPagePoint = React.useContext(MotionConfigContext).transformPagePoint;
4746 var dragControls = useConstant(function () {
4747 return new VisualElementDragControls({
4748 visualElement: visualElement,
4749 });
4750 });
4751 dragControls.updateProps(tslib.__assign(tslib.__assign({}, props), { transformPagePoint: transformPagePoint }));
4752 // If we've been provided a DragControls for manual control over the drag gesture,
4753 // subscribe this component to it on mount.
4754 React.useEffect(function () { return groupDragControls && groupDragControls.subscribe(dragControls); }, [dragControls]);
4755 // Mount the drag controls with the visualElement
4756 React.useEffect(function () { return dragControls.mount(visualElement); }, []);
4757}
4758
4759var makeRenderlessComponent = function (hook) { return function (props) {
4760 hook(props);
4761 return null;
4762}; };
4763
4764var Component = makeRenderlessComponent(function (_a) {
4765 var visualElement = _a.visualElement, props = tslib.__rest(_a, ["visualElement"]);
4766 return useDrag(props, visualElement);
4767});
4768/**
4769 * @public
4770 */
4771var Drag = {
4772 key: "drag",
4773 shouldRender: function (props) { return !!props.drag; },
4774 getComponent: function () { return Component; },
4775};
4776
4777/**
4778 *
4779 * @param handlers -
4780 * @param ref -
4781 *
4782 * @internalremarks
4783 * Currently this sets new pan gesture functions every render. The memo route has been explored
4784 * in the past but ultimately we're still creating new functions every render. An optimisation
4785 * to explore is creating the pan gestures and loading them into a `ref`.
4786 *
4787 * @internal
4788 */
4789function usePanGesture(_a, ref) {
4790 var onPan = _a.onPan, onPanStart = _a.onPanStart, onPanEnd = _a.onPanEnd, onPanSessionStart = _a.onPanSessionStart;
4791 var hasPanEvents = onPan || onPanStart || onPanEnd || onPanSessionStart;
4792 var panSession = React.useRef(null);
4793 var transformPagePoint = React.useContext(MotionConfigContext).transformPagePoint;
4794 var handlers = {
4795 onSessionStart: onPanSessionStart,
4796 onStart: onPanStart,
4797 onMove: onPan,
4798 onEnd: function (event, info) {
4799 panSession.current = null;
4800 onPanEnd && onPanEnd(event, info);
4801 },
4802 };
4803 React.useEffect(function () {
4804 if (panSession.current !== null) {
4805 panSession.current.updateHandlers(handlers);
4806 }
4807 });
4808 function onPointerDown(event) {
4809 panSession.current = new PanSession(event, handlers, {
4810 transformPagePoint: transformPagePoint,
4811 });
4812 }
4813 usePointerEvent(ref, "pointerdown", hasPanEvents && onPointerDown);
4814 useUnmountEffect(function () { return panSession.current && panSession.current.end(); });
4815}
4816
4817/**
4818 * Recursively traverse up the tree to check whether the provided child node
4819 * is the parent or a descendant of it.
4820 *
4821 * @param parent - Element to find
4822 * @param child - Element to test against parent
4823 */
4824var isNodeOrChild = function (parent, child) {
4825 if (!child) {
4826 return false;
4827 }
4828 else if (parent === child) {
4829 return true;
4830 }
4831 else {
4832 return isNodeOrChild(parent, child.parentElement);
4833 }
4834};
4835
4836var order$1 = ["whileHover", "whileTap", "whileDrag"];
4837var getGesturePriority = function (gesture) {
4838 return order$1.indexOf(gesture) + 1;
4839};
4840
4841var tapGesturePriority = getGesturePriority("whileTap");
4842/**
4843 * @param handlers -
4844 * @internal
4845 */
4846function useTapGesture(_a, ref) {
4847 var onTap = _a.onTap, onTapStart = _a.onTapStart, onTapCancel = _a.onTapCancel, whileTap = _a.whileTap, controls = _a.controls;
4848 var hasTapListeners = onTap || onTapStart || onTapCancel || whileTap;
4849 var isTapping = React.useRef(false);
4850 var cancelPointerEventListener = React.useRef(null);
4851 function removePointerUp() {
4852 cancelPointerEventListener.current &&
4853 cancelPointerEventListener.current();
4854 cancelPointerEventListener.current = null;
4855 }
4856 if (whileTap && controls) {
4857 controls.setOverride(whileTap, tapGesturePriority);
4858 }
4859 // We load this event handler into a ref so we can later refer to
4860 // onPointerUp.current which will always have reference to the latest props
4861 var onPointerUp = React.useRef(null);
4862 onPointerUp.current = function (event, info) {
4863 var element = ref.current;
4864 removePointerUp();
4865 if (!isTapping.current || !element)
4866 return;
4867 isTapping.current = false;
4868 if (controls && whileTap) {
4869 controls.clearOverride(tapGesturePriority);
4870 }
4871 // Check the gesture lock - if we get it, it means no drag gesture is active
4872 // and we can safely fire the tap gesture.
4873 var openGestureLock = getGlobalLock(true);
4874 if (!openGestureLock)
4875 return;
4876 openGestureLock();
4877 if (!isNodeOrChild(element, event.target)) {
4878 onTapCancel && onTapCancel(event, info);
4879 }
4880 else {
4881 onTap && onTap(event, info);
4882 }
4883 };
4884 function onPointerDown(event, info) {
4885 removePointerUp();
4886 cancelPointerEventListener.current = addPointerEvent(window, "pointerup", function (event, info) { return onPointerUp.current(event, info); });
4887 var element = ref.current;
4888 if (!element || isTapping.current)
4889 return;
4890 isTapping.current = true;
4891 onTapStart && onTapStart(event, info);
4892 if (controls && whileTap) {
4893 controls.startOverride(tapGesturePriority);
4894 }
4895 }
4896 usePointerEvent(ref, "pointerdown", hasTapListeners ? onPointerDown : undefined);
4897 useUnmountEffect(removePointerUp);
4898}
4899
4900var hoverPriority = getGesturePriority("whileHover");
4901var filterTouch = function (listener) { return function (event, info) {
4902 if (isMouseEvent(event))
4903 listener(event, info);
4904}; };
4905/**
4906 *
4907 * @param props
4908 * @param ref
4909 * @internal
4910 */
4911function useHoverGesture(_a, ref) {
4912 var whileHover = _a.whileHover, onHoverStart = _a.onHoverStart, onHoverEnd = _a.onHoverEnd, controls = _a.controls;
4913 if (whileHover && controls) {
4914 controls.setOverride(whileHover, hoverPriority);
4915 }
4916 usePointerEvent(ref, "pointerenter", filterTouch(function (event, info) {
4917 if (onHoverStart)
4918 onHoverStart(event, info);
4919 if (whileHover && controls) {
4920 controls.startOverride(hoverPriority);
4921 }
4922 }));
4923 usePointerEvent(ref, "pointerleave", filterTouch(function (event, info) {
4924 if (onHoverEnd)
4925 onHoverEnd(event, info);
4926 if (whileHover && controls) {
4927 controls.clearOverride(hoverPriority);
4928 }
4929 }));
4930}
4931
4932/**
4933 * Add pan and tap gesture recognition to an element.
4934 *
4935 * @param props - Gesture event handlers
4936 * @param ref - React `ref` containing a DOM `Element`
4937 * @public
4938 */
4939function useGestures(props, ref) {
4940 usePanGesture(props, ref);
4941 useTapGesture(props, ref);
4942 useHoverGesture(props, ref);
4943}
4944
4945var gestureProps = [
4946 "onPan",
4947 "onPanStart",
4948 "onPanEnd",
4949 "onPanSessionStart",
4950 "onTap",
4951 "onTapStart",
4952 "onTapCancel",
4953 "whileTap",
4954 "whileHover",
4955 "onHoverStart",
4956 "onHoverEnd",
4957];
4958var GestureComponent = makeRenderlessComponent(function (_a) {
4959 var visualElement = _a.visualElement, props = tslib.__rest(_a, ["visualElement"]);
4960 useGestures(props, visualElement);
4961});
4962/**
4963 * @public
4964 */
4965var Gestures = {
4966 key: "gestures",
4967 shouldRender: function (props) {
4968 return gestureProps.some(function (key) { return props.hasOwnProperty(key); });
4969 },
4970 getComponent: function () { return GestureComponent; },
4971};
4972
4973var ExitComponent = makeRenderlessComponent(function (props) {
4974 var animate = props.animate, controls = props.controls, exit = props.exit;
4975 var _a = usePresence(), isPresent = _a[0], onExitComplete = _a[1];
4976 var presenceContext = React.useContext(PresenceContext);
4977 var isPlayingExitAnimation = React.useRef(false);
4978 var custom = (presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.custom) !== undefined
4979 ? presenceContext.custom
4980 : props.custom;
4981 React.useEffect(function () {
4982 if (!isPresent) {
4983 if (!isPlayingExitAnimation.current && exit) {
4984 controls.setProps(tslib.__assign(tslib.__assign({}, props), { custom: custom }));
4985 controls.start(exit).then(onExitComplete);
4986 }
4987 isPlayingExitAnimation.current = true;
4988 }
4989 else if (isPlayingExitAnimation.current &&
4990 animate &&
4991 typeof animate !== "boolean" &&
4992 !(animate instanceof AnimationControls)) {
4993 controls.start(animate);
4994 }
4995 if (isPresent) {
4996 isPlayingExitAnimation.current = false;
4997 }
4998 }, [animate, controls, custom, exit, isPresent, onExitComplete, props]);
4999});
5000/**
5001 * @public
5002 */
5003var Exit = {
5004 key: "exit",
5005 shouldRender: function (props) { return !!props.exit && !checkShouldInheritVariant(props); },
5006 getComponent: function () { return ExitComponent; },
5007};
5008
5009var AnimatePropType;
5010(function (AnimatePropType) {
5011 AnimatePropType["Target"] = "Target";
5012 AnimatePropType["VariantLabel"] = "VariantLabel";
5013 AnimatePropType["AnimationSubscription"] = "AnimationSubscription";
5014})(AnimatePropType || (AnimatePropType = {}));
5015
5016function shallowCompare(next, prev) {
5017 if (prev === null)
5018 return false;
5019 var prevLength = prev.length;
5020 if (prevLength !== next.length)
5021 return false;
5022 for (var i = 0; i < prevLength; i++) {
5023 if (prev[i] !== next[i])
5024 return false;
5025 }
5026 return true;
5027}
5028
5029var hasUpdated = function (prev, next) {
5030 return (next !== undefined &&
5031 (Array.isArray(prev) && Array.isArray(next)
5032 ? !shallowCompare(next, prev)
5033 : prev !== next));
5034};
5035function targetWithoutTransition(_a, mergeTransitionEnd) {
5036 if (mergeTransitionEnd === void 0) { mergeTransitionEnd = false; }
5037 var transition = _a.transition, transitionEnd = _a.transitionEnd, target = tslib.__rest(_a, ["transition", "transitionEnd"]);
5038 return mergeTransitionEnd
5039 ? tslib.__assign(tslib.__assign({}, target), transitionEnd)
5040 : target;
5041}
5042/**
5043 * Handle the `animate` prop when its an object of values, ie:
5044 *
5045 * ```jsx
5046 * <motion.div animate={{ opacity: 1 }} />
5047 * ```
5048 *
5049 * @internalremarks
5050 * It might be worth consolidating this with `use-variants`
5051 *
5052 * ```jsx
5053 * <motion.div animate="visible" />
5054 * ```
5055 *
5056 * @param target
5057 * @param controls
5058 * @param values
5059 * @param transition
5060 *
5061 * @internal
5062 */
5063function useAnimateProp(targetAndTransition, controls, visualElement, defaultTransition) {
5064 var isInitialRender = React.useRef(true);
5065 var prevValues = React.useRef(null);
5066 if (!prevValues.current) {
5067 prevValues.current = targetWithoutTransition(targetAndTransition, true);
5068 }
5069 React.useEffect(function () {
5070 var targetToAnimate = {};
5071 // These are the values we're actually animating
5072 var animatingTarget = targetWithoutTransition(targetAndTransition);
5073 // This is the target as it'll be once transitionEnd values are applied
5074 var finalTarget = targetWithoutTransition(targetAndTransition, true);
5075 // Detect which values have changed between renders
5076 for (var key in animatingTarget) {
5077 // This value should animate on mount if this value doesn't already exist (wasn't
5078 // defined in `style` or `initial`) or if it does exist and it's already changed.
5079 var shouldAnimateOnMount = isInitialRender.current &&
5080 (!visualElement.hasValue(key) ||
5081 visualElement.getValue(key).get() !== finalTarget[key]);
5082 // If this value has updated between renders or it's we're animating this value on mount,
5083 // add it to the animate target.
5084 var isValidValue = finalTarget[key] !== null;
5085 var valueHasUpdated = hasUpdated(prevValues.current[key], finalTarget[key]);
5086 if (isValidValue && (valueHasUpdated || shouldAnimateOnMount)) {
5087 targetToAnimate[key] = animatingTarget[key];
5088 }
5089 }
5090 isInitialRender.current = false;
5091 prevValues.current = tslib.__assign(tslib.__assign({}, prevValues.current), finalTarget);
5092 if (Object.keys(targetToAnimate).length) {
5093 controls.start(tslib.__assign(tslib.__assign({}, targetToAnimate), { transition: targetAndTransition.transition || defaultTransition, transitionEnd: targetAndTransition.transitionEnd }));
5094 }
5095 }, [targetAndTransition]);
5096}
5097
5098var labelsToArray = function (label) {
5099 if (!label) {
5100 return [];
5101 }
5102 if (Array.isArray(label)) {
5103 return label;
5104 }
5105 return [label];
5106};
5107var resolveVariantLabels = function (variant) {
5108 var unresolvedVariant = variant instanceof MotionValue ? variant.get() : variant;
5109 return Array.from(new Set(labelsToArray(unresolvedVariant)));
5110};
5111/**
5112 * Hooks in React sometimes accept a dependency array as their final argument. (ie useEffect/useMemo)
5113 * When values in this array change, React re-runs the dependency. However if the array
5114 * contains a variable number of items, React throws an error.
5115 */
5116var asDependencyList = function (list) { return [
5117 list.join(","),
5118]; };
5119
5120var hasVariantChanged = function (oldVariant, newVariant) {
5121 return oldVariant.join(",") !== newVariant.join(",");
5122};
5123/**
5124 * Handle variants and the `animate` prop when its set as variant labels.
5125 *
5126 * @param initial - Initial variant(s)
5127 * @param animate - Variant(s) to animate to
5128 * @param inherit - `true` is inheriting animations from parent
5129 * @param controls - Animation controls
5130 *
5131 * @internal
5132 */
5133function useVariants(initial, animate, inherit, controls) {
5134 var targetVariants = resolveVariantLabels(animate);
5135 var context = React.useContext(MotionContext);
5136 var parentAlreadyMounted = context.hasMounted && context.hasMounted.current;
5137 var hasMounted = React.useRef(false);
5138 React.useEffect(function () {
5139 var shouldAnimate = false;
5140 if (inherit) {
5141 // If we're inheriting variant changes and the parent has already
5142 // mounted when this component loads, we need to manually trigger
5143 // this animation.
5144 shouldAnimate = !!parentAlreadyMounted;
5145 targetVariants = resolveVariantLabels(context.animate);
5146 }
5147 else {
5148 shouldAnimate =
5149 hasMounted.current ||
5150 hasVariantChanged(resolveVariantLabels(initial), targetVariants);
5151 }
5152 shouldAnimate && controls.start(targetVariants);
5153 hasMounted.current = true;
5154 }, asDependencyList(targetVariants));
5155}
5156
5157/**
5158 * `useAnimationGroupSubscription` allows a component to subscribe to an
5159 * externally-created `AnimationControls`, created by the `useAnimation` hook.
5160 *
5161 * @param animation
5162 * @param controls
5163 *
5164 * @internal
5165 */
5166function useAnimationGroupSubscription(animation, controls) {
5167 var unsubscribe = React.useMemo(function () { return animation.subscribe(controls); }, [
5168 animation,
5169 ]);
5170 React.useEffect(function () { return function () {
5171 unsubscribe && unsubscribe();
5172 }; }, [unsubscribe]);
5173}
5174
5175var _a, _b;
5176var AnimatePropComponents = (_a = {},
5177 _a[AnimatePropType.Target] = makeRenderlessComponent(function (_a) {
5178 var animate = _a.animate, controls = _a.controls, visualElement = _a.visualElement, transition = _a.transition;
5179 return useAnimateProp(animate, controls, visualElement, transition);
5180 }),
5181 _a[AnimatePropType.VariantLabel] = makeRenderlessComponent(function (_a) {
5182 var animate = _a.animate, _b = _a.inherit, inherit = _b === void 0 ? true : _b, controls = _a.controls, initial = _a.initial;
5183 return useVariants(initial, animate, inherit, controls);
5184 }),
5185 _a[AnimatePropType.AnimationSubscription] = makeRenderlessComponent(function (_a) {
5186 var animate = _a.animate, controls = _a.controls;
5187 return useAnimationGroupSubscription(animate, controls);
5188 }),
5189 _a);
5190var isVariantLabel$1 = function (prop) {
5191 return Array.isArray(prop) || typeof prop === "string";
5192};
5193var isAnimationSubscription = function (_a) {
5194 var animate = _a.animate;
5195 return animate instanceof AnimationControls;
5196};
5197var animationProps = ["initial", "animate", "whileTap", "whileHover"];
5198var animatePropTypeTests = (_b = {},
5199 _b[AnimatePropType.Target] = function (props) {
5200 return (props.animate !== undefined &&
5201 !isVariantLabel$1(props.animate) &&
5202 !isAnimationSubscription(props));
5203 },
5204 _b[AnimatePropType.VariantLabel] = function (props) {
5205 return (props.variants !== undefined ||
5206 animationProps.some(function (key) { return typeof props[key] === "string"; }));
5207 },
5208 _b[AnimatePropType.AnimationSubscription] = isAnimationSubscription,
5209 _b);
5210var getAnimationComponent = function (props) {
5211 var animatePropType = undefined;
5212 for (var key in AnimatePropType) {
5213 if (animatePropTypeTests[key](props)) {
5214 animatePropType = key;
5215 }
5216 }
5217 return animatePropType ? AnimatePropComponents[animatePropType] : undefined;
5218};
5219/**
5220 * @public
5221 */
5222var Animation = {
5223 key: "animation",
5224 shouldRender: function () { return true; },
5225 getComponent: getAnimationComponent,
5226};
5227
5228function tweenAxis(target, prev, next, p) {
5229 target.min = popcorn.mix(prev.min, next.min, p);
5230 target.max = popcorn.mix(prev.max, next.max, p);
5231}
5232
5233var progressTarget = 1000;
5234var Animate = /** @class */ (function (_super) {
5235 tslib.__extends(Animate, _super);
5236 function Animate() {
5237 var _this = _super !== null && _super.apply(this, arguments) || this;
5238 _this.frameTarget = {
5239 x: { min: 0, max: 0 },
5240 y: { min: 0, max: 0 },
5241 };
5242 _this.stopAxisAnimation = {
5243 x: undefined,
5244 y: undefined,
5245 };
5246 _this.animate = function (target, origin, _a) {
5247 if (_a === void 0) { _a = {}; }
5248 var originBox = _a.originBox, targetBox = _a.targetBox, visibilityAction = _a.visibilityAction, config = tslib.__rest(_a, ["originBox", "targetBox", "visibilityAction"]);
5249 var _b = _this.props, visualElement = _b.visualElement, layout = _b.layout;
5250 /**
5251 * Allow the measured origin (prev bounding box) and target (actual layout) to be
5252 * overridden by the provided config.
5253 */
5254 origin = originBox || origin;
5255 target = targetBox || target;
5256 var boxHasMoved = hasMoved(origin, target);
5257 var animations = eachAxis(function (axis) {
5258 /**
5259 * If layout is set to "position", we can resize the origin box based on the target
5260 * box and only animate its position.
5261 */
5262 if (layout === "position") {
5263 var targetLength = target[axis].max - target[axis].min;
5264 origin[axis].max = origin[axis].min + targetLength;
5265 }
5266 if (visualElement.isTargetBoxLocked) {
5267 return;
5268 }
5269 else if (visibilityAction !== undefined) {
5270 // If we're meant to show/hide the visualElement, do so
5271 visibilityAction === VisibilityAction.Hide
5272 ? visualElement.hide()
5273 : visualElement.show();
5274 }
5275 else if (boxHasMoved) {
5276 // If the box has moved, animate between it's current visual state and its
5277 // final state
5278 return _this.animateAxis(axis, target[axis], origin[axis], config);
5279 }
5280 else {
5281 // If the box has remained in the same place, immediately set the axis target
5282 // to the final desired state
5283 return visualElement.setAxisTarget(axis, target[axis].min, target[axis].max);
5284 }
5285 });
5286 // Force a render to ensure there's no flash of uncorrected bounding box.
5287 visualElement.render();
5288 /**
5289 * If this visualElement isn't present (ie it's been removed from the tree by the user but
5290 * kept in by the tree by AnimatePresence) then call safeToRemove when all axis animations
5291 * have successfully finished.
5292 */
5293 return Promise.all(animations).then(function () {
5294 var _a, _b;
5295 (_b = (_a = _this.props).onLayoutAnimationComplete) === null || _b === void 0 ? void 0 : _b.call(_a);
5296 if (visualElement.isPresent) {
5297 visualElement.presence = Presence.Present;
5298 }
5299 else {
5300 _this.safeToRemove();
5301 }
5302 });
5303 };
5304 return _this;
5305 }
5306 Animate.prototype.componentDidMount = function () {
5307 var visualElement = this.props.visualElement;
5308 visualElement.enableLayoutProjection();
5309 this.unsubLayoutReady = visualElement.onLayoutUpdate(this.animate);
5310 };
5311 Animate.prototype.componentWillUnmount = function () {
5312 var _this = this;
5313 this.unsubLayoutReady();
5314 eachAxis(function (axis) { var _a, _b; return (_b = (_a = _this.stopAxisAnimation)[axis]) === null || _b === void 0 ? void 0 : _b.call(_a); });
5315 };
5316 /**
5317 * TODO: This manually performs animations on the visualElement's layout progress
5318 * values. It'd be preferable to amend the HTMLVisualElement.startLayoutAxisAnimation
5319 * API to accept more custom animations like this.
5320 */
5321 Animate.prototype.animateAxis = function (axis, target, origin, _a) {
5322 var _b, _c;
5323 var _d = _a === void 0 ? {} : _a, transition = _d.transition, crossfadeOpacity = _d.crossfadeOpacity;
5324 (_c = (_b = this.stopAxisAnimation)[axis]) === null || _c === void 0 ? void 0 : _c.call(_b);
5325 var visualElement = this.props.visualElement;
5326 var frameTarget = this.frameTarget[axis];
5327 var layoutProgress = visualElement.axisProgress[axis];
5328 /**
5329 * Set layout progress back to 0. We set it twice to hard-reset any velocity that might
5330 * be re-incoporated into a subsequent spring animation.
5331 */
5332 layoutProgress.clearListeners();
5333 layoutProgress.set(0);
5334 layoutProgress.set(0);
5335 /**
5336 * If this is a crossfade animation, create a function that updates both the opacity of this component
5337 * and the one being crossfaded out.
5338 */
5339 var crossfade = crossfadeOpacity && this.createCrossfadeAnimation(crossfadeOpacity);
5340 /**
5341 * Create an animation function to run once per frame. This will tween the visual bounding box from
5342 * origin to target using the latest progress value.
5343 */
5344 var frame = function () {
5345 // Convert the latest layoutProgress, which is a value from 0-1000, into a 0-1 progress
5346 var p = layoutProgress.get() / progressTarget;
5347 // Tween the axis and update the visualElement with the latest values
5348 tweenAxis(frameTarget, origin, target, p);
5349 visualElement.setAxisTarget(axis, frameTarget.min, frameTarget.max);
5350 // If this is a crossfade animation, update both elements.
5351 crossfade === null || crossfade === void 0 ? void 0 : crossfade(p);
5352 };
5353 // Synchronously run a frame to ensure there's no flash of the uncorrected bounding box.
5354 frame();
5355 // Start the animation on this axis
5356 var animation = startAnimation(axis === "x" ? "layoutX" : "layoutY", layoutProgress, progressTarget, transition || this.props.transition || defaultTransition);
5357 // Create a function to stop animation on this specific axis
5358 var unsubscribeProgress = layoutProgress.onChange(frame);
5359 this.stopAxisAnimation[axis] = function () {
5360 layoutProgress.stop();
5361 unsubscribeProgress();
5362 };
5363 return animation;
5364 };
5365 Animate.prototype.createCrossfadeAnimation = function (crossfadeOpacity) {
5366 var visualElement = this.props.visualElement;
5367 var opacity = visualElement.getValue("opacity", 0);
5368 return function (p) {
5369 opacity.set(easeCrossfadeIn(popcorn.mix(0, 1, p)));
5370 crossfadeOpacity.set(easeCrossfadeOut(popcorn.mix(1, 0, p)));
5371 };
5372 };
5373 Animate.prototype.safeToRemove = function () {
5374 var _a, _b;
5375 (_b = (_a = this.props).safeToRemove) === null || _b === void 0 ? void 0 : _b.call(_a);
5376 };
5377 Animate.prototype.render = function () {
5378 return null;
5379 };
5380 return Animate;
5381}(React.Component));
5382function AnimateLayoutContextProvider(props) {
5383 var _a = usePresence(), safeToRemove = _a[1];
5384 return React.createElement(Animate, tslib.__assign({}, props, { safeToRemove: safeToRemove }));
5385}
5386function hasMoved(a, b) {
5387 return hasAxisMoved(a.x, b.x) || hasAxisMoved(a.y, b.y);
5388}
5389function hasAxisMoved(a, b) {
5390 return a.min !== b.min || a.max !== b.max;
5391}
5392var defaultTransition = {
5393 duration: 0.45,
5394 ease: [0.4, 0, 0.1, 1],
5395};
5396function compress(min, max, easing) {
5397 return function (p) {
5398 // Could replace ifs with clamp
5399 if (p < min)
5400 return 0;
5401 if (p > max)
5402 return 1;
5403 return easing(popcorn.progress(min, max, p));
5404 };
5405}
5406var easeCrossfadeIn = compress(0, 0.5, popcorn.circOut);
5407var easeCrossfadeOut = compress(0.5, 0.95, popcorn.linear);
5408/**
5409 * @public
5410 */
5411var AnimateLayout = {
5412 key: "animate-layout",
5413 shouldRender: function (props) { return !!props.layout || !!props.layoutId; },
5414 getComponent: function () { return AnimateLayoutContextProvider; },
5415};
5416
5417/**
5418 * This component is responsible for scheduling the measuring of the motion component
5419 */
5420var Measure = /** @class */ (function (_super) {
5421 tslib.__extends(Measure, _super);
5422 function Measure(props) {
5423 var _this = _super.call(this, props) || this;
5424 /**
5425 * If this component isn't the child of a SyncContext, make it responsible for flushing
5426 * the layout batcher
5427 */
5428 var syncLayout = props.syncLayout;
5429 if (!isSharedLayout(syncLayout)) {
5430 _this.componentDidUpdate = function () { return syncLayout.flush(); };
5431 }
5432 return _this;
5433 }
5434 /**
5435 * If this is a child of a SyncContext, register the VisualElement with it on mount.
5436 */
5437 Measure.prototype.componentDidMount = function () {
5438 var _a = this.props, syncLayout = _a.syncLayout, visualElement = _a.visualElement;
5439 isSharedLayout(syncLayout) && syncLayout.register(visualElement);
5440 };
5441 /**
5442 * If this is a child of a SyncContext, notify it that it needs to re-render. It will then
5443 * handle the snapshotting.
5444 *
5445 * If it is stand-alone component, add it to the batcher.
5446 */
5447 Measure.prototype.getSnapshotBeforeUpdate = function () {
5448 var _a = this.props, syncLayout = _a.syncLayout, visualElement = _a.visualElement;
5449 if (isSharedLayout(syncLayout)) {
5450 syncLayout.syncUpdate();
5451 }
5452 else {
5453 visualElement.snapshotBoundingBox();
5454 syncLayout.add(visualElement);
5455 }
5456 return null;
5457 };
5458 Measure.prototype.componentDidUpdate = function () { };
5459 Measure.prototype.render = function () {
5460 return null;
5461 };
5462 return Measure;
5463}(React__default.Component));
5464function MeasureContextProvider(props) {
5465 var syncLayout = React.useContext(SharedLayoutContext);
5466 return React__default.createElement(Measure, tslib.__assign({}, props, { syncLayout: syncLayout }));
5467}
5468var MeasureLayout = {
5469 key: "measure-layout",
5470 shouldRender: function (props) {
5471 return !!props.drag || !!props.layout || !!props.layoutId;
5472 },
5473 getComponent: function () { return MeasureContextProvider; },
5474};
5475
5476/**
5477 * Convert any React component into a `motion` component. The provided component
5478 * **must** use `React.forwardRef` to the underlying DOM component you want to animate.
5479 *
5480 * ```jsx
5481 * const Component = React.forwardRef((props, ref) => {
5482 * return <div ref={ref} />
5483 * })
5484 *
5485 * const MotionComponent = motion.custom(Component)
5486 * ```
5487 *
5488 * @public
5489 */
5490function createMotionProxy(defaultFeatures) {
5491 var config = {
5492 defaultFeatures: defaultFeatures,
5493 useVisualElement: useDomVisualElement,
5494 render: render,
5495 animationControlsConfig: {
5496 makeTargetAnimatable: parseDomVariant,
5497 },
5498 };
5499 function custom(Component) {
5500 return createMotionComponent(Component, config);
5501 }
5502 var componentCache = new Map();
5503 function get(target, key) {
5504 if (key === "custom")
5505 return target.custom;
5506 if (!componentCache.has(key)) {
5507 componentCache.set(key, createMotionComponent(key, config));
5508 }
5509 return componentCache.get(key);
5510 }
5511 return new Proxy({ custom: custom }, { get: get });
5512}
5513/**
5514 * HTML & SVG components, optimised for use with gestures and animation. These can be used as
5515 * drop-in replacements for any HTML & SVG component, all CSS & SVG properties are supported.
5516 *
5517 * @public
5518 */
5519var motion = /*@__PURE__*/ createMotionProxy([
5520 MeasureLayout,
5521 Animation,
5522 Drag,
5523 Gestures,
5524 Exit,
5525 AnimateLayout,
5526]);
5527/**
5528 * @public
5529 */
5530var m = /*@__PURE__*/ createMotionProxy([MeasureLayout]);
5531
5532function useForceUpdate() {
5533 var _a = React.useState(0), forcedRenderCount = _a[0], setForcedRenderCount = _a[1];
5534 return React.useCallback(function () { return setForcedRenderCount(forcedRenderCount + 1); }, [
5535 forcedRenderCount,
5536 ]);
5537}
5538
5539var presenceId = 0;
5540function getPresenceId() {
5541 var id = presenceId;
5542 presenceId++;
5543 return id;
5544}
5545var PresenceChild = function (_a) {
5546 var children = _a.children, initial = _a.initial, isPresent = _a.isPresent, onExitComplete = _a.onExitComplete, custom = _a.custom;
5547 var presenceChildren = useConstant(newChildrenMap);
5548 var context = {
5549 id: useConstant(getPresenceId),
5550 initial: initial,
5551 isPresent: isPresent,
5552 custom: custom,
5553 onExitComplete: function (childId) {
5554 presenceChildren.set(childId, true);
5555 var allComplete = true;
5556 presenceChildren.forEach(function (isComplete) {
5557 if (!isComplete)
5558 allComplete = false;
5559 });
5560 allComplete && (onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete());
5561 },
5562 register: function (childId) {
5563 presenceChildren.set(childId, false);
5564 return function () { return presenceChildren.delete(childId); };
5565 },
5566 };
5567 React.useMemo(function () {
5568 presenceChildren.forEach(function (_, key) { return presenceChildren.set(key, false); });
5569 }, [isPresent]);
5570 return (React.createElement(PresenceContext.Provider, { value: context }, children));
5571};
5572function newChildrenMap() {
5573 return new Map();
5574}
5575
5576function getChildKey(child) {
5577 return child.key || "";
5578}
5579function updateChildLookup(children, allChildren) {
5580 var seenChildren = process.env.NODE_ENV !== "production" ? new Set() : null;
5581 children.forEach(function (child) {
5582 var key = getChildKey(child);
5583 if (process.env.NODE_ENV !== "production" && seenChildren) {
5584 if (seenChildren.has(key)) {
5585 console.warn("Children of AnimatePresence require unique keys. \"" + key + "\" is a duplicate.");
5586 }
5587 seenChildren.add(key);
5588 }
5589 allChildren.set(key, child);
5590 });
5591}
5592function onlyElements(children) {
5593 var filtered = [];
5594 // We use forEach here instead of map as map mutates the component key by preprending `.$`
5595 React.Children.forEach(children, function (child) {
5596 if (React.isValidElement(child))
5597 filtered.push(child);
5598 });
5599 return filtered;
5600}
5601/**
5602 * `AnimatePresence` enables the animation of components that have been removed from the tree.
5603 *
5604 * When adding/removing more than a single child, every child **must** be given a unique `key` prop.
5605 *
5606 * @library
5607 *
5608 * Any `Frame` components that have an `exit` property defined will animate out when removed from
5609 * the tree.
5610 *
5611 * ```jsx
5612 * import { Frame, AnimatePresence } from 'framer'
5613 *
5614 * // As items are added and removed from `items`
5615 * export function Items({ items }) {
5616 * return (
5617 * <AnimatePresence>
5618 * {items.map(item => (
5619 * <Frame
5620 * key={item.id}
5621 * initial={{ opacity: 0 }}
5622 * animate={{ opacity: 1 }}
5623 * exit={{ opacity: 0 }}
5624 * />
5625 * ))}
5626 * </AnimatePresence>
5627 * )
5628 * }
5629 * ```
5630 *
5631 * You can sequence exit animations throughout a tree using variants.
5632 *
5633 * @motion
5634 *
5635 * Any `motion` components that have an `exit` property defined will animate out when removed from
5636 * the tree.
5637 *
5638 * ```jsx
5639 * import { motion, AnimatePresence } from 'framer-motion'
5640 *
5641 * export const Items = ({ items }) => (
5642 * <AnimatePresence>
5643 * {items.map(item => (
5644 * <motion.div
5645 * key={item.id}
5646 * initial={{ opacity: 0 }}
5647 * animate={{ opacity: 1 }}
5648 * exit={{ opacity: 0 }}
5649 * />
5650 * ))}
5651 * </AnimatePresence>
5652 * )
5653 * ```
5654 *
5655 * You can sequence exit animations throughout a tree using variants.
5656 *
5657 * If a child contains multiple `motion` components with `exit` props, it will only unmount the child
5658 * once all `motion` components have finished animating out. Likewise, any components using
5659 * `usePresence` all need to call `safeToRemove`.
5660 *
5661 * @public
5662 */
5663var AnimatePresence = function (_a) {
5664 var children = _a.children, custom = _a.custom, _b = _a.initial, initial = _b === void 0 ? true : _b, onExitComplete = _a.onExitComplete, exitBeforeEnter = _a.exitBeforeEnter;
5665 // We want to force a re-render once all exiting animations have finished. We
5666 // either use a local forceRender function, or one from a parent context if it exists.
5667 var forceRender = useForceUpdate();
5668 var layoutContext = React.useContext(SharedLayoutContext);
5669 if (isSharedLayout(layoutContext)) {
5670 forceRender = layoutContext.forceUpdate;
5671 }
5672 var isInitialRender = React.useRef(true);
5673 // Filter out any children that aren't ReactElements. We can only track ReactElements with a props.key
5674 var filteredChildren = onlyElements(children);
5675 // Keep a living record of the children we're actually rendering so we
5676 // can diff to figure out which are entering and exiting
5677 var presentChildren = React.useRef(filteredChildren);
5678 // A lookup table to quickly reference components by key
5679 var allChildren = React.useRef(new Map())
5680 .current;
5681 // A living record of all currently exiting components.
5682 var exiting = React.useRef(new Set()).current;
5683 updateChildLookup(filteredChildren, allChildren);
5684 // If this is the initial component render, just deal with logic surrounding whether
5685 // we play onMount animations or not.
5686 if (isInitialRender.current) {
5687 isInitialRender.current = false;
5688 return (React.createElement(React.Fragment, null, filteredChildren.map(function (child) { return (React.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, initial: initial ? undefined : false }, child)); })));
5689 }
5690 // If this is a subsequent render, deal with entering and exiting children
5691 var childrenToRender = tslib.__spreadArrays(filteredChildren);
5692 // Diff the keys of the currently-present and target children to update our
5693 // exiting list.
5694 var presentKeys = presentChildren.current.map(getChildKey);
5695 var targetKeys = filteredChildren.map(getChildKey);
5696 // Diff the present children with our target children and mark those that are exiting
5697 var numPresent = presentKeys.length;
5698 for (var i = 0; i < numPresent; i++) {
5699 var key = presentKeys[i];
5700 if (targetKeys.indexOf(key) === -1) {
5701 exiting.add(key);
5702 }
5703 else {
5704 // In case this key has re-entered, remove from the exiting list
5705 exiting.delete(key);
5706 }
5707 }
5708 // If we currently have exiting children, and we're deferring rendering incoming children
5709 // until after all current children have exiting, empty the childrenToRender array
5710 if (exitBeforeEnter && exiting.size) {
5711 childrenToRender = [];
5712 }
5713 // Loop through all currently exiting components and clone them to overwrite `animate`
5714 // with any `exit` prop they might have defined.
5715 exiting.forEach(function (key) {
5716 // If this component is actually entering again, early return
5717 if (targetKeys.indexOf(key) !== -1)
5718 return;
5719 var child = allChildren.get(key);
5720 if (!child)
5721 return;
5722 var insertionIndex = presentKeys.indexOf(key);
5723 var onExit = function () {
5724 allChildren.delete(key);
5725 exiting.delete(key);
5726 // Remove this child from the present children
5727 var removeIndex = presentChildren.current.findIndex(function (presentChild) { return presentChild.key === key; });
5728 presentChildren.current.splice(removeIndex, 1);
5729 // Defer re-rendering until all exiting children have indeed left
5730 if (!exiting.size) {
5731 presentChildren.current = filteredChildren;
5732 forceRender();
5733 onExitComplete && onExitComplete();
5734 }
5735 };
5736 childrenToRender.splice(insertionIndex, 0, React.createElement(PresenceChild, { key: getChildKey(child), isPresent: false, onExitComplete: onExit, custom: custom }, child));
5737 });
5738 // Add `MotionContext` even to children that don't need it to ensure we're rendering
5739 // the same tree between renders
5740 childrenToRender = childrenToRender.map(function (child) {
5741 var key = child.key;
5742 return exiting.has(key) ? (child) : (React.createElement(PresenceChild, { key: getChildKey(child), isPresent: true }, child));
5743 });
5744 presentChildren.current = childrenToRender;
5745 if (process.env.NODE_ENV !== "production" &&
5746 exitBeforeEnter &&
5747 childrenToRender.length > 1) {
5748 console.warn("You're attempting to animate multiple children within AnimatePresence, but its exitBeforeEnter prop is set to true. This will lead to odd visual behaviour.");
5749 }
5750 return (React.createElement(React.Fragment, null, exiting.size
5751 ? childrenToRender
5752 : childrenToRender.map(function (child) { return React.cloneElement(child); })));
5753};
5754
5755function createSwitchAnimation(child, stack) {
5756 if (stack && child !== stack.lead) {
5757 return { visibilityAction: VisibilityAction.Hide };
5758 }
5759 else if (stack &&
5760 child.presence !== Presence.Entering &&
5761 child === stack.lead &&
5762 stack.lead !== stack.prevLead) {
5763 return { visibilityAction: VisibilityAction.Show };
5764 }
5765 var originBox;
5766 var targetBox;
5767 if (child.presence === Presence.Entering) {
5768 originBox = stack === null || stack === void 0 ? void 0 : stack.getFollowOrigin();
5769 }
5770 else if (child.presence === Presence.Exiting) {
5771 targetBox = stack === null || stack === void 0 ? void 0 : stack.getFollowTarget();
5772 }
5773 return { originBox: originBox, targetBox: targetBox };
5774}
5775function createCrossfadeAnimation(child, stack) {
5776 var _a, _b, _c;
5777 var config = {};
5778 var stackLead = stack && stack.lead;
5779 var stackLeadPresence = stackLead === null || stackLead === void 0 ? void 0 : stackLead.presence;
5780 if (stack && child === stackLead) {
5781 if (child.presence === Presence.Entering) {
5782 config.originBox = stack.getFollowOrigin();
5783 }
5784 else if (child.presence === Presence.Exiting) {
5785 config.targetBox = stack.getFollowTarget();
5786 }
5787 }
5788 else if (stack && child === stack.follow) {
5789 config.transition = stack.getLeadTransition();
5790 if (stackLeadPresence === Presence.Entering) {
5791 config.targetBox = stack.getLeadTarget();
5792 }
5793 else if (stackLeadPresence === Presence.Exiting) {
5794 config.originBox = stack.getLeadOrigin();
5795 }
5796 }
5797 // If neither the lead or follow component is the root child of AnimatePresence,
5798 // don't handle crossfade animations
5799 if (!((_a = stack === null || stack === void 0 ? void 0 : stack.follow) === null || _a === void 0 ? void 0 : _a.isPresenceRoot) && !(stackLead === null || stackLead === void 0 ? void 0 : stackLead.isPresenceRoot)) {
5800 return config;
5801 }
5802 if (!stack || child === stackLead) {
5803 if (child.presence === Presence.Entering) {
5804 config.crossfadeOpacity = (_b = stack === null || stack === void 0 ? void 0 : stack.follow) === null || _b === void 0 ? void 0 : _b.getValue("opacity", 0);
5805 }
5806 }
5807 else if (stack && child === stack.follow) {
5808 if (!stackLead || stackLeadPresence === Presence.Entering) ;
5809 else if (stackLeadPresence === Presence.Exiting) {
5810 config.crossfadeOpacity = (_c = stack === null || stack === void 0 ? void 0 : stack.lead) === null || _c === void 0 ? void 0 : _c.getValue("opacity", 1);
5811 }
5812 }
5813 else {
5814 config.visibilityAction = VisibilityAction.Hide;
5815 }
5816 return config;
5817}
5818
5819/**
5820 * For each layout animation, we want to identify two components
5821 * within a stack that will serve as the "lead" and "follow" components.
5822 *
5823 * In the switch animation, the lead component performs the entire animation.
5824 * It uses the follow bounding box to animate out from and back to. The follow
5825 * component is hidden.
5826 *
5827 * In the crossfade animation, both the lead and follow components perform
5828 * the entire animation, animating from the follow origin bounding box to the lead
5829 * target bounding box.
5830 *
5831 * Generalising a stack as First In Last Out, *searching from the end* we can
5832 * generally consider the lead component to be:
5833 * - If the last child is present, the last child
5834 * - If the last child is exiting, the last *encountered* exiting component
5835 */
5836function findLeadAndFollow(stack, _a) {
5837 var prevLead = _a[0], prevFollow = _a[1];
5838 var lead = undefined;
5839 var leadIndex = 0;
5840 var follow = undefined;
5841 // Find the lead child first
5842 var numInStack = stack.length;
5843 var lastIsPresent = false;
5844 for (var i = numInStack - 1; i >= 0; i--) {
5845 var child = stack[i];
5846 var isLastInStack = i === numInStack - 1;
5847 if (isLastInStack)
5848 lastIsPresent = child.isPresent;
5849 if (lastIsPresent) {
5850 lead = child;
5851 }
5852 else {
5853 // If the child before this will be present, make this the
5854 // lead.
5855 var prev = stack[i - 1];
5856 if (prev && prev.isPresent)
5857 lead = child;
5858 }
5859 if (lead) {
5860 leadIndex = i;
5861 break;
5862 }
5863 }
5864 if (!lead)
5865 lead = stack[0];
5866 // Find the follow child
5867 follow = stack[leadIndex - 1];
5868 // If the lead component is exiting, find the closest follow
5869 // present component
5870 if (lead) {
5871 for (var i = leadIndex - 1; i >= 0; i--) {
5872 var child = stack[i];
5873 if (child.isPresent) {
5874 follow = child;
5875 break;
5876 }
5877 }
5878 }
5879 // If the lead has changed and the previous lead still exists in the
5880 // stack, set it to the previous lead. This allows us to differentiate between
5881 // a, b, c(exit) -> a, b(exit), c(exit)
5882 // and
5883 // a, b(exit), c -> a, b(exit), c(exit)
5884 if (lead !== prevLead &&
5885 !lastIsPresent &&
5886 follow === prevFollow &&
5887 stack.find(function (stackChild) { return stackChild === prevLead; })) {
5888 lead = prevLead;
5889 }
5890 return [lead, follow];
5891}
5892var LayoutStack = /** @class */ (function () {
5893 function LayoutStack() {
5894 this.order = [];
5895 // Track whether we've ever had a child
5896 this.hasChildren = false;
5897 }
5898 LayoutStack.prototype.add = function (child) {
5899 var _a;
5900 var layoutOrder = child.config.layoutOrder;
5901 if (layoutOrder === undefined) {
5902 this.order.push(child);
5903 }
5904 else {
5905 var index = this.order.findIndex(function (stackChild) {
5906 return layoutOrder <= (stackChild.config.layoutOrder || 0);
5907 });
5908 if (index === -1) {
5909 child.presence = this.hasChildren
5910 ? Presence.Entering
5911 : Presence.Present;
5912 index = this.order.length;
5913 }
5914 this.order.splice(index, 0, child);
5915 }
5916 /**
5917 *
5918 */
5919 // Load previous values from snapshot into this child
5920 // TODO Neaten up
5921 // TODO Double check when reimplementing move
5922 // TODO Add isDragging status and
5923 if (this.snapshot) {
5924 child.prevSnapshot = this.snapshot;
5925 // TODO Remove in favour of above
5926 child.prevViewportBox = this.snapshot.boundingBox;
5927 var latest = this.snapshot.latestMotionValues;
5928 for (var key in latest) {
5929 if (!child.hasValue(key)) {
5930 child.addValue(key, motionValue(latest[key]));
5931 }
5932 else {
5933 (_a = child.getValue(key)) === null || _a === void 0 ? void 0 : _a.set(latest[key]);
5934 }
5935 }
5936 }
5937 this.hasChildren = true;
5938 };
5939 LayoutStack.prototype.remove = function (child) {
5940 var index = this.order.findIndex(function (stackChild) { return child === stackChild; });
5941 if (index !== -1)
5942 this.order.splice(index, 1);
5943 };
5944 LayoutStack.prototype.updateLeadAndFollow = function () {
5945 this.prevLead = this.lead;
5946 this.prevFollow = this.follow;
5947 var _a = findLeadAndFollow(this.order, [
5948 this.lead,
5949 this.follow,
5950 ]), lead = _a[0], follow = _a[1];
5951 this.lead = lead;
5952 this.follow = follow;
5953 };
5954 LayoutStack.prototype.updateSnapshot = function () {
5955 if (!this.lead)
5956 return;
5957 var snapshot = {
5958 boundingBox: this.lead.prevViewportBox,
5959 latestMotionValues: {},
5960 };
5961 this.lead.forEachValue(function (value, key) {
5962 var latest = value.get();
5963 if (!isTransformProp(latest)) {
5964 snapshot.latestMotionValues[key] = latest;
5965 }
5966 });
5967 var dragControls = elementDragControls.get(this.lead);
5968 if (dragControls && dragControls.isDragging) {
5969 snapshot.isDragging = true;
5970 snapshot.cursorProgress = dragControls.cursorProgress;
5971 }
5972 this.snapshot = snapshot;
5973 };
5974 LayoutStack.prototype.isLeadPresent = function () {
5975 var _a;
5976 return this.lead && ((_a = this.lead) === null || _a === void 0 ? void 0 : _a.presence) !== Presence.Exiting;
5977 };
5978 LayoutStack.prototype.shouldStackAnimate = function () {
5979 return true;
5980 // return this.lead && this.lead?.isPresent
5981 // ? this.lead?.props?._shouldAnimate === true
5982 // : this.follow && this.follow?.props._shouldAnimate === true
5983 };
5984 LayoutStack.prototype.getFollowOrigin = function () {
5985 var _a;
5986 // This shouldAnimate check is quite specifically a fix for the optimisation made in Framer
5987 // where components are kept in the tree ready to be re-used
5988 return this.follow // && this.follow.shouldAnimate
5989 ? this.follow.prevViewportBox
5990 : (_a = this.snapshot) === null || _a === void 0 ? void 0 : _a.boundingBox;
5991 };
5992 LayoutStack.prototype.getFollowTarget = function () {
5993 var _a;
5994 return (_a = this.follow) === null || _a === void 0 ? void 0 : _a.box;
5995 };
5996 LayoutStack.prototype.getLeadOrigin = function () {
5997 var _a;
5998 return (_a = this.lead) === null || _a === void 0 ? void 0 : _a.prevViewportBox;
5999 };
6000 LayoutStack.prototype.getLeadTarget = function () {
6001 var _a;
6002 return (_a = this.lead) === null || _a === void 0 ? void 0 : _a.box;
6003 };
6004 LayoutStack.prototype.getLeadTransition = function () {
6005 var _a;
6006 return (_a = this.lead) === null || _a === void 0 ? void 0 : _a.config.transition;
6007 };
6008 return LayoutStack;
6009}());
6010
6011/**
6012 * @public
6013 */
6014var AnimateSharedLayout = /** @class */ (function (_super) {
6015 tslib.__extends(AnimateSharedLayout, _super);
6016 function AnimateSharedLayout() {
6017 var _this = _super !== null && _super.apply(this, arguments) || this;
6018 /**
6019 * A list of all the children in the shared layout
6020 */
6021 _this.children = new Set();
6022 /**
6023 * As animate components with a defined `layoutId` are added/removed to the tree,
6024 * we store them in order. When one is added, it will animate out from the
6025 * previous one, and when it's removed, it'll animate to the previous one.
6026 */
6027 _this.stacks = new Map();
6028 /**
6029 * Track whether the component has mounted. If it hasn't, the presence of added children
6030 * are set to Present, whereas if it has they're considered Entering
6031 */
6032 _this.hasMounted = false;
6033 /**
6034 * Track whether we already have an update scheduled. If we don't, we'll run snapshots
6035 * and schedule one.
6036 */
6037 _this.updateScheduled = false;
6038 /**
6039 * Tracks whether we already have a render scheduled. If we don't, we'll force one with this.forceRender
6040 */
6041 _this.renderScheduled = false;
6042 /**
6043 * The methods provided to all children in the shared layout tree.
6044 */
6045 _this.syncContext = tslib.__assign(tslib.__assign({}, createBatcher()), { syncUpdate: function (force) { return _this.scheduleUpdate(force); }, forceUpdate: function () {
6046 // By copying syncContext to itself, when this component re-renders it'll also re-render
6047 // all children subscribed to the SharedLayout context.
6048 _this.syncContext = tslib.__assign({}, _this.syncContext);
6049 _this.scheduleUpdate(true);
6050 }, register: function (child) { return _this.addChild(child); }, remove: function (child) { return _this.removeChild(child); } });
6051 return _this;
6052 }
6053 AnimateSharedLayout.prototype.componentDidMount = function () {
6054 this.hasMounted = true;
6055 this.updateStacks();
6056 };
6057 AnimateSharedLayout.prototype.componentDidUpdate = function () {
6058 this.startLayoutAnimation();
6059 };
6060 AnimateSharedLayout.prototype.shouldComponentUpdate = function () {
6061 this.renderScheduled = true;
6062 return true;
6063 };
6064 AnimateSharedLayout.prototype.startLayoutAnimation = function () {
6065 var _this = this;
6066 /**
6067 * Reset update and render scheduled status
6068 */
6069 this.renderScheduled = this.updateScheduled = false;
6070 var type = this.props.type;
6071 /**
6072 * Update presence metadata based on the latest AnimatePresence status.
6073 * This is a kind of goofy way of dealing with this, perhaps there's a better model to find.
6074 */
6075 this.children.forEach(function (child) {
6076 if (!child.isPresent) {
6077 child.presence = Presence.Exiting;
6078 }
6079 else if (child.presence !== Presence.Entering) {
6080 child.presence =
6081 child.presence === Presence.Exiting
6082 ? Presence.Entering
6083 : Presence.Present;
6084 }
6085 });
6086 /**
6087 * In every layoutId stack, nominate a component to lead the animation and another
6088 * to follow
6089 */
6090 this.updateStacks();
6091 /**
6092 * Decide which animation to use between shared layoutId components
6093 */
6094 var createAnimation = type === "crossfade"
6095 ? createCrossfadeAnimation
6096 : createSwitchAnimation;
6097 /**
6098 * Create a handler which we can use to flush the children animations
6099 */
6100 var handler = {
6101 measureLayout: function (child) { return child.measureLayout(); },
6102 layoutReady: function (child) {
6103 var layoutId = child.layoutId;
6104 child.layoutReady(createAnimation(child, _this.getStack(layoutId)));
6105 },
6106 };
6107 /**
6108 * Shared layout animations can be used without the AnimateSharedLayout wrapping component.
6109 * This requires some co-ordination across components to stop layout thrashing
6110 * and ensure measurements are taken at the correct time.
6111 *
6112 * Here we use that same mechanism of schedule/flush.
6113 */
6114 this.children.forEach(function (child) { return _this.syncContext.add(child); });
6115 this.syncContext.flush(handler);
6116 /**
6117 * Clear snapshots so subsequent rerenders don't retain memory of outgoing components
6118 */
6119 this.stacks.forEach(function (stack) { return (stack.snapshot = undefined); });
6120 };
6121 AnimateSharedLayout.prototype.updateStacks = function () {
6122 this.stacks.forEach(function (stack) { return stack.updateLeadAndFollow(); });
6123 };
6124 AnimateSharedLayout.prototype.scheduleUpdate = function (force) {
6125 if (force === void 0) { force = false; }
6126 if (!(force || !this.updateScheduled))
6127 return;
6128 /**
6129 * Flag we've scheduled an update
6130 */
6131 this.updateScheduled = true;
6132 /**
6133 * Snapshot children
6134 */
6135 this.children.forEach(function (child) { return child.snapshotBoundingBox(); });
6136 /**
6137 * Every child keeps a local snapshot, but we also want to record
6138 * snapshots of the visible children as, if they're are being removed
6139 * in this render, we can still access them.
6140 */
6141 this.stacks.forEach(function (stack) { return stack.updateSnapshot(); });
6142 /**
6143 * Force a rerender by setting state if we aren't already going to render.
6144 */
6145 if (force || !this.renderScheduled) {
6146 this.renderScheduled = true;
6147 this.forceUpdate();
6148 }
6149 };
6150 AnimateSharedLayout.prototype.addChild = function (child) {
6151 this.children.add(child);
6152 this.addToStack(child);
6153 child.presence = this.hasMounted ? Presence.Entering : Presence.Present;
6154 };
6155 AnimateSharedLayout.prototype.removeChild = function (child) {
6156 this.scheduleUpdate();
6157 this.children.delete(child);
6158 this.removeFromStack(child);
6159 };
6160 AnimateSharedLayout.prototype.addToStack = function (child) {
6161 var stack = this.getStack(child.layoutId);
6162 stack === null || stack === void 0 ? void 0 : stack.add(child);
6163 };
6164 AnimateSharedLayout.prototype.removeFromStack = function (child) {
6165 var stack = this.getStack(child.layoutId);
6166 stack === null || stack === void 0 ? void 0 : stack.remove(child);
6167 };
6168 /**
6169 * Return a stack of animate children based on the provided layoutId.
6170 * Will create a stack if none currently exists with that layoutId.
6171 */
6172 AnimateSharedLayout.prototype.getStack = function (id) {
6173 if (id === undefined)
6174 return;
6175 // Create stack if it doesn't already exist
6176 !this.stacks.has(id) && this.stacks.set(id, new LayoutStack());
6177 return this.stacks.get(id);
6178 };
6179 AnimateSharedLayout.prototype.render = function () {
6180 return (React.createElement(SharedLayoutContext.Provider, { value: this.syncContext }, this.props.children));
6181 };
6182 return AnimateSharedLayout;
6183}(React.Component));
6184
6185/**
6186 * Creates a `MotionValue` to track the state and velocity of a value.
6187 *
6188 * Usually, these are created automatically. For advanced use-cases, like use with `useTransform`, you can create `MotionValue`s externally and pass them into the animated component via the `style` prop.
6189 *
6190 * @library
6191 *
6192 * ```jsx
6193 * export function MyComponent() {
6194 * const scale = useMotionValue(1)
6195 *
6196 * return <Frame scale={scale} />
6197 * }
6198 * ```
6199 *
6200 * @motion
6201 *
6202 * ```jsx
6203 * export const MyComponent = () => {
6204 * const scale = useMotionValue(1)
6205 *
6206 * return <motion.div style={{ scale }} />
6207 * }
6208 * ```
6209 *
6210 * @param initial - The initial state.
6211 *
6212 * @public
6213 */
6214function useMotionValue(initial) {
6215 return useConstant(function () { return motionValue(initial); });
6216}
6217
6218/**
6219 * If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself
6220 *
6221 * TODO: Remove and move to library
6222 *
6223 * @internal
6224 */
6225function resolveMotionValue(value) {
6226 var unwrappedValue = value instanceof MotionValue ? value.get() : value;
6227 return isCustomValue(unwrappedValue)
6228 ? unwrappedValue.toValue()
6229 : unwrappedValue;
6230}
6231
6232var isCustomValueType = function (v) {
6233 return typeof v === "object" && v.mix;
6234};
6235var getMixer = function (v) { return (isCustomValueType(v) ? v.mix : undefined); };
6236function transform() {
6237 var args = [];
6238 for (var _i = 0; _i < arguments.length; _i++) {
6239 args[_i] = arguments[_i];
6240 }
6241 var useImmediate = !Array.isArray(args[0]);
6242 var argOffset = useImmediate ? 0 : -1;
6243 var inputValue = args[0 + argOffset];
6244 var inputRange = args[1 + argOffset];
6245 var outputRange = args[2 + argOffset];
6246 var options = args[3 + argOffset];
6247 var interpolator = popcorn.interpolate(inputRange, outputRange, tslib.__assign({ mixer: getMixer(outputRange[0]) }, options));
6248 return useImmediate ? interpolator(inputValue) : interpolator;
6249}
6250
6251var isTransformer = function (v) {
6252 return typeof v === "function";
6253};
6254function useTransform(parent, customTransform, to, options) {
6255 var comparitor = isTransformer(customTransform)
6256 ? [parent]
6257 : [parent, customTransform.join(","), to === null || to === void 0 ? void 0 : to.join(",")];
6258 var transformer = React.useMemo(function () {
6259 return isTransformer(customTransform)
6260 ? customTransform
6261 : transform(customTransform, to, options);
6262 }, comparitor);
6263 var initialValue = transformer(parent.get());
6264 var value = useMotionValue(initialValue);
6265 // Handle subscription to parent
6266 var unsubscribe = React.useRef();
6267 React.useMemo(function () {
6268 unsubscribe.current && unsubscribe.current();
6269 unsubscribe.current = parent.onChange(function (v) { return value.set(transformer(v)); });
6270 // Manually set with the latest parent value in case we've re-parented
6271 value.set(initialValue);
6272 }, [parent, value, transformer]);
6273 useUnmountEffect(function () { return unsubscribe.current && unsubscribe.current(); });
6274 return value;
6275}
6276
6277// Keep things reasonable and avoid scale: Infinity. In practise we might need
6278// to add another value, opacity, that could interpolate scaleX/Y [0,0.01] => [0,1]
6279// to simply hide content at unreasonable scales.
6280var maxScale = 100000;
6281var invertScale = function (scale) {
6282 return scale > 0.001 ? 1 / scale : maxScale;
6283};
6284/**
6285 * Returns a `MotionValue` each for `scaleX` and `scaleY` that update with the inverse
6286 * of their respective parent scales.
6287 *
6288 * This is useful for undoing the distortion of content when scaling a parent component.
6289 *
6290 * By default, `useInvertedScale` will automatically fetch `scaleX` and `scaleY` from the nearest parent.
6291 * By passing other `MotionValue`s in as `useInvertedScale({ scaleX, scaleY })`, it will invert the output
6292 * of those instead.
6293 *
6294 * @motion
6295 *
6296 * ```jsx
6297 * const MyComponent = () => {
6298 * const { scaleX, scaleY } = useInvertedScale()
6299 * return <motion.div style={{ scaleX, scaleY }} />
6300 * }
6301 * ```
6302 *
6303 * @library
6304 *
6305 * ```jsx
6306 * function MyComponent() {
6307 * const { scaleX, scaleY } = useInvertedScale()
6308 * return <Frame scaleX={scaleX} scaleY={scaleY} />
6309 * }
6310 * ```
6311 *
6312 * @public
6313 */
6314function useInvertedScale(scale) {
6315 var parentScaleX = useMotionValue(1);
6316 var parentScaleY = useMotionValue(1);
6317 var visualElement = React.useContext(MotionContext).visualElement;
6318 heyListen.invariant(!!(scale || visualElement), "If no scale values are provided, useInvertedScale must be used within a child of another motion component.");
6319 if (scale) {
6320 parentScaleX = scale.scaleX || parentScaleX;
6321 parentScaleY = scale.scaleY || parentScaleY;
6322 }
6323 else if (visualElement) {
6324 parentScaleX = visualElement.getValue("scaleX", 1);
6325 parentScaleY = visualElement.getValue("scaleY", 1);
6326 }
6327 var scaleX = useTransform(parentScaleX, invertScale);
6328 var scaleY = useTransform(parentScaleY, invertScale);
6329 return { scaleX: scaleX, scaleY: scaleY };
6330}
6331
6332function useOnChange(value, callback) {
6333 React.useEffect(function () { return (isMotionValue(value) ? value.onChange(callback) : undefined); }, [value]);
6334}
6335
6336/**
6337 * Creates a `MotionValue` that, when `set`, will use a spring animation to animate to its new state.
6338 *
6339 * It can either work as a stand-alone `MotionValue` by initialising it with a value, or as a subscriber
6340 * to another `MotionValue`.
6341 *
6342 * @remarks
6343 *
6344 * ```jsx
6345 * const x = useSpring(0, { stiffness: 300 })
6346 * const y = useSpring(x, { damping: 10 })
6347 * ```
6348 *
6349 * @param inputValue - `MotionValue` or number. If provided a `MotionValue`, when the input `MotionValue` changes, the created `MotionValue` will spring towards that value.
6350 * @param springConfig - Configuration options for the spring.
6351 * @returns `MotionValue`
6352 *
6353 * @public
6354 */
6355function useSpring(source, config) {
6356 if (config === void 0) { config = {}; }
6357 var activeSpringAnimation = React.useRef(null);
6358 var value = useMotionValue(isMotionValue(source) ? source.get() : source);
6359 React.useMemo(function () {
6360 return value.attach(function (v, set) {
6361 if (activeSpringAnimation.current) {
6362 activeSpringAnimation.current.stop();
6363 }
6364 activeSpringAnimation.current = popmotion.spring(tslib.__assign({ from: value.get(), to: v, velocity: value.getVelocity() }, config)).start(set);
6365 return value.get();
6366 });
6367 }, Object.values(config));
6368 useOnChange(source, function (v) { return value.set(parseFloat(v)); });
6369 return value;
6370}
6371
6372function createScrollMotionValues() {
6373 return {
6374 scrollX: motionValue(0),
6375 scrollY: motionValue(0),
6376 scrollXProgress: motionValue(0),
6377 scrollYProgress: motionValue(0),
6378 };
6379}
6380function setProgress(offset, maxOffset, value) {
6381 value.set(!offset || !maxOffset ? 0 : offset / maxOffset);
6382}
6383function createScrollUpdater(values, getOffsets) {
6384 var update = function () {
6385 var _a = getOffsets(), xOffset = _a.xOffset, yOffset = _a.yOffset, xMaxOffset = _a.xMaxOffset, yMaxOffset = _a.yMaxOffset;
6386 // Set absolute positions
6387 values.scrollX.set(xOffset);
6388 values.scrollY.set(yOffset);
6389 // Set 0-1 progress
6390 setProgress(xOffset, xMaxOffset, values.scrollXProgress);
6391 setProgress(yOffset, yMaxOffset, values.scrollYProgress);
6392 };
6393 update();
6394 return update;
6395}
6396
6397var isBrowser$2 = typeof window !== "undefined";
6398var useIsomorphicLayoutEffect = isBrowser$2 ? React.useLayoutEffect : React.useEffect;
6399
6400var getElementScrollOffsets = function (element) { return function () {
6401 return {
6402 xOffset: element.scrollLeft,
6403 yOffset: element.scrollTop,
6404 xMaxOffset: element.scrollWidth - element.offsetWidth,
6405 yMaxOffset: element.scrollHeight - element.offsetHeight,
6406 };
6407}; };
6408/**
6409 * Returns MotionValues that update when the provided element scrolls:
6410 *
6411 * - `scrollX` — Horizontal scroll distance in pixels.
6412 * - `scrollY` — Vertical scroll distance in pixels.
6413 * - `scrollXProgress` — Horizontal scroll progress between `0` and `1`.
6414 * - `scrollYProgress` — Vertical scroll progress between `0` and `1`.
6415 *
6416 * This element must be set to `overflow: scroll` on either or both axes to report scroll offset.
6417 *
6418 * @library
6419 *
6420 * ```jsx
6421 * import * as React from "react"
6422 * import {
6423 * Frame,
6424 * useElementScroll,
6425 * useTransform
6426 * } from "framer"
6427 *
6428 * export function MyComponent() {
6429 * const ref = React.useRef()
6430 * const { scrollYProgress } = useElementScroll(ref)
6431 *
6432 * return (
6433 * <Frame ref={ref}>
6434 * <Frame scaleX={scrollYProgress} />
6435 * </Frame>
6436 * )
6437 * }
6438 * ```
6439 *
6440 * @motion
6441 *
6442 * ```jsx
6443 * export const MyComponent = () => {
6444 * const ref = useRef()
6445 * const { scrollYProgress } = useElementScroll(ref)
6446 *
6447 * return (
6448 * <div ref={ref}>
6449 * <motion.div style={{ scaleX: scrollYProgress }} />
6450 * </div>
6451 * )
6452 * }
6453 * ```
6454 *
6455 * @public
6456 */
6457function useElementScroll(ref) {
6458 var values = useConstant(createScrollMotionValues);
6459 useIsomorphicLayoutEffect(function () {
6460 var element = ref.current;
6461 heyListen.invariant(!!element, "ref provided to useScroll must be passed into a HTML element.");
6462 if (!element)
6463 return;
6464 var updateScrollValues = createScrollUpdater(values, getElementScrollOffsets(element));
6465 var scrollListener = addDomEvent(element, "scroll", updateScrollValues, { passive: true });
6466 var resizeListener = addDomEvent(element, "resize", updateScrollValues);
6467 return function () {
6468 scrollListener && scrollListener();
6469 resizeListener && resizeListener();
6470 };
6471 }, []);
6472 return values;
6473}
6474
6475var viewportScrollValues = createScrollMotionValues();
6476function getViewportScrollOffsets() {
6477 return {
6478 xOffset: window.pageXOffset,
6479 yOffset: window.pageYOffset,
6480 xMaxOffset: document.body.clientWidth - window.innerWidth,
6481 yMaxOffset: document.body.clientHeight - window.innerHeight,
6482 };
6483}
6484var hasListeners = false;
6485function addEventListeners() {
6486 hasListeners = true;
6487 if (typeof window === "undefined")
6488 return;
6489 var updateScrollValues = createScrollUpdater(viewportScrollValues, getViewportScrollOffsets);
6490 addDomEvent(window, "scroll", updateScrollValues, { passive: true });
6491 addDomEvent(window, "resize", updateScrollValues);
6492}
6493/**
6494 * Returns MotionValues that update when the viewport scrolls:
6495 *
6496 * - `scrollX` — Horizontal scroll distance in pixels.
6497 * - `scrollY` — Vertical scroll distance in pixels.
6498 * - `scrollXProgress` — Horizontal scroll progress between `0` and `1`.
6499 * - `scrollYProgress` — Vertical scroll progress between `0` and `1`.
6500 *
6501 * @library
6502 *
6503 * ```jsx
6504 * import * as React from "react"
6505 * import {
6506 * Frame,
6507 * useViewportScroll,
6508 * useTransform
6509 * } from "framer"
6510 *
6511 * export function MyComponent() {
6512 * const { scrollYProgress } = useViewportScroll()
6513 * return <Frame scaleX={scrollYProgress} />
6514 * }
6515 * ```
6516 *
6517 * @motion
6518 *
6519 * ```jsx
6520 * export const MyComponent = () => {
6521 * const { scrollYProgress } = useViewportScroll()
6522 * return <motion.div style={{ scaleX: scrollYProgress }} />
6523 * }
6524 * ```
6525 *
6526 * @public
6527 */
6528function useViewportScroll() {
6529 useIsomorphicLayoutEffect(function () {
6530 !hasListeners && addEventListeners();
6531 }, []);
6532 return viewportScrollValues;
6533}
6534
6535/**
6536 * Creates `AnimationControls`, which can be used to manually start, stop
6537 * and sequence animations on one or more components.
6538 *
6539 * The returned `AnimationControls` should be passed to the `animate` property
6540 * of the components you want to animate.
6541 *
6542 * These components can then be animated with the `start` method.
6543 *
6544 * @library
6545 *
6546 * ```jsx
6547 * import * as React from 'react'
6548 * import { Frame, useAnimation } from 'framer'
6549 *
6550 * export function MyComponent(props) {
6551 * const controls = useAnimation()
6552 *
6553 * controls.start({
6554 * x: 100,
6555 * transition: { duration: 0.5 },
6556 * })
6557 *
6558 * return <Frame animate={controls} />
6559 * }
6560 * ```
6561 *
6562 * @motion
6563 *
6564 * ```jsx
6565 * import * as React from 'react'
6566 * import { motion, useAnimation } from 'framer-motion'
6567 *
6568 * export function MyComponent(props) {
6569 * const controls = useAnimation()
6570 *
6571 * controls.start({
6572 * x: 100,
6573 * transition: { duration: 0.5 },
6574 * })
6575 *
6576 * return <motion.div animate={controls} />
6577 * }
6578 * ```
6579 *
6580 * @returns Animation controller with `start` and `stop` methods
6581 *
6582 * @public
6583 */
6584function useAnimation() {
6585 var animationControls = useConstant(function () { return new AnimationControls(); });
6586 React.useEffect(function () {
6587 animationControls.mount();
6588 return function () { return animationControls.unmount(); };
6589 }, []);
6590 return animationControls;
6591}
6592
6593/**
6594 * Cycles through a series of visual properties. Can be used to toggle between or cycle through animations. It works similar to `useState` in React. It is provided an initial array of possible states, and returns an array of two arguments.
6595 *
6596 * @library
6597 *
6598 * ```jsx
6599 * import * as React from "react"
6600 * import { Frame, useCycle } from "framer"
6601 *
6602 * export function MyComponent() {
6603 * const [x, cycleX] = useCycle(0, 50, 100)
6604 *
6605 * return (
6606 * <Frame
6607 * animate={{ x: x }}
6608 * onTap={() => cycleX()}
6609 * />
6610 * )
6611 * }
6612 * ```
6613 *
6614 * @motion
6615 *
6616 * An index value can be passed to the returned `cycle` function to cycle to a specific index.
6617 *
6618 * ```jsx
6619 * import * as React from "react"
6620 * import { motion, useCycle } from "framer-motion"
6621 *
6622 * export const MyComponent = () => {
6623 * const [x, cycleX] = useCycle(0, 50, 100)
6624 *
6625 * return (
6626 * <motion.div
6627 * animate={{ x: x }}
6628 * onTap={() => cycleX()}
6629 * />
6630 * )
6631 * }
6632 * ```
6633 *
6634 * @param items - items to cycle through
6635 * @returns [currentState, cycleState]
6636 *
6637 * @public
6638 */
6639function useCycle() {
6640 var items = [];
6641 for (var _i = 0; _i < arguments.length; _i++) {
6642 items[_i] = arguments[_i];
6643 }
6644 // TODO: After Framer X beta, remove this warning
6645 heyListen.warning(items.length > 1, "useCycle syntax has changed. `useCycle([0, 1, 2])` becomes `useCycle(0, 1, 2)`");
6646 var index = React.useRef(0);
6647 var _a = React.useState(items[index.current]), item = _a[0], setItem = _a[1];
6648 return [
6649 item,
6650 function (next) {
6651 index.current =
6652 typeof next !== "number"
6653 ? popcorn.wrap(0, items.length, index.current + 1)
6654 : next;
6655 setItem(items[index.current]);
6656 },
6657 ];
6658}
6659
6660// Does this device prefer reduced motion? Returns `null` server-side.
6661var prefersReducedMotion = motionValue(null);
6662if (typeof window !== "undefined") {
6663 if (window.matchMedia) {
6664 var motionMediaQuery_1 = window.matchMedia("(prefers-reduced-motion)");
6665 var setReducedMotionPreferences = function () {
6666 return prefersReducedMotion.set(motionMediaQuery_1.matches);
6667 };
6668 motionMediaQuery_1.addListener(setReducedMotionPreferences);
6669 setReducedMotionPreferences();
6670 }
6671 else {
6672 prefersReducedMotion.set(false);
6673 }
6674}
6675function determineShouldReduceMotion(prefersReduced, isReducedMotion) {
6676 return typeof isReducedMotion === "boolean"
6677 ? isReducedMotion
6678 : Boolean(prefersReduced);
6679}
6680/**
6681 * A hook that returns `true` if we should be using reduced motion based on the current device's Reduced Motion setting.
6682 *
6683 * This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing motion-sickness inducing
6684 * `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion.
6685 *
6686 * It will actively respond to changes and re-render your components with the latest setting.
6687 *
6688 * ```jsx
6689 * export function Sidebar({ isOpen }) {
6690 * const shouldReduceMotion = useReducedMotion()
6691 * const closedX = shouldReduceMotion ? 0 : "-100%"
6692 *
6693 * return (
6694 * <motion.div animate={{
6695 * opacity: isOpen ? 1 : 0,
6696 * x: isOpen ? 0 : closedX
6697 * }} />
6698 * )
6699 * }
6700 * ```
6701 *
6702 * @return boolean
6703 *
6704 * @public
6705 */
6706function useReducedMotion() {
6707 var isReducedMotion = React.useContext(MotionContext).isReducedMotion;
6708 var _a = React.useState(determineShouldReduceMotion(prefersReducedMotion.get(), isReducedMotion)), shouldReduceMotion = _a[0], setShouldReduceMotion = _a[1];
6709 React.useEffect(function () {
6710 return prefersReducedMotion.onChange(function (v) {
6711 setShouldReduceMotion(determineShouldReduceMotion(v, isReducedMotion));
6712 });
6713 }, [setShouldReduceMotion, isReducedMotion]);
6714 return shouldReduceMotion;
6715}
6716
6717/**
6718 * Define accessibility options for a tree. Can be used to force the tree into Reduced Motion mode,
6719 * or disable device detection.
6720 *
6721 * @internal
6722 */
6723function ReducedMotion(_a) {
6724 var children = _a.children, enabled = _a.enabled;
6725 var context = React.useContext(MotionContext);
6726 context = React.useMemo(function () { return (tslib.__assign(tslib.__assign({}, context), { isReducedMotion: enabled })); }, [enabled]);
6727 return (React.createElement(MotionContext.Provider, { value: context }, children));
6728}
6729
6730/**
6731 * Can manually trigger a drag gesture on one or more `drag`-enabled `motion` components.
6732 *
6733 * @library
6734 *
6735 * ```jsx
6736 * const dragControls = useDragControls()
6737 *
6738 * function startDrag(event) {
6739 * dragControls.start(event, { snapToCursor: true })
6740 * }
6741 *
6742 * return (
6743 * <>
6744 * <Frame onTapStart={startDrag} />
6745 * <Frame drag="x" dragControls={dragControls} />
6746 * </>
6747 * )
6748 * ```
6749 *
6750 * @motion
6751 *
6752 * ```jsx
6753 * const dragControls = useDragControls()
6754 *
6755 * function startDrag(event) {
6756 * dragControls.start(event, { snapToCursor: true })
6757 * }
6758 *
6759 * return (
6760 * <>
6761 * <div onMouseDown={startDrag} />
6762 * <motion.div drag="x" dragControls={dragControls} />
6763 * </>
6764 * )
6765 * ```
6766 *
6767 * @public
6768 */
6769var DragControls = /** @class */ (function () {
6770 function DragControls() {
6771 this.componentControls = new Set();
6772 }
6773 /**
6774 * Subscribe a component's internal `VisualElementDragControls` to the user-facing API.
6775 *
6776 * @internal
6777 */
6778 DragControls.prototype.subscribe = function (controls) {
6779 var _this = this;
6780 this.componentControls.add(controls);
6781 return function () { return _this.componentControls.delete(controls); };
6782 };
6783 /**
6784 * Start a drag gesture on every `motion` component that has this set of drag controls
6785 * passed into it via the `dragControls` prop.
6786 *
6787 * ```jsx
6788 * dragControls.start(e, {
6789 * snapToCursor: true
6790 * })
6791 * ```
6792 *
6793 * @param event - A mouse/touch/pointer event.
6794 * @param options - Options
6795 *
6796 * @public
6797 */
6798 DragControls.prototype.start = function (event, options) {
6799 this.componentControls.forEach(function (controls) {
6800 controls.start(event.nativeEvent || event, options);
6801 });
6802 };
6803 return DragControls;
6804}());
6805var createDragControls = function () { return new DragControls(); };
6806/**
6807 * Usually, dragging is initiated by pressing down on a `motion` component with a `drag` prop
6808 * and moving it. For some use-cases, for instance clicking at an arbitrary point on a video scrubber, we
6809 * might want to initiate that dragging from a different component than the draggable one.
6810 *
6811 * By creating a `dragControls` using the `useDragControls` hook, we can pass this into
6812 * the draggable component's `dragControls` prop. It exposes a `start` method
6813 * that can start dragging from pointer events on other components.
6814 *
6815 * @library
6816 *
6817 * ```jsx
6818 * const dragControls = useDragControls()
6819 *
6820 * function startDrag(event) {
6821 * dragControls.start(event, { snapToCursor: true })
6822 * }
6823 *
6824 * return (
6825 * <>
6826 * <Frame onTapStart={startDrag} />
6827 * <Frame drag="x" dragControls={dragControls} />
6828 * </>
6829 * )
6830 * ```
6831 *
6832 * @motion
6833 *
6834 * ```jsx
6835 * const dragControls = useDragControls()
6836 *
6837 * function startDrag(event) {
6838 * dragControls.start(event, { snapToCursor: true })
6839 * }
6840 *
6841 * return (
6842 * <>
6843 * <div onMouseDown={startDrag} />
6844 * <motion.div drag="x" dragControls={dragControls} />
6845 * </>
6846 * )
6847 * ```
6848 *
6849 * @public
6850 */
6851function useDragControls() {
6852 return useConstant(createDragControls);
6853}
6854
6855/**
6856 * Uses the ref that is passed in, or creates a new one
6857 * @param external - External ref
6858 * @internal
6859 */
6860function useExternalRef(externalRef) {
6861 // We're conditionally calling `useRef` here which is sort of naughty as hooks
6862 // shouldn't be called conditionally. However, Framer Motion will break if this
6863 // condition changes anyway. It might be possible to use an invariant here to
6864 // make it explicit, but I expect changing `ref` is not normal behaviour.
6865 var ref = !externalRef || typeof externalRef === "function"
6866 ? React.useRef(null)
6867 : externalRef;
6868 // Handle `ref` functions. Again, calling the hook conditionally is kind of naughty
6869 // but `ref` types changing between renders would break Motion anyway. If we receive
6870 // bug reports about this, we should track the provided ref and throw an invariant
6871 // rather than move the conditional to inside the useEffect as this will be fired
6872 // for every Frame component within Framer.
6873 if (externalRef && typeof externalRef === "function") {
6874 React.useEffect(function () {
6875 externalRef(ref.current);
6876 return function () { return externalRef(null); };
6877 }, []);
6878 }
6879 return ref;
6880}
6881
6882/**
6883 * This is just a very basic VisualElement, more of a hack to keep supporting useAnimatedState with
6884 * the latest APIs.
6885 */
6886var StateVisualElement = /** @class */ (function (_super) {
6887 tslib.__extends(StateVisualElement, _super);
6888 function StateVisualElement() {
6889 var _this = _super !== null && _super.apply(this, arguments) || this;
6890 _this.initialState = {};
6891 return _this;
6892 }
6893 StateVisualElement.prototype.updateLayoutDelta = function () { };
6894 StateVisualElement.prototype.build = function () { };
6895 StateVisualElement.prototype.clean = function () { };
6896 StateVisualElement.prototype.getBoundingBox = function () {
6897 return { x: { min: 0, max: 0 }, y: { min: 0, max: 0 } };
6898 };
6899 StateVisualElement.prototype.readNativeValue = function (key) {
6900 return this.initialState[key] || 0;
6901 };
6902 StateVisualElement.prototype.render = function () {
6903 this.build();
6904 };
6905 return StateVisualElement;
6906}(VisualElement));
6907/**
6908 * This is not an officially supported API and may be removed
6909 * on any version.
6910 * @internal
6911 */
6912function useAnimatedState(initialState) {
6913 var _a = React.useState(initialState), animationState = _a[0], setAnimationState = _a[1];
6914 var visualElement = useConstant(function () { return new StateVisualElement(); });
6915 visualElement.updateConfig({
6916 onUpdate: function (v) { return setAnimationState(tslib.__assign({}, v)); },
6917 });
6918 visualElement.initialState = initialState;
6919 var controls = useVisualElementAnimation(visualElement, {}, {});
6920 React.useEffect(function () {
6921 visualElement.mount({});
6922 return function () { return visualElement.unmount(); };
6923 }, []);
6924 var startAnimation = useConstant(function () { return function (animationDefinition) {
6925 return controls.start(animationDefinition);
6926 }; });
6927 return [animationState, startAnimation];
6928}
6929
6930exports.AnimateLayoutFeature = AnimateLayout;
6931exports.AnimatePresence = AnimatePresence;
6932exports.AnimateSharedLayout = AnimateSharedLayout;
6933exports.AnimationControls = AnimationControls;
6934exports.AnimationFeature = Animation;
6935exports.DragControls = DragControls;
6936exports.DragFeature = Drag;
6937exports.ExitFeature = Exit;
6938exports.GesturesFeature = Gestures;
6939exports.MotionConfig = MotionConfig;
6940exports.MotionConfigContext = MotionConfigContext;
6941exports.MotionContext = MotionContext;
6942exports.MotionValue = MotionValue;
6943exports.PresenceContext = PresenceContext;
6944exports.ReducedMotion = ReducedMotion;
6945exports.VisualElementAnimationControls = VisualElementAnimationControls;
6946exports.addScaleCorrection = addScaleCorrection;
6947exports.animationControls = animationControls;
6948exports.createMotionComponent = createMotionComponent;
6949exports.isValidMotionProp = isValidMotionProp;
6950exports.m = m;
6951exports.motion = motion;
6952exports.motionValue = motionValue;
6953exports.resolveMotionValue = resolveMotionValue;
6954exports.transform = transform;
6955exports.useAnimatedState = useAnimatedState;
6956exports.useAnimation = useAnimation;
6957exports.useCycle = useCycle;
6958exports.useDomEvent = useDomEvent;
6959exports.useDragControls = useDragControls;
6960exports.useElementScroll = useElementScroll;
6961exports.useExternalRef = useExternalRef;
6962exports.useGestures = useGestures;
6963exports.useInvertedScale = useInvertedScale;
6964exports.useIsPresent = useIsPresent;
6965exports.useMotionValue = useMotionValue;
6966exports.usePanGesture = usePanGesture;
6967exports.usePresence = usePresence;
6968exports.useReducedMotion = useReducedMotion;
6969exports.useSpring = useSpring;
6970exports.useTapGesture = useTapGesture;
6971exports.useTransform = useTransform;
6972exports.useViewportScroll = useViewportScroll;