: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
const isAnimationFinished = this.holdTime === null &&
(this.state === "finished" || (this.state === "running" && done));
if (isAnimationFinished && finalKeyframe !== undefined) {
state.value = getFinalKeyframe(keyframes, this.options, finalKeyframe);
if (isAnimationFinished) {
const { resolved } = this;
return resolved ? millisecondsToSeconds(resolved.calculatedDuration) : 0;
return millisecondsToSeconds(this.currentTime);
newTime = secondsToMilliseconds(newTime);
this.currentTime = newTime;
if (this.holdTime !== null || this.speed === 0) {
this.startTime = this.driver.now() - newTime / this.speed;
return this.playbackSpeed;
const hasChanged = this.playbackSpeed !== newSpeed;
this.playbackSpeed = newSpeed;
this.time = millisecondsToSeconds(this.currentTime);
if (!this.resolver.isScheduled) {
this.pendingPlayState = "running";
const { driver = frameloopDriver, onPlay } = this.options;
this.driver = driver((timestamp) => this.tick(timestamp));
const now = this.driver.now();
if (this.holdTime !== null) {
this.startTime = now - this.holdTime;
else if (!this.startTime || this.state === "finished") {
if (this.state === "finished") {
this.updateFinishedPromise();
this.cancelTime = this.startTime;
* Set playState to running only after we've used it in
this.pendingPlayState = "paused";
this.holdTime = (_a = this.currentTime) !== null && _a !== void 0 ? _a : 0;
if (this.state !== "running") {
this.pendingPlayState = this.state = "finished";
const { onComplete } = this.options;
onComplete && onComplete();
if (this.cancelTime !== null) {
this.tick(this.cancelTime);
this.updateFinishedPromise();
this.resolveFinishedPromise();
this.updateFinishedPromise();
this.startTime = this.cancelTime = null;
return this.tick(time, true);
function animateValue(options) {
return new MainThreadAnimation(options);
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/easing/utils/is-bezier-definition.mjs
const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/animators/waapi/easing.mjs
function isWaapiSupportedEasing(easing) {
return Boolean(!easing ||
(typeof easing === "string" && easing in supportedWaapiEasing) ||
isBezierDefinition(easing) ||
(Array.isArray(easing) && easing.every(isWaapiSupportedEasing)));
const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
const supportedWaapiEasing = {
easeInOut: "ease-in-out",
circIn: cubicBezierAsString([0, 0.65, 0.55, 1]),
circOut: cubicBezierAsString([0.55, 0, 1, 0.45]),
backIn: cubicBezierAsString([0.31, 0.01, 0.66, -0.59]),
backOut: cubicBezierAsString([0.33, 1.53, 0.69, 0.99]),
function mapEasingToNativeEasingWithDefault(easing) {
return (mapEasingToNativeEasing(easing) ||
supportedWaapiEasing.easeOut);
function mapEasingToNativeEasing(easing) {
else if (isBezierDefinition(easing)) {
return cubicBezierAsString(easing);
else if (Array.isArray(easing)) {
return easing.map(mapEasingToNativeEasingWithDefault);
return supportedWaapiEasing[easing];
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/animators/waapi/index.mjs
function animateStyle(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease, times, } = {}) {
const keyframeOptions = { [valueName]: keyframes };
keyframeOptions.offset = times;
const easing = mapEasingToNativeEasing(ease);
* If this is an easing array, apply to keyframes, not animation as a whole
if (Array.isArray(easing))
keyframeOptions.easing = easing;
return element.animate(keyframeOptions, {
easing: !Array.isArray(easing) ? easing : "linear",
direction: repeatType === "reverse" ? "alternate" : "normal",
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/animators/AcceleratedAnimation.mjs
const supportsWaapi = memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
* A list of values that can be hardware-accelerated.
const acceleratedValues = new Set([
// TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved
// or until we implement support for linear() easing.
* 10ms is chosen here as it strikes a balance between smooth
* results (more than one keyframe per frame at 60fps) and
const sampleDelta = 10; //ms
* Implement a practical max duration for keyframe generation
* to prevent infinite loops
const AcceleratedAnimation_maxDuration = 20000;
* Check if an animation can run natively via WAAPI or requires pregenerated keyframes.
* WAAPI doesn't support spring or function easings so we run these as JS animation before
function requiresPregeneratedKeyframes(options) {
return (options.type === "spring" ||
options.name === "backgroundColor" ||
!isWaapiSupportedEasing(options.ease));
function pregenerateKeyframes(keyframes, options) {
* Create a main-thread animation to pregenerate keyframes.
* We sample this at regular intervals to generate keyframes that we then
* linearly interpolate between.
const sampleAnimation = new MainThreadAnimation({
let state = { done: false, value: keyframes[0] };
const pregeneratedKeyframes = [];
* Bail after 20 seconds of pre-generated keyframes as it's likely
* we're heading for an infinite loop.
while (!state.done && t < AcceleratedAnimation_maxDuration) {
state = sampleAnimation.sample(t);
pregeneratedKeyframes.push(state.value);
keyframes: pregeneratedKeyframes,
duration: t - sampleDelta,
class AcceleratedAnimation extends BaseAnimation {
const { name, motionValue, keyframes } = this.options;
this.resolver = new DOMKeyframesResolver(keyframes, (resolvedKeyframes, finalKeyframe) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe), name, motionValue);
this.resolver.scheduleResolve();
initPlayback(keyframes, finalKeyframe) {
let { duration = 300, times, ease, type, motionValue, name, } = this.options;
* If element has since been unmounted, return false to indicate
* the animation failed to initialised.
if (!((_a = motionValue.owner) === null || _a === void 0 ? void 0 : _a.current)) {
* If this animation needs pre-generated keyframes then generate.
if (requiresPregeneratedKeyframes(this.options)) {
const { onComplete, onUpdate, motionValue, ...options } = this.options;
const pregeneratedAnimation = pregenerateKeyframes(keyframes, options);
keyframes = pregeneratedAnimation.keyframes;
// If this is a very short animation, ensure we have
// at least two keyframes to animate between as older browsers
// can't animate between a single keyframe.
if (keyframes.length === 1) {
keyframes[1] = keyframes[0];
duration = pregeneratedAnimation.duration;
times = pregeneratedAnimation.times;
ease = pregeneratedAnimation.ease;
const animation = animateStyle(motionValue.owner.current, name, keyframes, { ...this.options, duration, times, ease });
// Override the browser calculated startTime with one synchronised to other JS
// and WAAPI animations starting this event loop.
animation.startTime = time.now();
if (this.pendingTimeline) {
animation.timeline = this.pendingTimeline;
this.pendingTimeline = undefined;
* Prefer the `onfinish` prop as it's more widely supported than
* the `finished` promise.
* Here, we synchronously set the provided MotionValue to the end
* keyframe. If we didn't, when the WAAPI animation is finished it would
* be removed from the element which would then revert to its old styles.
animation.onfinish = () => {
const { onComplete } = this.options;
motionValue.set(getFinalKeyframe(keyframes, this.options, finalKeyframe));
onComplete && onComplete();
this.resolveFinishedPromise();
const { resolved } = this;
const { duration } = resolved;
return millisecondsToSeconds(duration);
const { resolved } = this;
const { animation } = resolved;
return millisecondsToSeconds(animation.currentTime || 0);
const { resolved } = this;
const { animation } = resolved;
animation.currentTime = secondsToMilliseconds(newTime);
const { resolved } = this;
const { animation } = resolved;
return animation.playbackRate;
const { resolved } = this;
const { animation } = resolved;
animation.playbackRate = newSpeed;
const { resolved } = this;
const { animation } = resolved;
return animation.playState;
* Replace the default DocumentTimeline with another AnimationTimeline.
* Currently used for scroll animations.
attachTimeline(timeline) {
this.pendingTimeline = timeline;
const { resolved } = this;
const { animation } = resolved;
animation.timeline = timeline;
animation.onfinish = null;
const { resolved } = this;
const { animation } = resolved;
if (animation.playState === "finished") {
this.updateFinishedPromise();
const { resolved } = this;
const { animation } = resolved;
if (this.state === "idle")
const { resolved } = this;
const { animation, keyframes, duration, type, ease, times } = resolved;
if (animation.playState === "idle" ||
animation.playState === "finished") {
* WAAPI doesn't natively have any interruption capabilities.
* Rather than read commited styles back out of the DOM, we can
* create a renderless JS animation and sample it twice to calculate
* its current value, "previous" value, and therefore allow
* Motion to calculate velocity for any subsequent animation.
const { motionValue, onUpdate, onComplete, ...options } = this.options;
const sampleAnimation = new MainThreadAnimation({
const sampleTime = secondsToMilliseconds(this.time);
motionValue.setWithVelocity(sampleAnimation.sample(sampleTime - sampleDelta).value, sampleAnimation.sample(sampleTime).value, sampleDelta);
const { resolved } = this;
resolved.animation.finish();
const { resolved } = this;
resolved.animation.cancel();
static supports(options) {
const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
return (supportsWaapi() &&
acceleratedValues.has(name) &&
motionValue.owner.current instanceof HTMLElement &&
* If we're outputting values to onUpdate then we can't use WAAPI as there's
* no way to read the value from WAAPI every frame.
!motionValue.owner.getProps().onUpdate &&
repeatType !== "mirror" &&
;// CONCATENATED MODULE: ./node_modules/framer-motion/dist/es/animation/interfaces/motion-value.mjs