1880 lines
46 KiB
JavaScript
1880 lines
46 KiB
JavaScript
import { ref, computed, nextTick, watch, mergeProps, unref, withCtx, createVNode, reactive, isRef, defineComponent, useSlots, h, Fragment, useSSRContext, inject, toRaw } from 'vue';
|
|
import { ssrRenderAttrs, ssrRenderComponent, ssrRenderClass, ssrRenderSlot, ssrInterpolate, ssrRenderStyle } from 'vue/server-renderer';
|
|
import { useDrag } from '@vueuse/gesture';
|
|
import { TransitionRoot } from '@headlessui/vue';
|
|
import { d as defu } from '../_/nitro.mjs';
|
|
import { a as useConfigStore, R as unrefElement, S as tryOnUnmounted, T as isObject$2, n as useIntersectionObserver, U as useEventListener } from './server.mjs';
|
|
import sync, { getFrameData } from 'framesync';
|
|
import { inertia, animate, velocityPerSecond, cubicBezier, bounceOut, bounceInOut, bounceIn, anticipate, backOut, backInOut, backIn, circOut, circInOut, circIn, easeOut, easeInOut, easeIn, linear } from 'popmotion';
|
|
import { complex, number, alpha, filter, px, progressPercentage, degrees, scale, color } from 'style-value-types';
|
|
import { _ as _export_sfc } from './_plugin-vue_export-helper-1tPrXgE0.mjs';
|
|
|
|
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);
|
|
class SubscriptionManager {
|
|
constructor() {
|
|
__publicField(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();
|
|
}
|
|
}
|
|
function isFloat(value) {
|
|
return !Number.isNaN(Number.parseFloat(value));
|
|
}
|
|
class MotionValue {
|
|
/**
|
|
* init - The initiating value
|
|
* config - Optional configuration options
|
|
*/
|
|
constructor(init) {
|
|
__publicField(this, "current");
|
|
__publicField(this, "prev");
|
|
__publicField(this, "timeDelta", 0);
|
|
__publicField(this, "lastUpdated", 0);
|
|
__publicField(this, "updateSubscribers", new SubscriptionManager());
|
|
__publicField(this, "stopAnimation");
|
|
__publicField(this, "canTrackVelocity", false);
|
|
__publicField(this, "updateAndNotify", (v) => {
|
|
this.prev = this.current;
|
|
this.current = v;
|
|
const { delta, timestamp } = getFrameData();
|
|
if (this.lastUpdated !== timestamp) {
|
|
this.timeDelta = delta;
|
|
this.lastUpdated = timestamp;
|
|
}
|
|
sync.postRender(this.scheduleVelocityCheck);
|
|
this.updateSubscribers.notify(this.current);
|
|
});
|
|
__publicField(this, "scheduleVelocityCheck", () => sync.postRender(this.velocityCheck));
|
|
__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 ? 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 = 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;
|
|
};
|
|
tryOnUnmounted();
|
|
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 = {
|
|
...number,
|
|
transform: Math.round
|
|
};
|
|
const valueTypes = {
|
|
// Color props
|
|
color,
|
|
backgroundColor: color,
|
|
outlineColor: color,
|
|
fill: color,
|
|
stroke: color,
|
|
// Border props
|
|
borderColor: color,
|
|
borderTopColor: color,
|
|
borderRightColor: color,
|
|
borderBottomColor: color,
|
|
borderLeftColor: color,
|
|
borderWidth: px,
|
|
borderTopWidth: px,
|
|
borderRightWidth: px,
|
|
borderBottomWidth: px,
|
|
borderLeftWidth: px,
|
|
borderRadius: px,
|
|
radius: px,
|
|
borderTopLeftRadius: px,
|
|
borderTopRightRadius: px,
|
|
borderBottomRightRadius: px,
|
|
borderBottomLeftRadius: px,
|
|
// Positioning props
|
|
width: px,
|
|
maxWidth: px,
|
|
height: px,
|
|
maxHeight: px,
|
|
size: px,
|
|
top: px,
|
|
right: px,
|
|
bottom: px,
|
|
left: px,
|
|
// Spacing props
|
|
padding: px,
|
|
paddingTop: px,
|
|
paddingRight: px,
|
|
paddingBottom: px,
|
|
paddingLeft: px,
|
|
margin: px,
|
|
marginTop: px,
|
|
marginRight: px,
|
|
marginBottom: px,
|
|
marginLeft: px,
|
|
// Transform props
|
|
rotate: degrees,
|
|
rotateX: degrees,
|
|
rotateY: degrees,
|
|
rotateZ: degrees,
|
|
scale,
|
|
scaleX: scale,
|
|
scaleY: scale,
|
|
scaleZ: scale,
|
|
skew: degrees,
|
|
skewX: degrees,
|
|
skewY: degrees,
|
|
distance: px,
|
|
translateX: px,
|
|
translateY: px,
|
|
translateZ: px,
|
|
x: px,
|
|
y: px,
|
|
z: px,
|
|
perspective: px,
|
|
transformPerspective: px,
|
|
opacity: alpha,
|
|
originX: progressPercentage,
|
|
originY: progressPercentage,
|
|
originZ: px,
|
|
// Misc
|
|
zIndex: int,
|
|
filter,
|
|
WebkitFilter: filter,
|
|
// SVG
|
|
fillOpacity: alpha,
|
|
strokeOpacity: 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 !== filter)
|
|
defaultValueType = complex;
|
|
return defaultValueType.getAnimatableNone ? defaultValueType.getAnimatableNone(value) : void 0;
|
|
}
|
|
const easingLookup = {
|
|
linear,
|
|
easeIn,
|
|
easeInOut,
|
|
easeOut,
|
|
circIn,
|
|
circInOut,
|
|
circOut,
|
|
backIn,
|
|
backInOut,
|
|
backOut,
|
|
anticipate,
|
|
bounceIn,
|
|
bounceInOut,
|
|
bounceOut
|
|
};
|
|
function easingDefinitionToFunction(definition) {
|
|
if (Array.isArray(definition)) {
|
|
const [x1, y1, x2, y2] = definition;
|
|
return 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" && 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" ? inertia({ ...options, ...valueTransition }) : 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 = unref(variants);
|
|
const isAnimating = ref(false);
|
|
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() {
|
|
var _a, _b;
|
|
await Promise.all(animations);
|
|
(_b = (_a = variant.transition) == null ? void 0 : _a.onComplete) == null ? void 0 : _b.call(_a);
|
|
}
|
|
return Promise.all([waitForComplete()]);
|
|
};
|
|
const set = (variant) => {
|
|
const variantData = isObject$2(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
|
|
};
|
|
}
|
|
function registerEventListeners({ target, state, variants, apply }) {
|
|
const _variants = unref(variants);
|
|
const hovered = ref(false);
|
|
const tapped = ref(false);
|
|
const focused = ref(false);
|
|
const mutableKeys = 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 = 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) {
|
|
useEventListener(target, "mouseenter", () => hovered.value = true);
|
|
useEventListener(target, "mouseleave", () => {
|
|
hovered.value = false;
|
|
tapped.value = false;
|
|
});
|
|
}
|
|
if (_variants.tapped) ;
|
|
if (_variants.focused) {
|
|
useEventListener(target, "focus", () => focused.value = true);
|
|
useEventListener(target, "blur", () => focused.value = false);
|
|
}
|
|
watch([hovered, tapped, focused], () => {
|
|
apply(computedProperties.value);
|
|
});
|
|
}
|
|
function registerLifeCycleHooks({ set, target, variants, variant }) {
|
|
const _variants = unref(variants);
|
|
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 }) {
|
|
watch(
|
|
state,
|
|
(newVal) => {
|
|
if (newVal)
|
|
apply(newVal);
|
|
},
|
|
{
|
|
immediate: true
|
|
}
|
|
);
|
|
}
|
|
function registerVisibilityHooks({ target, variants, variant }) {
|
|
const _variants = unref(variants);
|
|
if (_variants && (_variants.visible || _variants.visibleOnce)) {
|
|
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 = reactive({
|
|
...props
|
|
});
|
|
const style = ref({});
|
|
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) {
|
|
watch(
|
|
() => 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 = reactive({ ...props });
|
|
const transform = ref("");
|
|
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, 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);
|
|
});
|
|
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);
|
|
});
|
|
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 = reactive({});
|
|
const apply = (values) => Object.entries(values).forEach(([key, value]) => motionProperties[key] = value);
|
|
const { style } = useElementStyle(target, apply);
|
|
const { transform } = useElementTransform(target, apply);
|
|
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);
|
|
return {
|
|
motionProperties,
|
|
style,
|
|
transform
|
|
};
|
|
}
|
|
function useMotionVariants(variants = {}) {
|
|
const _variants = unref(variants);
|
|
const variant = ref();
|
|
const state = 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 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,
|
|
fadeVisible,
|
|
fadeVisibleOnce,
|
|
pop,
|
|
popVisible,
|
|
popVisibleOnce,
|
|
rollBottom,
|
|
rollLeft,
|
|
rollRight,
|
|
rollTop,
|
|
rollVisibleBottom,
|
|
rollVisibleLeft,
|
|
rollVisibleOnceBottom,
|
|
rollVisibleOnceLeft,
|
|
rollVisibleOnceRight,
|
|
rollVisibleOnceTop,
|
|
rollVisibleRight,
|
|
rollVisibleTop,
|
|
slideBottom,
|
|
slideLeft,
|
|
slideRight,
|
|
slideTop,
|
|
slideVisibleBottom,
|
|
slideVisibleLeft,
|
|
slideVisibleOnceBottom,
|
|
slideVisibleOnceLeft,
|
|
slideVisibleOnceRight,
|
|
slideVisibleOnceTop,
|
|
slideVisibleRight,
|
|
slideVisibleTop
|
|
};
|
|
const CUSTOM_PRESETS = Symbol(
|
|
""
|
|
);
|
|
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 = reactive({});
|
|
const customPresets = inject(CUSTOM_PRESETS, {});
|
|
const preset = computed(() => {
|
|
if (props.preset == null) {
|
|
return {};
|
|
}
|
|
if (customPresets != null && props.preset in customPresets) {
|
|
return structuredClone(toRaw(customPresets)[props.preset]);
|
|
}
|
|
if (props.preset in presets) {
|
|
return structuredClone(presets[props.preset]);
|
|
}
|
|
return {};
|
|
});
|
|
const propsConfig = 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) {
|
|
var _a;
|
|
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;
|
|
(_a = variantConfig.transition) != null ? _a : variantConfig.transition = {};
|
|
variantConfig.transition[transitionKey] = transitionValueParsed;
|
|
}
|
|
}
|
|
return config;
|
|
}
|
|
const motionConfig = computed(() => {
|
|
const config = defu(
|
|
{},
|
|
propsConfig.value,
|
|
preset.value,
|
|
props.variants || {}
|
|
);
|
|
return applyTransitionHelpers({ ...config }, props);
|
|
});
|
|
function setNodeInstance(node, index, style) {
|
|
var _a2, _b;
|
|
var _a;
|
|
(_a2 = node.props) != null ? _a2 : node.props = {};
|
|
(_b = (_a = node.props).style) != null ? _b : _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
|
|
};
|
|
}
|
|
defineComponent({
|
|
name: "Motion",
|
|
props: {
|
|
...MotionComponentProps,
|
|
is: {
|
|
type: [String, Object],
|
|
default: "div"
|
|
}
|
|
},
|
|
setup(props) {
|
|
const slots = useSlots();
|
|
const { motionConfig, setNodeInstance } = setupMotionComponent(props);
|
|
return () => {
|
|
const style = variantToStyle(motionConfig.value.initial || {});
|
|
const node = h(props.is, void 0, slots);
|
|
setNodeInstance(node, 0, style);
|
|
return node;
|
|
};
|
|
}
|
|
});
|
|
defineComponent({
|
|
name: "MotionGroup",
|
|
props: {
|
|
...MotionComponentProps,
|
|
is: {
|
|
type: [String, Object],
|
|
required: false
|
|
}
|
|
},
|
|
setup(props) {
|
|
const slots = useSlots();
|
|
const { motionConfig, setNodeInstance } = setupMotionComponent(props);
|
|
return () => {
|
|
var _a;
|
|
const style = variantToStyle(motionConfig.value.initial || {});
|
|
const nodes = ((_a = slots.default) == null ? void 0 : _a.call(slots)) || [];
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
const n = nodes[i];
|
|
if (n.type === 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 h(props.is, void 0, nodes);
|
|
}
|
|
return nodes;
|
|
};
|
|
}
|
|
});
|
|
const SCROLL_LOCK_CLASS = "no-scroll";
|
|
function useLockScroll(selectorElements, lockedClass) {
|
|
const elements = wrap(selectorElements);
|
|
if (!lockedClass || !isString(lockedClass)) {
|
|
lockedClass = SCROLL_LOCK_CLASS;
|
|
}
|
|
const locked = ref(false);
|
|
watch(
|
|
locked,
|
|
(l) => {
|
|
if (lockedClass) {
|
|
if (!elements.value) return;
|
|
elements.value.classList.toggle(lockedClass, l);
|
|
}
|
|
},
|
|
{
|
|
immediate: true
|
|
}
|
|
);
|
|
const lock = () => locked.value = true;
|
|
const unlock = () => locked.value = false;
|
|
const remove = () => {
|
|
if (elements.value) {
|
|
elements.value.classList.remove(lockedClass);
|
|
}
|
|
};
|
|
return {
|
|
isScrollLocked: locked,
|
|
lockScroll: lock,
|
|
unlockScroll: unlock,
|
|
clearLockScroll: remove
|
|
};
|
|
}
|
|
function wrap(o) {
|
|
return isRef(o) ? o : ref(o);
|
|
}
|
|
const isString = (val) => typeof val === "string";
|
|
const elHasScrollY = (el) => {
|
|
const { scrollHeight, offsetHeight } = el;
|
|
return scrollHeight > offsetHeight;
|
|
};
|
|
const elScrolledBottom = (el) => {
|
|
const { scrollHeight, scrollTop, offsetHeight } = el;
|
|
return scrollHeight - scrollTop === offsetHeight;
|
|
};
|
|
const elScrolledTop = (el) => {
|
|
const { scrollTop } = el;
|
|
return scrollTop === 0;
|
|
};
|
|
const _sfc_main = {
|
|
__name: "index",
|
|
__ssrInlineRender: true,
|
|
props: {
|
|
allowCloseScrollup: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
showCloseButton: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
title: {
|
|
type: String,
|
|
default: ""
|
|
},
|
|
subtitle: {
|
|
type: String,
|
|
default: ""
|
|
},
|
|
sheetClass: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
headerCls: {
|
|
type: [String, Object],
|
|
default: null
|
|
},
|
|
contentCls: {
|
|
type: [String, Object],
|
|
default: null
|
|
},
|
|
closeOnClickOutside: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
duration: {
|
|
type: Number,
|
|
default: 300
|
|
}
|
|
},
|
|
emits: ["onClickOutside", "onClose"],
|
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
__expose({
|
|
calculateHeight,
|
|
setOpen,
|
|
setClose,
|
|
openSheet,
|
|
closeSheet
|
|
});
|
|
const config = useConfigStore();
|
|
const props = __props;
|
|
const emit = __emit;
|
|
const sheetRef = ref();
|
|
const sheetContentRef = ref();
|
|
const headerWrapperRef = ref();
|
|
let headerWrapperHeight = ref(0);
|
|
let renderSheet = ref(true);
|
|
let sheetHeight = ref(0);
|
|
let state = ref();
|
|
let isDragging = ref(false);
|
|
let overlayState = ref(0);
|
|
let axisY = ref(0);
|
|
let wrapperIndex = ref("z-[1000]");
|
|
let windowHeight = ref(0);
|
|
const getContentHeight = computed(() => {
|
|
const offsetHeight = windowHeight.value / 100 * 5;
|
|
let height = windowHeight.value - (headerWrapperHeight.value + offsetHeight);
|
|
return { "max-height": `${height}px` };
|
|
});
|
|
const { motionProperties } = useMotionProperties(sheetRef);
|
|
const { push } = useMotionTransitions();
|
|
const keyFrame = {
|
|
type: "keyframe",
|
|
ease: "linear",
|
|
duration: 0,
|
|
delay: 0
|
|
};
|
|
const getOverlayStyle = computed(() => {
|
|
return {
|
|
block: true,
|
|
fixed: true,
|
|
"inset-0": true,
|
|
"bg-overlay": true,
|
|
"z-[1000]": true,
|
|
"cursor-pointer": props.closeOnClickOutside
|
|
};
|
|
});
|
|
async function openSheet() {
|
|
var _a;
|
|
await nextTick();
|
|
await ((_a = sheetRef.value) == null ? void 0 : _a.setOpen());
|
|
}
|
|
async function closeSheet() {
|
|
var _a;
|
|
await nextTick();
|
|
await ((_a = sheetRef.value) == null ? void 0 : _a.setClose());
|
|
}
|
|
const getWrapperClass = computed(() => {
|
|
return {
|
|
"opacity-100": state.value === "open",
|
|
"!-z-40 opacity-0": state.value !== "open"
|
|
};
|
|
});
|
|
const getContentOverflow = computed(() => {
|
|
return {
|
|
"overflow-y-auto": !isDragging.value,
|
|
"overflow-y-hidden": isDragging.value
|
|
};
|
|
});
|
|
function dragHandler(ctx) {
|
|
const { dragging } = ctx;
|
|
if (dragging) {
|
|
handleDrag(ctx);
|
|
} else {
|
|
handleDragEnd(ctx);
|
|
}
|
|
}
|
|
function calculateHeight() {
|
|
nextTick(() => {
|
|
setTimeout(() => {
|
|
var _a, _b;
|
|
sheetHeight.value = (_a = sheetRef.value) == null ? void 0 : _a.clientHeight;
|
|
windowHeight.value = (void 0).innerHeight;
|
|
headerWrapperHeight.value = (_b = headerWrapperRef.value) == null ? void 0 : _b.clientHeight;
|
|
axisY.value = windowHeight.value;
|
|
push("y", axisY.value, motionProperties, keyFrame);
|
|
}, 100);
|
|
});
|
|
}
|
|
function handleDrag(ctx) {
|
|
if (ctx.tap || !allowDrag(ctx)) return;
|
|
isDragging.value = true;
|
|
const {
|
|
movement: [, y]
|
|
} = ctx;
|
|
const setY = axisY.value + y;
|
|
if (y < 0) return;
|
|
push("y", setY, motionProperties, keyFrame);
|
|
}
|
|
function handleDragEnd(ctx) {
|
|
if (ctx.tap || !allowDrag(ctx)) return;
|
|
isDragging.value = false;
|
|
const {
|
|
swipe: [, sy],
|
|
movement: [, y]
|
|
} = ctx;
|
|
if (sy > 0) {
|
|
setClose();
|
|
return;
|
|
} else if (sy < 0) {
|
|
setOpen();
|
|
return;
|
|
}
|
|
axisY.value = axisY.value + y;
|
|
if (windowHeight.value - axisY.value > windowHeight.value / 3) {
|
|
setOpen();
|
|
return;
|
|
} else {
|
|
setClose();
|
|
return;
|
|
}
|
|
}
|
|
function allowDrag(ctx) {
|
|
var _a;
|
|
if (!props.allowCloseScrollup) return false;
|
|
const {
|
|
swipe: [, sy],
|
|
movement: [, y]
|
|
} = ctx;
|
|
const dragTarget = (_a = ctx == null ? void 0 : ctx.event) == null ? void 0 : _a.srcElement;
|
|
const isDragUp = y < 0 || sy < 0;
|
|
const targetIsContent = dragTarget.closest("#sheet-content");
|
|
if (elHasScrollY(sheetContentRef.value) && targetIsContent) {
|
|
if (isDragUp && elScrolledBottom(sheetContentRef.value)) return true;
|
|
else if (!isDragUp && elScrolledTop(sheetContentRef.value)) return true;
|
|
else return false;
|
|
}
|
|
return true;
|
|
}
|
|
async function setOpen() {
|
|
renderSheet.value = true;
|
|
isDragging.value = true;
|
|
await nextTick();
|
|
setTimeout(() => {
|
|
const { lockScroll } = useLockScroll((void 0).querySelector("html body"));
|
|
lockScroll();
|
|
sheetHeight.value = sheetRef.value.clientHeight;
|
|
windowHeight.value = (void 0).innerHeight;
|
|
axisY.value = windowHeight.value - sheetHeight.value;
|
|
push("y", axisY.value, motionProperties, {
|
|
...keyFrame,
|
|
duration: props.duration
|
|
});
|
|
state.value = "open";
|
|
overlayState.value = 1;
|
|
}, 10);
|
|
}
|
|
async function setClose(option = { clickOutside: false }) {
|
|
if (option.clickOutside) emit("onClickOutside", true);
|
|
await nextTick();
|
|
const { unlockScroll } = useLockScroll((void 0).querySelector("html body"));
|
|
unlockScroll();
|
|
axisY.value = windowHeight.value;
|
|
push("y", axisY.value, motionProperties, {
|
|
...keyFrame,
|
|
duration: props.duration
|
|
});
|
|
overlayState.value = 0;
|
|
setTimeout(() => {
|
|
state.value = "close";
|
|
emit("onClose", true);
|
|
renderSheet.value = false;
|
|
}, props.duration);
|
|
}
|
|
function onOutsideClick() {
|
|
if (!props.closeOnClickOutside) return;
|
|
setClose({ clickOutside: true });
|
|
}
|
|
watch(
|
|
() => state.value,
|
|
(val) => {
|
|
setTimeout(() => {
|
|
wrapperIndex.value = val === "open" ? "z-[1001]" : "-z-40";
|
|
}, 75);
|
|
}
|
|
);
|
|
useDrag(dragHandler, {
|
|
domTarget: sheetRef,
|
|
filterTaps: true,
|
|
// preventWindowScrollY: true,
|
|
useTouch: true
|
|
});
|
|
return (_ctx, _push, _parent, _attrs) => {
|
|
_push(`<div${ssrRenderAttrs(mergeProps({
|
|
class: ["fixed inset-0 bg-#00000086 transition-all duration-300", [getWrapperClass.value, unref(wrapperIndex)]]
|
|
}, _attrs))} data-v-544971fc>`);
|
|
_push(ssrRenderComponent(unref(TransitionRoot), {
|
|
show: unref(overlayState) === 1,
|
|
enter: "transition-opacity ease-in duration-300",
|
|
"enter-from": "opacity-0",
|
|
"enter-to": "opacity-100",
|
|
leave: "transition-opacity ease-out duration-300",
|
|
"leave-from": "opacity-100",
|
|
"leave-to": "opacity-0"
|
|
}, {
|
|
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
if (_push2) {
|
|
_push2(`<div class="${ssrRenderClass(getOverlayStyle.value)}" data-v-544971fc${_scopeId}></div>`);
|
|
} else {
|
|
return [
|
|
createVNode("div", {
|
|
class: getOverlayStyle.value,
|
|
onClick: onOutsideClick
|
|
}, null, 2)
|
|
];
|
|
}
|
|
}),
|
|
_: 1
|
|
}, _parent));
|
|
_push(`<div class="${ssrRenderClass([unref(config).isNightStore ? "bg-zinc-9" : "bg-white", "relative backdrop-blur-sheet rounded-t-[15px] z-[1002]"])}" id="sheet-card" data-v-544971fc>`);
|
|
if (unref(renderSheet)) {
|
|
_push(`<!--[--><div data-v-544971fc><div class="pointer-events-none" data-v-544971fc>`);
|
|
ssrRenderSlot(_ctx.$slots, "headerImage", {}, null, _push, _parent);
|
|
_push(`<div class="bg-white-2 h-4 w-45 rounded mx-auto cursor-pointer absolute top-12 left-1/2 -translate-x-1/2" data-v-544971fc></div></div>`);
|
|
ssrRenderSlot(_ctx.$slots, "header", {}, () => {
|
|
_push(`<div id="sheetHeader" class="${ssrRenderClass([__props.headerCls, "flex w-full justify-between align-center sticky top-0 pt-2 pb-2"])}" data-v-544971fc><div class="text-lg" data-v-544971fc>`);
|
|
if (__props.title) {
|
|
_push(`<div class="text-18 font-semibold" data-v-544971fc>${ssrInterpolate(__props.title)}</div>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
if (__props.showCloseButton) {
|
|
_push(`<div class="cursor-pointer" data-v-544971fc><svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="{2}" data-v-544971fc><path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" data-v-544971fc></path></svg></div>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
}, _push, _parent);
|
|
_push(`</div><div id="sheet-content" class="${ssrRenderClass([[__props.contentCls, getContentOverflow.value], "relative w-full"])}" style="${ssrRenderStyle(getContentHeight.value)}" data-v-544971fc>`);
|
|
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent);
|
|
_push(`</div><!--]-->`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div></div>`);
|
|
};
|
|
}
|
|
};
|
|
const _sfc_setup = _sfc_main.setup;
|
|
_sfc_main.setup = (props, ctx) => {
|
|
const ssrContext = useSSRContext();
|
|
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/BasicPacks/BasicSheet/index.vue");
|
|
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
|
|
};
|
|
const BasicSheet = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-544971fc"]]);
|
|
|
|
export { BasicSheet as B };
|
|
//# sourceMappingURL=index-DVD7vSfp.mjs.map
|