Initial commit

This commit is contained in:
Ammaar Reshi
2025-01-04 14:06:53 +00:00
parent 7082408604
commit d6025af146
23760 changed files with 3299690 additions and 0 deletions

319
node_modules/framer-motion/dist/es/value/index.mjs generated vendored Normal file
View File

@ -0,0 +1,319 @@
import { SubscriptionManager } from '../utils/subscription-manager.mjs';
import { velocityPerSecond } from '../utils/velocity-per-second.mjs';
import { warnOnce } from '../utils/warn-once.mjs';
import { time } from '../frameloop/sync-time.mjs';
import { frame } from '../frameloop/frame.mjs';
/**
* Maximum time between the value of two frames, beyond which we
* assume the velocity has since been 0.
*/
const MAX_VELOCITY_DELTA = 30;
const isFloat = (value) => {
return !isNaN(parseFloat(value));
};
const collectMotionValues = {
current: undefined,
};
/**
* `MotionValue` is used to track the state and velocity of motion values.
*
* @public
*/
class MotionValue {
/**
* @param init - The initiating value
* @param config - Optional configuration options
*
* - `transformer`: A function to transform incoming values with.
*
* @internal
*/
constructor(init, options = {}) {
/**
* This will be replaced by the build step with the latest version number.
* When MotionValues are provided to motion components, warn if versions are mixed.
*/
this.version = "11.13.1";
/**
* Tracks whether this value can output a velocity. Currently this is only true
* if the value is numerical, but we might be able to widen the scope here and support
* other value types.
*
* @internal
*/
this.canTrackVelocity = null;
/**
* An object containing a SubscriptionManager for each active event.
*/
this.events = {};
this.updateAndNotify = (v, render = true) => {
const currentTime = time.now();
/**
* If we're updating the value during another frame or eventloop
* than the previous frame, then the we set the previous frame value
* to current.
*/
if (this.updatedAt !== currentTime) {
this.setPrevFrameValue();
}
this.prev = this.current;
this.setCurrent(v);
// Update update subscribers
if (this.current !== this.prev && this.events.change) {
this.events.change.notify(this.current);
}
// Update render subscribers
if (render && this.events.renderRequest) {
this.events.renderRequest.notify(this.current);
}
};
this.hasAnimated = false;
this.setCurrent(init);
this.owner = options.owner;
}
setCurrent(current) {
this.current = current;
this.updatedAt = time.now();
if (this.canTrackVelocity === null && current !== undefined) {
this.canTrackVelocity = isFloat(this.current);
}
}
setPrevFrameValue(prevFrameValue = this.current) {
this.prevFrameValue = prevFrameValue;
this.prevUpdatedAt = this.updatedAt;
}
/**
* Adds a function that will be notified when the `MotionValue` is updated.
*
* It returns a function that, when called, will cancel the subscription.
*
* When calling `onChange` inside a React component, it should be wrapped with the
* `useEffect` hook. As it returns an unsubscribe function, this should be returned
* from the `useEffect` function to ensure you don't add duplicate subscribers..
*
* ```jsx
* export const MyComponent = () => {
* const x = useMotionValue(0)
* const y = useMotionValue(0)
* const opacity = useMotionValue(1)
*
* useEffect(() => {
* function updateOpacity() {
* const maxXY = Math.max(x.get(), y.get())
* const newOpacity = transform(maxXY, [0, 100], [1, 0])
* opacity.set(newOpacity)
* }
*
* const unsubscribeX = x.on("change", updateOpacity)
* const unsubscribeY = y.on("change", updateOpacity)
*
* return () => {
* unsubscribeX()
* unsubscribeY()
* }
* }, [])
*
* return <motion.div style={{ x }} />
* }
* ```
*
* @param subscriber - A function that receives the latest value.
* @returns A function that, when called, will cancel this subscription.
*
* @deprecated
*/
onChange(subscription) {
if (process.env.NODE_ENV !== "production") {
warnOnce(false, `value.onChange(callback) is deprecated. Switch to value.on("change", callback).`);
}
return this.on("change", subscription);
}
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = new SubscriptionManager();
}
const unsubscribe = this.events[eventName].add(callback);
if (eventName === "change") {
return () => {
unsubscribe();
/**
* If we have no more change listeners by the start
* of the next frame, stop active animations.
*/
frame.read(() => {
if (!this.events.change.getSize()) {
this.stop();
}
});
};
}
return unsubscribe;
}
clearListeners() {
for (const eventManagers in this.events) {
this.events[eventManagers].clear();
}
}
/**
* Attaches a passive effect to the `MotionValue`.
*
* @internal
*/
attach(passiveEffect, stopPassiveEffect) {
this.passiveEffect = passiveEffect;
this.stopPassiveEffect = stopPassiveEffect;
}
/**
* Sets the state of the `MotionValue`.
*
* @remarks
*
* ```jsx
* const x = useMotionValue(0)
* x.set(10)
* ```
*
* @param latest - Latest value to set.
* @param render - Whether to notify render subscribers. Defaults to `true`
*
* @public
*/
set(v, render = true) {
if (!render || !this.passiveEffect) {
this.updateAndNotify(v, render);
}
else {
this.passiveEffect(v, this.updateAndNotify);
}
}
setWithVelocity(prev, current, delta) {
this.set(current);
this.prev = undefined;
this.prevFrameValue = prev;
this.prevUpdatedAt = this.updatedAt - delta;
}
/**
* Set the state of the `MotionValue`, stopping any active animations,
* effects, and resets velocity to `0`.
*/
jump(v, endAnimation = true) {
this.updateAndNotify(v);
this.prev = v;
this.prevUpdatedAt = this.prevFrameValue = undefined;
endAnimation && this.stop();
if (this.stopPassiveEffect)
this.stopPassiveEffect();
}
/**
* Returns the latest state of `MotionValue`
*
* @returns - The latest state of `MotionValue`
*
* @public
*/
get() {
if (collectMotionValues.current) {
collectMotionValues.current.push(this);
}
return this.current;
}
/**
* @public
*/
getPrevious() {
return this.prev;
}
/**
* Returns the latest velocity of `MotionValue`
*
* @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical.
*
* @public
*/
getVelocity() {
const currentTime = time.now();
if (!this.canTrackVelocity ||
this.prevFrameValue === undefined ||
currentTime - this.updatedAt > MAX_VELOCITY_DELTA) {
return 0;
}
const delta = Math.min(this.updatedAt - this.prevUpdatedAt, MAX_VELOCITY_DELTA);
// Casts because of parseFloat's poor typing
return velocityPerSecond(parseFloat(this.current) -
parseFloat(this.prevFrameValue), delta);
}
/**
* Registers a new animation to control this `MotionValue`. Only one
* animation can drive a `MotionValue` at one time.
*
* ```jsx
* value.start()
* ```
*
* @param animation - A function that starts the provided animation
*
* @internal
*/
start(startAnimation) {
this.stop();
return new Promise((resolve) => {
this.hasAnimated = true;
this.animation = startAnimation(resolve);
if (this.events.animationStart) {
this.events.animationStart.notify();
}
}).then(() => {
if (this.events.animationComplete) {
this.events.animationComplete.notify();
}
this.clearAnimation();
});
}
/**
* Stop the currently active animation.
*
* @public
*/
stop() {
if (this.animation) {
this.animation.stop();
if (this.events.animationCancel) {
this.events.animationCancel.notify();
}
}
this.clearAnimation();
}
/**
* Returns `true` if this value is currently animating.
*
* @public
*/
isAnimating() {
return !!this.animation;
}
clearAnimation() {
delete this.animation;
}
/**
* Destroy and clean up subscribers to this `MotionValue`.
*
* The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically
* handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually
* created a `MotionValue` via the `motionValue` function.
*
* @public
*/
destroy() {
this.clearListeners();
this.stop();
if (this.stopPassiveEffect) {
this.stopPassiveEffect();
}
}
}
function motionValue(init, options) {
return new MotionValue(init, options);
}
export { MotionValue, collectMotionValues, motionValue };

