Mission Control Dashboard - Initial implementation

This commit is contained in:
Daniel Arroyo
2026-03-27 18:36:05 +00:00
parent 257cea2c7d
commit a8fb4d4555
12516 changed files with 2307128 additions and 2 deletions

15
node_modules/motion-dom/dist/es/render/Feature.mjs generated vendored Normal file
View File

@@ -0,0 +1,15 @@
/**
* Feature base class for extending VisualElement functionality.
* Features are plugins that can be mounted/unmounted to add behavior
* like gestures, animations, or layout tracking.
*/
class Feature {
constructor(node) {
this.isMounted = false;
this.node = node;
}
update() { }
}
export { Feature };
//# sourceMappingURL=Feature.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Feature.mjs","sources":["../../../src/render/Feature.ts"],"sourcesContent":["import type { VisualElement } from \"./VisualElement\"\n\n/**\n * Feature base class for extending VisualElement functionality.\n * Features are plugins that can be mounted/unmounted to add behavior\n * like gestures, animations, or layout tracking.\n */\nexport abstract class Feature<T extends any = any> {\n isMounted = false\n\n node: VisualElement<T>\n\n constructor(node: VisualElement<T>) {\n this.node = node\n }\n\n abstract mount(): void\n\n abstract unmount(): void\n\n update(): void {}\n}\n"],"names":[],"mappings":"AAEA;;;;AAIG;MACmB,OAAO,CAAA;AAKzB,IAAA,WAAA,CAAY,IAAsB,EAAA;QAJlC,IAAA,CAAA,SAAS,GAAG,KAAK;AAKb,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;IACpB;AAMA,IAAA,MAAM,KAAU;AACnB;;;;"}

View File

@@ -0,0 +1,560 @@
import { warnOnce, secondsToMilliseconds, isNumericalString, isZeroValueString, SubscriptionManager } from 'motion-utils';
import { KeyframeResolver } from '../animation/keyframes/KeyframesResolver.mjs';
import { NativeAnimation } from '../animation/NativeAnimation.mjs';
import { acceleratedValues } from '../animation/waapi/utils/accelerated-values.mjs';
import { microtask } from '../frameloop/microtask.mjs';
import { time } from '../frameloop/sync-time.mjs';
import { createBox } from '../projection/geometry/models.mjs';
import { motionValue } from '../value/index.mjs';
import { complex } from '../value/types/complex/index.mjs';
import { getAnimatableNone } from '../value/types/utils/animatable-none.mjs';
import { findValueType } from '../value/types/utils/find.mjs';
import { isMotionValue } from '../value/utils/is-motion-value.mjs';
import { visualElementStore } from './store.mjs';
import { isControllingVariants, isVariantNode } from './utils/is-controlling-variants.mjs';
import { transformProps } from './utils/keys-transform.mjs';
import { updateMotionValuesFromProps } from './utils/motion-values.mjs';
import { initPrefersReducedMotion } from './utils/reduced-motion/index.mjs';
import { resolveVariantFromProps } from './utils/resolve-variants.mjs';
import { hasReducedMotionListener, prefersReducedMotion } from './utils/reduced-motion/state.mjs';
import { frame, cancelFrame } from '../frameloop/frame.mjs';
const propEventHandlers = [
"AnimationStart",
"AnimationComplete",
"Update",
"BeforeLayoutMeasure",
"LayoutMeasure",
"LayoutAnimationStart",
"LayoutAnimationComplete",
];
/**
* Static feature definitions - can be injected by framework layer
*/
let featureDefinitions = {};
/**
* Set feature definitions for all VisualElements.
* This should be called by the framework layer (e.g., framer-motion) during initialization.
*/
function setFeatureDefinitions(definitions) {
featureDefinitions = definitions;
}
/**
* Get the current feature definitions
*/
function getFeatureDefinitions() {
return featureDefinitions;
}
/**
* A VisualElement is an imperative abstraction around UI elements such as
* HTMLElement, SVGElement, Three.Object3D etc.
*/
class VisualElement {
/**
* This method takes React props and returns found MotionValues. For example, HTML
* MotionValues will be found within the style prop, whereas for Three.js within attribute arrays.
*
* This isn't an abstract method as it needs calling in the constructor, but it is
* intended to be one.
*/
scrapeMotionValuesFromProps(_props, _prevProps, _visualElement) {
return {};
}
constructor({ parent, props, presenceContext, reducedMotionConfig, skipAnimations, blockInitialAnimation, visualState, }, options = {}) {
/**
* A reference to the current underlying Instance, e.g. a HTMLElement
* or Three.Mesh etc.
*/
this.current = null;
/**
* A set containing references to this VisualElement's children.
*/
this.children = new Set();
/**
* Determine what role this visual element should take in the variant tree.
*/
this.isVariantNode = false;
this.isControllingVariants = false;
/**
* Decides whether this VisualElement should animate in reduced motion
* mode.
*
* TODO: This is currently set on every individual VisualElement but feels
* like it could be set globally.
*/
this.shouldReduceMotion = null;
/**
* Decides whether animations should be skipped for this VisualElement.
* Useful for E2E tests and visual regression testing.
*/
this.shouldSkipAnimations = false;
/**
* A map of all motion values attached to this visual element. Motion
* values are source of truth for any given animated value. A motion
* value might be provided externally by the component via props.
*/
this.values = new Map();
this.KeyframeResolver = KeyframeResolver;
/**
* Cleanup functions for active features (hover/tap/exit etc)
*/
this.features = {};
/**
* A map of every subscription that binds the provided or generated
* motion values onChange listeners to this visual element.
*/
this.valueSubscriptions = new Map();
/**
* A reference to the previously-provided motion values as returned
* from scrapeMotionValuesFromProps. We use the keys in here to determine
* if any motion values need to be removed after props are updated.
*/
this.prevMotionValues = {};
/**
* Track whether this element has been mounted before, to detect
* remounts after Suspense unmount/remount cycles.
*/
this.hasBeenMounted = false;
/**
* An object containing a SubscriptionManager for each active event.
*/
this.events = {};
/**
* An object containing an unsubscribe function for each prop event subscription.
* For example, every "Update" event can have multiple subscribers via
* VisualElement.on(), but only one of those can be defined via the onUpdate prop.
*/
this.propEventSubscriptions = {};
this.notifyUpdate = () => this.notify("Update", this.latestValues);
this.render = () => {
if (!this.current)
return;
this.triggerBuild();
this.renderInstance(this.current, this.renderState, this.props.style, this.projection);
};
this.renderScheduledAt = 0.0;
this.scheduleRender = () => {
const now = time.now();
if (this.renderScheduledAt < now) {
this.renderScheduledAt = now;
frame.render(this.render, false, true);
}
};
const { latestValues, renderState } = visualState;
this.latestValues = latestValues;
this.baseTarget = { ...latestValues };
this.initialValues = props.initial ? { ...latestValues } : {};
this.renderState = renderState;
this.parent = parent;
this.props = props;
this.presenceContext = presenceContext;
this.depth = parent ? parent.depth + 1 : 0;
this.reducedMotionConfig = reducedMotionConfig;
this.skipAnimationsConfig = skipAnimations;
this.options = options;
this.blockInitialAnimation = Boolean(blockInitialAnimation);
this.isControllingVariants = isControllingVariants(props);
this.isVariantNode = isVariantNode(props);
if (this.isVariantNode) {
this.variantChildren = new Set();
}
this.manuallyAnimateOnMount = Boolean(parent && parent.current);
/**
* Any motion values that are provided to the element when created
* aren't yet bound to the element, as this would technically be impure.
* However, we iterate through the motion values and set them to the
* initial values for this component.
*
* TODO: This is impure and we should look at changing this to run on mount.
* Doing so will break some tests but this isn't necessarily a breaking change,
* more a reflection of the test.
*/
const { willChange, ...initialMotionValues } = this.scrapeMotionValuesFromProps(props, {}, this);
for (const key in initialMotionValues) {
const value = initialMotionValues[key];
if (latestValues[key] !== undefined && isMotionValue(value)) {
value.set(latestValues[key]);
}
}
}
mount(instance) {
/**
* If this element has been mounted before (e.g. after a Suspense
* unmount/remount), reset motion values to their initial state
* so animations replay correctly from initial → animate.
*/
if (this.hasBeenMounted) {
for (const key in this.initialValues) {
this.values.get(key)?.jump(this.initialValues[key]);
this.latestValues[key] = this.initialValues[key];
}
}
this.current = instance;
visualElementStore.set(instance, this);
if (this.projection && !this.projection.instance) {
this.projection.mount(instance);
}
if (this.parent && this.isVariantNode && !this.isControllingVariants) {
this.removeFromVariantTree = this.parent.addVariantChild(this);
}
this.values.forEach((value, key) => this.bindToMotionValue(key, value));
/**
* Determine reduced motion preference. Only initialize the matchMedia
* listener if we actually need the dynamic value (i.e., when config
* is neither "never" nor "always").
*/
if (this.reducedMotionConfig === "never") {
this.shouldReduceMotion = false;
}
else if (this.reducedMotionConfig === "always") {
this.shouldReduceMotion = true;
}
else {
if (!hasReducedMotionListener.current) {
initPrefersReducedMotion();
}
this.shouldReduceMotion = prefersReducedMotion.current;
}
if (process.env.NODE_ENV !== "production") {
warnOnce(this.shouldReduceMotion !== true, "You have Reduced Motion enabled on your device. Animations may not appear as expected.", "reduced-motion-disabled");
}
/**
* Set whether animations should be skipped based on the config.
*/
this.shouldSkipAnimations = this.skipAnimationsConfig ?? false;
this.parent?.addChild(this);
this.update(this.props, this.presenceContext);
this.hasBeenMounted = true;
}
unmount() {
this.projection && this.projection.unmount();
cancelFrame(this.notifyUpdate);
cancelFrame(this.render);
this.valueSubscriptions.forEach((remove) => remove());
this.valueSubscriptions.clear();
this.removeFromVariantTree && this.removeFromVariantTree();
this.parent?.removeChild(this);
for (const key in this.events) {
this.events[key].clear();
}
for (const key in this.features) {
const feature = this.features[key];
if (feature) {
feature.unmount();
feature.isMounted = false;
}
}
this.current = null;
}
addChild(child) {
this.children.add(child);
this.enteringChildren ?? (this.enteringChildren = new Set());
this.enteringChildren.add(child);
}
removeChild(child) {
this.children.delete(child);
this.enteringChildren && this.enteringChildren.delete(child);
}
bindToMotionValue(key, value) {
if (this.valueSubscriptions.has(key)) {
this.valueSubscriptions.get(key)();
}
if (value.accelerate &&
acceleratedValues.has(key) &&
this.current instanceof HTMLElement) {
const { factory, keyframes, times, ease, duration } = value.accelerate;
const animation = new NativeAnimation({
element: this.current,
name: key,
keyframes,
times,
ease,
duration: secondsToMilliseconds(duration),
});
const cleanup = factory(animation);
this.valueSubscriptions.set(key, () => {
cleanup();
animation.cancel();
});
return;
}
const valueIsTransform = transformProps.has(key);
if (valueIsTransform && this.onBindTransform) {
this.onBindTransform();
}
const removeOnChange = value.on("change", (latestValue) => {
this.latestValues[key] = latestValue;
this.props.onUpdate && frame.preRender(this.notifyUpdate);
if (valueIsTransform && this.projection) {
this.projection.isTransformDirty = true;
}
this.scheduleRender();
});
let removeSyncCheck;
if (typeof window !== "undefined" &&
window.MotionCheckAppearSync) {
removeSyncCheck = window.MotionCheckAppearSync(this, key, value);
}
this.valueSubscriptions.set(key, () => {
removeOnChange();
if (removeSyncCheck)
removeSyncCheck();
if (value.owner)
value.stop();
});
}
sortNodePosition(other) {
/**
* If these nodes aren't even of the same type we can't compare their depth.
*/
if (!this.current ||
!this.sortInstanceNodePosition ||
this.type !== other.type) {
return 0;
}
return this.sortInstanceNodePosition(this.current, other.current);
}
updateFeatures() {
let key = "animation";
for (key in featureDefinitions) {
const featureDefinition = featureDefinitions[key];
if (!featureDefinition)
continue;
const { isEnabled, Feature: FeatureConstructor } = featureDefinition;
/**
* If this feature is enabled but not active, make a new instance.
*/
if (!this.features[key] &&
FeatureConstructor &&
isEnabled(this.props)) {
this.features[key] = new FeatureConstructor(this);
}
/**
* If we have a feature, mount or update it.
*/
if (this.features[key]) {
const feature = this.features[key];
if (feature.isMounted) {
feature.update();
}
else {
feature.mount();
feature.isMounted = true;
}
}
}
}
triggerBuild() {
this.build(this.renderState, this.latestValues, this.props);
}
/**
* Measure the current viewport box with or without transforms.
* Only measures axis-aligned boxes, rotate and skew must be manually
* removed with a re-render to work.
*/
measureViewportBox() {
return this.current
? this.measureInstanceViewportBox(this.current, this.props)
: createBox();
}
getStaticValue(key) {
return this.latestValues[key];
}
setStaticValue(key, value) {
this.latestValues[key] = value;
}
/**
* Update the provided props. Ensure any newly-added motion values are
* added to our map, old ones removed, and listeners updated.
*/
update(props, presenceContext) {
if (props.transformTemplate || this.props.transformTemplate) {
this.scheduleRender();
}
this.prevProps = this.props;
this.props = props;
this.prevPresenceContext = this.presenceContext;
this.presenceContext = presenceContext;
/**
* Update prop event handlers ie onAnimationStart, onAnimationComplete
*/
for (let i = 0; i < propEventHandlers.length; i++) {
const key = propEventHandlers[i];
if (this.propEventSubscriptions[key]) {
this.propEventSubscriptions[key]();
delete this.propEventSubscriptions[key];
}
const listenerName = ("on" + key);
const listener = props[listenerName];
if (listener) {
this.propEventSubscriptions[key] = this.on(key, listener);
}
}
this.prevMotionValues = updateMotionValuesFromProps(this, this.scrapeMotionValuesFromProps(props, this.prevProps || {}, this), this.prevMotionValues);
if (this.handleChildMotionValue) {
this.handleChildMotionValue();
}
}
getProps() {
return this.props;
}
/**
* Returns the variant definition with a given name.
*/
getVariant(name) {
return this.props.variants ? this.props.variants[name] : undefined;
}
/**
* Returns the defined default transition on this component.
*/
getDefaultTransition() {
return this.props.transition;
}
getTransformPagePoint() {
return this.props.transformPagePoint;
}
getClosestVariantNode() {
return this.isVariantNode
? this
: this.parent
? this.parent.getClosestVariantNode()
: undefined;
}
/**
* Add a child visual element to our set of children.
*/
addVariantChild(child) {
const closestVariantNode = this.getClosestVariantNode();
if (closestVariantNode) {
closestVariantNode.variantChildren &&
closestVariantNode.variantChildren.add(child);
return () => closestVariantNode.variantChildren.delete(child);
}
}
/**
* Add a motion value and bind it to this visual element.
*/
addValue(key, value) {
// Remove existing value if it exists
const existingValue = this.values.get(key);
if (value !== existingValue) {
if (existingValue)
this.removeValue(key);
this.bindToMotionValue(key, value);
this.values.set(key, value);
this.latestValues[key] = value.get();
}
}
/**
* Remove a motion value and unbind any active subscriptions.
*/
removeValue(key) {
this.values.delete(key);
const unsubscribe = this.valueSubscriptions.get(key);
if (unsubscribe) {
unsubscribe();
this.valueSubscriptions.delete(key);
}
delete this.latestValues[key];
this.removeValueFromRenderState(key, this.renderState);
}
/**
* Check whether we have a motion value for this key
*/
hasValue(key) {
return this.values.has(key);
}
getValue(key, defaultValue) {
if (this.props.values && this.props.values[key]) {
return this.props.values[key];
}
let value = this.values.get(key);
if (value === undefined && defaultValue !== undefined) {
value = motionValue(defaultValue === null ? undefined : defaultValue, { owner: this });
this.addValue(key, value);
}
return value;
}
/**
* If we're trying to animate to a previously unencountered value,
* we need to check for it in our state and as a last resort read it
* directly from the instance (which might have performance implications).
*/
readValue(key, target) {
let value = this.latestValues[key] !== undefined || !this.current
? this.latestValues[key]
: this.getBaseTargetFromProps(this.props, key) ??
this.readValueFromInstance(this.current, key, this.options);
if (value !== undefined && value !== null) {
if (typeof value === "string" &&
(isNumericalString(value) || isZeroValueString(value))) {
// If this is a number read as a string, ie "0" or "200", convert it to a number
value = parseFloat(value);
}
else if (!findValueType(value) && complex.test(target)) {
value = getAnimatableNone(key, target);
}
this.setBaseTarget(key, isMotionValue(value) ? value.get() : value);
}
return isMotionValue(value) ? value.get() : value;
}
/**
* Set the base target to later animate back to. This is currently
* only hydrated on creation and when we first read a value.
*/
setBaseTarget(key, value) {
this.baseTarget[key] = value;
}
/**
* Find the base target for a value thats been removed from all animation
* props.
*/
getBaseTarget(key) {
const { initial } = this.props;
let valueFromInitial;
if (typeof initial === "string" || typeof initial === "object") {
const variant = resolveVariantFromProps(this.props, initial, this.presenceContext?.custom);
if (variant) {
valueFromInitial = variant[key];
}
}
/**
* If this value still exists in the current initial variant, read that.
*/
if (initial && valueFromInitial !== undefined) {
return valueFromInitial;
}
/**
* Alternatively, if this VisualElement config has defined a getBaseTarget
* so we can read the value from an alternative source, try that.
*/
const target = this.getBaseTargetFromProps(this.props, key);
if (target !== undefined && !isMotionValue(target))
return target;
/**
* If the value was initially defined on initial, but it doesn't any more,
* return undefined. Otherwise return the value as initially read from the DOM.
*/
return this.initialValues[key] !== undefined &&
valueFromInitial === undefined
? undefined
: this.baseTarget[key];
}
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = new SubscriptionManager();
}
return this.events[eventName].add(callback);
}
notify(eventName, ...args) {
if (this.events[eventName]) {
this.events[eventName].notify(...args);
}
}
scheduleRenderMicrotask() {
microtask.render(this.render);
}
}
export { VisualElement, getFeatureDefinitions, setFeatureDefinitions };
//# sourceMappingURL=VisualElement.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,43 @@
import { isMotionValue } from '../../value/utils/is-motion-value.mjs';
import { DOMKeyframesResolver } from '../../animation/keyframes/DOMKeyframesResolver.mjs';
import { VisualElement } from '../VisualElement.mjs';
class DOMVisualElement extends VisualElement {
constructor() {
super(...arguments);
this.KeyframeResolver = DOMKeyframesResolver;
}
sortInstanceNodePosition(a, b) {
/**
* compareDocumentPosition returns a bitmask, by using the bitwise &
* we're returning true if 2 in that bitmask is set to true. 2 is set
* to true if b preceeds a.
*/
return a.compareDocumentPosition(b) & 2 ? 1 : -1;
}
getBaseTargetFromProps(props, key) {
const style = props.style;
return style ? style[key] : undefined;
}
removeValueFromRenderState(key, { vars, style }) {
delete vars[key];
delete style[key];
}
handleChildMotionValue() {
if (this.childSubscription) {
this.childSubscription();
delete this.childSubscription;
}
const { children } = this.props;
if (isMotionValue(children)) {
this.childSubscription = children.on("change", (latest) => {
if (this.current) {
this.current.textContent = `${latest}`;
}
});
}
}
}
export { DOMVisualElement };
//# sourceMappingURL=DOMVisualElement.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DOMVisualElement.mjs","sources":["../../../../src/render/dom/DOMVisualElement.ts"],"sourcesContent":["import { isMotionValue } from \"../../value/utils/is-motion-value\"\nimport type { MotionValue } from \"../../value\"\nimport type { AnyResolvedKeyframe } from \"../../animation/types\"\nimport { DOMKeyframesResolver } from \"../../animation/keyframes/DOMKeyframesResolver\"\nimport type { MotionNodeOptions } from \"../../node/types\"\nimport type { DOMVisualElementOptions } from \"./types\"\nimport type { HTMLRenderState } from \"../html/types\"\nimport { VisualElement, MotionStyle } from \"../VisualElement\"\n\nexport abstract class DOMVisualElement<\n Instance extends HTMLElement | SVGElement = HTMLElement,\n State extends HTMLRenderState = HTMLRenderState,\n Options extends DOMVisualElementOptions = DOMVisualElementOptions\n> extends VisualElement<Instance, State, Options> {\n sortInstanceNodePosition(a: Instance, b: Instance): number {\n /**\n * compareDocumentPosition returns a bitmask, by using the bitwise &\n * we're returning true if 2 in that bitmask is set to true. 2 is set\n * to true if b preceeds a.\n */\n return a.compareDocumentPosition(b) & 2 ? 1 : -1\n }\n\n getBaseTargetFromProps(\n props: MotionNodeOptions,\n key: string\n ): AnyResolvedKeyframe | MotionValue<any> | undefined {\n const style = (props as MotionNodeOptions & { style?: MotionStyle }).style\n return style ? (style[key] as string) : undefined\n }\n\n removeValueFromRenderState(\n key: string,\n { vars, style }: HTMLRenderState\n ): void {\n delete vars[key]\n delete style[key]\n }\n\n KeyframeResolver = DOMKeyframesResolver\n\n childSubscription?: VoidFunction\n handleChildMotionValue() {\n if (this.childSubscription) {\n this.childSubscription()\n delete this.childSubscription\n }\n\n const { children } = this.props as MotionNodeOptions & { children?: MotionValue | any }\n if (isMotionValue(children)) {\n this.childSubscription = children.on(\"change\", (latest) => {\n if (this.current) {\n this.current.textContent = `${latest}`\n }\n })\n }\n }\n}\n"],"names":[],"mappings":";;;;AASM,MAAgB,gBAIpB,SAAQ,aAAuC,CAAA;AAJjD,IAAA,WAAA,GAAA;;QA8BI,IAAA,CAAA,gBAAgB,GAAG,oBAAoB;IAkB3C;IA3CI,wBAAwB,CAAC,CAAW,EAAE,CAAW,EAAA;AAC7C;;;;AAIG;AACH,QAAA,OAAO,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE;IACpD;IAEA,sBAAsB,CAClB,KAAwB,EACxB,GAAW,EAAA;AAEX,QAAA,MAAM,KAAK,GAAI,KAAqD,CAAC,KAAK;AAC1E,QAAA,OAAO,KAAK,GAAI,KAAK,CAAC,GAAG,CAAY,GAAG,SAAS;IACrD;AAEA,IAAA,0BAA0B,CACtB,GAAW,EACX,EAAE,IAAI,EAAE,KAAK,EAAmB,EAAA;AAEhC,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC;AAChB,QAAA,OAAO,KAAK,CAAC,GAAG,CAAC;IACrB;IAKA,sBAAsB,GAAA;AAClB,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE;YACxB,IAAI,CAAC,iBAAiB,EAAE;YACxB,OAAO,IAAI,CAAC,iBAAiB;QACjC;AAEA,QAAA,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,KAA6D;AACvF,QAAA,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE;AACzB,YAAA,IAAI,CAAC,iBAAiB,GAAG,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,KAAI;AACtD,gBAAA,IAAI,IAAI,CAAC,OAAO,EAAE;oBACd,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,CAAA,EAAG,MAAM,EAAE;gBAC1C;AACJ,YAAA,CAAC,CAAC;QACN;IACJ;AACH;;;;"}

