UNPKG

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