View File

@ -0,0 +1,14 @@
import { warnOnce } from '../../utils/warn-once.mjs';
import { useScroll } from '../use-scroll.mjs';
/**
* @deprecated useElementScroll is deprecated. Convert to useScroll({ container: ref })
*/
function useElementScroll(ref) {
if (process.env.NODE_ENV === "development") {
warnOnce(false, "useElementScroll is deprecated. Convert to useScroll({ container: ref }).");
}
return useScroll({ container: ref });
}
export { useElementScroll };

View File

@ -0,0 +1,14 @@
import { warnOnce } from '../../utils/warn-once.mjs';
import { useScroll } from '../use-scroll.mjs';
/**
* @deprecated useViewportScroll is deprecated. Convert to useScroll()
*/
function useViewportScroll() {
if (process.env.NODE_ENV !== "production") {
warnOnce(false, "useViewportScroll is deprecated. Convert to useScroll().");
}
return useScroll();
}
export { useViewportScroll };

View File

@ -0,0 +1,40 @@
import { rgba } from './rgba.mjs';
import { isColorString } from './utils.mjs';
function parseHex(v) {
let r = "";
let g = "";
let b = "";
let a = "";
// If we have 6 characters, ie #FF0000
if (v.length > 5) {
r = v.substring(1, 3);
g = v.substring(3, 5);
b = v.substring(5, 7);
a = v.substring(7, 9);
// Or we have 3 characters, ie #F00
}
else {
r = v.substring(1, 2);
g = v.substring(2, 3);
b = v.substring(3, 4);
a = v.substring(4, 5);
r += r;
g += g;
b += b;
a += a;
}
return {
red: parseInt(r, 16),
green: parseInt(g, 16),
blue: parseInt(b, 16),
alpha: a ? parseInt(a, 16) / 255 : 1,
};
}
const hex = {
test: /*@__PURE__*/ isColorString("#"),
parse: parseHex,
transform: rgba.transform,
};
export { hex };