View File

@@ -0,0 +1,4 @@
const isCSSVar = (name) => name.startsWith("--");
export { isCSSVar };
//# sourceMappingURL=is-css-var.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-css-var.mjs","sources":["../../../../src/render/dom/is-css-var.ts"],"sourcesContent":["export const isCSSVar = (name: string) => name.startsWith(\"--\")\n"],"names":[],"mappings":"AAAO,MAAM,QAAQ,GAAG,CAAC,IAAY,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI;;;;"}

View File

@@ -0,0 +1,84 @@
const radToDeg = (rad) => (rad * 180) / Math.PI;
const rotate = (v) => {
const angle = radToDeg(Math.atan2(v[1], v[0]));
return rebaseAngle(angle);
};
const matrix2dParsers = {
x: 4,
y: 5,
translateX: 4,
translateY: 5,
scaleX: 0,
scaleY: 3,
scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
rotate,
rotateZ: rotate,
skewX: (v) => radToDeg(Math.atan(v[1])),
skewY: (v) => radToDeg(Math.atan(v[2])),
skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2,
};
const rebaseAngle = (angle) => {
angle = angle % 360;
if (angle < 0)
angle += 360;
return angle;
};
const rotateZ = rotate;
const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
const matrix3dParsers = {
x: 12,
y: 13,
z: 14,
translateX: 12,
translateY: 13,
translateZ: 14,
scaleX,
scaleY,
scale: (v) => (scaleX(v) + scaleY(v)) / 2,
rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
rotateZ,
rotate: rotateZ,
skewX: (v) => radToDeg(Math.atan(v[4])),
skewY: (v) => radToDeg(Math.atan(v[1])),
skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2,
};
function defaultTransformValue(name) {
return name.includes("scale") ? 1 : 0;
}
function parseValueFromTransform(transform, name) {
if (!transform || transform === "none") {
return defaultTransformValue(name);
}
const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u);
let parsers;
let match;
if (matrix3dMatch) {
parsers = matrix3dParsers;
match = matrix3dMatch;
}
else {
const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u);
parsers = matrix2dParsers;
match = matrix2dMatch;
}
if (!match) {
return defaultTransformValue(name);
}
const valueParser = parsers[name];
const values = match[1].split(",").map(convertTransformToNumber);
return typeof valueParser === "function"
? valueParser(values)
: values[valueParser];
}
const readTransformValue = (instance, name) => {
const { transform = "none" } = getComputedStyle(instance);
return parseValueFromTransform(transform, name);
};
function convertTransformToNumber(value) {
return parseFloat(value.trim());
}
export { defaultTransformValue, parseValueFromTransform, readTransformValue };
//# sourceMappingURL=parse-transform.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
import { isCSSVar } from './is-css-var.mjs';
function getComputedStyle(element, name) {
const computedStyle = window.getComputedStyle(element);
return isCSSVar(name)
? computedStyle.getPropertyValue(name)
: computedStyle[name];
}
export { getComputedStyle };
//# sourceMappingURL=style-computed.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"style-computed.mjs","sources":["../../../../src/render/dom/style-computed.ts"],"sourcesContent":["import { isCSSVar } from \"./is-css-var\"\n\nexport function getComputedStyle(\n element: HTMLElement | SVGElement,\n name: string\n) {\n const computedStyle = window.getComputedStyle(element)\n return isCSSVar(name)\n ? computedStyle.getPropertyValue(name)\n : computedStyle[name as any]\n}\n"],"names":[],"mappings":";;AAEM,SAAU,gBAAgB,CAC5B,OAAiC,EACjC,IAAY,EAAA;IAEZ,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC;IACtD,OAAO,QAAQ,CAAC,IAAI;AAChB,UAAE,aAAa,CAAC,gBAAgB,CAAC,IAAI;AACrC,UAAE,aAAa,CAAC,IAAW,CAAC;AACpC;;;;"}

View File

@@ -0,0 +1,10 @@
import { isCSSVar } from './is-css-var.mjs';
function setStyle(element, name, value) {
isCSSVar(name)
? element.style.setProperty(name, value)
: (element.style[name] = value);
}
export { setStyle };
//# sourceMappingURL=style-set.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"style-set.mjs","sources":["../../../../src/render/dom/style-set.ts"],"sourcesContent":["import { AnyResolvedKeyframe } from \"../../animation/types\"\nimport { isCSSVar } from \"./is-css-var\"\n\nexport function setStyle(\n element: HTMLElement | SVGElement,\n name: string,\n value: AnyResolvedKeyframe\n) {\n isCSSVar(name)\n ? element.style.setProperty(name, value as string)\n : (element.style[name as any] = value as string)\n}\n"],"names":[],"mappings":";;SAGgB,QAAQ,CACpB,OAAiC,EACjC,IAAY,EACZ,KAA0B,EAAA;IAE1B,QAAQ,CAAC,IAAI;UACP,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,KAAe;WAC9C,OAAO,CAAC,KAAK,CAAC,IAAW,CAAC,GAAG,KAAe,CAAC;AACxD;;;;"}

View File

@@ -0,0 +1,6 @@
function camelToDash(str) {
return str.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);
}
export { camelToDash };
//# sourceMappingURL=camel-to-dash.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"camel-to-dash.mjs","sources":["../../../../../src/render/dom/utils/camel-to-dash.ts"],"sourcesContent":["export function camelToDash(str: string): string {\n return str.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`)\n}\n"],"names":[],"mappings":"AAAM,SAAU,WAAW,CAAC,GAAW,EAAA;AACnC,IAAA,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,KAAK,IAAI,KAAK,CAAC,WAAW,EAAE,CAAA,CAAE,CAAC;AACxE;;;;"}

View File

