@vueuse/core
Version:
Collection of essential Vue Composition Utilities
1,617 lines (1,584 loc) • 270 kB
JavaScript
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