: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/debug/record.mjs
if (window.MotionDebug) {
window.MotionDebug.record(data);
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/render/dom/utils/is-svg-element.mjs
function isSVGElement(element) {
return element instanceof SVGElement && element.tagName !== "svg";
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/interfaces/single-value.mjs
function animateSingleValue(value, keyframes, options) {
const motionValue$1 = isMotionValue(value) ? value : motionValue(value);
motionValue$1.start(animateMotionValue("", motionValue$1, keyframes, options));
return motionValue$1.animation;
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/projection/node/create-projection-node.mjs
const transformAxes = ["", "X", "Y", "Z"];
const hiddenVisibility = { visibility: "hidden" };
* We use 1000 as the animation target as 0-1000 maps better to pixels than 0-1
* which has a noticeable difference in spring animations
const animationTarget = 1000;
let create_projection_node_id = 0;
* Use a mutable data object for debug data so as to not create a new
const projectionFrameData = {
recalculatedProjection: 0,
function resetDistortingTransform(key, visualElement, values, sharedAnimationValues) {
const { latestValues } = visualElement;
// Record the distorting transform and then temporarily set it to 0
values[key] = latestValues[key];
visualElement.setStaticValue(key, 0);
if (sharedAnimationValues) {
sharedAnimationValues[key] = 0;
function createProjectionNode({ attachResizeListener, defaultParent, measureScroll, checkIsScrollRoot, resetTransform, }) {
return class ProjectionNode {
constructor(latestValues = {}, parent = defaultParent === null || defaultParent === void 0 ? void 0 : defaultParent()) {
* A unique ID generated for every projection node.
this.id = create_projection_node_id++;
* An id that represents a unique session instigated by startUpdate.
* A Set containing all this component's children. This is used to iterate
* TODO: This could be faster to iterate as a flat array stored on the root node.
this.children = new Set();
* Options for the node. We use this to configure what kind of layout animations
* we should perform (if any).
* We use this to detect when its safe to shut down part of a projection tree.
* We have to keep projecting children for scale correction and relative projection
* until all their parents stop performing layout animations.
this.isTreeAnimating = false;
this.isAnimationBlocked = false;
* Flag to true if we think this layout has been changed. We can't always know this,
* currently we set it to true every time a component renders, or if it has a layoutDependency
* if that has changed between renders. Additionally, components can be grouped by LayoutGroup
* and if one node is dirtied, they all are.
this.isLayoutDirty = false;
* Flag to true if we think the projection calculations for this node needs
* recalculating as a result of an updated transform or layout animation.
this.isProjectionDirty = false;
* Flag to true if the layout *or* transform has changed. This then gets propagated
* throughout the projection tree, forcing any element below to recalculate on the next frame.
this.isSharedProjectionDirty = false;
* Flag transform dirty. This gets propagated throughout the whole tree but is only
* respected by shared nodes.
this.isTransformDirty = false;
* Block layout updates for instant layout transitions throughout the tree.
this.updateManuallyBlocked = false;
this.updateBlockedByResize = false;
* Set to true between the start of the first `willUpdate` call and the end of the `didUpdate`
* If this is an SVG element we currently disable projection transforms
* Flag to true (during promotion) if a node doing an instant layout transition needs to reset
* Flags whether this node should have its transform reset prior to measuring.
this.shouldResetTransform = false;
* An object representing the calculated contextual/accumulated/tree scale.
* This will be used to scale calculcated projection transforms, as these are
* calculated in screen-space but need to be scaled for elements to layoutly
* make it to their calculated destinations.
this.treeScale = { x: 1, y: 1 };
this.eventHandlers = new Map();
this.hasTreeAnimated = false;
// Note: Currently only running on root node
this.updateScheduled = false;
this.projectionUpdateScheduled = false;
this.checkUpdateFailed = () => {
this.clearAllSnapshots();
* This is a multi-step process as shared nodes might be of different depths. Nodes
* are sorted by depth order, so we need to resolve the entire tree before moving to
this.updateProjection = () => {
this.projectionUpdateScheduled = false;
* Reset debug counts. Manually resetting rather than creating a new
projectionFrameData.totalNodes =
projectionFrameData.resolvedTargetDeltas =
projectionFrameData.recalculatedProjection =
this.nodes.forEach(propagateDirtyNodes);
this.nodes.forEach(resolveTargetDelta);
this.nodes.forEach(calcProjection);
this.nodes.forEach(cleanDirtyNodes);
record(projectionFrameData);
this.hasProjected = false;
this.animationProgress = 0;
// TODO Only running on root node
this.sharedNodes = new Map();
this.latestValues = latestValues;
this.root = parent ? parent.root || parent : this;
this.path = parent ? [...parent.path, parent] : [];
this.depth = parent ? parent.depth + 1 : 0;
for (let i = 0; i < this.path.length; i++) {
this.path[i].shouldResetTransform = true;
this.nodes = new FlatTree();
addEventListener(name, handler) {
if (!this.eventHandlers.has(name)) {
this.eventHandlers.set(name, new SubscriptionManager());
return this.eventHandlers.get(name).add(handler);
notifyListeners(name, ...args) {
const subscriptionManager = this.eventHandlers.get(name);
subscriptionManager && subscriptionManager.notify(...args);
return this.eventHandlers.has(name);
mount(instance, isLayoutDirty = this.root.hasTreeAnimated) {
this.isSVG = isSVGElement(instance);
this.instance = instance;
const { layoutId, layout, visualElement } = this.options;
if (visualElement && !visualElement.current) {
visualElement.mount(instance);
this.root.nodes.add(this);
this.parent && this.parent.children.add(this);
if (isLayoutDirty && (layout || layoutId)) {
this.isLayoutDirty = true;
if (attachResizeListener) {
const resizeUnblockUpdate = () => (this.root.updateBlockedByResize = false);
attachResizeListener(instance, () => {
this.root.updateBlockedByResize = true;
cancelDelay && cancelDelay();
cancelDelay = delay(resizeUnblockUpdate, 250);
if (globalProjectionState.hasAnimatedSinceResize) {
globalProjectionState.hasAnimatedSinceResize = false;
this.nodes.forEach(finishAnimation);
this.root.registerSharedNode(layoutId, this);
// Only register the handler if it requires layout animation
if (this.options.animate !== false &&
this.addEventListener("didUpdate", ({ delta, hasLayoutChanged, hasRelativeTargetChanged, layout: newLayout, }) => {
if (this.isTreeAnimationBlocked()) {
this.relativeTarget = undefined;
// TODO: Check here if an animation exists
const layoutTransition = this.options.transition ||
visualElement.getDefaultTransition() ||
const { onLayoutAnimationStart, onLayoutAnimationComplete, } = visualElement.getProps();
* The target layout of the element might stay the same,
* but its position relative to its parent has changed.
const targetChanged = !this.targetLayout ||
!boxEqualsRounded(this.targetLayout, newLayout) ||
hasRelativeTargetChanged;
* If the layout hasn't seemed to have changed, it might be that the
* element is visually in the same place in the document but its position
* relative to its parent has indeed changed. So here we check for that.
const hasOnlyRelativeTargetChanged = !hasLayoutChanged && hasRelativeTargetChanged;
if (this.options.layoutRoot ||
(this.resumeFrom && this.resumeFrom.instance) ||
hasOnlyRelativeTargetChanged ||
(targetChanged || !this.currentAnimation))) {
this.resumingFrom = this.resumeFrom;
this.resumingFrom.resumingFrom = undefined;
this.setAnimationOrigin(delta, hasOnlyRelativeTargetChanged);
const animationOptions = {
...getValueTransition(layoutTransition, "layout"),
onPlay: onLayoutAnimationStart,
onComplete: onLayoutAnimationComplete,
if (visualElement.shouldReduceMotion ||
this.options.layoutRoot) {
animationOptions.delay = 0;
animationOptions.type = false;
this.startAnimation(animationOptions);
* If the layout hasn't changed and we have an animation that hasn't started yet,
* finish it immediately. Otherwise it will be animating from a location
* that was probably never commited to screen and look like a jumpy box.
if (this.isLead() && this.options.onExitComplete) {
this.options.onExitComplete();
this.targetLayout = newLayout;
this.options.layoutId && this.willUpdate();
this.root.nodes.remove(this);
const stack = this.getStack();
stack && stack.remove(this);
this.parent && this.parent.children.delete(this);
this.instance = undefined;
cancelFrame(this.updateProjection);
this.updateManuallyBlocked = true;
this.updateManuallyBlocked = false;
return this.updateManuallyBlocked || this.updateBlockedByResize;
isTreeAnimationBlocked() {
return (this.isAnimationBlocked ||
(this.parent && this.parent.isTreeAnimationBlocked()) ||
// Note: currently only running on root node
if (this.isUpdateBlocked())
* If we're running optimised appear animations then these must be
* cancelled before measuring the DOM. This is so we can measure
* the true layout of the element rather than the WAAPI animation
* which will be unaffected by the resetSkewAndRotate step.
if (window.HandoffCancelAllAnimations) {
window.HandoffCancelAllAnimations();
this.nodes && this.nodes.forEach(resetSkewAndRotation);
const { visualElement } = this.options;
return visualElement && visualElement.getProps().transformTemplate;
willUpdate(shouldNotifyListeners = true) {
this.root.hasTreeAnimated = true;
if (this.root.isUpdateBlocked()) {
this.options.onExitComplete && this.options.onExitComplete();
!this.root.isUpdating && this.root.startUpdate();
this.isLayoutDirty = true;
for (let i = 0; i < this.path.length; i++) {
const node = this.path[i];
node.shouldResetTransform = true;
node.updateScroll("snapshot");
if (node.options.layoutRoot) {
const { layoutId, layout } = this.options;
if (layoutId === undefined && !layout)
const transformTemplate = this.getTransformTemplate();
this.prevTransformTemplateValue = transformTemplate
? transformTemplate(this.latestValues, "")
shouldNotifyListeners && this.notifyListeners("willUpdate");
this.updateScheduled = false;
const updateWasBlocked = this.isUpdateBlocked();
// When doing an instant transition, we skip the layout update,
// but should still clean up the measurements so that the next
// snapshot could be taken correctly.
this.clearAllSnapshots();
this.nodes.forEach(clearMeasurements);
this.nodes.forEach(clearIsLayoutDirty);
this.nodes.forEach(resetTransformStyle);
* Read ==================
// Update layout measurements of updated children
this.nodes.forEach(updateLayout);
// Notify listeners that the layout is updated
this.nodes.forEach(notifyLayoutUpdate);
this.clearAllSnapshots();
* Manually flush any pending updates. Ideally
* we could leave this to the following requestAnimationFrame but this seems
* to leave a flash of incorrectly styled content.
frameData.delta = clamp_clamp(0, 1000 / 60, now - frameData.timestamp);
frameData.timestamp = now;
frameData.isProcessing = true;
steps.update.process(frameData);
steps.preRender.process(frameData);
steps.render.process(frameData);
frameData.isProcessing = false;
if (!this.updateScheduled) {
this.updateScheduled = true;
microtask.read(() => this.update());
this.nodes.forEach(clearSnapshot);
this.sharedNodes.forEach(removeLeadSnapshots);
scheduleUpdateProjection() {
if (!this.projectionUpdateScheduled) {
this.projectionUpdateScheduled = true;
frame_frame.preRender(this.updateProjection, false, true);
scheduleCheckAfterUnmount() {
* If the unmounting node is in a layoutGroup and did trigger a willUpdate,
* we manually call didUpdate to give a chance to the siblings to animate.
* Otherwise, cleanup all snapshots to prevents future nodes from reusing them.
frame_frame.postRender(() => {
if (this.isLayoutDirty) {
this.root.checkUpdateFailed();
if (this.snapshot || !this.instance)
this.snapshot = this.measure();
// TODO: Incorporate into a forwarded scroll offset