@@ -0,0 +1,45 @@
import { isCSSVariableName } from '../../animation/utils/is-css-variable.mjs';
import { transformProps } from '../utils/keys-transform.mjs';
import { defaultTransformValue, readTransformValue } from '../dom/parse-transform.mjs';
import { measureViewportBox } from '../../projection/utils/measure.mjs';
import { DOMVisualElement } from '../dom/DOMVisualElement.mjs';
import { buildHTMLStyles } from './utils/build-styles.mjs';
import { renderHTML } from './utils/render.mjs';
import { scrapeMotionValuesFromProps } from './utils/scrape-motion-values.mjs';
function getComputedStyle(element) {
return window.getComputedStyle(element);
}
class HTMLVisualElement extends DOMVisualElement {
constructor() {
super(...arguments);
this.type = "html";
this.renderInstance = renderHTML;
}
readValueFromInstance(instance, key) {
if (transformProps.has(key)) {
return this.projection?.isProjecting
? defaultTransformValue(key)
: readTransformValue(instance, key);
}
else {
const computedStyle = getComputedStyle(instance);
const value = (isCSSVariableName(key)
? computedStyle.getPropertyValue(key)
: computedStyle[key]) || 0;
return typeof value === "string" ? value.trim() : value;
}
}
measureInstanceViewportBox(instance, { transformPagePoint }) {
return measureViewportBox(instance, transformPagePoint);
}
build(renderState, latestValues, props) {
buildHTMLStyles(renderState, latestValues, props.transformTemplate);
}
scrapeMotionValuesFromProps(props, prevProps, visualElement) {
return scrapeMotionValuesFromProps(props, prevProps, visualElement);
}
}
export { HTMLVisualElement, getComputedStyle };
//# sourceMappingURL=HTMLVisualElement.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTMLVisualElement.mjs","sources":["../../../../src/render/html/HTMLVisualElement.ts"],"sourcesContent":["import type { Box } from \"motion-utils\"\nimport type { AnyResolvedKeyframe } from \"../../animation/types\"\nimport { isCSSVariableName } from \"../../animation/utils/is-css-variable\"\nimport type { MotionNodeOptions } from \"../../node/types\"\nimport { transformProps } from \"../utils/keys-transform\"\nimport {\n defaultTransformValue,\n readTransformValue,\n} from \"../dom/parse-transform\"\nimport { measureViewportBox } from \"../../projection/utils/measure\"\nimport { DOMVisualElement } from \"../dom/DOMVisualElement\"\nimport type { DOMVisualElementOptions } from \"../dom/types\"\nimport type { ResolvedValues, MotionConfigContextProps } from \"../types\"\nimport type { VisualElement } from \"../VisualElement\"\nimport { HTMLRenderState } from \"./types\"\nimport { buildHTMLStyles } from \"./utils/build-styles\"\nimport { renderHTML } from \"./utils/render\"\nimport { scrapeMotionValuesFromProps } from \"./utils/scrape-motion-values\"\n\nexport function getComputedStyle(element: HTMLElement) {\n return window.getComputedStyle(element)\n}\n\nexport class HTMLVisualElement extends DOMVisualElement<\n HTMLElement,\n HTMLRenderState,\n DOMVisualElementOptions\n> {\n type = \"html\"\n\n readValueFromInstance(\n instance: HTMLElement,\n key: string\n ): AnyResolvedKeyframe | null | undefined {\n if (transformProps.has(key)) {\n return this.projection?.isProjecting\n ? defaultTransformValue(key)\n : readTransformValue(instance, key)\n } else {\n const computedStyle = getComputedStyle(instance)\n const value =\n (isCSSVariableName(key)\n ? computedStyle.getPropertyValue(key)\n : computedStyle[key as keyof typeof computedStyle]) || 0\n\n return typeof value === \"string\" ? value.trim() : (value as number)\n }\n }\n\n measureInstanceViewportBox(\n instance: HTMLElement,\n { transformPagePoint }: MotionNodeOptions & Partial<MotionConfigContextProps>\n ): Box {\n return measureViewportBox(instance, transformPagePoint)\n }\n\n build(\n renderState: HTMLRenderState,\n latestValues: ResolvedValues,\n props: MotionNodeOptions\n ) {\n buildHTMLStyles(renderState, latestValues, props.transformTemplate)\n }\n\n scrapeMotionValuesFromProps(\n props: MotionNodeOptions,\n prevProps: MotionNodeOptions,\n visualElement: VisualElement\n ) {\n return scrapeMotionValuesFromProps(props, prevProps, visualElement)\n }\n\n renderInstance = renderHTML\n}\n"],"names":[],"mappings":";;;;;;;;;AAmBM,SAAU,gBAAgB,CAAC,OAAoB,EAAA;AACjD,IAAA,OAAO,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC;AAC3C;AAEM,MAAO,iBAAkB,SAAQ,gBAItC,CAAA;AAJD,IAAA,WAAA,GAAA;;QAKI,IAAA,CAAA,IAAI,GAAG,MAAM;QA4Cb,IAAA,CAAA,cAAc,GAAG,UAAU;IAC/B;IA3CI,qBAAqB,CACjB,QAAqB,EACrB,GAAW,EAAA;AAEX,QAAA,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACzB,YAAA,OAAO,IAAI,CAAC,UAAU,EAAE;AACpB,kBAAE,qBAAqB,CAAC,GAAG;AAC3B,kBAAE,kBAAkB,CAAC,QAAQ,EAAE,GAAG,CAAC;QAC3C;aAAO;AACH,YAAA,MAAM,aAAa,GAAG,gBAAgB,CAAC,QAAQ,CAAC;AAChD,YAAA,MAAM,KAAK,GACP,CAAC,iBAAiB,CAAC,GAAG;AAClB,kBAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG;kBAClC,aAAa,CAAC,GAAiC,CAAC,KAAK,CAAC;AAEhE,YAAA,OAAO,OAAO,KAAK,KAAK,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,GAAI,KAAgB;QACvE;IACJ;AAEA,IAAA,0BAA0B,CACtB,QAAqB,EACrB,EAAE,kBAAkB,EAAyD,EAAA;AAE7E,QAAA,OAAO,kBAAkB,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IAC3D;AAEA,IAAA,KAAK,CACD,WAA4B,EAC5B,YAA4B,EAC5B,KAAwB,EAAA;QAExB,eAAe,CAAC,WAAW,EAAE,YAAY,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACvE;AAEA,IAAA,2BAA2B,CACvB,KAAwB,EACxB,SAA4B,EAC5B,aAA4B,EAAA;QAE5B,OAAO,2BAA2B,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC;IACvE;AAGH;;;;"}

View File

@@ -0,0 +1,66 @@
import { getValueAsType } from '../../../value/types/utils/get-as-type.mjs';
import { numberValueTypes } from '../../../value/types/maps/number.mjs';
import { transformProps } from '../../utils/keys-transform.mjs';
import { isCSSVariableName } from '../../../animation/utils/is-css-variable.mjs';
import { buildTransform } from './build-transform.mjs';
function buildHTMLStyles(state, latestValues, transformTemplate) {
const { style, vars, transformOrigin } = state;
// Track whether we encounter any transform or transformOrigin values.
let hasTransform = false;
let hasTransformOrigin = false;
/**
* Loop over all our latest animated values and decide whether to handle them
* as a style or CSS variable.
*
* Transforms and transform origins are kept separately for further processing.
*/
for (const key in latestValues) {
const value = latestValues[key];
if (transformProps.has(key)) {
// If this is a transform, flag to enable further transform processing
hasTransform = true;
continue;
}
else if (isCSSVariableName(key)) {
vars[key] = value;
continue;
}
else {
// Convert the value to its default value type, ie 0 -> "0px"
const valueAsType = getValueAsType(value, numberValueTypes[key]);
if (key.startsWith("origin")) {
// If this is a transform origin, flag and enable further transform-origin processing
hasTransformOrigin = true;
transformOrigin[key] =
valueAsType;
}
else {
style[key] = valueAsType;
}
}
}
if (!latestValues.transform) {
if (hasTransform || transformTemplate) {
style.transform = buildTransform(latestValues, state.transform, transformTemplate);
}
else if (style.transform) {
/**
* If we have previously created a transform but currently don't have any,
* reset transform style to none.
*/
style.transform = "none";
}
}
/**
* Build a transformOrigin style. Uses the same defaults as the browser for
* undefined origins.
*/
if (hasTransformOrigin) {
const { originX = "50%", originY = "50%", originZ = 0, } = transformOrigin;
style.transformOrigin = `${originX} ${originY} ${originZ}`;
}
}
export { buildHTMLStyles };
//# sourceMappingURL=build-styles.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"build-styles.mjs","sources":["../../../../../src/render/html/utils/build-styles.ts"],"sourcesContent":["import { getValueAsType } from \"../../../value/types/utils/get-as-type\"\nimport { numberValueTypes } from \"../../../value/types/maps/number\"\nimport { transformProps } from \"../../utils/keys-transform\"\nimport { isCSSVariableName } from \"../../../animation/utils/is-css-variable\"\nimport { ResolvedValues } from \"../../types\"\nimport { HTMLRenderState } from \"../types\"\nimport { buildTransform } from \"./build-transform\"\nimport type { MotionNodeOptions } from \"../../../node/types\"\n\nexport function buildHTMLStyles(\n state: HTMLRenderState,\n latestValues: ResolvedValues,\n transformTemplate?: MotionNodeOptions[\"transformTemplate\"]\n) {\n const { style, vars, transformOrigin } = state\n\n // Track whether we encounter any transform or transformOrigin values.\n let hasTransform = false\n let hasTransformOrigin = false\n\n /**\n * Loop over all our latest animated values and decide whether to handle them\n * as a style or CSS variable.\n *\n * Transforms and transform origins are kept separately for further processing.\n */\n for (const key in latestValues) {\n const value = latestValues[key]\n\n if (transformProps.has(key)) {\n // If this is a transform, flag to enable further transform processing\n hasTransform = true\n continue\n } else if (isCSSVariableName(key)) {\n vars[key] = value\n continue\n } else {\n // Convert the value to its default value type, ie 0 -> \"0px\"\n const valueAsType = getValueAsType(value, numberValueTypes[key])\n\n if (key.startsWith(\"origin\")) {\n // If this is a transform origin, flag and enable further transform-origin processing\n hasTransformOrigin = true\n transformOrigin[key as keyof typeof transformOrigin] =\n valueAsType\n } else {\n style[key] = valueAsType\n }\n }\n }\n\n if (!latestValues.transform) {\n if (hasTransform || transformTemplate) {\n style.transform = buildTransform(\n latestValues,\n state.transform,\n transformTemplate\n )\n } else if (style.transform) {\n /**\n * If we have previously created a transform but currently don't have any,\n * reset transform style to none.\n */\n style.transform = \"none\"\n }\n }\n\n /**\n * Build a transformOrigin style. Uses the same defaults as the browser for\n * undefined origins.\n */\n if (hasTransformOrigin) {\n const {\n originX = \"50%\",\n originY = \"50%\",\n originZ = 0,\n } = transformOrigin\n style.transformOrigin = `${originX} ${originY} ${originZ}`\n }\n}\n"],"names":[],"mappings":";;;;;;SASgB,eAAe,CAC3B,KAAsB,EACtB,YAA4B,EAC5B,iBAA0D,EAAA;IAE1D,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,KAAK;;IAG9C,IAAI,YAAY,GAAG,KAAK;IACxB,IAAI,kBAAkB,GAAG,KAAK;AAE9B;;;;;AAKG;AACH,IAAA,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE;AAC5B,QAAA,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC;AAE/B,QAAA,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;;YAEzB,YAAY,GAAG,IAAI;YACnB;QACJ;AAAO,aAAA,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE;AAC/B,YAAA,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK;YACjB;QACJ;aAAO;;YAEH,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;AAEhE,YAAA,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;;gBAE1B,kBAAkB,GAAG,IAAI;gBACzB,eAAe,CAAC,GAAmC,CAAC;AAChD,oBAAA,WAAW;YACnB;iBAAO;AACH,gBAAA,KAAK,CAAC,GAAG,CAAC,GAAG,WAAW;YAC5B;QACJ;IACJ;AAEA,IAAA,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE;AACzB,QAAA,IAAI,YAAY,IAAI,iBAAiB,EAAE;AACnC,YAAA,KAAK,CAAC,SAAS,GAAG,cAAc,CAC5B,YAAY,EACZ,KAAK,CAAC,SAAS,EACf,iBAAiB,CACpB;QACL;AAAO,aAAA,IAAI,KAAK,CAAC,SAAS,EAAE;AACxB;;;AAGG;AACH,YAAA,KAAK,CAAC,SAAS,GAAG,MAAM;QAC5B;IACJ;AAEA;;;AAGG;IACH,IAAI,kBAAkB,EAAE;AACpB,QAAA,MAAM,EACF,OAAO,GAAG,KAAK,EACf,OAAO,GAAG,KAAK,EACf,OAAO,GAAG,CAAC,GACd,GAAG,eAAe;QACnB,KAAK,CAAC,eAAe,GAAG,CAAA,EAAG,OAAO,IAAI,OAAO,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE;IAC9D;AACJ;;;;"}

View File

@@ -0,0 +1,64 @@
import { getValueAsType } from '../../../value/types/utils/get-as-type.mjs';
import { numberValueTypes } from '../../../value/types/maps/number.mjs';
import { transformPropOrder } from '../../utils/keys-transform.mjs';
const translateAlias = {
x: "translateX",
y: "translateY",
z: "translateZ",
transformPerspective: "perspective",
};
const numTransforms = transformPropOrder.length;
/**
* Build a CSS transform style from individual x/y/scale etc properties.
*
* This outputs with a default order of transforms/scales/rotations, this can be customised by
* providing a transformTemplate function.
*/
function buildTransform(latestValues, transform, transformTemplate) {
// The transform string we're going to build into.
let transformString = "";
let transformIsDefault = true;
/**
* Loop over all possible transforms in order, adding the ones that
* are present to the transform string.
*/
for (let i = 0; i < numTransforms; i++) {
const key = transformPropOrder[i];
const value = latestValues[key];
if (value === undefined)
continue;
let valueIsDefault = true;
if (typeof value === "number") {
valueIsDefault = value === (key.startsWith("scale") ? 1 : 0);
}
else {
const parsed = parseFloat(value);
valueIsDefault = key.startsWith("scale") ? parsed === 1 : parsed === 0;
}
if (!valueIsDefault || transformTemplate) {
const valueAsType = getValueAsType(value, numberValueTypes[key]);
if (!valueIsDefault) {
transformIsDefault = false;
const transformName = translateAlias[key] || key;
transformString += `${transformName}(${valueAsType}) `;
}
if (transformTemplate) {
transform[key] = valueAsType;
}
}
}
transformString = transformString.trim();
// If we have a custom `transform` template, pass our transform values and
// generated transformString to that before returning
if (transformTemplate) {
transformString = transformTemplate(transform, transformIsDefault ? "" : transformString);
}
else if (transformIsDefault) {
transformString = "none";
}
return transformString;
}
export { buildTransform };
//# sourceMappingURL=build-transform.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"build-transform.mjs","sources":["../../../../../src/render/html/utils/build-transform.ts"],"sourcesContent":["import { getValueAsType } from \"../../../value/types/utils/get-as-type\"\nimport { numberValueTypes } from \"../../../value/types/maps/number\"\nimport { transformPropOrder } from \"../../utils/keys-transform\"\nimport { ResolvedValues } from \"../../types\"\nimport { HTMLRenderState } from \"../types\"\nimport type { MotionNodeOptions } from \"../../../node/types\"\n\nconst translateAlias = {\n x: \"translateX\",\n y: \"translateY\",\n z: \"translateZ\",\n transformPerspective: \"perspective\",\n}\n\nconst numTransforms = transformPropOrder.length\n\n/**\n * Build a CSS transform style from individual x/y/scale etc properties.\n *\n * This outputs with a default order of transforms/scales/rotations, this can be customised by\n * providing a transformTemplate function.\n */\nexport function buildTransform(\n latestValues: ResolvedValues,\n transform: HTMLRenderState[\"transform\"],\n transformTemplate?: MotionNodeOptions[\"transformTemplate\"]\n) {\n // The transform string we're going to build into.\n let transformString = \"\"\n let transformIsDefault = true\n\n /**\n * Loop over all possible transforms in order, adding the ones that\n * are present to the transform string.\n */\n for (let i = 0; i < numTransforms; i++) {\n const key = transformPropOrder[i] as keyof typeof translateAlias\n const value = latestValues[key]\n\n if (value === undefined) continue\n\n let valueIsDefault = true\n if (typeof value === \"number\") {\n valueIsDefault = value === (key.startsWith(\"scale\") ? 1 : 0)\n } else {\n const parsed = parseFloat(value)\n valueIsDefault = key.startsWith(\"scale\") ? parsed === 1 : parsed === 0\n }\n\n if (!valueIsDefault || transformTemplate) {\n const valueAsType = getValueAsType(value, numberValueTypes[key])\n\n if (!valueIsDefault) {\n transformIsDefault = false\n const transformName = translateAlias[key] || key\n transformString += `${transformName}(${valueAsType}) `\n }\n\n if (transformTemplate) {\n transform[key] = valueAsType\n }\n }\n }\n\n transformString = transformString.trim()\n\n // If we have a custom `transform` template, pass our transform values and\n // generated transformString to that before returning\n if (transformTemplate) {\n transformString = transformTemplate(\n transform,\n transformIsDefault ? \"\" : transformString\n )\n } else if (transformIsDefault) {\n transformString = \"none\"\n }\n\n return transformString\n}\n"],"names":[],"mappings":";;;;AAOA,MAAM,cAAc,GAAG;AACnB,IAAA,CAAC,EAAE,YAAY;AACf,IAAA,CAAC,EAAE,YAAY;AACf,IAAA,CAAC,EAAE,YAAY;AACf,IAAA,oBAAoB,EAAE,aAAa;CACtC;AAED,MAAM,aAAa,GAAG,kBAAkB,CAAC,MAAM;AAE/C;;;;;AAKG;SACa,cAAc,CAC1B,YAA4B,EAC5B,SAAuC,EACvC,iBAA0D,EAAA;;IAG1D,IAAI,eAAe,GAAG,EAAE;IACxB,IAAI,kBAAkB,GAAG,IAAI;AAE7B;;;AAGG;AACH,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE;AACpC,QAAA,MAAM,GAAG,GAAG,kBAAkB,CAAC,CAAC,CAAgC;AAChE,QAAA,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC;QAE/B,IAAI,KAAK,KAAK,SAAS;YAAE;QAEzB,IAAI,cAAc,GAAG,IAAI;AACzB,QAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC3B,YAAA,cAAc,GAAG,KAAK,MAAM,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChE;aAAO;AACH,YAAA,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC;AAChC,YAAA,cAAc,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC;QAC1E;AAEA,QAAA,IAAI,CAAC,cAAc,IAAI,iBAAiB,EAAE;YACtC,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;YAEhE,IAAI,CAAC,cAAc,EAAE;gBACjB,kBAAkB,GAAG,KAAK;gBAC1B,MAAM,aAAa,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,GAAG;AAChD,gBAAA,eAAe,IAAI,CAAA,EAAG,aAAa,CAAA,CAAA,EAAI,WAAW,IAAI;YAC1D;YAEA,IAAI,iBAAiB,EAAE;AACnB,gBAAA,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW;YAChC;QACJ;IACJ;AAEA,IAAA,eAAe,GAAG,eAAe,CAAC,IAAI,EAAE;;;IAIxC,IAAI,iBAAiB,EAAE;AACnB,QAAA,eAAe,GAAG,iBAAiB,CAC/B,SAAS,EACT,kBAAkB,GAAG,EAAE,GAAG,eAAe,CAC5C;IACL;SAAO,IAAI,kBAAkB,EAAE;QAC3B,eAAe,GAAG,MAAM;IAC5B;AAEA,IAAA,OAAO,eAAe;AAC1B;;;;"}

