: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
const type = target.types[i];
const originIndex = origin.indexes[type][pointers[type]];
const originValue = (_a = origin.values[originIndex]) !== null && _a !== void 0 ? _a : 0;
orderedOrigin[i] = originValue;
const mixComplex = (origin, target) => {
const template = complex.createTransformer(target);
const originStats = analyseComplexValue(origin);
const targetStats = analyseComplexValue(target);
const canInterpolate = originStats.indexes.var.length === targetStats.indexes.var.length &&
originStats.indexes.color.length === targetStats.indexes.color.length &&
originStats.indexes.number.length >= targetStats.indexes.number.length;
if ((invisibleValues.has(origin) &&
!targetStats.values.length) ||
(invisibleValues.has(target) &&
!originStats.values.length)) {
return mixVisibility(origin, target);
return pipe(mixArray(matchOrder(originStats, targetStats), targetStats.values), template);
warning(true, `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`);
return mixImmediate(origin, target);
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/utils/mix/index.mjs
function mix(from, to, p) {
if (typeof from === "number" &&
typeof to === "number" &&
return mixNumber(from, to, p);
const mixer = getMixer(from);
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/utils/interpolate.mjs
function createMixers(output, ease, customMixer) {
const mixerFactory = customMixer || mix;
const numMixers = output.length - 1;
for (let i = 0; i < numMixers; i++) {
let mixer = mixerFactory(output[i], output[i + 1]);
const easingFunction = Array.isArray(ease) ? ease[i] || noop_noop : ease;
mixer = pipe(easingFunction, mixer);
* Create a function that maps from a numerical input array to a generic output array.
* - Colors (hex, hsl, hsla, rgb, rgba)
* - Complex (combinations of one or more numbers or strings)
* const mixColor = interpolate([0, 1], ['#fff', '#000'])
* mixColor(0.5) // 'rgba(128, 128, 128, 1)'
* TODO Revist this approach once we've moved to data models for values,
* probably not needed to pregenerate mixer functions.
function interpolate(input, output, { clamp: isClamp = true, ease, mixer } = {}) {
const inputLength = input.length;
errors_invariant(inputLength === output.length, "Both input and output ranges must be the same length");
* If we're only provided a single input, we can just make a function
* that returns the output.
if (inputLength === 2 && input[0] === input[1])
// If input runs highest -> lowest, reverse both arrays
if (input[0] > input[inputLength - 1]) {
input = [...input].reverse();
output = [...output].reverse();
const mixers = createMixers(output, ease, mixer);
const numMixers = mixers.length;
const interpolator = (v) => {
for (; i < input.length - 2; i++) {
const progressInRange = progress(input[i], input[i + 1], v);
return mixers[i](progressInRange);
? (v) => interpolator(clamp_clamp(input[0], input[inputLength - 1], v))
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/utils/offsets/fill.mjs
function fillOffset(offset, remaining) {
const min = offset[offset.length - 1];
for (let i = 1; i <= remaining; i++) {
const offsetProgress = progress(0, remaining, i);
offset.push(mixNumber(min, 1, offsetProgress));
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/utils/offsets/default.mjs
function defaultOffset(arr) {
fillOffset(offset, arr.length - 1);
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/utils/offsets/time.mjs
function convertOffsetToTimes(offset, duration) {
return offset.map((o) => o * duration);
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/generators/keyframes.mjs
function defaultEasing(values, easing) {
return values.map(() => easing || easeInOut).splice(0, values.length - 1);
function keyframes_keyframes({ duration = 300, keyframes: keyframeValues, times, ease = "easeInOut", }) {
* Easing functions can be externally defined as strings. Here we convert them
const easingFunctions = isEasingArray(ease)
? ease.map(easingDefinitionToFunction)
: easingDefinitionToFunction(ease);
* This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
* to reduce GC during animation.
value: keyframeValues[0],
* Create a times array based on the provided 0-1 offsets
const absoluteTimes = convertOffsetToTimes(
// Only use the provided offsets if they're the correct length
// TODO Maybe we should warn here if there's a length mismatch
times && times.length === keyframeValues.length
: defaultOffset(keyframeValues), duration);
const mapTimeToKeyframe = interpolate(absoluteTimes, keyframeValues, {
ease: Array.isArray(easingFunctions)
: defaultEasing(keyframeValues, easingFunctions),
calculatedDuration: duration,
state.value = mapTimeToKeyframe(t);
state.done = t >= duration;
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/generators/utils/calc-duration.mjs
* Implement a practical max duration for keyframe generation
* to prevent infinite loops
const maxGeneratorDuration = 20000;
function calcGeneratorDuration(generator) {
let state = generator.next(duration);
while (!state.done && duration < maxGeneratorDuration) {
state = generator.next(duration);
return duration >= maxGeneratorDuration ? Infinity : duration;
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/animators/drivers/driver-frameloop.mjs
const frameloopDriver = (update) => {
const passTimestamp = ({ timestamp }) => update(timestamp);
start: () => frame_frame.update(passTimestamp, true),
stop: () => cancelFrame(passTimestamp),
* If we're processing this frame we can use the
* framelocked timestamp to keep things in sync.
now: () => (frameData.isProcessing ? frameData.timestamp : time.now()),
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/animators/MainThreadAnimation.mjs
tween: keyframes_keyframes,
keyframes: keyframes_keyframes,
const percentToProgress = (percent) => percent / 100;
* Animation that runs on the main thread. Designed to be WAAPI-spec in the subset of
* features we expose publically. Mostly the compatibility is to ensure visual identity
* between both WAAPI and main thread animations.
class MainThreadAnimation extends BaseAnimation {
constructor({ KeyframeResolver: KeyframeResolver$1 = KeyframeResolver, ...options }) {
* The time at which the animation was paused.
* The time at which the animation was started.
* The time at which the animation was cancelled.
* The current time of the animation.
* Playback speed as a factor. 0 would be stopped, -1 reverse and 2 double speed.
* The state of the animation to apply when the animation is resolved. This
* allows calls to the public API to control the animation before it is resolved,
* without us having to resolve it first.
this.pendingPlayState = "running";
* This method is bound to the instance to fix a pattern where
* animation.stop is returned as a reference from a useEffect.
if (this.state === "idle")
const { onStop } = this.options;
const { name, motionValue, keyframes } = this.options;
const onResolved = (resolvedKeyframes, finalKeyframe) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe);
if (name && motionValue && motionValue.owner) {
this.resolver = motionValue.owner.resolveKeyframes(keyframes, onResolved, name, motionValue);
this.resolver = new KeyframeResolver$1(keyframes, onResolved, name, motionValue);
this.resolver.scheduleResolve();
initPlayback(keyframes$1) {
const { type = "keyframes", repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = this.options;
const generatorFactory = generators[type] || keyframes_keyframes;
* If our generator doesn't support mixing numbers, we need to replace keyframes with
* [0, 100] and then make a function that maps that to the actual keyframes.
* 100 is chosen instead of 1 as it works nicer with spring animations.
let mapPercentToKeyframes;
if (generatorFactory !== keyframes_keyframes &&
typeof keyframes$1[0] !== "number") {
mapPercentToKeyframes = pipe(percentToProgress, mix(keyframes$1[0], keyframes$1[1]));
const generator = generatorFactory({ ...this.options, keyframes: keyframes$1 });
* If we have a mirror repeat type we need to create a second generator that outputs the
* mirrored (not reversed) animation and later ping pong between the two generators.
if (repeatType === "mirror") {
mirroredGenerator = generatorFactory({
keyframes: [...keyframes$1].reverse(),
* If duration is undefined and we have repeat options,
* we need to calculate a duration from the generator.
* We set it to the generator itself to cache the duration.
* Any timeline resolver will need to have already precalculated
* the duration by this step.
if (generator.calculatedDuration === null) {
generator.calculatedDuration = calcGeneratorDuration(generator);
const { calculatedDuration } = generator;
const resolvedDuration = calculatedDuration + repeatDelay;
const totalDuration = resolvedDuration * (repeat + 1) - repeatDelay;
const { autoplay = true } = this.options;
if (this.pendingPlayState === "paused" || !autoplay) {
this.state = this.pendingPlayState;
tick(timestamp, sample = false) {
const { resolved } = this;
// If the animations has failed to resolve, return the final keyframe.
const { keyframes } = this.options;
return { done: true, value: keyframes[keyframes.length - 1] };
const { finalKeyframe, generator, mirroredGenerator, mapPercentToKeyframes, keyframes, calculatedDuration, totalDuration, resolvedDuration, } = resolved;
if (this.startTime === null)
return generator.next(0);
const { delay, repeat, repeatType, repeatDelay, onUpdate } = this.options;
* requestAnimationFrame timestamps can come through as lower than
* the startTime as set by performance.now(). Here we prevent this,
* though in the future it could be possible to make setting startTime
* a pending operation that gets resolved here.
this.startTime = Math.min(this.startTime, timestamp);
else if (this.speed < 0) {
this.startTime = Math.min(timestamp - totalDuration / this.speed, this.startTime);
this.currentTime = timestamp;
else if (this.holdTime !== null) {
this.currentTime = this.holdTime;
// Rounding the time because floating point arithmetic is not always accurate, e.g. 3000.367 - 1000.367 =
// 2000.0000000000002. This is a problem when we are comparing the currentTime with the duration, for
Math.round(timestamp - this.startTime) * this.speed;
const timeWithoutDelay = this.currentTime - delay * (this.speed >= 0 ? 1 : -1);
const isInDelayPhase = this.speed >= 0
: timeWithoutDelay > totalDuration;
this.currentTime = Math.max(timeWithoutDelay, 0);
// If this animation has finished, set the current time to the total duration.
if (this.state === "finished" && this.holdTime === null) {
this.currentTime = totalDuration;
let elapsed = this.currentTime;
let frameGenerator = generator;
* Get the current progress (0-1) of the animation. If t is >
* than duration we'll get values like 2.5 (midway through the
const progress = Math.min(this.currentTime, totalDuration) / resolvedDuration;
* Get the current iteration (0 indexed). For instance the floor of
let currentIteration = Math.floor(progress);
* Get the current progress of the iteration by taking the remainder
* so 2.5 is 0.5 through iteration 2
let iterationProgress = progress % 1.0;
* If iteration progress is 1 we count that as the end
* of the previous iteration.
if (!iterationProgress && progress >= 1) {
iterationProgress === 1 && currentIteration--;
currentIteration = Math.min(currentIteration, repeat + 1);
* Reverse progress if we're not running in "normal" direction
const isOddIteration = Boolean(currentIteration % 2);
if (repeatType === "reverse") {
iterationProgress = 1 - iterationProgress;
iterationProgress -= repeatDelay / resolvedDuration;
else if (repeatType === "mirror") {
frameGenerator = mirroredGenerator;
elapsed = clamp_clamp(0, 1, iterationProgress) * resolvedDuration;
* If we're in negative time, set state as the initial keyframe.
* This prevents delay: x, duration: 0 animations from finishing
const state = isInDelayPhase
? { done: false, value: keyframes[0] }
: frameGenerator.next(elapsed);
if (mapPercentToKeyframes) {
state.value = mapPercentToKeyframes(state.value);
if (!isInDelayPhase && calculatedDuration !== null) {
? this.currentTime >= totalDuration