1849 lines
47 KiB
JavaScript
1849 lines
47 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
const defu = require('defu');
|
||
|
|
const vue = require('vue');
|
||
|
|
const core = require('@vueuse/core');
|
||
|
|
const shared = require('@vueuse/shared');
|
||
|
|
const sync = require('framesync');
|
||
|
|
const popmotion = require('popmotion');
|
||
|
|
const styleValueTypes = require('style-value-types');
|
||
|
|
|
||
|
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
||
|
|
|
||
|
|
const defu__default = /*#__PURE__*/_interopDefaultCompat(defu);
|
||
|
|
const sync__default = /*#__PURE__*/_interopDefaultCompat(sync);
|
||
|
|
|
||
|
|
const motionState = {};
|
||
|
|
|
||
|
|
var __defProp$1 = Object.defineProperty;
|
||
|
|
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||
|
|
var __publicField$1 = (obj, key, value) => {
|
||
|
|
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
||
|
|
return value;
|
||
|
|
};
|
||
|
|
class SubscriptionManager {
|
||
|
|
constructor() {
|
||
|
|
__publicField$1(this, "subscriptions", /* @__PURE__ */ new Set());
|
||
|
|
}
|
||
|
|
add(handler) {
|
||
|
|
this.subscriptions.add(handler);
|
||
|
|
return () => this.subscriptions.delete(handler);
|
||
|
|
}
|
||
|
|
notify(a, b, c) {
|
||
|
|
if (!this.subscriptions.size)
|
||
|
|
return;
|
||
|
|
for (const handler of this.subscriptions)
|
||
|
|
handler(a, b, c);
|
||
|
|
}
|
||
|
|
clear() {
|
||
|
|
this.subscriptions.clear();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var __defProp = Object.defineProperty;
|
||
|
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||
|
|
var __publicField = (obj, key, value) => {
|
||
|
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
||
|
|
return value;
|
||
|
|
};
|
||
|
|
function isFloat(value) {
|
||
|
|
return !Number.isNaN(Number.parseFloat(value));
|
||
|
|
}
|
||
|
|
class MotionValue {
|
||
|
|
/**
|
||
|
|
* init - The initiating value
|
||
|
|
* config - Optional configuration options
|
||
|
|
*/
|
||
|
|
constructor(init) {
|
||
|
|
/**
|
||
|
|
* The current state of the `MotionValue`.
|
||
|
|
*/
|
||
|
|
__publicField(this, "current");
|
||
|
|
/**
|
||
|
|
* The previous state of the `MotionValue`.
|
||
|
|
*/
|
||
|
|
__publicField(this, "prev");
|
||
|
|
/**
|
||
|
|
* Duration, in milliseconds, since last updating frame.
|
||
|
|
*/
|
||
|
|
__publicField(this, "timeDelta", 0);
|
||
|
|
/**
|
||
|
|
* Timestamp of the last time this `MotionValue` was updated.
|
||
|
|
*/
|
||
|
|
__publicField(this, "lastUpdated", 0);
|
||
|
|
/**
|
||
|
|
* Functions to notify when the `MotionValue` updates.
|
||
|
|
*/
|
||
|
|
__publicField(this, "updateSubscribers", new SubscriptionManager());
|
||
|
|
/**
|
||
|
|
* A reference to the currently-controlling Popmotion animation
|
||
|
|
*/
|
||
|
|
__publicField(this, "stopAnimation");
|
||
|
|
/**
|
||
|
|
* Tracks whether this value can output a velocity.
|
||
|
|
*/
|
||
|
|
__publicField(this, "canTrackVelocity", false);
|
||
|
|
/**
|
||
|
|
* Update and notify `MotionValue` subscribers.
|
||
|
|
*
|
||
|
|
* @param v
|
||
|
|
* @param render
|
||
|
|
*/
|
||
|
|
__publicField(this, "updateAndNotify", (v) => {
|
||
|
|
this.prev = this.current;
|
||
|
|
this.current = v;
|
||
|
|
const { delta, timestamp } = sync.getFrameData();
|
||
|
|
if (this.lastUpdated !== timestamp) {
|
||
|
|
this.timeDelta = delta;
|
||
|
|
this.lastUpdated = timestamp;
|
||
|
|
}
|
||
|
|
sync__default.postRender(this.scheduleVelocityCheck);
|
||
|
|
this.updateSubscribers.notify(this.current);
|
||
|
|
});
|
||
|
|
/**
|
||
|
|
* Schedule a velocity check for the next frame.
|
||
|
|
*/
|
||
|
|
__publicField(this, "scheduleVelocityCheck", () => sync__default.postRender(this.velocityCheck));
|
||
|
|
/**
|
||
|
|
* Updates `prev` with `current` if the value hasn't been updated this frame.
|
||
|
|
* This ensures velocity calculations return `0`.
|
||
|
|
*/
|
||
|
|
__publicField(this, "velocityCheck", ({ timestamp }) => {
|
||
|
|
if (!this.canTrackVelocity)
|
||
|
|
this.canTrackVelocity = isFloat(this.current);
|
||
|
|
if (timestamp !== this.lastUpdated)
|
||
|
|
this.prev = this.current;
|
||
|
|
});
|
||
|
|
this.prev = this.current = init;
|
||
|
|
this.canTrackVelocity = isFloat(this.current);
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Adds a function that will be notified when the `MotionValue` is updated.
|
||
|
|
*
|
||
|
|
* It returns a function that, when called, will cancel the subscription.
|
||
|
|
*/
|
||
|
|
onChange(subscription) {
|
||
|
|
return this.updateSubscribers.add(subscription);
|
||
|
|
}
|
||
|
|
clearListeners() {
|
||
|
|
this.updateSubscribers.clear();
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Sets the state of the `MotionValue`.
|
||
|
|
*
|
||
|
|
* @param v
|
||
|
|
* @param render
|
||
|
|
*/
|
||
|
|
set(v) {
|
||
|
|
this.updateAndNotify(v);
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Returns the latest state of `MotionValue`
|
||
|
|
*
|
||
|
|
* @returns - The latest state of `MotionValue`
|
||
|
|
*/
|
||
|
|
get() {
|
||
|
|
return this.current;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Get previous value.
|
||
|
|
*
|
||
|
|
* @returns - The previous latest state of `MotionValue`
|
||
|
|
*/
|
||
|
|
getPrevious() {
|
||
|
|
return this.prev;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Returns the latest velocity of `MotionValue`
|
||
|
|
*
|
||
|
|
* @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical.
|
||
|
|
*/
|
||
|
|
getVelocity() {
|
||
|
|
return this.canTrackVelocity ? popmotion.velocityPerSecond(Number.parseFloat(this.current) - Number.parseFloat(this.prev), this.timeDelta) : 0;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Registers a new animation to control this `MotionValue`. Only one
|
||
|
|
* animation can drive a `MotionValue` at one time.
|
||
|
|
*/
|
||
|
|
start(animation) {
|
||
|
|
this.stop();
|
||
|
|
return new Promise((resolve) => {
|
||
|
|
const { stop } = animation(resolve);
|
||
|
|
this.stopAnimation = stop;
|
||
|
|
}).then(() => this.clearAnimation());
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Stop the currently active animation.
|
||
|
|
*/
|
||
|
|
stop() {
|
||
|
|
if (this.stopAnimation)
|
||
|
|
this.stopAnimation();
|
||
|
|
this.clearAnimation();
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Returns `true` if this value is currently animating.
|
||
|
|
*/
|
||
|
|
isAnimating() {
|
||
|
|
return !!this.stopAnimation;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Clear the current animation reference.
|
||
|
|
*/
|
||
|
|
clearAnimation() {
|
||
|
|
this.stopAnimation = null;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Destroy and clean up subscribers to this `MotionValue`.
|
||
|
|
*/
|
||
|
|
destroy() {
|
||
|
|
this.updateSubscribers.clear();
|
||
|
|
this.stop();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function getMotionValue(init) {
|
||
|
|
return new MotionValue(init);
|
||
|
|
}
|
||
|
|
|
||
|
|
const { isArray } = Array;
|
||
|
|
function useMotionValues() {
|
||
|
|
const motionValues = vue.ref({});
|
||
|
|
const stop = (keys) => {
|
||
|
|
const destroyKey = (key) => {
|
||
|
|
if (!motionValues.value[key])
|
||
|
|
return;
|
||
|
|
motionValues.value[key].stop();
|
||
|
|
motionValues.value[key].destroy();
|
||
|
|
delete motionValues.value[key];
|
||
|
|
};
|
||
|
|
if (keys) {
|
||
|
|
if (isArray(keys)) {
|
||
|
|
keys.forEach(destroyKey);
|
||
|
|
} else {
|
||
|
|
destroyKey(keys);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
Object.keys(motionValues.value).forEach(destroyKey);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const get = (key, from, target) => {
|
||
|
|
if (motionValues.value[key])
|
||
|
|
return motionValues.value[key];
|
||
|
|
const motionValue = getMotionValue(from);
|
||
|
|
motionValue.onChange((v) => target[key] = v);
|
||
|
|
motionValues.value[key] = motionValue;
|
||
|
|
return motionValue;
|
||
|
|
};
|
||
|
|
shared.tryOnUnmounted(stop);
|
||
|
|
return {
|
||
|
|
motionValues,
|
||
|
|
get,
|
||
|
|
stop
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function isKeyframesTarget(v) {
|
||
|
|
return Array.isArray(v);
|
||
|
|
}
|
||
|
|
function underDampedSpring() {
|
||
|
|
return {
|
||
|
|
type: "spring",
|
||
|
|
stiffness: 500,
|
||
|
|
damping: 25,
|
||
|
|
restDelta: 0.5,
|
||
|
|
restSpeed: 10
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function criticallyDampedSpring(to) {
|
||
|
|
return {
|
||
|
|
type: "spring",
|
||
|
|
stiffness: 550,
|
||
|
|
damping: to === 0 ? 2 * Math.sqrt(550) : 30,
|
||
|
|
restDelta: 0.01,
|
||
|
|
restSpeed: 10
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function overDampedSpring(to) {
|
||
|
|
return {
|
||
|
|
type: "spring",
|
||
|
|
stiffness: 550,
|
||
|
|
damping: to === 0 ? 100 : 30,
|
||
|
|
restDelta: 0.01,
|
||
|
|
restSpeed: 10
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function linearTween() {
|
||
|
|
return {
|
||
|
|
type: "keyframes",
|
||
|
|
ease: "linear",
|
||
|
|
duration: 300
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function keyframes(values) {
|
||
|
|
return {
|
||
|
|
type: "keyframes",
|
||
|
|
duration: 800,
|
||
|
|
values
|
||
|
|
};
|
||
|
|
}
|
||
|
|
const defaultTransitions = {
|
||
|
|
default: overDampedSpring,
|
||
|
|
x: underDampedSpring,
|
||
|
|
y: underDampedSpring,
|
||
|
|
z: underDampedSpring,
|
||
|
|
rotate: underDampedSpring,
|
||
|
|
rotateX: underDampedSpring,
|
||
|
|
rotateY: underDampedSpring,
|
||
|
|
rotateZ: underDampedSpring,
|
||
|
|
scaleX: criticallyDampedSpring,
|
||
|
|
scaleY: criticallyDampedSpring,
|
||
|
|
scale: criticallyDampedSpring,
|
||
|
|
backgroundColor: linearTween,
|
||
|
|
color: linearTween,
|
||
|
|
opacity: linearTween
|
||
|
|
};
|
||
|
|
function getDefaultTransition(valueKey, to) {
|
||
|
|
let transitionFactory;
|
||
|
|
if (isKeyframesTarget(to)) {
|
||
|
|
transitionFactory = keyframes;
|
||
|
|
} else {
|
||
|
|
transitionFactory = defaultTransitions[valueKey] || defaultTransitions.default;
|
||
|
|
}
|
||
|
|
return { to, ...transitionFactory(to) };
|
||
|
|
}
|
||
|
|
|
||
|
|
const int = {
|
||
|
|
...styleValueTypes.number,
|
||
|
|
transform: Math.round
|
||
|
|
};
|
||
|
|
const valueTypes = {
|
||
|
|
// Color props
|
||
|
|
color: styleValueTypes.color,
|
||
|
|
backgroundColor: styleValueTypes.color,
|
||
|
|
outlineColor: styleValueTypes.color,
|
||
|
|
fill: styleValueTypes.color,
|
||
|
|
stroke: styleValueTypes.color,
|
||
|
|
// Border props
|
||
|
|
borderColor: styleValueTypes.color,
|
||
|
|
borderTopColor: styleValueTypes.color,
|
||
|
|
borderRightColor: styleValueTypes.color,
|
||
|
|
borderBottomColor: styleValueTypes.color,
|
||
|
|
borderLeftColor: styleValueTypes.color,
|
||
|
|
borderWidth: styleValueTypes.px,
|
||
|
|
borderTopWidth: styleValueTypes.px,
|
||
|
|
borderRightWidth: styleValueTypes.px,
|
||
|
|
borderBottomWidth: styleValueTypes.px,
|
||
|
|
borderLeftWidth: styleValueTypes.px,
|
||
|
|
borderRadius: styleValueTypes.px,
|
||
|
|
radius: styleValueTypes.px,
|
||
|
|
borderTopLeftRadius: styleValueTypes.px,
|
||
|
|
borderTopRightRadius: styleValueTypes.px,
|
||
|
|
borderBottomRightRadius: styleValueTypes.px,
|
||
|
|
borderBottomLeftRadius: styleValueTypes.px,
|
||
|
|
// Positioning props
|
||
|
|
width: styleValueTypes.px,
|
||
|
|
maxWidth: styleValueTypes.px,
|
||
|
|
height: styleValueTypes.px,
|
||
|
|
maxHeight: styleValueTypes.px,
|
||
|
|
size: styleValueTypes.px,
|
||
|
|
top: styleValueTypes.px,
|
||
|
|
right: styleValueTypes.px,
|
||
|
|
bottom: styleValueTypes.px,
|
||
|
|
left: styleValueTypes.px,
|
||
|
|
// Spacing props
|
||
|
|
padding: styleValueTypes.px,
|
||
|
|
paddingTop: styleValueTypes.px,
|
||
|
|
paddingRight: styleValueTypes.px,
|
||
|
|
paddingBottom: styleValueTypes.px,
|
||
|
|
paddingLeft: styleValueTypes.px,
|
||
|
|
margin: styleValueTypes.px,
|
||
|
|
marginTop: styleValueTypes.px,
|
||
|
|
marginRight: styleValueTypes.px,
|
||
|
|
marginBottom: styleValueTypes.px,
|
||
|
|
marginLeft: styleValueTypes.px,
|
||
|
|
// Transform props
|
||
|
|
rotate: styleValueTypes.degrees,
|
||
|
|
rotateX: styleValueTypes.degrees,
|
||
|
|
rotateY: styleValueTypes.degrees,
|
||
|
|
rotateZ: styleValueTypes.degrees,
|
||
|
|
scale: styleValueTypes.scale,
|
||
|
|
scaleX: styleValueTypes.scale,
|
||
|
|
scaleY: styleValueTypes.scale,
|
||
|
|
scaleZ: styleValueTypes.scale,
|
||
|
|
skew: styleValueTypes.degrees,
|
||
|
|
skewX: styleValueTypes.degrees,
|
||
|
|
skewY: styleValueTypes.degrees,
|
||
|
|
distance: styleValueTypes.px,
|
||
|
|
translateX: styleValueTypes.px,
|
||
|
|
translateY: styleValueTypes.px,
|
||
|
|
translateZ: styleValueTypes.px,
|
||
|
|
x: styleValueTypes.px,
|
||
|
|
y: styleValueTypes.px,
|
||
|
|
z: styleValueTypes.px,
|
||
|
|
perspective: styleValueTypes.px,
|
||
|
|
transformPerspective: styleValueTypes.px,
|
||
|
|
opacity: styleValueTypes.alpha,
|
||
|
|
originX: styleValueTypes.progressPercentage,
|
||
|
|
originY: styleValueTypes.progressPercentage,
|
||
|
|
originZ: styleValueTypes.px,
|
||
|
|
// Misc
|
||
|
|
zIndex: int,
|
||
|
|
filter: styleValueTypes.filter,
|
||
|
|
WebkitFilter: styleValueTypes.filter,
|
||
|
|
// SVG
|
||
|
|
fillOpacity: styleValueTypes.alpha,
|
||
|
|
strokeOpacity: styleValueTypes.alpha,
|
||
|
|
numOctaves: int
|
||
|
|
};
|
||
|
|
const getValueType = (key) => valueTypes[key];
|
||
|
|
function getValueAsType(value, type) {
|
||
|
|
return type && typeof value === "number" && type.transform ? type.transform(value) : value;
|
||
|
|
}
|
||
|
|
function getAnimatableNone(key, value) {
|
||
|
|
let defaultValueType = getValueType(key);
|
||
|
|
if (defaultValueType !== styleValueTypes.filter)
|
||
|
|
defaultValueType = styleValueTypes.complex;
|
||
|
|
return defaultValueType.getAnimatableNone ? defaultValueType.getAnimatableNone(value) : void 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
const easingLookup = {
|
||
|
|
linear: popmotion.linear,
|
||
|
|
easeIn: popmotion.easeIn,
|
||
|
|
easeInOut: popmotion.easeInOut,
|
||
|
|
easeOut: popmotion.easeOut,
|
||
|
|
circIn: popmotion.circIn,
|
||
|
|
circInOut: popmotion.circInOut,
|
||
|
|
circOut: popmotion.circOut,
|
||
|
|
backIn: popmotion.backIn,
|
||
|
|
backInOut: popmotion.backInOut,
|
||
|
|
backOut: popmotion.backOut,
|
||
|
|
anticipate: popmotion.anticipate,
|
||
|
|
bounceIn: popmotion.bounceIn,
|
||
|
|
bounceInOut: popmotion.bounceInOut,
|
||
|
|
bounceOut: popmotion.bounceOut
|
||
|
|
};
|
||
|
|
function easingDefinitionToFunction(definition) {
|
||
|
|
if (Array.isArray(definition)) {
|
||
|
|
const [x1, y1, x2, y2] = definition;
|
||
|
|
return popmotion.cubicBezier(x1, y1, x2, y2);
|
||
|
|
} else if (typeof definition === "string") {
|
||
|
|
return easingLookup[definition];
|
||
|
|
}
|
||
|
|
return definition;
|
||
|
|
}
|
||
|
|
function isEasingArray(ease) {
|
||
|
|
return Array.isArray(ease) && typeof ease[0] !== "number";
|
||
|
|
}
|
||
|
|
function isAnimatable(key, value) {
|
||
|
|
if (key === "zIndex")
|
||
|
|
return false;
|
||
|
|
if (typeof value === "number" || Array.isArray(value))
|
||
|
|
return true;
|
||
|
|
if (typeof value === "string" && styleValueTypes.complex.test(value) && !value.startsWith("url(")) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function hydrateKeyframes(options) {
|
||
|
|
if (Array.isArray(options.to) && options.to[0] === null) {
|
||
|
|
options.to = [...options.to];
|
||
|
|
options.to[0] = options.from;
|
||
|
|
}
|
||
|
|
return options;
|
||
|
|
}
|
||
|
|
function convertTransitionToAnimationOptions({ ease, times, delay, ...transition }) {
|
||
|
|
const options = { ...transition };
|
||
|
|
if (times)
|
||
|
|
options.offset = times;
|
||
|
|
if (ease) {
|
||
|
|
options.ease = isEasingArray(ease) ? ease.map(easingDefinitionToFunction) : easingDefinitionToFunction(ease);
|
||
|
|
}
|
||
|
|
if (delay)
|
||
|
|
options.elapsed = -delay;
|
||
|
|
return options;
|
||
|
|
}
|
||
|
|
function getPopmotionAnimationOptions(transition, options, key) {
|
||
|
|
if (Array.isArray(options.to)) {
|
||
|
|
if (!transition.duration)
|
||
|
|
transition.duration = 800;
|
||
|
|
}
|
||
|
|
hydrateKeyframes(options);
|
||
|
|
if (!isTransitionDefined(transition)) {
|
||
|
|
transition = {
|
||
|
|
...transition,
|
||
|
|
...getDefaultTransition(key, options.to)
|
||
|
|
};
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
...options,
|
||
|
|
...convertTransitionToAnimationOptions(transition)
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function isTransitionDefined({ delay, repeat, repeatType, repeatDelay, from, ...transition }) {
|
||
|
|
return !!Object.keys(transition).length;
|
||
|
|
}
|
||
|
|
function getValueTransition(transition, key) {
|
||
|
|
return transition[key] || transition.default || transition;
|
||
|
|
}
|
||
|
|
function getAnimation(key, value, target, transition, onComplete) {
|
||
|
|
const valueTransition = getValueTransition(transition, key);
|
||
|
|
let origin = valueTransition.from === null || valueTransition.from === void 0 ? value.get() : valueTransition.from;
|
||
|
|
const isTargetAnimatable = isAnimatable(key, target);
|
||
|
|
if (origin === "none" && isTargetAnimatable && typeof target === "string")
|
||
|
|
origin = getAnimatableNone(key, target);
|
||
|
|
const isOriginAnimatable = isAnimatable(key, origin);
|
||
|
|
function start(complete) {
|
||
|
|
const options = {
|
||
|
|
from: origin,
|
||
|
|
to: target,
|
||
|
|
velocity: transition.velocity ? transition.velocity : value.getVelocity(),
|
||
|
|
onUpdate: (v) => value.set(v)
|
||
|
|
};
|
||
|
|
return valueTransition.type === "inertia" || valueTransition.type === "decay" ? popmotion.inertia({ ...options, ...valueTransition }) : popmotion.animate({
|
||
|
|
...getPopmotionAnimationOptions(valueTransition, options, key),
|
||
|
|
onUpdate: (v) => {
|
||
|
|
options.onUpdate(v);
|
||
|
|
if (valueTransition.onUpdate)
|
||
|
|
valueTransition.onUpdate(v);
|
||
|
|
},
|
||
|
|
onComplete: () => {
|
||
|
|
if (onComplete)
|
||
|
|
onComplete();
|
||
|
|
if (complete)
|
||
|
|
complete();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function set(complete) {
|
||
|
|
value.set(target);
|
||
|
|
if (onComplete)
|
||
|
|
onComplete();
|
||
|
|
if (complete)
|
||
|
|
complete();
|
||
|
|
return { stop: () => {
|
||
|
|
} };
|
||
|
|
}
|
||
|
|
return !isOriginAnimatable || !isTargetAnimatable || valueTransition.type === false ? set : start;
|
||
|
|
}
|
||
|
|
|
||
|
|
function useMotionTransitions() {
|
||
|
|
const { motionValues, stop, get } = useMotionValues();
|
||
|
|
const push = (key, value, target, transition = {}, onComplete) => {
|
||
|
|
const from = target[key];
|
||
|
|
const motionValue = get(key, from, target);
|
||
|
|
if (transition && transition.immediate) {
|
||
|
|
motionValue.set(value);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const animation = getAnimation(key, motionValue, value, transition, onComplete);
|
||
|
|
motionValue.start(animation);
|
||
|
|
};
|
||
|
|
return { motionValues, stop, push };
|
||
|
|
}
|
||
|
|
|
||
|
|
function useMotionControls(motionProperties, variants = {}, { motionValues, push, stop } = useMotionTransitions()) {
|
||
|
|
const _variants = vue.unref(variants);
|
||
|
|
const isAnimating = vue.ref(false);
|
||
|
|
vue.watch(
|
||
|
|
motionValues,
|
||
|
|
(newVal) => {
|
||
|
|
isAnimating.value = Object.values(newVal).filter((value) => value.isAnimating()).length > 0;
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true,
|
||
|
|
deep: true
|
||
|
|
}
|
||
|
|
);
|
||
|
|
const getVariantFromKey = (variant) => {
|
||
|
|
if (!_variants || !_variants[variant])
|
||
|
|
throw new Error(`The variant ${variant} does not exist.`);
|
||
|
|
return _variants[variant];
|
||
|
|
};
|
||
|
|
const apply = (variant) => {
|
||
|
|
if (typeof variant === "string")
|
||
|
|
variant = getVariantFromKey(variant);
|
||
|
|
const animations = Object.entries(variant).map(([key, value]) => {
|
||
|
|
if (key === "transition")
|
||
|
|
return void 0;
|
||
|
|
return new Promise(
|
||
|
|
(resolve) => (
|
||
|
|
// @ts-expect-error - Fix errors later for typescript 5
|
||
|
|
push(key, value, motionProperties, variant.transition || getDefaultTransition(key, variant[key]), resolve)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
}).filter(Boolean);
|
||
|
|
async function waitForComplete() {
|
||
|
|
await Promise.all(animations);
|
||
|
|
variant.transition?.onComplete?.();
|
||
|
|
}
|
||
|
|
return Promise.all([waitForComplete()]);
|
||
|
|
};
|
||
|
|
const set = (variant) => {
|
||
|
|
const variantData = core.isObject(variant) ? variant : getVariantFromKey(variant);
|
||
|
|
Object.entries(variantData).forEach(([key, value]) => {
|
||
|
|
if (key === "transition")
|
||
|
|
return;
|
||
|
|
push(key, value, motionProperties, {
|
||
|
|
immediate: true
|
||
|
|
});
|
||
|
|
});
|
||
|
|
};
|
||
|
|
const leave = async (done) => {
|
||
|
|
let leaveVariant;
|
||
|
|
if (_variants) {
|
||
|
|
if (_variants.leave)
|
||
|
|
leaveVariant = _variants.leave;
|
||
|
|
if (!_variants.leave && _variants.initial)
|
||
|
|
leaveVariant = _variants.initial;
|
||
|
|
}
|
||
|
|
if (!leaveVariant) {
|
||
|
|
done();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
await apply(leaveVariant);
|
||
|
|
done();
|
||
|
|
};
|
||
|
|
return {
|
||
|
|
isAnimating,
|
||
|
|
apply,
|
||
|
|
set,
|
||
|
|
leave,
|
||
|
|
stop
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const isBrowser = typeof window !== "undefined";
|
||
|
|
const supportsPointerEvents = () => isBrowser && (window.onpointerdown === null || undefined.TEST);
|
||
|
|
const supportsTouchEvents = () => isBrowser && (window.ontouchstart === null || undefined.TEST);
|
||
|
|
const supportsMouseEvents = () => isBrowser && (window.onmousedown === null || undefined.TEST);
|
||
|
|
|
||
|
|
function registerEventListeners({ target, state, variants, apply }) {
|
||
|
|
const _variants = vue.unref(variants);
|
||
|
|
const hovered = vue.ref(false);
|
||
|
|
const tapped = vue.ref(false);
|
||
|
|
const focused = vue.ref(false);
|
||
|
|
const mutableKeys = vue.computed(() => {
|
||
|
|
let result = [...Object.keys(state.value || {})];
|
||
|
|
if (!_variants)
|
||
|
|
return result;
|
||
|
|
if (_variants.hovered)
|
||
|
|
result = [...result, ...Object.keys(_variants.hovered)];
|
||
|
|
if (_variants.tapped)
|
||
|
|
result = [...result, ...Object.keys(_variants.tapped)];
|
||
|
|
if (_variants.focused)
|
||
|
|
result = [...result, ...Object.keys(_variants.focused)];
|
||
|
|
return result;
|
||
|
|
});
|
||
|
|
const computedProperties = vue.computed(() => {
|
||
|
|
const result = {};
|
||
|
|
Object.assign(result, state.value);
|
||
|
|
if (hovered.value && _variants.hovered)
|
||
|
|
Object.assign(result, _variants.hovered);
|
||
|
|
if (tapped.value && _variants.tapped)
|
||
|
|
Object.assign(result, _variants.tapped);
|
||
|
|
if (focused.value && _variants.focused)
|
||
|
|
Object.assign(result, _variants.focused);
|
||
|
|
for (const key in result) {
|
||
|
|
if (!mutableKeys.value.includes(key))
|
||
|
|
delete result[key];
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
});
|
||
|
|
if (_variants.hovered) {
|
||
|
|
core.useEventListener(target, "mouseenter", () => hovered.value = true);
|
||
|
|
core.useEventListener(target, "mouseleave", () => {
|
||
|
|
hovered.value = false;
|
||
|
|
tapped.value = false;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
if (_variants.tapped) {
|
||
|
|
if (supportsMouseEvents()) {
|
||
|
|
core.useEventListener(target, "mousedown", () => tapped.value = true);
|
||
|
|
core.useEventListener(target, "mouseup", () => tapped.value = false);
|
||
|
|
}
|
||
|
|
if (supportsPointerEvents()) {
|
||
|
|
core.useEventListener(target, "pointerdown", () => tapped.value = true);
|
||
|
|
core.useEventListener(target, "pointerup", () => tapped.value = false);
|
||
|
|
}
|
||
|
|
if (supportsTouchEvents()) {
|
||
|
|
core.useEventListener(target, "touchstart", () => tapped.value = true);
|
||
|
|
core.useEventListener(target, "touchend", () => tapped.value = false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (_variants.focused) {
|
||
|
|
core.useEventListener(target, "focus", () => focused.value = true);
|
||
|
|
core.useEventListener(target, "blur", () => focused.value = false);
|
||
|
|
}
|
||
|
|
vue.watch([hovered, tapped, focused], () => {
|
||
|
|
apply(computedProperties.value);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function registerLifeCycleHooks({ set, target, variants, variant }) {
|
||
|
|
const _variants = vue.unref(variants);
|
||
|
|
vue.watch(
|
||
|
|
() => target,
|
||
|
|
() => {
|
||
|
|
if (!_variants)
|
||
|
|
return;
|
||
|
|
if (_variants.initial) {
|
||
|
|
set("initial");
|
||
|
|
variant.value = "initial";
|
||
|
|
}
|
||
|
|
if (_variants.enter)
|
||
|
|
variant.value = "enter";
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true,
|
||
|
|
flush: "pre"
|
||
|
|
}
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
function registerVariantsSync({ state, apply }) {
|
||
|
|
vue.watch(
|
||
|
|
state,
|
||
|
|
(newVal) => {
|
||
|
|
if (newVal)
|
||
|
|
apply(newVal);
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true
|
||
|
|
}
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
function registerVisibilityHooks({ target, variants, variant }) {
|
||
|
|
const _variants = vue.unref(variants);
|
||
|
|
if (_variants && (_variants.visible || _variants.visibleOnce)) {
|
||
|
|
core.useIntersectionObserver(target, ([{ isIntersecting }]) => {
|
||
|
|
if (_variants.visible) {
|
||
|
|
if (isIntersecting)
|
||
|
|
variant.value = "visible";
|
||
|
|
else
|
||
|
|
variant.value = "initial";
|
||
|
|
} else if (_variants.visibleOnce) {
|
||
|
|
if (isIntersecting && variant.value !== "visibleOnce")
|
||
|
|
variant.value = "visibleOnce";
|
||
|
|
else if (!variant.value)
|
||
|
|
variant.value = "initial";
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function useMotionFeatures(instance, options = {
|
||
|
|
syncVariants: true,
|
||
|
|
lifeCycleHooks: true,
|
||
|
|
visibilityHooks: true,
|
||
|
|
eventListeners: true
|
||
|
|
}) {
|
||
|
|
if (options.lifeCycleHooks)
|
||
|
|
registerLifeCycleHooks(instance);
|
||
|
|
if (options.syncVariants)
|
||
|
|
registerVariantsSync(instance);
|
||
|
|
if (options.visibilityHooks)
|
||
|
|
registerVisibilityHooks(instance);
|
||
|
|
if (options.eventListeners)
|
||
|
|
registerEventListeners(instance);
|
||
|
|
}
|
||
|
|
|
||
|
|
function reactiveStyle(props = {}) {
|
||
|
|
const state = vue.reactive({
|
||
|
|
...props
|
||
|
|
});
|
||
|
|
const style = vue.ref({});
|
||
|
|
vue.watch(
|
||
|
|
state,
|
||
|
|
() => {
|
||
|
|
const result = {};
|
||
|
|
for (const [key, value] of Object.entries(state)) {
|
||
|
|
const valueType = getValueType(key);
|
||
|
|
const valueAsType = getValueAsType(value, valueType);
|
||
|
|
result[key] = valueAsType;
|
||
|
|
}
|
||
|
|
style.value = result;
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true,
|
||
|
|
deep: true
|
||
|
|
}
|
||
|
|
);
|
||
|
|
return {
|
||
|
|
state,
|
||
|
|
style
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function usePermissiveTarget(target, onTarget) {
|
||
|
|
vue.watch(
|
||
|
|
() => core.unrefElement(target),
|
||
|
|
(el) => {
|
||
|
|
if (!el)
|
||
|
|
return;
|
||
|
|
onTarget(el);
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true
|
||
|
|
}
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const translateAlias = {
|
||
|
|
x: "translateX",
|
||
|
|
y: "translateY",
|
||
|
|
z: "translateZ"
|
||
|
|
};
|
||
|
|
function reactiveTransform(props = {}, enableHardwareAcceleration = true) {
|
||
|
|
const state = vue.reactive({ ...props });
|
||
|
|
const transform = vue.ref("");
|
||
|
|
vue.watch(
|
||
|
|
state,
|
||
|
|
(newVal) => {
|
||
|
|
let result = "";
|
||
|
|
let hasHardwareAcceleration = false;
|
||
|
|
if (enableHardwareAcceleration && (newVal.x || newVal.y || newVal.z)) {
|
||
|
|
const str = [newVal.x || 0, newVal.y || 0, newVal.z || 0].map((val) => getValueAsType(val, styleValueTypes.px)).join(",");
|
||
|
|
result += `translate3d(${str}) `;
|
||
|
|
hasHardwareAcceleration = true;
|
||
|
|
}
|
||
|
|
for (const [key, value] of Object.entries(newVal)) {
|
||
|
|
if (enableHardwareAcceleration && (key === "x" || key === "y" || key === "z"))
|
||
|
|
continue;
|
||
|
|
const valueType = getValueType(key);
|
||
|
|
const valueAsType = getValueAsType(value, valueType);
|
||
|
|
result += `${translateAlias[key] || key}(${valueAsType}) `;
|
||
|
|
}
|
||
|
|
if (enableHardwareAcceleration && !hasHardwareAcceleration)
|
||
|
|
result += "translateZ(0px) ";
|
||
|
|
transform.value = result.trim();
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true,
|
||
|
|
deep: true
|
||
|
|
}
|
||
|
|
);
|
||
|
|
return {
|
||
|
|
state,
|
||
|
|
transform
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const transformAxes = ["", "X", "Y", "Z"];
|
||
|
|
const order = ["perspective", "translate", "scale", "rotate", "skew"];
|
||
|
|
const transformProps = ["transformPerspective", "x", "y", "z"];
|
||
|
|
order.forEach((operationKey) => {
|
||
|
|
transformAxes.forEach((axesKey) => {
|
||
|
|
const key = operationKey + axesKey;
|
||
|
|
transformProps.push(key);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
const transformPropSet = new Set(transformProps);
|
||
|
|
function isTransformProp(key) {
|
||
|
|
return transformPropSet.has(key);
|
||
|
|
}
|
||
|
|
const transformOriginProps = /* @__PURE__ */ new Set(["originX", "originY", "originZ"]);
|
||
|
|
function isTransformOriginProp(key) {
|
||
|
|
return transformOriginProps.has(key);
|
||
|
|
}
|
||
|
|
function splitValues(variant) {
|
||
|
|
const transform = {};
|
||
|
|
const style = {};
|
||
|
|
Object.entries(variant).forEach(([key, value]) => {
|
||
|
|
if (isTransformProp(key) || isTransformOriginProp(key))
|
||
|
|
transform[key] = value;
|
||
|
|
else
|
||
|
|
style[key] = value;
|
||
|
|
});
|
||
|
|
return { transform, style };
|
||
|
|
}
|
||
|
|
function variantToStyle(variant) {
|
||
|
|
const { transform: _transform, style: _style } = splitValues(variant);
|
||
|
|
const { transform } = reactiveTransform(_transform);
|
||
|
|
const { style } = reactiveStyle(_style);
|
||
|
|
if (transform.value)
|
||
|
|
style.value.transform = transform.value;
|
||
|
|
return style.value;
|
||
|
|
}
|
||
|
|
|
||
|
|
function useElementStyle(target, onInit) {
|
||
|
|
let _cache;
|
||
|
|
let _target;
|
||
|
|
const { state, style } = reactiveStyle();
|
||
|
|
usePermissiveTarget(target, (el) => {
|
||
|
|
_target = el;
|
||
|
|
for (const key of Object.keys(valueTypes)) {
|
||
|
|
if (el.style[key] === null || el.style[key] === "" || isTransformProp(key) || isTransformOriginProp(key))
|
||
|
|
continue;
|
||
|
|
state[key] = el.style[key];
|
||
|
|
}
|
||
|
|
if (_cache) {
|
||
|
|
Object.entries(_cache).forEach(([key, value]) => el.style[key] = value);
|
||
|
|
}
|
||
|
|
if (onInit)
|
||
|
|
onInit(state);
|
||
|
|
});
|
||
|
|
vue.watch(
|
||
|
|
style,
|
||
|
|
(newVal) => {
|
||
|
|
if (!_target) {
|
||
|
|
_cache = newVal;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
for (const key in newVal)
|
||
|
|
_target.style[key] = newVal[key];
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true
|
||
|
|
}
|
||
|
|
);
|
||
|
|
return {
|
||
|
|
style: state
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function parseTransform(transform) {
|
||
|
|
const transforms = transform.trim().split(/\) |\)/);
|
||
|
|
if (transforms.length === 1)
|
||
|
|
return {};
|
||
|
|
const parseValues = (value) => {
|
||
|
|
if (value.endsWith("px") || value.endsWith("deg"))
|
||
|
|
return Number.parseFloat(value);
|
||
|
|
if (Number.isNaN(Number(value)))
|
||
|
|
return Number(value);
|
||
|
|
return value;
|
||
|
|
};
|
||
|
|
return transforms.reduce((acc, transform2) => {
|
||
|
|
if (!transform2)
|
||
|
|
return acc;
|
||
|
|
const [name, transformValue] = transform2.split("(");
|
||
|
|
const valueArray = transformValue.split(",");
|
||
|
|
const values = valueArray.map((val) => {
|
||
|
|
return parseValues(val.endsWith(")") ? val.replace(")", "") : val.trim());
|
||
|
|
});
|
||
|
|
const value = values.length === 1 ? values[0] : values;
|
||
|
|
return {
|
||
|
|
...acc,
|
||
|
|
[name]: value
|
||
|
|
};
|
||
|
|
}, {});
|
||
|
|
}
|
||
|
|
function stateFromTransform(state, transform) {
|
||
|
|
Object.entries(parseTransform(transform)).forEach(([key, value]) => {
|
||
|
|
const axes = ["x", "y", "z"];
|
||
|
|
if (key === "translate3d") {
|
||
|
|
if (value === 0) {
|
||
|
|
axes.forEach((axis) => state[axis] = 0);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
value.forEach((axisValue, index) => state[axes[index]] = axisValue);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
value = Number.parseFloat(`${value}`);
|
||
|
|
if (key === "translateX") {
|
||
|
|
state.x = value;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (key === "translateY") {
|
||
|
|
state.y = value;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (key === "translateZ") {
|
||
|
|
state.z = value;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
state[key] = value;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function useElementTransform(target, onInit) {
|
||
|
|
let _cache;
|
||
|
|
let _target;
|
||
|
|
const { state, transform } = reactiveTransform();
|
||
|
|
usePermissiveTarget(target, (el) => {
|
||
|
|
_target = el;
|
||
|
|
if (el.style.transform)
|
||
|
|
stateFromTransform(state, el.style.transform);
|
||
|
|
if (_cache)
|
||
|
|
el.style.transform = _cache;
|
||
|
|
if (onInit)
|
||
|
|
onInit(state);
|
||
|
|
});
|
||
|
|
vue.watch(
|
||
|
|
transform,
|
||
|
|
(newValue) => {
|
||
|
|
if (!_target) {
|
||
|
|
_cache = newValue;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
_target.style.transform = newValue;
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true
|
||
|
|
}
|
||
|
|
);
|
||
|
|
return {
|
||
|
|
transform: state
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function objectEntries(obj) {
|
||
|
|
return Object.entries(obj);
|
||
|
|
}
|
||
|
|
|
||
|
|
function useMotionProperties(target, defaultValues) {
|
||
|
|
const motionProperties = vue.reactive({});
|
||
|
|
const apply = (values) => Object.entries(values).forEach(([key, value]) => motionProperties[key] = value);
|
||
|
|
const { style } = useElementStyle(target, apply);
|
||
|
|
const { transform } = useElementTransform(target, apply);
|
||
|
|
vue.watch(
|
||
|
|
motionProperties,
|
||
|
|
(newVal) => {
|
||
|
|
objectEntries(newVal).forEach(([key, value]) => {
|
||
|
|
const target2 = isTransformProp(key) ? transform : style;
|
||
|
|
if (target2[key] && target2[key] === value)
|
||
|
|
return;
|
||
|
|
target2[key] = value;
|
||
|
|
});
|
||
|
|
},
|
||
|
|
{
|
||
|
|
immediate: true,
|
||
|
|
deep: true
|
||
|
|
}
|
||
|
|
);
|
||
|
|
usePermissiveTarget(target, () => defaultValues && apply(defaultValues));
|
||
|
|
return {
|
||
|
|
motionProperties,
|
||
|
|
style,
|
||
|
|
transform
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function useMotionVariants(variants = {}) {
|
||
|
|
const _variants = vue.unref(variants);
|
||
|
|
const variant = vue.ref();
|
||
|
|
const state = vue.computed(() => {
|
||
|
|
if (!variant.value)
|
||
|
|
return;
|
||
|
|
return _variants[variant.value];
|
||
|
|
});
|
||
|
|
return {
|
||
|
|
state,
|
||
|
|
variant
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function useMotion(target, variants = {}, options) {
|
||
|
|
const { motionProperties } = useMotionProperties(target);
|
||
|
|
const { variant, state } = useMotionVariants(variants);
|
||
|
|
const controls = useMotionControls(motionProperties, variants);
|
||
|
|
const instance = {
|
||
|
|
target,
|
||
|
|
variant,
|
||
|
|
variants,
|
||
|
|
state,
|
||
|
|
motionProperties,
|
||
|
|
...controls
|
||
|
|
};
|
||
|
|
useMotionFeatures(instance, options);
|
||
|
|
return instance;
|
||
|
|
}
|
||
|
|
|
||
|
|
const transitionKeys = ["delay", "duration"];
|
||
|
|
const directivePropsKeys = ["initial", "enter", "leave", "visible", "visible-once", "visibleOnce", "hovered", "tapped", "focused", ...transitionKeys];
|
||
|
|
function isTransitionKey(val) {
|
||
|
|
return transitionKeys.includes(val);
|
||
|
|
}
|
||
|
|
function resolveVariants(node, variantsRef) {
|
||
|
|
const target = node.props ? node.props : node.data && node.data.attrs ? node.data.attrs : {};
|
||
|
|
if (target) {
|
||
|
|
if (target.variants && core.isObject(target.variants)) {
|
||
|
|
variantsRef.value = {
|
||
|
|
...variantsRef.value,
|
||
|
|
...target.variants
|
||
|
|
};
|
||
|
|
}
|
||
|
|
for (let key of directivePropsKeys) {
|
||
|
|
if (!target || !target[key])
|
||
|
|
continue;
|
||
|
|
if (isTransitionKey(key) && typeof target[key] === "number") {
|
||
|
|
for (const variantKey of ["enter", "visible", "visibleOnce"]) {
|
||
|
|
const variantConfig = variantsRef.value[variantKey];
|
||
|
|
if (variantConfig == null)
|
||
|
|
continue;
|
||
|
|
variantConfig.transition ?? (variantConfig.transition = {});
|
||
|
|
variantConfig.transition[key] = target[key];
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (core.isObject(target[key])) {
|
||
|
|
const prop = target[key];
|
||
|
|
if (key === "visible-once")
|
||
|
|
key = "visibleOnce";
|
||
|
|
variantsRef.value[key] = prop;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function directive(variants, isPreset = false) {
|
||
|
|
const register = (el, binding, node) => {
|
||
|
|
const key = binding.value && typeof binding.value === "string" ? binding.value : node.key;
|
||
|
|
if (key && motionState[key])
|
||
|
|
motionState[key].stop();
|
||
|
|
const variantsObject = isPreset ? structuredClone(vue.toRaw(variants) || {}) : variants || {};
|
||
|
|
const variantsRef = vue.ref(variantsObject);
|
||
|
|
if (typeof binding.value === "object")
|
||
|
|
variantsRef.value = binding.value;
|
||
|
|
resolveVariants(node, variantsRef);
|
||
|
|
const motionOptions = { eventListeners: true, lifeCycleHooks: true, syncVariants: true, visibilityHooks: false };
|
||
|
|
const motionInstance = useMotion(el, variantsRef, motionOptions);
|
||
|
|
el.motionInstance = motionInstance;
|
||
|
|
if (key)
|
||
|
|
motionState[key] = motionInstance;
|
||
|
|
};
|
||
|
|
const mounted = (el, _binding, _node) => {
|
||
|
|
el.motionInstance && registerVisibilityHooks(el.motionInstance);
|
||
|
|
};
|
||
|
|
return {
|
||
|
|
created: register,
|
||
|
|
mounted,
|
||
|
|
getSSRProps(binding, node) {
|
||
|
|
let { initial: bindingInitial } = binding.value || node && node?.props || {};
|
||
|
|
bindingInitial = vue.unref(bindingInitial);
|
||
|
|
const initial = defu__default({}, variants?.initial || {}, bindingInitial || {});
|
||
|
|
if (!initial || Object.keys(initial).length === 0)
|
||
|
|
return;
|
||
|
|
const style = variantToStyle(initial);
|
||
|
|
return {
|
||
|
|
style
|
||
|
|
};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const fade = {
|
||
|
|
initial: {
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const fadeVisible = {
|
||
|
|
initial: {
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const fadeVisibleOnce = {
|
||
|
|
initial: {
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const pop = {
|
||
|
|
initial: {
|
||
|
|
scale: 0,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
scale: 1,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const popVisible = {
|
||
|
|
initial: {
|
||
|
|
scale: 0,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
scale: 1,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const popVisibleOnce = {
|
||
|
|
initial: {
|
||
|
|
scale: 0,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
scale: 1,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const rollLeft = {
|
||
|
|
initial: {
|
||
|
|
x: -100,
|
||
|
|
rotate: 90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
x: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollVisibleLeft = {
|
||
|
|
initial: {
|
||
|
|
x: -100,
|
||
|
|
rotate: 90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
x: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollVisibleOnceLeft = {
|
||
|
|
initial: {
|
||
|
|
x: -100,
|
||
|
|
rotate: 90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
x: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollRight = {
|
||
|
|
initial: {
|
||
|
|
x: 100,
|
||
|
|
rotate: -90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
x: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollVisibleRight = {
|
||
|
|
initial: {
|
||
|
|
x: 100,
|
||
|
|
rotate: -90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
x: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollVisibleOnceRight = {
|
||
|
|
initial: {
|
||
|
|
x: 100,
|
||
|
|
rotate: -90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
x: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollTop = {
|
||
|
|
initial: {
|
||
|
|
y: -100,
|
||
|
|
rotate: -90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
y: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollVisibleTop = {
|
||
|
|
initial: {
|
||
|
|
y: -100,
|
||
|
|
rotate: -90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
y: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollVisibleOnceTop = {
|
||
|
|
initial: {
|
||
|
|
y: -100,
|
||
|
|
rotate: -90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
y: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollBottom = {
|
||
|
|
initial: {
|
||
|
|
y: 100,
|
||
|
|
rotate: 90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
y: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollVisibleBottom = {
|
||
|
|
initial: {
|
||
|
|
y: 100,
|
||
|
|
rotate: 90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
y: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const rollVisibleOnceBottom = {
|
||
|
|
initial: {
|
||
|
|
y: 100,
|
||
|
|
rotate: 90,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
y: 0,
|
||
|
|
rotate: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const slideLeft = {
|
||
|
|
initial: {
|
||
|
|
x: -100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
x: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideVisibleLeft = {
|
||
|
|
initial: {
|
||
|
|
x: -100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
x: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideVisibleOnceLeft = {
|
||
|
|
initial: {
|
||
|
|
x: -100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
x: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideRight = {
|
||
|
|
initial: {
|
||
|
|
x: 100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
x: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideVisibleRight = {
|
||
|
|
initial: {
|
||
|
|
x: 100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
x: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideVisibleOnceRight = {
|
||
|
|
initial: {
|
||
|
|
x: 100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
x: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideTop = {
|
||
|
|
initial: {
|
||
|
|
y: -100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
y: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideVisibleTop = {
|
||
|
|
initial: {
|
||
|
|
y: -100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
y: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideVisibleOnceTop = {
|
||
|
|
initial: {
|
||
|
|
y: -100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
y: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideBottom = {
|
||
|
|
initial: {
|
||
|
|
y: 100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
enter: {
|
||
|
|
y: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideVisibleBottom = {
|
||
|
|
initial: {
|
||
|
|
y: 100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visible: {
|
||
|
|
y: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const slideVisibleOnceBottom = {
|
||
|
|
initial: {
|
||
|
|
y: 100,
|
||
|
|
opacity: 0
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
y: 0,
|
||
|
|
opacity: 1
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const presets = {
|
||
|
|
__proto__: null,
|
||
|
|
fade: fade,
|
||
|
|
fadeVisible: fadeVisible,
|
||
|
|
fadeVisibleOnce: fadeVisibleOnce,
|
||
|
|
pop: pop,
|
||
|
|
popVisible: popVisible,
|
||
|
|
popVisibleOnce: popVisibleOnce,
|
||
|
|
rollBottom: rollBottom,
|
||
|
|
rollLeft: rollLeft,
|
||
|
|
rollRight: rollRight,
|
||
|
|
rollTop: rollTop,
|
||
|
|
rollVisibleBottom: rollVisibleBottom,
|
||
|
|
rollVisibleLeft: rollVisibleLeft,
|
||
|
|
rollVisibleOnceBottom: rollVisibleOnceBottom,
|
||
|
|
rollVisibleOnceLeft: rollVisibleOnceLeft,
|
||
|
|
rollVisibleOnceRight: rollVisibleOnceRight,
|
||
|
|
rollVisibleOnceTop: rollVisibleOnceTop,
|
||
|
|
rollVisibleRight: rollVisibleRight,
|
||
|
|
rollVisibleTop: rollVisibleTop,
|
||
|
|
slideBottom: slideBottom,
|
||
|
|
slideLeft: slideLeft,
|
||
|
|
slideRight: slideRight,
|
||
|
|
slideTop: slideTop,
|
||
|
|
slideVisibleBottom: slideVisibleBottom,
|
||
|
|
slideVisibleLeft: slideVisibleLeft,
|
||
|
|
slideVisibleOnceBottom: slideVisibleOnceBottom,
|
||
|
|
slideVisibleOnceLeft: slideVisibleOnceLeft,
|
||
|
|
slideVisibleOnceRight: slideVisibleOnceRight,
|
||
|
|
slideVisibleOnceTop: slideVisibleOnceTop,
|
||
|
|
slideVisibleRight: slideVisibleRight,
|
||
|
|
slideVisibleTop: slideVisibleTop
|
||
|
|
};
|
||
|
|
|
||
|
|
function slugify(str) {
|
||
|
|
const a = "\xE0\xE1\xE2\xE4\xE6\xE3\xE5\u0101\u0103\u0105\xE7\u0107\u010D\u0111\u010F\xE8\xE9\xEA\xEB\u0113\u0117\u0119\u011B\u011F\u01F5\u1E27\xEE\xEF\xED\u012B\u012F\xEC\u0142\u1E3F\xF1\u0144\u01F9\u0148\xF4\xF6\xF2\xF3\u0153\xF8\u014D\xF5\u0151\u1E55\u0155\u0159\xDF\u015B\u0161\u015F\u0219\u0165\u021B\xFB\xFC\xF9\xFA\u016B\u01D8\u016F\u0171\u0173\u1E83\u1E8D\xFF\xFD\u017E\u017A\u017C\xB7/_,:;";
|
||
|
|
const b = "aaaaaaaaaacccddeeeeeeeegghiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz------";
|
||
|
|
const p = new RegExp(a.split("").join("|"), "g");
|
||
|
|
return str.toString().replace(/[A-Z]/g, (s) => `-${s}`).toLowerCase().replace(/\s+/g, "-").replace(p, (c) => b.charAt(a.indexOf(c))).replace(/&/g, "-and-").replace(/[^\w\-]+/g, "").replace(/-{2,}/g, "-").replace(/^-+/, "").replace(/-+$/, "");
|
||
|
|
}
|
||
|
|
|
||
|
|
const CUSTOM_PRESETS = Symbol(
|
||
|
|
undefined ? "motionCustomPresets" : ""
|
||
|
|
);
|
||
|
|
|
||
|
|
const MotionComponentProps = {
|
||
|
|
// Preset to be loaded
|
||
|
|
preset: {
|
||
|
|
type: String,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
// Instance
|
||
|
|
instance: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
// Variants
|
||
|
|
variants: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
// Initial variant
|
||
|
|
initial: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
// Lifecycle hooks variants
|
||
|
|
enter: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
leave: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
// Intersection observer variants
|
||
|
|
visible: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
visibleOnce: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
// Event listeners variants
|
||
|
|
hovered: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
tapped: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
focused: {
|
||
|
|
type: Object,
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
// Helpers
|
||
|
|
delay: {
|
||
|
|
type: [Number, String],
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
duration: {
|
||
|
|
type: [Number, String],
|
||
|
|
required: false
|
||
|
|
}
|
||
|
|
};
|
||
|
|
function isObject(val) {
|
||
|
|
return Object.prototype.toString.call(val) === "[object Object]";
|
||
|
|
}
|
||
|
|
function clone(v) {
|
||
|
|
if (Array.isArray(v)) {
|
||
|
|
return v.map(clone);
|
||
|
|
}
|
||
|
|
if (isObject(v)) {
|
||
|
|
const res = {};
|
||
|
|
for (const key in v) {
|
||
|
|
res[key] = clone(v[key]);
|
||
|
|
}
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
function setupMotionComponent(props) {
|
||
|
|
const instances = vue.reactive({});
|
||
|
|
const customPresets = vue.inject(CUSTOM_PRESETS, {});
|
||
|
|
const preset = vue.computed(() => {
|
||
|
|
if (props.preset == null) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
if (customPresets != null && props.preset in customPresets) {
|
||
|
|
return structuredClone(vue.toRaw(customPresets)[props.preset]);
|
||
|
|
}
|
||
|
|
if (props.preset in presets) {
|
||
|
|
return structuredClone(presets[props.preset]);
|
||
|
|
}
|
||
|
|
return {};
|
||
|
|
});
|
||
|
|
const propsConfig = vue.computed(() => ({
|
||
|
|
initial: props.initial,
|
||
|
|
enter: props.enter,
|
||
|
|
leave: props.leave,
|
||
|
|
visible: props.visible,
|
||
|
|
visibleOnce: props.visibleOnce,
|
||
|
|
hovered: props.hovered,
|
||
|
|
tapped: props.tapped,
|
||
|
|
focused: props.focused
|
||
|
|
}));
|
||
|
|
function applyTransitionHelpers(config, values) {
|
||
|
|
for (const transitionKey of ["delay", "duration"]) {
|
||
|
|
if (values[transitionKey] == null)
|
||
|
|
continue;
|
||
|
|
const transitionValueParsed = Number.parseInt(
|
||
|
|
values[transitionKey]
|
||
|
|
);
|
||
|
|
for (const variantKey of ["enter", "visible", "visibleOnce"]) {
|
||
|
|
const variantConfig = config[variantKey];
|
||
|
|
if (variantConfig == null)
|
||
|
|
continue;
|
||
|
|
variantConfig.transition ?? (variantConfig.transition = {});
|
||
|
|
variantConfig.transition[transitionKey] = transitionValueParsed;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return config;
|
||
|
|
}
|
||
|
|
const motionConfig = vue.computed(() => {
|
||
|
|
const config = defu__default(
|
||
|
|
{},
|
||
|
|
propsConfig.value,
|
||
|
|
preset.value,
|
||
|
|
props.variants || {}
|
||
|
|
);
|
||
|
|
return applyTransitionHelpers({ ...config }, props);
|
||
|
|
});
|
||
|
|
if (undefined) {
|
||
|
|
if (props.preset != null && presets?.[props.preset] == null && customPresets?.[props.preset] == null) {
|
||
|
|
console.warn(`[@vueuse/motion]: Preset \`${props.preset}\` not found.`);
|
||
|
|
}
|
||
|
|
const replayAnimation = (instance) => {
|
||
|
|
if (instance.variants?.initial) {
|
||
|
|
instance.set("initial");
|
||
|
|
}
|
||
|
|
vue.nextTick(() => {
|
||
|
|
if (instance.variants?.enter)
|
||
|
|
instance.apply("enter");
|
||
|
|
if (instance.variants?.visible)
|
||
|
|
instance.apply("visible");
|
||
|
|
if (instance.variants?.visibleOnce)
|
||
|
|
instance.apply("visibleOnce");
|
||
|
|
});
|
||
|
|
};
|
||
|
|
vue.onUpdated(() => {
|
||
|
|
for (const key in instances) {
|
||
|
|
replayAnimation(instances[key]);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function setNodeInstance(node, index, style) {
|
||
|
|
var _a;
|
||
|
|
node.props ?? (node.props = {});
|
||
|
|
(_a = node.props).style ?? (_a.style = {});
|
||
|
|
node.props.style = { ...node.props.style, ...style };
|
||
|
|
const elementMotionConfig = applyTransitionHelpers(
|
||
|
|
clone(motionConfig.value),
|
||
|
|
node.props
|
||
|
|
);
|
||
|
|
node.props.onVnodeMounted = ({ el }) => {
|
||
|
|
instances[index] = useMotion(
|
||
|
|
el,
|
||
|
|
elementMotionConfig
|
||
|
|
);
|
||
|
|
};
|
||
|
|
node.props.onVnodeUpdated = ({ el }) => {
|
||
|
|
const styles = variantToStyle(instances[index].state);
|
||
|
|
for (const [key, val] of Object.entries(styles)) {
|
||
|
|
el.style[key] = val;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
return node;
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
motionConfig,
|
||
|
|
setNodeInstance
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const MotionComponent = vue.defineComponent({
|
||
|
|
name: "Motion",
|
||
|
|
props: {
|
||
|
|
...MotionComponentProps,
|
||
|
|
is: {
|
||
|
|
type: [String, Object],
|
||
|
|
default: "div"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
setup(props) {
|
||
|
|
const slots = vue.useSlots();
|
||
|
|
const { motionConfig, setNodeInstance } = setupMotionComponent(props);
|
||
|
|
return () => {
|
||
|
|
const style = variantToStyle(motionConfig.value.initial || {});
|
||
|
|
const node = vue.h(props.is, void 0, slots);
|
||
|
|
setNodeInstance(node, 0, style);
|
||
|
|
return node;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
const MotionGroupComponent = vue.defineComponent({
|
||
|
|
name: "MotionGroup",
|
||
|
|
props: {
|
||
|
|
...MotionComponentProps,
|
||
|
|
is: {
|
||
|
|
type: [String, Object],
|
||
|
|
required: false
|
||
|
|
}
|
||
|
|
},
|
||
|
|
setup(props) {
|
||
|
|
const slots = vue.useSlots();
|
||
|
|
const { motionConfig, setNodeInstance } = setupMotionComponent(props);
|
||
|
|
return () => {
|
||
|
|
const style = variantToStyle(motionConfig.value.initial || {});
|
||
|
|
const nodes = slots.default?.() || [];
|
||
|
|
for (let i = 0; i < nodes.length; i++) {
|
||
|
|
const n = nodes[i];
|
||
|
|
if (n.type === vue.Fragment && Array.isArray(n.children)) {
|
||
|
|
n.children.forEach(function setChildInstance(child, index) {
|
||
|
|
if (child == null)
|
||
|
|
return;
|
||
|
|
if (Array.isArray(child)) {
|
||
|
|
setChildInstance(child, index);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (typeof child === "object") {
|
||
|
|
setNodeInstance(child, index, style);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
setNodeInstance(n, i, style);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (props.is) {
|
||
|
|
return vue.h(props.is, void 0, nodes);
|
||
|
|
}
|
||
|
|
return nodes;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
const MotionPlugin = {
|
||
|
|
install(app, options) {
|
||
|
|
app.directive("motion", directive());
|
||
|
|
if (!options || options && !options.excludePresets) {
|
||
|
|
for (const key in presets) {
|
||
|
|
const preset = presets[key];
|
||
|
|
app.directive(`motion-${slugify(key)}`, directive(preset, true));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (options && options.directives) {
|
||
|
|
for (const key in options.directives) {
|
||
|
|
const variants = options.directives[key];
|
||
|
|
if (!variants.initial && undefined) {
|
||
|
|
console.warn(
|
||
|
|
`Your directive v-motion-${key} is missing initial variant!`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
app.directive(`motion-${key}`, directive(variants, true));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
app.provide(CUSTOM_PRESETS, options?.directives);
|
||
|
|
app.component("Motion", MotionComponent);
|
||
|
|
app.component("MotionGroup", MotionGroupComponent);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
function isMotionInstance(obj) {
|
||
|
|
const _obj = obj;
|
||
|
|
return _obj.apply !== void 0 && typeof _obj.apply === "function" && _obj.set !== void 0 && typeof _obj.set === "function" && _obj.target !== void 0 && vue.isRef(_obj.target);
|
||
|
|
}
|
||
|
|
|
||
|
|
function useMotions() {
|
||
|
|
return motionState;
|
||
|
|
}
|
||
|
|
|
||
|
|
function useSpring(values, spring) {
|
||
|
|
const { stop, get } = useMotionValues();
|
||
|
|
return {
|
||
|
|
values,
|
||
|
|
stop,
|
||
|
|
set: (properties) => Promise.all(
|
||
|
|
Object.entries(properties).map(([key, value]) => {
|
||
|
|
const motionValue = get(key, values[key], values);
|
||
|
|
return motionValue.start((onComplete) => {
|
||
|
|
const options = {
|
||
|
|
type: "spring",
|
||
|
|
...spring || getDefaultTransition(key, value)
|
||
|
|
};
|
||
|
|
return popmotion.animate({
|
||
|
|
from: motionValue.get(),
|
||
|
|
to: value,
|
||
|
|
velocity: motionValue.getVelocity(),
|
||
|
|
onUpdate: (v) => motionValue.set(v),
|
||
|
|
onComplete,
|
||
|
|
...options
|
||
|
|
});
|
||
|
|
});
|
||
|
|
})
|
||
|
|
)
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function useReducedMotion(options = {}) {
|
||
|
|
return core.useMediaQuery("(prefers-reduced-motion: reduce)", options);
|
||
|
|
}
|
||
|
|
|
||
|
|
exports.MotionComponent = MotionComponent;
|
||
|
|
exports.MotionDirective = directive;
|
||
|
|
exports.MotionGroupComponent = MotionGroupComponent;
|
||
|
|
exports.MotionPlugin = MotionPlugin;
|
||
|
|
exports.fade = fade;
|
||
|
|
exports.fadeVisible = fadeVisible;
|
||
|
|
exports.fadeVisibleOnce = fadeVisibleOnce;
|
||
|
|
exports.isMotionInstance = isMotionInstance;
|
||
|
|
exports.pop = pop;
|
||
|
|
exports.popVisible = popVisible;
|
||
|
|
exports.popVisibleOnce = popVisibleOnce;
|
||
|
|
exports.reactiveStyle = reactiveStyle;
|
||
|
|
exports.reactiveTransform = reactiveTransform;
|
||
|
|
exports.rollBottom = rollBottom;
|
||
|
|
exports.rollLeft = rollLeft;
|
||
|
|
exports.rollRight = rollRight;
|
||
|
|
exports.rollTop = rollTop;
|
||
|
|
exports.rollVisibleBottom = rollVisibleBottom;
|
||
|
|
exports.rollVisibleLeft = rollVisibleLeft;
|
||
|
|
exports.rollVisibleOnceBottom = rollVisibleOnceBottom;
|
||
|
|
exports.rollVisibleOnceLeft = rollVisibleOnceLeft;
|
||
|
|
exports.rollVisibleOnceRight = rollVisibleOnceRight;
|
||
|
|
exports.rollVisibleOnceTop = rollVisibleOnceTop;
|
||
|
|
exports.rollVisibleRight = rollVisibleRight;
|
||
|
|
exports.rollVisibleTop = rollVisibleTop;
|
||
|
|
exports.slideBottom = slideBottom;
|
||
|
|
exports.slideLeft = slideLeft;
|
||
|
|
exports.slideRight = slideRight;
|
||
|
|
exports.slideTop = slideTop;
|
||
|
|
exports.slideVisibleBottom = slideVisibleBottom;
|
||
|
|
exports.slideVisibleLeft = slideVisibleLeft;
|
||
|
|
exports.slideVisibleOnceBottom = slideVisibleOnceBottom;
|
||
|
|
exports.slideVisibleOnceLeft = slideVisibleOnceLeft;
|
||
|
|
exports.slideVisibleOnceRight = slideVisibleOnceRight;
|
||
|
|
exports.slideVisibleOnceTop = slideVisibleOnceTop;
|
||
|
|
exports.slideVisibleRight = slideVisibleRight;
|
||
|
|
exports.slideVisibleTop = slideVisibleTop;
|
||
|
|
exports.slugify = slugify;
|
||
|
|
exports.useElementStyle = useElementStyle;
|
||
|
|
exports.useElementTransform = useElementTransform;
|
||
|
|
exports.useMotion = useMotion;
|
||
|
|
exports.useMotionControls = useMotionControls;
|
||
|
|
exports.useMotionFeatures = useMotionFeatures;
|
||
|
|
exports.useMotionProperties = useMotionProperties;
|
||
|
|
exports.useMotionTransitions = useMotionTransitions;
|
||
|
|
exports.useMotionVariants = useMotionVariants;
|
||
|
|
exports.useMotions = useMotions;
|
||
|
|
exports.useReducedMotion = useReducedMotion;
|
||
|
|
exports.useSpring = useSpring;
|