View File

@@ -0,0 +1,18 @@
function renderHTML(element, { style, vars }, styleProp, projection) {
const elementStyle = element.style;
let key;
for (key in style) {
// CSSStyleDeclaration has [index: number]: string; in the types, so we use that as key type.
elementStyle[key] = style[key];
}
// Write projection styles directly to element style
projection?.applyProjectionStyles(elementStyle, styleProp);
for (key in vars) {
// Loop over any CSS variables and assign those.
// They can only be assigned using `setProperty`.
elementStyle.setProperty(key, vars[key]);
}
}
export { renderHTML };
//# sourceMappingURL=render.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"render.mjs","sources":["../../../../../src/render/html/utils/render.ts"],"sourcesContent":["import type { MotionStyle } from \"../../VisualElement\"\nimport { HTMLRenderState } from \"../types\"\n\nexport function renderHTML(\n element: HTMLElement,\n { style, vars }: HTMLRenderState,\n styleProp?: MotionStyle,\n projection?: any\n) {\n const elementStyle = element.style\n\n let key: string\n for (key in style) {\n // CSSStyleDeclaration has [index: number]: string; in the types, so we use that as key type.\n elementStyle[key as unknown as number] = style[key] as string\n }\n\n // Write projection styles directly to element style\n projection?.applyProjectionStyles(elementStyle, styleProp)\n\n for (key in vars) {\n // Loop over any CSS variables and assign those.\n // They can only be assigned using `setProperty`.\n elementStyle.setProperty(key, vars[key] as string)\n }\n}\n"],"names":[],"mappings":"AAGM,SAAU,UAAU,CACtB,OAAoB,EACpB,EAAE,KAAK,EAAE,IAAI,EAAmB,EAChC,SAAuB,EACvB,UAAgB,EAAA;AAEhB,IAAA,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK;AAElC,IAAA,IAAI,GAAW;AACf,IAAA,KAAK,GAAG,IAAI,KAAK,EAAE;;QAEf,YAAY,CAAC,GAAwB,CAAC,GAAG,KAAK,CAAC,GAAG,CAAW;IACjE;;AAGA,IAAA,UAAU,EAAE,qBAAqB,CAAC,YAAY,EAAE,SAAS,CAAC;AAE1D,IAAA,KAAK,GAAG,IAAI,IAAI,EAAE;;;QAGd,YAAY,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAW,CAAC;IACtD;AACJ;;;;"}

View File

@@ -0,0 +1,22 @@
import { isMotionValue } from '../../../value/utils/is-motion-value.mjs';
import { isForcedMotionValue } from '../../utils/is-forced-motion-value.mjs';
function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
const style = props.style;
const prevStyle = prevProps?.style;
const newValues = {};
if (!style)
return newValues;
for (const key in style) {
if (isMotionValue(style[key]) ||
(prevStyle && isMotionValue(prevStyle[key])) ||
isForcedMotionValue(key, props) ||
visualElement?.getValue(key)?.liveStyle !== undefined) {
newValues[key] = style[key];
}
}
return newValues;
}
export { scrapeMotionValuesFromProps };
//# sourceMappingURL=scrape-motion-values.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"scrape-motion-values.mjs","sources":["../../../../../src/render/html/utils/scrape-motion-values.ts"],"sourcesContent":["import { isMotionValue } from \"../../../value/utils/is-motion-value\"\nimport type { MotionNodeOptions } from \"../../../node/types\"\nimport { isForcedMotionValue } from \"../../utils/is-forced-motion-value\"\nimport type { VisualElement } from \"../../VisualElement\"\n\nexport function scrapeMotionValuesFromProps(\n props: MotionNodeOptions,\n prevProps: MotionNodeOptions,\n visualElement?: VisualElement\n) {\n const style = (props as any).style\n const prevStyle = (prevProps as any)?.style\n const newValues: { [key: string]: any } = {}\n\n if (!style) return newValues\n\n for (const key in style) {\n if (\n isMotionValue(style[key]) ||\n (prevStyle && isMotionValue(prevStyle[key])) ||\n isForcedMotionValue(key, props) ||\n visualElement?.getValue(key)?.liveStyle !== undefined\n ) {\n newValues[key] = style[key]\n }\n }\n\n return newValues\n}\n"],"names":[],"mappings":";;;SAKgB,2BAA2B,CACvC,KAAwB,EACxB,SAA4B,EAC5B,aAA6B,EAAA;AAE7B,IAAA,MAAM,KAAK,GAAI,KAAa,CAAC,KAAK;AAClC,IAAA,MAAM,SAAS,GAAI,SAAiB,EAAE,KAAK;IAC3C,MAAM,SAAS,GAA2B,EAAE;AAE5C,IAAA,IAAI,CAAC,KAAK;AAAE,QAAA,OAAO,SAAS;AAE5B,IAAA,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE;AACrB,QAAA,IACI,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;aACxB,SAAS,IAAI,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,YAAA,mBAAmB,CAAC,GAAG,EAAE,KAAK,CAAC;YAC/B,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,KAAK,SAAS,EACvD;YACE,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;QAC/B;IACJ;AAEA,IAAA,OAAO,SAAS;AACpB;;;;"}

View File

@@ -0,0 +1,42 @@
import { createBox } from '../../projection/geometry/models.mjs';
import { VisualElement } from '../VisualElement.mjs';
function isObjectKey(key, object) {
return key in object;
}
class ObjectVisualElement extends VisualElement {
constructor() {
super(...arguments);
this.type = "object";
}
readValueFromInstance(instance, key) {
if (isObjectKey(key, instance)) {
const value = instance[key];
if (typeof value === "string" || typeof value === "number") {
return value;
}
}
return undefined;
}
getBaseTargetFromProps() {
return undefined;
}
removeValueFromRenderState(key, renderState) {
delete renderState.output[key];
}
measureInstanceViewportBox() {
return createBox();
}
build(renderState, latestValues) {
Object.assign(renderState.output, latestValues);
}
renderInstance(instance, { output }) {
Object.assign(instance, output);
}
sortInstanceNodePosition() {
return 0;
}
}
export { ObjectVisualElement };
//# sourceMappingURL=ObjectVisualElement.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ObjectVisualElement.mjs","sources":["../../../../src/render/object/ObjectVisualElement.ts"],"sourcesContent":["import { createBox } from \"../../projection/geometry/models\"\nimport { ResolvedValues } from \"../types\"\nimport { VisualElement } from \"../VisualElement\"\n\ninterface ObjectRenderState {\n output: ResolvedValues\n}\n\nfunction isObjectKey(key: string, object: Object): key is keyof Object {\n return key in object\n}\n\nexport class ObjectVisualElement extends VisualElement<\n Object,\n ObjectRenderState\n> {\n type = \"object\"\n\n readValueFromInstance(instance: Object, key: string) {\n if (isObjectKey(key, instance)) {\n const value = instance[key]\n if (typeof value === \"string\" || typeof value === \"number\") {\n return value\n }\n }\n\n return undefined\n }\n\n getBaseTargetFromProps() {\n return undefined\n }\n\n removeValueFromRenderState(\n key: string,\n renderState: ObjectRenderState\n ): void {\n delete renderState.output[key]\n }\n\n measureInstanceViewportBox() {\n return createBox()\n }\n\n build(renderState: ObjectRenderState, latestValues: ResolvedValues) {\n Object.assign(renderState.output, latestValues)\n }\n\n renderInstance(instance: Object, { output }: ObjectRenderState) {\n Object.assign(instance, output)\n }\n\n sortInstanceNodePosition() {\n return 0\n }\n}\n"],"names":[],"mappings":";;;AAQA,SAAS,WAAW,CAAC,GAAW,EAAE,MAAc,EAAA;IAC5C,OAAO,GAAG,IAAI,MAAM;AACxB;AAEM,MAAO,mBAAoB,SAAQ,aAGxC,CAAA;AAHD,IAAA,WAAA,GAAA;;QAII,IAAA,CAAA,IAAI,GAAG,QAAQ;IAuCnB;IArCI,qBAAqB,CAAC,QAAgB,EAAE,GAAW,EAAA;AAC/C,QAAA,IAAI,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE;AAC5B,YAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC;YAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AACxD,gBAAA,OAAO,KAAK;YAChB;QACJ;AAEA,QAAA,OAAO,SAAS;IACpB;IAEA,sBAAsB,GAAA;AAClB,QAAA,OAAO,SAAS;IACpB;IAEA,0BAA0B,CACtB,GAAW,EACX,WAA8B,EAAA;AAE9B,QAAA,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;IAClC;IAEA,0BAA0B,GAAA;QACtB,OAAO,SAAS,EAAE;IACtB;IAEA,KAAK,CAAC,WAA8B,EAAE,YAA4B,EAAA;QAC9D,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC;IACnD;AAEA,IAAA,cAAc,CAAC,QAAgB,EAAE,EAAE,MAAM,EAAqB,EAAA;AAC1D,QAAA,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;IACnC;IAEA,wBAAwB,GAAA;AACpB,QAAA,OAAO,CAAC;IACZ;AACH;;;;"}

4
node_modules/motion-dom/dist/es/render/store.mjs generated vendored Normal file
View File

@@ -0,0 +1,4 @@
const visualElementStore = new WeakMap();
export { visualElementStore };
//# sourceMappingURL=store.mjs.map

1
node_modules/motion-dom/dist/es/render/store.mjs.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"store.mjs","sources":["../../../src/render/store.ts"],"sourcesContent":["import type { VisualElement } from \"./VisualElement\"\n\nexport const visualElementStore = new WeakMap<any, VisualElement>()\n"],"names":[],"mappings":"AAEO,MAAM,kBAAkB,GAAG,IAAI,OAAO;;;;"}

View File

@@ -0,0 +1,46 @@
import { transformProps } from '../utils/keys-transform.mjs';
import { getDefaultValueType } from '../../value/types/maps/defaults.mjs';
import { createBox } from '../../projection/geometry/models.mjs';
import { DOMVisualElement } from '../dom/DOMVisualElement.mjs';
import { camelToDash } from '../dom/utils/camel-to-dash.mjs';
import { buildSVGAttrs } from './utils/build-attrs.mjs';
import { camelCaseAttributes } from './utils/camel-case-attrs.mjs';
import { isSVGTag } from './utils/is-svg-tag.mjs';
import { renderSVG } from './utils/render.mjs';
import { scrapeMotionValuesFromProps } from './utils/scrape-motion-values.mjs';
class SVGVisualElement extends DOMVisualElement {
constructor() {
super(...arguments);
this.type = "svg";
this.isSVGTag = false;
this.measureInstanceViewportBox = createBox;
}
getBaseTargetFromProps(props, key) {
return props[key];
}
readValueFromInstance(instance, key) {
if (transformProps.has(key)) {
const defaultType = getDefaultValueType(key);
return defaultType ? defaultType.default || 0 : 0;
}
key = !camelCaseAttributes.has(key) ? camelToDash(key) : key;
return instance.getAttribute(key);
}
scrapeMotionValuesFromProps(props, prevProps, visualElement) {
return scrapeMotionValuesFromProps(props, prevProps, visualElement);
}
build(renderState, latestValues, props) {
buildSVGAttrs(renderState, latestValues, this.isSVGTag, props.transformTemplate, props.style);
}
renderInstance(instance, renderState, styleProp, projection) {
renderSVG(instance, renderState, styleProp, projection);
}
mount(instance) {
this.isSVGTag = isSVGTag(instance.tagName);
super.mount(instance);
}
}
export { SVGVisualElement };
//# sourceMappingURL=SVGVisualElement.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SVGVisualElement.mjs","sources":["../../../../src/render/svg/SVGVisualElement.ts"],"sourcesContent":["import type { AnyResolvedKeyframe } from \"../../animation/types\"\nimport type { MotionValue } from \"../../value\"\nimport type { MotionNodeOptions } from \"../../node/types\"\nimport { transformProps } from \"../utils/keys-transform\"\nimport { getDefaultValueType } from \"../../value/types/maps/defaults\"\nimport { createBox } from \"../../projection/geometry/models\"\nimport { DOMVisualElement } from \"../dom/DOMVisualElement\"\nimport type { DOMVisualElementOptions } from \"../dom/types\"\nimport { camelToDash } from \"../dom/utils/camel-to-dash\"\nimport type { ResolvedValues } from \"../types\"\nimport type { VisualElement, MotionStyle } from \"../VisualElement\"\nimport { SVGRenderState } from \"./types\"\nimport { buildSVGAttrs } from \"./utils/build-attrs\"\nimport { camelCaseAttributes } from \"./utils/camel-case-attrs\"\nimport { isSVGTag } from \"./utils/is-svg-tag\"\nimport { renderSVG } from \"./utils/render\"\nimport { scrapeMotionValuesFromProps } from \"./utils/scrape-motion-values\"\nexport class SVGVisualElement extends DOMVisualElement<\n SVGElement,\n SVGRenderState,\n DOMVisualElementOptions\n> {\n type = \"svg\"\n\n isSVGTag = false\n\n getBaseTargetFromProps(\n props: MotionNodeOptions,\n key: string\n ): AnyResolvedKeyframe | MotionValue<any> | undefined {\n return props[key as keyof MotionNodeOptions]\n }\n\n readValueFromInstance(instance: SVGElement, key: string) {\n if (transformProps.has(key)) {\n const defaultType = getDefaultValueType(key)\n return defaultType ? defaultType.default || 0 : 0\n }\n key = !camelCaseAttributes.has(key) ? camelToDash(key) : key\n return instance.getAttribute(key)\n }\n\n measureInstanceViewportBox = createBox\n\n scrapeMotionValuesFromProps(\n props: MotionNodeOptions,\n prevProps: MotionNodeOptions,\n visualElement: VisualElement\n ) {\n return scrapeMotionValuesFromProps(props, prevProps, visualElement)\n }\n\n build(\n renderState: SVGRenderState,\n latestValues: ResolvedValues,\n props: MotionNodeOptions\n ) {\n buildSVGAttrs(\n renderState,\n latestValues,\n this.isSVGTag,\n props.transformTemplate,\n (props as any).style\n )\n }\n\n renderInstance(\n instance: SVGElement,\n renderState: SVGRenderState,\n styleProp?: MotionStyle | undefined,\n projection?: any\n ): void {\n renderSVG(instance, renderState, styleProp, projection)\n }\n\n mount(instance: SVGElement) {\n this.isSVGTag = isSVGTag(instance.tagName)\n super.mount(instance)\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAiBM,MAAO,gBAAiB,SAAQ,gBAIrC,CAAA;AAJD,IAAA,WAAA,GAAA;;QAKI,IAAA,CAAA,IAAI,GAAG,KAAK;QAEZ,IAAA,CAAA,QAAQ,GAAG,KAAK;QAkBhB,IAAA,CAAA,0BAA0B,GAAG,SAAS;IAqC1C;IArDI,sBAAsB,CAClB,KAAwB,EACxB,GAAW,EAAA;AAEX,QAAA,OAAO,KAAK,CAAC,GAA8B,CAAC;IAChD;IAEA,qBAAqB,CAAC,QAAoB,EAAE,GAAW,EAAA;AACnD,QAAA,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACzB,YAAA,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,CAAC;AAC5C,YAAA,OAAO,WAAW,GAAG,WAAW,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC;QACrD;AACA,QAAA,GAAG,GAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,GAAG;AAC5D,QAAA,OAAO,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC;IACrC;AAIA,IAAA,2BAA2B,CACvB,KAAwB,EACxB,SAA4B,EAC5B,aAA4B,EAAA;QAE5B,OAAO,2BAA2B,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC;IACvE;AAEA,IAAA,KAAK,CACD,WAA2B,EAC3B,YAA4B,EAC5B,KAAwB,EAAA;AAExB,QAAA,aAAa,CACT,WAAW,EACX,YAAY,EACZ,IAAI,CAAC,QAAQ,EACb,KAAK,CAAC,iBAAiB,EACtB,KAAa,CAAC,KAAK,CACvB;IACL;AAEA,IAAA,cAAc,CACV,QAAoB,EACpB,WAA2B,EAC3B,SAAmC,EACnC,UAAgB,EAAA;QAEhB,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC;IAC3D;AAEA,IAAA,KAAK,CAAC,QAAoB,EAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;AAC1C,QAAA,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;IACzB;AACH;;;;"}

