UNPKG

193 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7var tslib = require('tslib');
8var React = require('react');
9var sync = require('framesync');
10var sync__default = _interopDefault(sync);
11var popcorn = require('@popmotion/popcorn');
12var styler = require('stylefire');
13var styler__default = _interopDefault(styler);
14var heyListen = require('hey-listen');
15var styleValueTypes = require('style-value-types');
16var popmotion = require('popmotion');
17var easingLookup = require('@popmotion/easing');
18
19var isFloat = function (value) {
20 return !isNaN(parseFloat(value));
21};
22/**
23 * `MotionValue` is used to track the state and velocity of motion values.
24 *
25 * @public
26 */
27var MotionValue = /** @class */ (function () {
28 /**
29 * @param init - The initiating value
30 * @param config - Optional configuration options
31 *
32 * - `transformer`: A function to transform incoming values with.
33 *
34 * @internal
35 */
36 function MotionValue(init, _a) {
37 var _this = this;
38 var _b = _a === void 0 ? {} : _a, transformer = _b.transformer, parent = _b.parent;
39 /**
40 * Duration, in milliseconds, since last updating frame.
41 *
42 * @internal
43 */
44 this.timeDelta = 0;
45 /**
46 * Timestamp of the last time this `MotionValue` was updated.
47 *
48 * @internal
49 */
50 this.lastUpdated = 0;
51 /**
52 * Tracks whether this value can output a velocity. Currently this is only true
53 * if the value is numerical, but we might be able to widen the scope here and support
54 * other value types.
55 *
56 * @internal
57 */
58 this.canTrackVelocity = false;
59 this.updateAndNotify = function (v, render) {
60 if (render === void 0) { render = true; }
61 _this.prev = _this.current;
62 _this.current = _this.transformer ? _this.transformer(v) : v;
63 if (_this.updateSubscribers && _this.prev !== _this.current) {
64 _this.updateSubscribers.forEach(_this.notifySubscriber);
65 }
66 if (_this.children) {
67 _this.children.forEach(_this.setChild);
68 }
69 if (render && _this.renderSubscribers) {
70 _this.renderSubscribers.forEach(_this.notifySubscriber);
71 }
72 // Update timestamp
73 var _a = sync.getFrameData(), delta = _a.delta, timestamp = _a.timestamp;
74 if (_this.lastUpdated !== timestamp) {
75 _this.timeDelta = delta;
76 _this.lastUpdated = timestamp;
77 sync__default.postRender(_this.scheduleVelocityCheck);
78 }
79 };
80 /**
81 * Notify a subscriber with the latest value.
82 *
83 * This is an instanced and bound function to prevent generating a new
84 * function once per frame.
85 *
86 * @param subscriber - The subscriber to notify.
87 *
88 * @internal
89 */
90 this.notifySubscriber = function (subscriber) {
91 subscriber(_this.current);
92 };
93 /**
94 * Schedule a velocity check for the next frame.
95 *
96 * This is an instanced and bound function to prevent generating a new
97 * function once per frame.
98 *
99 * @internal
100 */
101 this.scheduleVelocityCheck = function () { return sync__default.postRender(_this.velocityCheck); };
102 /**
103 * Updates `prev` with `current` if the value hasn't been updated this frame.
104 * This ensures velocity calculations return `0`.
105 *
106 * This is an instanced and bound function to prevent generating a new
107 * function once per frame.
108 *
109 * @internal
110 */
111 this.velocityCheck = function (_a) {
112 var timestamp = _a.timestamp;
113 if (timestamp !== _this.lastUpdated) {
114 _this.prev = _this.current;
115 }
116 };
117 /**
118 * Updates child `MotionValue`.
119 *
120 * @param child - Child `MotionValue`.
121 *
122 * @internal
123 */
124 this.setChild = function (child) { return child.set(_this.current); };
125 this.parent = parent;
126 this.transformer = transformer;
127 this.set(init, false);
128 this.canTrackVelocity = isFloat(this.current);
129 }
130 /**
131 * Creates a new `MotionValue` that's subscribed to the output of this one.
132 *
133 * @param config - Optional configuration options
134 *
135 * - `transformer`: A function to transform incoming values with.
136 *
137 * @internal
138 */
139 MotionValue.prototype.addChild = function (config) {
140 if (config === void 0) { config = {}; }
141 var child = new MotionValue(this.current, tslib.__assign({ parent: this }, config));
142 if (!this.children)
143 this.children = new Set();
144 this.children.add(child);
145 return child;
146 };
147 /**
148 * Stops a `MotionValue` from being subscribed to this one.
149 *
150 * @param child - The subscribed `MotionValue`
151 *
152 * @internal
153 */
154 MotionValue.prototype.removeChild = function (child) {
155 if (!this.children) {
156 return;
157 }
158 this.children.delete(child);
159 };
160 /**
161 * Subscribes a subscriber function to a subscription list.
162 *
163 * @param subscriptions - A `Set` of subscribers.
164 * @param subscription - A subscriber function.
165 */
166 MotionValue.prototype.subscribeTo = function (subscriptions, subscription) {
167 var _this = this;
168 var updateSubscriber = function () { return subscription(_this.current); };
169 subscriptions.add(updateSubscriber);
170 return function () { return subscriptions.delete(updateSubscriber); };
171 };
172 /**
173 * Adds a function that will be notified when the `MotionValue` is updated.
174 *
175 * It returns a function that, when called, will cancel the subscription.
176 *
177 * When calling `onChange` inside a React component, it should be wrapped with the
178 * `useEffect` hook. As it returns an unsubscribe function, this should be returned
179 * from the `useEffect` function to ensure you don't add duplicate subscribers..
180 *
181 * @library
182 *
183 * ```jsx
184 * function MyComponent() {
185 * const x = useMotionValue(0)
186 * const y = useMotionValue(0)
187 * const opacity = useMotionValue(1)
188 *
189 * useEffect(() => {
190 * function updateOpacity() {
191 * const maxXY = Math.max(x.get(), y.get())
192 * const newOpacity = transform(maxXY, [0, 100], [1, 0])
193 * opacity.set(newOpacity)
194 * }
195 *
196 * const unsubscribeX = x.onChange(updateOpacity)
197 * const unsubscribeY = y.onChange(updateOpacity)
198 *
199 * return () => {
200 * unsubscribeX()
201 * unsubscribeY()
202 * }
203 * }, [])
204 *
205 * return <Frame x={x} />
206 * }
207 * ```
208 *
209 * @motion
210 *
211 * ```jsx
212 * export const MyComponent = () => {
213 * const x = useMotionValue(0)
214 * const y = useMotionValue(0)
215 * const opacity = useMotionValue(1)
216 *
217 * useEffect(() => {
218 * function updateOpacity() {
219 * const maxXY = Math.max(x.get(), y.get())
220 * const newOpacity = transform(maxXY, [0, 100], [1, 0])
221 * opacity.set(newOpacity)
222 * }
223 *
224 * const unsubscribeX = x.onChange(updateOpacity)
225 * const unsubscribeY = y.onChange(updateOpacity)
226 *
227 * return () => {
228 * unsubscribeX()
229 * unsubscribeY()
230 * }
231 * }, [])
232 *
233 * return <motion.div style={{ x }} />
234 * }
235 * ```
236 *
237 * @internalremarks
238 *
239 * We could look into a `useOnChange` hook if the above lifecycle management proves confusing.
240 *
241 * ```jsx
242 * useOnChange(x, () => {})
243 * ```
244 *
245 * @param subscriber - A function that receives the latest value.
246 * @returns A function that, when called, will cancel this subscription.
247 *
248 * @public
249 */
250 MotionValue.prototype.onChange = function (subscription) {
251 if (!this.updateSubscribers)
252 this.updateSubscribers = new Set();
253 return this.subscribeTo(this.updateSubscribers, subscription);
254 };
255 /**
256 * Adds a function that will be notified when the `MotionValue` requests a render.
257 *
258 * @param subscriber - A function that's provided the latest value.
259 * @returns A function that, when called, will cancel this subscription.
260 *
261 * @internal
262 */
263 MotionValue.prototype.onRenderRequest = function (subscription) {
264 if (!this.renderSubscribers)
265 this.renderSubscribers = new Set();
266 // Render immediately
267 this.notifySubscriber(subscription);
268 return this.subscribeTo(this.renderSubscribers, subscription);
269 };
270 /**
271 * Attaches a passive effect to the `MotionValue`.
272 *
273 * @internal
274 */
275 MotionValue.prototype.attach = function (passiveEffect) {
276 this.passiveEffect = passiveEffect;
277 };
278 /**
279 * Sets the state of the `MotionValue`.
280 *
281 * @remarks
282 *
283 * ```jsx
284 * const x = useMotionValue(0)
285 * x.set(10)
286 * ```
287 *
288 * @param latest - Latest value to set.
289 * @param render - Whether to notify render subscribers. Defaults to `true`
290 *
291 * @public
292 */
293 MotionValue.prototype.set = function (v, render) {
294 if (render === void 0) { render = true; }
295 if (!render || !this.passiveEffect) {
296 this.updateAndNotify(v, render);
297 }
298 else {
299 this.passiveEffect(v, this.updateAndNotify);
300 }
301 };
302 /**
303 * Returns the latest state of `MotionValue`
304 *
305 * @returns - The latest state of `MotionValue`
306 *
307 * @public
308 */
309 MotionValue.prototype.get = function () {
310 return this.current;
311 };
312 /**
313 * Returns the latest velocity of `MotionValue`
314 *
315 * @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical.
316 *
317 * @public
318 */
319 MotionValue.prototype.getVelocity = function () {
320 // This could be isFloat(this.prev) && isFloat(this.current), but that would be wasteful
321 return this.canTrackVelocity
322 ? // These casts could be avoided if parseFloat would be typed better
323 popcorn.velocityPerSecond(parseFloat(this.current) -
324 parseFloat(this.prev), this.timeDelta)
325 : 0;
326 };
327 /**
328 * Registers a new animation to control this `MotionValue`. Only one
329 * animation can drive a `MotionValue` at one time.
330 *
331 * ```jsx
332 * value.start()
333 * ```
334 *
335 * @param animation - A function that starts the provided animation
336 *
337 * @internal
338 */
339 MotionValue.prototype.start = function (animation) {
340 var _this = this;
341 this.stop();
342 return new Promise(function (resolve) {
343 _this.stopAnimation = animation(resolve);
344 }).then(function () { return _this.clearAnimation(); });
345 };
346 /**
347 * Stop the currently active animation.
348 *
349 * @public
350 */
351 MotionValue.prototype.stop = function () {
352 if (this.stopAnimation)
353 this.stopAnimation();
354 this.clearAnimation();
355 };
356 /**
357 * Returns `true` if this value is currently animating.
358 *
359 * @public
360 */
361 MotionValue.prototype.isAnimating = function () {
362 return !!this.stopAnimation;
363 };
364 MotionValue.prototype.clearAnimation = function () {
365 this.stopAnimation = null;
366 };
367 /**
368 * Destroy and clean up subscribers to this `MotionValue`.
369 *
370 * The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically
371 * handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually
372 * created a `MotionValue` via the `motionValue` function.
373 *
374 * @public
375 */
376 MotionValue.prototype.destroy = function () {
377 this.updateSubscribers && this.updateSubscribers.clear();
378 this.renderSubscribers && this.renderSubscribers.clear();
379 this.parent && this.parent.removeChild(this);
380 this.stop();
381 };
382 return MotionValue;
383}());
384/**
385 * @internal
386 */
387function motionValue(init, opts) {
388 return new MotionValue(init, opts);
389}
390
391/**
392 * Creates a constant value over the lifecycle of a component.
393 *
394 * Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
395 * a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
396 * you can ensure that initialisers don't execute twice or more.
397 */
398function useConstant(init) {
399 var ref = React.useRef(null);
400 if (ref.current === null) {
401 ref.current = init();
402 }
403 return ref.current;
404}
405
406var isMotionValue = function (value) {
407 return value instanceof MotionValue;
408};
409
410// Creating a styler factory for the `onUpdate` prop allows all values
411// to fire and the `onUpdate` prop will only fire once per frame
412var updateStyler = styler.createStylerFactory({
413 onRead: function () { return null; },
414 onRender: function (state, _a) {
415 var onUpdate = _a.onUpdate;
416 return onUpdate(state);
417 },
418});
419var MotionValuesMap = /** @class */ (function () {
420 function MotionValuesMap() {
421 this.hasMounted = false;
422 this.values = new Map();
423 this.unsubscribers = new Map();
424 }
425 MotionValuesMap.prototype.has = function (key) {
426 return this.values.has(key);
427 };
428 MotionValuesMap.prototype.set = function (key, value) {
429 this.values.set(key, value);
430 if (this.hasMounted) {
431 this.bindValueToOutput(key, value);
432 }
433 };
434 MotionValuesMap.prototype.get = function (key, defaultValue) {
435 var value = this.values.get(key);
436 if (value === undefined && defaultValue !== undefined) {
437 value = new MotionValue(defaultValue);
438 this.set(key, value);
439 }
440 return value;
441 };
442 MotionValuesMap.prototype.forEach = function (callback) {
443 return this.values.forEach(callback);
444 };
445 MotionValuesMap.prototype.bindValueToOutput = function (key, value) {
446 var _this = this;
447 var onRender = function (v) { return _this.output && _this.output(key, v); };
448 var unsubscribeOnRender = value.onRenderRequest(onRender);
449 var onChange = function (v) {
450 _this.onUpdate && _this.onUpdate.set(key, v);
451 };
452 var unsubscribeOnChange = value.onChange(onChange);
453 if (this.unsubscribers.has(key)) {
454 this.unsubscribers.get(key)();
455 }
456 this.unsubscribers.set(key, function () {
457 unsubscribeOnRender();
458 unsubscribeOnChange();
459 });
460 };
461 MotionValuesMap.prototype.setOnUpdate = function (onUpdate) {
462 this.onUpdate = undefined;
463 if (onUpdate) {
464 this.onUpdate = updateStyler({ onUpdate: onUpdate });
465 }
466 };
467 MotionValuesMap.prototype.setTransformTemplate = function (transformTemplate) {
468 if (this.transformTemplate !== transformTemplate) {
469 this.transformTemplate = transformTemplate;
470 this.updateTransformTemplate();
471 }
472 };
473 MotionValuesMap.prototype.getTransformTemplate = function () {
474 return this.transformTemplate;
475 };
476 MotionValuesMap.prototype.updateTransformTemplate = function () {
477 if (this.output) {
478 this.output("transform", this.transformTemplate);
479 }
480 };
481 MotionValuesMap.prototype.mount = function (output) {
482 var _this = this;
483 this.hasMounted = true;
484 if (output)
485 this.output = output;
486 this.values.forEach(function (value, key) { return _this.bindValueToOutput(key, value); });
487 this.updateTransformTemplate();
488 };
489 MotionValuesMap.prototype.unmount = function () {
490 var _this = this;
491 this.values.forEach(function (_value, key) {
492 var unsubscribe = _this.unsubscribers.get(key);
493 unsubscribe && unsubscribe();
494 });
495 };
496 return MotionValuesMap;
497}());
498var specialMotionValueProps = new Set(["dragOriginX", "dragOriginY"]);
499var useMotionValues = function (props) {
500 var motionValues = useConstant(function () {
501 var map = new MotionValuesMap();
502 /**
503 * Loop through every prop and add any detected `MotionValue`s. This is SVG-specific
504 * code that should be extracted, perhaps considered hollistically with `useMotionStyles`.
505 *
506 * <motion.circle cx={motionValue(0)} />
507 */
508 for (var key in props) {
509 if (isMotionValue(props[key]) &&
510 !specialMotionValueProps.has(key)) {
511 map.set(key, props[key]);
512 }
513 }
514 return map;
515 });
516 motionValues.setOnUpdate(props.onUpdate);
517 motionValues.setTransformTemplate(props.transformTemplate);
518 return motionValues;
519};
520
521var session = null;
522var syncRenderSession = {
523 isOpen: function () { return session !== null; },
524 open: function () {
525 heyListen.invariant(!session, "Sync render session already open");
526 session = [];
527 },
528 flush: function () {
529 heyListen.invariant(session !== null, "No sync render session found");
530 session && session.forEach(function (styler) { return styler.render(); });
531 session = null;
532 },
533 push: function (styler) {
534 heyListen.invariant(session !== null, "No sync render session found");
535 session && session.push(styler);
536 },
537};
538
539/**
540 * `useEffect` gets resolved bottom-up. We defer some optional functionality to child
541 * components, so to ensure everything runs correctly we export the ref-binding logic
542 * to a new component rather than in `useMotionValues`.
543 */
544var MountComponent = function (_a) {
545 var ref = _a.innerRef, values = _a.values, isStatic = _a.isStatic;
546 React.useEffect(function () {
547 heyListen.invariant(ref.current instanceof Element, "No `ref` found. Ensure components created with `motion.custom` forward refs using `React.forwardRef`");
548 var domStyler = styler__default(ref.current, {
549 preparseOutput: false,
550 enableHardwareAcceleration: !isStatic,
551 });
552 values.mount(function (key, value) {
553 domStyler.set(key, value);
554 if (syncRenderSession.isOpen()) {
555 syncRenderSession.push(domStyler);
556 }
557 });
558 return function () { return values.unmount(); };
559 }, []);
560 return null;
561};
562var Mount = React.memo(MountComponent);
563
564var createValueResolver = function (resolver) { return function (values) {
565 var resolvedValues = {};
566 values.forEach(function (value, key) { return (resolvedValues[key] = resolver(value)); });
567 return resolvedValues;
568}; };
569var resolveCurrent = createValueResolver(function (value) { return value.get(); });
570
571var transformOriginProps = new Set(["originX", "originY", "originZ"]);
572var isTransformOriginProp = function (key) { return transformOriginProps.has(key); };
573var buildStyleAttr = function (values, styleProp, isStatic) {
574 var motionValueStyles = resolveCurrent(values);
575 var transformTemplate = values.getTransformTemplate();
576 if (transformTemplate) {
577 // If `transform` has been manually set as a string, pass that through the template
578 // otherwise pass it forward to Stylefire's style property builder
579 motionValueStyles.transform = styleProp.transform
580 ? transformTemplate({}, styleProp.transform)
581 : transformTemplate;
582 }
583 return styler.buildStyleProperty(tslib.__assign(tslib.__assign({}, styleProp), motionValueStyles), !isStatic);
584};
585var useMotionStyles = function (values, styleProp, isStatic, transformValues) {
586 if (styleProp === void 0) { styleProp = {}; }
587 var style = {};
588 var prevMotionStyles = React.useRef({}).current;
589 for (var key in styleProp) {
590 var thisStyle = styleProp[key];
591 if (isMotionValue(thisStyle)) {
592 // If this is a motion value, add it to our MotionValuesMap
593 values.set(key, thisStyle);
594 }
595 else if (!isStatic &&
596 (styler.isTransformProp(key) || isTransformOriginProp(key))) {
597 // Or if it's a transform prop, create a motion value (or update an existing one)
598 // to ensure Stylefire can reconcile all the transform values together.
599 // A further iteration on this would be to create a single styler per component that gets
600 // used in the DOM renderer's buildStyleAttr *and* animations, then we would only
601 // have to convert animating values to `MotionValues` (we could probably remove this entire function).
602 // The only architectural consideration is to allow Stylefire to have elements mounted after
603 // a styler is created.
604 if (!values.has(key)) {
605 // If it doesn't exist as a motion value, create it
606 values.set(key, motionValue(thisStyle));
607 }
608 else {
609 // Otherwise only update it if it's changed from a previous render
610 if (thisStyle !== prevMotionStyles[key]) {
611 var value = values.get(key);
612 value.set(thisStyle);
613 }
614 }
615 prevMotionStyles[key] = thisStyle;
616 }
617 else {
618 style[key] = thisStyle;
619 }
620 }
621 return transformValues ? transformValues(style) : style;
622};
623
624var isKeyframesTarget = function (v) {
625 return Array.isArray(v);
626};
627
628var isCustomValue = function (v) {
629 return Boolean(v && typeof v === "object" && v.mix && v.toValue);
630};
631var resolveFinalValueInKeyframes = function (v) {
632 // TODO maybe throw if v.length - 1 is placeholder token?
633 return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
634};
635
636var auto = {
637 test: function (v) { return v === "auto"; },
638 parse: function (v) { return v; },
639};
640var dimensionTypes = [styleValueTypes.number, styleValueTypes.px, styleValueTypes.percent, styleValueTypes.degrees, styleValueTypes.vw, styleValueTypes.vh, auto];
641var valueTypes = tslib.__spreadArrays(dimensionTypes, [styleValueTypes.color, styleValueTypes.complex]);
642var testValueType = function (v) { return function (type) { return type.test(v); }; };
643var getDimensionValueType = function (v) {
644 return dimensionTypes.find(testValueType(v));
645};
646var getValueType = function (v) { return valueTypes.find(testValueType(v)); };
647
648var underDampedSpring = function () { return ({
649 type: "spring",
650 stiffness: 500,
651 damping: 25,
652 restDelta: 0.5,
653 restSpeed: 10,
654}); };
655var overDampedSpring = function (to) { return ({
656 type: "spring",
657 stiffness: 700,
658 damping: to === 0 ? 100 : 35,
659}); };
660var linearTween = function () { return ({
661 ease: "linear",
662 duration: 0.3,
663}); };
664var keyframes = function (values) { return ({
665 type: "keyframes",
666 duration: 0.8,
667 values: values,
668}); };
669var defaultTransitions = {
670 x: underDampedSpring,
671 y: underDampedSpring,
672 z: underDampedSpring,
673 rotate: underDampedSpring,
674 rotateX: underDampedSpring,
675 rotateY: underDampedSpring,
676 rotateZ: underDampedSpring,
677 scaleX: overDampedSpring,
678 scaleY: overDampedSpring,
679 scale: overDampedSpring,
680 opacity: linearTween,
681 backgroundColor: linearTween,
682 color: linearTween,
683 default: overDampedSpring,
684};
685var getDefaultTransition = function (valueKey, to) {
686 var transitionFactory;
687 if (isKeyframesTarget(to)) {
688 transitionFactory = keyframes;
689 }
690 else {
691 transitionFactory =
692 defaultTransitions[valueKey] || defaultTransitions.default;
693 }
694 return tslib.__assign({ to: to }, transitionFactory(to));
695};
696
697/**
698 * A Popmotion action that accepts a single `to` prop. When it starts, it immediately
699 * updates with `to` and then completes. By using this we can compose instant transitions
700 * in with the same logic that applies `delay` or returns a `Promise` etc.
701 *
702 * Accepting `duration` is a little bit of a hack that simply defers the completetion of
703 * the animation until after the duration finishes. This is for situations when you're **only**
704 * animating non-animatable values and then setting something on `transitionEnd`. Really
705 * you want this to fire after the "animation" finishes, rather than instantly.
706 *
707 * ```
708 * animate={{
709 * display: 'block',
710 * transitionEnd: { display: 'none' }
711 * }}
712 * ```
713 */
714var just = function (_a) {
715 var to = _a.to, duration = _a.duration;
716 return popmotion.action(function (_a) {
717 var update = _a.update, complete = _a.complete;
718 update(to);
719 duration ? popmotion.delay(duration).start({ complete: complete }) : complete();
720 });
721};
722
723var easingDefinitionToFunction = function (definition) {
724 if (Array.isArray(definition)) {
725 // If cubic bezier definition, create bezier curve
726 heyListen.invariant(definition.length === 4, "Cubic bezier arrays must contain four numerical values.");
727 var x1 = definition[0], y1 = definition[1], x2 = definition[2], y2 = definition[3];
728 return easingLookup.cubicBezier(x1, y1, x2, y2);
729 }
730 else if (typeof definition === "string") {
731 // Else lookup from table
732 heyListen.invariant(easingLookup[definition] !== undefined, "Invalid easing type '" + definition + "'");
733 return easingLookup[definition];
734 }
735 return definition;
736};
737var isEasingArray = function (ease) {
738 return Array.isArray(ease) && typeof ease[0] !== "number";
739};
740
741var isDurationAnimation = function (v) {
742 return v.hasOwnProperty("duration") || v.hasOwnProperty("repeatDelay");
743};
744
745/**
746 * Check if a value is animatable. Examples:
747 *
748 * ✅: 100, "100px", "#fff"
749 * ❌: "block", "url(2.jpg)"
750 * @param value
751 *
752 * @internal
753 */
754var isAnimatable = function (key, value) {
755 // If the list of keys tat might be non-animatable grows, replace with Set
756 if (key === "zIndex")
757 return false;
758 // If it's a number or a keyframes array, we can animate it. We might at some point
759 // need to do a deep isAnimatable check of keyframes, or let Popmotion handle this,
760 // but for now lets leave it like this for performance reasons
761 if (typeof value === "number" || Array.isArray(value))
762 return true;
763 if (typeof value === "string" && // It's animatable if we have a string
764 styleValueTypes.complex.test(value) && // And it contains numbers and/or colors
765 !value.startsWith("url(") // Unless it starts with "url("
766 ) {
767 return true;
768 }
769 return false;
770};
771
772/**
773 * Converts seconds to milliseconds
774 *
775 * @param seconds - Time in seconds.
776 * @return milliseconds - Converted time in milliseconds.
777 */
778var secondsToMilliseconds = function (seconds) { return seconds * 1000; };
779
780var transitions = { tween: popmotion.tween, spring: popmotion.spring, keyframes: popmotion.keyframes, inertia: popmotion.inertia, just: just };
781var transitionOptionParser = {
782 tween: function (opts) {
783 if (opts.ease) {
784 var ease = isEasingArray(opts.ease) ? opts.ease[0] : opts.ease;
785 opts.ease = easingDefinitionToFunction(ease);
786 }
787 return opts;
788 },
789 keyframes: function (_a) {
790 var from = _a.from, to = _a.to, velocity = _a.velocity, opts = tslib.__rest(_a, ["from", "to", "velocity"]);
791 if (opts.values && opts.values[0] === null) {
792 var values = tslib.__spreadArrays(opts.values);
793 values[0] = from;
794 opts.values = values;
795 }
796 if (opts.ease) {
797 opts.easings = isEasingArray(opts.ease)
798 ? opts.ease.map(easingDefinitionToFunction)
799 : easingDefinitionToFunction(opts.ease);
800 }
801 opts.ease = easingLookup.linear;
802 return opts;
803 },
804};
805var isTransitionDefined = function (_a) {
806 var when = _a.when, delay = _a.delay, delayChildren = _a.delayChildren, staggerChildren = _a.staggerChildren, staggerDirection = _a.staggerDirection, transition = tslib.__rest(_a, ["when", "delay", "delayChildren", "staggerChildren", "staggerDirection"]);
807 return Object.keys(transition).length;
808};
809var getTransitionDefinition = function (key, to, transitionDefinition) {
810 var delay = transitionDefinition ? transitionDefinition.delay : 0;
811 // If no object, return default transition
812 // A better way to handle this would be to deconstruct out all the shared Orchestration props
813 // and see if there's any props remaining
814 if (transitionDefinition === undefined ||
815 !isTransitionDefined(transitionDefinition)) {
816 return tslib.__assign({ delay: delay }, getDefaultTransition(key, to));
817 }
818 var valueTransitionDefinition = transitionDefinition[key] ||
819 transitionDefinition.default ||
820 transitionDefinition;
821 if (valueTransitionDefinition.type === false) {
822 return {
823 delay: valueTransitionDefinition.hasOwnProperty("delay")
824 ? valueTransitionDefinition.delay
825 : delay,
826 to: isKeyframesTarget(to)
827 ? to[to.length - 1]
828 : to,
829 type: "just",
830 };
831 }
832 else if (isKeyframesTarget(to)) {
833 return tslib.__assign(tslib.__assign({ values: to, duration: 0.8, delay: delay, ease: "linear" }, valueTransitionDefinition), {
834 // This animation must be keyframes if we're animating through an array
835 type: "keyframes" });
836 }
837 else {
838 return tslib.__assign({ type: "tween", to: to,
839 delay: delay }, valueTransitionDefinition);
840 }
841};
842var preprocessOptions = function (type, opts) {
843 return transitionOptionParser[type]
844 ? transitionOptionParser[type](opts)
845 : opts;
846};
847var getAnimation = function (key, value, target, transition) {
848 var origin = value.get();
849 var isOriginAnimatable = isAnimatable(key, origin);
850 var isTargetAnimatable = isAnimatable(key, target);
851 // TODO we could probably improve this check to ensure both values are of the same type -
852 // for instance 100 to #fff. This might live better in Popmotion.
853 heyListen.warning(isOriginAnimatable === isTargetAnimatable, "You are trying to animate " + key + " from \"" + origin + "\" to " + target + ". \"" + origin + "\" is not an animatable value - to enable this animation set " + origin + " to a value animatable to " + target + " via the `style` property.");
854 // Parse the `transition` prop and return options for the Popmotion animation
855 var _a = getTransitionDefinition(key, target, transition), _b = _a.type, type = _b === void 0 ? "tween" : _b, transitionDefinition = tslib.__rest(_a, ["type"]);
856 // If this is an animatable pair of values, return an animation, otherwise use `just`
857 var actionFactory = isOriginAnimatable && isTargetAnimatable
858 ? transitions[type]
859 : just;
860 var opts = preprocessOptions(type, tslib.__assign({ from: origin, velocity: value.getVelocity() }, transitionDefinition));
861 // Convert duration from Framer Motion's seconds into Popmotion's milliseconds
862 if (isDurationAnimation(opts)) {
863 if (opts.duration) {
864 opts.duration = secondsToMilliseconds(opts.duration);
865 }
866 if (opts.repeatDelay) {
867 opts.repeatDelay = secondsToMilliseconds(opts.repeatDelay);
868 }
869 }
870 return [actionFactory, opts];
871};
872/**
873 * Start animation on a value. This function completely encapsulates Popmotion-specific logic.
874 *
875 * @internal
876 */
877function startAnimation(key, value, target, _a) {
878 var _b = _a.delay, delay = _b === void 0 ? 0 : _b, transition = tslib.__rest(_a, ["delay"]);
879 return value.start(function (complete) {
880 var activeAnimation;
881 var _a = getAnimation(key, value, target, transition), animationFactory = _a[0], _b = _a[1], valueDelay = _b.delay, options = tslib.__rest(_b, ["delay"]);
882 if (valueDelay !== undefined) {
883 delay = valueDelay;
884 }
885 var animate = function () {
886 var animation = animationFactory(options);
887 // Bind animation opts to animation
888 activeAnimation = animation.start({
889 update: function (v) { return value.set(v); },
890 complete: complete,
891 });
892 };
893 // If we're delaying this animation, only resolve it **after** the delay to
894 // ensure the value's resolve velocity is up-to-date.
895 if (delay) {
896 activeAnimation = popmotion.delay(secondsToMilliseconds(delay)).start({
897 complete: animate,
898 });
899 }
900 else {
901 animate();
902 }
903 return function () {
904 if (activeAnimation)
905 activeAnimation.stop();
906 };
907 });
908}
909
910/**
911 * Get the current value of every `MotionValue`
912 * @param values -
913 */
914var getCurrent = function (values) {
915 var current = {};
916 values.forEach(function (value, key) { return (current[key] = value.get()); });
917 return current;
918};
919/**
920 * Get the current velocity of every `MotionValue`
921 * @param values -
922 */
923var getVelocity = function (values) {
924 var velocity = {};
925 values.forEach(function (value, key) { return (velocity[key] = value.getVelocity()); });
926 return velocity;
927};
928/**
929 * Check if value is a function that returns a `Target`. A generic typeof === 'function'
930 * check, just helps with typing.
931 * @param p -
932 */
933var isTargetResolver = function (p) {
934 return typeof p === "function";
935};
936/**
937 * Check if value is a list of variant labels
938 * @param v -
939 */
940var isVariantLabels = function (v) { return Array.isArray(v); };
941/**
942 * Check if value is a numerical string, ie "100" or "100px"
943 */
944var isNumericalString = function (v) { return /^\d*\.?\d+$/.test(v); };
945/**
946 * Control animations for a single component
947 *
948 * @internal
949 */
950var ValueAnimationControls = /** @class */ (function () {
951 function ValueAnimationControls(_a) {
952 var _this = this;
953 var values = _a.values, readValueFromSource = _a.readValueFromSource, makeTargetAnimatable = _a.makeTargetAnimatable;
954 /**
955 * A reference to the component's latest props. We could probably ditch this in
956 * favour to a reference to the `custom` prop now we don't send all props through
957 * to target resolvers.
958 */
959 this.props = {};
960 /**
961 * The component's variants, as provided by `variants`
962 */
963 this.variants = {};
964 /**
965 * A set of values that we animate back to when a value is cleared of all overrides.
966 */
967 this.baseTarget = {};
968 /**
969 * A series of target overrides that we can animate to/from when overrides are set/cleared.
970 */
971 this.overrides = [];
972 /**
973 * A series of target overrides as they were originally resolved.
974 */
975 this.resolvedOverrides = [];
976 /**
977 * A Set of currently active override indexes
978 */
979 this.activeOverrides = new Set();
980 /**
981 * A Set of value keys that are currently animating.
982 */
983 this.isAnimating = new Set();
984 /**
985 * Check if the associated `MotionValueMap` has a key with the provided string.
986 * Pre-bound to the class so we can provide directly to the `filter` in `checkForNewValues`.
987 */
988 this.hasValue = function (key) { return !_this.values.has(key); };
989 this.values = values;
990 this.readValueFromSource = readValueFromSource;
991 this.makeTargetAnimatable = makeTargetAnimatable;
992 this.values.forEach(function (value, key) { return (_this.baseTarget[key] = value.get()); });
993 }
994 /**
995 * Set the reference to the component's props.
996 * @param props -
997 */
998 ValueAnimationControls.prototype.setProps = function (props) {
999 this.props = props;
1000 };
1001 /**
1002 * Set the reference to the component's variants
1003 * @param variants -
1004 */
1005 ValueAnimationControls.prototype.setVariants = function (variants) {
1006 if (variants)
1007 this.variants = variants;
1008 };
1009 /**
1010 * Set the component's default transition
1011 * @param transition -
1012 */
1013 ValueAnimationControls.prototype.setDefaultTransition = function (transition) {
1014 if (transition)
1015 this.defaultTransition = transition;
1016 };
1017 /**
1018 * Set motion values without animation.
1019 *
1020 * @param definition -
1021 * @param isActive -
1022 */
1023 ValueAnimationControls.prototype.setValues = function (definition, _a) {
1024 var _this = this;
1025 var _b = _a === void 0 ? {} : _a, _c = _b.isActive, isActive = _c === void 0 ? new Set() : _c, priority = _b.priority;
1026 var _d = this.resolveVariant(definition), target = _d.target, transitionEnd = _d.transitionEnd;
1027 target = this.transformValues(tslib.__assign(tslib.__assign({}, target), transitionEnd));
1028 return Object.keys(target).forEach(function (key) {
1029 if (isActive.has(key))
1030 return;
1031 isActive.add(key);
1032 if (target) {
1033 var targetValue = resolveFinalValueInKeyframes(target[key]);
1034 if (_this.values.has(key)) {
1035 var value = _this.values.get(key);
1036 value && value.set(targetValue);
1037 }
1038 else {
1039 _this.values.set(key, motionValue(targetValue));
1040 }
1041 if (!priority)
1042 _this.baseTarget[key] = targetValue;
1043 }
1044 });
1045 };
1046 /**
1047 * Allows `transformValues` to be set by a component that allows us to
1048 * transform the values in a given `Target`. This allows Framer Library
1049 * to extend Framer Motion to animate `Color` variables etc. Currently we have
1050 * to manually support these extended types here in Framer Motion.
1051 *
1052 * @param values -
1053 */
1054 ValueAnimationControls.prototype.transformValues = function (values) {
1055 var transformValues = this.props.transformValues;
1056 return transformValues ? transformValues(values) : values;
1057 };
1058 /**
1059 * Check a `Target` for new values we haven't animated yet, and add them
1060 * to the `MotionValueMap`.
1061 *
1062 * Currently there's functionality here that is DOM-specific, we should allow
1063 * this functionality to be injected by the factory that creates DOM-specific
1064 * components.
1065 *
1066 * @param target -
1067 */
1068 ValueAnimationControls.prototype.checkForNewValues = function (target) {
1069 var newValueKeys = Object.keys(target).filter(this.hasValue);
1070 var numNewValues = newValueKeys.length;
1071 if (!numNewValues)
1072 return;
1073 for (var i = 0; i < numNewValues; i++) {
1074 var key = newValueKeys[i];
1075 var targetValue = target[key];
1076 var value = null;
1077 // If this is a keyframes value, we can attempt to use the first value in the
1078 // array as that's going to be the first value of the animation anyway
1079 if (Array.isArray(targetValue)) {
1080 value = targetValue[0];
1081 }
1082 // If it isn't a keyframes or the first keyframes value was set as `null`, read the
1083 // value from the DOM. It might be worth investigating whether to check props (for SVG)
1084 // or props.style (for HTML) if the value exists there before attempting to read.
1085 if (value === null) {
1086 value = this.readValueFromSource(key);
1087 heyListen.invariant(value !== null, "No initial value for \"" + key + "\" can be inferred. Ensure an initial value for \"" + key + "\" is defined on the component.");
1088 }
1089 if (typeof value === "string" && isNumericalString(value)) {
1090 // If this is a number read as a string, ie "0" or "200", convert it to a number
1091 value = parseFloat(value);
1092 }
1093 else if (!getValueType(value) && styleValueTypes.complex.test(targetValue)) {
1094 // If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
1095 value = styleValueTypes.complex.getAnimatableNone(targetValue);
1096 }
1097 this.values.set(key, motionValue(value));
1098 this.baseTarget[key] = value;
1099 }
1100 };
1101 /**
1102 * Resolve a variant from its label or resolver into an actual `Target` we can animate to.
1103 * @param variant -
1104 */
1105 ValueAnimationControls.prototype.resolveVariant = function (variant) {
1106 if (!variant) {
1107 return {
1108 target: undefined,
1109 transition: undefined,
1110 transitionEnd: undefined,
1111 };
1112 }
1113 if (isTargetResolver(variant)) {
1114 // resolve current and velocity
1115 variant = variant(this.props.custom, getCurrent(this.values), getVelocity(this.values));
1116 }
1117 var _a = variant.transition, transition = _a === void 0 ? this.defaultTransition : _a, transitionEnd = variant.transitionEnd, target = tslib.__rest(variant, ["transition", "transitionEnd"]);
1118 return { transition: transition, transitionEnd: transitionEnd, target: target };
1119 };
1120 /**
1121 * Get the highest active override priority index
1122 */
1123 ValueAnimationControls.prototype.getHighestPriority = function () {
1124 if (!this.activeOverrides.size)
1125 return 0;
1126 return Math.max.apply(Math, Array.from(this.activeOverrides));
1127 };
1128 /**
1129 * Set an override. We add this layer of indirection so if, for instance, a tap gesture
1130 * starts and overrides a hover gesture, when we clear the tap gesture and fallback to the
1131 * hover gesture, if that hover gesture has changed in the meantime we can go to that rather
1132 * than the one that was resolved when the hover gesture animation started.
1133 *
1134 * @param definition -
1135 * @param overrideIndex -
1136 */
1137 ValueAnimationControls.prototype.setOverride = function (definition, overrideIndex) {
1138 this.overrides[overrideIndex] = definition;
1139 if (this.children) {
1140 this.children.forEach(function (child) {
1141 return child.setOverride(definition, overrideIndex);
1142 });
1143 }
1144 };
1145 /**
1146 * Start an override animation.
1147 * @param overrideIndex -
1148 */
1149 ValueAnimationControls.prototype.startOverride = function (overrideIndex) {
1150 var override = this.overrides[overrideIndex];
1151 if (override) {
1152 return this.start(override, { priority: overrideIndex });
1153 }
1154 };
1155 /**
1156 * Clear an override. We check every value we animated to in this override to see if
1157 * its present on any lower-priority overrides. If not, we animate it back to its base target.
1158 * @param overrideIndex -
1159 */
1160 ValueAnimationControls.prototype.clearOverride = function (overrideIndex) {
1161 var _this = this;
1162 if (this.children) {
1163 this.children.forEach(function (child) { return child.clearOverride(overrideIndex); });
1164 }
1165 var override = this.overrides[overrideIndex];
1166 if (!override)
1167 return;
1168 this.activeOverrides.delete(overrideIndex);
1169 var highest = this.getHighestPriority();
1170 this.resetIsAnimating();
1171 if (highest) {
1172 var highestOverride = this.overrides[highest];
1173 highestOverride && this.startOverride(highest);
1174 }
1175 // Figure out which remaining values were affected by the override and animate those
1176 var overrideTarget = this.resolvedOverrides[overrideIndex];
1177 if (!overrideTarget)
1178 return;
1179 var remainingValues = {};
1180 for (var key in this.baseTarget) {
1181 if (overrideTarget[key] !== undefined) {
1182 remainingValues[key] = this.baseTarget[key];
1183 }
1184 }
1185 this.onStart();
1186 this.animate(remainingValues).then(function () { return _this.onComplete(); });
1187 };
1188 /**
1189 * Apply a target/variant without any animation
1190 */
1191 ValueAnimationControls.prototype.apply = function (definition) {
1192 if (Array.isArray(definition)) {
1193 return this.applyVariantLabels(definition);
1194 }
1195 else if (typeof definition === "string") {
1196 return this.applyVariantLabels([definition]);
1197 }
1198 else {
1199 this.setValues(definition);
1200 }
1201 };
1202 /**
1203 * Apply variant labels without animation
1204 */
1205 ValueAnimationControls.prototype.applyVariantLabels = function (variantLabelList) {
1206 var _this = this;
1207 var isActive = new Set();
1208 var reversedList = tslib.__spreadArrays(variantLabelList).reverse();
1209 reversedList.forEach(function (key) {
1210 var _a = _this.resolveVariant(_this.variants[key]), target = _a.target, transitionEnd = _a.transitionEnd;
1211 if (transitionEnd) {
1212 _this.setValues(transitionEnd, { isActive: isActive });
1213 }
1214 if (target) {
1215 _this.setValues(target, { isActive: isActive });
1216 }
1217 if (_this.children && _this.children.size) {
1218 _this.children.forEach(function (child) {
1219 return child.applyVariantLabels(variantLabelList);
1220 });
1221 }
1222 });
1223 };
1224 ValueAnimationControls.prototype.start = function (definition, opts) {
1225 var _this = this;
1226 if (opts === void 0) { opts = {}; }
1227 if (opts.priority) {
1228 this.activeOverrides.add(opts.priority);
1229 }
1230 this.resetIsAnimating(opts.priority);
1231 var animation;
1232 if (isVariantLabels(definition)) {
1233 animation = this.animateVariantLabels(definition, opts);
1234 }
1235 else if (typeof definition === "string") {
1236 animation = this.animateVariant(definition, opts);
1237 }
1238 else {
1239 animation = this.animate(definition, opts);
1240 }
1241 this.onStart();
1242 return animation.then(function () { return _this.onComplete(); });
1243 };
1244 ValueAnimationControls.prototype.animate = function (animationDefinition, _a) {
1245 var _this = this;
1246 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;
1247 var _e = this.resolveVariant(animationDefinition), target = _e.target, transition = _e.transition, transitionEnd = _e.transitionEnd;
1248 if (transitionOverride) {
1249 transition = transitionOverride;
1250 }
1251 if (!target)
1252 return Promise.resolve();
1253 target = this.transformValues(target);
1254 if (transitionEnd) {
1255 transitionEnd = this.transformValues(transitionEnd);
1256 }
1257 this.checkForNewValues(target);
1258 if (this.makeTargetAnimatable) {
1259 var animatable = this.makeTargetAnimatable(target, transitionEnd);
1260 target = animatable.target;
1261 transitionEnd = animatable.transitionEnd;
1262 }
1263 if (priority) {
1264 this.resolvedOverrides[priority] = target;
1265 }
1266 this.checkForNewValues(target);
1267 var animations = [];
1268 for (var key in target) {
1269 var value = this.values.get(key);
1270 if (!value || !target || target[key] === undefined)
1271 continue;
1272 var valueTarget = target[key];
1273 if (!priority) {
1274 this.baseTarget[key] = resolveFinalValueInKeyframes(valueTarget);
1275 }
1276 if (this.isAnimating.has(key))
1277 continue;
1278 this.isAnimating.add(key);
1279 animations.push(startAnimation(key, value, valueTarget, tslib.__assign({ delay: delay }, transition)));
1280 }
1281 var allAnimations = Promise.all(animations);
1282 return transitionEnd
1283 ? allAnimations.then(function () {
1284 _this.setValues(transitionEnd, { priority: priority });
1285 })
1286 : allAnimations;
1287 };
1288 ValueAnimationControls.prototype.animateVariantLabels = function (variantLabels, opts) {
1289 var _this = this;
1290 var animations = tslib.__spreadArrays(variantLabels).reverse()
1291 .map(function (label) { return _this.animateVariant(label, opts); });
1292 return Promise.all(animations);
1293 };
1294 ValueAnimationControls.prototype.animateVariant = function (variantLabel, opts) {
1295 var _this = this;
1296 var when = false;
1297 var delayChildren = 0;
1298 var staggerChildren = 0;
1299 var staggerDirection = 1;
1300 var priority = (opts && opts.priority) || 0;
1301 var variant = this.variants[variantLabel];
1302 var getAnimations = variant
1303 ? function () { return _this.animate(variant, opts); }
1304 : function () { return Promise.resolve(); };
1305 var getChildrenAnimations = this.children
1306 ? function () {
1307 return _this.animateChildren(variantLabel, delayChildren, staggerChildren, staggerDirection, priority);
1308 }
1309 : function () { return Promise.resolve(); };
1310 if (variant && this.children) {
1311 var transition = this.resolveVariant(variant).transition;
1312 if (transition) {
1313 when = transition.when || when;
1314 delayChildren = transition.delayChildren || delayChildren;
1315 staggerChildren = transition.staggerChildren || staggerChildren;
1316 staggerDirection =
1317 transition.staggerDirection || staggerDirection;
1318 }
1319 }
1320 if (when) {
1321 var _a = when === "beforeChildren"
1322 ? [getAnimations, getChildrenAnimations]
1323 : [getChildrenAnimations, getAnimations], first = _a[0], last = _a[1];
1324 return first().then(last);
1325 }
1326 else {
1327 return Promise.all([getAnimations(), getChildrenAnimations()]);
1328 }
1329 };
1330 ValueAnimationControls.prototype.animateChildren = function (variantLabel, delayChildren, staggerChildren, staggerDirection, priority) {
1331 if (delayChildren === void 0) { delayChildren = 0; }
1332 if (staggerChildren === void 0) { staggerChildren = 0; }
1333 if (staggerDirection === void 0) { staggerDirection = 1; }
1334 if (priority === void 0) { priority = 0; }
1335 if (!this.children) {
1336 return Promise.resolve();
1337 }
1338 var animations = [];
1339 var maxStaggerDuration = (this.children.size - 1) * staggerChildren;
1340 var generateStaggerDuration = staggerDirection === 1
1341 ? function (i) { return i * staggerChildren; }
1342 : function (i) { return maxStaggerDuration - i * staggerChildren; };
1343 Array.from(this.children).forEach(function (childControls, i) {
1344 var animation = childControls.animateVariant(variantLabel, {
1345 priority: priority,
1346 delay: delayChildren + generateStaggerDuration(i),
1347 });
1348 animations.push(animation);
1349 });
1350 return Promise.all(animations);
1351 };
1352 ValueAnimationControls.prototype.onStart = function () {
1353 var onAnimationStart = this.props.onAnimationStart;
1354 onAnimationStart && onAnimationStart();
1355 };
1356 ValueAnimationControls.prototype.onComplete = function () {
1357 var onAnimationComplete = this.props.onAnimationComplete;
1358 onAnimationComplete && onAnimationComplete();
1359 };
1360 ValueAnimationControls.prototype.checkOverrideIsAnimating = function (priority) {
1361 var numOverrides = this.overrides.length;
1362 for (var i = priority + 1; i < numOverrides; i++) {
1363 var resolvedOverride = this.resolvedOverrides[i];
1364 if (resolvedOverride) {
1365 for (var key in resolvedOverride) {
1366 this.isAnimating.add(key);
1367 }
1368 }
1369 }
1370 };
1371 ValueAnimationControls.prototype.resetIsAnimating = function (priority) {
1372 if (priority === void 0) { priority = 0; }
1373 this.isAnimating.clear();
1374 // If this isn't the highest priority gesture, block the animation
1375 // of anything that's currently being animated
1376 if (priority < this.getHighestPriority()) {
1377 this.checkOverrideIsAnimating(priority);
1378 }
1379 if (this.children) {
1380 this.children.forEach(function (child) { return child.resetIsAnimating(priority); });
1381 }
1382 };
1383 ValueAnimationControls.prototype.stop = function () {
1384 this.values.forEach(function (value) { return value.stop(); });
1385 };
1386 /**
1387 * Add the controls of a child component.
1388 * @param controls -
1389 */
1390 ValueAnimationControls.prototype.addChild = function (controls) {
1391 if (!this.children) {
1392 this.children = new Set();
1393 }
1394 this.children.add(controls);
1395 // We set child overrides when `setOverride` is called, but also have to do it here
1396 // as the first time `setOverride` is called all the children might not have been added yet.
1397 this.overrides.forEach(function (override, i) {
1398 override && controls.setOverride(override, i);
1399 });
1400 };
1401 ValueAnimationControls.prototype.removeChild = function (controls) {
1402 if (!this.children) {
1403 return;
1404 }
1405 this.children.delete(controls);
1406 };
1407 ValueAnimationControls.prototype.resetChildren = function () {
1408 if (this.children)
1409 this.children.clear();
1410 };
1411 return ValueAnimationControls;
1412}());
1413
1414/**
1415 * Use callback either only on the initial render or on all renders. In concurrent mode
1416 * the "initial" render might run multiple times
1417 *
1418 * @param callback - Callback to run
1419 * @param isInitialOnly - Set to `true` to only run on initial render, or `false` for all renders. Defaults to `false`.
1420 *
1421 * @public
1422 */
1423function useInitialOrEveryRender(callback, isInitialOnly) {
1424 if (isInitialOnly === void 0) { isInitialOnly = false; }
1425 var isInitialRender = React.useRef(true);
1426 if (!isInitialOnly || (isInitialOnly && isInitialRender.current)) {
1427 callback();
1428 }
1429 isInitialRender.current = false;
1430}
1431
1432/**
1433 * Control animations on one or more components.
1434 *
1435 * @public
1436 */
1437var AnimationControls = /** @class */ (function () {
1438 function AnimationControls() {
1439 /**
1440 * Track whether the host component has mounted.
1441 *
1442 * @internal
1443 */
1444 this.hasMounted = false;
1445 /**
1446 * Pending animations that are started before a component is mounted.
1447 *
1448 * @internal
1449 */
1450 this.pendingAnimations = [];
1451 /**
1452 * A collection of linked component animation controls.
1453 *
1454 * @internal
1455 */
1456 this.componentControls = new Set();
1457 }
1458 /**
1459 * Set variants on this and all child components.
1460 *
1461 * @param variants - The variants to set
1462 *
1463 * @internal
1464 */
1465 AnimationControls.prototype.setVariants = function (variants) {
1466 this.variants = variants;
1467 this.componentControls.forEach(function (controls) {
1468 return controls.setVariants(variants);
1469 });
1470 };
1471 /**
1472 * Set a default transition on this and all child components
1473 *
1474 * @param transition - The default transition to set
1475 *
1476 * @internal
1477 */
1478 AnimationControls.prototype.setDefaultTransition = function (transition) {
1479 this.defaultTransition = transition;
1480 this.componentControls.forEach(function (controls) {
1481 return controls.setDefaultTransition(transition);
1482 });
1483 };
1484 /**
1485 * Subscribes a component's animation controls to this.
1486 *
1487 * @param controls - The controls to subscribe
1488 * @returns An unsubscribe function.
1489 *
1490 * @internal
1491 */
1492 AnimationControls.prototype.subscribe = function (controls) {
1493 var _this = this;
1494 this.componentControls.add(controls);
1495 if (this.variants)
1496 controls.setVariants(this.variants);
1497 if (this.defaultTransition)
1498 controls.setDefaultTransition(this.defaultTransition);
1499 return function () { return _this.componentControls.delete(controls); };
1500 };
1501 /**
1502 * Starts an animation on all linked components.
1503 *
1504 * @remarks
1505 *
1506 * ```jsx
1507 * controls.start("variantLabel")
1508 * controls.start({
1509 * x: 0,
1510 * transition: { duration: 1 }
1511 * })
1512 * ```
1513 *
1514 * @param definition - Properties or variant label to animate to
1515 * @param transition - Optional `transtion` to apply to a variant
1516 * @returns - A `Promise` that resolves when all animations have completed.
1517 *
1518 * @public
1519 */
1520 AnimationControls.prototype.start = function (definition, transitionOverride) {
1521 var _this = this;
1522 if (this.hasMounted) {
1523 var animations_1 = [];
1524 this.componentControls.forEach(function (controls) {
1525 var animation = controls.start(definition, {
1526 transitionOverride: transitionOverride,
1527 });
1528 animations_1.push(animation);
1529 });
1530 return Promise.all(animations_1);
1531 }
1532 else {
1533 return new Promise(function (resolve) {
1534 _this.pendingAnimations.push({
1535 animation: [definition, transitionOverride],
1536 resolve: resolve,
1537 });
1538 });
1539 }
1540 };
1541 /**
1542 * Instantly set to a set of properties or a variant.
1543 *
1544 * ```jsx
1545 * // With properties
1546 * controls.set({ opacity: 0 })
1547 *
1548 * // With variants
1549 * controls.set("hidden")
1550 * ```
1551 *
1552 * @internalremarks
1553 * We could perform a similar trick to `.start` where this can be called before mount
1554 * and we maintain a list of of pending actions that get applied on mount. But the
1555 * expectation of `set` is that it happens synchronously and this would be difficult
1556 * to do before any children have even attached themselves. It's also poor practise
1557 * and we should discourage render-synchronous `.start` calls rather than lean into this.
1558 *
1559 * @public
1560 */
1561 AnimationControls.prototype.set = function (definition) {
1562 heyListen.invariant(this.hasMounted, "controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook.");
1563 return this.componentControls.forEach(function (controls) {
1564 return controls.apply(definition);
1565 });
1566 };
1567 /**
1568 * Stops animations on all linked components.
1569 *
1570 * ```jsx
1571 * controls.stop()
1572 * ```
1573 *
1574 * @public
1575 */
1576 AnimationControls.prototype.stop = function () {
1577 this.componentControls.forEach(function (controls) { return controls.stop(); });
1578 };
1579 /**
1580 * Initialises the animation controls.
1581 *
1582 * @internal
1583 */
1584 AnimationControls.prototype.mount = function () {
1585 var _this = this;
1586 this.hasMounted = true;
1587 this.pendingAnimations.forEach(function (_a) {
1588 var animation = _a.animation, resolve = _a.resolve;
1589 return _this.start.apply(_this, animation).then(resolve);
1590 });
1591 };
1592 /**
1593 * Stops all child animations when the host component unmounts.
1594 *
1595 * @internal
1596 */
1597 AnimationControls.prototype.unmount = function () {
1598 this.hasMounted = false;
1599 this.stop();
1600 };
1601 return AnimationControls;
1602}());
1603/**
1604 * @internal
1605 */
1606var animationControls = function () { return new AnimationControls(); };
1607
1608/**
1609 * @internal
1610 */
1611var MotionContext = React.createContext({
1612 static: false,
1613});
1614var isVariantLabel = function (v) {
1615 return typeof v === "string" || Array.isArray(v);
1616};
1617var isAnimationControls = function (v) {
1618 return v instanceof AnimationControls;
1619};
1620/**
1621 * Set up the context for children motion components.
1622 *
1623 * We also use this opportunity to apply `initial` values
1624 */
1625var useMotionContext = function (parentContext, controls, values, isStatic, _a) {
1626 if (isStatic === void 0) { isStatic = false; }
1627 var initial = _a.initial, animate = _a.animate, variants = _a.variants, whileTap = _a.whileTap, whileHover = _a.whileHover;
1628 // Override initial with that from a parent context, if defined
1629 if (parentContext.exitProps &&
1630 parentContext.exitProps.initial !== undefined) {
1631 initial = parentContext.exitProps.initial;
1632 }
1633 var initialState;
1634 if (initial === false && !isAnimationControls(animate)) {
1635 initialState = animate;
1636 }
1637 else if (typeof initial !== "boolean") {
1638 initialState = initial;
1639 }
1640 // Track mounted status so children can detect whether they were present during their
1641 // parent's first render
1642 var hasMounted = React.useRef(false);
1643 // We propagate this component's ValueAnimationControls *if* we're being provided variants,
1644 // if we're being used to control variants, or if we're being passed animation controls.
1645 // Otherwise this component should be "invisible" to variant propagation. This is a slight concession
1646 // to Framer X where every `Frame` is a `motion` component and it might be if we change that in the future
1647 // that this restriction is removed.
1648 var shouldPropagateControls = variants ||
1649 isVariantLabel(animate) ||
1650 isVariantLabel(whileTap) ||
1651 isVariantLabel(whileHover) ||
1652 isAnimationControls(animate);
1653 // If this component's `initial` prop is a variant label, propagate it. Otherwise pass the parent's.
1654 var targetInitial = isVariantLabel(initialState)
1655 ? initialState
1656 : parentContext.initial;
1657 // If this is a variant tree we need to propagate the `animate` prop in case new children are added after
1658 // the tree initially animates.
1659 var targetAnimate = isVariantLabel(animate)
1660 ? animate
1661 : parentContext.animate;
1662 // Only allow `initial` to trigger context re-renders if this is a `static` component (ie we're on the Framer canvas)
1663 // or in another non-animation/interaction environment.
1664 var initialDependency = isStatic ? targetInitial : null;
1665 // Only allow `animate` to trigger context re-renders if it's a variant label. If this is an array of
1666 // variant labels there's probably an optimisation to deep-compare but it might be an over-optimisation.
1667 // We want to do this as we rely on React's component rendering order each render cycle to determine
1668 // the new order of any child components for the `staggerChildren` functionality.
1669 var animateDependency = shouldPropagateControls && isVariantLabel(targetAnimate)
1670 ? targetAnimate
1671 : null;
1672 // The context to provide to the child. We `useMemo` because although `controls` and `initial` are
1673 // unlikely to change, by making the context an object it'll be considered a new value every render.
1674 // So all child motion components will re-render as a result.
1675 var context = React.useMemo(function () { return ({
1676 controls: shouldPropagateControls
1677 ? controls
1678 : parentContext.controls,
1679 initial: targetInitial,
1680 animate: targetAnimate,
1681 values: values,
1682 hasMounted: hasMounted,
1683 isReducedMotion: parentContext.isReducedMotion,
1684 }); }, [initialDependency, animateDependency, parentContext.isReducedMotion]);
1685 // Update the `static` property every render. This is unlikely to change but also essentially free.
1686 context.static = isStatic;
1687 // Set initial state. If this is a static component (ie in Framer canvas), respond to updates
1688 // in `initial`.
1689 useInitialOrEveryRender(function () {
1690 var initialToApply = initialState || parentContext.initial;
1691 initialToApply && controls.apply(initialToApply);
1692 }, !isStatic);
1693 React.useEffect(function () {
1694 hasMounted.current = true;
1695 }, []);
1696 return context;
1697};
1698
1699/**
1700 * Creates an imperative set of controls to trigger animations.
1701 *
1702 * This allows a consolidated, uniform API for animations, to be triggered by other APIs like the `animate` prop, or the gesture handlers.
1703 *
1704 * @param values
1705 * @param props
1706 * @param ref
1707 * @param subscribeToParentControls
1708 *
1709 * @internal
1710 */
1711function useValueAnimationControls(config, props, subscribeToParentControls, parentContext) {
1712 var variants = props.variants, transition = props.transition;
1713 var parentControls = React.useContext(MotionContext).controls;
1714 var controls = useConstant(function () { return new ValueAnimationControls(config); });
1715 // Reset and resubscribe children every render to ensure stagger order is correct
1716 if (!parentContext ||
1717 !parentContext.exitProps ||
1718 !parentContext.exitProps.isExiting) {
1719 controls.resetChildren();
1720 controls.setProps(props);
1721 controls.setVariants(variants);
1722 controls.setDefaultTransition(transition);
1723 }
1724 // We have to subscribe to the parent controls within a useEffect rather than during render,
1725 // as
1726 React.useEffect(function () {
1727 if (subscribeToParentControls && parentControls) {
1728 parentControls.addChild(controls);
1729 }
1730 });
1731 React.useEffect(function () {
1732 return function () {
1733 // Remove reference to onAnimationComplete from controls. All the MotionValues
1734 // are unsubscribed from this component separately. We let animations run out
1735 // as they might be animating other components.
1736 var onAnimationComplete = props.onAnimationComplete, unmountProps = tslib.__rest(props, ["onAnimationComplete"]);
1737 controls.setProps(unmountProps);
1738 parentControls && parentControls.removeChild(controls);
1739 };
1740 }, []);
1741 return controls;
1742}
1743
1744var checkShouldInheritVariant = function (_a) {
1745 var animate = _a.animate, variants = _a.variants, _b = _a.inherit, inherit = _b === void 0 ? true : _b;
1746 return (inherit &&
1747 !!variants &&
1748 (!animate || animate instanceof AnimationControls));
1749};
1750
1751/**
1752 * Uses the ref that is passed in, or creates a new one
1753 * @param external - External ref
1754 * @internal
1755 */
1756function useExternalRef(externalRef) {
1757 // We're conditionally calling `useRef` here which is sort of naughty as hooks
1758 // shouldn't be called conditionally. However, Framer Motion will break if this
1759 // condition changes anyway. It might be possible to use an invariant here to
1760 // make it explicit, but I expect changing `ref` is not normal behaviour.
1761 var ref = !externalRef || typeof externalRef === "function"
1762 ? React.useRef(null)
1763 : externalRef;
1764 // Handle `ref` functions. Again, calling the hook conditionally is kind of naughty
1765 // but `ref` types changing between renders would break Motion anyway. If we receive
1766 // bug reports about this, we should track the provided ref and throw an invariant
1767 // rather than move the conditional to inside the useEffect as this will be fired
1768 // for every Frame component within Framer.
1769 if (externalRef && typeof externalRef === "function") {
1770 React.useEffect(function () {
1771 externalRef(ref.current);
1772 return function () { return externalRef(null); };
1773 }, []);
1774 }
1775 return ref;
1776}
1777
1778/**
1779 * @internal
1780 */
1781var createMotionComponent = function (_a) {
1782 var getValueControlsConfig = _a.getValueControlsConfig, loadFunctionalityComponents = _a.loadFunctionalityComponents, renderComponent = _a.renderComponent;
1783 function MotionComponent(props, externalRef) {
1784 var ref = useExternalRef(externalRef);
1785 var parentContext = React.useContext(MotionContext);
1786 var isStatic = parentContext.static || props.static || false;
1787 var values = useMotionValues(props);
1788 var style = useMotionStyles(values, props.style, isStatic, props.transformValues);
1789 var shouldInheritVariant = checkShouldInheritVariant(props);
1790 var controlsConfig = useConstant(function () {
1791 return getValueControlsConfig(ref, values);
1792 });
1793 var controls = useValueAnimationControls(controlsConfig, props, shouldInheritVariant, parentContext);
1794 var context = useMotionContext(parentContext, controls, values, isStatic, props);
1795 var functionality = isStatic
1796 ? null
1797 : loadFunctionalityComponents(ref, values, props, parentContext, controls, shouldInheritVariant);
1798 var renderedComponent = renderComponent(ref, style, values, props, isStatic);
1799 return (React.createElement(React.Fragment, null,
1800 React.createElement(MotionContext.Provider, { value: context }, renderedComponent),
1801 React.createElement(React.Fragment, null,
1802 React.createElement(Mount, { innerRef: ref, values: values, isStatic: isStatic }),
1803 functionality)));
1804 }
1805 return React.forwardRef(MotionComponent);
1806};
1807
1808/**
1809 * @internal
1810 */
1811var htmlElements = [
1812 "a",
1813 "abbr",
1814 "address",
1815 "area",
1816 "article",
1817 "aside",
1818 "audio",
1819 "b",
1820 "base",
1821 "bdi",
1822 "bdo",
1823 "big",
1824 "blockquote",
1825 "body",
1826 "br",
1827 "button",
1828 "canvas",
1829 "caption",
1830 "cite",
1831 "code",
1832 "col",
1833 "colgroup",
1834 "data",
1835 "datalist",
1836 "dd",
1837 "del",
1838 "details",
1839 "dfn",
1840 "dialog",
1841 "div",
1842 "dl",
1843 "dt",
1844 "em",
1845 "embed",
1846 "fieldset",
1847 "figcaption",
1848 "figure",
1849 "footer",
1850 "form",
1851 "h1",
1852 "h2",
1853 "h3",
1854 "h4",
1855 "h5",
1856 "h6",
1857 "head",
1858 "header",
1859 "hgroup",
1860 "hr",
1861 "html",
1862 "i",
1863 "iframe",
1864 "img",
1865 "input",
1866 "ins",
1867 "kbd",
1868 "keygen",
1869 "label",
1870 "legend",
1871 "li",
1872 "link",
1873 "main",
1874 "map",
1875 "mark",
1876 "menu",
1877 "menuitem",
1878 "meta",
1879 "meter",
1880 "nav",
1881 "noscript",
1882 "object",
1883 "ol",
1884 "optgroup",
1885 "option",
1886 "output",
1887 "p",
1888 "param",
1889 "picture",
1890 "pre",
1891 "progress",
1892 "q",
1893 "rp",
1894 "rt",
1895 "ruby",
1896 "s",
1897 "samp",
1898 "script",
1899 "section",
1900 "select",
1901 "small",
1902 "source",
1903 "span",
1904 "strong",
1905 "style",
1906 "sub",
1907 "summary",
1908 "sup",
1909 "table",
1910 "tbody",
1911 "td",
1912 "textarea",
1913 "tfoot",
1914 "th",
1915 "thead",
1916 "time",
1917 "title",
1918 "tr",
1919 "track",
1920 "u",
1921 "ul",
1922 "var",
1923 "video",
1924 "wbr",
1925 "webview",
1926];
1927/**
1928 * @internal
1929 */
1930var svgElements = [
1931 "animate",
1932 "circle",
1933 "clipPath",
1934 "defs",
1935 "desc",
1936 "ellipse",
1937 "feBlend",
1938 "feColorMatrix",
1939 "feComponentTransfer",
1940 "feComposite",
1941 "feConvolveMatrix",
1942 "feDiffuseLighting",
1943 "feDisplacementMap",
1944 "feDistantLight",
1945 "feDropShadow",
1946 "feFlood",
1947 "feFuncA",
1948 "feFuncB",
1949 "feFuncG",
1950 "feFuncR",
1951 "feGaussianBlur",
1952 "feImage",
1953 "feMerge",
1954 "feMergeNode",
1955 "feMorphology",
1956 "feOffset",
1957 "fePointLight",
1958 "feSpecularLighting",
1959 "feSpotLight",
1960 "feTile",
1961 "feTurbulence",
1962 "filter",
1963 "foreignObject",
1964 "g",
1965 "image",
1966 "line",
1967 "linearGradient",
1968 "marker",
1969 "mask",
1970 "metadata",
1971 "path",
1972 "pattern",
1973 "polygon",
1974 "polyline",
1975 "radialGradient",
1976 "rect",
1977 "stop",
1978 "svg",
1979 "switch",
1980 "symbol",
1981 "text",
1982 "textPath",
1983 "tspan",
1984 "use",
1985 "view",
1986];
1987
1988/**
1989 * @internal
1990 */
1991var MotionPluginContext = React.createContext({
1992 transformPagePoint: function (p) { return p; },
1993});
1994/**
1995 * @remarks For now I think this should remain a private API for our own use
1996 * until we can figure out a nicer way of allowing people to add these
1997 *
1998 * @internal
1999 */
2000function MotionPlugins(_a) {
2001 var children = _a.children, props = tslib.__rest(_a, ["children"]);
2002 var pluginContext = React.useContext(MotionPluginContext);
2003 var value = React.useRef(tslib.__assign({}, pluginContext)).current;
2004 // Mutative to prevent triggering rerenders in all listening
2005 // components every time this component renders
2006 for (var key in props) {
2007 value[key] = props[key];
2008 }
2009 return (React.createElement(MotionPluginContext.Provider, { value: value }, children));
2010}
2011
2012function useUnmountEffect(callback) {
2013 return React.useEffect(function () { return function () { return callback(); }; }, []);
2014}
2015
2016function addDomEvent(target, eventName, handler, options) {
2017 if (!handler)
2018 return;
2019 target.addEventListener(eventName, handler, options);
2020 return function () { return target.removeEventListener(eventName, handler, options); };
2021}
2022/**
2023 * Attaches an event listener directly to the provided DOM element.
2024 *
2025 * Bypassing React's event system can be desirable, for instance when attaching non-passive
2026 * event handlers.
2027 *
2028 * ```jsx
2029 * const ref = useRef(null)
2030 *
2031 * useDomEvent(ref, 'wheel', onWheel, { passive: false })
2032 *
2033 * return <div ref={ref} />
2034 * ```
2035 *
2036 * @param ref - React.RefObject that's been provided to the element you want to bind the listener to.
2037 * @param eventName - Name of the event you want listen for.
2038 * @param handler - Function to fire when receiving the event.
2039 * @param options - Options to pass to `Event.addEventListener`.
2040 *
2041 * @public
2042 */
2043function useDomEvent(ref, eventName, handler, options) {
2044 React.useEffect(function () {
2045 var element = ref.current;
2046 if (handler && element) {
2047 return addDomEvent(element, eventName, handler, options);
2048 }
2049 }, [ref, eventName, handler, options]);
2050}
2051
2052function isMouseEvent(event) {
2053 // PointerEvent inherits from MouseEvent so we can't use a straight instanceof check.
2054 if (typeof PointerEvent !== "undefined" && event instanceof PointerEvent) {
2055 return !!(event.pointerType === "mouse");
2056 }
2057 return event instanceof MouseEvent;
2058}
2059function isTouchEvent(event) {
2060 var hasTouches = !!event.touches;
2061 return hasTouches;
2062}
2063
2064/**
2065 * Filters out events not attached to the primary pointer (currently left mouse button)
2066 * @param eventHandler
2067 */
2068function filterPrimaryPointer(eventHandler) {
2069 if (!eventHandler)
2070 return undefined;
2071 return function (event) {
2072 var isMouseEvent = event instanceof MouseEvent;
2073 var isPrimaryPointer = !isMouseEvent ||
2074 (isMouseEvent && event.button === 0);
2075 if (isPrimaryPointer) {
2076 eventHandler(event);
2077 }
2078 };
2079}
2080var defaultPagePoint = { pageX: 0, pageY: 0 };
2081function pointFromTouch(e) {
2082 var primaryTouch = e.touches[0] || e.changedTouches[0];
2083 var _a = primaryTouch || defaultPagePoint, pageX = _a.pageX, pageY = _a.pageY;
2084 return { x: pageX, y: pageY };
2085}
2086function pointFromMouse(_a) {
2087 var _b = _a.pageX, pageX = _b === void 0 ? 0 : _b, _c = _a.pageY, pageY = _c === void 0 ? 0 : _c;
2088 return { x: pageX, y: pageY };
2089}
2090function extractEventInfo(event) {
2091 return {
2092 point: isTouchEvent(event)
2093 ? pointFromTouch(event)
2094 : pointFromMouse(event),
2095 };
2096}
2097var wrapHandler = function (handler, shouldFilterPrimaryPointer) {
2098 if (shouldFilterPrimaryPointer === void 0) { shouldFilterPrimaryPointer = false; }
2099 if (!handler)
2100 return;
2101 var listener = function (event) { return handler(event, extractEventInfo(event)); };
2102 return shouldFilterPrimaryPointer
2103 ? filterPrimaryPointer(listener)
2104 : listener;
2105};
2106
2107var isBrowser = typeof window !== "undefined";
2108// We check for event support via functions in case they've been mocked by a testing suite.
2109var supportsPointerEvents = function () {
2110 return isBrowser && window.onpointerdown === null;
2111};
2112var supportsTouchEvents = function () {
2113 return isBrowser && window.ontouchstart === null;
2114};
2115var supportsMouseEvents = function () {
2116 return isBrowser && window.onmousedown === null;
2117};
2118
2119var mouseEventNames = {
2120 pointerdown: "mousedown",
2121 pointermove: "mousemove",
2122 pointerup: "mouseup",
2123 pointercancel: "mousecancel",
2124 pointerover: "mouseover",
2125 pointerout: "mouseout",
2126 pointerenter: "mouseenter",
2127 pointerleave: "mouseleave",
2128};
2129var touchEventNames = {
2130 pointerdown: "touchstart",
2131 pointermove: "touchmove",
2132 pointerup: "touchend",
2133 pointercancel: "touchcancel",
2134};
2135function getPointerEventName(name) {
2136 if (supportsPointerEvents()) {
2137 return name;
2138 }
2139 else if (supportsTouchEvents()) {
2140 return touchEventNames[name];
2141 }
2142 else if (supportsMouseEvents()) {
2143 return mouseEventNames[name];
2144 }
2145 return name;
2146}
2147function addPointerEvent(target, eventName, handler, options) {
2148 return addDomEvent(target, getPointerEventName(eventName), wrapHandler(handler, eventName === "pointerdown"), options);
2149}
2150function usePointerEvent(ref, eventName, handler, options) {
2151 return useDomEvent(ref, getPointerEventName(eventName), wrapHandler(handler, eventName === "pointerdown"), options);
2152}
2153
2154/** @public */
2155(function (Point) {
2156 /** @beta */
2157 Point.subtract = function (a, b) {
2158 return { x: a.x - b.x, y: a.y - b.y };
2159 };
2160 /** @beta */
2161 Point.relativeTo = function (idOrElem) {
2162 var elem;
2163 var getElem = function () {
2164 // Caching element here could be leaky because of React lifecycle
2165 if (elem !== undefined)
2166 return elem;
2167 if (typeof idOrElem === "string") {
2168 elem = document.getElementById(idOrElem);
2169 }
2170 else {
2171 elem = idOrElem;
2172 }
2173 return elem;
2174 };
2175 return function (_a) {
2176 var x = _a.x, y = _a.y;
2177 var localElem = getElem();
2178 if (!localElem)
2179 return undefined;
2180 var rect = localElem.getBoundingClientRect();
2181 return {
2182 x: x - rect.left - window.scrollX,
2183 y: y - rect.top - window.scrollY,
2184 };
2185 };
2186 };
2187})(exports.Point || (exports.Point = {}));
2188
2189var isViewportScrollBlocked = false;
2190var isBrowser$1 = typeof window !== "undefined";
2191if (isBrowser$1) {
2192 document.addEventListener("touchmove", function (event) {
2193 if (isViewportScrollBlocked) {
2194 event.preventDefault();
2195 }
2196 }, { passive: false });
2197}
2198var blockViewportScroll = function () { return (isViewportScrollBlocked = true); };
2199var unblockViewportScroll = function () { return (isViewportScrollBlocked = false); };
2200
2201/**
2202 * @internal
2203 */
2204var PanSession = /** @class */ (function () {
2205 function PanSession(event, handlers, _a) {
2206 var _this = this;
2207 var transformPagePoint = (_a === void 0 ? {} : _a).transformPagePoint;
2208 /**
2209 * @internal
2210 */
2211 this.startEvent = null;
2212 /**
2213 * @internal
2214 */
2215 this.lastMoveEvent = null;
2216 /**
2217 * @internal
2218 */
2219 this.lastMoveEventInfo = null;
2220 /**
2221 * @internal
2222 */
2223 this.handlers = {};
2224 this.updatePoint = function () {
2225 if (!(_this.lastMoveEvent && _this.lastMoveEventInfo))
2226 return;
2227 var info = getPanInfo(_this.lastMoveEventInfo, _this.history);
2228 var isPanStarted = _this.startEvent !== null;
2229 // Only start panning if the offset is larger than 3 pixels. If we make it
2230 // any larger than this we'll want to reset the pointer history
2231 // on the first update to avoid visual snapping to the cursoe.
2232 var isDistancePastThreshold = popcorn.distance(info.offset, { x: 0, y: 0 }) >= 3;
2233 if (!isPanStarted && !isDistancePastThreshold)
2234 return;
2235 var point = info.point;
2236 var timestamp = sync.getFrameData().timestamp;
2237 _this.history.push(tslib.__assign(tslib.__assign({}, point), { timestamp: timestamp }));
2238 var _a = _this.handlers, onStart = _a.onStart, onMove = _a.onMove;
2239 if (!isPanStarted) {
2240 onStart && onStart(_this.lastMoveEvent, info);
2241 _this.startEvent = _this.lastMoveEvent;
2242 }
2243 onMove && onMove(_this.lastMoveEvent, info);
2244 };
2245 // If we have more than one touch, don't start detecting this gesture
2246 if (isTouchEvent(event) && event.touches.length > 1)
2247 return;
2248 this.handlers = handlers;
2249 this.transformPagePoint = transformPagePoint;
2250 var info = extractEventInfo(event);
2251 var initialInfo = transformPoint(info, this.transformPagePoint);
2252 var point = initialInfo.point;
2253 var timestamp = sync.getFrameData().timestamp;
2254 this.history = [tslib.__assign(tslib.__assign({}, point), { timestamp: timestamp })];
2255 var onSessionStart = handlers.onSessionStart;
2256 onSessionStart &&
2257 onSessionStart(event, getPanInfo(initialInfo, this.history));
2258 var removeOnPointerMove = addPointerEvent(window, "pointermove", function (event, info) { return _this.handlePointerMove(event, info); });
2259 var removeOnPointerUp = addPointerEvent(window, "pointerup", function (event, info) { return _this.handlePointerUp(event, info); });
2260 this.removeListeners = function () {
2261 removeOnPointerMove && removeOnPointerMove();
2262 removeOnPointerUp && removeOnPointerUp();
2263 };
2264 }
2265 PanSession.prototype.handlePointerMove = function (event, info) {
2266 this.lastMoveEvent = event;
2267 this.lastMoveEventInfo = transformPoint(info, this.transformPagePoint);
2268 // Because Safari doesn't trigger mouseup events when it's above a `<select>`
2269 if (isMouseEvent(event) && event.buttons === 0) {
2270 this.handlePointerUp(event, info);
2271 return;
2272 }
2273 // Throttle mouse move event to once per frame
2274 sync__default.update(this.updatePoint, true);
2275 };
2276 PanSession.prototype.handlePointerUp = function (event, info) {
2277 this.end();
2278 var onEnd = this.handlers.onEnd;
2279 if (!onEnd)
2280 return;
2281 var panInfo = getPanInfo(transformPoint(info, this.transformPagePoint), this.history);
2282 onEnd && onEnd(event, panInfo);
2283 };
2284 PanSession.prototype.updateHandlers = function (handlers) {
2285 this.handlers = handlers;
2286 };
2287 PanSession.prototype.end = function () {
2288 this.removeListeners && this.removeListeners();
2289 sync.cancelSync.update(this.updatePoint);
2290 unblockViewportScroll();
2291 };
2292 return PanSession;
2293}());
2294function transformPoint(info, transformPagePoint) {
2295 return transformPagePoint ? { point: transformPagePoint(info.point) } : info;
2296}
2297function getPanInfo(_a, history) {
2298 var point = _a.point;
2299 return {
2300 point: point,
2301 delta: exports.Point.subtract(point, lastDevicePoint(history)),
2302 offset: exports.Point.subtract(point, startDevicePoint(history)),
2303 velocity: getVelocity$1(history, 0.1),
2304 };
2305}
2306function startDevicePoint(history) {
2307 return history[0];
2308}
2309function lastDevicePoint(history) {
2310 return history[history.length - 1];
2311}
2312function getVelocity$1(history, timeDelta) {
2313 if (history.length < 2) {
2314 return { x: 0, y: 0 };
2315 }
2316 var i = history.length - 1;
2317 var timestampedPoint = null;
2318 var lastPoint = lastDevicePoint(history);
2319 while (i >= 0) {
2320 timestampedPoint = history[i];
2321 if (lastPoint.timestamp - timestampedPoint.timestamp >
2322 secondsToMilliseconds(timeDelta)) {
2323 break;
2324 }
2325 i--;
2326 }
2327 if (!timestampedPoint) {
2328 return { x: 0, y: 0 };
2329 }
2330 var time = (lastPoint.timestamp - timestampedPoint.timestamp) / 1000;
2331 if (time === 0) {
2332 return { x: 0, y: 0 };
2333 }
2334 var currentVelocity = {
2335 x: (lastPoint.x - timestampedPoint.x) / time,
2336 y: (lastPoint.y - timestampedPoint.y) / time,
2337 };
2338 if (currentVelocity.x === Infinity) {
2339 currentVelocity.x = 0;
2340 }
2341 if (currentVelocity.y === Infinity) {
2342 currentVelocity.y = 0;
2343 }
2344 return currentVelocity;
2345}
2346
2347/**
2348 *
2349 * @param handlers -
2350 * @param ref -
2351 *
2352 * @internalremarks
2353 * Currently this sets new pan gesture functions every render. The memo route has been explored
2354 * in the past but ultimately we're still creating new functions every render. An optimisation
2355 * to explore is creating the pan gestures and loading them into a `ref`.
2356 *
2357 * @internal
2358 */
2359function usePanGesture(_a, ref) {
2360 var onPan = _a.onPan, onPanStart = _a.onPanStart, onPanEnd = _a.onPanEnd, onPanSessionStart = _a.onPanSessionStart;
2361 var hasPanEvents = onPan || onPanStart || onPanEnd || onPanSessionStart;
2362 var panSession = React.useRef(null);
2363 var transformPagePoint = React.useContext(MotionPluginContext).transformPagePoint;
2364 var handlers = {
2365 onSessionStart: onPanSessionStart,
2366 onStart: onPanStart,
2367 onMove: onPan,
2368 onEnd: function (event, info) {
2369 panSession.current = null;
2370 onPanEnd && onPanEnd(event, info);
2371 },
2372 };
2373 if (panSession.current !== null) {
2374 panSession.current.updateHandlers(handlers);
2375 }
2376 function onPointerDown(event) {
2377 panSession.current = new PanSession(event, handlers, {
2378 transformPagePoint: transformPagePoint,
2379 });
2380 }
2381 usePointerEvent(ref, "pointerdown", hasPanEvents && onPointerDown);
2382 useUnmountEffect(function () { return panSession.current && panSession.current.end(); });
2383}
2384
2385/**
2386 * Recursively traverse up the tree to check whether the provided child node
2387 * is the parent or a descendant of it.
2388 *
2389 * @param parent - Element to find
2390 * @param child - Element to test against parent
2391 */
2392var isNodeOrChild = function (parent, child) {
2393 if (!child) {
2394 return false;
2395 }
2396 else if (parent === child) {
2397 return true;
2398 }
2399 else {
2400 return isNodeOrChild(parent, child.parentElement);
2401 }
2402};
2403
2404var order = ["whileHover", "whileTap", "whileDrag"];
2405var getGesturePriority = function (gesture) {
2406 return order.indexOf(gesture) + 1;
2407};
2408
2409function createLock(name) {
2410 var lock = null;
2411 return function () {
2412 var openLock = function () {
2413 lock = null;
2414 };
2415 if (lock === null) {
2416 lock = name;
2417 return openLock;
2418 }
2419 return false;
2420 };
2421}
2422var globalHorizontalLock = createLock("dragHorizontal");
2423var globalVerticalLock = createLock("dragVertical");
2424function getGlobalLock(drag) {
2425 var lock = false;
2426 if (drag === "y") {
2427 lock = globalVerticalLock();
2428 }
2429 else if (drag === "x") {
2430 lock = globalHorizontalLock();
2431 }
2432 else {
2433 var openHorizontal_1 = globalHorizontalLock();
2434 var openVertical_1 = globalVerticalLock();
2435 if (openHorizontal_1 && openVertical_1) {
2436 lock = function () {
2437 openHorizontal_1();
2438 openVertical_1();
2439 };
2440 }
2441 else {
2442 // Release the locks because we don't use them
2443 if (openHorizontal_1)
2444 openHorizontal_1();
2445 if (openVertical_1)
2446 openVertical_1();
2447 }
2448 }
2449 return lock;
2450}
2451
2452var tapGesturePriority = getGesturePriority("whileTap");
2453/**
2454 * @param handlers -
2455 * @internal
2456 */
2457function useTapGesture(_a, ref) {
2458 var onTap = _a.onTap, onTapStart = _a.onTapStart, onTapCancel = _a.onTapCancel, whileTap = _a.whileTap, controls = _a.controls;
2459 var hasTapListeners = onTap || onTapStart || onTapCancel || whileTap;
2460 var isTapping = React.useRef(false);
2461 var cancelPointerEventListener = React.useRef(null);
2462 function removePointerUp() {
2463 cancelPointerEventListener.current &&
2464 cancelPointerEventListener.current();
2465 cancelPointerEventListener.current = null;
2466 }
2467 if (whileTap && controls) {
2468 controls.setOverride(whileTap, tapGesturePriority);
2469 }
2470 // We load this event handler into a ref so we can later refer to
2471 // onPointerUp.current which will always have reference to the latest props
2472 var onPointerUp = React.useRef(null);
2473 onPointerUp.current = function (event, info) {
2474 var element = ref.current;
2475 removePointerUp();
2476 if (!isTapping.current || !element)
2477 return;
2478 isTapping.current = false;
2479 if (controls && whileTap) {
2480 controls.clearOverride(tapGesturePriority);
2481 }
2482 // Check the gesture lock - if we get it, it means no drag gesture is active
2483 // and we can safely fire the tap gesture.
2484 var openGestureLock = getGlobalLock(true);
2485 if (!openGestureLock)
2486 return;
2487 openGestureLock();
2488 if (!isNodeOrChild(element, event.target)) {
2489 onTapCancel && onTapCancel(event, info);
2490 }
2491 else {
2492 onTap && onTap(event, info);
2493 }
2494 };
2495 function onPointerDown(event, info) {
2496 removePointerUp();
2497 cancelPointerEventListener.current = addPointerEvent(window, "pointerup", function (event, info) { return onPointerUp.current(event, info); });
2498 var element = ref.current;
2499 if (!element || isTapping.current)
2500 return;
2501 isTapping.current = true;
2502 onTapStart && onTapStart(event, info);
2503 if (controls && whileTap) {
2504 controls.startOverride(tapGesturePriority);
2505 }
2506 }
2507 usePointerEvent(ref, "pointerdown", hasTapListeners ? onPointerDown : undefined);
2508 useUnmountEffect(removePointerUp);
2509}
2510
2511var hoverPriority = getGesturePriority("whileHover");
2512var filterTouch = function (listener) { return function (event, info) {
2513 if (isMouseEvent(event))
2514 listener(event, info);
2515}; };
2516/**
2517 *
2518 * @param props
2519 * @param ref
2520 * @internal
2521 */
2522function useHoverGesture(_a, ref) {
2523 var whileHover = _a.whileHover, onHoverStart = _a.onHoverStart, onHoverEnd = _a.onHoverEnd, controls = _a.controls;
2524 if (whileHover && controls) {
2525 controls.setOverride(whileHover, hoverPriority);
2526 }
2527 usePointerEvent(ref, "pointerenter", filterTouch(function (event, info) {
2528 if (onHoverStart)
2529 onHoverStart(event, info);
2530 if (whileHover && controls) {
2531 controls.startOverride(hoverPriority);
2532 }
2533 }));
2534 usePointerEvent(ref, "pointerleave", filterTouch(function (event, info) {
2535 if (onHoverEnd)
2536 onHoverEnd(event, info);
2537 if (whileHover && controls) {
2538 controls.clearOverride(hoverPriority);
2539 }
2540 }));
2541}
2542
2543/**
2544 * Add pan and tap gesture recognition to an element.
2545 *
2546 * @param props - Gesture event handlers
2547 * @param ref - React `ref` containing a DOM `Element`
2548 * @public
2549 */
2550function useGestures(props, ref) {
2551 usePanGesture(props, ref);
2552 useTapGesture(props, ref);
2553 useHoverGesture(props, ref);
2554}
2555
2556var makeRenderlessComponent = function (hook) { return function (props) {
2557 hook(props);
2558 return null;
2559}; };
2560
2561var gestureProps = [
2562 "onPan",
2563 "onPanStart",
2564 "onPanEnd",
2565 "onPanSessionStart",
2566 "onTap",
2567 "onTapStart",
2568 "onTapCancel",
2569 "whileTap",
2570 "whileHover",
2571 "onHoverStart",
2572 "onHoverEnd",
2573];
2574var Gestures = {
2575 key: "gestures",
2576 shouldRender: function (props) {
2577 return gestureProps.some(function (key) { return props.hasOwnProperty(key); });
2578 },
2579 Component: makeRenderlessComponent(function (_a) {
2580 var innerRef = _a.innerRef, props = tslib.__rest(_a, ["innerRef"]);
2581 useGestures(props, innerRef);
2582 }),
2583};
2584
2585var isRefObject = function (ref) {
2586 return typeof ref === "object" && ref.hasOwnProperty("current");
2587};
2588
2589var noop = function (v) { return v; };
2590/**
2591 * Don't block the default pointerdown behaviour of these elements.
2592 */
2593var allowDefaultPointerDown = new Set(["INPUT", "TEXTAREA", "SELECT"]);
2594var ComponentDragControls = /** @class */ (function () {
2595 function ComponentDragControls(_a) {
2596 var ref = _a.ref, values = _a.values, controls = _a.controls;
2597 /**
2598 * Track whether we're currently dragging.
2599 *
2600 * @internal
2601 */
2602 this.isDragging = false;
2603 /**
2604 * The current direction of drag, or `null` if both.
2605 *
2606 * @internal
2607 */
2608 this.currentDirection = null;
2609 /**
2610 * The permitted t/r/b/l boundaries of travel, in pixels.
2611 *
2612 * @internal
2613 */
2614 this.constraints = false;
2615 /**
2616 * A reference to the host component's latest props.
2617 *
2618 * @internal
2619 */
2620 this.props = {
2621 transformPagePoint: noop,
2622 };
2623 /**
2624 * References to the MotionValues used for tracking the current dragged point.
2625 *
2626 * @internal
2627 */
2628 this.point = {};
2629 /**
2630 * The origin point for the current drag gesture.
2631 *
2632 * @internal
2633 */
2634 this.origin = {
2635 x: motionValue(0),
2636 y: motionValue(0),
2637 };
2638 // This is a reference to the global drag gesture lock, ensuring only one component
2639 // can "capture" the drag of one or both axes.
2640 // TODO: Look into moving this into pansession?
2641 this.openGlobalLock = null;
2642 /**
2643 * @internal
2644 */
2645 this.panSession = null;
2646 /**
2647 * A reference to the previous constraints bounding box
2648 *
2649 * @internal
2650 */
2651 this.prevConstraintsBox = {
2652 width: 0,
2653 height: 0,
2654 x: 0,
2655 y: 0,
2656 };
2657 this.ref = ref;
2658 this.values = values;
2659 this.controls = controls;
2660 }
2661 /**
2662 * Start dragging the host component.
2663 *
2664 * @param event - The originating pointer event.
2665 * @param options -
2666 *
2667 * @public
2668 */
2669 ComponentDragControls.prototype.start = function (originEvent, _a) {
2670 var _this = this;
2671 var _b = (_a === void 0 ? {} : _a).snapToCursor, snapToCursor = _b === void 0 ? false : _b;
2672 snapToCursor && this.snapToCursor(originEvent);
2673 var onSessionStart = function (event) {
2674 // Prevent browser-specific behaviours like text selection or Chrome's image dragging.
2675 if (event.target &&
2676 !allowDefaultPointerDown.has(event.target.tagName)) {
2677 // On iOS it's important to not `preventDefault` the `touchstart`
2678 // event, as otherwise clicks won't fire inside the draggable element.
2679 if (!supportsTouchEvents()) {
2680 event.preventDefault();
2681 // Make sure input elements loose focus when we prevent the default.
2682 if (document.activeElement instanceof HTMLElement) {
2683 document.activeElement.blur();
2684 }
2685 }
2686 }
2687 // Initiate viewport scroll blocking on touch start. This is a very aggressive approach
2688 // which has come out of the difficulty in us being able to do this once a scroll gesture
2689 // has initiated in mobile browsers. This means if there's a horizontally-scrolling carousel
2690 // on a page we can't let a user scroll the page itself from it. Ideally what we'd do is
2691 // trigger this once we've got a scroll direction determined. This approach sort-of worked
2692 // but if the component was dragged too far in a single frame page scrolling would initiate.
2693 blockViewportScroll();
2694 // Stop any animations on both axis values immediately. This allows the user to throw and catch
2695 // the component.
2696 bothAxis(function (axis) {
2697 var axisPoint = _this.point[axis];
2698 axisPoint && axisPoint.stop();
2699 });
2700 };
2701 var onStart = function (event, info) {
2702 // If constraints are an element, resolve them again in case they've updated.
2703 if (_this.constraintsNeedResolution) {
2704 var _a = _this.props, dragConstraints = _a.dragConstraints, transformPagePoint_1 = _a.transformPagePoint;
2705 _this.constraints = calculateConstraintsFromDom(dragConstraints, _this.ref, _this.point, transformPagePoint_1);
2706 _this.applyConstraintsToPoint();
2707 }
2708 // Set point origin and stop any existing animations.
2709 bothAxis(function (axis) {
2710 var axisPoint = _this.point[axis];
2711 if (!axisPoint)
2712 return;
2713 _this.origin[axis].set(axisPoint.get());
2714 });
2715 // Attempt to grab the global drag gesture lock - maybe make this part of PanSession
2716 var _b = _this.props, drag = _b.drag, dragPropagation = _b.dragPropagation;
2717 if (drag && !dragPropagation) {
2718 if (_this.openGlobalLock)
2719 _this.openGlobalLock();
2720 _this.openGlobalLock = getGlobalLock(drag);
2721 if (!_this.openGlobalLock)
2722 return;
2723 }
2724 _this.isDragging = true;
2725 _this.currentDirection = null;
2726 var onDragStart = _this.props.onDragStart;
2727 onDragStart &&
2728 onDragStart(event, convertPanToDrag(info, _this.point));
2729 };
2730 var onMove = function (event, info) {
2731 var _a = _this.props, dragPropagation = _a.dragPropagation, dragDirectionLock = _a.dragDirectionLock;
2732 // If we didn't successfully receive the gesture lock, early return.
2733 if (!dragPropagation && !_this.openGlobalLock)
2734 return;
2735 var offset = info.offset;
2736 // Attempt to detect drag direction if directionLock is true
2737 if (dragDirectionLock && _this.currentDirection === null) {
2738 _this.currentDirection = getCurrentDirection(offset);
2739 // If we've successfully set a direction, notify listener
2740 if (_this.currentDirection !== null) {
2741 var onDirectionLock = _this.props.onDirectionLock;
2742 onDirectionLock && onDirectionLock(_this.currentDirection);
2743 }
2744 return;
2745 }
2746 _this.updatePoint("x", offset);
2747 _this.updatePoint("y", offset);
2748 var onDrag = _this.props.onDrag;
2749 onDrag && onDrag(event, convertPanToDrag(info, _this.point));
2750 };
2751 var onEnd = function (event, info) {
2752 _this.stop(event, info);
2753 };
2754 var transformPagePoint = this.props.transformPagePoint;
2755 this.panSession = new PanSession(originEvent, {
2756 onSessionStart: onSessionStart,
2757 onStart: onStart,
2758 onMove: onMove,
2759 onEnd: onEnd,
2760 }, { transformPagePoint: transformPagePoint });
2761 };
2762 ComponentDragControls.prototype.cancelDrag = function () {
2763 unblockViewportScroll();
2764 this.isDragging = false;
2765 this.panSession && this.panSession.end();
2766 this.panSession = null;
2767 if (!this.props.dragPropagation && this.openGlobalLock) {
2768 this.openGlobalLock();
2769 this.openGlobalLock = null;
2770 }
2771 };
2772 ComponentDragControls.prototype.stop = function (event, info) {
2773 var _a;
2774 (_a = this.panSession) === null || _a === void 0 ? void 0 : _a.end();
2775 this.panSession = null;
2776 var isDragging = this.isDragging;
2777 this.cancelDrag();
2778 if (!isDragging)
2779 return;
2780 var _b = this.props, dragMomentum = _b.dragMomentum, dragElastic = _b.dragElastic, onDragEnd = _b.onDragEnd;
2781 if (dragMomentum || dragElastic) {
2782 var velocity = info.velocity;
2783 this.animateDragEnd(velocity);
2784 }
2785 else {
2786 this.recordBoxInfo(this.constraints);
2787 }
2788 onDragEnd && onDragEnd(event, convertPanToDrag(info, this.point));
2789 };
2790 ComponentDragControls.prototype.recordBoxInfo = function (constraints) {
2791 if (constraints) {
2792 var right = constraints.right, left = constraints.left, bottom = constraints.bottom, top_1 = constraints.top;
2793 this.prevConstraintsBox.width = (right || 0) - (left || 0);
2794 this.prevConstraintsBox.height = (bottom || 0) - (top_1 || 0);
2795 }
2796 if (this.point.x)
2797 this.prevConstraintsBox.x = this.point.x.get();
2798 if (this.point.y)
2799 this.prevConstraintsBox.y = this.point.y.get();
2800 };
2801 ComponentDragControls.prototype.snapToCursor = function (event) {
2802 var _this = this;
2803 var transformPagePoint = this.props.transformPagePoint;
2804 var point = extractEventInfo(event).point;
2805 var boundingBox = getBoundingBox(this.ref, transformPagePoint);
2806 var center = {
2807 x: boundingBox.width / 2 + boundingBox.left + window.scrollX,
2808 y: boundingBox.height / 2 + boundingBox.top + window.scrollY,
2809 };
2810 var offset = {
2811 x: point.x - center.x,
2812 y: point.y - center.y,
2813 };
2814 bothAxis(function (axis) {
2815 var point = _this.point[axis];
2816 if (!point)
2817 return;
2818 _this.origin[axis].set(point.get());
2819 });
2820 this.updatePoint("x", offset);
2821 this.updatePoint("y", offset);
2822 };
2823 ComponentDragControls.prototype.setPoint = function (axis, value) {
2824 this.point[axis] = value;
2825 };
2826 ComponentDragControls.prototype.updatePoint = function (axis, offset) {
2827 var _a = this.props, drag = _a.drag, dragElastic = _a.dragElastic;
2828 var axisPoint = this.point[axis];
2829 // If we're not dragging this axis, do an early return.
2830 if (!shouldDrag(axis, drag, this.currentDirection) || !axisPoint)
2831 return;
2832 var current = applyConstraints(axis, this.origin[axis].get() + offset[axis], this.constraints, dragElastic);
2833 axisPoint.set(current);
2834 };
2835 ComponentDragControls.prototype.updateProps = function (_a) {
2836 var _this = this;
2837 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 ? true : _f, _g = _a.dragMomentum, dragMomentum = _g === void 0 ? true : _g, remainingProps = tslib.__rest(_a, ["drag", "dragDirectionLock", "dragPropagation", "dragConstraints", "dragElastic", "dragMomentum"]);
2838 this.props = tslib.__assign({ drag: drag,
2839 dragDirectionLock: dragDirectionLock,
2840 dragPropagation: dragPropagation,
2841 dragConstraints: dragConstraints,
2842 dragElastic: dragElastic,
2843 dragMomentum: dragMomentum }, remainingProps);
2844 var _dragValueX = remainingProps._dragValueX, _dragValueY = remainingProps._dragValueY, dragOriginX = remainingProps.dragOriginX, dragOriginY = remainingProps.dragOriginY;
2845 if (dragOriginX)
2846 this.origin.x = dragOriginX;
2847 if (dragOriginY)
2848 this.origin.y = dragOriginY;
2849 // Get the `MotionValue` for both draggable axes, or create them if they don't already
2850 // exist on this component.
2851 bothAxis(function (axis) {
2852 if (!shouldDrag(axis, drag, _this.currentDirection))
2853 return;
2854 var defaultValue = axis === "x" ? _dragValueX : _dragValueY;
2855 _this.setPoint(axis, defaultValue || _this.values.get(axis, 0));
2856 });
2857 // If `dragConstraints` is a React `ref`, we should resolve the constraints once the
2858 // component has rendered.
2859 this.constraintsNeedResolution = isRefObject(dragConstraints);
2860 this.constraints = this.constraintsNeedResolution
2861 ? this.constraints || false
2862 : dragConstraints;
2863 };
2864 ComponentDragControls.prototype.applyConstraintsToPoint = function (constraints) {
2865 var _this = this;
2866 if (constraints === void 0) { constraints = this.constraints; }
2867 return bothAxis(function (axis) {
2868 var axisPoint = _this.point[axis];
2869 axisPoint &&
2870 !axisPoint.isAnimating() &&
2871 applyConstraints(axis, axisPoint, constraints, 0);
2872 });
2873 };
2874 ComponentDragControls.prototype.animateDragEnd = function (velocity) {
2875 var _this = this;
2876 var _a = this.props, drag = _a.drag, dragMomentum = _a.dragMomentum, dragElastic = _a.dragElastic, dragTransition = _a.dragTransition, _dragValueX = _a._dragValueX, _dragValueY = _a._dragValueY, _dragTransitionControls = _a._dragTransitionControls;
2877 var momentumAnimations = bothAxis(function (axis) {
2878 var _a;
2879 if (!shouldDrag(axis, drag, _this.currentDirection)) {
2880 return;
2881 }
2882 var transition = _this.constraints
2883 ? getConstraints(axis, _this.constraints)
2884 : {};
2885 /**
2886 * Overdamp the boundary spring if `dragElastic` is disabled. There's still a frame
2887 * of spring animations so we should look into adding a disable spring option to `inertia`.
2888 * We could do something here where we affect the `bounceStiffness` and `bounceDamping`
2889 * using the value of `dragElastic`.
2890 */
2891 var bounceStiffness = dragElastic ? 200 : 1000000;
2892 var bounceDamping = dragElastic ? 40 : 10000000;
2893 var animationControls = _dragTransitionControls || _this.controls;
2894 var inertia = tslib.__assign(tslib.__assign({ type: "inertia", velocity: dragMomentum ? velocity[axis] : 0, bounceStiffness: bounceStiffness,
2895 bounceDamping: bounceDamping, timeConstant: 750, restDelta: 1 }, dragTransition), transition);
2896 var externalAxisMotionValue = axis === "x" ? _dragValueX : _dragValueY;
2897 // If we're not animating on an externally-provided `MotionValue` we can use the
2898 // component's animation controls which will handle interactions with whileHover (etc),
2899 // otherwise we just have to animate the `MotionValue` itself.
2900 return externalAxisMotionValue
2901 ? startAnimation(axis, externalAxisMotionValue, 0, inertia)
2902 : animationControls.start((_a = {},
2903 _a[axis] = 0,
2904 _a.transition = inertia,
2905 _a));
2906 });
2907 // Run all animations and then resolve the new drag constraints.
2908 return Promise.all(momentumAnimations).then(function () {
2909 _this.recordBoxInfo(_this.constraints);
2910 _this.scalePoint();
2911 var onDragTransitionEnd = _this.props.onDragTransitionEnd;
2912 onDragTransitionEnd && onDragTransitionEnd();
2913 });
2914 };
2915 ComponentDragControls.prototype.scalePoint = function () {
2916 var _this = this;
2917 var _a = this.props, dragConstraints = _a.dragConstraints, transformPagePoint = _a.transformPagePoint;
2918 if (!isRefObject(dragConstraints))
2919 return;
2920 var constraintsBox = getBoundingBox(dragConstraints, transformPagePoint);
2921 var draggableBox = getBoundingBox(this.ref, transformPagePoint);
2922 // Scale a point relative to the transformation of a constraints-providing element.
2923 var scaleAxisPoint = function (axis, dimension) {
2924 var pointToScale = _this.point[axis];
2925 if (!pointToScale)
2926 return;
2927 // Stop any current animations as they bug out if you resize during one
2928 if (pointToScale.isAnimating()) {
2929 pointToScale.stop();
2930 _this.recordBoxInfo();
2931 return;
2932 }
2933 // If the previous dimension was `0` (default), set `scale` to `1` to prevent
2934 // divide by zero errors.
2935 var scale = _this.prevConstraintsBox[dimension]
2936 ? (constraintsBox[dimension] - draggableBox[dimension]) /
2937 _this.prevConstraintsBox[dimension]
2938 : 1;
2939 pointToScale.set(_this.prevConstraintsBox[axis] * scale);
2940 };
2941 scaleAxisPoint("x", "width");
2942 scaleAxisPoint("y", "height");
2943 };
2944 ComponentDragControls.prototype.mount = function (element) {
2945 var _this = this;
2946 var stopPointerListener = addPointerEvent(element, "pointerdown", function (event) {
2947 var _a = _this.props, drag = _a.drag, _b = _a.dragListener, dragListener = _b === void 0 ? true : _b;
2948 drag && dragListener && _this.start(event);
2949 });
2950 var stopResizeListener = addDomEvent(window, "resize", function () {
2951 return _this.scalePoint();
2952 });
2953 if (this.constraintsNeedResolution) {
2954 var _a = this.props, dragConstraints = _a.dragConstraints, transformPagePoint = _a.transformPagePoint;
2955 var constraints = calculateConstraintsFromDom(dragConstraints, this.ref, this.point, transformPagePoint);
2956 this.applyConstraintsToPoint(constraints);
2957 this.recordBoxInfo(constraints);
2958 }
2959 else if (!this.isDragging && this.constraints) {
2960 this.applyConstraintsToPoint();
2961 }
2962 return function () {
2963 stopPointerListener && stopPointerListener();
2964 stopResizeListener && stopResizeListener();
2965 _this.cancelDrag();
2966 };
2967 };
2968 return ComponentDragControls;
2969}());
2970// Call a handler once for each axis
2971function bothAxis(handler) {
2972 return [handler("x"), handler("y")];
2973}
2974function convertPanToDrag(info, point) {
2975 return tslib.__assign(tslib.__assign({}, info), { point: {
2976 x: point.x ? point.x.get() : 0,
2977 y: point.y ? point.y.get() : 0,
2978 } });
2979}
2980function getConstraints(axis, _a) {
2981 var top = _a.top, right = _a.right, bottom = _a.bottom, left = _a.left;
2982 if (axis === "x") {
2983 return { min: left, max: right };
2984 }
2985 else {
2986 return { min: top, max: bottom };
2987 }
2988}
2989function shouldDrag(direction, drag, currentDirection) {
2990 return ((drag === true || drag === direction) &&
2991 (currentDirection === null || currentDirection === direction));
2992}
2993/**
2994 * Based on an x/y offset determine the current drag direction. If both axis' offsets are lower
2995 * than the provided threshold, return `null`.
2996 *
2997 * @param offset - The x/y offset from origin.
2998 * @param lockThreshold - (Optional) - the minimum absolute offset before we can determine a drag direction.
2999 */
3000function getCurrentDirection(offset, lockThreshold) {
3001 if (lockThreshold === void 0) { lockThreshold = 10; }
3002 var direction = null;
3003 if (Math.abs(offset.y) > lockThreshold) {
3004 direction = "y";
3005 }
3006 else if (Math.abs(offset.x) > lockThreshold) {
3007 direction = "x";
3008 }
3009 return direction;
3010}
3011/**
3012 * Takes a parent Element and a draggable Element and returns pixel-based drag constraints.
3013 *
3014 * @param constraintsRef
3015 * @param draggableRef
3016 */
3017function calculateConstraintsFromDom(constraintsRef, draggableRef, point, transformPagePoint) {
3018 heyListen.invariant(constraintsRef.current !== null && draggableRef.current !== null, "If `dragConstraints` is set as a React ref, that ref must be passed to another component's `ref` prop.");
3019 var parentBoundingBox = getBoundingBox(constraintsRef, transformPagePoint);
3020 var draggableBoundingBox = getBoundingBox(draggableRef, transformPagePoint);
3021 var left = parentBoundingBox.left -
3022 draggableBoundingBox.left +
3023 getCurrentOffset(point.x);
3024 var top = parentBoundingBox.top -
3025 draggableBoundingBox.top +
3026 getCurrentOffset(point.y);
3027 var right = parentBoundingBox.width - draggableBoundingBox.width + left;
3028 var bottom = parentBoundingBox.height - draggableBoundingBox.height + top;
3029 return { top: top, left: left, right: right, bottom: bottom };
3030}
3031function getBoundingBox(ref, transformPagePoint) {
3032 var rect = ref.current.getBoundingClientRect();
3033 var _a = transformPagePoint({
3034 x: rect.left,
3035 y: rect.top,
3036 }), left = _a.x, top = _a.y;
3037 var _b = transformPagePoint({
3038 x: rect.width,
3039 y: rect.height,
3040 }), width = _b.x, height = _b.y;
3041 return { left: left, top: top, width: width, height: height };
3042}
3043function getCurrentOffset(point) {
3044 return point ? point.get() : 0;
3045}
3046function applyConstraints(axis, value, constraints, dragElastic) {
3047 var constrainedValue = value instanceof MotionValue ? value.get() : value;
3048 if (!constraints) {
3049 return constrainedValue;
3050 }
3051 var _a = getConstraints(axis, constraints), min = _a.min, max = _a.max;
3052 if (min !== undefined && constrainedValue < min) {
3053 constrainedValue = dragElastic
3054 ? applyOverdrag(min, constrainedValue, dragElastic)
3055 : Math.max(min, constrainedValue);
3056 }
3057 else if (max !== undefined && constrainedValue > max) {
3058 constrainedValue = dragElastic
3059 ? applyOverdrag(max, constrainedValue, dragElastic)
3060 : Math.min(max, constrainedValue);
3061 }
3062 if (value instanceof MotionValue) {
3063 value.set(constrainedValue);
3064 }
3065 return constrainedValue;
3066}
3067function applyOverdrag(origin, current, dragElastic) {
3068 var dragFactor = typeof dragElastic === "number" ? dragElastic : 0.35;
3069 return popcorn.mix(origin, current, dragFactor);
3070}
3071
3072/**
3073 * A hook that allows an element to be dragged.
3074 *
3075 * @param param
3076 * @param ref
3077 * @param values
3078 * @param controls
3079 *
3080 * @internal
3081 */
3082function useDrag(props, ref, values, controls) {
3083 var groupDragControls = props.dragControls;
3084 var transformPagePoint = React.useContext(MotionPluginContext).transformPagePoint;
3085 var dragControls = useConstant(function () { return new ComponentDragControls({ ref: ref, values: values, controls: controls }); });
3086 dragControls.updateProps(tslib.__assign(tslib.__assign({}, props), { transformPagePoint: transformPagePoint }));
3087 React.useEffect(function () { return groupDragControls && groupDragControls.subscribe(dragControls); }, [dragControls]);
3088 React.useEffect(function () { return dragControls.mount(ref.current); }, []);
3089}
3090
3091var Drag = {
3092 key: "drag",
3093 shouldRender: function (props) { return !!props.drag; },
3094 Component: makeRenderlessComponent(function (_a) {
3095 var innerRef = _a.innerRef, values = _a.values, controls = _a.controls, props = tslib.__rest(_a, ["innerRef", "values", "controls"]);
3096 return useDrag(props, innerRef, values, controls);
3097 }),
3098};
3099
3100function isCSSVariable(value) {
3101 return typeof value === "string" && value.startsWith("var(--");
3102}
3103/**
3104 * Parse Framer's special CSS variable format into a CSS token and a fallback.
3105 *
3106 * ```
3107 * `var(--foo, #fff)` => [`--foo`, '#fff']
3108 * ```
3109 *
3110 * @param current
3111 */
3112var cssVariableRegex = /var\((--[a-zA-Z0-9-_]+),? ?([a-zA-Z0-9 ()%#.,-]+)?\)/;
3113function parseCSSVariable(current) {
3114 var match = cssVariableRegex.exec(current);
3115 if (!match)
3116 return [,];
3117 var token = match[1], fallback = match[2];
3118 return [token, fallback];
3119}
3120var maxDepth = 4;
3121function getVariableValue(current, element, depth) {
3122 if (depth === void 0) { depth = 1; }
3123 heyListen.invariant(depth <= maxDepth, "Max CSS variable fallback depth detected in property \"" + current + "\". This may indicate a circular fallback dependency.");
3124 var _a = parseCSSVariable(current), token = _a[0], fallback = _a[1];
3125 // No CSS variable detected
3126 if (!token)
3127 return;
3128 // Attempt to read this CSS variable off the element
3129 var resolved = window.getComputedStyle(element).getPropertyValue(token);
3130 if (resolved) {
3131 return resolved;
3132 }
3133 else if (isCSSVariable(fallback)) {
3134 // The fallback might itself be a CSS variable, in which case we attempt to resolve it too.
3135 return getVariableValue(fallback, element, depth + 1);
3136 }
3137 else {
3138 return fallback;
3139 }
3140}
3141/**
3142 * Resolve CSS variables from
3143 *
3144 * @internal
3145 */
3146function resolveCSSVariables(values, ref, _a, transitionEnd) {
3147 var target = tslib.__rest(_a, []);
3148 var element = ref.current;
3149 if (!(element instanceof HTMLElement))
3150 return { target: target, transitionEnd: transitionEnd };
3151 // If `transitionEnd` isn't `undefined`, clone it. We could clone `target` and `transitionEnd`
3152 // only if they change but I think this reads clearer and this isn't a performance-critical path.
3153 if (transitionEnd) {
3154 transitionEnd = tslib.__assign({}, transitionEnd);
3155 }
3156 // Go through existing `MotionValue`s and ensure any existing CSS variables are resolved
3157 values.forEach(function (value) {
3158 var current = value.get();
3159 if (!isCSSVariable(current))
3160 return;
3161 var resolved = getVariableValue(current, element);
3162 if (resolved)
3163 value.set(resolved);
3164 });
3165 // Cycle through every target property and resolve CSS variables. Currently
3166 // we only read single-var properties like `var(--foo)`, not `calc(var(--foo) + 20px)`
3167 for (var key in target) {
3168 var current = target[key];
3169 if (!isCSSVariable(current))
3170 continue;
3171 var resolved = getVariableValue(current, element);
3172 if (!resolved)
3173 continue;
3174 // Clone target if it hasn't already been
3175 target[key] = resolved;
3176 // If the user hasn't already set this key on `transitionEnd`, set it to the unresolved
3177 // CSS variable. This will ensure that after the animation the component will reflect
3178 // changes in the value of the CSS variable.
3179 if (transitionEnd && transitionEnd[key] === undefined) {
3180 transitionEnd[key] = current;
3181 }
3182 }
3183 return { target: target, transitionEnd: transitionEnd };
3184}
3185
3186var positionalKeys = new Set([
3187 "width",
3188 "height",
3189 "top",
3190 "left",
3191 "right",
3192 "bottom",
3193 "x",
3194 "y",
3195]);
3196var isPositionalKey = function (key) { return positionalKeys.has(key); };
3197var hasPositionalKey = function (target) {
3198 return Object.keys(target).some(isPositionalKey);
3199};
3200var setAndResetVelocity = function (value, to) {
3201 // Looks odd but setting it twice doesn't render, it'll just
3202 // set both prev and current to the latest value
3203 value.set(to, false);
3204 value.set(to);
3205};
3206var isNumOrPxType = function (v) {
3207 return v === styleValueTypes.number || v === styleValueTypes.px;
3208};
3209var BoundingBoxDimension;
3210(function (BoundingBoxDimension) {
3211 BoundingBoxDimension["width"] = "width";
3212 BoundingBoxDimension["height"] = "height";
3213 BoundingBoxDimension["left"] = "left";
3214 BoundingBoxDimension["right"] = "right";
3215 BoundingBoxDimension["top"] = "top";
3216 BoundingBoxDimension["bottom"] = "bottom";
3217})(BoundingBoxDimension || (BoundingBoxDimension = {}));
3218var getPosFromMatrix = function (matrix, pos) {
3219 return parseFloat(matrix.split(", ")[pos]);
3220};
3221var getTranslateFromMatrix = function (pos2, pos3) { return function (_bbox, _a) {
3222 var transform = _a.transform;
3223 if (transform === "none" || !transform)
3224 return 0;
3225 var matrix3d = transform.match(/^matrix3d\((.+)\)$/);
3226 if (matrix3d) {
3227 return getPosFromMatrix(matrix3d[1], pos3);
3228 }
3229 else {
3230 var matrix = transform.match(/^matrix\((.+)\)$/);
3231 return getPosFromMatrix(matrix[1], pos2);
3232 }
3233}; };
3234var transformKeys = new Set(["x", "y", "z"]);
3235var nonTranslationalTransformKeys = styler.transformProps.filter(function (key) { return !transformKeys.has(key); });
3236function removeNonTranslationalTransform(values, elementStyler) {
3237 var removedTransforms = [];
3238 nonTranslationalTransformKeys.forEach(function (key) {
3239 var value = values.get(key);
3240 if (value !== undefined) {
3241 removedTransforms.push([key, value.get()]);
3242 value.set(key.startsWith("scale") ? 1 : 0);
3243 }
3244 });
3245 // Apply changes to element before measurement
3246 if (removedTransforms.length)
3247 elementStyler.render();
3248 return removedTransforms;
3249}
3250var positionalValues = {
3251 // Dimensions
3252 width: function (_a) {
3253 var width = _a.width;
3254 return width;
3255 },
3256 height: function (_a) {
3257 var height = _a.height;
3258 return height;
3259 },
3260 top: function (_bbox, _a) {
3261 var top = _a.top;
3262 return parseFloat(top);
3263 },
3264 left: function (_bbox, _a) {
3265 var left = _a.left;
3266 return parseFloat(left);
3267 },
3268 bottom: function (_a, _b) {
3269 var height = _a.height;
3270 var top = _b.top;
3271 return parseFloat(top) + height;
3272 },
3273 right: function (_a, _b) {
3274 var width = _a.width;
3275 var left = _b.left;
3276 return parseFloat(left) + width;
3277 },
3278 // Transform
3279 x: getTranslateFromMatrix(4, 13),
3280 y: getTranslateFromMatrix(5, 14),
3281};
3282var convertChangedValueTypes = function (target, values, element, elementStyler, changedKeys) {
3283 var originBbox = element.getBoundingClientRect();
3284 var elementComputedStyle = getComputedStyle(element);
3285 var display = elementComputedStyle.display, top = elementComputedStyle.top, left = elementComputedStyle.left, bottom = elementComputedStyle.bottom, right = elementComputedStyle.right, transform = elementComputedStyle.transform;
3286 var originComputedStyle = { top: top, left: left, bottom: bottom, right: right, transform: transform };
3287 // If the element is currently set to display: "none", make it visible before
3288 // measuring the target bounding box
3289 if (display === "none") {
3290 elementStyler.set("display", target.display || "block");
3291 }
3292 // Apply the latest values (as set in checkAndConvertChangedValueTypes)
3293 elementStyler.render();
3294 var targetBbox = element.getBoundingClientRect();
3295 changedKeys.forEach(function (key) {
3296 // Restore styles to their **calculated computed style**, not their actual
3297 // originally set style. This allows us to animate between equivalent pixel units.
3298 var value = values.get(key);
3299 setAndResetVelocity(value, positionalValues[key](originBbox, originComputedStyle));
3300 target[key] = positionalValues[key](targetBbox, elementComputedStyle);
3301 });
3302 return target;
3303};
3304var checkAndConvertChangedValueTypes = function (values, ref, target, transitionEnd) {
3305 if (transitionEnd === void 0) { transitionEnd = {}; }
3306 target = tslib.__assign({}, target);
3307 transitionEnd = tslib.__assign({}, transitionEnd);
3308 var element = ref.current;
3309 var elementStyler = styler__default(element);
3310 var targetPositionalKeys = Object.keys(target).filter(isPositionalKey);
3311 // We want to remove any transform values that could affect the element's bounding box before
3312 // it's measured. We'll reapply these later.
3313 var removedTransformValues = [];
3314 var hasAttemptedToRemoveTransformValues = false;
3315 var changedValueTypeKeys = targetPositionalKeys.reduce(function (acc, key) {
3316 var value = values.get(key);
3317 if (!value)
3318 return acc;
3319 var from = value.get();
3320 var to = target[key];
3321 var fromType = getDimensionValueType(from);
3322 var toType;
3323 // TODO: The current implementation of this basically throws an error
3324 // if you try and do value conversion via keyframes. There's probably
3325 // a way of doing this but the performance implications would need greater scrutiny,
3326 // as it'd be doing multiple resize-remeasure operations.
3327 if (isKeyframesTarget(to)) {
3328 var numKeyframes = to.length;
3329 for (var i = to[0] === null ? 1 : 0; i < numKeyframes; i++) {
3330 if (!toType) {
3331 toType = getDimensionValueType(to[i]);
3332 heyListen.invariant(toType === fromType ||
3333 (isNumOrPxType(fromType) &&
3334 isNumOrPxType(toType)), "Keyframes must be of the same dimension as the current value");
3335 }
3336 else {
3337 heyListen.invariant(getDimensionValueType(to[i]) === toType, "All keyframes must be of the same type");
3338 }
3339 }
3340 }
3341 else {
3342 toType = getDimensionValueType(to);
3343 }
3344 if (fromType !== toType) {
3345 // If they're both just number or px, convert them both to numbers rather than
3346 // relying on resize/remeasure to convert (which is wasteful in this situation)
3347 if (isNumOrPxType(fromType) && isNumOrPxType(toType)) {
3348 var current = value.get();
3349 if (typeof current === "string") {
3350 value.set(parseFloat(current));
3351 }
3352 if (typeof to === "string") {
3353 target[key] = parseFloat(to);
3354 }
3355 else if (Array.isArray(to) && toType === styleValueTypes.px) {
3356 target[key] = to.map(parseFloat);
3357 }
3358 }
3359 else {
3360 // If we're going to do value conversion via DOM measurements, we first
3361 // need to remove non-positional transform values that could affect the bbox measurements.
3362 if (!hasAttemptedToRemoveTransformValues) {
3363 removedTransformValues = removeNonTranslationalTransform(values, elementStyler);
3364 hasAttemptedToRemoveTransformValues = true;
3365 }
3366 acc.push(key);
3367 transitionEnd[key] =
3368 transitionEnd[key] !== undefined
3369 ? transitionEnd[key]
3370 : target[key];
3371 setAndResetVelocity(value, to);
3372 }
3373 }
3374 return acc;
3375 }, []);
3376 if (changedValueTypeKeys.length) {
3377 var convertedTarget = convertChangedValueTypes(target, values, element, elementStyler, changedValueTypeKeys);
3378 // If we removed transform values, reapply them before the next render
3379 if (removedTransformValues.length) {
3380 removedTransformValues.forEach(function (_a) {
3381 var key = _a[0], value = _a[1];
3382 values.get(key).set(value);
3383 });
3384 }
3385 // Reapply original values
3386 elementStyler.render();
3387 return { target: convertedTarget, transitionEnd: transitionEnd };
3388 }
3389 else {
3390 return { target: target, transitionEnd: transitionEnd };
3391 }
3392};
3393/**
3394 * Convert value types for x/y/width/height/top/left/bottom/right
3395 *
3396 * Allows animation between `'auto'` -> `'100%'` or `0` -> `'calc(50% - 10vw)'`
3397 *
3398 * @param values
3399 * @param ref
3400 * @param target
3401 * @param transitionEnd
3402 * @internal
3403 */
3404function unitConversion(values, ref, target, transitionEnd) {
3405 return hasPositionalKey(target)
3406 ? checkAndConvertChangedValueTypes(values, ref, target, transitionEnd)
3407 : { target: target, transitionEnd: transitionEnd };
3408}
3409
3410var parseDomVariant = function (values, ref) {
3411 return function (target, transitionEnd) {
3412 var resolved = resolveCSSVariables(values, ref, target, transitionEnd);
3413 target = resolved.target;
3414 transitionEnd = resolved.transitionEnd;
3415 return unitConversion(values, ref, target, transitionEnd);
3416 };
3417};
3418
3419function useForceUpdate() {
3420 var _a = React.useState(0), forcedRenderCount = _a[0], setForcedRenderCount = _a[1];
3421 return React.useCallback(function () { return setForcedRenderCount(forcedRenderCount + 1); }, [
3422 forcedRenderCount,
3423 ]);
3424}
3425
3426var SyncLayoutContext = React.createContext(null);
3427/**
3428 * When layout changes happen asynchronously to their instigating render (ie when exiting
3429 * children of `AnimatePresence` are removed), `SyncLayout` can wrap parent and sibling
3430 * components that need to animate as a result of this layout change.
3431 *
3432 * @motion
3433 *
3434 * ```jsx
3435 * const MyComponent = ({ isVisible }) => {
3436 * return (
3437 * <SyncLayout>
3438 * <AnimatePresence>
3439 * {isVisible && (
3440 * <motion.div exit={{ opacity: 0 }} />
3441 * )}
3442 * </AnimatePresence>
3443 * <motion.div positionTransition />
3444 * </SyncLayout>
3445 * )
3446 * }
3447 * ```
3448 *
3449 * @internalremarks
3450 *
3451 * The way this component works is by memoising a function and passing it down via context.
3452 * The function, when called, updates the local state, which is used to invalidate the
3453 * memoisation cache. A new function is called, performing a synced re-render of components
3454 * that are using the SyncLayoutContext.
3455 *
3456 * @internal
3457 */
3458var UnstableSyncLayout = function (_a) {
3459 var children = _a.children;
3460 var forceUpdate = useForceUpdate();
3461 return (React.createElement(SyncLayoutContext.Provider, { value: forceUpdate }, children));
3462};
3463
3464var _a;
3465var StepName;
3466(function (StepName) {
3467 StepName["Prepare"] = "prepare";
3468 StepName["Read"] = "read";
3469 StepName["Render"] = "render";
3470})(StepName || (StepName = {}));
3471var stepOrder = [StepName.Prepare, StepName.Read, StepName.Render];
3472var jobs = stepOrder.reduce(function (acc, key) {
3473 acc[key] = [];
3474 return acc;
3475}, {});
3476var jobsNeedProcessing = false;
3477function flushCallbackList(list) {
3478 var numJobs = list.length;
3479 for (var i = 0; i < numJobs; i++) {
3480 list[i]();
3481 }
3482 list.length = 0;
3483}
3484function flushAllJobs() {
3485 if (!jobsNeedProcessing)
3486 return;
3487 flushCallbackList(jobs.prepare);
3488 flushCallbackList(jobs.read);
3489 flushCallbackList(jobs.render);
3490 jobsNeedProcessing = false;
3491}
3492// Note: The approach of schedulng jobs during the render step is incompatible with concurrent mode
3493// where multiple renders might happen without a DOM update. This would result in unneccessary batched
3494// jobs. But this was already a problem with our previous approach to positionTransition.
3495// Hopefully the React team offer a getSnapshotBeforeUpdate-esque hook and we can move to that.
3496var createUseSyncEffect = function (stepName) { return function (callback) {
3497 if (!callback)
3498 return;
3499 jobsNeedProcessing = true;
3500 jobs[stepName].push(callback);
3501}; };
3502var layoutSync = (_a = {},
3503 _a[StepName.Prepare] = createUseSyncEffect(StepName.Prepare),
3504 _a[StepName.Read] = createUseSyncEffect(StepName.Read),
3505 _a[StepName.Render] = createUseSyncEffect(StepName.Render),
3506 _a.flush = flushAllJobs,
3507 _a);
3508
3509function isHTMLElement(element) {
3510 return element instanceof HTMLElement;
3511}
3512
3513var defaultLayoutTransition = {
3514 duration: 0.8,
3515 ease: [0.45, 0.05, 0.19, 1.0],
3516};
3517var defaultPositionTransition = underDampedSpring();
3518function getDefaultLayoutTransition(isPositionOnly) {
3519 return isPositionOnly ? defaultPositionTransition : defaultLayoutTransition;
3520}
3521function isResolver(transition) {
3522 return typeof transition === "function";
3523}
3524var axisLabels = {
3525 x: {
3526 id: "x",
3527 size: "width",
3528 min: "left",
3529 max: "right",
3530 origin: "originX",
3531 },
3532 y: {
3533 id: "y",
3534 size: "height",
3535 min: "top",
3536 max: "bottom",
3537 origin: "originY",
3538 },
3539};
3540function centerOf(min, max) {
3541 return (min + max) / 2;
3542}
3543function calcAxisDelta(prev, next, names) {
3544 var _a;
3545 var sizeDelta = prev[names.size] - next[names.size];
3546 var origin = 0.5;
3547 // If the element has changed size we want to check whether either side is in
3548 // the same position before/after the layout transition. If so, we can anchor
3549 // the element to that position and only animate its size.
3550 if (sizeDelta) {
3551 if (prev[names.min] === next[names.min]) {
3552 origin = 0;
3553 }
3554 else if (prev[names.max] === next[names.max]) {
3555 origin = 1;
3556 }
3557 }
3558 var delta = (_a = {},
3559 _a[names.size] = sizeDelta,
3560 _a[names.origin] = origin,
3561 _a[names.id] =
3562 // Only measure a position delta if we haven't anchored to one side
3563 origin === 0.5
3564 ? centerOf(prev[names.min], prev[names.max]) -
3565 centerOf(next[names.min], next[names.max])
3566 : 0,
3567 _a);
3568 return delta;
3569}
3570function calcDelta(prev, next) {
3571 var delta = tslib.__assign(tslib.__assign({}, calcAxisDelta(prev, next, axisLabels.x)), calcAxisDelta(prev, next, axisLabels.y));
3572 return delta;
3573}
3574var offset = {
3575 getLayout: function (_a) {
3576 var offset = _a.offset;
3577 return offset;
3578 },
3579 measure: function (element) {
3580 var offsetLeft = element.offsetLeft, offsetTop = element.offsetTop, offsetWidth = element.offsetWidth, offsetHeight = element.offsetHeight;
3581 return {
3582 left: offsetLeft,
3583 top: offsetTop,
3584 right: offsetLeft + offsetWidth,
3585 bottom: offsetTop + offsetHeight,
3586 width: offsetWidth,
3587 height: offsetHeight,
3588 };
3589 },
3590};
3591var boundingBox = {
3592 getLayout: function (_a) {
3593 var boundingBox = _a.boundingBox;
3594 return boundingBox;
3595 },
3596 measure: function (element) {
3597 var _a = element.getBoundingClientRect(), left = _a.left, top = _a.top, width = _a.width, height = _a.height, right = _a.right, bottom = _a.bottom;
3598 return { left: left, top: top, width: width, height: height, right: right, bottom: bottom };
3599 },
3600};
3601function readPositionStyle(element) {
3602 return window.getComputedStyle(element).position;
3603}
3604function getLayoutType(prev, next, isPositionOnly) {
3605 return isPositionOnly && prev === next ? offset : boundingBox;
3606}
3607function isSizeKey(key) {
3608 return key === "width" || key === "height";
3609}
3610function getTransition(_a) {
3611 var layoutTransition = _a.layoutTransition, positionTransition = _a.positionTransition;
3612 return layoutTransition || positionTransition;
3613}
3614var LayoutAnimation = /** @class */ (function (_super) {
3615 tslib.__extends(LayoutAnimation, _super);
3616 function LayoutAnimation() {
3617 return _super !== null && _super.apply(this, arguments) || this;
3618 }
3619 // Measure the current state of the DOM before it's updated, and schedule checks to see
3620 // if it's changed as a result of a React render.
3621 LayoutAnimation.prototype.getSnapshotBeforeUpdate = function () {
3622 var _a = this.props, innerRef = _a.innerRef, positionTransition = _a.positionTransition, values = _a.values, controls = _a.controls;
3623 var element = innerRef.current;
3624 if (!isHTMLElement(element))
3625 return;
3626 var layoutTransition = getTransition(this.props);
3627 var isPositionOnly = !!positionTransition;
3628 var positionStyle = readPositionStyle(element);
3629 var prev = {
3630 offset: offset.measure(element),
3631 boundingBox: boundingBox.measure(element),
3632 };
3633 var transform;
3634 var next;
3635 var compare;
3636 // We split the unsetting, read and reapplication of the `transform` style prop into
3637 // different steps via useSyncEffect. Multiple components might all be doing the same
3638 // thing and by splitting these jobs and flushing them in batches we prevent layout thrashing.
3639 layoutSync.prepare(function () {
3640 // Unset the transform of all layoutTransition components so we can accurately measure
3641 // the target bounding box
3642 transform = element.style.transform;
3643 element.style.transform = "";
3644 });
3645 layoutSync.read(function () {
3646 // Read the target VisualInfo of all layoutTransition components
3647 next = {
3648 offset: offset.measure(element),
3649 boundingBox: boundingBox.measure(element),
3650 };
3651 var nextPosition = readPositionStyle(element);
3652 compare = getLayoutType(positionStyle, nextPosition, isPositionOnly);
3653 });
3654 layoutSync.render(function () {
3655 // Reverse the layout delta of all newly laid-out layoutTransition components into their
3656 // prev visual state and then animate them into their new one using transforms.
3657 var prevLayout = compare.getLayout(prev);
3658 var nextLayout = compare.getLayout(next);
3659 var delta = calcDelta(prevLayout, nextLayout);
3660 var hasAnyChanged = delta.x || delta.y || delta.width || delta.height;
3661 if (!hasAnyChanged) {
3662 // If layout hasn't changed, reapply the transform and get out of here.
3663 transform && (element.style.transform = transform);
3664 return;
3665 }
3666 styler__default(element).set({
3667 originX: delta.originX,
3668 originY: delta.originY,
3669 });
3670 syncRenderSession.open();
3671 var target = {};
3672 var transition = {};
3673 var transitionDefinition = isResolver(layoutTransition)
3674 ? layoutTransition({ delta: delta })
3675 : layoutTransition;
3676 function makeTransition(layoutKey, transformKey, targetValue, visualOrigin) {
3677 // If this dimension hasn't changed, early return
3678 var deltaKey = isSizeKey(layoutKey) ? layoutKey : transformKey;
3679 if (!delta[deltaKey])
3680 return;
3681 var baseTransition = typeof transitionDefinition === "boolean"
3682 ? tslib.__assign({}, getDefaultLayoutTransition(isPositionOnly)) : transitionDefinition;
3683 var value = values.get(transformKey, targetValue);
3684 var velocity = value.getVelocity();
3685 transition[transformKey] = baseTransition[transformKey]
3686 ? tslib.__assign({}, baseTransition[transformKey]) : tslib.__assign({}, baseTransition);
3687 if (transition[transformKey].velocity === undefined) {
3688 transition[transformKey].velocity = velocity || 0;
3689 }
3690 // The target value of all transforms is the default value of that prop (ie x = 0, scaleX = 1)
3691 // This is because we're inverting the layout change with `transform` and then animating to `transform: none`
3692 target[transformKey] = targetValue;
3693 var offsetToApply = !isSizeKey(layoutKey) && compare === offset
3694 ? value.get()
3695 : 0;
3696 value.set(visualOrigin + offsetToApply);
3697 }
3698 makeTransition("left", "x", 0, delta.x);
3699 makeTransition("top", "y", 0, delta.y);
3700 if (!isPositionOnly) {
3701 makeTransition("width", "scaleX", 1, prev.boundingBox.width / next.boundingBox.width);
3702 makeTransition("height", "scaleY", 1, prev.boundingBox.height / next.boundingBox.height);
3703 }
3704 target.transition = transition;
3705 // Only start the transition if `transitionDefinition` isn't `false`. Otherwise we want
3706 // to leave the values in their newly-inverted state and let the user cope with the rest.
3707 transitionDefinition && controls.start(target);
3708 // Force a render to ensure there's no visual flickering
3709 syncRenderSession.flush();
3710 });
3711 return null;
3712 };
3713 LayoutAnimation.prototype.componentDidUpdate = function () {
3714 layoutSync.flush();
3715 };
3716 LayoutAnimation.prototype.render = function () {
3717 return null;
3718 };
3719 LayoutAnimation.contextType = SyncLayoutContext;
3720 return LayoutAnimation;
3721}(React.Component));
3722var Layout = {
3723 key: "layout",
3724 shouldRender: function (_a) {
3725 var positionTransition = _a.positionTransition, layoutTransition = _a.layoutTransition;
3726 heyListen.invariant(!(positionTransition && layoutTransition), "Don't set both positionTransition and layoutTransition on the same component");
3727 return (typeof window !== "undefined" &&
3728 !!(positionTransition || layoutTransition));
3729 },
3730 Component: LayoutAnimation,
3731};
3732
3733/**
3734 * A list of all valid MotionProps
3735 *
3736 * @internalremarks
3737 * This doesn't throw if a `MotionProp` name is missing - it should.
3738 */
3739var validMotionProps = new Set([
3740 "initial",
3741 "animate",
3742 "exit",
3743 "style",
3744 "variants",
3745 "transition",
3746 "transformTemplate",
3747 "transformValues",
3748 "custom",
3749 "inherit",
3750 "static",
3751 "positionTransition",
3752 "layoutTransition",
3753 "onAnimationStart",
3754 "onAnimationComplete",
3755 "onUpdate",
3756 "onDragStart",
3757 "onDrag",
3758 "onDragEnd",
3759 "onDirectionLock",
3760 "onDragTransitionEnd",
3761 "drag",
3762 "dragControls",
3763 "dragListener",
3764 "dragConstraints",
3765 "dragDirectionLock",
3766 "dragElastic",
3767 "dragMomentum",
3768 "dragPropagation",
3769 "dragTransition",
3770 "_dragValueX",
3771 "_dragValueY",
3772 "_dragTransitionControls",
3773 "dragOriginX",
3774 "dragOriginY",
3775 "onPan",
3776 "onPanStart",
3777 "onPanEnd",
3778 "onPanSessionStart",
3779 "onTap",
3780 "onTapStart",
3781 "onTapCancel",
3782 "whileHover",
3783 "whileTap",
3784 "onHoverEnd",
3785 "onHoverStart",
3786]);
3787/**
3788 * Check whether a prop name is a valid `MotionProp` key.
3789 *
3790 * @param key - Name of the property to check
3791 * @returns `true` is key is a valid `MotionProp`.
3792 *
3793 * @public
3794 */
3795function isValidMotionProp(key) {
3796 return validMotionProps.has(key);
3797}
3798
3799var AnimatePropType;
3800(function (AnimatePropType) {
3801 AnimatePropType["Target"] = "Target";
3802 AnimatePropType["VariantLabel"] = "VariantLabel";
3803 AnimatePropType["AnimationSubscription"] = "AnimationSubscription";
3804})(AnimatePropType || (AnimatePropType = {}));
3805
3806function shallowCompare(next, prev) {
3807 if (prev === null)
3808 return false;
3809 var prevLength = prev.length;
3810 if (prevLength !== next.length)
3811 return false;
3812 for (var i = 0; i < prevLength; i++) {
3813 if (prev[i] !== next[i])
3814 return false;
3815 }
3816 return true;
3817}
3818
3819var hasUpdated = function (prev, next) {
3820 return (next !== undefined &&
3821 (Array.isArray(prev) && Array.isArray(next)
3822 ? !shallowCompare(next, prev)
3823 : prev !== next));
3824};
3825function targetWithoutTransition(_a, mergeTransitionEnd) {
3826 if (mergeTransitionEnd === void 0) { mergeTransitionEnd = false; }
3827 var transition = _a.transition, transitionEnd = _a.transitionEnd, target = tslib.__rest(_a, ["transition", "transitionEnd"]);
3828 return mergeTransitionEnd
3829 ? tslib.__assign(tslib.__assign({}, target), transitionEnd)
3830 : target;
3831}
3832/**
3833 * Handle the `animate` prop when its an object of values, ie:
3834 *
3835 * ```jsx
3836 * <motion.div animate={{ opacity: 1 }} />
3837 * ```
3838 *
3839 * @internalremarks
3840 * It might be worth consolidating this with `use-variants`
3841 *
3842 * ```jsx
3843 * <motion.div animate="visible" />
3844 * ```
3845 *
3846 * @param target
3847 * @param controls
3848 * @param values
3849 * @param transition
3850 *
3851 * @internal
3852 */
3853function useAnimateProp(targetAndTransition, controls, values, defaultTransition) {
3854 var isInitialRender = React.useRef(true);
3855 var prevValues = React.useRef(null);
3856 if (!prevValues.current) {
3857 prevValues.current = targetWithoutTransition(targetAndTransition, true);
3858 }
3859 React.useEffect(function () {
3860 var targetToAnimate = {};
3861 // These are the values we're actually animating
3862 var animatingTarget = targetWithoutTransition(targetAndTransition);
3863 // This is the target as it'll be once transitionEnd values are applied
3864 var finalTarget = targetWithoutTransition(targetAndTransition, true);
3865 // Detect which values have changed between renders
3866 for (var key in animatingTarget) {
3867 // This value should animate on mount if this value doesn't already exist (wasn't
3868 // defined in `style` or `initial`) or if it does exist and it's already changed.
3869 var shouldAnimateOnMount = isInitialRender.current &&
3870 (!values.has(key) ||
3871 values.get(key).get() !== finalTarget[key]);
3872 // If this value has updated between renders or it's we're animating this value on mount,
3873 // add it to the animate target.
3874 var isValidValue = finalTarget[key] !== null;
3875 var valueHasUpdated = hasUpdated(prevValues.current[key], finalTarget[key]);
3876 if (isValidValue && (valueHasUpdated || shouldAnimateOnMount)) {
3877 targetToAnimate[key] = animatingTarget[key];
3878 }
3879 }
3880 isInitialRender.current = false;
3881 prevValues.current = tslib.__assign(tslib.__assign({}, prevValues.current), finalTarget);
3882 if (Object.keys(targetToAnimate).length) {
3883 controls.start(tslib.__assign(tslib.__assign({}, targetToAnimate), { transition: targetAndTransition.transition || defaultTransition, transitionEnd: targetAndTransition.transitionEnd }));
3884 }
3885 }, [targetAndTransition]);
3886}
3887
3888var labelsToArray = function (label) {
3889 if (!label) {
3890 return [];
3891 }
3892 if (Array.isArray(label)) {
3893 return label;
3894 }
3895 return [label];
3896};
3897var resolveVariantLabels = function (variant) {
3898 var unresolvedVariant = variant instanceof MotionValue ? variant.get() : variant;
3899 return Array.from(new Set(labelsToArray(unresolvedVariant)));
3900};
3901/**
3902 * Hooks in React sometimes accept a dependency array as their final argument. (ie useEffect/useMemo)
3903 * When values in this array change, React re-runs the dependency. However if the array
3904 * contains a variable number of items, React throws an error.
3905 */
3906var asDependencyList = function (list) { return [
3907 list.join(","),
3908]; };
3909
3910var hasVariantChanged = function (oldVariant, newVariant) {
3911 return oldVariant.join(",") !== newVariant.join(",");
3912};
3913/**
3914 * Handle variants and the `animate` prop when its set as variant labels.
3915 *
3916 * @param initial - Initial variant(s)
3917 * @param animate - Variant(s) to animate to
3918 * @param inherit - `true` is inheriting animations from parent
3919 * @param controls - Animation controls
3920 *
3921 * @internal
3922 */
3923function useVariants(initial, animate, inherit, controls) {
3924 var targetVariants = resolveVariantLabels(animate);
3925 var context = React.useContext(MotionContext);
3926 var parentAlreadyMounted = context.hasMounted && context.hasMounted.current;
3927 var hasMounted = React.useRef(false);
3928 React.useEffect(function () {
3929 var shouldAnimate = false;
3930 if (inherit) {
3931 // If we're inheriting variant changes and the parent has already
3932 // mounted when this component loads, we need to manually trigger
3933 // this animation.
3934 shouldAnimate = !!parentAlreadyMounted;
3935 targetVariants = resolveVariantLabels(context.animate);
3936 }
3937 else {
3938 shouldAnimate =
3939 hasMounted.current ||
3940 hasVariantChanged(resolveVariantLabels(initial), targetVariants);
3941 }
3942 shouldAnimate && controls.start(targetVariants);
3943 hasMounted.current = true;
3944 }, asDependencyList(targetVariants));
3945}
3946
3947/**
3948 * `useAnimationGroupSubscription` allows a component to subscribe to an
3949 * externally-created `AnimationControls`, created by the `useAnimation` hook.
3950 *
3951 * @param animation
3952 * @param controls
3953 *
3954 * @internal
3955 */
3956function useAnimationGroupSubscription(animation, controls) {
3957 var unsubscribe = React.useMemo(function () { return animation.subscribe(controls); }, [
3958 animation,
3959 ]);
3960 React.useEffect(function () { return function () {
3961 unsubscribe && unsubscribe();
3962 }; }, [unsubscribe]);
3963}
3964
3965var _a$1, _b;
3966var AnimatePropComponents = (_a$1 = {},
3967 _a$1[AnimatePropType.Target] = makeRenderlessComponent(function (_a) {
3968 var animate = _a.animate, controls = _a.controls, values = _a.values, transition = _a.transition;
3969 return useAnimateProp(animate, controls, values, transition);
3970 }),
3971 _a$1[AnimatePropType.VariantLabel] = makeRenderlessComponent(function (_a) {
3972 var animate = _a.animate, _b = _a.inherit, inherit = _b === void 0 ? true : _b, controls = _a.controls, initial = _a.initial;
3973 return useVariants(initial, animate, inherit, controls);
3974 }),
3975 _a$1[AnimatePropType.AnimationSubscription] = makeRenderlessComponent(function (_a) {
3976 var animate = _a.animate, controls = _a.controls;
3977 return useAnimationGroupSubscription(animate, controls);
3978 }),
3979 _a$1);
3980var isVariantLabel$1 = function (prop) {
3981 return Array.isArray(prop) || typeof prop === "string";
3982};
3983var isAnimationSubscription = function (_a) {
3984 var animate = _a.animate;
3985 return animate instanceof AnimationControls;
3986};
3987var animationProps = ["initial", "animate", "whileTap", "whileHover"];
3988var animatePropTypeTests = (_b = {},
3989 _b[AnimatePropType.Target] = function (props) {
3990 return (props.animate !== undefined &&
3991 !isVariantLabel$1(props.animate) &&
3992 !isAnimationSubscription(props));
3993 },
3994 _b[AnimatePropType.VariantLabel] = function (props) {
3995 return (props.variants !== undefined ||
3996 animationProps.some(function (key) { return typeof props[key] === "string"; }));
3997 },
3998 _b[AnimatePropType.AnimationSubscription] = isAnimationSubscription,
3999 _b);
4000var getAnimationComponent = function (props) {
4001 var animatePropType = undefined;
4002 for (var key in AnimatePropType) {
4003 if (animatePropTypeTests[key](props)) {
4004 animatePropType = key;
4005 }
4006 }
4007 return animatePropType ? AnimatePropComponents[animatePropType] : undefined;
4008};
4009
4010var Exit = {
4011 key: "exit",
4012 shouldRender: function (_a, _b) {
4013 var exit = _a.exit;
4014 var exitProps = _b.exitProps;
4015 var hasExitProps = !!exitProps;
4016 var hasExitAnimation = !!exit;
4017 heyListen.invariant(!hasExitProps || (hasExitProps && hasExitAnimation), "No exit prop defined on a child of AnimatePresence.");
4018 return hasExitProps && hasExitAnimation;
4019 },
4020 Component: makeRenderlessComponent(function (props) {
4021 var animate = props.animate, controls = props.controls, parentContext = props.parentContext, exit = props.exit;
4022 var exitProps = parentContext.exitProps;
4023 var isPlayingExitAnimation = React.useRef(false);
4024 // This early return is more for types - it won't actually run because of the `shouldRender` above.
4025 if (!exitProps || !exit)
4026 return;
4027 var isExiting = exitProps.isExiting, custom = exitProps.custom, onExitComplete = exitProps.onExitComplete;
4028 React.useEffect(function () {
4029 if (isExiting) {
4030 if (!isPlayingExitAnimation.current && exit) {
4031 controls.setProps(tslib.__assign(tslib.__assign({}, props), { custom: custom !== undefined ? custom : props.custom }));
4032 controls.start(exit).then(onExitComplete);
4033 }
4034 isPlayingExitAnimation.current = true;
4035 }
4036 else if (isPlayingExitAnimation.current &&
4037 animate &&
4038 !(animate instanceof AnimationControls)) {
4039 controls.start(animate);
4040 }
4041 if (!isExiting) {
4042 isPlayingExitAnimation.current = false;
4043 }
4044 }, [isExiting]);
4045 }),
4046};
4047
4048var isPropValid = function (key) { return !isValidMotionProp(key); };
4049/**
4050 * Emotion and Styled Components both allow users to pass through arbitrary props to their components
4051 * to dynamically generate CSS. They both use the `@emotion/is-prop-valid` package to determine which
4052 * of these should be passed to the underlying DOM node.
4053 *
4054 * However, when styling a Motion component `styled(motion.div)`, both packages pass through *all* props
4055 * as it's seen as an arbitrary component rather than a DOM node. Motion only allows arbitrary props
4056 * passed through the `custom` prop so it doesn't *need* the payload or computational overhead of
4057 * `@emotion/is-prop-valid`, however to fix this problem we need to use it.
4058 *
4059 * By making it an optionalDependency we can offer this functionality only in the situations where it's
4060 * actually required.
4061 */
4062try {
4063 var emotionIsPropValid_1 = require("@emotion/is-prop-valid").default;
4064 isPropValid = function (key) {
4065 // Handle events explicitly as Emotion validates them all as true
4066 if (key.startsWith("on")) {
4067 return !isValidMotionProp(key);
4068 }
4069 else {
4070 return emotionIsPropValid_1(key);
4071 }
4072 };
4073}
4074catch (_a) {
4075 // We don't need to actually do anything here - the fallback is the existing `isPropValid`.
4076}
4077function filterValidProps(props) {
4078 var domProps = {};
4079 for (var key in props) {
4080 if (isPropValid(key)) {
4081 domProps[key] = props[key];
4082 }
4083 }
4084 return domProps;
4085}
4086var buildSVGProps = function (values, style) {
4087 var motionValueStyles = resolveCurrent(values);
4088 var props = styler.buildSVGAttrs(motionValueStyles, undefined, undefined, undefined, undefined, false);
4089 props.style = tslib.__assign(tslib.__assign({}, style), props.style);
4090 return props;
4091};
4092var functionalityComponents = [Layout, Drag, Gestures, Exit];
4093var numFunctionalityComponents = functionalityComponents.length;
4094/**
4095 * Create a configuration for `motion` components that provides DOM-specific functionality.
4096 *
4097 * @internal
4098 */
4099function createDomMotionConfig(Component) {
4100 var isDOM = typeof Component === "string";
4101 var isSVG = isDOM && svgElements.indexOf(Component) !== -1;
4102 return {
4103 renderComponent: function (ref, style, values, props, isStatic) {
4104 var forwardedProps = isDOM ? filterValidProps(props) : props;
4105 var staticVisualStyles = isSVG
4106 ? buildSVGProps(values, style)
4107 : { style: buildStyleAttr(values, style, isStatic) };
4108 return React.createElement(Component, tslib.__assign(tslib.__assign(tslib.__assign({}, forwardedProps), { ref: ref }), staticVisualStyles));
4109 },
4110 /**
4111 * loadFunctionalityComponents gets used by the `motion` component
4112 *
4113 * Each functionality component gets provided the `ref`, animation controls and the `MotionValuesMap`
4114 * generated for that component, as well as all the `props` passed to it by the user.
4115 *
4116 * The pattern used to determine whether to load and use each piece of functionality is
4117 * consistent (should render? Then push component) and could be used to extend functionality.
4118 *
4119 * By exposing a mutable piece of memory via an API like `extendMotionComponent` we could
4120 * allow users to add `FunctionalComponentDefinition`s. This would allow us to offer file size
4121 * reductions by shipping an entry point that doesn't load gesture and drag functionality, and
4122 * also offer a way for users to develop plugins/other functionality. Because these functionalities
4123 * are loaded as components, we can look into using Suspense for this purpose.
4124 *
4125 * For user-defined functionality we'd need to allow
4126 * 1) User-defined prop typing (extending `P`)
4127 * 2) User-defined "clean props" function that removes their plugin's props before being passed to the DOM.
4128 */
4129 loadFunctionalityComponents: function (ref, values, props, context, controls, inherit) {
4130 var activeComponents = [];
4131 // TODO: Consolidate Animation functionality loading strategy with other functionality components
4132 var Animation = getAnimationComponent(props);
4133 if (Animation) {
4134 activeComponents.push(React.createElement(Animation, { key: "animation", initial: props.initial, animate: props.animate, variants: props.variants, transition: props.transition, controls: controls, inherit: inherit, values: values }));
4135 }
4136 for (var i = 0; i < numFunctionalityComponents; i++) {
4137 var _a = functionalityComponents[i], shouldRender = _a.shouldRender, key = _a.key, Component_1 = _a.Component;
4138 if (shouldRender(props, context)) {
4139 activeComponents.push(React.createElement(Component_1, tslib.__assign({ key: key }, props, { parentContext: context, values: values, controls: controls, innerRef: ref })));
4140 }
4141 }
4142 return activeComponents;
4143 },
4144 getValueControlsConfig: function (ref, values) {
4145 return {
4146 values: values,
4147 readValueFromSource: function (key) {
4148 return styler__default(ref.current).get(key);
4149 },
4150 // TODO: This is a good second source of plugins. This function contains the CSS variable
4151 // and unit conversion support. These functions share a common signature. We could make another
4152 // API for adding these.
4153 makeTargetAnimatable: parseDomVariant(values, ref),
4154 };
4155 },
4156 };
4157}
4158
4159var htmlMotionComponents = htmlElements.reduce(function (acc, Component) {
4160 var config = createDomMotionConfig(Component);
4161 // Suppress "Expression produces a union type that is too complex to represent" error
4162 // @ts-ignore
4163 acc[Component] = createMotionComponent(config);
4164 return acc;
4165}, {});
4166var svgMotionComponents = svgElements.reduce(function (acc, Component) {
4167 // Suppress "Expression produces a union type that is too complex to represent" error
4168 // @ts-ignore
4169 acc[Component] = createMotionComponent(createDomMotionConfig(Component));
4170 return acc;
4171}, {});
4172/**
4173 * HTML & SVG components, optimised for use with gestures and animation. These can be used as
4174 * drop-in replacements for any HTML & SVG component, all CSS & SVG properties are supported.
4175 *
4176 * @internalremarks
4177 *
4178 * I'd like to make it possible for these to be loaded "on demand" - to reduce bundle size by only
4179 * including HTML/SVG stylers, animation and/or gesture support when necessary.
4180 *
4181 * ```jsx
4182 * <motion.div animate={{ x: 100 }} />
4183 *
4184 * <motion.p animate={{ height: 200 }} />
4185 *
4186 * <svg><motion.circle r={10} animate={{ r: 20 }} /></svg>
4187 * ```
4188 *
4189 * @public
4190 */
4191var motion = tslib.__assign(tslib.__assign({
4192 /**
4193 * Convert a custom React component into a `motion` component.
4194 *
4195 * It can also accept a string, to create [custom DOM elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements).
4196 *
4197 * ```jsx
4198 * const Component = React.forwardRef((props: Props, ref) => {
4199 * return <div ref={ref} />
4200 * })
4201 *
4202 * const MotionComponent = motion.custom<Props>(Component)
4203 * ```
4204 *
4205 * @param Component -
4206 */
4207 custom: function custom(Component) {
4208 return createMotionComponent(createDomMotionConfig(Component));
4209 } }, htmlMotionComponents), svgMotionComponents);
4210
4211/**
4212 * Creates a `MotionValue` to track the state and velocity of a value.
4213 *
4214 * 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.
4215 *
4216 * @library
4217 *
4218 * ```jsx
4219 * export function MyComponent() {
4220 * const scale = useMotionValue(1)
4221 *
4222 * return <Frame scale={scale} />
4223 * }
4224 * ```
4225 *
4226 * @motion
4227 *
4228 * ```jsx
4229 * export const MyComponent = () => {
4230 * const scale = useMotionValue(1)
4231 *
4232 * return <motion.div style={{ scale }} />
4233 * }
4234 * ```
4235 *
4236 * @param initial - The initial state.
4237 *
4238 * @public
4239 */
4240function useMotionValue(initial) {
4241 return useConstant(function () { return motionValue(initial); });
4242}
4243
4244/**
4245 * If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself
4246 *
4247 * TODO: Remove and move to library
4248 *
4249 * @internal
4250 */
4251function unwrapMotionValue(value) {
4252 var unwrappedValue = value instanceof MotionValue ? value.get() : value;
4253 return isCustomValue(unwrappedValue)
4254 ? unwrappedValue.toValue()
4255 : unwrappedValue;
4256}
4257
4258var isCustomValueType = function (v) {
4259 return typeof v === "object" && v.mix;
4260};
4261var getMixer = function (v) { return (isCustomValueType(v) ? v.mix : undefined); };
4262function transform() {
4263 var args = [];
4264 for (var _i = 0; _i < arguments.length; _i++) {
4265 args[_i] = arguments[_i];
4266 }
4267 var useImmediate = !Array.isArray(args[0]);
4268 var argOffset = useImmediate ? 0 : -1;
4269 var inputValue = args[0 + argOffset];
4270 var inputRange = args[1 + argOffset];
4271 var outputRange = args[2 + argOffset];
4272 var options = args[3 + argOffset];
4273 var interpolator = popcorn.interpolate(inputRange, outputRange, tslib.__assign({ mixer: getMixer(outputRange[0]) }, options));
4274 return useImmediate ? interpolator(inputValue) : interpolator;
4275}
4276
4277var isTransformer = function (v) {
4278 return typeof v === "function";
4279};
4280var noop$1 = function (v) { return v; };
4281function useTransform(parent, customTransform, to, options) {
4282 var value = React.useRef(null);
4283 var comparitor = [parent];
4284 var transformer = noop$1;
4285 if (isTransformer(customTransform)) {
4286 transformer = customTransform;
4287 }
4288 else if (Array.isArray(to)) {
4289 var from = customTransform;
4290 transformer = transform(from, to, options);
4291 comparitor = [parent, from.join(","), to.join(",")];
4292 }
4293 return React.useMemo(function () {
4294 if (value.current)
4295 value.current.destroy();
4296 value.current = parent.addChild({ transformer: transformer });
4297 return value.current;
4298 }, comparitor);
4299}
4300
4301// Keep things reasonable and avoid scale: Infinity. In practise we might need
4302// to add another value, opacity, that could interpolate scaleX/Y [0,0.01] => [0,1]
4303// to simply hide content at unreasonable scales.
4304var maxScale = 100000;
4305var invertScale = function (scale) { return (scale > 0.001 ? 1 / scale : maxScale); };
4306/**
4307 * Returns a `MotionValue` each for `scaleX` and `scaleY` that update with the inverse
4308 * of their respective parent scales.
4309 *
4310 * This is useful for undoing the distortion of content when scaling a parent component.
4311 *
4312 * By default, `useInvertedScale` will automatically fetch `scaleX` and `scaleY` from the nearest parent.
4313 * By passing other `MotionValue`s in as `useInvertedScale({ scaleX, scaleY })`, it will invert the output
4314 * of those instead.
4315 *
4316 * @motion
4317 *
4318 * ```jsx
4319 * const MyComponent = () => {
4320 * const { scaleX, scaleY } = useInvertedScale()
4321 * return <motion.div style={{ scaleX, scaleY }} />
4322 * }
4323 * ```
4324 *
4325 * @library
4326 *
4327 * ```jsx
4328 * function MyComponent() {
4329 * const { scaleX, scaleY } = useInvertedScale()
4330 * return <Frame scaleX={scaleX} scaleY={scaleY} />
4331 * }
4332 * ```
4333 *
4334 * @public
4335 */
4336function useInvertedScale(scale) {
4337 var parentScaleX = useMotionValue(1);
4338 var parentScaleY = useMotionValue(1);
4339 var values = React.useContext(MotionContext).values;
4340 heyListen.invariant(!!(scale || values), "If no scale values are provided, useInvertedScale must be used within a child of another motion component.");
4341 if (scale) {
4342 parentScaleX = scale.scaleX || parentScaleX;
4343 parentScaleY = scale.scaleY || parentScaleY;
4344 }
4345 else if (values) {
4346 parentScaleX = values.get("scaleX", 1);
4347 parentScaleY = values.get("scaleY", 1);
4348 }
4349 var scaleX = useTransform(parentScaleX, invertScale);
4350 var scaleY = useTransform(parentScaleY, invertScale);
4351 return { scaleX: scaleX, scaleY: scaleY };
4352}
4353
4354function useOnChange(value, callback) {
4355 React.useEffect(function () { return (isMotionValue(value) ? value.onChange(callback) : undefined); }, [value]);
4356}
4357
4358/**
4359 * Creates a `MotionValue` that, when `set`, will use a spring animation to animate to its new state.
4360 *
4361 * It can either work as a stand-alone `MotionValue` by initialising it with a value, or as a subscriber
4362 * to another `MotionValue`.
4363 *
4364 * @remarks
4365 *
4366 * ```jsx
4367 * const x = useSpring(0, { stiffness: 300 })
4368 * const y = useSpring(x, { damping: 10 })
4369 * ```
4370 *
4371 * @param inputValue - `MotionValue` or number. If provided a `MotionValue`, when the input `MotionValue` changes, the created `MotionValue` will spring towards that value.
4372 * @param springConfig - Configuration options for the spring.
4373 * @returns `MotionValue`
4374 *
4375 * @public
4376 */
4377function useSpring(source, config) {
4378 if (config === void 0) { config = {}; }
4379 var activeSpringAnimation = React.useRef(null);
4380 var value = useMotionValue(isMotionValue(source) ? source.get() : source);
4381 React.useMemo(function () {
4382 return value.attach(function (v, set) {
4383 if (activeSpringAnimation.current) {
4384 activeSpringAnimation.current.stop();
4385 }
4386 activeSpringAnimation.current = popmotion.spring(tslib.__assign({ from: value.get(), to: v, velocity: value.getVelocity() }, config)).start(set);
4387 return value.get();
4388 });
4389 }, Object.values(config));
4390 useOnChange(source, function (v) { return value.set(parseFloat(v)); });
4391 return value;
4392}
4393
4394var scrollX = motionValue(0);
4395var scrollY = motionValue(0);
4396var scrollXProgress = motionValue(0);
4397var scrollYProgress = motionValue(0);
4398var setProgress = function (offset, maxOffset, value) {
4399 value.set(!maxOffset || !offset ? 0 : offset / maxOffset);
4400};
4401var hasEventListener = false;
4402var addScrollListener = function () {
4403 hasEventListener = true;
4404 if (typeof window === "undefined")
4405 return;
4406 var updateScrollValues = function () {
4407 var xOffset = window.pageXOffset;
4408 var yOffset = window.pageYOffset;
4409 // Set absolute positions
4410 scrollX.set(xOffset);
4411 scrollY.set(yOffset);
4412 // Set 0-1 progress
4413 setProgress(xOffset, document.body.clientWidth - window.innerWidth, scrollXProgress);
4414 setProgress(yOffset, document.body.clientHeight - window.innerHeight, scrollYProgress);
4415 };
4416 updateScrollValues();
4417 window.addEventListener("resize", updateScrollValues);
4418 window.addEventListener("scroll", updateScrollValues, { passive: true });
4419};
4420var viewportMotionValues = {
4421 scrollX: scrollX,
4422 scrollY: scrollY,
4423 scrollXProgress: scrollXProgress,
4424 scrollYProgress: scrollYProgress,
4425};
4426/**
4427 * Provides `MotionValue`s that update when the viewport scrolls:
4428 *
4429 * - `scrollX` — Horizontal scroll distance in pixels.
4430 * - `scrollY` — Vertical scroll distance in pixels.
4431 * - `scrollXProgress` — Horizontal scroll progress between `0` and `1`.
4432 * - `scrollYProgress` — Vertical scroll progress between `0` and `1`.
4433 *
4434 * **Note:** If the returned scroll `MotionValue`s don't seem to be updating,
4435 * double check if the `body` tag styles are set to `width: 100%; height: 100%` or
4436 * similar, as this can break accurate measurement of viewport scroll.
4437 *
4438 * @library
4439 *
4440 * ```jsx
4441 * import * as React from "react"
4442 * import {
4443 * Frame,
4444 * useViewportScroll,
4445 * useTransform
4446 * } from "framer"
4447 *
4448 * export function MyComponent() {
4449 * const { scrollYProgress } = useViewportScroll()
4450 * return <Frame scaleX={scrollYProgress} />
4451 * }
4452 * ```
4453 *
4454 * @motion
4455 *
4456 * ```jsx
4457 * export const MyComponent = () => {
4458 * const { scrollYProgress } = useViewportScroll()
4459 * return <motion.div style={{ scaleX: scrollYProgress }} />
4460 * }
4461 * ```
4462 *
4463 * @internalremarks
4464 * This isn't technically a hook yet, but in the future it might be nice
4465 * to accept refs to elements and add scroll listeners to those, which
4466 * may involve the use of lifecycle.
4467 *
4468 * @public
4469 */
4470function useViewportScroll() {
4471 if (!hasEventListener) {
4472 addScrollListener();
4473 }
4474 return viewportMotionValues;
4475}
4476
4477/**
4478 * Creates `AnimationControls`, which can be used to manually start, stop
4479 * and sequence animations on one or more components.
4480 *
4481 * The returned `AnimationControls` should be passed to the `animate` property
4482 * of the components you want to animate.
4483 *
4484 * These components can then be animated with the `start` method.
4485 *
4486 * @library
4487 *
4488 * ```jsx
4489 * import * as React from 'react'
4490 * import { Frame, useAnimation } from 'framer'
4491 *
4492 * export function MyComponent(props) {
4493 * const controls = useAnimation()
4494 *
4495 * controls.start({
4496 * x: 100,
4497 * transition: { duration: 0.5 },
4498 * })
4499 *
4500 * return <Frame animate={controls} />
4501 * }
4502 * ```
4503 *
4504 * @motion
4505 *
4506 * ```jsx
4507 * import * as React from 'react'
4508 * import { motion, useAnimation } from 'framer-motion'
4509 *
4510 * export function MyComponent(props) {
4511 * const controls = useAnimation()
4512 *
4513 * controls.start({
4514 * x: 100,
4515 * transition: { duration: 0.5 },
4516 * })
4517 *
4518 * return <motion.div animate={controls} />
4519 * }
4520 * ```
4521 *
4522 * @returns Animation controller with `start` and `stop` methods
4523 *
4524 * @public
4525 */
4526function useAnimation() {
4527 var animationControls = useConstant(function () { return new AnimationControls(); });
4528 React.useEffect(function () {
4529 animationControls.mount();
4530 return function () { return animationControls.unmount(); };
4531 }, []);
4532 return animationControls;
4533}
4534
4535/**
4536 * Experimental API.
4537 *
4538 * Makes an animated version of `useState`.
4539 *
4540 * @remarks
4541 *
4542 * When the returned state setter is called, values will be animated to their new target.
4543 *
4544 * This allows the animation of arbitrary React components.
4545 *
4546 * **Note:** When animating DOM components, it's always preferable to use the `animate` prop, as Framer
4547 * will bypass React's rendering cycle with one optimised for 60fps motion. This Hook is specifically
4548 * for animating props on arbitrary React components, or for animating text content.
4549 *
4550 * ```jsx
4551 * const [state, setState] = useAnimatedState({ percentage: 0 })
4552 *
4553 * return (
4554 * <Graph
4555 * percentage={state.percentage}
4556 * onTap={() => setState({ percentage: 50 })}
4557 * />
4558 * )
4559 * ```
4560 *
4561 * @internalremarks
4562 *
4563 * TODO:
4564 * - Make hook accept a typed version of Target that accepts any value (not just DOM values)
4565 * - Allow hook to accept single values. ie useAnimatedState(0)
4566 * - Allow providing MotionValues via initialState.
4567 *
4568 * @beta
4569 */
4570function useAnimatedState(initialState) {
4571 var _a = React.useState(initialState), animationState = _a[0], onUpdate = _a[1];
4572 var config = useConstant(function () { return ({ onUpdate: onUpdate }); });
4573 var values = useMotionValues(config);
4574 var controls = useValueAnimationControls({
4575 values: values,
4576 readValueFromSource: function (key) { return animationState[key]; },
4577 }, {}, false);
4578 var startAnimation = useConstant(function () { return function (animationDefinition) {
4579 return controls.start(animationDefinition);
4580 }; });
4581 React.useEffect(function () {
4582 values.mount();
4583 return function () { return values.unmount(); };
4584 }, []);
4585 return [animationState, startAnimation];
4586}
4587
4588/**
4589 * 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.
4590 *
4591 * @library
4592 *
4593 * ```jsx
4594 * import * as React from "react"
4595 * import { Frame, useCycle } from "framer"
4596 *
4597 * export function MyComponent() {
4598 * const [x, cycleX] = useCycle(0, 50, 100)
4599 *
4600 * return (
4601 * <Frame
4602 * animate={{ x: x }}
4603 * onTap={() => cycleX()}
4604 * />
4605 * )
4606 * }
4607 * ```
4608 *
4609 * @motion
4610 *
4611 * An index value can be passed to the returned `cycle` function to cycle to a specific index.
4612 *
4613 * ```jsx
4614 * import * as React from "react"
4615 * import { motion, useCycle } from "framer-motion"
4616 *
4617 * export const MyComponent = () => {
4618 * const [x, cycleX] = useCycle(0, 50, 100)
4619 *
4620 * return (
4621 * <motion.div
4622 * animate={{ x: x }}
4623 * onTap={() => cycleX()}
4624 * />
4625 * )
4626 * }
4627 * ```
4628 *
4629 * @param items - items to cycle through
4630 * @returns [currentState, cycleState]
4631 *
4632 * @public
4633 */
4634function useCycle() {
4635 var items = [];
4636 for (var _i = 0; _i < arguments.length; _i++) {
4637 items[_i] = arguments[_i];
4638 }
4639 // TODO: After Framer X beta, remove this warning
4640 heyListen.warning(items.length > 1, "useCycle syntax has changed. `useCycle([0, 1, 2])` becomes `useCycle(0, 1, 2)`");
4641 var index = React.useRef(0);
4642 var _a = React.useState(items[index.current]), item = _a[0], setItem = _a[1];
4643 return [
4644 item,
4645 function (next) {
4646 index.current =
4647 typeof next !== "number"
4648 ? popcorn.wrap(0, items.length, index.current + 1)
4649 : next;
4650 setItem(items[index.current]);
4651 },
4652 ];
4653}
4654
4655/**
4656 * Can manually trigger a drag gesture on one or more `drag`-enabled `motion` components.
4657 *
4658 * @library
4659 *
4660 * ```jsx
4661 * const dragControls = useDragControls()
4662 *
4663 * function startDrag(event) {
4664 * dragControls.start(event, { snapToCursor: true })
4665 * }
4666 *
4667 * return (
4668 * <>
4669 * <Frame onTapStart={startDrag} />
4670 * <Frame drag="x" dragControls={dragControls} />
4671 * </>
4672 * )
4673 * ```
4674 *
4675 * @motion
4676 *
4677 * ```jsx
4678 * const dragControls = useDragControls()
4679 *
4680 * function startDrag(event) {
4681 * dragControls.start(event, { snapToCursor: true })
4682 * }
4683 *
4684 * return (
4685 * <>
4686 * <div onMouseDown={startDrag} />
4687 * <motion.div drag="x" dragControls={dragControls} />
4688 * </>
4689 * )
4690 * ```
4691 *
4692 * @public
4693 */
4694var DragControls = /** @class */ (function () {
4695 function DragControls() {
4696 this.componentControls = new Set();
4697 }
4698 /**
4699 * Subscribe a component's internal `ComponentDragControls` to the user-facing API.
4700 *
4701 * @internal
4702 */
4703 DragControls.prototype.subscribe = function (controls) {
4704 var _this = this;
4705 this.componentControls.add(controls);
4706 return function () { return _this.componentControls.delete(controls); };
4707 };
4708 /**
4709 * Start a drag gesture on every `motion` component that has this set of drag controls
4710 * passed into it via the `dragControls` prop.
4711 *
4712 * ```jsx
4713 * dragControls.start(e, {
4714 * snapToCursor: true
4715 * })
4716 * ```
4717 *
4718 * @param event - A mouse/touch/pointer event.
4719 * @param options - Options
4720 *
4721 * @public
4722 */
4723 DragControls.prototype.start = function (event, options) {
4724 this.componentControls.forEach(function (controls) {
4725 controls.start(event.nativeEvent || event, options);
4726 });
4727 };
4728 return DragControls;
4729}());
4730var createDragControls = function () { return new DragControls(); };
4731/**
4732 * Usually, dragging is initiated by pressing down on a `motion` component with a `drag` prop
4733 * and moving it. For some use-cases, for instance clicking at an arbitrary point on a video scrubber, we
4734 * might want to initiate that dragging from a different component than the draggable one.
4735 *
4736 * By creating a `dragControls` using the `useDragControls` hook, we can pass this into
4737 * the draggable component's `dragControls` prop. It exposes a `start` method
4738 * that can start dragging from pointer events on other components.
4739 *
4740 * @library
4741 *
4742 * ```jsx
4743 * const dragControls = useDragControls()
4744 *
4745 * function startDrag(event) {
4746 * dragControls.start(event, { snapToCursor: true })
4747 * }
4748 *
4749 * return (
4750 * <>
4751 * <Frame onTapStart={startDrag} />
4752 * <Frame drag="x" dragControls={dragControls} />
4753 * </>
4754 * )
4755 * ```
4756 *
4757 * @motion
4758 *
4759 * ```jsx
4760 * const dragControls = useDragControls()
4761 *
4762 * function startDrag(event) {
4763 * dragControls.start(event, { snapToCursor: true })
4764 * }
4765 *
4766 * return (
4767 * <>
4768 * <div onMouseDown={startDrag} />
4769 * <motion.div drag="x" dragControls={dragControls} />
4770 * </>
4771 * )
4772 * ```
4773 *
4774 * @public
4775 */
4776function useDragControls() {
4777 return useConstant(createDragControls);
4778}
4779
4780var PresenceChild = function (_a) {
4781 var children = _a.children, exitProps = _a.exitProps;
4782 var context = React.useContext(MotionContext);
4783 // Create a new `value` in all instances to ensure `motion` children re-render
4784 // and detect any layout changes that might have occurred.
4785 context = tslib.__assign(tslib.__assign({}, context), { exitProps: exitProps || {} });
4786 return (React.createElement(MotionContext.Provider, { value: context }, children));
4787};
4788function getChildKey(child) {
4789 return child.key || "";
4790}
4791function updateChildLookup(children, allChildren) {
4792 var seenChildren = process.env.NODE_ENV !== "production" ? new Set() : null;
4793 children.forEach(function (child) {
4794 var key = getChildKey(child);
4795 if (process.env.NODE_ENV !== "production" && seenChildren) {
4796 if (seenChildren.has(key)) {
4797 console.warn("Children of AnimatePresence require unique keys. \"" + key + "\" is a duplicate.");
4798 }
4799 seenChildren.add(key);
4800 }
4801 allChildren.set(key, child);
4802 });
4803}
4804function onlyElements(children) {
4805 var filtered = [];
4806 // We use forEach here instead of map as map mutates the component key by preprending `.$`
4807 React.Children.forEach(children, function (child) {
4808 if (React.isValidElement(child))
4809 filtered.push(child);
4810 });
4811 return filtered;
4812}
4813/**
4814 * The `AnimatePresence` component enables the use of the `exit` prop to animate components
4815 * when they're removed from the component tree.
4816 *
4817 * When adding/removing more than a single child component, every component
4818 * **must** be given a unique `key` prop.
4819 *
4820 * You can propagate exit animations throughout a tree by using variants.
4821 *
4822 * @library
4823 *
4824 * You can use any component(s) within `AnimatePresence`, but the first `Frame` in each should
4825 * have an `exit` property defined.
4826 *
4827 * ```jsx
4828 * import { Frame, AnimatePresence } from 'framer'
4829 *
4830 * // As items are added and removed from `items`
4831 * export function Items({ items }) {
4832 * return (
4833 * <AnimatePresence>
4834 * {items.map(item => (
4835 * <Frame
4836 * key={item.id}
4837 * initial={{ opacity: 0 }}
4838 * animate={{ opacity: 1 }}
4839 * exit={{ opacity: 0 }}
4840 * />
4841 * ))}
4842 * </AnimatePresence>
4843 * )
4844 * }
4845 * ```
4846 *
4847 * @motion
4848 *
4849 * You can use any component(s) within `AnimatePresence`, but the first `motion` component in each should
4850 * have an `exit` property defined.
4851 *
4852 * ```jsx
4853 * import { motion, AnimatePresence } from 'framer-motion'
4854 *
4855 * export const Items = ({ items }) => (
4856 * <AnimatePresence>
4857 * {items.map(item => (
4858 * <motion.div
4859 * key={item.id}
4860 * initial={{ opacity: 0 }}
4861 * animate={{ opacity: 1 }}
4862 * exit={{ opacity: 0 }}
4863 * />
4864 * ))}
4865 * </AnimatePresence>
4866 * )
4867 * ```
4868 *
4869 * @public
4870 */
4871var AnimatePresence = function (_a) {
4872 var children = _a.children, custom = _a.custom, _b = _a.initial, initial = _b === void 0 ? true : _b, onExitComplete = _a.onExitComplete, exitBeforeEnter = _a.exitBeforeEnter;
4873 // We want to force a re-render once all exiting animations have finished. We
4874 // either use a local forceUpdate function, or one from a parent context if it exists.
4875 var localForceUpdate = useForceUpdate();
4876 var contextForceUpdate = React.useContext(SyncLayoutContext);
4877 var forceUpdate = contextForceUpdate || localForceUpdate;
4878 var isInitialRender = React.useRef(true);
4879 // Filter out any children that aren't ReactElements. We can only track ReactElements with a props.key
4880 var filteredChildren = onlyElements(children);
4881 // Keep a living record of the children we're actually rendering so we
4882 // can diff to figure out which are entering and exiting
4883 var presentChildren = React.useRef(filteredChildren);
4884 // A lookup table to quickly reference components by key
4885 var allChildren = React.useRef(new Map())
4886 .current;
4887 // A living record of all currently exiting components.
4888 var exiting = React.useRef(new Set()).current;
4889 updateChildLookup(filteredChildren, allChildren);
4890 // If this is the initial component render, just deal with logic surrounding whether
4891 // we play onMount animations or not.
4892 if (isInitialRender.current) {
4893 isInitialRender.current = false;
4894 return (React.createElement(React.Fragment, null, filteredChildren.map(function (child) { return (React.createElement(PresenceChild, { key: getChildKey(child), exitProps: initial ? undefined : { initial: false } }, child)); })));
4895 }
4896 // If this is a subsequent render, deal with entering and exiting children
4897 var childrenToRender = tslib.__spreadArrays(filteredChildren);
4898 // Diff the keys of the currently-present and target children to update our
4899 // exiting list.
4900 var presentKeys = presentChildren.current.map(getChildKey);
4901 var targetKeys = filteredChildren.map(getChildKey);
4902 // Diff the present children with our target children and mark those that are exiting
4903 var numPresent = presentKeys.length;
4904 for (var i = 0; i < numPresent; i++) {
4905 var key = presentKeys[i];
4906 if (targetKeys.indexOf(key) === -1) {
4907 exiting.add(key);
4908 }
4909 else {
4910 // In case this key has re-entered, remove from the exiting list
4911 exiting.delete(key);
4912 }
4913 }
4914 // If we currently have exiting children, and we're deferring rendering incoming children
4915 // until after all current children have exiting, empty the childrenToRender array
4916 if (exitBeforeEnter && exiting.size) {
4917 childrenToRender = [];
4918 }
4919 // Loop through all currently exiting components and clone them to overwrite `animate`
4920 // with any `exit` prop they might have defined.
4921 exiting.forEach(function (key) {
4922 // If this component is actually entering again, early return
4923 if (targetKeys.indexOf(key) !== -1)
4924 return;
4925 var child = allChildren.get(key);
4926 if (!child)
4927 return;
4928 var insertionIndex = presentKeys.indexOf(key);
4929 var onExit = function () {
4930 exiting.delete(key);
4931 // Remove this child from the present children
4932 var removeIndex = presentChildren.current.findIndex(function (child) { return child.key === key; });
4933 presentChildren.current.splice(removeIndex, 1);
4934 // Defer re-rendering until all exiting children have indeed left
4935 if (!exiting.size) {
4936 presentChildren.current = filteredChildren;
4937 forceUpdate();
4938 onExitComplete && onExitComplete();
4939 }
4940 };
4941 var exitProps = {
4942 custom: custom,
4943 isExiting: true,
4944 onExitComplete: onExit,
4945 };
4946 childrenToRender.splice(insertionIndex, 0, React.createElement(PresenceChild, { key: getChildKey(child), exitProps: exitProps }, child));
4947 });
4948 // Add `MotionContext` even to children that don't need it to ensure we're rendering
4949 // the same tree between renders
4950 childrenToRender = childrenToRender.map(function (child) {
4951 var key = child.key;
4952 return exiting.has(key) ? (child) : (React.createElement(PresenceChild, { key: getChildKey(child) }, child));
4953 });
4954 presentChildren.current = childrenToRender;
4955 if (process.env.NODE_ENV !== "production" &&
4956 exitBeforeEnter &&
4957 childrenToRender.length > 1) {
4958 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.");
4959 }
4960 return (React.createElement(React.Fragment, null, exiting.size
4961 ? childrenToRender
4962 : childrenToRender.map(function (child) { return React.cloneElement(child); })));
4963};
4964
4965/**
4966 * When a component is the child of an `AnimatePresence` component, it has access to
4967 * information about whether it's still present the React tree. `usePresence` can be
4968 * used to access that data and perform operations before the component can be considered
4969 * safe to remove.
4970 *
4971 * It returns two values. `isPresent` is a boolean that is `true` when the component
4972 * is present within the React tree. It is `false` when it's been removed, but still visible.
4973 *
4974 * When `isPresent` is `false`, the `safeToRemove` callback can be used to tell `AnimatePresence`
4975 * that it's safe to remove the component from the DOM, for instance after a animation has completed.
4976 *
4977 * ```jsx
4978 * const [isPresent, safeToRemove] = usePresence()
4979 *
4980 * useEffect(() => {
4981 * !isPresent setTimeout(safeToRemove, 1000)
4982 * }, [isPresent])
4983 * ```
4984 *
4985 * @public
4986 */
4987function usePresence() {
4988 var exitProps = React.useContext(MotionContext).exitProps;
4989 if (!exitProps)
4990 return [true];
4991 var isExiting = exitProps.isExiting, onExitComplete = exitProps.onExitComplete;
4992 return isExiting && onExitComplete ? [false, onExitComplete] : [true];
4993}
4994
4995// Does this device prefer reduced motion? Returns `null` server-side.
4996var prefersReducedMotion = motionValue(null);
4997if (typeof window !== "undefined") {
4998 if (window.matchMedia) {
4999 var motionMediaQuery_1 = window.matchMedia("(prefers-reduced-motion)");
5000 var setReducedMotionPreferences = function () {
5001 return prefersReducedMotion.set(motionMediaQuery_1.matches);
5002 };
5003 motionMediaQuery_1.addListener(setReducedMotionPreferences);
5004 setReducedMotionPreferences();
5005 }
5006 else {
5007 prefersReducedMotion.set(false);
5008 }
5009}
5010function determineShouldReduceMotion(prefersReduced, isReducedMotion) {
5011 return typeof isReducedMotion === "boolean"
5012 ? isReducedMotion
5013 : Boolean(prefersReduced);
5014}
5015
5016/**
5017 * A hook that returns `true` if we should be using reduced motion based on the current device's Reduced Motion setting.
5018 *
5019 * This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing motion-sickness inducing
5020 * `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion.
5021 *
5022 * It will actively respond to changes and re-render your components with the latest setting.
5023 *
5024 * ```jsx
5025 * export function Sidebar({ isOpem }) {
5026 * const shouldReduceMotion = useReducedMotion()
5027 * const closedX = shouldReduceMotion ? 0 : "-100%"
5028 *
5029 * return (
5030 * <motion.div animate={{
5031 * opacity: isOpen ? 1 : 0,
5032 * x: isOpen ? 0 : closedX
5033 * }} />
5034 * )
5035 * }
5036 * ```
5037 *
5038 * @return boolean
5039 *
5040 * @public
5041 */
5042function useReducedMotion() {
5043 var isReducedMotion = React.useContext(MotionContext).isReducedMotion;
5044 var _a = React.useState(determineShouldReduceMotion(prefersReducedMotion.get(), isReducedMotion)), shouldReduceMotion = _a[0], setShouldReduceMotion = _a[1];
5045 React.useEffect(function () {
5046 return prefersReducedMotion.onChange(function (v) {
5047 setShouldReduceMotion(determineShouldReduceMotion(v, isReducedMotion));
5048 });
5049 }, [setShouldReduceMotion, isReducedMotion]);
5050 return shouldReduceMotion;
5051}
5052
5053/**
5054 * Define accessibility options for a tree. Can be used to force the tree into Reduced Motion mode,
5055 * or disable device detection.
5056 *
5057 * @internal
5058 */
5059function ReducedMotion(_a) {
5060 var children = _a.children, enabled = _a.enabled;
5061 var context = React.useContext(MotionContext);
5062 context = React.useMemo(function () { return (tslib.__assign(tslib.__assign({}, context), { isReducedMotion: enabled })); }, [enabled]);
5063 return (React.createElement(MotionContext.Provider, { value: context }, children));
5064}
5065
5066exports.AnimatePresence = AnimatePresence;
5067exports.AnimationControls = AnimationControls;
5068exports.DragControls = DragControls;
5069exports.MotionContext = MotionContext;
5070exports.MotionPluginContext = MotionPluginContext;
5071exports.MotionPlugins = MotionPlugins;
5072exports.MotionValue = MotionValue;
5073exports.ReducedMotion = ReducedMotion;
5074exports.UnstableSyncLayout = UnstableSyncLayout;
5075exports.animationControls = animationControls;
5076exports.createMotionComponent = createMotionComponent;
5077exports.isValidMotionProp = isValidMotionProp;
5078exports.motion = motion;
5079exports.motionValue = motionValue;
5080exports.transform = transform;
5081exports.unwrapMotionValue = unwrapMotionValue;
5082exports.useAnimatedState = useAnimatedState;
5083exports.useAnimation = useAnimation;
5084exports.useCycle = useCycle;
5085exports.useDomEvent = useDomEvent;
5086exports.useDragControls = useDragControls;
5087exports.useExternalRef = useExternalRef;
5088exports.useGestures = useGestures;
5089exports.useInvertedScale = useInvertedScale;
5090exports.useMotionValue = useMotionValue;
5091exports.usePanGesture = usePanGesture;
5092exports.usePresence = usePresence;
5093exports.useReducedMotion = useReducedMotion;
5094exports.useSpring = useSpring;
5095exports.useTapGesture = useTapGesture;
5096exports.useTransform = useTransform;
5097exports.useViewportScroll = useViewportScroll;