View File

@ -0,0 +1,22 @@
import { alpha } from '../numbers/index.mjs';
import { percent } from '../numbers/units.mjs';
import { sanitize } from '../utils/sanitize.mjs';
import { isColorString, splitColor } from './utils.mjs';
const hsla = {
test: /*@__PURE__*/ isColorString("hsl", "hue"),
parse: /*@__PURE__*/ splitColor("hue", "saturation", "lightness"),
transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
return ("hsla(" +
Math.round(hue) +
", " +
percent.transform(sanitize(saturation)) +
", " +
percent.transform(sanitize(lightness)) +
", " +
sanitize(alpha.transform(alpha$1)) +
")");
},
};
export { hsla };

View File

@ -0,0 +1,27 @@
import { hex } from './hex.mjs';
import { hsla } from './hsla.mjs';
import { rgba } from './rgba.mjs';
const color = {
test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
parse: (v) => {
if (rgba.test(v)) {
return rgba.parse(v);
}
else if (hsla.test(v)) {
return hsla.parse(v);
}
else {
return hex.parse(v);
}
},
transform: (v) => {
return typeof v === "string"
? v
: v.hasOwnProperty("red")
? rgba.transform(v)
: hsla.transform(v);
},
};
export { color };

View File

@ -0,0 +1,25 @@
import { clamp } from '../../../utils/clamp.mjs';
import { alpha, number } from '../numbers/index.mjs';
import { sanitize } from '../utils/sanitize.mjs';
import { isColorString, splitColor } from './utils.mjs';
const clampRgbUnit = (v) => clamp(0, 255, v);
const rgbUnit = {
...number,
transform: (v) => Math.round(clampRgbUnit(v)),
};
const rgba = {
test: /*@__PURE__*/ isColorString("rgb", "red"),
parse: /*@__PURE__*/ splitColor("red", "green", "blue"),
transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" +
rgbUnit.transform(red) +
", " +
rgbUnit.transform(green) +
", " +
rgbUnit.transform(blue) +
", " +
sanitize(alpha.transform(alpha$1)) +
")",
};
export { rgbUnit, rgba };

View File

@ -0,0 +1,29 @@
import { floatRegex } from '../utils/float-regex.mjs';
import { isNullish } from '../utils/is-nullish.mjs';
import { singleColorRegex } from '../utils/single-color-regex.mjs';
/**
* Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,
* but false if a number or multiple colors
*/
const isColorString = (type, testProp) => (v) => {
return Boolean((typeof v === "string" &&
singleColorRegex.test(v) &&
v.startsWith(type)) ||
(testProp &&
!isNullish(v) &&
Object.prototype.hasOwnProperty.call(v, testProp)));
};
const splitColor = (aName, bName, cName) => (v) => {
if (typeof v !== "string")
return v;
const [a, b, c, alpha] = v.match(floatRegex);
return {
[aName]: parseFloat(a),
[bName]: parseFloat(b),
[cName]: parseFloat(c),
alpha: alpha !== undefined ? parseFloat(alpha) : 1,
};
};
export { isColorString, splitColor };