View File

@@ -0,0 +1,73 @@
import { buildHTMLStyles } from '../../html/utils/build-styles.mjs';
import { buildSVGPath } from './path.mjs';
/**
* CSS Motion Path properties that should remain as CSS styles on SVG elements.
*/
const cssMotionPathProperties = [
"offsetDistance",
"offsetPath",
"offsetRotate",
"offsetAnchor",
];
/**
* Build SVG visual attributes, like cx and style.transform
*/
function buildSVGAttrs(state, { attrX, attrY, attrScale, pathLength, pathSpacing = 1, pathOffset = 0,
// This is object creation, which we try to avoid per-frame.
...latest }, isSVGTag, transformTemplate, styleProp) {
buildHTMLStyles(state, latest, transformTemplate);
/**
* For svg tags we just want to make sure viewBox is animatable and treat all the styles
* as normal HTML tags.
*/
if (isSVGTag) {
if (state.style.viewBox) {
state.attrs.viewBox = state.style.viewBox;
}
return;
}
state.attrs = state.style;
state.style = {};
const { attrs, style } = state;
/**
* However, we apply transforms as CSS transforms.
* So if we detect a transform, transformOrigin we take it from attrs and copy it into style.
*/
if (attrs.transform) {
style.transform = attrs.transform;
delete attrs.transform;
}
if (style.transform || attrs.transformOrigin) {
style.transformOrigin = attrs.transformOrigin ?? "50% 50%";
delete attrs.transformOrigin;
}
if (style.transform) {
/**
* SVG's element transform-origin uses its own median as a reference.
* Therefore, transformBox becomes a fill-box
*/
style.transformBox = styleProp?.transformBox ?? "fill-box";
delete attrs.transformBox;
}
for (const key of cssMotionPathProperties) {
if (attrs[key] !== undefined) {
style[key] = attrs[key];
delete attrs[key];
}
}
// Render attrX/attrY/attrScale as attributes
if (attrX !== undefined)
attrs.x = attrX;
if (attrY !== undefined)
attrs.y = attrY;
if (attrScale !== undefined)
attrs.scale = attrScale;
// Build SVG path if one has been defined
if (pathLength !== undefined) {
buildSVGPath(attrs, pathLength, pathSpacing, pathOffset, false);
}
}
export { buildSVGAttrs };
//# sourceMappingURL=build-attrs.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"build-attrs.mjs","sources":["../../../../../src/render/svg/utils/build-attrs.ts"],"sourcesContent":["import type { MotionNodeOptions } from \"../../../node/types\"\nimport { buildHTMLStyles } from \"../../html/utils/build-styles\"\nimport { ResolvedValues } from \"../../types\"\nimport { SVGRenderState } from \"../types\"\nimport { buildSVGPath } from \"./path\"\n\n/**\n * CSS Motion Path properties that should remain as CSS styles on SVG elements.\n */\nconst cssMotionPathProperties = [\n \"offsetDistance\",\n \"offsetPath\",\n \"offsetRotate\",\n \"offsetAnchor\",\n]\n\n/**\n * Build SVG visual attributes, like cx and style.transform\n */\nexport function buildSVGAttrs(\n state: SVGRenderState,\n {\n attrX,\n attrY,\n attrScale,\n pathLength,\n pathSpacing = 1,\n pathOffset = 0,\n // This is object creation, which we try to avoid per-frame.\n ...latest\n }: ResolvedValues,\n isSVGTag: boolean,\n transformTemplate?: MotionNodeOptions[\"transformTemplate\"],\n styleProp?: Record<string, any>\n) {\n buildHTMLStyles(state, latest, transformTemplate)\n\n /**\n * For svg tags we just want to make sure viewBox is animatable and treat all the styles\n * as normal HTML tags.\n */\n if (isSVGTag) {\n if (state.style.viewBox) {\n state.attrs.viewBox = state.style.viewBox\n }\n return\n }\n\n state.attrs = state.style\n state.style = {}\n const { attrs, style } = state\n\n /**\n * However, we apply transforms as CSS transforms.\n * So if we detect a transform, transformOrigin we take it from attrs and copy it into style.\n */\n if (attrs.transform) {\n style.transform = attrs.transform\n delete attrs.transform\n }\n if (style.transform || attrs.transformOrigin) {\n style.transformOrigin = attrs.transformOrigin ?? \"50% 50%\"\n delete attrs.transformOrigin\n }\n\n if (style.transform) {\n /**\n * SVG's element transform-origin uses its own median as a reference.\n * Therefore, transformBox becomes a fill-box\n */\n style.transformBox = (styleProp?.transformBox as string) ?? \"fill-box\"\n delete attrs.transformBox\n }\n\n for (const key of cssMotionPathProperties) {\n if (attrs[key] !== undefined) {\n style[key] = attrs[key]\n delete attrs[key]\n }\n }\n\n // Render attrX/attrY/attrScale as attributes\n if (attrX !== undefined) attrs.x = attrX\n if (attrY !== undefined) attrs.y = attrY\n if (attrScale !== undefined) attrs.scale = attrScale\n\n // Build SVG path if one has been defined\n if (pathLength !== undefined) {\n buildSVGPath(\n attrs,\n pathLength as number,\n pathSpacing as number,\n pathOffset as number,\n false\n )\n }\n}\n"],"names":[],"mappings":";;;AAMA;;AAEG;AACH,MAAM,uBAAuB,GAAG;IAC5B,gBAAgB;IAChB,YAAY;IACZ,cAAc;IACd,cAAc;CACjB;AAED;;AAEG;AACG,SAAU,aAAa,CACzB,KAAqB,EACrB,EACI,KAAK,EACL,KAAK,EACL,SAAS,EACT,UAAU,EACV,WAAW,GAAG,CAAC,EACf,UAAU,GAAG,CAAC;AACd;AACA,GAAG,MAAM,EACI,EACjB,QAAiB,EACjB,iBAA0D,EAC1D,SAA+B,EAAA;AAE/B,IAAA,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,iBAAiB,CAAC;AAEjD;;;AAGG;IACH,IAAI,QAAQ,EAAE;AACV,QAAA,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE;YACrB,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO;QAC7C;QACA;IACJ;AAEA,IAAA,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK;AACzB,IAAA,KAAK,CAAC,KAAK,GAAG,EAAE;AAChB,IAAA,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,KAAK;AAE9B;;;AAGG;AACH,IAAA,IAAI,KAAK,CAAC,SAAS,EAAE;AACjB,QAAA,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS;QACjC,OAAO,KAAK,CAAC,SAAS;IAC1B;IACA,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,eAAe,EAAE;QAC1C,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,IAAI,SAAS;QAC1D,OAAO,KAAK,CAAC,eAAe;IAChC;AAEA,IAAA,IAAI,KAAK,CAAC,SAAS,EAAE;AACjB;;;AAGG;QACH,KAAK,CAAC,YAAY,GAAI,SAAS,EAAE,YAAuB,IAAI,UAAU;QACtE,OAAO,KAAK,CAAC,YAAY;IAC7B;AAEA,IAAA,KAAK,MAAM,GAAG,IAAI,uBAAuB,EAAE;AACvC,QAAA,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;YAC1B,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;AACvB,YAAA,OAAO,KAAK,CAAC,GAAG,CAAC;QACrB;IACJ;;IAGA,IAAI,KAAK,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,CAAC,GAAG,KAAK;IACxC,IAAI,KAAK,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,CAAC,GAAG,KAAK;IACxC,IAAI,SAAS,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,KAAK,GAAG,SAAS;;AAGpD,IAAA,IAAI,UAAU,KAAK,SAAS,EAAE;QAC1B,YAAY,CACR,KAAK,EACL,UAAoB,EACpB,WAAqB,EACrB,UAAoB,EACpB,KAAK,CACR;IACL;AACJ;;;;"}

View File

@@ -0,0 +1,31 @@
/**
* A set of attribute names that are always read/written as camel case.
*/
const camelCaseAttributes = new Set([
"baseFrequency",
"diffuseConstant",
"kernelMatrix",
"kernelUnitLength",
"keySplines",
"keyTimes",
"limitingConeAngle",
"markerHeight",
"markerWidth",
"numOctaves",
"targetX",
"targetY",
"surfaceScale",
"specularConstant",
"specularExponent",
"stdDeviation",
"tableValues",
"viewBox",
"gradientTransform",
"pathLength",
"startOffset",
"textLength",
"lengthAdjust",
]);
export { camelCaseAttributes };
//# sourceMappingURL=camel-case-attrs.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"camel-case-attrs.mjs","sources":["../../../../../src/render/svg/utils/camel-case-attrs.ts"],"sourcesContent":["/**\n * A set of attribute names that are always read/written as camel case.\n */\nexport const camelCaseAttributes = new Set([\n \"baseFrequency\",\n \"diffuseConstant\",\n \"kernelMatrix\",\n \"kernelUnitLength\",\n \"keySplines\",\n \"keyTimes\",\n \"limitingConeAngle\",\n \"markerHeight\",\n \"markerWidth\",\n \"numOctaves\",\n \"targetX\",\n \"targetY\",\n \"surfaceScale\",\n \"specularConstant\",\n \"specularExponent\",\n \"stdDeviation\",\n \"tableValues\",\n \"viewBox\",\n \"gradientTransform\",\n \"pathLength\",\n \"startOffset\",\n \"textLength\",\n \"lengthAdjust\",\n])\n"],"names":[],"mappings":"AAAA;;AAEG;AACI,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IACvC,eAAe;IACf,iBAAiB;IACjB,cAAc;IACd,kBAAkB;IAClB,YAAY;IACZ,UAAU;IACV,mBAAmB;IACnB,cAAc;IACd,aAAa;IACb,YAAY;IACZ,SAAS;IACT,SAAS;IACT,cAAc;IACd,kBAAkB;IAClB,kBAAkB;IAClB,cAAc;IACd,aAAa;IACb,SAAS;IACT,mBAAmB;IACnB,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,cAAc;AACjB,CAAA;;;;"}

View File

@@ -0,0 +1,4 @@
const isSVGTag = (tag) => typeof tag === "string" && tag.toLowerCase() === "svg";
export { isSVGTag };
//# sourceMappingURL=is-svg-tag.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-svg-tag.mjs","sources":["../../../../../src/render/svg/utils/is-svg-tag.ts"],"sourcesContent":["export const isSVGTag = (tag: unknown) =>\n typeof tag === \"string\" && tag.toLowerCase() === \"svg\"\n"],"names":[],"mappings":"MAAa,QAAQ,GAAG,CAAC,GAAY,KACjC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK;;;;"}

View File

@@ -0,0 +1,32 @@
const dashKeys = {
offset: "stroke-dashoffset",
array: "stroke-dasharray",
};
const camelKeys = {
offset: "strokeDashoffset",
array: "strokeDasharray",
};
/**
* Build SVG path properties. Uses the path's measured length to convert
* our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset
* and stroke-dasharray attributes.
*
* This function is mutative to reduce per-frame GC.
*
* Note: We use unitless values for stroke-dasharray and stroke-dashoffset
* because Safari incorrectly scales px values when the page is zoomed.
*/
function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true) {
// Normalise path length by setting SVG attribute pathLength to 1
attrs.pathLength = 1;
// We use dash case when setting attributes directly to the DOM node and camel case
// when defining props on a React component.
const keys = useDashCase ? dashKeys : camelKeys;
// Build the dash offset (unitless to avoid Safari zoom bug)
attrs[keys.offset] = `${-offset}`;
// Build the dash array (unitless to avoid Safari zoom bug)
attrs[keys.array] = `${length} ${spacing}`;
}
export { buildSVGPath };
//# sourceMappingURL=path.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"path.mjs","sources":["../../../../../src/render/svg/utils/path.ts"],"sourcesContent":["import { ResolvedValues } from \"../../types\"\n\nconst dashKeys = {\n offset: \"stroke-dashoffset\",\n array: \"stroke-dasharray\",\n}\n\nconst camelKeys = {\n offset: \"strokeDashoffset\",\n array: \"strokeDasharray\",\n}\n\n/**\n * Build SVG path properties. Uses the path's measured length to convert\n * our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset\n * and stroke-dasharray attributes.\n *\n * This function is mutative to reduce per-frame GC.\n *\n * Note: We use unitless values for stroke-dasharray and stroke-dashoffset\n * because Safari incorrectly scales px values when the page is zoomed.\n */\nexport function buildSVGPath(\n attrs: ResolvedValues,\n length: number,\n spacing = 1,\n offset = 0,\n useDashCase: boolean = true\n): void {\n // Normalise path length by setting SVG attribute pathLength to 1\n attrs.pathLength = 1\n\n // We use dash case when setting attributes directly to the DOM node and camel case\n // when defining props on a React component.\n const keys = useDashCase ? dashKeys : camelKeys\n\n // Build the dash offset (unitless to avoid Safari zoom bug)\n attrs[keys.offset] = `${-offset}`\n\n // Build the dash array (unitless to avoid Safari zoom bug)\n attrs[keys.array] = `${length} ${spacing}`\n}\n"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAAG;AACb,IAAA,MAAM,EAAE,mBAAmB;AAC3B,IAAA,KAAK,EAAE,kBAAkB;CAC5B;AAED,MAAM,SAAS,GAAG;AACd,IAAA,MAAM,EAAE,kBAAkB;AAC1B,IAAA,KAAK,EAAE,iBAAiB;CAC3B;AAED;;;;;;;;;AASG;SACa,YAAY,CACxB,KAAqB,EACrB,MAAc,EACd,OAAO,GAAG,CAAC,EACX,MAAM,GAAG,CAAC,EACV,cAAuB,IAAI,EAAA;;AAG3B,IAAA,KAAK,CAAC,UAAU,GAAG,CAAC;;;IAIpB,MAAM,IAAI,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS;;IAG/C,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAA,EAAG,CAAC,MAAM,CAAA,CAAE;;IAGjC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE;AAC9C;;;;"}

View File

@@ -0,0 +1,13 @@
import { camelToDash } from '../../dom/utils/camel-to-dash.mjs';
import { renderHTML } from '../../html/utils/render.mjs';
import { camelCaseAttributes } from './camel-case-attrs.mjs';
function renderSVG(element, renderState, _styleProp, projection) {
renderHTML(element, renderState, undefined, projection);
for (const key in renderState.attrs) {
element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
}
}
export { renderSVG };
//# sourceMappingURL=render.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"render.mjs","sources":["../../../../../src/render/svg/utils/render.ts"],"sourcesContent":["import type { MotionStyle } from \"../../VisualElement\"\nimport { camelToDash } from \"../../dom/utils/camel-to-dash\"\nimport { renderHTML } from \"../../html/utils/render\"\nimport { SVGRenderState } from \"../types\"\nimport { camelCaseAttributes } from \"./camel-case-attrs\"\n\nexport function renderSVG(\n element: SVGElement,\n renderState: SVGRenderState,\n _styleProp?: MotionStyle,\n projection?: any\n) {\n renderHTML(element as any, renderState, undefined, projection)\n\n for (const key in renderState.attrs) {\n element.setAttribute(\n !camelCaseAttributes.has(key) ? camelToDash(key) : key,\n renderState.attrs[key] as string\n )\n }\n}\n"],"names":[],"mappings":";;;;AAMM,SAAU,SAAS,CACrB,OAAmB,EACnB,WAA2B,EAC3B,UAAwB,EACxB,UAAgB,EAAA;IAEhB,UAAU,CAAC,OAAc,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC;AAE9D,IAAA,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,KAAK,EAAE;AACjC,QAAA,OAAO,CAAC,YAAY,CAChB,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,GAAG,EACtD,WAAW,CAAC,KAAK,CAAC,GAAG,CAAW,CACnC;IACL;AACJ;;;;"}

