UNPKG

@vueuse/core

Version:

Collection of essential Vue Composition Utilities

1,617 lines (1,584 loc) 270 kB
import { bypassFilter, camelize, clamp, computedWithControl, containsProp, createEventHook, createFilterWrapper, createRef, createSingletonPromise, debounceFilter, hasOwn, identity, increaseWithUnit, injectLocal, isClient, isDef, isIOS, isObject, isWorker, makeDestructurable, noop, notNullish, objectEntries, objectOmit, objectPick, pausableFilter, pausableWatch, promiseTimeout, provideLocal, pxValue, syncRef, throttleFilter, timestamp, toArray, toRef, toRefs, tryOnMounted, tryOnScopeDispose, tryOnUnmounted, until, useDebounceFn, useIntervalFn, useThrottleFn, useTimeoutFn, watchIgnorable, watchImmediate, watchOnce, watchWithFilter, whenever } from "@vueuse/shared"; import { Fragment, TransitionGroup, computed, customRef, defineComponent, getCurrentInstance, getCurrentScope, h, hasInjectionContext, inject, isReadonly, isRef, markRaw, nextTick, onBeforeUpdate, onMounted, onUpdated, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRaw, toValue, unref, watch, watchEffect } from "vue"; export * from "@vueuse/shared" //#region computedAsync/index.ts function computedAsync(evaluationCallback, initialState, optionsOrRef) { var _globalThis$reportErr; let options; if (isRef(optionsOrRef)) options = { evaluating: optionsOrRef }; else options = optionsOrRef || {}; const { lazy = false, flush = "sync", evaluating = void 0, shallow = true, onError = (_globalThis$reportErr = globalThis.reportError) !== null && _globalThis$reportErr !== void 0 ? _globalThis$reportErr : noop } = options; const started = shallowRef(!lazy); const current = shallow ? shallowRef(initialState) : ref(initialState); let counter = 0; watchEffect(async (onInvalidate) => { if (!started.value) return; counter++; const counterAtBeginning = counter; let hasFinished = false; if (evaluating) Promise.resolve().then(() => { evaluating.value = true; }); try { const result = await evaluationCallback((cancelCallback) => { onInvalidate(() => { if (evaluating) evaluating.value = false; if (!hasFinished) cancelCallback(); }); }); if (counterAtBeginning === counter) current.value = result; } catch (e) { onError(e); } finally { if (evaluating && counterAtBeginning === counter) evaluating.value = false; hasFinished = true; } }, { flush }); if (lazy) return computed(() => { started.value = true; return current.value; }); else return current; } /** @deprecated use `computedAsync` instead */ const asyncComputed = computedAsync; //#endregion //#region computedInject/index.ts function computedInject(key, options, defaultSource, treatDefaultAsFactory) { let source = inject(key); if (defaultSource) source = inject(key, defaultSource); if (treatDefaultAsFactory) source = inject(key, defaultSource, treatDefaultAsFactory); if (typeof options === "function") return computed((oldValue) => options(source, oldValue)); else return computed({ get: (oldValue) => options.get(source, oldValue), set: options.set }); } //#endregion //#region createReusableTemplate/index.ts /** * This function creates `define` and `reuse` components in pair, * It also allow to pass a generic to bind with type. * * @see https://vueuse.org/createReusableTemplate * * @__NO_SIDE_EFFECTS__ */ function createReusableTemplate(options = {}) { const { inheritAttrs = true } = options; const render = shallowRef(); const define = defineComponent({ setup(_, { slots }) { return () => { render.value = slots.default; }; } }); const reuse = defineComponent({ inheritAttrs, props: options.props, setup(props, { attrs, slots }) { return () => { var _render$value; if (!render.value && true) throw new Error("[VueUse] Failed to find the definition of reusable template"); const vnode = (_render$value = render.value) === null || _render$value === void 0 ? void 0 : _render$value.call(render, { ...options.props == null ? keysToCamelKebabCase(attrs) : props, $slots: slots }); return inheritAttrs && (vnode === null || vnode === void 0 ? void 0 : vnode.length) === 1 ? vnode[0] : vnode; }; } }); return makeDestructurable({ define, reuse }, [define, reuse]); } function keysToCamelKebabCase(obj) { const newObj = {}; for (const key in obj) newObj[camelize(key)] = obj[key]; return newObj; } //#endregion //#region createTemplatePromise/index.ts /** * Creates a template promise component. * * @see https://vueuse.org/createTemplatePromise * * @__NO_SIDE_EFFECTS__ */ function createTemplatePromise(options = {}) { let index = 0; const instances = ref([]); function create(...args) { const props = shallowReactive({ key: index++, args, promise: void 0, resolve: () => {}, reject: () => {}, isResolving: false, options }); instances.value.push(props); props.promise = new Promise((_resolve, _reject) => { props.resolve = (v) => { props.isResolving = true; return _resolve(v); }; props.reject = _reject; }).finally(() => { props.promise = void 0; const index$1 = instances.value.indexOf(props); if (index$1 !== -1) instances.value.splice(index$1, 1); }); return props.promise; } function start(...args) { if (options.singleton && instances.value.length > 0) return instances.value[0].promise; return create(...args); } const component = defineComponent((_, { slots }) => { const renderList = () => instances.value.map((props) => { var _slots$default; return h(Fragment, { key: props.key }, (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots, props)); }); if (options.transition) return () => h(TransitionGroup, options.transition, renderList); return renderList; }); component.start = start; return component; } //#endregion //#region createUnrefFn/index.ts /** * Make a plain function accepting ref and raw values as arguments. * Returns the same value the unconverted function returns, with proper typing. * * @__NO_SIDE_EFFECTS__ */ function createUnrefFn(fn) { return function(...args) { return fn.apply(this, args.map((i) => toValue(i))); }; } //#endregion //#region _configurable.ts const defaultWindow = isClient ? window : void 0; const defaultDocument = isClient ? window.document : void 0; const defaultNavigator = isClient ? window.navigator : void 0; const defaultLocation = isClient ? window.location : void 0; //#endregion //#region unrefElement/index.ts /** * Get the dom element of a ref of element or Vue component instance * * @param elRef */ function unrefElement(elRef) { var _$el; const plain = toValue(elRef); return (_$el = plain === null || plain === void 0 ? void 0 : plain.$el) !== null && _$el !== void 0 ? _$el : plain; } //#endregion //#region useEventListener/index.ts function useEventListener(...args) { const register = (el, event, listener, options) => { el.addEventListener(event, listener, options); return () => el.removeEventListener(event, listener, options); }; const firstParamTargets = computed(() => { const test = toArray(toValue(args[0])).filter((e) => e != null); return test.every((e) => typeof e !== "string") ? test : void 0; }); return watchImmediate(() => { var _firstParamTargets$va, _firstParamTargets$va2; return [ (_firstParamTargets$va = (_firstParamTargets$va2 = firstParamTargets.value) === null || _firstParamTargets$va2 === void 0 ? void 0 : _firstParamTargets$va2.map((e) => unrefElement(e))) !== null && _firstParamTargets$va !== void 0 ? _firstParamTargets$va : [defaultWindow].filter((e) => e != null), toArray(toValue(firstParamTargets.value ? args[1] : args[0])), toArray(unref(firstParamTargets.value ? args[2] : args[1])), toValue(firstParamTargets.value ? args[3] : args[2]) ]; }, ([raw_targets, raw_events, raw_listeners, raw_options], _, onCleanup) => { if (!(raw_targets === null || raw_targets === void 0 ? void 0 : raw_targets.length) || !(raw_events === null || raw_events === void 0 ? void 0 : raw_events.length) || !(raw_listeners === null || raw_listeners === void 0 ? void 0 : raw_listeners.length)) return; const optionsClone = isObject(raw_options) ? { ...raw_options } : raw_options; const cleanups = raw_targets.flatMap((el) => raw_events.flatMap((event) => raw_listeners.map((listener) => register(el, event, listener, optionsClone)))); onCleanup(() => { cleanups.forEach((fn) => fn()); }); }, { flush: "post" }); } //#endregion //#region onClickOutside/index.ts let _iOSWorkaround = false; function onClickOutside(target, handler, options = {}) { const { window: window$1 = defaultWindow, ignore = [], capture = true, detectIframe = false, controls = false } = options; if (!window$1) return controls ? { stop: noop, cancel: noop, trigger: noop } : noop; if (isIOS && !_iOSWorkaround) { _iOSWorkaround = true; const listenerOptions = { passive: true }; Array.from(window$1.document.body.children).forEach((el) => el.addEventListener("click", noop, listenerOptions)); window$1.document.documentElement.addEventListener("click", noop, listenerOptions); } let shouldListen = true; const shouldIgnore = (event) => { return toValue(ignore).some((target$1) => { if (typeof target$1 === "string") return Array.from(window$1.document.querySelectorAll(target$1)).some((el) => el === event.target || event.composedPath().includes(el)); else { const el = unrefElement(target$1); return el && (event.target === el || event.composedPath().includes(el)); } }); }; /** * Determines if the given target has multiple root elements. * Referenced from: https://github.com/vuejs/test-utils/blob/ccb460be55f9f6be05ab708500a41ec8adf6f4bc/src/vue-wrapper.ts#L21 */ function hasMultipleRoots(target$1) { const vm = toValue(target$1); return vm && vm.$.subTree.shapeFlag === 16; } function checkMultipleRoots(target$1, event) { const vm = toValue(target$1); const children = vm.$.subTree && vm.$.subTree.children; if (children == null || !Array.isArray(children)) return false; return children.some((child) => child.el === event.target || event.composedPath().includes(child.el)); } const listener = (event) => { const el = unrefElement(target); if (event.target == null) return; if (!(el instanceof Element) && hasMultipleRoots(target) && checkMultipleRoots(target, event)) return; if (!el || el === event.target || event.composedPath().includes(el)) return; if ("detail" in event && event.detail === 0) shouldListen = !shouldIgnore(event); if (!shouldListen) { shouldListen = true; return; } handler(event); }; let isProcessingClick = false; const cleanup = [ useEventListener(window$1, "click", (event) => { if (!isProcessingClick) { isProcessingClick = true; setTimeout(() => { isProcessingClick = false; }, 0); listener(event); } }, { passive: true, capture }), useEventListener(window$1, "pointerdown", (e) => { const el = unrefElement(target); shouldListen = !shouldIgnore(e) && !!(el && !e.composedPath().includes(el)); }, { passive: true }), detectIframe && useEventListener(window$1, "blur", (event) => { setTimeout(() => { var _window$document$acti; const el = unrefElement(target); if (((_window$document$acti = window$1.document.activeElement) === null || _window$document$acti === void 0 ? void 0 : _window$document$acti.tagName) === "IFRAME" && !(el === null || el === void 0 ? void 0 : el.contains(window$1.document.activeElement))) handler(event); }, 0); }, { passive: true }) ].filter(Boolean); const stop = () => cleanup.forEach((fn) => fn()); if (controls) return { stop, cancel: () => { shouldListen = false; }, trigger: (event) => { shouldListen = true; listener(event); shouldListen = false; } }; return stop; } //#endregion //#region useMounted/index.ts /** * Mounted state in ref. * * @see https://vueuse.org/useMounted * * @__NO_SIDE_EFFECTS__ */ function useMounted() { const isMounted = shallowRef(false); const instance = getCurrentInstance(); if (instance) onMounted(() => { isMounted.value = true; }, instance); return isMounted; } //#endregion //#region useSupported/index.ts /* @__NO_SIDE_EFFECTS__ */ function useSupported(callback) { const isMounted = useMounted(); return computed(() => { isMounted.value; return Boolean(callback()); }); } //#endregion //#region useMutationObserver/index.ts /** * Watch for changes being made to the DOM tree. * * @see https://vueuse.org/useMutationObserver * @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver MutationObserver MDN * @param target * @param callback * @param options */ function useMutationObserver(target, callback, options = {}) { const { window: window$1 = defaultWindow,...mutationOptions } = options; let observer; const isSupported = /* @__PURE__ */ useSupported(() => window$1 && "MutationObserver" in window$1); const cleanup = () => { if (observer) { observer.disconnect(); observer = void 0; } }; const stopWatch = watch(computed(() => { const items = toArray(toValue(target)).map(unrefElement).filter(notNullish); return new Set(items); }), (newTargets) => { cleanup(); if (isSupported.value && newTargets.size) { observer = new MutationObserver(callback); newTargets.forEach((el) => observer.observe(el, mutationOptions)); } }, { immediate: true, flush: "post" }); const takeRecords = () => { return observer === null || observer === void 0 ? void 0 : observer.takeRecords(); }; const stop = () => { stopWatch(); cleanup(); }; tryOnScopeDispose(stop); return { isSupported, stop, takeRecords }; } //#endregion //#region onElementRemoval/index.ts /** * Fires when the element or any element containing it is removed. * * @param target * @param callback * @param options */ function onElementRemoval(target, callback, options = {}) { const { window: window$1 = defaultWindow, document: document$1 = window$1 === null || window$1 === void 0 ? void 0 : window$1.document, flush = "sync" } = options; if (!window$1 || !document$1) return noop; let stopFn; const cleanupAndUpdate = (fn) => { stopFn === null || stopFn === void 0 || stopFn(); stopFn = fn; }; const stopWatch = watchEffect(() => { const el = unrefElement(target); if (el) { const { stop } = useMutationObserver(document$1, (mutationsList) => { if (mutationsList.map((mutation) => [...mutation.removedNodes]).flat().some((node) => node === el || node.contains(el))) callback(mutationsList); }, { window: window$1, childList: true, subtree: true }); cleanupAndUpdate(stop); } }, { flush }); const stopHandle = () => { stopWatch(); cleanupAndUpdate(); }; tryOnScopeDispose(stopHandle); return stopHandle; } //#endregion //#region onKeyStroke/index.ts function createKeyPredicate(keyFilter) { if (typeof keyFilter === "function") return keyFilter; else if (typeof keyFilter === "string") return (event) => event.key === keyFilter; else if (Array.isArray(keyFilter)) return (event) => keyFilter.includes(event.key); return () => true; } function onKeyStroke(...args) { let key; let handler; let options = {}; if (args.length === 3) { key = args[0]; handler = args[1]; options = args[2]; } else if (args.length === 2) if (typeof args[1] === "object") { key = true; handler = args[0]; options = args[1]; } else { key = args[0]; handler = args[1]; } else { key = true; handler = args[0]; } const { target = defaultWindow, eventName = "keydown", passive = false, dedupe = false } = options; const predicate = createKeyPredicate(key); const listener = (e) => { if (e.repeat && toValue(dedupe)) return; if (predicate(e)) handler(e); }; return useEventListener(target, eventName, listener, passive); } /** * Listen to the keydown event of the given key. * * @see https://vueuse.org/onKeyStroke * @param key * @param handler * @param options */ function onKeyDown(key, handler, options = {}) { return onKeyStroke(key, handler, { ...options, eventName: "keydown" }); } /** * Listen to the keypress event of the given key. * * @see https://vueuse.org/onKeyStroke * @param key * @param handler * @param options */ function onKeyPressed(key, handler, options = {}) { return onKeyStroke(key, handler, { ...options, eventName: "keypress" }); } /** * Listen to the keyup event of the given key. * * @see https://vueuse.org/onKeyStroke * @param key * @param handler * @param options */ function onKeyUp(key, handler, options = {}) { return onKeyStroke(key, handler, { ...options, eventName: "keyup" }); } //#endregion //#region onLongPress/index.ts const DEFAULT_DELAY = 500; const DEFAULT_THRESHOLD = 10; function onLongPress(target, handler, options) { var _options$modifiers10, _options$modifiers11; const elementRef = computed(() => unrefElement(target)); let timeout; let posStart; let startTimestamp; let hasLongPressed = false; function clear() { if (timeout) { clearTimeout(timeout); timeout = void 0; } posStart = void 0; startTimestamp = void 0; hasLongPressed = false; } function getDelay(ev) { const delay = options === null || options === void 0 ? void 0 : options.delay; if (typeof delay === "function") return delay(ev); return delay !== null && delay !== void 0 ? delay : DEFAULT_DELAY; } function onRelease(ev) { var _options$modifiers, _options$modifiers2, _options$modifiers3; const [_startTimestamp, _posStart, _hasLongPressed] = [ startTimestamp, posStart, hasLongPressed ]; clear(); if (!(options === null || options === void 0 ? void 0 : options.onMouseUp) || !_posStart || !_startTimestamp) return; if ((options === null || options === void 0 || (_options$modifiers = options.modifiers) === null || _options$modifiers === void 0 ? void 0 : _options$modifiers.self) && ev.target !== elementRef.value) return; if (options === null || options === void 0 || (_options$modifiers2 = options.modifiers) === null || _options$modifiers2 === void 0 ? void 0 : _options$modifiers2.prevent) ev.preventDefault(); if (options === null || options === void 0 || (_options$modifiers3 = options.modifiers) === null || _options$modifiers3 === void 0 ? void 0 : _options$modifiers3.stop) ev.stopPropagation(); const dx = ev.x - _posStart.x; const dy = ev.y - _posStart.y; const distance = Math.sqrt(dx * dx + dy * dy); options.onMouseUp(ev.timeStamp - _startTimestamp, distance, _hasLongPressed); } function onDown(ev) { var _options$modifiers4, _options$modifiers5, _options$modifiers6; if ((options === null || options === void 0 || (_options$modifiers4 = options.modifiers) === null || _options$modifiers4 === void 0 ? void 0 : _options$modifiers4.self) && ev.target !== elementRef.value) return; clear(); if (options === null || options === void 0 || (_options$modifiers5 = options.modifiers) === null || _options$modifiers5 === void 0 ? void 0 : _options$modifiers5.prevent) ev.preventDefault(); if (options === null || options === void 0 || (_options$modifiers6 = options.modifiers) === null || _options$modifiers6 === void 0 ? void 0 : _options$modifiers6.stop) ev.stopPropagation(); posStart = { x: ev.x, y: ev.y }; startTimestamp = ev.timeStamp; timeout = setTimeout(() => { hasLongPressed = true; handler(ev); }, getDelay(ev)); } function onMove(ev) { var _options$modifiers7, _options$modifiers8, _options$modifiers9, _options$distanceThre; if ((options === null || options === void 0 || (_options$modifiers7 = options.modifiers) === null || _options$modifiers7 === void 0 ? void 0 : _options$modifiers7.self) && ev.target !== elementRef.value) return; if (!posStart || (options === null || options === void 0 ? void 0 : options.distanceThreshold) === false) return; if (options === null || options === void 0 || (_options$modifiers8 = options.modifiers) === null || _options$modifiers8 === void 0 ? void 0 : _options$modifiers8.prevent) ev.preventDefault(); if (options === null || options === void 0 || (_options$modifiers9 = options.modifiers) === null || _options$modifiers9 === void 0 ? void 0 : _options$modifiers9.stop) ev.stopPropagation(); const dx = ev.x - posStart.x; const dy = ev.y - posStart.y; if (Math.sqrt(dx * dx + dy * dy) >= ((_options$distanceThre = options === null || options === void 0 ? void 0 : options.distanceThreshold) !== null && _options$distanceThre !== void 0 ? _options$distanceThre : DEFAULT_THRESHOLD)) clear(); } const listenerOptions = { capture: options === null || options === void 0 || (_options$modifiers10 = options.modifiers) === null || _options$modifiers10 === void 0 ? void 0 : _options$modifiers10.capture, once: options === null || options === void 0 || (_options$modifiers11 = options.modifiers) === null || _options$modifiers11 === void 0 ? void 0 : _options$modifiers11.once }; const cleanup = [ useEventListener(elementRef, "pointerdown", onDown, listenerOptions), useEventListener(elementRef, "pointermove", onMove, listenerOptions), useEventListener(elementRef, ["pointerup", "pointerleave"], onRelease, listenerOptions) ]; const stop = () => cleanup.forEach((fn) => fn()); return stop; } //#endregion //#region onStartTyping/index.ts function isFocusedElementEditable() { const { activeElement, body } = document; if (!activeElement) return false; if (activeElement === body) return false; switch (activeElement.tagName) { case "INPUT": case "TEXTAREA": return true; } return activeElement.hasAttribute("contenteditable"); } function isTypedCharValid({ keyCode, metaKey, ctrlKey, altKey }) { if (metaKey || ctrlKey || altKey) return false; if (keyCode >= 48 && keyCode <= 57 || keyCode >= 96 && keyCode <= 105) return true; if (keyCode >= 65 && keyCode <= 90) return true; return false; } /** * Fires when users start typing on non-editable elements. * * @see https://vueuse.org/onStartTyping * @param callback * @param options */ function onStartTyping(callback, options = {}) { const { document: document$1 = defaultDocument } = options; const keydown = (event) => { if (!isFocusedElementEditable() && isTypedCharValid(event)) callback(event); }; if (document$1) useEventListener(document$1, "keydown", keydown, { passive: true }); } //#endregion //#region templateRef/index.ts /** * @deprecated Use Vue's built-in `useTemplateRef` instead. * * Shorthand for binding ref to template element. * * @see https://vueuse.org/templateRef * @param key * @param initialValue * * @__NO_SIDE_EFFECTS__ */ function templateRef(key, initialValue = null) { const instance = getCurrentInstance(); let _trigger = () => {}; const element = customRef((track, trigger) => { _trigger = trigger; return { get() { var _instance$proxy$$refs, _instance$proxy; track(); return (_instance$proxy$$refs = instance === null || instance === void 0 || (_instance$proxy = instance.proxy) === null || _instance$proxy === void 0 ? void 0 : _instance$proxy.$refs[key]) !== null && _instance$proxy$$refs !== void 0 ? _instance$proxy$$refs : initialValue; }, set() {} }; }); tryOnMounted(_trigger); onUpdated(_trigger); return element; } //#endregion //#region useActiveElement/index.ts /** * Reactive `document.activeElement` * * @see https://vueuse.org/useActiveElement * @param options * * @__NO_SIDE_EFFECTS__ */ function useActiveElement(options = {}) { var _options$document; const { window: window$1 = defaultWindow, deep = true, triggerOnRemoval = false } = options; const document$1 = (_options$document = options.document) !== null && _options$document !== void 0 ? _options$document : window$1 === null || window$1 === void 0 ? void 0 : window$1.document; const getDeepActiveElement = () => { let element = document$1 === null || document$1 === void 0 ? void 0 : document$1.activeElement; if (deep) { var _element$shadowRoot; while (element === null || element === void 0 ? void 0 : element.shadowRoot) element = element === null || element === void 0 || (_element$shadowRoot = element.shadowRoot) === null || _element$shadowRoot === void 0 ? void 0 : _element$shadowRoot.activeElement; } return element; }; const activeElement = shallowRef(); const trigger = () => { activeElement.value = getDeepActiveElement(); }; if (window$1) { const listenerOptions = { capture: true, passive: true }; useEventListener(window$1, "blur", (event) => { if (event.relatedTarget !== null) return; trigger(); }, listenerOptions); useEventListener(window$1, "focus", trigger, listenerOptions); } if (triggerOnRemoval) onElementRemoval(activeElement, trigger, { document: document$1 }); trigger(); return activeElement; } //#endregion //#region useRafFn/index.ts /** * Call function on every `requestAnimationFrame`. With controls of pausing and resuming. * * @see https://vueuse.org/useRafFn * @param fn * @param options */ function useRafFn(fn, options = {}) { const { immediate = true, fpsLimit = void 0, window: window$1 = defaultWindow, once = false } = options; const isActive = shallowRef(false); const intervalLimit = computed(() => { return fpsLimit ? 1e3 / toValue(fpsLimit) : null; }); let previousFrameTimestamp = 0; let rafId = null; function loop(timestamp$1) { if (!isActive.value || !window$1) return; if (!previousFrameTimestamp) previousFrameTimestamp = timestamp$1; const delta = timestamp$1 - previousFrameTimestamp; if (intervalLimit.value && delta < intervalLimit.value) { rafId = window$1.requestAnimationFrame(loop); return; } previousFrameTimestamp = timestamp$1; fn({ delta, timestamp: timestamp$1 }); if (once) { isActive.value = false; rafId = null; return; } rafId = window$1.requestAnimationFrame(loop); } function resume() { if (!isActive.value && window$1) { isActive.value = true; previousFrameTimestamp = 0; rafId = window$1.requestAnimationFrame(loop); } } function pause() { isActive.value = false; if (rafId != null && window$1) { window$1.cancelAnimationFrame(rafId); rafId = null; } } if (immediate) resume(); tryOnScopeDispose(pause); return { isActive: readonly(isActive), pause, resume }; } //#endregion //#region useAnimate/index.ts /** * Reactive Web Animations API * * @see https://vueuse.org/useAnimate * @param target * @param keyframes * @param options */ function useAnimate(target, keyframes, options) { let config; let animateOptions; if (isObject(options)) { config = options; animateOptions = objectOmit(options, [ "window", "immediate", "commitStyles", "persist", "onReady", "onError" ]); } else { config = { duration: options }; animateOptions = options; } const { window: window$1 = defaultWindow, immediate = true, commitStyles, persist, playbackRate: _playbackRate = 1, onReady, onError = (e) => { console.error(e); } } = config; const isSupported = /* @__PURE__ */ useSupported(() => window$1 && HTMLElement && "animate" in HTMLElement.prototype); const animate = shallowRef(void 0); const store = shallowReactive({ startTime: null, currentTime: null, timeline: null, playbackRate: _playbackRate, pending: false, playState: immediate ? "idle" : "paused", replaceState: "active" }); const pending = computed(() => store.pending); const playState = computed(() => store.playState); const replaceState = computed(() => store.replaceState); const startTime = computed({ get() { return store.startTime; }, set(value) { store.startTime = value; if (animate.value) animate.value.startTime = value; } }); const currentTime = computed({ get() { return store.currentTime; }, set(value) { store.currentTime = value; if (animate.value) { animate.value.currentTime = value; syncResume(); } } }); const timeline = computed({ get() { return store.timeline; }, set(value) { store.timeline = value; if (animate.value) animate.value.timeline = value; } }); const playbackRate = computed({ get() { return store.playbackRate; }, set(value) { store.playbackRate = value; if (animate.value) animate.value.playbackRate = value; } }); const play = () => { if (animate.value) try { animate.value.play(); syncResume(); } catch (e) { syncPause(); onError(e); } else update(); }; const pause = () => { try { var _animate$value; (_animate$value = animate.value) === null || _animate$value === void 0 || _animate$value.pause(); syncPause(); } catch (e) { onError(e); } }; const reverse = () => { if (!animate.value) update(); try { var _animate$value2; (_animate$value2 = animate.value) === null || _animate$value2 === void 0 || _animate$value2.reverse(); syncResume(); } catch (e) { syncPause(); onError(e); } }; const finish = () => { try { var _animate$value3; (_animate$value3 = animate.value) === null || _animate$value3 === void 0 || _animate$value3.finish(); syncPause(); } catch (e) { onError(e); } }; const cancel = () => { try { var _animate$value4; (_animate$value4 = animate.value) === null || _animate$value4 === void 0 || _animate$value4.cancel(); syncPause(); } catch (e) { onError(e); } }; watch(() => unrefElement(target), (el) => { if (el) update(true); else animate.value = void 0; }); watch(() => keyframes, (value) => { if (animate.value) { update(); const targetEl = unrefElement(target); if (targetEl) animate.value.effect = new KeyframeEffect(targetEl, toValue(value), animateOptions); } }, { deep: true }); tryOnMounted(() => update(true), false); tryOnScopeDispose(cancel); function update(init) { const el = unrefElement(target); if (!isSupported.value || !el) return; if (!animate.value) animate.value = el.animate(toValue(keyframes), animateOptions); if (persist) animate.value.persist(); if (_playbackRate !== 1) animate.value.playbackRate = _playbackRate; if (init && !immediate) animate.value.pause(); else syncResume(); onReady === null || onReady === void 0 || onReady(animate.value); } const listenerOptions = { passive: true }; useEventListener(animate, [ "cancel", "finish", "remove" ], syncPause, listenerOptions); useEventListener(animate, "finish", () => { var _animate$value5; if (commitStyles) (_animate$value5 = animate.value) === null || _animate$value5 === void 0 || _animate$value5.commitStyles(); }, listenerOptions); const { resume: resumeRef, pause: pauseRef } = useRafFn(() => { if (!animate.value) return; store.pending = animate.value.pending; store.playState = animate.value.playState; store.replaceState = animate.value.replaceState; store.startTime = animate.value.startTime; store.currentTime = animate.value.currentTime; store.timeline = animate.value.timeline; store.playbackRate = animate.value.playbackRate; }, { immediate: false }); function syncResume() { if (isSupported.value) resumeRef(); } function syncPause() { if (isSupported.value && window$1) window$1.requestAnimationFrame(pauseRef); } return { isSupported, animate, play, pause, reverse, finish, cancel, pending, playState, replaceState, startTime, currentTime, timeline, playbackRate }; } //#endregion //#region useAsyncQueue/index.ts /** * Asynchronous queue task controller. * * @see https://vueuse.org/useAsyncQueue * @param tasks * @param options */ function useAsyncQueue(tasks, options) { const { interrupt = true, onError = noop, onFinished = noop, signal } = options || {}; const promiseState = { aborted: "aborted", fulfilled: "fulfilled", pending: "pending", rejected: "rejected" }; const result = reactive(Array.from(Array.from({ length: tasks.length }), () => ({ state: promiseState.pending, data: null }))); const activeIndex = shallowRef(-1); if (!tasks || tasks.length === 0) { onFinished(); return { activeIndex, result }; } function updateResult(state, res) { activeIndex.value++; result[activeIndex.value].data = res; result[activeIndex.value].state = state; } tasks.reduce((prev, curr) => { return prev.then((prevRes) => { var _result$activeIndex$v; if (signal === null || signal === void 0 ? void 0 : signal.aborted) { updateResult(promiseState.aborted, /* @__PURE__ */ new Error("aborted")); return; } if (((_result$activeIndex$v = result[activeIndex.value]) === null || _result$activeIndex$v === void 0 ? void 0 : _result$activeIndex$v.state) === promiseState.rejected && interrupt) { onFinished(); return; } const done = curr(prevRes).then((currentRes) => { updateResult(promiseState.fulfilled, currentRes); if (activeIndex.value === tasks.length - 1) onFinished(); return currentRes; }); if (!signal) return done; return Promise.race([done, whenAborted(signal)]); }).catch((e) => { if (signal === null || signal === void 0 ? void 0 : signal.aborted) { updateResult(promiseState.aborted, e); return e; } updateResult(promiseState.rejected, e); onError(); if (activeIndex.value === tasks.length - 1) onFinished(); return e; }); }, Promise.resolve()); return { activeIndex, result }; } function whenAborted(signal) { return new Promise((resolve, reject) => { const error = /* @__PURE__ */ new Error("aborted"); if (signal.aborted) reject(error); else signal.addEventListener("abort", () => reject(error), { once: true }); }); } //#endregion //#region useAsyncState/index.ts /** * Reactive async state. Will not block your setup function and will trigger changes once * the promise is ready. * * @see https://vueuse.org/useAsyncState * @param promise The promise / async function to be resolved * @param initialState The initial state, used until the first evaluation finishes * @param options */ function useAsyncState(promise, initialState, options) { var _globalThis$reportErr; const { immediate = true, delay = 0, onError = (_globalThis$reportErr = globalThis.reportError) !== null && _globalThis$reportErr !== void 0 ? _globalThis$reportErr : noop, onSuccess = noop, resetOnExecute = true, shallow = true, throwError } = options !== null && options !== void 0 ? options : {}; const state = shallow ? shallowRef(initialState) : ref(initialState); const isReady = shallowRef(false); const isLoading = shallowRef(false); const error = shallowRef(void 0); let executionsCount = 0; async function execute(delay$1 = 0, ...args) { const executionId = executionsCount += 1; if (resetOnExecute) state.value = toValue(initialState); error.value = void 0; isReady.value = false; isLoading.value = true; if (delay$1 > 0) await promiseTimeout(delay$1); const _promise = typeof promise === "function" ? promise(...args) : promise; try { const data = await _promise; if (executionId === executionsCount) { state.value = data; isReady.value = true; } onSuccess(data); } catch (e) { if (executionId === executionsCount) error.value = e; onError(e); if (throwError) throw e; } finally { if (executionId === executionsCount) isLoading.value = false; } return state.value; } if (immediate) execute(delay); const shell = { state, isReady, isLoading, error, execute, executeImmediate: (...args) => execute(0, ...args) }; function waitUntilIsLoaded() { return new Promise((resolve, reject) => { until(isLoading).toBe(false).then(() => resolve(shell)).catch(reject); }); } return { ...shell, then(onFulfilled, onRejected) { return waitUntilIsLoaded().then(onFulfilled, onRejected); } }; } //#endregion //#region useBase64/serialization.ts const defaults = { array: (v) => JSON.stringify(v), object: (v) => JSON.stringify(v), set: (v) => JSON.stringify(Array.from(v)), map: (v) => JSON.stringify(Object.fromEntries(v)), null: () => "" }; function getDefaultSerialization(target) { if (!target) return defaults.null; if (target instanceof Map) return defaults.map; else if (target instanceof Set) return defaults.set; else if (Array.isArray(target)) return defaults.array; else return defaults.object; } //#endregion //#region useBase64/index.ts function useBase64(target, options) { const base64 = shallowRef(""); const promise = shallowRef(); function execute() { if (!isClient) return; promise.value = new Promise((resolve, reject) => { try { const _target = toValue(target); if (_target == null) resolve(""); else if (typeof _target === "string") resolve(blobToBase64(new Blob([_target], { type: "text/plain" }))); else if (_target instanceof Blob) resolve(blobToBase64(_target)); else if (_target instanceof ArrayBuffer) resolve(window.btoa(String.fromCharCode(...new Uint8Array(_target)))); else if (_target instanceof HTMLCanvasElement) resolve(_target.toDataURL(options === null || options === void 0 ? void 0 : options.type, options === null || options === void 0 ? void 0 : options.quality)); else if (_target instanceof HTMLImageElement) { const img = _target.cloneNode(false); img.crossOrigin = "Anonymous"; imgLoaded(img).then(() => { const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, canvas.width, canvas.height); resolve(canvas.toDataURL(options === null || options === void 0 ? void 0 : options.type, options === null || options === void 0 ? void 0 : options.quality)); }).catch(reject); } else if (typeof _target === "object") { const serialized = ((options === null || options === void 0 ? void 0 : options.serializer) || getDefaultSerialization(_target))(_target); return resolve(blobToBase64(new Blob([serialized], { type: "application/json" }))); } else reject(/* @__PURE__ */ new Error("target is unsupported types")); } catch (error) { reject(error); } }); promise.value.then((res) => { base64.value = (options === null || options === void 0 ? void 0 : options.dataUrl) === false ? res.replace(/^data:.*?;base64,/, "") : res; }); return promise.value; } if (isRef(target) || typeof target === "function") watch(target, execute, { immediate: true }); else execute(); return { base64, promise, execute }; } function imgLoaded(img) { return new Promise((resolve, reject) => { if (!img.complete) { img.onload = () => { resolve(); }; img.onerror = reject; } else resolve(); }); } function blobToBase64(blob) { return new Promise((resolve, reject) => { const fr = new FileReader(); fr.onload = (e) => { resolve(e.target.result); }; fr.onerror = reject; fr.readAsDataURL(blob); }); } //#endregion //#region useBattery/index.ts /** * Reactive Battery Status API. * * @see https://vueuse.org/useBattery * * @__NO_SIDE_EFFECTS__ */ function useBattery(options = {}) { const { navigator: navigator$1 = defaultNavigator } = options; const events$1 = [ "chargingchange", "chargingtimechange", "dischargingtimechange", "levelchange" ]; const isSupported = /* @__PURE__ */ useSupported(() => navigator$1 && "getBattery" in navigator$1 && typeof navigator$1.getBattery === "function"); const charging = shallowRef(false); const chargingTime = shallowRef(0); const dischargingTime = shallowRef(0); const level = shallowRef(1); let battery; function updateBatteryInfo() { charging.value = this.charging; chargingTime.value = this.chargingTime || 0; dischargingTime.value = this.dischargingTime || 0; level.value = this.level; } if (isSupported.value) navigator$1.getBattery().then((_battery) => { battery = _battery; updateBatteryInfo.call(battery); useEventListener(battery, events$1, updateBatteryInfo, { passive: true }); }); return { isSupported, charging, chargingTime, dischargingTime, level }; } //#endregion //#region useBluetooth/index.ts /* @__NO_SIDE_EFFECTS__ */ function useBluetooth(options) { let { acceptAllDevices = false } = options || {}; const { filters = void 0, optionalServices = void 0, navigator: navigator$1 = defaultNavigator } = options || {}; const isSupported = /* @__PURE__ */ useSupported(() => navigator$1 && "bluetooth" in navigator$1); const device = shallowRef(); const error = shallowRef(null); watch(device, () => { connectToBluetoothGATTServer(); }); async function requestDevice() { if (!isSupported.value) return; error.value = null; if (filters && filters.length > 0) acceptAllDevices = false; try { device.value = await (navigator$1 === null || navigator$1 === void 0 ? void 0 : navigator$1.bluetooth.requestDevice({ acceptAllDevices, filters, optionalServices })); } catch (err) { error.value = err; } } const server = shallowRef(); const isConnected = shallowRef(false); function reset() { isConnected.value = false; device.value = void 0; server.value = void 0; } async function connectToBluetoothGATTServer() { error.value = null; if (device.value && device.value.gatt) { useEventListener(device, "gattserverdisconnected", reset, { passive: true }); try { server.value = await device.value.gatt.connect(); isConnected.value = server.value.connected; } catch (err) { error.value = err; } } } tryOnMounted(() => { var _device$value$gatt; if (device.value) (_device$value$gatt = device.value.gatt) === null || _device$value$gatt === void 0 || _device$value$gatt.connect(); }); tryOnScopeDispose(() => { var _device$value$gatt2; if (device.value) (_device$value$gatt2 = device.value.gatt) === null || _device$value$gatt2 === void 0 || _device$value$gatt2.disconnect(); }); return { isSupported, isConnected: readonly(isConnected), device, requestDevice, server, error }; } //#endregion //#region useSSRWidth/index.ts const ssrWidthSymbol = Symbol("vueuse-ssr-width"); /* @__NO_SIDE_EFFECTS__ */ function useSSRWidth() { const ssrWidth = hasInjectionContext() ? injectLocal(ssrWidthSymbol, null) : null; return typeof ssrWidth === "number" ? ssrWidth : void 0; } function provideSSRWidth(width, app) { if (app !== void 0) app.provide(ssrWidthSymbol, width); else provideLocal(ssrWidthSymbol, width); } //#endregion //#region useMediaQuery/index.ts /** * Reactive Media Query. * * @see https://vueuse.org/useMediaQuery * @param query * @param options */ function useMediaQuery(query, options = {}) { const { window: window$1 = defaultWindow, ssrWidth = /* @__PURE__ */ useSSRWidth() } = options; const isSupported = /* @__PURE__ */ useSupported(() => window$1 && "matchMedia" in window$1 && typeof window$1.matchMedia === "function"); const ssrSupport = shallowRef(typeof ssrWidth === "number"); const mediaQuery = shallowRef(); const matches = shallowRef(false); const handler = (event) => { matches.value = event.matches; }; watchEffect(() => { if (ssrSupport.value) { ssrSupport.value = !isSupported.value; matches.value = toValue(query).split(",").some((queryString) => { const not = queryString.includes("not all"); const minWidth = queryString.match(/\(\s*min-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/); const maxWidth = queryString.match(/\(\s*max-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/); let res = Boolean(minWidth || maxWidth); if (minWidth && res) res = ssrWidth >= pxValue(minWidth[1]); if (maxWidth && res) res = ssrWidth <= pxValue(maxWidth[1]); return not ? !res : res; }); return; } if (!isSupported.value) return; mediaQuery.value = window$1.matchMedia(toValue(query)); matches.value = mediaQuery.value.matches; }); useEventListener(mediaQuery, "change", handler, { passive: true }); return computed(() => matches.value); } //#endregion //#region useBreakpoints/breakpoints.ts /** * Breakpoints from Tailwind V2 * * @see https://tailwindcss.com/docs/breakpoints */ const breakpointsTailwind = { "sm": 640, "md": 768, "lg": 1024, "xl": 1280, "2xl": 1536 }; /** * Breakpoints from Bootstrap V5 * * @see https://getbootstrap.com/docs/5.0/layout/breakpoints */ const breakpointsBootstrapV5 = { xs: 0, sm: 576, md: 768, lg: 992, xl: 1200, xxl: 1400 }; /** * Breakpoints from Vuetify V2 * * @see https://v2.vuetifyjs.com/en/features/breakpoints/ */ const breakpointsVuetifyV2 = { xs: 0, sm: 600, md: 960, lg: 1264, xl: 1904 }; /** * Breakpoints from Vuetify V3 * * @see https://vuetifyjs.com/en/styles/float/#overview */ const breakpointsVuetifyV3 = { xs: 0, sm: 600, md: 960, lg: 1280, xl: 1920, xxl: 2560 }; /** * Alias to `breakpointsVuetifyV2` * * @deprecated explictly use `breakpointsVuetifyV2` or `breakpointsVuetifyV3` instead */ const breakpointsVuetify = breakpointsVuetifyV2; /** * Breakpoints from Ant Design * * @see https://ant.design/components/layout/#breakpoint-width */ const breakpointsAntDesign = { xs: 480, sm: 576, md: 768, lg: 992, xl: 1200, xxl: 1600 }; /** * Breakpoints from Quasar V2 * * @see https://quasar.dev/style/breakpoints */ const breakpointsQuasar = { xs: 0, sm: 600, md: 1024, lg: 1440, xl: 1920 }; /** * Sematic Breakpoints */ const breakpointsSematic = { mobileS: 320, mobileM: 375, mobileL: 425, tablet: 768, laptop: 1024, laptopL: 1440, desktop4K: 2560 }; /** * Breakpoints from Master CSS * * @see https://docs.master.co/css/breakpoints */ const breakpointsMasterCss = { "3xs": 360, "2xs": 480, "xs": 600, "sm": 768, "md": 1024, "lg": 1280, "xl": 1440, "2xl": 1600, "3xl": 1920, "4xl": 2560 }; /** * Breakpoints from PrimeFlex * * @see https://primeflex.org/installation */ const breakpointsPrimeFlex = { sm: 576, md: 768, lg: 992, xl: 1200 }; /** * Breakpoints from ElementUI/ElementPlus * * @see https://element.eleme.io/#/en-US/component/layout * @see https://element-plus.org/en-US/component/layout.html */ const breakpointsElement = { xs: 0, sm: 768, md: 992, lg: 1200, xl: 1920 }; //#endregion //#region useBreakpoints/index.ts /** * Reactively viewport breakpoints * * @see https://vueuse.org/useBreakpoints * * @__NO_SIDE_EFFECTS__ */ function useBreakpoints(breakpoints, options = {}) { function getValue$1(k, delta) { let v = toValue(breakpoints[toValue(k)]); if (delta != null) v = increaseWithUnit(v, delta); if (typeof v === "number") v = `${v}px`; return v; } const { window: window$1 = defaultWindow, strategy = "min-width", ssrWidth = /* @__PURE__ */ useSSRWidth() } = options; const ssrSupport = typeof ssrWidth === "number"; const mounted = ssrSupport ? shallowRef(false) : { value: true }; if (ssrSupport) tryOnMounted(() => mounted.value = !!window$1); function match(query, size) { if (!mounted.value && ssrSupport) return query === "min" ? ssrWidth >= pxValue(size) : ssrWidth <= pxValue(size); if (!window$1) return false; return window$1.matchMedia(`(${query}-width: ${size})`).matches; } const greaterOrEqual = (k) => { return useMediaQuery(() => `(min-width: ${getValue$1(k)})`, options); }; const smallerOrEqual = (k) => { return useMediaQuery(() => `(max-width: ${getValue$1(k)})`, options); }; const shortcutMethods = Object.keys(breakpoints).reduce((shortcuts, k) => { Object.defineProperty(shortcuts, k, { get: () => strategy === "min-width" ? greaterOrEqual(k) : smallerOrEqual(k), enumerable: true, configurable: true }); return shortcuts; }, {}); function current() { const points = Object.keys(breakpoints).map((k) => [ k, shortcutMethods[k], pxValue(getValue$1(k)) ]).sort((a, b) => a[2] - b[2]); return computed(() => points.filter(([, v]) => v.value).map(([k]) => k)); } return Object.assign(shortcutMethods, { greaterOrEqual, smallerOrEqual, greater(k) { return useMediaQuery(() => `(min-width: ${getValue$1(k, .1)})`, options); }, smaller(k) { return useMediaQuery(() => `(max-width: ${getValue$1(k, -.1)})`, options); }, between(a, b) { return useMediaQuery(() => `(min-width: ${getValue$1(a)}) and (max-width: ${getValue$1(b, -.1)})`, options); }, isGreater(k) { return match("min", getValue$1(k, .1)); }, isGreaterOrEqual(k) { return match("min", getValue$1(k)); }, isSmaller(k) { return match("max", getValue$1(k, -.1)); }, isSmallerOrEqual(k) { return match("max", getValue$1(k)); }, isInBetween(a, b) { return match("min", getValue$1(a)) && match("max", getValue$1(b, -.1)); }, current, active() { const bps = current(); return computed(() => bps.value.length === 0 ? "" : bps.value.at(strategy === "min-width" ? -1 : 0)); } }); } //#endregion //#region useBroadcastChannel/index.ts /** * Reactive BroadcastChannel * * @see https://vueuse.org/useBroadcastChannel * @see https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel * @param options * */ function useBroadcastChannel(options) { const { name, window: window$1 = defaultWindow } = options; const isSupported = /* @__PURE__ */ useSupported(() => window$1 && "BroadcastChannel" in window$1); const isClosed = shallowRef(false); const channel = ref(); const data = ref(); const error = shallowRef(null); const post = (data$1) => { if (channel.value) channel.value.postMessage(data$1); }; const close = () => { if (channel.value) channel.value.close(); isClosed.value = true; }; if (isSupported.value) tryOnMounted(() => { error.value = null; channel.value = new BroadcastChannel(name); const listenerOptions = { passive: true }; useEventListener(channel, "message", (e) => { data.value = e.data; }, listenerOptions); useEventListener(channel, "messageerror", (e) => { error.value = e; }, listenerOptions); useEventListener(channel, "close", () => { isClosed.value = true; }, listenerOptions); }); tryOnScopeDispose(() => { close(); }); return { isSupported, channel, data, post, close, error, isClosed }; } //#endregion //#region useBrowserLocation/index.ts const WRITABLE_PROPERTIES = [ "hash", "host", "hostname", "href", "pathna