View File

@ -0,0 +1,30 @@
import { complex } from './index.mjs';
import { floatRegex } from '../utils/float-regex.mjs';
/**
* Properties that should default to 1 or 100%
*/
const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
function applyDefaultFilter(v) {
const [name, value] = v.slice(0, -1).split("(");
if (name === "drop-shadow")
return v;
const [number] = value.match(floatRegex) || [];
if (!number)
return v;
const unit = value.replace(number, "");
let defaultValue = maxDefaults.has(name) ? 1 : 0;
if (number !== value)
defaultValue *= 100;
return name + "(" + defaultValue + unit + ")";
}
const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
const filter = {
...complex,
getAnimatableNone: (v) => {
const functions = v.match(functionRegex);
return functions ? functions.map(applyDefaultFilter).join(" ") : v;
},
};
export { filter };

View File

@ -0,0 +1,92 @@
import { color } from '../color/index.mjs';
import { colorRegex } from '../utils/color-regex.mjs';
import { floatRegex } from '../utils/float-regex.mjs';
import { sanitize } from '../utils/sanitize.mjs';
function test(v) {
var _a, _b;
return (isNaN(v) &&
typeof v === "string" &&
(((_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) || 0) +
(((_b = v.match(colorRegex)) === null || _b === void 0 ? void 0 : _b.length) || 0) >
0);
}
const NUMBER_TOKEN = "number";
const COLOR_TOKEN = "color";
const VAR_TOKEN = "var";
const VAR_FUNCTION_TOKEN = "var(";
const SPLIT_TOKEN = "${}";
// this regex consists of the `singleCssVariableRegex|rgbHSLValueRegex|digitRegex`
const complexRegex = /var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;
function analyseComplexValue(value) {
const originalValue = value.toString();
const values = [];
const indexes = {
color: [],
number: [],
var: [],
};
const types = [];
let i = 0;
const tokenised = originalValue.replace(complexRegex, (parsedValue) => {
if (color.test(parsedValue)) {
indexes.color.push(i);
types.push(COLOR_TOKEN);
values.push(color.parse(parsedValue));
}
else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {
indexes.var.push(i);
types.push(VAR_TOKEN);
values.push(parsedValue);
}
else {
indexes.number.push(i);
types.push(NUMBER_TOKEN);
values.push(parseFloat(parsedValue));
}
++i;
return SPLIT_TOKEN;
});
const split = tokenised.split(SPLIT_TOKEN);
return { values, split, indexes, types };
}
function parseComplexValue(v) {
return analyseComplexValue(v).values;
}
function createTransformer(source) {
const { split, types } = analyseComplexValue(source);
const numSections = split.length;
return (v) => {
let output = "";
for (let i = 0; i < numSections; i++) {
output += split[i];
if (v[i] !== undefined) {
const type = types[i];
if (type === NUMBER_TOKEN) {
output += sanitize(v[i]);
}
else if (type === COLOR_TOKEN) {
output += color.transform(v[i]);
}
else {
output += v[i];
}
}
}
return output;
};
}
const convertNumbersToZero = (v) => typeof v === "number" ? 0 : v;
function getAnimatableNone(v) {
const parsed = parseComplexValue(v);
const transformer = createTransformer(v);
return transformer(parsed.map(convertNumbersToZero));
}
const complex = {
test,
parse: parseComplexValue,
createTransformer,
getAnimatableNone,
};
export { analyseComplexValue, complex };

View File

@ -0,0 +1,17 @@
import { clamp } from '../../../utils/clamp.mjs';
const number = {
test: (v) => typeof v === "number",
parse: parseFloat,
transform: (v) => v,
};
const alpha = {
...number,
transform: (v) => clamp(0, 1, v),
};
const scale = {
...number,
default: 1,
};
export { alpha, number, scale };

View File

@ -0,0 +1,17 @@
const createUnitType = (unit) => ({
test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
parse: parseFloat,
transform: (v) => `${v}${unit}`,
});
const degrees = /*@__PURE__*/ createUnitType("deg");
const percent = /*@__PURE__*/ createUnitType("%");
const px = /*@__PURE__*/ createUnitType("px");
const vh = /*@__PURE__*/ createUnitType("vh");
const vw = /*@__PURE__*/ createUnitType("vw");
const progressPercentage = {
...percent,
parse: (v) => percent.parse(v) / 100,
transform: (v) => percent.transform(v * 100),
};
export { degrees, percent, progressPercentage, px, vh, vw };

View File

@ -0,0 +1,3 @@
const colorRegex = /(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;
export { colorRegex };

View File

@ -0,0 +1,3 @@
const floatRegex = /-?(?:\d+(?:\.\d+)?|\.\d+)/gu;
export { floatRegex };

View File

@ -0,0 +1,5 @@
function isNullish(v) {
return v == null;
}
export { isNullish };

View File

@ -0,0 +1,5 @@
// If this number is a decimal, make it just five decimal places
// to avoid exponents
const sanitize = (v) => Math.round(v * 100000) / 100000;
export { sanitize };

View File

@ -0,0 +1,3 @@
const singleColorRegex = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
export { singleColorRegex };

View File

@ -0,0 +1,37 @@
import { useMotionValue } from './use-motion-value.mjs';
import { useIsomorphicLayoutEffect } from '../utils/use-isomorphic-effect.mjs';
import { cancelFrame, frame } from '../frameloop/frame.mjs';
function useCombineMotionValues(values, combineValues) {
/**
* Initialise the returned motion value. This remains the same between renders.
*/
const value = useMotionValue(combineValues());
/**
* Create a function that will update the template motion value with the latest values.
* This is pre-bound so whenever a motion value updates it can schedule its
* execution in Framesync. If it's already been scheduled it won't be fired twice
* in a single frame.
*/
const updateValue = () => value.set(combineValues());
/**
* Synchronously update the motion value with the latest values during the render.
* This ensures that within a React render, the styles applied to the DOM are up-to-date.
*/
updateValue();
/**
* Subscribe to all motion values found within the template. Whenever any of them change,
* schedule an update.
*/
useIsomorphicLayoutEffect(() => {
const scheduleUpdate = () => frame.preRender(updateValue, false, true);
const subscriptions = values.map((v) => v.on("change", scheduleUpdate));
return () => {
subscriptions.forEach((unsubscribe) => unsubscribe());
cancelFrame(updateValue);
};
});
return value;
}
export { useCombineMotionValues };

View File

@ -0,0 +1,19 @@
import { collectMotionValues } from './index.mjs';
import { useCombineMotionValues } from './use-combine-values.mjs';
function useComputed(compute) {
/**
* Open session of collectMotionValues. Any MotionValue that calls get()
* will be saved into this array.
*/
collectMotionValues.current = [];
compute();
const value = useCombineMotionValues(collectMotionValues.current, compute);
/**
* Synchronously close session of collectMotionValues.
*/
collectMotionValues.current = undefined;
return value;
}
export { useComputed };

View File

@ -0,0 +1,52 @@
import { useTransform } from './use-transform.mjs';
import { invariant, warning } from 'motion-utils';
import { useMotionValue } from './use-motion-value.mjs';
import { MotionContext } from '../context/MotionContext/index.mjs';
import { useContext } from 'react';
// Keep things reasonable and avoid scale: Infinity. In practise we might need
// to add another value, opacity, that could interpolate scaleX/Y [0,0.01] => [0,1]
// to simply hide content at unreasonable scales.
const maxScale = 100000;
const invertScale = (scale) => scale > 0.001 ? 1 / scale : maxScale;
let hasWarned = false;
/**
* Returns a `MotionValue` each for `scaleX` and `scaleY` that update with the inverse
* of their respective parent scales.
*
* This is useful for undoing the distortion of content when scaling a parent component.
*
* By default, `useInvertedScale` will automatically fetch `scaleX` and `scaleY` from the nearest parent.
* By passing other `MotionValue`s in as `useInvertedScale({ scaleX, scaleY })`, it will invert the output
* of those instead.
*
* ```jsx
* const MyComponent = () => {
* const { scaleX, scaleY } = useInvertedScale()
* return <motion.div style={{ scaleX, scaleY }} />
* }
* ```
*
* @deprecated
*/
function useInvertedScale(scale) {
let parentScaleX = useMotionValue(1);
let parentScaleY = useMotionValue(1);
const { visualElement } = useContext(MotionContext);
invariant(!!(scale || visualElement), "If no scale values are provided, useInvertedScale must be used within a child of another motion component.");
warning(hasWarned, "useInvertedScale is deprecated and will be removed in 3.0. Use the layout prop instead.");
hasWarned = true;
if (scale) {
parentScaleX = scale.scaleX || parentScaleX;
parentScaleY = scale.scaleY || parentScaleY;
}
else if (visualElement) {
parentScaleX = visualElement.getValue("scaleX", 1);
parentScaleY = visualElement.getValue("scaleY", 1);
}
const scaleX = useTransform(parentScaleX, invertScale);
const scaleY = useTransform(parentScaleY, invertScale);
return { scaleX, scaleY };
}
export { invertScale, useInvertedScale };

View File

@ -0,0 +1,45 @@
import { useCombineMotionValues } from './use-combine-values.mjs';
import { isMotionValue } from './utils/is-motion-value.mjs';
/**
* Combine multiple motion values into a new one using a string template literal.
*
* ```jsx
* import {
* motion,
* useSpring,
* useMotionValue,
* useMotionTemplate
* } from "framer-motion"
*
* function Component() {
* const shadowX = useSpring(0)
* const shadowY = useMotionValue(0)
* const shadow = useMotionTemplate`drop-shadow(${shadowX}px ${shadowY}px 20px rgba(0,0,0,0.3))`
*
* return <motion.div style={{ filter: shadow }} />
* }
* ```
*
* @public
*/
function useMotionTemplate(fragments, ...values) {
/**
* Create a function that will build a string from the latest motion values.
*/
const numFragments = fragments.length;
function buildValue() {
let output = ``;
for (let i = 0; i < numFragments; i++) {
output += fragments[i];
const value = values[i];
if (value) {
output += isMotionValue(value) ? value.get() : value;
}
}
return output;
}
return useCombineMotionValues(values.filter(isMotionValue), buildValue);
}
export { useMotionTemplate };

View File

@ -0,0 +1,38 @@
import { useContext, useState, useEffect } from 'react';
import { motionValue } from './index.mjs';
import { MotionConfigContext } from '../context/MotionConfigContext.mjs';
import { useConstant } from '../utils/use-constant.mjs';
/**
* Creates a `MotionValue` to track the state and velocity of a value.
*
* 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.
*
* ```jsx
* export const MyComponent = () => {
* const scale = useMotionValue(1)
*
* return <motion.div style={{ scale }} />
* }
* ```
*
* @param initial - The initial state.
*
* @public
*/
function useMotionValue(initial) {
const value = useConstant(() => motionValue(initial));
/**
* If this motion value is being used in static mode, like on
* the Framer canvas, force components to rerender when the motion
* value is updated.
*/
const { isStatic } = useContext(MotionConfigContext);
if (isStatic) {
const [, setLatest] = useState(initial);
useEffect(() => value.on("change", setLatest), []);
}
return value;
}
export { useMotionValue };

View File

@ -0,0 +1,39 @@
import { motionValue } from './index.mjs';
import { useConstant } from '../utils/use-constant.mjs';
import { useEffect } from 'react';
import { warning } from 'motion-utils';
import { scroll } from '../render/dom/scroll/index.mjs';
import { useIsomorphicLayoutEffect } from '../utils/use-isomorphic-effect.mjs';
function refWarning(name, ref) {
warning(Boolean(!ref || ref.current), `You have defined a ${name} options but the provided ref is not yet hydrated, probably because it's defined higher up the tree. Try calling useScroll() in the same component as the ref, or setting its \`layoutEffect: false\` option.`);
}
const createScrollMotionValues = () => ({
scrollX: motionValue(0),
scrollY: motionValue(0),
scrollXProgress: motionValue(0),
scrollYProgress: motionValue(0),
});
function useScroll({ container, target, layoutEffect = true, ...options } = {}) {
const values = useConstant(createScrollMotionValues);
const useLifecycleEffect = layoutEffect
? useIsomorphicLayoutEffect
: useEffect;
useLifecycleEffect(() => {
refWarning("target", target);
refWarning("container", container);
return scroll((_progress, { x, y }) => {
values.scrollX.set(x.current);
values.scrollXProgress.set(x.progress);
values.scrollY.set(y.current);
values.scrollYProgress.set(y.progress);
}, {
...options,
container: (container === null || container === void 0 ? void 0 : container.current) || undefined,
target: (target === null || target === void 0 ? void 0 : target.current) || undefined,
});
}, [container, target, JSON.stringify(options.offset)]);
return values;
}
export { useScroll };

View File

@ -0,0 +1,85 @@
import { useContext, useRef, useInsertionEffect } from 'react';
import { isMotionValue } from './utils/is-motion-value.mjs';
import { useMotionValue } from './use-motion-value.mjs';
import { MotionConfigContext } from '../context/MotionConfigContext.mjs';
import { useIsomorphicLayoutEffect } from '../utils/use-isomorphic-effect.mjs';
import { animateValue } from '../animation/animators/MainThreadAnimation.mjs';
import { frame, frameData } from '../frameloop/frame.mjs';
function toNumber(v) {
if (typeof v === "number")
return v;
return parseFloat(v);
}
/**
* Creates a `MotionValue` that, when `set`, will use a spring animation to animate to its new state.
*
* It can either work as a stand-alone `MotionValue` by initialising it with a value, or as a subscriber
* to another `MotionValue`.
*
* @remarks
*
* ```jsx
* const x = useSpring(0, { stiffness: 300 })
* const y = useSpring(x, { damping: 10 })
* ```
*
* @param inputValue - `MotionValue` or number. If provided a `MotionValue`, when the input `MotionValue` changes, the created `MotionValue` will spring towards that value.
* @param springConfig - Configuration options for the spring.
* @returns `MotionValue`
*
* @public
*/
function useSpring(source, config = {}) {
const { isStatic } = useContext(MotionConfigContext);
const activeSpringAnimation = useRef(null);
const value = useMotionValue(isMotionValue(source) ? toNumber(source.get()) : source);
const latestValue = useRef(value.get());
const latestSetter = useRef(() => { });
const startAnimation = () => {
/**
* If the previous animation hasn't had the chance to even render a frame, render it now.
*/
const animation = activeSpringAnimation.current;
if (animation && animation.time === 0) {
animation.sample(frameData.delta);
}
stopAnimation();
activeSpringAnimation.current = animateValue({
keyframes: [value.get(), latestValue.current],
velocity: value.getVelocity(),
type: "spring",
restDelta: 0.001,
restSpeed: 0.01,
...config,
onUpdate: latestSetter.current,
});
};
const stopAnimation = () => {
if (activeSpringAnimation.current) {
activeSpringAnimation.current.stop();
}
};
useInsertionEffect(() => {
return value.attach((v, set) => {
/**
* A more hollistic approach to this might be to use isStatic to fix VisualElement animations
* at that level, but this will work for now
*/
if (isStatic)
return set(v);
latestValue.current = v;
latestSetter.current = set;
frame.update(startAnimation);
return value.get();
}, stopAnimation);
}, [JSON.stringify(config)]);
useIsomorphicLayoutEffect(() => {
if (isMotionValue(source)) {
return source.on("change", (v) => value.set(toNumber(v)));
}
}, [value]);
return value;
}
export { useSpring };

10
node_modules/framer-motion/dist/es/value/use-time.mjs generated vendored Normal file
View File

@ -0,0 +1,10 @@
import { useAnimationFrame } from '../utils/use-animation-frame.mjs';
import { useMotionValue } from './use-motion-value.mjs';
function useTime() {
const time = useMotionValue(0);
useAnimationFrame((t) => time.set(t));
return time;
}
export { useTime };

View File

@ -0,0 +1,29 @@
import { transform } from '../utils/transform.mjs';
import { useCombineMotionValues } from './use-combine-values.mjs';
import { useConstant } from '../utils/use-constant.mjs';
import { useComputed } from './use-computed.mjs';
function useTransform(input, inputRangeOrTransformer, outputRange, options) {
if (typeof input === "function") {
return useComputed(input);
}
const transformer = typeof inputRangeOrTransformer === "function"
? inputRangeOrTransformer
: transform(inputRangeOrTransformer, outputRange, options);
return Array.isArray(input)
? useListTransform(input, transformer)
: useListTransform([input], ([latest]) => transformer(latest));
}
function useListTransform(values, transformer) {
const latest = useConstant(() => []);
return useCombineMotionValues(values, () => {
latest.length = 0;
const numValues = values.length;
for (let i = 0; i < numValues; i++) {
latest[i] = values[i].get();
}
return transformer(latest);
});
}
export { useTransform };

View File

@ -0,0 +1,35 @@
import { useMotionValueEvent } from '../utils/use-motion-value-event.mjs';
import { useMotionValue } from './use-motion-value.mjs';
import { frame } from '../frameloop/frame.mjs';
/**
* Creates a `MotionValue` that updates when the velocity of the provided `MotionValue` changes.
*
* ```javascript
* const x = useMotionValue(0)
* const xVelocity = useVelocity(x)
* const xAcceleration = useVelocity(xVelocity)
* ```
*
* @public
*/
function useVelocity(value) {
const velocity = useMotionValue(value.getVelocity());
const updateVelocity = () => {
const latest = value.getVelocity();
velocity.set(latest);
/**
* If we still have velocity, schedule an update for the next frame
* to keep checking until it is zero.
*/
if (latest)
frame.update(updateVelocity);
};
useMotionValueEvent(value, "change", () => {
// Schedule an update to this value at the end of the current frame.
frame.update(updateVelocity, false, true);
});
return velocity;
}
export { useVelocity };

View File

@ -0,0 +1,22 @@
import { MotionValue } from '../index.mjs';
import { getWillChangeName } from './get-will-change-name.mjs';
import { addUniqueItem } from '../../utils/array.mjs';
class WillChangeMotionValue extends MotionValue {
constructor() {
super(...arguments);
this.values = [];
}
add(name) {
const styleName = getWillChangeName(name);
if (styleName) {
addUniqueItem(this.values, styleName);
this.update();
}
}
update() {
this.set(this.values.length ? this.values.join(", ") : "auto");
}
}
export { WillChangeMotionValue };

View File

@ -0,0 +1,14 @@
import { isWillChangeMotionValue } from './is.mjs';
function addValueToWillChange(visualElement, key) {
const willChange = visualElement.getValue("willChange");
/**
* It could be that a user has set willChange to a regular MotionValue,
* in which case we can't add the value to it.
*/
if (isWillChangeMotionValue(willChange)) {
return willChange.add(key);
}
}
export { addValueToWillChange };

View File

@ -0,0 +1,14 @@
import { acceleratedValues } from '../../animation/animators/utils/accelerated-values.mjs';
import { camelToDash } from '../../render/dom/utils/camel-to-dash.mjs';
import { transformProps } from '../../render/html/utils/transform.mjs';
function getWillChangeName(name) {
if (transformProps.has(name)) {
return "transform";
}
else if (acceleratedValues.has(name)) {
return camelToDash(name);
}
}
export { getWillChangeName };

View File

@ -0,0 +1,8 @@
import { useConstant } from '../../utils/use-constant.mjs';
import { WillChangeMotionValue } from './WillChangeMotionValue.mjs';
function useWillChange() {
return useConstant(() => new WillChangeMotionValue("auto"));
}
export { useWillChange };

View File

@ -0,0 +1,7 @@
import { isMotionValue } from '../utils/is-motion-value.mjs';
function isWillChangeMotionValue(value) {
return Boolean(isMotionValue(value) && value.add);
}
export { isWillChangeMotionValue };

View File

@ -0,0 +1,3 @@
const isMotionValue = (value) => Boolean(value && value.getVelocity);
export { isMotionValue };

View File

@ -0,0 +1,16 @@
import { isCustomValue } from '../../utils/resolve-value.mjs';
import { isMotionValue } from './is-motion-value.mjs';
/**
* If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself
*
* TODO: Remove and move to library
*/
function resolveMotionValue(value) {
const unwrappedValue = isMotionValue(value) ? value.get() : value;
return isCustomValue(unwrappedValue)
? unwrappedValue.toValue()
: unwrappedValue;
}
export { resolveMotionValue };