View File

@@ -0,0 +1,20 @@
import { isMotionValue } from '../../../value/utils/is-motion-value.mjs';
import { transformPropOrder } from '../../utils/keys-transform.mjs';
import { scrapeMotionValuesFromProps as scrapeMotionValuesFromProps$1 } from '../../html/utils/scrape-motion-values.mjs';
function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);
for (const key in props) {
if (isMotionValue(props[key]) ||
isMotionValue(prevProps[key])) {
const targetKey = transformPropOrder.indexOf(key) !== -1
? "attr" + key.charAt(0).toUpperCase() + key.substring(1)
: key;
newValues[targetKey] = props[key];
}
}
return newValues;
}
export { scrapeMotionValuesFromProps };
//# sourceMappingURL=scrape-motion-values.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"scrape-motion-values.mjs","sources":["../../../../../src/render/svg/utils/scrape-motion-values.ts"],"sourcesContent":["import { isMotionValue } from \"../../../value/utils/is-motion-value\"\nimport type { MotionNodeOptions } from \"../../../node/types\"\nimport { transformPropOrder } from \"../../utils/keys-transform\"\nimport { scrapeMotionValuesFromProps as scrapeHTMLMotionValuesFromProps } from \"../../html/utils/scrape-motion-values\"\nimport type { VisualElement } from \"../../VisualElement\"\n\nexport function scrapeMotionValuesFromProps(\n props: MotionNodeOptions,\n prevProps: MotionNodeOptions,\n visualElement?: VisualElement\n) {\n const newValues = scrapeHTMLMotionValuesFromProps(\n props,\n prevProps,\n visualElement\n )\n\n for (const key in props) {\n if (\n isMotionValue(props[key as keyof typeof props]) ||\n isMotionValue(prevProps[key as keyof typeof prevProps])\n ) {\n const targetKey =\n transformPropOrder.indexOf(key) !== -1\n ? \"attr\" + key.charAt(0).toUpperCase() + key.substring(1)\n : key\n\n newValues[targetKey] = props[key as keyof typeof props]\n }\n }\n\n return newValues\n}\n"],"names":["scrapeHTMLMotionValuesFromProps"],"mappings":";;;;SAMgB,2BAA2B,CACvC,KAAwB,EACxB,SAA4B,EAC5B,aAA6B,EAAA;IAE7B,MAAM,SAAS,GAAGA,6BAA+B,CAC7C,KAAK,EACL,SAAS,EACT,aAAa,CAChB;AAED,IAAA,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE;AACrB,QAAA,IACI,aAAa,CAAC,KAAK,CAAC,GAAyB,CAAC,CAAC;AAC/C,YAAA,aAAa,CAAC,SAAS,CAAC,GAA6B,CAAC,CAAC,EACzD;YACE,MAAM,SAAS,GACX,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK;AAChC,kBAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;kBACtD,GAAG;YAEb,SAAS,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAyB,CAAC;QAC3D;IACJ;AAEA,IAAA,OAAO,SAAS;AACpB;;;;"}

View File

@@ -0,0 +1,386 @@
import { animateVisualElement } from '../../animation/interfaces/visual-element.mjs';
import { calcChildStagger } from '../../animation/utils/calc-child-stagger.mjs';
import { getVariantContext } from './get-variant-context.mjs';
import { isAnimationControls } from './is-animation-controls.mjs';
import { isKeyframesTarget } from './is-keyframes-target.mjs';
import { isVariantLabel } from './is-variant-label.mjs';
import { resolveVariant } from './resolve-dynamic-variants.mjs';
import { shallowCompare } from './shallow-compare.mjs';
import { variantPriorityOrder } from './variant-props.mjs';
const reversePriorityOrder = [...variantPriorityOrder].reverse();
const numAnimationTypes = variantPriorityOrder.length;
function createAnimateFunction(visualElement) {
return (animations) => {
return Promise.all(animations.map(({ animation, options }) => animateVisualElement(visualElement, animation, options)));
};
}
function createAnimationState(visualElement) {
let animate = createAnimateFunction(visualElement);
let state = createState();
let isInitialRender = true;
/**
* Track whether the animation state has been reset (e.g. via StrictMode
* double-invocation or Suspense unmount/remount). On the first
* animateChanges() call after a reset we need to behave like the initial
* render for variant-inheritance checks, even though isInitialRender is
* already false.
*/
let wasReset = false;
/**
* This function will be used to reduce the animation definitions for
* each active animation type into an object of resolved values for it.
*/
const buildResolvedTypeValues = (type) => (acc, definition) => {
const resolved = resolveVariant(visualElement, definition, type === "exit"
? visualElement.presenceContext?.custom
: undefined);
if (resolved) {
const { transition, transitionEnd, ...target } = resolved;
acc = { ...acc, ...target, ...transitionEnd };
}
return acc;
};
/**
* This just allows us to inject mocked animation functions
* @internal
*/
function setAnimateFunction(makeAnimator) {
animate = makeAnimator(visualElement);
}
/**
* When we receive new props, we need to:
* 1. Create a list of protected keys for each type. This is a directory of
* value keys that are currently being "handled" by types of a higher priority
* so that whenever an animation is played of a given type, these values are
* protected from being animated.
* 2. Determine if an animation type needs animating.
* 3. Determine if any values have been removed from a type and figure out
* what to animate those to.
*/
function animateChanges(changedActiveType) {
const { props } = visualElement;
const context = getVariantContext(visualElement.parent) || {};
/**
* A list of animations that we'll build into as we iterate through the animation
* types. This will get executed at the end of the function.
*/
const animations = [];
/**
* Keep track of which values have been removed. Then, as we hit lower priority
* animation types, we can check if they contain removed values and animate to that.
*/
const removedKeys = new Set();
/**
* A dictionary of all encountered keys. This is an object to let us build into and
* copy it without iteration. Each time we hit an animation type we set its protected
* keys - the keys its not allowed to animate - to the latest version of this object.
*/
let encounteredKeys = {};
/**
* If a variant has been removed at a given index, and this component is controlling
* variant animations, we want to ensure lower-priority variants are forced to animate.
*/
let removedVariantIndex = Infinity;
/**
* Iterate through all animation types in reverse priority order. For each, we want to
* detect which values it's handling and whether or not they've changed (and therefore
* need to be animated). If any values have been removed, we want to detect those in
* lower priority props and flag for animation.
*/
for (let i = 0; i < numAnimationTypes; i++) {
const type = reversePriorityOrder[i];
const typeState = state[type];
const prop = props[type] !== undefined
? props[type]
: context[type];
const propIsVariant = isVariantLabel(prop);
/**
* If this type has *just* changed isActive status, set activeDelta
* to that status. Otherwise set to null.
*/
const activeDelta = type === changedActiveType ? typeState.isActive : null;
if (activeDelta === false)
removedVariantIndex = i;
/**
* If this prop is an inherited variant, rather than been set directly on the
* component itself, we want to make sure we allow the parent to trigger animations.
*
* TODO: Can probably change this to a !isControllingVariants check
*/
let isInherited = prop === context[type] &&
prop !== props[type] &&
propIsVariant;
if (isInherited &&
(isInitialRender || wasReset) &&
visualElement.manuallyAnimateOnMount) {
isInherited = false;
}
/**
* Set all encountered keys so far as the protected keys for this type. This will
* be any key that has been animated or otherwise handled by active, higher-priortiy types.
*/
typeState.protectedKeys = { ...encounteredKeys };
// Check if we can skip analysing this prop early
if (
// If it isn't active and hasn't *just* been set as inactive
(!typeState.isActive && activeDelta === null) ||
// If we didn't and don't have any defined prop for this animation type
(!prop && !typeState.prevProp) ||
// Or if the prop doesn't define an animation
isAnimationControls(prop) ||
typeof prop === "boolean") {
continue;
}
/**
* If exit is already active and wasn't just activated, skip
* re-processing to prevent interrupting running exit animations.
* Re-resolving exit with a changed custom value can start new
* value animations that stop the originals, leaving the exit
* animation promise unresolved and the component stuck in the DOM.
*/
if (type === "exit" && typeState.isActive && activeDelta !== true) {
if (typeState.prevResolvedValues) {
encounteredKeys = {
...encounteredKeys,
...typeState.prevResolvedValues,
};
}
continue;
}
/**
* As we go look through the values defined on this type, if we detect
* a changed value or a value that was removed in a higher priority, we set
* this to true and add this prop to the animation list.
*/
const variantDidChange = checkVariantsDidChange(typeState.prevProp, prop);
let shouldAnimateType = variantDidChange ||
// If we're making this variant active, we want to always make it active
(type === changedActiveType &&
typeState.isActive &&
!isInherited &&
propIsVariant) ||
// If we removed a higher-priority variant (i is in reverse order)
(i > removedVariantIndex && propIsVariant);
let handledRemovedValues = false;
/**
* As animations can be set as variant lists, variants or target objects, we
* coerce everything to an array if it isn't one already
*/
const definitionList = Array.isArray(prop) ? prop : [prop];
/**
* Build an object of all the resolved values. We'll use this in the subsequent
* animateChanges calls to determine whether a value has changed.
*/
let resolvedValues = definitionList.reduce(buildResolvedTypeValues(type), {});
if (activeDelta === false)
resolvedValues = {};
/**
* Now we need to loop through all the keys in the prev prop and this prop,
* and decide:
* 1. If the value has changed, and needs animating
* 2. If it has been removed, and needs adding to the removedKeys set
* 3. If it has been removed in a higher priority type and needs animating
* 4. If it hasn't been removed in a higher priority but hasn't changed, and
* needs adding to the type's protectedKeys list.
*/
const { prevResolvedValues = {} } = typeState;
const allKeys = {
...prevResolvedValues,
...resolvedValues,
};
const markToAnimate = (key) => {
shouldAnimateType = true;
if (removedKeys.has(key)) {
handledRemovedValues = true;
removedKeys.delete(key);
}
typeState.needsAnimating[key] = true;
const motionValue = visualElement.getValue(key);
if (motionValue)
motionValue.liveStyle = false;
};
for (const key in allKeys) {
const next = resolvedValues[key];
const prev = prevResolvedValues[key];
// If we've already handled this we can just skip ahead
if (encounteredKeys.hasOwnProperty(key))
continue;
/**
* If the value has changed, we probably want to animate it.
*/
let valueHasChanged = false;
if (isKeyframesTarget(next) && isKeyframesTarget(prev)) {
valueHasChanged = !shallowCompare(next, prev);
}
else {
valueHasChanged = next !== prev;
}
if (valueHasChanged) {
if (next !== undefined && next !== null) {
// If next is defined and doesn't equal prev, it needs animating
markToAnimate(key);
}
else {
// If it's undefined, it's been removed.
removedKeys.add(key);
}
}
else if (next !== undefined && removedKeys.has(key)) {
/**
* If next hasn't changed and it isn't undefined, we want to check if it's
* been removed by a higher priority
*/
markToAnimate(key);
}
else {
/**
* If it hasn't changed, we add it to the list of protected values
* to ensure it doesn't get animated.
*/
typeState.protectedKeys[key] = true;
}
}
/**
* Update the typeState so next time animateChanges is called we can compare the
* latest prop and resolvedValues to these.
*/
typeState.prevProp = prop;
typeState.prevResolvedValues = resolvedValues;
if (typeState.isActive) {
encounteredKeys = { ...encounteredKeys, ...resolvedValues };
}
if ((isInitialRender || wasReset) &&
visualElement.blockInitialAnimation) {
shouldAnimateType = false;
}
/**
* If this is an inherited prop we want to skip this animation
* unless the inherited variants haven't changed on this render.
*/
const willAnimateViaParent = isInherited && variantDidChange;
const needsAnimating = !willAnimateViaParent || handledRemovedValues;
if (shouldAnimateType && needsAnimating) {
animations.push(...definitionList.map((animation) => {
const options = { type };
/**
* If we're performing the initial animation, but we're not
* rendering at the same time as the variant-controlling parent,
* we want to use the parent's transition to calculate the stagger.
*/
if (typeof animation === "string" &&
(isInitialRender || wasReset) &&
!willAnimateViaParent &&
visualElement.manuallyAnimateOnMount &&
visualElement.parent) {
const { parent } = visualElement;
const parentVariant = resolveVariant(parent, animation);
if (parent.enteringChildren && parentVariant) {
const { delayChildren } = parentVariant.transition || {};
options.delay = calcChildStagger(parent.enteringChildren, visualElement, delayChildren);
}
}
return {
animation: animation,
options,
};
}));
}
}
/**
* If there are some removed value that haven't been dealt with,
* we need to create a new animation that falls back either to the value
* defined in the style prop, or the last read value.
*/
if (removedKeys.size) {
const fallbackAnimation = {};
/**
* If the initial prop contains a transition we can use that, otherwise
* allow the animation function to use the visual element's default.
*/
if (typeof props.initial !== "boolean") {
const initialTransition = resolveVariant(visualElement, Array.isArray(props.initial)
? props.initial[0]
: props.initial);
if (initialTransition && initialTransition.transition) {
fallbackAnimation.transition = initialTransition.transition;
}
}
removedKeys.forEach((key) => {
const fallbackTarget = visualElement.getBaseTarget(key);
const motionValue = visualElement.getValue(key);
if (motionValue)
motionValue.liveStyle = true;
// @ts-expect-error - @mattgperry to figure if we should do something here
fallbackAnimation[key] = fallbackTarget ?? null;
});
animations.push({ animation: fallbackAnimation });
}
let shouldAnimate = Boolean(animations.length);
if (isInitialRender &&
(props.initial === false || props.initial === props.animate) &&
!visualElement.manuallyAnimateOnMount) {
shouldAnimate = false;
}
isInitialRender = false;
wasReset = false;
return shouldAnimate ? animate(animations) : Promise.resolve();
}
/**
* Change whether a certain animation type is active.
*/
function setActive(type, isActive) {
// If the active state hasn't changed, we can safely do nothing here
if (state[type].isActive === isActive)
return Promise.resolve();
// Propagate active change to children
visualElement.variantChildren?.forEach((child) => child.animationState?.setActive(type, isActive));
state[type].isActive = isActive;
const animations = animateChanges(type);
for (const key in state) {
state[key].protectedKeys = {};
}
return animations;
}
return {
animateChanges,
setActive,
setAnimateFunction,
getState: () => state,
reset: () => {
state = createState();
wasReset = true;
},
};
}
function checkVariantsDidChange(prev, next) {
if (typeof next === "string") {
return next !== prev;
}
else if (Array.isArray(next)) {
return !shallowCompare(next, prev);
}
return false;
}
function createTypeState(isActive = false) {
return {
isActive,
protectedKeys: {},
needsAnimating: {},
prevResolvedValues: {},
};
}
function createState() {
return {
animate: createTypeState(true),
whileInView: createTypeState(),
whileHover: createTypeState(),
whileTap: createTypeState(),
whileDrag: createTypeState(),
whileFocus: createTypeState(),
exit: createTypeState(),
};
}
export { checkVariantsDidChange, createAnimationState };
//# sourceMappingURL=animation-state.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,33 @@
import { isVariantLabel } from './is-variant-label.mjs';
import { variantProps } from './variant-props.mjs';
const numVariantProps = variantProps.length;
/**
* Get variant context from a visual element's parent chain.
* Uses `any` type for visualElement to avoid circular dependencies.
*/
function getVariantContext(visualElement) {
if (!visualElement)
return undefined;
if (!visualElement.isControllingVariants) {
const context = visualElement.parent
? getVariantContext(visualElement.parent) || {}
: {};
if (visualElement.props.initial !== undefined) {
context.initial = visualElement.props.initial;
}
return context;
}
const context = {};
for (let i = 0; i < numVariantProps; i++) {
const name = variantProps[i];
const prop = visualElement.props[name];
if (isVariantLabel(prop) || prop === false) {
context[name] = prop;
}
}
return context;
}
export { getVariantContext };
//# sourceMappingURL=get-variant-context.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"get-variant-context.mjs","sources":["../../../../src/render/utils/get-variant-context.ts"],"sourcesContent":["import { isVariantLabel } from \"./is-variant-label\"\nimport { variantProps } from \"./variant-props\"\n\nconst numVariantProps = variantProps.length\n\ntype VariantStateContext = {\n initial?: string | string[]\n animate?: string | string[]\n exit?: string | string[]\n whileHover?: string | string[]\n whileDrag?: string | string[]\n whileFocus?: string | string[]\n whileTap?: string | string[]\n}\n\n/**\n * Get variant context from a visual element's parent chain.\n * Uses `any` type for visualElement to avoid circular dependencies.\n */\nexport function getVariantContext(\n visualElement?: any\n): undefined | VariantStateContext {\n if (!visualElement) return undefined\n\n if (!visualElement.isControllingVariants) {\n const context = visualElement.parent\n ? getVariantContext(visualElement.parent) || {}\n : {}\n if (visualElement.props.initial !== undefined) {\n context.initial = visualElement.props.initial as any\n }\n return context\n }\n\n const context: VariantStateContext = {}\n for (let i = 0; i < numVariantProps; i++) {\n const name = variantProps[i] as keyof typeof context\n const prop = visualElement.props[name]\n\n if (isVariantLabel(prop) || prop === false) {\n ;(context as any)[name] = prop\n }\n }\n\n return context\n}\n"],"names":[],"mappings":";;;AAGA,MAAM,eAAe,GAAG,YAAY,CAAC,MAAM;AAY3C;;;AAGG;AACG,SAAU,iBAAiB,CAC7B,aAAmB,EAAA;AAEnB,IAAA,IAAI,CAAC,aAAa;AAAE,QAAA,OAAO,SAAS;AAEpC,IAAA,IAAI,CAAC,aAAa,CAAC,qBAAqB,EAAE;AACtC,QAAA,MAAM,OAAO,GAAG,aAAa,CAAC;cACxB,iBAAiB,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI;cAC3C,EAAE;QACR,IAAI,aAAa,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE;YAC3C,OAAO,CAAC,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,OAAc;QACxD;AACA,QAAA,OAAO,OAAO;IAClB;IAEA,MAAM,OAAO,GAAwB,EAAE;AACvC,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,EAAE,CAAC,EAAE,EAAE;AACtC,QAAA,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAyB;QACpD,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;QAEtC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,KAAK,EAAE;AACtC,YAAA,OAAe,CAAC,IAAI,CAAC,GAAG,IAAI;QAClC;IACJ;AAEA,IAAA,OAAO,OAAO;AAClB;;;;"}

