: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* it's easier to consider each axis individually. This function returns a bounding box
* as a map of single-axis min/max values.
function convertBoundingBoxToBox({ top, left, right, bottom, }) {
x: { min: left, max: right },
y: { min: top, max: bottom },
function convertBoxToBoundingBox({ x, y }) {
return { top: y.min, right: x.max, bottom: y.max, left: x.min };
* Applies a TransformPoint function to a bounding box. TransformPoint is usually a function
* provided by Framer to allow measured points to be corrected for device scaling. This is used
* when measuring DOM elements and DOM event points.
function transformBoxPoints(point, transformPoint) {
const topLeft = transformPoint({ x: point.left, y: point.top });
const bottomRight = transformPoint({ x: point.right, y: point.bottom });
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/projection/utils/has-transform.mjs
function isIdentityScale(scale) {
return scale === undefined || scale === 1;
function hasScale({ scale, scaleX, scaleY }) {
return (!isIdentityScale(scale) ||
!isIdentityScale(scaleX) ||
!isIdentityScale(scaleY));
function hasTransform(values) {
return (hasScale(values) ||
has2DTranslate(values) ||
function has2DTranslate(values) {
return is2DTranslate(values.x) || is2DTranslate(values.y);
function is2DTranslate(value) {
return value && value !== "0%";
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/projection/geometry/delta-apply.mjs
* Scales a point based on a factor and an originPoint
function scalePoint(point, scale, originPoint) {
const distanceFromOrigin = point - originPoint;
const scaled = scale * distanceFromOrigin;
return originPoint + scaled;
* Applies a translate/scale delta to a point
function applyPointDelta(point, translate, scale, originPoint, boxScale) {
if (boxScale !== undefined) {
point = scalePoint(point, boxScale, originPoint);
return scalePoint(point, scale, originPoint) + translate;
* Applies a translate/scale delta to an axis
function applyAxisDelta(axis, translate = 0, scale = 1, originPoint, boxScale) {
axis.min = applyPointDelta(axis.min, translate, scale, originPoint, boxScale);
axis.max = applyPointDelta(axis.max, translate, scale, originPoint, boxScale);
* Applies a translate/scale delta to a box
function applyBoxDelta(box, { x, y }) {
applyAxisDelta(box.x, x.translate, x.scale, x.originPoint);
applyAxisDelta(box.y, y.translate, y.scale, y.originPoint);
* Apply a tree of deltas to a box. We do this to calculate the effect of all the transforms
* in a tree upon our box before then calculating how to project it into our desired viewport-relative box
* This is the final nested loop within updateLayoutDelta for future refactoring
function applyTreeDeltas(box, treeScale, treePath, isSharedTransition = false) {
const treeLength = treePath.length;
treeScale.x = treeScale.y = 1;
for (let i = 0; i < treeLength; i++) {
delta = node.projectionDelta;
* TODO: Prefer to remove this, but currently we have motion components with
* display: contents in Framer.
const instance = node.instance;
instance.style.display === "contents") {
if (isSharedTransition &&
node.options.layoutScroll &&
x: -node.scroll.offset.x,
y: -node.scroll.offset.y,
// Incoporate each ancestor's scale into a culmulative treeScale for this component
treeScale.x *= delta.x.scale;
treeScale.y *= delta.y.scale;
// Apply each ancestor's calculated delta into this component's recorded layout box
applyBoxDelta(box, delta);
if (isSharedTransition && hasTransform(node.latestValues)) {
transformBox(box, node.latestValues);
* Snap tree scale back to 1 if it's within a non-perceivable threshold.
* This will help reduce useless scales getting rendered.
treeScale.x = snapToDefault(treeScale.x);
treeScale.y = snapToDefault(treeScale.y);
function snapToDefault(scale) {
if (Number.isInteger(scale))
return scale > 1.0000000000001 || scale < 0.999999999999 ? scale : 1;
function translateAxis(axis, distance) {
axis.min = axis.min + distance;
axis.max = axis.max + distance;
* Apply a transform to an axis from the latest resolved motion values.
* This function basically acts as a bridge between a flat motion value map
function transformAxis(axis, transforms, [key, scaleKey, originKey]) {
const axisOrigin = transforms[originKey] !== undefined ? transforms[originKey] : 0.5;
const originPoint = mixNumber(axis.min, axis.max, axisOrigin);
// Apply the axis delta to the final axis
applyAxisDelta(axis, transforms[key], transforms[scaleKey], originPoint, transforms.scale);
* The names of the motion values we want to apply as translation, scale and origin.
const xKeys = ["x", "scaleX", "originX"];
const yKeys = ["y", "scaleY", "originY"];
* Apply a transform to a box from the latest resolved motion values.
function transformBox(box, transform) {
transformAxis(box.x, transform, xKeys);
transformAxis(box.y, transform, yKeys);
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/projection/utils/measure.mjs
function measureViewportBox(instance, transformPoint) {
return convertBoundingBoxToBox(transformBoxPoints(instance.getBoundingClientRect(), transformPoint));
function measurePageBox(element, rootProjectionNode, transformPagePoint) {
const viewportBox = measureViewportBox(element, transformPagePoint);
const { scroll } = rootProjectionNode;
translateAxis(viewportBox.x, scroll.offset.x);
translateAxis(viewportBox.y, scroll.offset.y);
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/utils/get-context-window.mjs
// Fixes https://github.com/framer/motion/issues/2270
const getContextWindow = ({ current }) => {
return current ? current.ownerDocument.defaultView : null;
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/gestures/drag/VisualElementDragControls.mjs
const elementDragControls = new WeakMap();
// let latestPointerEvent: PointerEvent
class VisualElementDragControls {
constructor(visualElement) {
// This is a reference to the global drag gesture lock, ensuring only one component
// can "capture" the drag of one or both axes.
// TODO: Look into moving this into pansession?
this.openGlobalLock = null;
this.currentDirection = null;
this.originPoint = { x: 0, y: 0 };
* The permitted boundaries of travel, in pixels.
this.constraints = false;
this.hasMutatedConstraints = false;
* The per-axis resolved elastic values.
this.elastic = createBox();
this.visualElement = visualElement;
start(originEvent, { snapToCursor = false } = {}) {
* Don't start dragging if this component is exiting
const { presenceContext } = this.visualElement;
if (presenceContext && presenceContext.isPresent === false)
const onSessionStart = (event) => {
const { dragSnapToOrigin } = this.getProps();
// Stop or pause any animations on both axis values immediately. This allows the user to throw and catch
dragSnapToOrigin ? this.pauseAnimation() : this.stopAnimation();
this.snapToCursor(extractEventInfo(event, "page").point);
const onStart = (event, info) => {
// Attempt to grab the global drag gesture lock - maybe make this part of PanSession
const { drag, dragPropagation, onDragStart } = this.getProps();
if (drag && !dragPropagation) {
this.openGlobalLock = getGlobalLock(drag);
// If we don 't have the lock, don't start dragging
if (!this.openGlobalLock)
this.currentDirection = null;
this.resolveConstraints();
if (this.visualElement.projection) {
this.visualElement.projection.isAnimationBlocked = true;
this.visualElement.projection.target = undefined;
let current = this.getAxisMotionValue(axis).get() || 0;
* If the MotionValue is a percentage value convert to px
if (percent.test(current)) {
const { projection } = this.visualElement;
if (projection && projection.layout) {
const measuredAxis = projection.layout.layoutBox[axis];
const length = calcLength(measuredAxis);
current = length * (parseFloat(current) / 100);
this.originPoint[axis] = current;
// Fire onDragStart event
frame_frame.postRender(() => onDragStart(event, info));
const { animationState } = this.visualElement;
animationState && animationState.setActive("whileDrag", true);
const onMove = (event, info) => {
// latestPointerEvent = event
const { dragPropagation, dragDirectionLock, onDirectionLock, onDrag, } = this.getProps();
// If we didn't successfully receive the gesture lock, early return.
if (!dragPropagation && !this.openGlobalLock)
// Attempt to detect drag direction if directionLock is true
if (dragDirectionLock && this.currentDirection === null) {
this.currentDirection = getCurrentDirection(offset);
// If we've successfully set a direction, notify listener
if (this.currentDirection !== null) {
onDirectionLock && onDirectionLock(this.currentDirection);
// Update each point with the latest position
this.updateAxis("x", info.point, offset);
this.updateAxis("y", info.point, offset);
* Ideally we would leave the renderer to fire naturally at the end of
* this frame but if the element is about to change layout as the result
* of a re-render we want to ensure the browser can read the latest
* bounding box to ensure the pointer and element don't fall out of sync.
this.visualElement.render();
* This must fire after the render call as it might trigger a state
* change which itself might trigger a layout update.
onDrag && onDrag(event, info);
const onSessionEnd = (event, info) => this.stop(event, info);
const resumeAnimation = () => eachAxis((axis) => {
return this.getAnimationState(axis) === "paused" &&
((_a = this.getAxisMotionValue(axis).animation) === null || _a === void 0 ? void 0 : _a.play());
const { dragSnapToOrigin } = this.getProps();
this.panSession = new PanSession(originEvent, {
transformPagePoint: this.visualElement.getTransformPagePoint(),
contextWindow: getContextWindow(this.visualElement),
const isDragging = this.isDragging;
const { velocity } = info;
this.startAnimation(velocity);
const { onDragEnd } = this.getProps();
frame_frame.postRender(() => onDragEnd(event, info));
const { projection, animationState } = this.visualElement;
projection.isAnimationBlocked = false;
this.panSession && this.panSession.end();
this.panSession = undefined;
const { dragPropagation } = this.getProps();
if (!dragPropagation && this.openGlobalLock) {
this.openGlobalLock = null;
animationState && animationState.setActive("whileDrag", false);
updateAxis(axis, _point, offset) {
const { drag } = this.getProps();
// If we're not dragging this axis, do an early return.
if (!offset || !shouldDrag(axis, drag, this.currentDirection))
const axisValue = this.getAxisMotionValue(axis);
let next = this.originPoint[axis] + offset[axis];
if (this.constraints && this.constraints[axis]) {
next = applyConstraints(next, this.constraints[axis], this.elastic[axis]);
const { dragConstraints, dragElastic } = this.getProps();
const layout = this.visualElement.projection &&
!this.visualElement.projection.layout
? this.visualElement.projection.measure(false)
: (_a = this.visualElement.projection) === null || _a === void 0 ? void 0 : _a.layout;
const prevConstraints = this.constraints;
if (dragConstraints && isRefObject(dragConstraints)) {
this.constraints = this.resolveRefConstraints();
if (dragConstraints && layout) {
this.constraints = calcRelativeConstraints(layout.layoutBox, dragConstraints);
this.constraints = false;
this.elastic = resolveDragElastic(dragElastic);
* If we're outputting to external MotionValues, we want to rebase the measured constraints
* from viewport-relative to component-relative.
if (prevConstraints !== this.constraints &&
!this.hasMutatedConstraints) {
if (this.constraints !== false &&
this.getAxisMotionValue(axis)) {
this.constraints[axis] = rebaseAxisConstraints(layout.layoutBox[axis], this.constraints[axis]);
resolveRefConstraints() {
const { dragConstraints: constraints, onMeasureDragConstraints } = this.getProps();
if (!constraints || !isRefObject(constraints))
const constraintsElement = constraints.current;
errors_invariant(constraintsElement !== null, "If `dragConstraints` is set as a React ref, that ref must be passed to another component's `ref` prop.");
const { projection } = this.visualElement;
if (!projection || !projection.layout)
const constraintsBox = measurePageBox(constraintsElement, projection.root, this.visualElement.getTransformPagePoint());
let measuredConstraints = calcViewportConstraints(projection.layout.layoutBox, constraintsBox);
* If there's an onMeasureDragConstraints listener we call it and
* if different constraints are returned, set constraints to that
if (onMeasureDragConstraints) {
const userConstraints = onMeasureDragConstraints(convertBoxToBoundingBox(measuredConstraints));
this.hasMutatedConstraints = !!userConstraints;
measuredConstraints = convertBoundingBoxToBox(userConstraints);
return measuredConstraints;
startAnimation(velocity) {
const { drag, dragMomentum, dragElastic, dragTransition, dragSnapToOrigin, onDragTransitionEnd, } = this.getProps();
const constraints = this.constraints || {};
const momentumAnimations = eachAxis((axis) => {
if (!shouldDrag(axis, drag, this.currentDirection)) {
let transition = (constraints && constraints[axis]) || {};
transition = { min: 0, max: 0 };
* Overdamp the boundary spring if `dragElastic` is disabled. There's still a frame
* of spring animations so we should look into adding a disable spring option to `inertia`.
* We could do something here where we affect the `bounceStiffness` and `bounceDamping`
* using the value of `dragElastic`.
const bounceStiffness = dragElastic ? 200 : 1000000;
const bounceDamping = dragElastic ? 40 : 10000000;
velocity: dragMomentum ? velocity[axis] : 0,