UNPKG

vue-circular-gauge

Version:

Circular gauge component for Vue.js with customizable colors, animations, and thresholds

1,638 lines 288 kB
import { inject, provide, watch, computed, ref, useAttrs, getCurrentInstance, onBeforeMount, onMounted, onBeforeUnmount, onUnmounted, onBeforeUpdate, onUpdated, defineComponent, h, Comment, mergeProps, cloneVNode, createElementBlock, openBlock, unref, createElementVNode, createBlock, createCommentVNode, toDisplayString } from "vue"; const calculatePrimaryStrokeDasharray = (strokePercent, offsetFactor, gapPercent, circumference) => { const percentToPx = circumference / 100; if (offsetFactor > 0 && strokePercent > 100 - gapPercent * 2 * offsetFactor) { const subtract = -strokePercent + 100; return `${Math.max(strokePercent * percentToPx - subtract * percentToPx, 0)} ${circumference}`; } else { const subtract = gapPercent * 2 * offsetFactor; return `${Math.max(strokePercent * percentToPx - subtract * percentToPx, 0)} ${circumference}`; } }; const calculateSecondaryStrokeDasharray = (strokePercent, offsetFactorSecondary, gapPercent, circumference) => { const percentToPx = circumference / 100; if (offsetFactorSecondary < 1 && strokePercent < gapPercent * 2 * offsetFactorSecondary) { const subtract = strokePercent; return `${Math.max((100 - strokePercent) * percentToPx - subtract * percentToPx, 0)} ${circumference}`; } else { const subtract = gapPercent * 2 * offsetFactorSecondary; return `${Math.max((100 - strokePercent) * percentToPx - subtract * percentToPx, 0)} ${circumference}`; } }; const calculatePrimaryTransform = (strokePercent, offsetFactor, gapPercent, isAscendingVariant) => { const percentToDegree = 360 / 100; if (offsetFactor > 0 && strokePercent > 100 - gapPercent * 2 * offsetFactor) { const add = 0.5 * (-strokePercent + 100); const rotateDegValue = -90 + add * percentToDegree; return isAscendingVariant ? `rotate(${rotateDegValue}deg)` : `rotate(${-1 * rotateDegValue}deg) scaleX(-1)`; } else { const add = gapPercent * offsetFactor; const rotateDegValue = -90 + add * percentToDegree; return isAscendingVariant ? `rotate(${rotateDegValue}deg)` : `rotate(${-1 * rotateDegValue}deg) scaleX(-1)`; } }; const calculateSecondaryTransform = (strokePercent, offsetFactorSecondary, gapPercent, isAscendingVariant) => { const percentToDegree = 360 / 100; if (offsetFactorSecondary < 1 && strokePercent < gapPercent * 2 * offsetFactorSecondary) { const subtract = 0.5 * strokePercent; const rotateDegValue = -90 + subtract * percentToDegree; return isAscendingVariant ? `rotate(${rotateDegValue}deg) scaleY(-1)` : `rotate(${-1 * rotateDegValue}deg) scaleY(-1) scaleX(-1)`; } else { const subtract = gapPercent * offsetFactorSecondary; const rotateDegValue = 360 - 90 - subtract * percentToDegree; return isAscendingVariant ? `rotate(${rotateDegValue}deg) scaleY(-1)` : `rotate(${-1 * rotateDegValue}deg) scaleY(-1) scaleX(-1)`; } }; const checkCustomColorRange = (color2, strokePercent) => { const colorKeys = Object.keys(color2).sort((a, b) => Number(a) - Number(b)); let stroke = ""; for (let i = 0; i < colorKeys.length; i++) { const currentKey = Number(colorKeys[i]); const nextKey = Number(colorKeys[i + 1]); if (strokePercent >= currentKey && (strokePercent < nextKey || !nextKey)) { stroke = color2[currentKey]; break; } } return stroke; }; const calculatePrimaryStroke = (primary, strokePercent) => { if (!primary) { return strokePercent <= 25 ? "hsl(358 75% 59%)" : strokePercent <= 50 ? "hsl(39 100% 57%)" : strokePercent <= 75 ? "hsl(212 100% 48%)" : "hsl(131 41% 46%)"; } else if (typeof primary === "string") { return primary; } else if (typeof primary === "object") { return checkCustomColorRange(primary, strokePercent); } }; const calculateSecondaryStroke = (secondary, strokePercent) => { if (!secondary) { return "hsl(0 0% 92%)"; } else if (typeof secondary === "string") { return secondary; } else if (typeof secondary === "object") { return checkCustomColorRange(secondary, 100 - strokePercent); } }; const calculatePrimaryOpacity = (offsetFactor, strokePercent, gapPercent, offsetFactorSecondary) => { if (offsetFactor > 0 && strokePercent < gapPercent * 2 * offsetFactor && strokePercent < gapPercent * 2 * offsetFactorSecondary) { return 0; } else return 1; }; const calculateSecondaryOpacity = (offsetFactor, strokePercent, gapPercent, offsetFactorSecondary) => { if (offsetFactor === 0 && strokePercent > 100 - gapPercent * 2 || offsetFactor > 0 && strokePercent > 100 - gapPercent * 2 * offsetFactor && strokePercent > 100 - gapPercent * 2 * offsetFactorSecondary) { return 0; } else return 1; }; const sizeConfig = { xs: { size: 32 }, sm: { size: 48 }, md: { size: 72 }, lg: { size: 96 }, xl: { size: 120 }, "2xl": { size: 144 } }; const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token); const isCSSVariableName = /* @__PURE__ */ checkStringStartsWith("--"); const startsAsVariableToken = /* @__PURE__ */ checkStringStartsWith("var(--"); const isCSSVariableToken = (value) => { const startsWithToken = startsAsVariableToken(value); if (!startsWithToken) return false; return singleCssVariableRegex.test(value.split("/*")[0].trim()); }; const singleCssVariableRegex = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu; const scaleCorrectors = {}; function addScaleCorrector(correctors) { for (const key in correctors) { scaleCorrectors[key] = correctors[key]; if (isCSSVariableName(key)) { scaleCorrectors[key].isCSSVariable = true; } } } function createContext(providerComponentName, contextName) { const symbolDescription = typeof providerComponentName === "string" && true ? `${providerComponentName}Context` : contextName; const injectionKey = Symbol(symbolDescription); const injectContext = (fallback) => { const context = inject(injectionKey, fallback); if (context) return context; if (context === null) return context; throw new Error( `Injection \`${injectionKey.toString()}\` not found. Component must be used within ${Array.isArray(providerComponentName) ? `one of the following components: ${providerComponentName.join( ", " )}` : `\`${providerComponentName}\``}` ); }; const provideContext = (contextValue) => { provide(injectionKey, contextValue); return contextValue; }; return [injectContext, provideContext]; } const [injectMotion, provideMotion] = createContext("Motion"); const [injectLayoutGroup, provideLayoutGroup] = createContext("LayoutGroup"); function isAnimationControls$1(v) { return v !== null && typeof v === "object" && typeof v.start === "function"; } class Feature { constructor(state) { this.state = state; } beforeMount() { } mount() { } unmount() { } update() { } beforeUpdate() { } beforeUnmount() { } } var warning$1 = function() { }; var invariant$1 = function() { }; if (process.env.NODE_ENV !== "production") { warning$1 = function(check, message) { if (!check && typeof console !== "undefined") { console.warn(message); } }; invariant$1 = function(check, message) { if (!check) { throw new Error(message); } }; } function resolveVariant$1(definition, variants, custom) { if (Array.isArray(definition)) { return definition.reduce((acc, item) => { const resolvedVariant = resolveVariant$1(item, variants, custom); return resolvedVariant ? { ...acc, ...resolvedVariant } : acc; }, {}); } else if (typeof definition === "object") { return definition; } else if (definition && variants) { const variant = variants[definition]; return typeof variant === "function" ? variant(custom) : variant; } } function hasChanged(a, b) { if (typeof a !== typeof b) return true; if (Array.isArray(a) && Array.isArray(b)) return !shallowCompare(a, b); return a !== b; } function shallowCompare(next, prev) { const prevLength = prev.length; if (prevLength !== next.length) return false; for (let i = 0; i < prevLength; i++) { if (prev[i] !== next[i]) return false; } return true; } function isCssVar(name) { return name == null ? void 0 : name.startsWith("--"); } const noopReturn = (v) => v; function isNumber$1(value) { return typeof value === "number"; } const svgElements = [ "animate", "circle", "defs", "desc", "ellipse", "g", "image", "line", "filter", "marker", "mask", "metadata", "path", "pattern", "polygon", "polyline", "rect", "stop", "svg", "switch", "symbol", "text", "tspan", "use", "view", "clipPath", "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feDropShadow", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence", "foreignObject", "linearGradient", "radialGradient", "textPath" ]; const svgElementSet = new Set(svgElements); function isSVGElement$1(as) { return svgElementSet.has(as); } function isAnimateChanged(oldOptions, newOptions) { const oldAnimate = oldOptions.animate; const newAnimate = newOptions.animate; if (oldAnimate === newAnimate) return false; if (!oldAnimate || !newAnimate) { return true; } if (typeof oldAnimate === "object" || typeof newAnimate === "object") { const oldKeys = Object.keys(oldAnimate); const newKeys = Object.keys(newAnimate); if (oldKeys.length !== newKeys.length) return true; return oldKeys.some((key) => { if (key === "transition") return false; const oldVal = oldAnimate[key]; const newVal = newAnimate[key]; return oldVal !== newVal; }); } return oldAnimate !== newAnimate; } class FeatureManager { constructor(state) { this.features = []; const { features = [], lazyMotionContext } = state.options; const allFeatures = features.concat(lazyMotionContext.features.value); this.features = allFeatures.map((Feature2) => new Feature2(state)); const featureInstances = this.features; watch(lazyMotionContext.features, (features2) => { features2.forEach((feature) => { if (!allFeatures.includes(feature)) { allFeatures.push(feature); const featureInstance = new feature(state); featureInstances.push(featureInstance); if (state.isMounted()) { featureInstance.beforeMount(); featureInstance.mount(); } } }); }, { flush: "pre" }); } mount() { this.features.forEach((feature) => feature.mount()); } beforeMount() { this.features.forEach((feature) => { var _a; return (_a = feature.beforeMount) == null ? void 0 : _a.call(feature); }); } unmount() { this.features.forEach((feature) => feature.unmount()); } update() { this.features.forEach((feature) => { var _a; return (_a = feature.update) == null ? void 0 : _a.call(feature); }); } beforeUpdate() { this.features.forEach((feature) => feature.beforeUpdate()); } beforeUnmount() { this.features.forEach((feature) => feature.beforeUnmount()); } } const doneCallbacks = /* @__PURE__ */ new WeakMap(); const [injectAnimatePresence, provideAnimatePresence] = createContext("AnimatePresenceContext"); function isVariantLabels(value) { return typeof value === "string" || value === false || Array.isArray(value); } const noop = /* @__NO_SIDE_EFFECTS__ */ (any) => any; const stepsOrder = [ "setup", // Compute "read", // Read "resolveKeyframes", // Write/Read/Write/Read "preUpdate", // Compute "update", // Compute "preRender", // Compute "render", // Write "postRender" // Compute ]; function createRenderStep(runNextFrame, stepName) { let thisFrame = /* @__PURE__ */ new Set(); let nextFrame = /* @__PURE__ */ new Set(); let isProcessing = false; let flushNextFrame = false; const toKeepAlive = /* @__PURE__ */ new WeakSet(); let latestFrameData = { delta: 0, timestamp: 0, isProcessing: false }; function triggerCallback(callback) { if (toKeepAlive.has(callback)) { step.schedule(callback); runNextFrame(); } callback(latestFrameData); } const step = { /** * Schedule a process to run on the next frame. */ schedule: (callback, keepAlive = false, immediate = false) => { const addToCurrentFrame = immediate && isProcessing; const queue = addToCurrentFrame ? thisFrame : nextFrame; if (keepAlive) toKeepAlive.add(callback); if (!queue.has(callback)) queue.add(callback); return callback; }, /** * Cancel the provided callback from running on the next frame. */ cancel: (callback) => { nextFrame.delete(callback); toKeepAlive.delete(callback); }, /** * Execute all schedule callbacks. */ process: (frameData2) => { latestFrameData = frameData2; if (isProcessing) { flushNextFrame = true; return; } isProcessing = true; [thisFrame, nextFrame] = [nextFrame, thisFrame]; thisFrame.forEach(triggerCallback); thisFrame.clear(); isProcessing = false; if (flushNextFrame) { flushNextFrame = false; step.process(frameData2); } } }; return step; } const MotionGlobalConfig = {}; const maxElapsed = 40; function createRenderBatcher(scheduleNextBatch, allowKeepAlive) { let runNextFrame = false; let useDefaultElapsed = true; const state = { delta: 0, timestamp: 0, isProcessing: false }; const flagRunNextFrame = () => runNextFrame = true; const steps = stepsOrder.reduce((acc, key) => { acc[key] = createRenderStep(flagRunNextFrame); return acc; }, {}); const { setup, read, resolveKeyframes, preUpdate, update, preRender, render, postRender } = steps; const processBatch = () => { const timestamp = MotionGlobalConfig.useManualTiming ? state.timestamp : performance.now(); runNextFrame = false; if (!MotionGlobalConfig.useManualTiming) { state.delta = useDefaultElapsed ? 1e3 / 60 : Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1); } state.timestamp = timestamp; state.isProcessing = true; setup.process(state); read.process(state); resolveKeyframes.process(state); preUpdate.process(state); update.process(state); preRender.process(state); render.process(state); postRender.process(state); state.isProcessing = false; if (runNextFrame && allowKeepAlive) { useDefaultElapsed = false; scheduleNextBatch(processBatch); } }; const wake = () => { runNextFrame = true; useDefaultElapsed = true; if (!state.isProcessing) { scheduleNextBatch(processBatch); } }; const schedule = stepsOrder.reduce((acc, key) => { const step = steps[key]; acc[key] = (process2, keepAlive = false, immediate = false) => { if (!runNextFrame) wake(); return step.schedule(process2, keepAlive, immediate); }; return acc; }, {}); const cancel = (process2) => { for (let i = 0; i < stepsOrder.length; i++) { steps[stepsOrder[i]].cancel(process2); } }; return { schedule, cancel, state, steps }; } const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps } = /* @__PURE__ */ createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true); const mountedStates = /* @__PURE__ */ new WeakMap(); let id$1 = 0; const mountedLayoutIds = /* @__PURE__ */ new Set(); class MotionState { constructor(options, parent) { var _a; this.element = null; this.isSafeToRemove = false; this.isVShow = false; this.children = /* @__PURE__ */ new Set(); this.activeStates = { initial: true, animate: true }; this.currentProcess = null; this._context = null; this.animateUpdates = noop; this.id = `motion-state-${id$1++}`; this.options = options; this.parent = parent; (_a = parent == null ? void 0 : parent.children) == null ? void 0 : _a.add(this); this.depth = (parent == null ? void 0 : parent.depth) + 1 || 0; const initial = options.initial === void 0 && options.variants ? this.context.initial : options.initial; const initialVariantSource = initial === false ? ["initial", "animate"] : ["initial"]; this.initTarget(initialVariantSource); this.featureManager = new FeatureManager(this); this.type = isSVGElement$1(this.options.as) ? "svg" : "html"; } // Get animation context, falling back to parent context for inheritance get context() { if (!this._context) { const handler = { get: (target, prop) => { var _a; return isVariantLabels(this.options[prop]) ? this.options[prop] : (_a = this.parent) == null ? void 0 : _a.context[prop]; } }; this._context = new Proxy({}, handler); } return this._context; } // Initialize animation target values initTarget(initialVariantSource) { this.baseTarget = initialVariantSource.reduce((acc, variant) => { return { ...acc, ...resolveVariant$1(this.options[variant] || this.context[variant], this.options.variants) }; }, {}); this.target = {}; } // Update visual element with new options updateOptions(options) { var _a; this.options = options; (_a = this.visualElement) == null ? void 0 : _a.update({ ...this.options, whileTap: this.options.whilePress, reducedMotionConfig: this.options.motionConfig.reduceMotion }, { isPresent: !doneCallbacks.has(this.element) }); } // Called before mounting, executes in parent-to-child order beforeMount() { this.featureManager.beforeMount(); } // Mount motion state to DOM element, handles parent-child relationships mount(element, options, notAnimate = false) { var _a; invariant$1( Boolean(element), "Animation state must be mounted with valid Element" ); this.element = element; this.updateOptions(options); this.featureManager.mount(); if (!notAnimate && this.options.animate) { (_a = this.startAnimation) == null ? void 0 : _a.call(this); } if (this.options.layoutId) { mountedLayoutIds.add(this.options.layoutId); frame.render(() => { mountedLayoutIds.clear(); }); } } clearAnimation() { var _a, _b; this.currentProcess && cancelFrame(this.currentProcess); this.currentProcess = null; (_b = (_a = this.visualElement) == null ? void 0 : _a.variantChildren) == null ? void 0 : _b.forEach((child) => { child.state.clearAnimation(); }); } // update trigger animation startAnimation() { this.clearAnimation(); this.currentProcess = frame.render(() => { this.currentProcess = null; this.animateUpdates(); }); } // Called before unmounting, executes in child-to-parent order beforeUnmount() { this.featureManager.beforeUnmount(); } // Unmount motion state and optionally unmount children // Handles unmounting in the correct order based on component tree unmount(unMountChildren = false) { const shouldDelay = this.options.layoutId && !mountedLayoutIds.has(this.options.layoutId); const unmount = () => { const unmountState = () => { var _a, _b, _c; if (unMountChildren) { Array.from(this.children).reverse().forEach(this.unmountChild); } (_b = (_a = this.parent) == null ? void 0 : _a.children) == null ? void 0 : _b.delete(this); mountedStates.delete(this.element); this.featureManager.unmount(); (_c = this.visualElement) == null ? void 0 : _c.unmount(); this.clearAnimation(); }; shouldDelay ? Promise.resolve().then(unmountState) : unmountState(); }; unmount(); } unmountChild(child) { child.unmount(true); } // Called before updating, executes in parent-to-child order beforeUpdate() { this.featureManager.beforeUpdate(); } // Update motion state with new options update(options) { const hasAnimateChange = isAnimateChanged(this.options, options); this.updateOptions(options); this.featureManager.update(); if (hasAnimateChange) { this.startAnimation(); } } // Set animation state active status and propagate to children setActive(name, isActive, isAnimate = true) { var _a; if (!this.element || this.activeStates[name] === isActive) return; this.activeStates[name] = isActive; (_a = this.visualElement.variantChildren) == null ? void 0 : _a.forEach((child) => { child.state.setActive(name, isActive, false); }); if (isAnimate) { this.animateUpdates({ isFallback: !isActive && name !== "exit" && this.visualElement.isControllingVariants, isExit: name === "exit" && this.activeStates.exit }); } } isMounted() { return Boolean(this.element); } // Called before layout updates to prepare for changes willUpdate(label) { var _a; if (this.options.layout || this.options.layoutId) { (_a = this.visualElement.projection) == null ? void 0 : _a.willUpdate(); } } } const visualElementStore = /* @__PURE__ */ new WeakMap(); function motionEvent(name, target, isExit) { return new CustomEvent(name, { detail: { target, isExit } }); } const rotation = { syntax: "<angle>", initialValue: "0deg", toDefaultUnit: (v) => `${v}deg` }; const baseTransformProperties = { translate: { syntax: "<length-percentage>", initialValue: "0px", toDefaultUnit: (v) => `${v}px` }, rotate: rotation, scale: { syntax: "<number>", initialValue: 1, toDefaultUnit: noopReturn }, skew: rotation }; const order = ["translate", "scale", "rotate", "skew"]; const axes = ["", "X", "Y", "Z"]; const transformDefinitions = /* @__PURE__ */ new Map(); const transforms = ["transformPerspective", "x", "y", "z", "translateX", "translateY", "translateZ", "scale", "scaleX", "scaleY", "rotate", "rotateX", "rotateY", "rotateZ", "skew", "skewX", "skewY"]; order.forEach((name) => { axes.forEach((axis) => { transforms.push(name + axis); transformDefinitions.set( name + axis, baseTransformProperties[name] ); }); }); const transformLookup = new Set(transforms); const isTransform = (name) => transformLookup.has(name); const transformAlias = { x: "translateX", y: "translateY", z: "translateZ" }; function compareTransformOrder([a], [b]) { return transforms.indexOf(a) - transforms.indexOf(b); } function transformListToString(template, [name, value]) { return `${template} ${name}(${value})`; } function buildTransformTemplate(transforms2) { return transforms2.sort(compareTransformOrder).reduce(transformListToString, "").trim(); } const transformResetValue = { translate: [0, 0], rotate: 0, scale: 1, skew: 0, x: 0, y: 0, z: 0 }; function createUnitType$1(unit) { return { test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1, parse: parseFloat, transform: (v) => `${v}${unit}` }; } const percent$1 = /* @__PURE__ */ createUnitType$1("%"); const px$1 = /* @__PURE__ */ createUnitType$1("px"); function isMotionValue$1(value) { return Boolean(value && value.getVelocity); } const style = { get: (element, name) => { let value = isCssVar(name) ? element.style.getPropertyValue(name) : getComputedStyle(element)[name]; if (!value && value !== "0") { const definition = transformDefinitions.get(name); if (definition) value = definition.initialValue; } return value; }, set: (element, name, value) => { if (isCssVar(name)) { element.style.setProperty(name, value); } else { element.style[name] = value; } } }; function createStyles(keyframes2) { var _a; const initialKeyframes = {}; const transforms2 = []; for (let key in keyframes2) { let value = keyframes2[key]; value = isMotionValue$1(value) ? value.get() : value; if (isTransform(key)) { if (key in transformAlias) { key = transformAlias[key]; } } let initialKeyframe = Array.isArray(value) ? value[0] : value; const definition = transformDefinitions.get(key); if (definition) { initialKeyframe = isNumber$1(value) ? (_a = definition.toDefaultUnit) == null ? void 0 : _a.call(definition, value) : value; transforms2.push([key, initialKeyframe]); } else { initialKeyframes[key] = initialKeyframe; } } if (transforms2.length) { initialKeyframes.transform = buildTransformTemplate(transforms2); } if (Object.keys(initialKeyframes).length === 0) { return null; } return initialKeyframes; } const SVG_STYLE_TO_ATTRIBUTES = { "fill": true, "stroke": true, "opacity": true, "stroke-width": true, "fill-opacity": true, "stroke-opacity": true, "stroke-linecap": true, "stroke-linejoin": true, "stroke-dasharray": true, "stroke-dashoffset": true, "cx": true, "cy": true, "r": true, "d": true, "x1": true, "y1": true, "x2": true, "y2": true, "points": true, "path-length": true, "viewBox": true, "width": true, "height": true, "preserve-aspect-ratio": true, "clip-path": true, "filter": true, "mask": true, "stop-color": true, "stop-opacity": true, "gradient-transform": true, "gradient-units": true, "spread-method": true, "marker-end": true, "marker-mid": true, "marker-start": true, "text-anchor": true, "dominant-baseline": true, "font-family": true, "font-size": true, "font-weight": true, "letter-spacing": true, "vector-effect": true }; function camelToKebab(str) { return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); } function buildSVGPath$1(attrs, length, spacing = 1, offset = 0) { attrs.pathLength = 1; delete attrs["path-length"]; attrs["stroke-dashoffset"] = px$1.transform(-offset); const pathLength = px$1.transform(length); const pathSpacing = px$1.transform(spacing); attrs["stroke-dasharray"] = `${pathLength} ${pathSpacing}`; } function convertSvgStyleToAttributes(keyframes2) { const attrs = {}; const styleProps = {}; for (const key in keyframes2) { const kebabKey = camelToKebab(key); if (kebabKey in SVG_STYLE_TO_ATTRIBUTES) { const value = keyframes2[key]; attrs[kebabKey] = isMotionValue$1(value) ? value.get() : value; } else { styleProps[key] = keyframes2[key]; } } if (attrs["path-length"] !== void 0) { buildSVGPath$1(attrs, attrs["path-length"], attrs["path-spacing"], attrs["path-offset"]); } return { attrs, style: styleProps }; } typeof WorkerGlobalScope !== "undefined" && globalThis instanceof WorkerGlobalScope; const isDef = (val) => typeof val !== "undefined"; function convertBoundingBoxToBox$1({ top, left, right, bottom }) { return { x: { min: left, max: right }, y: { min: top, max: bottom } }; } function transformBoxPoints$1(point, transformPoint2) { if (!transformPoint2) return point; const topLeft = transformPoint2({ x: point.left, y: point.top }); const bottomRight = transformPoint2({ x: point.right, y: point.bottom }); return { top: topLeft.y, left: topLeft.x, bottom: bottomRight.y, right: bottomRight.x }; } function measureViewportBox$1(instance, transformPoint2) { return convertBoundingBoxToBox$1(transformBoxPoints$1(instance.getBoundingClientRect(), transformPoint2)); } const isMotionValue = (value) => Boolean(value && value.getVelocity); const featureProps = { animation: [ "animate", "variants", "whileHover", "whileTap", "exit", "whileInView", "whileFocus", "whileDrag" ], exit: ["exit"], drag: ["drag", "dragControls"], focus: ["whileFocus"], hover: ["whileHover", "onHoverStart", "onHoverEnd"], tap: ["whileTap", "onTap", "onTapStart", "onTapCancel"], pan: ["onPan", "onPanStart", "onPanSessionStart", "onPanEnd"], inView: ["whileInView", "onViewportEnter", "onViewportLeave"], layout: ["layout", "layoutId"] }; const featureDefinitions = {}; for (const key in featureProps) { featureDefinitions[key] = { isEnabled: (props) => featureProps[key].some((name) => !!props[name]) }; } const createAxisDelta = () => ({ translate: 0, scale: 1, origin: 0, originPoint: 0 }); const createDelta = () => ({ x: createAxisDelta(), y: createAxisDelta() }); const createAxis$1 = () => ({ min: 0, max: 0 }); const createBox$1 = () => ({ x: createAxis$1(), y: createAxis$1() }); const isBrowser = typeof window !== "undefined"; const prefersReducedMotion = { current: null }; const hasReducedMotionListener = { current: false }; function initPrefersReducedMotion() { hasReducedMotionListener.current = true; if (!isBrowser) return; if (window.matchMedia) { const motionMediaQuery = window.matchMedia("(prefers-reduced-motion)"); const setReducedMotionPreferences = () => prefersReducedMotion.current = motionMediaQuery.matches; motionMediaQuery.addListener(setReducedMotionPreferences); setReducedMotionPreferences(); } else { prefersReducedMotion.current = false; } } function isAnimationControls(v) { return v !== null && typeof v === "object" && typeof v.start === "function"; } function isVariantLabel(v) { return typeof v === "string" || Array.isArray(v); } const variantPriorityOrder = [ "animate", "whileInView", "whileFocus", "whileHover", "whileTap", "whileDrag", "exit" ]; const variantProps = ["initial", ...variantPriorityOrder]; function isControllingVariants(props) { return isAnimationControls(props.animate) || variantProps.some((name) => isVariantLabel(props[name])); } function isVariantNode(props) { return Boolean(isControllingVariants(props) || props.variants); } let now; function clearTime() { now = void 0; } const time = { now: () => { if (now === void 0) { time.set(frameData.isProcessing || MotionGlobalConfig.useManualTiming ? frameData.timestamp : performance.now()); } return now; }, set: (newTime) => { now = newTime; queueMicrotask(clearTime); } }; const warned = /* @__PURE__ */ new Set(); function warnOnce(condition, message, element) { if (condition || warned.has(message)) return; console.warn(message); warned.add(message); } function addUniqueItem(arr, item) { if (arr.indexOf(item) === -1) arr.push(item); } function removeItem(arr, item) { const index2 = arr.indexOf(item); if (index2 > -1) arr.splice(index2, 1); } class SubscriptionManager { constructor() { this.subscriptions = []; } add(handler) { addUniqueItem(this.subscriptions, handler); return () => removeItem(this.subscriptions, handler); } notify(a, b, c) { const numSubscriptions = this.subscriptions.length; if (!numSubscriptions) return; if (numSubscriptions === 1) { this.subscriptions[0](a, b, c); } else { for (let i = 0; i < numSubscriptions; i++) { const handler = this.subscriptions[i]; handler && handler(a, b, c); } } } getSize() { return this.subscriptions.length; } clear() { this.subscriptions.length = 0; } } function velocityPerSecond(velocity, frameDuration) { return frameDuration ? velocity * (1e3 / frameDuration) : 0; } const MAX_VELOCITY_DELTA = 30; const isFloat = (value) => { return !isNaN(parseFloat(value)); }; class MotionValue { /** * @param init - The initiating value * @param config - Optional configuration options * * - `transformer`: A function to transform incoming values with. */ constructor(init, options = {}) { this.version = "__VERSION__"; this.canTrackVelocity = null; this.events = {}; this.updateAndNotify = (v, render = true) => { var _a, _b; const currentTime = time.now(); if (this.updatedAt !== currentTime) { this.setPrevFrameValue(); } this.prev = this.current; this.setCurrent(v); if (this.current !== this.prev) { (_a = this.events.change) == null ? void 0 : _a.notify(this.current); if (this.dependents) { for (const dependent of this.dependents) { dependent.dirty(); } } } if (render) { (_b = this.events.renderRequest) == null ? void 0 : _b.notify(this.current); } }; this.hasAnimated = false; this.setCurrent(init); this.owner = options.owner; } setCurrent(current) { this.current = current; this.updatedAt = time.now(); if (this.canTrackVelocity === null && current !== void 0) { this.canTrackVelocity = isFloat(this.current); } } setPrevFrameValue(prevFrameValue = this.current) { this.prevFrameValue = prevFrameValue; this.prevUpdatedAt = this.updatedAt; } /** * Adds a function that will be notified when the `MotionValue` is updated. * * It returns a function that, when called, will cancel the subscription. * * When calling `onChange` inside a React component, it should be wrapped with the * `useEffect` hook. As it returns an unsubscribe function, this should be returned * from the `useEffect` function to ensure you don't add duplicate subscribers.. * * ```jsx * export const MyComponent = () => { * const x = useMotionValue(0) * const y = useMotionValue(0) * const opacity = useMotionValue(1) * * useEffect(() => { * function updateOpacity() { * const maxXY = Math.max(x.get(), y.get()) * const newOpacity = transform(maxXY, [0, 100], [1, 0]) * opacity.set(newOpacity) * } * * const unsubscribeX = x.on("change", updateOpacity) * const unsubscribeY = y.on("change", updateOpacity) * * return () => { * unsubscribeX() * unsubscribeY() * } * }, []) * * return <motion.div style={{ x }} /> * } * ``` * * @param subscriber - A function that receives the latest value. * @returns A function that, when called, will cancel this subscription. * * @deprecated */ onChange(subscription) { if (process.env.NODE_ENV !== "production") { warnOnce(false, `value.onChange(callback) is deprecated. Switch to value.on("change", callback).`); } return this.on("change", subscription); } on(eventName, callback) { if (!this.events[eventName]) { this.events[eventName] = new SubscriptionManager(); } const unsubscribe = this.events[eventName].add(callback); if (eventName === "change") { return () => { unsubscribe(); frame.read(() => { if (!this.events.change.getSize()) { this.stop(); } }); }; } return unsubscribe; } clearListeners() { for (const eventManagers in this.events) { this.events[eventManagers].clear(); } } /** * Attaches a passive effect to the `MotionValue`. */ attach(passiveEffect, stopPassiveEffect) { this.passiveEffect = passiveEffect; this.stopPassiveEffect = stopPassiveEffect; } /** * Sets the state of the `MotionValue`. * * @remarks * * ```jsx * const x = useMotionValue(0) * x.set(10) * ``` * * @param latest - Latest value to set. * @param render - Whether to notify render subscribers. Defaults to `true` * * @public */ set(v, render = true) { if (!render || !this.passiveEffect) { this.updateAndNotify(v, render); } else { this.passiveEffect(v, this.updateAndNotify); } } setWithVelocity(prev, current, delta) { this.set(current); this.prev = void 0; this.prevFrameValue = prev; this.prevUpdatedAt = this.updatedAt - delta; } /** * Set the state of the `MotionValue`, stopping any active animations, * effects, and resets velocity to `0`. */ jump(v, endAnimation = true) { this.updateAndNotify(v); this.prev = v; this.prevUpdatedAt = this.prevFrameValue = void 0; endAnimation && this.stop(); if (this.stopPassiveEffect) this.stopPassiveEffect(); } dirty() { var _a; (_a = this.events.change) == null ? void 0 : _a.notify(this.current); } addDependent(dependent) { if (!this.dependents) { this.dependents = /* @__PURE__ */ new Set(); } this.dependents.add(dependent); } removeDependent(dependent) { if (this.dependents) { this.dependents.delete(dependent); } } /** * Returns the latest state of `MotionValue` * * @returns - The latest state of `MotionValue` * * @public */ get() { return this.current; } /** * @public */ getPrevious() { return this.prev; } /** * Returns the latest velocity of `MotionValue` * * @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical. * * @public */ getVelocity() { const currentTime = time.now(); if (!this.canTrackVelocity || this.prevFrameValue === void 0 || currentTime - this.updatedAt > MAX_VELOCITY_DELTA) { return 0; } const delta = Math.min(this.updatedAt - this.prevUpdatedAt, MAX_VELOCITY_DELTA); return velocityPerSecond(parseFloat(this.current) - parseFloat(this.prevFrameValue), delta); } /** * Registers a new animation to control this `MotionValue`. Only one * animation can drive a `MotionValue` at one time. * * ```jsx * value.start() * ``` * * @param animation - A function that starts the provided animation */ start(startAnimation) { this.stop(); return new Promise((resolve) => { this.hasAnimated = true; this.animation = startAnimation(resolve); if (this.events.animationStart) { this.events.animationStart.notify(); } }).then(() => { if (this.events.animationComplete) { this.events.animationComplete.notify(); } this.clearAnimation(); }); } /** * Stop the currently active animation. * * @public */ stop() { if (this.animation) { this.animation.stop(); if (this.events.animationCancel) { this.events.animationCancel.notify(); } } this.clearAnimation(); } /** * Returns `true` if this value is currently animating. * * @public */ isAnimating() { return !!this.animation; } clearAnimation() { delete this.animation; } /** * Destroy and clean up subscribers to this `MotionValue`. * * The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically * handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually * created a `MotionValue` via the `motionValue` function. * * @public */ destroy() { var _a, _b; (_a = this.dependents) == null ? void 0 : _a.clear(); (_b = this.events.destroy) == null ? void 0 : _b.notify(); this.clearListeners(); this.stop(); if (this.stopPassiveEffect) { this.stopPassiveEffect(); } } } function motionValue(init, options) { return new MotionValue(init, options); } function updateMotionValuesFromProps(element, next, prev) { for (const key in next) { const nextValue = next[key]; const prevValue = prev[key]; if (isMotionValue(nextValue)) { element.addValue(key, nextValue); } else if (isMotionValue(prevValue)) { element.addValue(key, motionValue(nextValue, { owner: element })); } else if (prevValue !== nextValue) { if (element.hasValue(key)) { const existingValue = element.getValue(key); if (existingValue.liveStyle === true) { existingValue.jump(nextValue); } else if (!existingValue.hasAnimated) { existingValue.set(nextValue); } } else { const latestValue = element.getStaticValue(key); element.addValue(key, motionValue(latestValue !== void 0 ? latestValue : nextValue, { owner: element })); } } } for (const key in prev) { if (next[key] === void 0) element.removeValue(key); } return next; } function getValueState(visualElement) { const state = [{}, {}]; visualElement == null ? void 0 : visualElement.values.forEach((value, key) => { state[0][key] = value.get(); state[1][key] = value.getVelocity(); }); return state; } function resolveVariantFromProps(props, definition, custom, visualElement) { if (typeof definition === "function") { const [current, velocity] = getValueState(visualElement); definition = definition(custom !== void 0 ? custom : props.custom, current, velocity); } if (typeof definition === "string") { definition = props.variants && props.variants[definition]; } if (typeof definition === "function") { const [current, velocity] = getValueState(visualElement); definition = definition(custom !== void 0 ? custom : props.custom, current, velocity); } return definition; } function fillWildcards(keyframes2) { for (let i = 1; i < keyframes2.length; i++) { keyframes2[i] ?? (keyframes2[i] = keyframes2[i - 1]); } } const radToDeg = (rad) => rad * 180 / Math.PI; const rotate = (v) => { const angle = radToDeg(Math.atan2(v[1], v[0])); return rebaseAngle(angle); }; const matrix2dParsers = { x: 4, y: 5, translateX: 4, translateY: 5, scaleX: 0, scaleY: 3, scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2, rotate, rotateZ: rotate, skewX: (v) => radToDeg(Math.atan(v[1])), skewY: (v) => radToDeg(Math.atan(v[2])), skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2 }; const rebaseAngle = (angle) => { angle = angle % 360; if (angle < 0) angle += 360; return angle; }; const rotateZ = rotate; const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]); const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]); const matrix3dParsers = { x: 12, y: 13, z: 14, translateX: 12, translateY: 13, translateZ: 14, scaleX, scaleY, scale: (v) => (scaleX(v) + scaleY(v)) / 2, rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))), rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))), rotateZ, rotate: rotateZ, skewX: (v) => radToDeg(Math.atan(v[4])), skewY: (v) => radToDeg(Math.atan(v[1])), skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2 }; function defaultTransformValue(name) { return name.includes("scale") ? 1 : 0; } function parseValueFromTransform(transform, name) { if (!transform || transform === "none") { return defaultTransformValue(name); } const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u); let parsers; let match; if (matrix3dMatch) { parsers = matrix3dParsers; match = matrix3dMatch; } else { const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u); parsers = matrix2dParsers; match = matrix2dMatch; } if (!match) { return defaultTransformValue(name); } const valueParser = parsers[name]; const values = match[1].split(",").map(convertTransformToNumber); return typeof valueParser === "function" ? valueParser(values) : values[valueParser]; } const readTransformValue = (instance, name) => { const { transform = "none" } = getComputedStyle(instance); return parseValueFromTransform(transform, name); }; function convertTransformToNumber(value) { return parseFloat(value.trim()); } const transformPropOrder = [ "transformPerspective", "x", "y", "z", "translateX", "translateY", "translateZ", "scale", "scaleX", "scaleY", "rotate", "rotateX", "rotateY", "rotateZ", "skew", "skewX", "skewY" ]; const transformProps = /* @__PURE__ */ (() => new Set(transformPropOrder))(); const clamp$1 = (min, max, v) => { if (v > max) return max; if (v < min) return min; return v; }; const number = { test: (v) => typeof v === "number", parse: parseFloat, transform: (v) => v }; const alpha = { ...number, transform: (v) => clamp$1(0, 1, v) }; const scale = { ...number, default: 1 }; const createUnitType = /* @__NO_SIDE_EFFECTS__ */ (unit) => ({ test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1, parse: parseFloat, transform: (v) => `${v}${unit}` }); const degrees = /* @__PURE__ */ createUnitType("deg"); const percent = /* @__PURE__ */ createUnitType("%"); const px = /* @__PURE__ */ createUnitType("px"); const vh = /* @__PURE__ */ createUnitType("vh"); const vw = /* @__PURE__ */ createUnitType("vw"); const progressPercentage = /* @__PURE__ */ (() => ({ ...percent, parse: (v) => percent.parse(v) / 100, transform: (v) => percent.transform(v * 100) }))(); const isNumOrPxType = (v) => v === number || v === px; const transformKeys = /* @__PURE__ */ new Set(["x", "y", "z"]); const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key)); function removeNonTranslationalTransform(visualElement) { const removedTransforms = []; nonTranslationalTransformKeys.forEach((key) => { const value = visualElement.getValue(key); if (value !== void 0) { removedTransforms.push([key, value.get()]); value.set(key.startsWith("scale") ? 1 : 0); } }); return removedTransforms; } const positionalValues = { // Dimensions width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight), height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom), top: (_bbox, { top }) => parseFloat(top), left: (_bbox, { left }) => parseFloat(left), bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min), right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min), // Transform x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"), y: (_bbox, { transform }) => parseValueFromTransform(transform, "y") }; positionalValues.translateX = positionalValues.x; positionalValues.translateY = positionalValues.y; const toResolve = /* @__PURE__ */ new Set(); let isScheduled = false; let anyNeedsMeasurement = false; let isForced = false; function measureAllKeyframes() { if (anyNeedsMeasurement) { const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement); const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element)); const transformsToRestore = /* @__PURE__ */ new Map(); elementsToMeasure.forEach((element) => { const removedTransforms = removeNonTranslationalTransform(element); if (!removedTransforms.length) return; transformsToRestore.set(element, removedTransforms); element.render(); }); resolversToMeasure.forEach((resolver) => resolver.measureInitialState()); elementsToMeasure.forEach((element) => { element.render(); const restore = transformsToRestore.get(element); if (restore) { restore.forEach(([key, value]) => { var _a; (_a = element.getValue(key)) == null ? void 0 : _a.set(value); }); } }); resolversToMeasure.forEach((resolver) => resolver.measureEndState()); resolversToMeasure.forEach((resolver) => { if (resolver.suspendedScrollY !== void 0) { window.scrollTo(0, resolver.suspendedScrollY); } }); } anyNeedsMeasurement = false; isScheduled = false; toResolve.forEach((resolver) => resolver.complete(isForced)); toResolve.clear(); } function readAllKeyframes() { toResolve.forEach((resolver) => { resolver.readKeyframes(); if (resolver.needsMeasurement) { anyNeedsMeasurement = true; } }); } function flushKeyframeResolvers() { isForced = true; readAllKeyframes(); measureAllKeyframes(); isForced = false; } class KeyframeResolver { constructor(unresolvedKeyframes, onComplete, name, motionValue2, element, isAsync = false) { this.state = "pending"; this.isAsync = false; this.needsMeasurement = false; this.unresolvedKeyframes = [...unresolvedKeyframes]; this.onComplete = onComplete; this.name = name; this.motionValue = motionValue2; this.element = element; this.isAsync = isAsync; } scheduleResolve() { this.state = "scheduled"; if (this.isAsync) { toResolve.add(this); if (!isScheduled) { isScheduled = true; frame.read(readAllKeyframes); frame.resolveKeyframes(measureAllKeyframes); } } else { this.readKeyframes(); this.complete(); } } readKeyframes() { const { unresolvedKeyframes, name, element, motionValue: motionValue2 } = this; if (unresolvedKeyframes[0] === null) { const currentValue = motionValue2 == null ? void 0 : motionValue2.get(); const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1]; if (currentValue !== void 0) { unresolvedKeyframes[0] = currentValue; } else if (element && name) { const valueAsRead = element.readValue(name, finalKeyframe); if (valueAsRead !== void 0 && valueAsRead !== null) { unresolvedKeyframes[0] = valueAsRead; } } if (unresolvedKeyframes[0] === void 0) { unresolvedKeyframes[0] = finalKeyframe; } if (motionValue2 && currentValue === void 0) { motionValue2.set(unresolvedKeyframes[0]); } } fillWildcards(unresolvedKeyframes); } setFinalKeyframe() { } measureInitialState() { } renderEndStyles() { } measureEndState