View File

@@ -0,0 +1,8 @@
function isAnimationControls(v) {
return (v !== null &&
typeof v === "object" &&
typeof v.start === "function");
}
export { isAnimationControls };
//# sourceMappingURL=is-animation-controls.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-animation-controls.mjs","sources":["../../../../src/render/utils/is-animation-controls.ts"],"sourcesContent":["import type { LegacyAnimationControls } from \"../../node/types\"\n\nexport function isAnimationControls(v?: unknown): v is LegacyAnimationControls {\n return (\n v !== null &&\n typeof v === \"object\" &&\n typeof (v as LegacyAnimationControls).start === \"function\"\n )\n}\n"],"names":[],"mappings":"AAEM,SAAU,mBAAmB,CAAC,CAAW,EAAA;IAC3C,QACI,CAAC,KAAK,IAAI;QACV,OAAO,CAAC,KAAK,QAAQ;AACrB,QAAA,OAAQ,CAA6B,CAAC,KAAK,KAAK,UAAU;AAElE;;;;"}

View File

@@ -0,0 +1,14 @@
import { isAnimationControls } from './is-animation-controls.mjs';
import { isVariantLabel } from './is-variant-label.mjs';
import { variantProps } from './variant-props.mjs';
function isControllingVariants(props) {
return (isAnimationControls(props.animate) ||
variantProps.some((name) => isVariantLabel(props[name])));
}
function isVariantNode(props) {
return Boolean(isControllingVariants(props) || props.variants);
}
export { isControllingVariants, isVariantNode };
//# sourceMappingURL=is-controlling-variants.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-controlling-variants.mjs","sources":["../../../../src/render/utils/is-controlling-variants.ts"],"sourcesContent":["import type { MotionNodeOptions } from \"../../node/types\"\nimport { isAnimationControls } from \"./is-animation-controls\"\nimport { isVariantLabel } from \"./is-variant-label\"\nimport { variantProps } from \"./variant-props\"\n\nexport function isControllingVariants(props: MotionNodeOptions) {\n return (\n isAnimationControls(props.animate) ||\n variantProps.some((name) =>\n isVariantLabel(props[name as keyof typeof props])\n )\n )\n}\n\nexport function isVariantNode(props: MotionNodeOptions) {\n return Boolean(isControllingVariants(props) || props.variants)\n}\n"],"names":[],"mappings":";;;;AAKM,SAAU,qBAAqB,CAAC,KAAwB,EAAA;AAC1D,IAAA,QACI,mBAAmB,CAAC,KAAK,CAAC,OAAO,CAAC;AAClC,QAAA,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,KACnB,cAAc,CAAC,KAAK,CAAC,IAA0B,CAAC,CAAC,CACpD;AAET;AAEM,SAAU,aAAa,CAAC,KAAwB,EAAA;IAClD,OAAO,OAAO,CAAC,qBAAqB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC;AAClE;;;;"}

View File

@@ -0,0 +1,13 @@
import { transformProps } from './keys-transform.mjs';
import { scaleCorrectors } from '../../projection/styles/scale-correction.mjs';
export { addScaleCorrector } from '../../projection/styles/scale-correction.mjs';
function isForcedMotionValue(key, { layout, layoutId }) {
return (transformProps.has(key) ||
key.startsWith("origin") ||
((layout || layoutId !== undefined) &&
(!!scaleCorrectors[key] || key === "opacity")));
}
export { isForcedMotionValue, scaleCorrectors };
//# sourceMappingURL=is-forced-motion-value.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-forced-motion-value.mjs","sources":["../../../../src/render/utils/is-forced-motion-value.ts"],"sourcesContent":["import { transformProps } from \"./keys-transform\"\nimport type { MotionNodeOptions } from \"../../node/types\"\nimport {\n scaleCorrectors,\n addScaleCorrector,\n} from \"../../projection/styles/scale-correction\"\n\nexport { scaleCorrectors, addScaleCorrector }\n\nexport function isForcedMotionValue(\n key: string,\n { layout, layoutId }: MotionNodeOptions\n) {\n return (\n transformProps.has(key) ||\n key.startsWith(\"origin\") ||\n ((layout || layoutId !== undefined) &&\n (!!scaleCorrectors[key] || key === \"opacity\"))\n )\n}\n"],"names":[],"mappings":";;;;AASM,SAAU,mBAAmB,CAC/B,GAAW,EACX,EAAE,MAAM,EAAE,QAAQ,EAAqB,EAAA;AAEvC,IAAA,QACI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;AACvB,QAAA,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC;AACxB,SAAC,CAAC,MAAM,IAAI,QAAQ,KAAK,SAAS;AAC9B,aAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,SAAS,CAAC,CAAC;AAE1D;;;;"}

View File

@@ -0,0 +1,6 @@
const isKeyframesTarget = (v) => {
return Array.isArray(v);
};
export { isKeyframesTarget };
//# sourceMappingURL=is-keyframes-target.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-keyframes-target.mjs","sources":["../../../../src/render/utils/is-keyframes-target.ts"],"sourcesContent":["import type { UnresolvedValueKeyframe, ValueKeyframesDefinition } from \"../../animation/types\"\n\nexport const isKeyframesTarget = (\n v: ValueKeyframesDefinition\n): v is UnresolvedValueKeyframe[] => {\n return Array.isArray(v)\n}\n"],"names":[],"mappings":"AAEO,MAAM,iBAAiB,GAAG,CAC7B,CAA2B,KACK;AAChC,IAAA,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3B;;;;"}

View File

@@ -0,0 +1,9 @@
/**
* Decides if the supplied variable is variant label
*/
function isVariantLabel(v) {
return typeof v === "string" || Array.isArray(v);
}
export { isVariantLabel };
//# sourceMappingURL=is-variant-label.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-variant-label.mjs","sources":["../../../../src/render/utils/is-variant-label.ts"],"sourcesContent":["/**\n * Decides if the supplied variable is variant label\n */\nexport function isVariantLabel(v: unknown): v is string | string[] {\n return typeof v === \"string\" || Array.isArray(v)\n}\n"],"names":[],"mappings":"AAAA;;AAEG;AACG,SAAU,cAAc,CAAC,CAAU,EAAA;IACrC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AACpD;;;;"}

View File

@@ -0,0 +1,14 @@
import { transformPropOrder } from './keys-transform.mjs';
const positionalKeys = new Set([
"width",
"height",
"top",
"left",
"right",
"bottom",
...transformPropOrder,
]);
export { positionalKeys };
//# sourceMappingURL=keys-position.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"keys-position.mjs","sources":["../../../../src/render/utils/keys-position.ts"],"sourcesContent":["import { transformPropOrder } from \"./keys-transform\"\n\nexport const positionalKeys = new Set([\n \"width\",\n \"height\",\n \"top\",\n \"left\",\n \"right\",\n \"bottom\",\n ...transformPropOrder,\n])\n"],"names":[],"mappings":";;AAEO,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAClC,OAAO;IACP,QAAQ;IACR,KAAK;IACL,MAAM;IACN,OAAO;IACP,QAAQ;AACR,IAAA,GAAG,kBAAkB;AACxB,CAAA;;;;"}

View File

@@ -0,0 +1,29 @@
/**
* Generate a list of every possible transform key.
*/
const transformPropOrder = [
"transformPerspective",
"x",
"y",
"z",
"translateX",
"translateY",
"translateZ",
"scale",
"scaleX",
"scaleY",
"rotate",
"rotateX",
"rotateY",
"rotateZ",
"skew",
"skewX",
"skewY",
];
/**
* A quick lookup for transform props.
*/
const transformProps = /*@__PURE__*/ (() => new Set(transformPropOrder))();
export { transformPropOrder, transformProps };
//# sourceMappingURL=keys-transform.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"keys-transform.mjs","sources":["../../../../src/render/utils/keys-transform.ts"],"sourcesContent":["/**\n * Generate a list of every possible transform key.\n */\nexport const transformPropOrder = [\n \"transformPerspective\",\n \"x\",\n \"y\",\n \"z\",\n \"translateX\",\n \"translateY\",\n \"translateZ\",\n \"scale\",\n \"scaleX\",\n \"scaleY\",\n \"rotate\",\n \"rotateX\",\n \"rotateY\",\n \"rotateZ\",\n \"skew\",\n \"skewX\",\n \"skewY\",\n]\n\n/**\n * A quick lookup for transform props.\n */\nexport const transformProps = /*@__PURE__*/ (() =>\n new Set(transformPropOrder))()\n"],"names":[],"mappings":"AAAA;;AAEG;AACI,MAAM,kBAAkB,GAAG;IAC9B,sBAAsB;IACtB,GAAG;IACH,GAAG;IACH,GAAG;IACH,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,SAAS;IACT,SAAS;IACT,MAAM;IACN,OAAO;IACP,OAAO;;AAGX;;AAEG;AACI,MAAM,cAAc,iBAAiB,CAAC,MACzC,IAAI,GAAG,CAAC,kBAAkB,CAAC;;;;"}

View File

@@ -0,0 +1,56 @@
import { motionValue } from '../../value/index.mjs';
import { isMotionValue } from '../../value/utils/is-motion-value.mjs';
/**
* Updates motion values from props changes.
* Uses `any` type for element to avoid circular dependencies with VisualElement.
*/
function updateMotionValuesFromProps(element, next, prev) {
for (const key in next) {
const nextValue = next[key];
const prevValue = prev[key];
if (isMotionValue(nextValue)) {
/**
* If this is a motion value found in props or style, we want to add it
* to our visual element's motion value map.
*/
element.addValue(key, nextValue);
}
else if (isMotionValue(prevValue)) {
/**
* If we're swapping from a motion value to a static value,
* create a new motion value from that
*/
element.addValue(key, motionValue(nextValue, { owner: element }));
}
else if (prevValue !== nextValue) {
/**
* If this is a flat value that has changed, update the motion value
* or create one if it doesn't exist. We only want to do this if we're
* not handling the value with our animation state.
*/
if (element.hasValue(key)) {
const existingValue = element.getValue(key);
if (existingValue.liveStyle === true) {
existingValue.jump(nextValue);
}
else if (!existingValue.hasAnimated) {
existingValue.set(nextValue);
}
}
else {
const latestValue = element.getStaticValue(key);
element.addValue(key, motionValue(latestValue !== undefined ? latestValue : nextValue, { owner: element }));
}
}
}
// Handle removed values
for (const key in prev) {
if (next[key] === undefined)
element.removeValue(key);
}
return next;
}
export { updateMotionValuesFromProps };
//# sourceMappingURL=motion-values.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"motion-values.mjs","sources":["../../../../src/render/utils/motion-values.ts"],"sourcesContent":["import { motionValue } from \"../../value\"\nimport { isMotionValue } from \"../../value/utils/is-motion-value\"\n\ntype MotionStyleLike = Record<string, any>\n\n/**\n * Updates motion values from props changes.\n * Uses `any` type for element to avoid circular dependencies with VisualElement.\n */\nexport function updateMotionValuesFromProps(\n element: any,\n next: MotionStyleLike,\n prev: MotionStyleLike\n) {\n for (const key in next) {\n const nextValue = next[key]\n const prevValue = prev[key]\n\n if (isMotionValue(nextValue)) {\n /**\n * If this is a motion value found in props or style, we want to add it\n * to our visual element's motion value map.\n */\n element.addValue(key, nextValue)\n } else if (isMotionValue(prevValue)) {\n /**\n * If we're swapping from a motion value to a static value,\n * create a new motion value from that\n */\n element.addValue(key, motionValue(nextValue, { owner: element }))\n } else if (prevValue !== nextValue) {\n /**\n * If this is a flat value that has changed, update the motion value\n * or create one if it doesn't exist. We only want to do this if we're\n * not handling the value with our animation state.\n */\n if (element.hasValue(key)) {\n const existingValue = element.getValue(key)!\n\n if (existingValue.liveStyle === true) {\n existingValue.jump(nextValue)\n } else if (!existingValue.hasAnimated) {\n existingValue.set(nextValue)\n }\n } else {\n const latestValue = element.getStaticValue(key)\n element.addValue(\n key,\n motionValue(\n latestValue !== undefined ? latestValue : nextValue,\n { owner: element }\n )\n )\n }\n }\n }\n\n // Handle removed values\n for (const key in prev) {\n if (next[key] === undefined) element.removeValue(key)\n }\n\n return next\n}\n"],"names":[],"mappings":";;;AAKA;;;AAGG;SACa,2BAA2B,CACvC,OAAY,EACZ,IAAqB,EACrB,IAAqB,EAAA;AAErB,IAAA,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;AACpB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC;AAC3B,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC;AAE3B,QAAA,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE;AAC1B;;;AAGG;AACH,YAAA,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;QACpC;AAAO,aAAA,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE;AACjC;;;AAGG;AACH,YAAA,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACrE;AAAO,aAAA,IAAI,SAAS,KAAK,SAAS,EAAE;AAChC;;;;AAIG;AACH,YAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;gBACvB,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAE;AAE5C,gBAAA,IAAI,aAAa,CAAC,SAAS,KAAK,IAAI,EAAE;AAClC,oBAAA,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC;gBACjC;AAAO,qBAAA,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE;AACnC,oBAAA,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;gBAChC;YACJ;iBAAO;gBACH,MAAM,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC;gBAC/C,OAAO,CAAC,QAAQ,CACZ,GAAG,EACH,WAAW,CACP,WAAW,KAAK,SAAS,GAAG,WAAW,GAAG,SAAS,EACnD,EAAE,KAAK,EAAE,OAAO,EAAE,CACrB,CACJ;YACL;QACJ;IACJ;;AAGA,IAAA,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;AACpB,QAAA,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,SAAS;AAAE,YAAA,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC;IACzD;AAEA,IAAA,OAAO,IAAI;AACf;;;;"}

View File

@@ -0,0 +1,20 @@
import { hasReducedMotionListener, prefersReducedMotion } from './state.mjs';
const isBrowser = typeof window !== "undefined";
function initPrefersReducedMotion() {
hasReducedMotionListener.current = true;
if (!isBrowser)
return;
if (window.matchMedia) {
const motionMediaQuery = window.matchMedia("(prefers-reduced-motion)");
const setReducedMotionPreferences = () => (prefersReducedMotion.current = motionMediaQuery.matches);
motionMediaQuery.addEventListener("change", setReducedMotionPreferences);
setReducedMotionPreferences();
}
else {
prefersReducedMotion.current = false;
}
}
export { hasReducedMotionListener, initPrefersReducedMotion, prefersReducedMotion };
//# sourceMappingURL=index.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":["../../../../../src/render/utils/reduced-motion/index.ts"],"sourcesContent":["import { hasReducedMotionListener, prefersReducedMotion } from \"./state\"\n\nconst isBrowser = typeof window !== \"undefined\"\n\nexport function initPrefersReducedMotion() {\n hasReducedMotionListener.current = true\n if (!isBrowser) return\n\n if (window.matchMedia) {\n const motionMediaQuery = window.matchMedia(\"(prefers-reduced-motion)\")\n\n const setReducedMotionPreferences = () =>\n (prefersReducedMotion.current = motionMediaQuery.matches)\n\n motionMediaQuery.addEventListener(\"change\", setReducedMotionPreferences)\n\n setReducedMotionPreferences()\n } else {\n prefersReducedMotion.current = false\n }\n}\n\nexport { prefersReducedMotion, hasReducedMotionListener }\n"],"names":[],"mappings":";;AAEA,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK,WAAW;SAE/B,wBAAwB,GAAA;AACpC,IAAA,wBAAwB,CAAC,OAAO,GAAG,IAAI;AACvC,IAAA,IAAI,CAAC,SAAS;QAAE;AAEhB,IAAA,IAAI,MAAM,CAAC,UAAU,EAAE;QACnB,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,0BAA0B,CAAC;AAEtE,QAAA,MAAM,2BAA2B,GAAG,OAC/B,oBAAoB,CAAC,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC;AAE7D,QAAA,gBAAgB,CAAC,gBAAgB,CAAC,QAAQ,EAAE,2BAA2B,CAAC;AAExE,QAAA,2BAA2B,EAAE;IACjC;SAAO;AACH,QAAA,oBAAoB,CAAC,OAAO,GAAG,KAAK;IACxC;AACJ;;;;"}

View File

@@ -0,0 +1,6 @@
// Does this device prefer reduced motion? Returns `null` server-side.
const prefersReducedMotion = { current: null };
const hasReducedMotionListener = { current: false };
export { hasReducedMotionListener, prefersReducedMotion };
//# sourceMappingURL=state.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"state.mjs","sources":["../../../../../src/render/utils/reduced-motion/state.ts"],"sourcesContent":["interface ReducedMotionState {\n current: boolean | null\n}\n\n// Does this device prefer reduced motion? Returns `null` server-side.\nexport const prefersReducedMotion: ReducedMotionState = { current: null }\n\nexport const hasReducedMotionListener = { current: false }\n"],"names":[],"mappings":"AAIA;MACa,oBAAoB,GAAuB,EAAE,OAAO,EAAE,IAAI;MAE1D,wBAAwB,GAAG,EAAE,OAAO,EAAE,KAAK;;;;"}

View File

@@ -0,0 +1,9 @@
import { resolveVariantFromProps } from './resolve-variants.mjs';
function resolveVariant(visualElement, definition, custom) {
const props = visualElement.getProps();
return resolveVariantFromProps(props, definition, custom !== undefined ? custom : props.custom, visualElement);
}
export { resolveVariant };
//# sourceMappingURL=resolve-dynamic-variants.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"resolve-dynamic-variants.mjs","sources":["../../../../src/render/utils/resolve-dynamic-variants.ts"],"sourcesContent":["import type {\n AnimationDefinition,\n TargetAndTransition,\n TargetResolver,\n} from \"../../node/types\"\nimport { resolveVariantFromProps } from \"./resolve-variants\"\n\n/**\n * Resolves a variant if it's a variant resolver.\n * Uses `any` type for visualElement to avoid circular dependencies.\n */\nexport function resolveVariant(\n visualElement: any,\n definition?: TargetAndTransition | TargetResolver,\n custom?: any\n): TargetAndTransition\nexport function resolveVariant(\n visualElement: any,\n definition?: AnimationDefinition,\n custom?: any\n): TargetAndTransition | undefined\nexport function resolveVariant(\n visualElement: any,\n definition?: AnimationDefinition,\n custom?: any\n) {\n const props = visualElement.getProps()\n return resolveVariantFromProps(\n props,\n definition,\n custom !== undefined ? custom : props.custom,\n visualElement\n )\n}\n"],"names":[],"mappings":";;SAqBgB,cAAc,CAC1B,aAAkB,EAClB,UAAgC,EAChC,MAAY,EAAA;AAEZ,IAAA,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,EAAE;IACtC,OAAO,uBAAuB,CAC1B,KAAK,EACL,UAAU,EACV,MAAM,KAAK,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,EAC5C,aAAa,CAChB;AACL;;;;"}

View File

@@ -0,0 +1,37 @@
function getValueState(visualElement) {
const state = [{}, {}];
visualElement?.values.forEach((value, key) => {
state[0][key] = value.get();
state[1][key] = value.getVelocity();
});
return state;
}
function resolveVariantFromProps(props, definition, custom, visualElement) {
/**
* If the variant definition is a function, resolve.
*/
if (typeof definition === "function") {
const [current, velocity] = getValueState(visualElement);
definition = definition(custom !== undefined ? custom : props.custom, current, velocity);
}
/**
* If the variant definition is a variant label, or
* the function returned a variant label, resolve.
*/
if (typeof definition === "string") {
definition = props.variants && props.variants[definition];
}
/**
* At this point we've resolved both functions and variant labels,
* but the resolved variant label might itself have been a function.
* If so, resolve. This can only have returned a valid target object.
*/
if (typeof definition === "function") {
const [current, velocity] = getValueState(visualElement);
definition = definition(custom !== undefined ? custom : props.custom, current, velocity);
}
return definition;
}
export { resolveVariantFromProps };
//# sourceMappingURL=resolve-variants.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"resolve-variants.mjs","sources":["../../../../src/render/utils/resolve-variants.ts"],"sourcesContent":["import type {\n AnimationDefinition,\n MotionNodeOptions,\n TargetAndTransition,\n TargetResolver,\n} from \"../../node/types\"\nimport type { ResolvedValues } from \"../types\"\n\nfunction getValueState(visualElement?: any): [ResolvedValues, ResolvedValues] {\n const state: [ResolvedValues, ResolvedValues] = [{}, {}]\n\n visualElement?.values.forEach((value: any, key: string) => {\n state[0][key] = value.get()\n state[1][key] = value.getVelocity()\n })\n\n return state\n}\n\nexport function resolveVariantFromProps(\n props: MotionNodeOptions,\n definition: TargetAndTransition | TargetResolver,\n custom?: any,\n visualElement?: any\n): TargetAndTransition\nexport function resolveVariantFromProps(\n props: MotionNodeOptions,\n definition?: AnimationDefinition,\n custom?: any,\n visualElement?: any\n): undefined | TargetAndTransition\nexport function resolveVariantFromProps(\n props: MotionNodeOptions,\n definition?: AnimationDefinition,\n custom?: any,\n visualElement?: any\n) {\n /**\n * If the variant definition is a function, resolve.\n */\n if (typeof definition === \"function\") {\n const [current, velocity] = getValueState(visualElement)\n definition = definition(\n custom !== undefined ? custom : props.custom,\n current,\n velocity\n )\n }\n\n /**\n * If the variant definition is a variant label, or\n * the function returned a variant label, resolve.\n */\n if (typeof definition === \"string\") {\n definition = props.variants && props.variants[definition]\n }\n\n /**\n * At this point we've resolved both functions and variant labels,\n * but the resolved variant label might itself have been a function.\n * If so, resolve. This can only have returned a valid target object.\n */\n if (typeof definition === \"function\") {\n const [current, velocity] = getValueState(visualElement)\n definition = definition(\n custom !== undefined ? custom : props.custom,\n current,\n velocity\n )\n }\n\n return definition\n}\n"],"names":[],"mappings":"AAQA,SAAS,aAAa,CAAC,aAAmB,EAAA;AACtC,IAAA,MAAM,KAAK,GAAqC,CAAC,EAAE,EAAE,EAAE,CAAC;IAExD,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,KAAU,EAAE,GAAW,KAAI;QACtD,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE;QAC3B,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE;AACvC,IAAA,CAAC,CAAC;AAEF,IAAA,OAAO,KAAK;AAChB;AAcM,SAAU,uBAAuB,CACnC,KAAwB,EACxB,UAAgC,EAChC,MAAY,EACZ,aAAmB,EAAA;AAEnB;;AAEG;AACH,IAAA,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE;QAClC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,aAAa,CAAC,aAAa,CAAC;QACxD,UAAU,GAAG,UAAU,CACnB,MAAM,KAAK,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,EAC5C,OAAO,EACP,QAAQ,CACX;IACL;AAEA;;;AAGG;AACH,IAAA,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;QAChC,UAAU,GAAG,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;IAC7D;AAEA;;;;AAIG;AACH,IAAA,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE;QAClC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,aAAa,CAAC,aAAa,CAAC;QACxD,UAAU,GAAG,UAAU,CACnB,MAAM,KAAK,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,EAC5C,OAAO,EACP,QAAQ,CACX;IACL;AAEA,IAAA,OAAO,UAAU;AACrB;;;;"}

View File

@@ -0,0 +1,32 @@
import { motionValue } from '../../value/index.mjs';
import { resolveVariant } from './resolve-dynamic-variants.mjs';
import { isKeyframesTarget } from './is-keyframes-target.mjs';
/**
* Set VisualElement's MotionValue, creating a new MotionValue for it if
* it doesn't exist.
*/
function setMotionValue(visualElement, key, value) {
if (visualElement.hasValue(key)) {
visualElement.getValue(key).set(value);
}
else {
visualElement.addValue(key, motionValue(value));
}
}
function resolveFinalValueInKeyframes(v) {
// TODO maybe throw if v.length - 1 is placeholder token?
return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
}
function setTarget(visualElement, definition) {
const resolved = resolveVariant(visualElement, definition);
let { transitionEnd = {}, transition = {}, ...target } = resolved || {};
target = { ...target, ...transitionEnd };
for (const key in target) {
const value = resolveFinalValueInKeyframes(target[key]);
setMotionValue(visualElement, key, value);
}
}
export { setTarget };
//# sourceMappingURL=setters.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"setters.mjs","sources":["../../../../src/render/utils/setters.ts"],"sourcesContent":["import { motionValue } from \"../../value\"\nimport { resolveVariant } from \"./resolve-dynamic-variants\"\nimport { isKeyframesTarget } from \"./is-keyframes-target\"\nimport type { AnimationDefinition } from \"../../node/types\"\nimport type {\n AnyResolvedKeyframe,\n UnresolvedValueKeyframe,\n ValueKeyframesDefinition,\n} from \"../../animation/types\"\nimport type { VisualElement } from \"../VisualElement\"\n\n/**\n * Set VisualElement's MotionValue, creating a new MotionValue for it if\n * it doesn't exist.\n */\nfunction setMotionValue(\n visualElement: VisualElement,\n key: string,\n value: AnyResolvedKeyframe\n) {\n if (visualElement.hasValue(key)) {\n visualElement.getValue(key)!.set(value)\n } else {\n visualElement.addValue(key, motionValue(value))\n }\n}\n\nfunction resolveFinalValueInKeyframes(\n v: ValueKeyframesDefinition\n): UnresolvedValueKeyframe {\n // TODO maybe throw if v.length - 1 is placeholder token?\n return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v\n}\n\nexport function setTarget(\n visualElement: VisualElement,\n definition: AnimationDefinition\n) {\n const resolved = resolveVariant(visualElement, definition)\n let { transitionEnd = {}, transition = {}, ...target } = resolved || {}\n\n target = { ...target, ...transitionEnd }\n\n for (const key in target) {\n const value = resolveFinalValueInKeyframes(\n target[key as keyof typeof target] as any\n )\n setMotionValue(visualElement, key, value as AnyResolvedKeyframe)\n }\n}\n"],"names":[],"mappings":";;;;AAWA;;;AAGG;AACH,SAAS,cAAc,CACnB,aAA4B,EAC5B,GAAW,EACX,KAA0B,EAAA;AAE1B,IAAA,IAAI,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAC7B,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAE,CAAC,GAAG,CAAC,KAAK,CAAC;IAC3C;SAAO;QACH,aAAa,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IACnD;AACJ;AAEA,SAAS,4BAA4B,CACjC,CAA2B,EAAA;;IAG3B,OAAO,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC1D;AAEM,SAAU,SAAS,CACrB,aAA4B,EAC5B,UAA+B,EAAA;IAE/B,MAAM,QAAQ,GAAG,cAAc,CAAC,aAAa,EAAE,UAAU,CAAC;AAC1D,IAAA,IAAI,EAAE,aAAa,GAAG,EAAE,EAAE,UAAU,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,GAAG,QAAQ,IAAI,EAAE;IAEvE,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,GAAG,aAAa,EAAE;AAExC,IAAA,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE;QACtB,MAAM,KAAK,GAAG,4BAA4B,CACtC,MAAM,CAAC,GAA0B,CAAQ,CAC5C;AACD,QAAA,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,KAA4B,CAAC;IACpE;AACJ;;;;"}

View File

@@ -0,0 +1,15 @@
function shallowCompare(next, prev) {
if (!Array.isArray(prev))
return false;
const prevLength = prev.length;
if (prevLength !== next.length)
return false;
for (let i = 0; i < prevLength; i++) {
if (prev[i] !== next[i])
return false;
}
return true;
}
export { shallowCompare };
//# sourceMappingURL=shallow-compare.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"shallow-compare.mjs","sources":["../../../../src/render/utils/shallow-compare.ts"],"sourcesContent":["export function shallowCompare(next: any[], prev: any[] | null) {\n if (!Array.isArray(prev)) return false\n\n const prevLength = prev.length\n\n if (prevLength !== next.length) return false\n\n for (let i = 0; i < prevLength; i++) {\n if (prev[i] !== next[i]) return false\n }\n\n return true\n}\n"],"names":[],"mappings":"AAAM,SAAU,cAAc,CAAC,IAAW,EAAE,IAAkB,EAAA;AAC1D,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;AAAE,QAAA,OAAO,KAAK;AAEtC,IAAA,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM;AAE9B,IAAA,IAAI,UAAU,KAAK,IAAI,CAAC,MAAM;AAAE,QAAA,OAAO,KAAK;AAE5C,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE;QACjC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;AAAE,YAAA,OAAO,KAAK;IACzC;AAEA,IAAA,OAAO,IAAI;AACf;;;;"}

View File

@@ -0,0 +1,13 @@
const variantPriorityOrder = [
"animate",
"whileInView",
"whileFocus",
"whileHover",
"whileTap",
"whileDrag",
"exit",
];
const variantProps = ["initial", ...variantPriorityOrder];
export { variantPriorityOrder, variantProps };
//# sourceMappingURL=variant-props.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"variant-props.mjs","sources":["../../../../src/render/utils/variant-props.ts"],"sourcesContent":["import type { AnimationType } from \"../types\"\n\nexport const variantPriorityOrder: AnimationType[] = [\n \"animate\",\n \"whileInView\",\n \"whileFocus\",\n \"whileHover\",\n \"whileTap\",\n \"whileDrag\",\n \"exit\",\n]\n\nexport const variantProps = [\"initial\", ...variantPriorityOrder]\n"],"names":[],"mappings":"AAEO,MAAM,oBAAoB,GAAoB;IACjD,SAAS;IACT,aAAa;IACb,YAAY;IACZ,YAAY;IACZ,UAAU;IACV,WAAW;IACX,MAAM;;AAGH,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,GAAG,oBAAoB;;;;"}