10697 lines
282 KiB
JavaScript
10697 lines
282 KiB
JavaScript
import {
|
|
Fragment,
|
|
TransitionGroup,
|
|
computed,
|
|
customRef,
|
|
defineComponent,
|
|
effectScope,
|
|
getCurrentInstance,
|
|
getCurrentScope,
|
|
h,
|
|
hasInjectionContext,
|
|
inject,
|
|
isReactive,
|
|
isReadonly,
|
|
isRef,
|
|
markRaw,
|
|
nextTick,
|
|
onBeforeMount,
|
|
onBeforeUnmount,
|
|
onBeforeUpdate,
|
|
onMounted,
|
|
onScopeDispose,
|
|
onUnmounted,
|
|
onUpdated,
|
|
provide,
|
|
reactive,
|
|
readonly,
|
|
ref,
|
|
shallowReactive,
|
|
shallowRef,
|
|
toRaw,
|
|
toRef,
|
|
toRefs,
|
|
toValue,
|
|
unref,
|
|
watch,
|
|
watchEffect,
|
|
} from './chunk-H6MPEGKE.js';
|
|
|
|
// node_modules/@vueuse/shared/index.mjs
|
|
function computedEager(fn, options) {
|
|
var _a;
|
|
const result = shallowRef();
|
|
watchEffect(
|
|
() => {
|
|
result.value = fn();
|
|
},
|
|
{
|
|
...options,
|
|
flush:
|
|
(_a = options == null ? void 0 : options.flush) != null ? _a : 'sync',
|
|
}
|
|
);
|
|
return readonly(result);
|
|
}
|
|
function computedWithControl(source, fn) {
|
|
let v = void 0;
|
|
let track;
|
|
let trigger;
|
|
const dirty = shallowRef(true);
|
|
const update = () => {
|
|
dirty.value = true;
|
|
trigger();
|
|
};
|
|
watch(source, update, { flush: 'sync' });
|
|
const get2 = typeof fn === 'function' ? fn : fn.get;
|
|
const set2 = typeof fn === 'function' ? void 0 : fn.set;
|
|
const result = customRef((_track, _trigger) => {
|
|
track = _track;
|
|
trigger = _trigger;
|
|
return {
|
|
get() {
|
|
if (dirty.value) {
|
|
v = get2(v);
|
|
dirty.value = false;
|
|
}
|
|
track();
|
|
return v;
|
|
},
|
|
set(v2) {
|
|
set2 == null ? void 0 : set2(v2);
|
|
},
|
|
};
|
|
});
|
|
if (Object.isExtensible(result)) result.trigger = update;
|
|
return result;
|
|
}
|
|
function tryOnScopeDispose(fn) {
|
|
if (getCurrentScope()) {
|
|
onScopeDispose(fn);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function createEventHook() {
|
|
const fns = /* @__PURE__ */ new Set();
|
|
const off = (fn) => {
|
|
fns.delete(fn);
|
|
};
|
|
const clear = () => {
|
|
fns.clear();
|
|
};
|
|
const on = (fn) => {
|
|
fns.add(fn);
|
|
const offFn = () => off(fn);
|
|
tryOnScopeDispose(offFn);
|
|
return {
|
|
off: offFn,
|
|
};
|
|
};
|
|
const trigger = (...args) => {
|
|
return Promise.all(Array.from(fns).map((fn) => fn(...args)));
|
|
};
|
|
return {
|
|
on,
|
|
off,
|
|
trigger,
|
|
clear,
|
|
};
|
|
}
|
|
function createGlobalState(stateFactory) {
|
|
let initialized = false;
|
|
let state;
|
|
const scope = effectScope(true);
|
|
return (...args) => {
|
|
if (!initialized) {
|
|
state = scope.run(() => stateFactory(...args));
|
|
initialized = true;
|
|
}
|
|
return state;
|
|
};
|
|
}
|
|
var localProvidedStateMap = /* @__PURE__ */ new WeakMap();
|
|
var injectLocal = (...args) => {
|
|
var _a;
|
|
const key = args[0];
|
|
const instance = (_a = getCurrentInstance()) == null ? void 0 : _a.proxy;
|
|
if (instance == null && !hasInjectionContext())
|
|
throw new Error('injectLocal must be called in setup');
|
|
if (
|
|
instance &&
|
|
localProvidedStateMap.has(instance) &&
|
|
key in localProvidedStateMap.get(instance)
|
|
)
|
|
return localProvidedStateMap.get(instance)[key];
|
|
return inject(...args);
|
|
};
|
|
var provideLocal = (key, value) => {
|
|
var _a;
|
|
const instance = (_a = getCurrentInstance()) == null ? void 0 : _a.proxy;
|
|
if (instance == null) throw new Error('provideLocal must be called in setup');
|
|
if (!localProvidedStateMap.has(instance))
|
|
localProvidedStateMap.set(instance, /* @__PURE__ */ Object.create(null));
|
|
const localProvidedState = localProvidedStateMap.get(instance);
|
|
localProvidedState[key] = value;
|
|
provide(key, value);
|
|
};
|
|
function createInjectionState(composable, options) {
|
|
const key =
|
|
(options == null ? void 0 : options.injectionKey) ||
|
|
Symbol(composable.name || 'InjectionState');
|
|
const defaultValue = options == null ? void 0 : options.defaultValue;
|
|
const useProvidingState = (...args) => {
|
|
const state = composable(...args);
|
|
provideLocal(key, state);
|
|
return state;
|
|
};
|
|
const useInjectedState = () => injectLocal(key, defaultValue);
|
|
return [useProvidingState, useInjectedState];
|
|
}
|
|
function createRef(value, deep) {
|
|
if (deep === true) {
|
|
return ref(value);
|
|
} else {
|
|
return shallowRef(value);
|
|
}
|
|
}
|
|
function createSharedComposable(composable) {
|
|
let subscribers = 0;
|
|
let state;
|
|
let scope;
|
|
const dispose = () => {
|
|
subscribers -= 1;
|
|
if (scope && subscribers <= 0) {
|
|
scope.stop();
|
|
state = void 0;
|
|
scope = void 0;
|
|
}
|
|
};
|
|
return (...args) => {
|
|
subscribers += 1;
|
|
if (!scope) {
|
|
scope = effectScope(true);
|
|
state = scope.run(() => composable(...args));
|
|
}
|
|
tryOnScopeDispose(dispose);
|
|
return state;
|
|
};
|
|
}
|
|
function extendRef(ref2, extend, { enumerable = false, unwrap = true } = {}) {
|
|
for (const [key, value] of Object.entries(extend)) {
|
|
if (key === 'value') continue;
|
|
if (isRef(value) && unwrap) {
|
|
Object.defineProperty(ref2, key, {
|
|
get() {
|
|
return value.value;
|
|
},
|
|
set(v) {
|
|
value.value = v;
|
|
},
|
|
enumerable,
|
|
});
|
|
} else {
|
|
Object.defineProperty(ref2, key, { value, enumerable });
|
|
}
|
|
}
|
|
return ref2;
|
|
}
|
|
function get(obj, key) {
|
|
if (key == null) return unref(obj);
|
|
return unref(obj)[key];
|
|
}
|
|
function isDefined(v) {
|
|
return unref(v) != null;
|
|
}
|
|
function makeDestructurable(obj, arr) {
|
|
if (typeof Symbol !== 'undefined') {
|
|
const clone = { ...obj };
|
|
Object.defineProperty(clone, Symbol.iterator, {
|
|
enumerable: false,
|
|
value() {
|
|
let index = 0;
|
|
return {
|
|
next: () => ({
|
|
value: arr[index++],
|
|
done: index > arr.length,
|
|
}),
|
|
};
|
|
},
|
|
});
|
|
return clone;
|
|
} else {
|
|
return Object.assign([...arr], obj);
|
|
}
|
|
}
|
|
function reactify(fn, options) {
|
|
const unrefFn =
|
|
(options == null ? void 0 : options.computedGetter) === false
|
|
? unref
|
|
: toValue;
|
|
return function (...args) {
|
|
return computed(() =>
|
|
fn.apply(
|
|
this,
|
|
args.map((i) => unrefFn(i))
|
|
)
|
|
);
|
|
};
|
|
}
|
|
function reactifyObject(obj, optionsOrKeys = {}) {
|
|
let keys2 = [];
|
|
let options;
|
|
if (Array.isArray(optionsOrKeys)) {
|
|
keys2 = optionsOrKeys;
|
|
} else {
|
|
options = optionsOrKeys;
|
|
const { includeOwnProperties = true } = optionsOrKeys;
|
|
keys2.push(...Object.keys(obj));
|
|
if (includeOwnProperties) keys2.push(...Object.getOwnPropertyNames(obj));
|
|
}
|
|
return Object.fromEntries(
|
|
keys2.map((key) => {
|
|
const value = obj[key];
|
|
return [
|
|
key,
|
|
typeof value === 'function'
|
|
? reactify(value.bind(obj), options)
|
|
: value,
|
|
];
|
|
})
|
|
);
|
|
}
|
|
function toReactive(objectRef) {
|
|
if (!isRef(objectRef)) return reactive(objectRef);
|
|
const proxy = new Proxy(
|
|
{},
|
|
{
|
|
get(_, p, receiver) {
|
|
return unref(Reflect.get(objectRef.value, p, receiver));
|
|
},
|
|
set(_, p, value) {
|
|
if (isRef(objectRef.value[p]) && !isRef(value))
|
|
objectRef.value[p].value = value;
|
|
else objectRef.value[p] = value;
|
|
return true;
|
|
},
|
|
deleteProperty(_, p) {
|
|
return Reflect.deleteProperty(objectRef.value, p);
|
|
},
|
|
has(_, p) {
|
|
return Reflect.has(objectRef.value, p);
|
|
},
|
|
ownKeys() {
|
|
return Object.keys(objectRef.value);
|
|
},
|
|
getOwnPropertyDescriptor() {
|
|
return {
|
|
enumerable: true,
|
|
configurable: true,
|
|
};
|
|
},
|
|
}
|
|
);
|
|
return reactive(proxy);
|
|
}
|
|
function reactiveComputed(fn) {
|
|
return toReactive(computed(fn));
|
|
}
|
|
function reactiveOmit(obj, ...keys2) {
|
|
const flatKeys = keys2.flat();
|
|
const predicate = flatKeys[0];
|
|
return reactiveComputed(() =>
|
|
typeof predicate === 'function'
|
|
? Object.fromEntries(
|
|
Object.entries(toRefs(obj)).filter(
|
|
([k, v]) => !predicate(toValue(v), k)
|
|
)
|
|
)
|
|
: Object.fromEntries(
|
|
Object.entries(toRefs(obj)).filter((e) => !flatKeys.includes(e[0]))
|
|
)
|
|
);
|
|
}
|
|
var isClient = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
var isWorker =
|
|
typeof WorkerGlobalScope !== 'undefined' &&
|
|
globalThis instanceof WorkerGlobalScope;
|
|
var isDef = (val) => typeof val !== 'undefined';
|
|
var notNullish = (val) => val != null;
|
|
var assert = (condition, ...infos) => {
|
|
if (!condition) console.warn(...infos);
|
|
};
|
|
var toString = Object.prototype.toString;
|
|
var isObject = (val) => toString.call(val) === '[object Object]';
|
|
var now = () => Date.now();
|
|
var timestamp = () => +Date.now();
|
|
var clamp = (n, min, max) => Math.min(max, Math.max(min, n));
|
|
var noop = () => {};
|
|
var rand = (min, max) => {
|
|
min = Math.ceil(min);
|
|
max = Math.floor(max);
|
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
};
|
|
var hasOwn = (val, key) => Object.prototype.hasOwnProperty.call(val, key);
|
|
var isIOS = getIsIOS();
|
|
function getIsIOS() {
|
|
var _a, _b;
|
|
return (
|
|
isClient &&
|
|
((_a = window == null ? void 0 : window.navigator) == null
|
|
? void 0
|
|
: _a.userAgent) &&
|
|
(/iP(?:ad|hone|od)/.test(window.navigator.userAgent) ||
|
|
(((_b = window == null ? void 0 : window.navigator) == null
|
|
? void 0
|
|
: _b.maxTouchPoints) > 2 &&
|
|
/iPad|Macintosh/.test(
|
|
window == null ? void 0 : window.navigator.userAgent
|
|
)))
|
|
);
|
|
}
|
|
function createFilterWrapper(filter, fn) {
|
|
function wrapper(...args) {
|
|
return new Promise((resolve, reject) => {
|
|
Promise.resolve(
|
|
filter(() => fn.apply(this, args), { fn, thisArg: this, args })
|
|
)
|
|
.then(resolve)
|
|
.catch(reject);
|
|
});
|
|
}
|
|
return wrapper;
|
|
}
|
|
var bypassFilter = (invoke2) => {
|
|
return invoke2();
|
|
};
|
|
function debounceFilter(ms, options = {}) {
|
|
let timer;
|
|
let maxTimer;
|
|
let lastRejector = noop;
|
|
const _clearTimeout = (timer2) => {
|
|
clearTimeout(timer2);
|
|
lastRejector();
|
|
lastRejector = noop;
|
|
};
|
|
let lastInvoker;
|
|
const filter = (invoke2) => {
|
|
const duration = toValue(ms);
|
|
const maxDuration = toValue(options.maxWait);
|
|
if (timer) _clearTimeout(timer);
|
|
if (duration <= 0 || (maxDuration !== void 0 && maxDuration <= 0)) {
|
|
if (maxTimer) {
|
|
_clearTimeout(maxTimer);
|
|
maxTimer = null;
|
|
}
|
|
return Promise.resolve(invoke2());
|
|
}
|
|
return new Promise((resolve, reject) => {
|
|
lastRejector = options.rejectOnCancel ? reject : resolve;
|
|
lastInvoker = invoke2;
|
|
if (maxDuration && !maxTimer) {
|
|
maxTimer = setTimeout(() => {
|
|
if (timer) _clearTimeout(timer);
|
|
maxTimer = null;
|
|
resolve(lastInvoker());
|
|
}, maxDuration);
|
|
}
|
|
timer = setTimeout(() => {
|
|
if (maxTimer) _clearTimeout(maxTimer);
|
|
maxTimer = null;
|
|
resolve(invoke2());
|
|
}, duration);
|
|
});
|
|
};
|
|
return filter;
|
|
}
|
|
function throttleFilter(...args) {
|
|
let lastExec = 0;
|
|
let timer;
|
|
let isLeading = true;
|
|
let lastRejector = noop;
|
|
let lastValue;
|
|
let ms;
|
|
let trailing;
|
|
let leading;
|
|
let rejectOnCancel;
|
|
if (!isRef(args[0]) && typeof args[0] === 'object')
|
|
({
|
|
delay: ms,
|
|
trailing = true,
|
|
leading = true,
|
|
rejectOnCancel = false,
|
|
} = args[0]);
|
|
else [ms, trailing = true, leading = true, rejectOnCancel = false] = args;
|
|
const clear = () => {
|
|
if (timer) {
|
|
clearTimeout(timer);
|
|
timer = void 0;
|
|
lastRejector();
|
|
lastRejector = noop;
|
|
}
|
|
};
|
|
const filter = (_invoke) => {
|
|
const duration = toValue(ms);
|
|
const elapsed = Date.now() - lastExec;
|
|
const invoke2 = () => {
|
|
return (lastValue = _invoke());
|
|
};
|
|
clear();
|
|
if (duration <= 0) {
|
|
lastExec = Date.now();
|
|
return invoke2();
|
|
}
|
|
if (elapsed > duration && (leading || !isLeading)) {
|
|
lastExec = Date.now();
|
|
invoke2();
|
|
} else if (trailing) {
|
|
lastValue = new Promise((resolve, reject) => {
|
|
lastRejector = rejectOnCancel ? reject : resolve;
|
|
timer = setTimeout(
|
|
() => {
|
|
lastExec = Date.now();
|
|
isLeading = true;
|
|
resolve(invoke2());
|
|
clear();
|
|
},
|
|
Math.max(0, duration - elapsed)
|
|
);
|
|
});
|
|
}
|
|
if (!leading && !timer)
|
|
timer = setTimeout(() => (isLeading = true), duration);
|
|
isLeading = false;
|
|
return lastValue;
|
|
};
|
|
return filter;
|
|
}
|
|
function pausableFilter(extendFilter = bypassFilter, options = {}) {
|
|
const { initialState = 'active' } = options;
|
|
const isActive = toRef2(initialState === 'active');
|
|
function pause() {
|
|
isActive.value = false;
|
|
}
|
|
function resume() {
|
|
isActive.value = true;
|
|
}
|
|
const eventFilter = (...args) => {
|
|
if (isActive.value) extendFilter(...args);
|
|
};
|
|
return { isActive: readonly(isActive), pause, resume, eventFilter };
|
|
}
|
|
function cacheStringFunction(fn) {
|
|
const cache = /* @__PURE__ */ Object.create(null);
|
|
return (str) => {
|
|
const hit = cache[str];
|
|
return hit || (cache[str] = fn(str));
|
|
};
|
|
}
|
|
var hyphenateRE = /\B([A-Z])/g;
|
|
var hyphenate = cacheStringFunction((str) =>
|
|
str.replace(hyphenateRE, '-$1').toLowerCase()
|
|
);
|
|
var camelizeRE = /-(\w)/g;
|
|
var camelize = cacheStringFunction((str) => {
|
|
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
|
|
});
|
|
function promiseTimeout(ms, throwOnTimeout = false, reason = 'Timeout') {
|
|
return new Promise((resolve, reject) => {
|
|
if (throwOnTimeout) setTimeout(() => reject(reason), ms);
|
|
else setTimeout(resolve, ms);
|
|
});
|
|
}
|
|
function identity(arg) {
|
|
return arg;
|
|
}
|
|
function createSingletonPromise(fn) {
|
|
let _promise;
|
|
function wrapper() {
|
|
if (!_promise) _promise = fn();
|
|
return _promise;
|
|
}
|
|
wrapper.reset = async () => {
|
|
const _prev = _promise;
|
|
_promise = void 0;
|
|
if (_prev) await _prev;
|
|
};
|
|
return wrapper;
|
|
}
|
|
function invoke(fn) {
|
|
return fn();
|
|
}
|
|
function containsProp(obj, ...props) {
|
|
return props.some((k) => k in obj);
|
|
}
|
|
function increaseWithUnit(target, delta) {
|
|
var _a;
|
|
if (typeof target === 'number') return target + delta;
|
|
const value =
|
|
((_a = target.match(/^-?\d+\.?\d*/)) == null ? void 0 : _a[0]) || '';
|
|
const unit = target.slice(value.length);
|
|
const result = Number.parseFloat(value) + delta;
|
|
if (Number.isNaN(result)) return target;
|
|
return result + unit;
|
|
}
|
|
function pxValue(px) {
|
|
return px.endsWith('rem')
|
|
? Number.parseFloat(px) * 16
|
|
: Number.parseFloat(px);
|
|
}
|
|
function objectPick(obj, keys2, omitUndefined = false) {
|
|
return keys2.reduce((n, k) => {
|
|
if (k in obj) {
|
|
if (!omitUndefined || obj[k] !== void 0) n[k] = obj[k];
|
|
}
|
|
return n;
|
|
}, {});
|
|
}
|
|
function objectOmit(obj, keys2, omitUndefined = false) {
|
|
return Object.fromEntries(
|
|
Object.entries(obj).filter(([key, value]) => {
|
|
return (!omitUndefined || value !== void 0) && !keys2.includes(key);
|
|
})
|
|
);
|
|
}
|
|
function objectEntries(obj) {
|
|
return Object.entries(obj);
|
|
}
|
|
function getLifeCycleTarget(target) {
|
|
return target || getCurrentInstance();
|
|
}
|
|
function toArray(value) {
|
|
return Array.isArray(value) ? value : [value];
|
|
}
|
|
function toRef2(...args) {
|
|
if (args.length !== 1) return toRef(...args);
|
|
const r = args[0];
|
|
return typeof r === 'function'
|
|
? readonly(customRef(() => ({ get: r, set: noop })))
|
|
: ref(r);
|
|
}
|
|
var resolveRef = toRef2;
|
|
function reactivePick(obj, ...keys2) {
|
|
const flatKeys = keys2.flat();
|
|
const predicate = flatKeys[0];
|
|
return reactiveComputed(() =>
|
|
typeof predicate === 'function'
|
|
? Object.fromEntries(
|
|
Object.entries(toRefs(obj)).filter(([k, v]) =>
|
|
predicate(toValue(v), k)
|
|
)
|
|
)
|
|
: Object.fromEntries(flatKeys.map((k) => [k, toRef2(obj, k)]))
|
|
);
|
|
}
|
|
function refAutoReset(defaultValue, afterMs = 1e4) {
|
|
return customRef((track, trigger) => {
|
|
let value = toValue(defaultValue);
|
|
let timer;
|
|
const resetAfter = () =>
|
|
setTimeout(() => {
|
|
value = toValue(defaultValue);
|
|
trigger();
|
|
}, toValue(afterMs));
|
|
tryOnScopeDispose(() => {
|
|
clearTimeout(timer);
|
|
});
|
|
return {
|
|
get() {
|
|
track();
|
|
return value;
|
|
},
|
|
set(newValue) {
|
|
value = newValue;
|
|
trigger();
|
|
clearTimeout(timer);
|
|
timer = resetAfter();
|
|
},
|
|
};
|
|
});
|
|
}
|
|
function useDebounceFn(fn, ms = 200, options = {}) {
|
|
return createFilterWrapper(debounceFilter(ms, options), fn);
|
|
}
|
|
function refDebounced(value, ms = 200, options = {}) {
|
|
const debounced = ref(value.value);
|
|
const updater = useDebounceFn(
|
|
() => {
|
|
debounced.value = value.value;
|
|
},
|
|
ms,
|
|
options
|
|
);
|
|
watch(value, () => updater());
|
|
return debounced;
|
|
}
|
|
function refDefault(source, defaultValue) {
|
|
return computed({
|
|
get() {
|
|
var _a;
|
|
return (_a = source.value) != null ? _a : defaultValue;
|
|
},
|
|
set(value) {
|
|
source.value = value;
|
|
},
|
|
});
|
|
}
|
|
function useThrottleFn(
|
|
fn,
|
|
ms = 200,
|
|
trailing = false,
|
|
leading = true,
|
|
rejectOnCancel = false
|
|
) {
|
|
return createFilterWrapper(
|
|
throttleFilter(ms, trailing, leading, rejectOnCancel),
|
|
fn
|
|
);
|
|
}
|
|
function refThrottled(value, delay = 200, trailing = true, leading = true) {
|
|
if (delay <= 0) return value;
|
|
const throttled = ref(value.value);
|
|
const updater = useThrottleFn(
|
|
() => {
|
|
throttled.value = value.value;
|
|
},
|
|
delay,
|
|
trailing,
|
|
leading
|
|
);
|
|
watch(value, () => updater());
|
|
return throttled;
|
|
}
|
|
function refWithControl(initial, options = {}) {
|
|
let source = initial;
|
|
let track;
|
|
let trigger;
|
|
const ref2 = customRef((_track, _trigger) => {
|
|
track = _track;
|
|
trigger = _trigger;
|
|
return {
|
|
get() {
|
|
return get2();
|
|
},
|
|
set(v) {
|
|
set2(v);
|
|
},
|
|
};
|
|
});
|
|
function get2(tracking = true) {
|
|
if (tracking) track();
|
|
return source;
|
|
}
|
|
function set2(value, triggering = true) {
|
|
var _a, _b;
|
|
if (value === source) return;
|
|
const old = source;
|
|
if (
|
|
((_a = options.onBeforeChange) == null
|
|
? void 0
|
|
: _a.call(options, value, old)) === false
|
|
)
|
|
return;
|
|
source = value;
|
|
(_b = options.onChanged) == null ? void 0 : _b.call(options, value, old);
|
|
if (triggering) trigger();
|
|
}
|
|
const untrackedGet = () => get2(false);
|
|
const silentSet = (v) => set2(v, false);
|
|
const peek = () => get2(false);
|
|
const lay = (v) => set2(v, false);
|
|
return extendRef(
|
|
ref2,
|
|
{
|
|
get: get2,
|
|
set: set2,
|
|
untrackedGet,
|
|
silentSet,
|
|
peek,
|
|
lay,
|
|
},
|
|
{ enumerable: true }
|
|
);
|
|
}
|
|
var controlledRef = refWithControl;
|
|
function set(...args) {
|
|
if (args.length === 2) {
|
|
const [ref2, value] = args;
|
|
ref2.value = value;
|
|
}
|
|
if (args.length === 3) {
|
|
const [target, key, value] = args;
|
|
target[key] = value;
|
|
}
|
|
}
|
|
function watchWithFilter(source, cb, options = {}) {
|
|
const { eventFilter = bypassFilter, ...watchOptions } = options;
|
|
return watch(source, createFilterWrapper(eventFilter, cb), watchOptions);
|
|
}
|
|
function watchPausable(source, cb, options = {}) {
|
|
const {
|
|
eventFilter: filter,
|
|
initialState = 'active',
|
|
...watchOptions
|
|
} = options;
|
|
const { eventFilter, pause, resume, isActive } = pausableFilter(filter, {
|
|
initialState,
|
|
});
|
|
const stop = watchWithFilter(source, cb, {
|
|
...watchOptions,
|
|
eventFilter,
|
|
});
|
|
return { stop, pause, resume, isActive };
|
|
}
|
|
function syncRef(left, right, ...[options]) {
|
|
const {
|
|
flush = 'sync',
|
|
deep = false,
|
|
immediate = true,
|
|
direction = 'both',
|
|
transform = {},
|
|
} = options || {};
|
|
const watchers = [];
|
|
const transformLTR = ('ltr' in transform && transform.ltr) || ((v) => v);
|
|
const transformRTL = ('rtl' in transform && transform.rtl) || ((v) => v);
|
|
if (direction === 'both' || direction === 'ltr') {
|
|
watchers.push(
|
|
watchPausable(
|
|
left,
|
|
(newValue) => {
|
|
watchers.forEach((w) => w.pause());
|
|
right.value = transformLTR(newValue);
|
|
watchers.forEach((w) => w.resume());
|
|
},
|
|
{ flush, deep, immediate }
|
|
)
|
|
);
|
|
}
|
|
if (direction === 'both' || direction === 'rtl') {
|
|
watchers.push(
|
|
watchPausable(
|
|
right,
|
|
(newValue) => {
|
|
watchers.forEach((w) => w.pause());
|
|
left.value = transformRTL(newValue);
|
|
watchers.forEach((w) => w.resume());
|
|
},
|
|
{ flush, deep, immediate }
|
|
)
|
|
);
|
|
}
|
|
const stop = () => {
|
|
watchers.forEach((w) => w.stop());
|
|
};
|
|
return stop;
|
|
}
|
|
function syncRefs(source, targets, options = {}) {
|
|
const { flush = 'sync', deep = false, immediate = true } = options;
|
|
const targetsArray = toArray(targets);
|
|
return watch(
|
|
source,
|
|
(newValue) => targetsArray.forEach((target) => (target.value = newValue)),
|
|
{ flush, deep, immediate }
|
|
);
|
|
}
|
|
function toRefs2(objectRef, options = {}) {
|
|
if (!isRef(objectRef)) return toRefs(objectRef);
|
|
const result = Array.isArray(objectRef.value)
|
|
? Array.from({ length: objectRef.value.length })
|
|
: {};
|
|
for (const key in objectRef.value) {
|
|
result[key] = customRef(() => ({
|
|
get() {
|
|
return objectRef.value[key];
|
|
},
|
|
set(v) {
|
|
var _a;
|
|
const replaceRef =
|
|
(_a = toValue(options.replaceRef)) != null ? _a : true;
|
|
if (replaceRef) {
|
|
if (Array.isArray(objectRef.value)) {
|
|
const copy = [...objectRef.value];
|
|
copy[key] = v;
|
|
objectRef.value = copy;
|
|
} else {
|
|
const newObject = { ...objectRef.value, [key]: v };
|
|
Object.setPrototypeOf(
|
|
newObject,
|
|
Object.getPrototypeOf(objectRef.value)
|
|
);
|
|
objectRef.value = newObject;
|
|
}
|
|
} else {
|
|
objectRef.value[key] = v;
|
|
}
|
|
},
|
|
}));
|
|
}
|
|
return result;
|
|
}
|
|
var toValue2 = toValue;
|
|
var resolveUnref = toValue;
|
|
function tryOnBeforeMount(fn, sync = true, target) {
|
|
const instance = getLifeCycleTarget(target);
|
|
if (instance) onBeforeMount(fn, target);
|
|
else if (sync) fn();
|
|
else nextTick(fn);
|
|
}
|
|
function tryOnBeforeUnmount(fn, target) {
|
|
const instance = getLifeCycleTarget(target);
|
|
if (instance) onBeforeUnmount(fn, target);
|
|
}
|
|
function tryOnMounted(fn, sync = true, target) {
|
|
const instance = getLifeCycleTarget();
|
|
if (instance) onMounted(fn, target);
|
|
else if (sync) fn();
|
|
else nextTick(fn);
|
|
}
|
|
function tryOnUnmounted(fn, target) {
|
|
const instance = getLifeCycleTarget(target);
|
|
if (instance) onUnmounted(fn, target);
|
|
}
|
|
function createUntil(r, isNot = false) {
|
|
function toMatch(
|
|
condition,
|
|
{ flush = 'sync', deep = false, timeout, throwOnTimeout } = {}
|
|
) {
|
|
let stop = null;
|
|
const watcher = new Promise((resolve) => {
|
|
stop = watch(
|
|
r,
|
|
(v) => {
|
|
if (condition(v) !== isNot) {
|
|
if (stop) stop();
|
|
else nextTick(() => (stop == null ? void 0 : stop()));
|
|
resolve(v);
|
|
}
|
|
},
|
|
{
|
|
flush,
|
|
deep,
|
|
immediate: true,
|
|
}
|
|
);
|
|
});
|
|
const promises = [watcher];
|
|
if (timeout != null) {
|
|
promises.push(
|
|
promiseTimeout(timeout, throwOnTimeout)
|
|
.then(() => toValue(r))
|
|
.finally(() => (stop == null ? void 0 : stop()))
|
|
);
|
|
}
|
|
return Promise.race(promises);
|
|
}
|
|
function toBe(value, options) {
|
|
if (!isRef(value)) return toMatch((v) => v === value, options);
|
|
const {
|
|
flush = 'sync',
|
|
deep = false,
|
|
timeout,
|
|
throwOnTimeout,
|
|
} = options != null ? options : {};
|
|
let stop = null;
|
|
const watcher = new Promise((resolve) => {
|
|
stop = watch(
|
|
[r, value],
|
|
([v1, v2]) => {
|
|
if (isNot !== (v1 === v2)) {
|
|
if (stop) stop();
|
|
else nextTick(() => (stop == null ? void 0 : stop()));
|
|
resolve(v1);
|
|
}
|
|
},
|
|
{
|
|
flush,
|
|
deep,
|
|
immediate: true,
|
|
}
|
|
);
|
|
});
|
|
const promises = [watcher];
|
|
if (timeout != null) {
|
|
promises.push(
|
|
promiseTimeout(timeout, throwOnTimeout)
|
|
.then(() => toValue(r))
|
|
.finally(() => {
|
|
stop == null ? void 0 : stop();
|
|
return toValue(r);
|
|
})
|
|
);
|
|
}
|
|
return Promise.race(promises);
|
|
}
|
|
function toBeTruthy(options) {
|
|
return toMatch((v) => Boolean(v), options);
|
|
}
|
|
function toBeNull(options) {
|
|
return toBe(null, options);
|
|
}
|
|
function toBeUndefined(options) {
|
|
return toBe(void 0, options);
|
|
}
|
|
function toBeNaN(options) {
|
|
return toMatch(Number.isNaN, options);
|
|
}
|
|
function toContains(value, options) {
|
|
return toMatch((v) => {
|
|
const array = Array.from(v);
|
|
return array.includes(value) || array.includes(toValue(value));
|
|
}, options);
|
|
}
|
|
function changed(options) {
|
|
return changedTimes(1, options);
|
|
}
|
|
function changedTimes(n = 1, options) {
|
|
let count = -1;
|
|
return toMatch(() => {
|
|
count += 1;
|
|
return count >= n;
|
|
}, options);
|
|
}
|
|
if (Array.isArray(toValue(r))) {
|
|
const instance = {
|
|
toMatch,
|
|
toContains,
|
|
changed,
|
|
changedTimes,
|
|
get not() {
|
|
return createUntil(r, !isNot);
|
|
},
|
|
};
|
|
return instance;
|
|
} else {
|
|
const instance = {
|
|
toMatch,
|
|
toBe,
|
|
toBeTruthy,
|
|
toBeNull,
|
|
toBeNaN,
|
|
toBeUndefined,
|
|
changed,
|
|
changedTimes,
|
|
get not() {
|
|
return createUntil(r, !isNot);
|
|
},
|
|
};
|
|
return instance;
|
|
}
|
|
}
|
|
function until(r) {
|
|
return createUntil(r);
|
|
}
|
|
function defaultComparator(value, othVal) {
|
|
return value === othVal;
|
|
}
|
|
function useArrayDifference(...args) {
|
|
var _a, _b;
|
|
const list = args[0];
|
|
const values = args[1];
|
|
let compareFn = (_a = args[2]) != null ? _a : defaultComparator;
|
|
const { symmetric = false } = (_b = args[3]) != null ? _b : {};
|
|
if (typeof compareFn === 'string') {
|
|
const key = compareFn;
|
|
compareFn = (value, othVal) => value[key] === othVal[key];
|
|
}
|
|
const diff1 = computed(() =>
|
|
toValue(list).filter(
|
|
(x) => toValue(values).findIndex((y) => compareFn(x, y)) === -1
|
|
)
|
|
);
|
|
if (symmetric) {
|
|
const diff2 = computed(() =>
|
|
toValue(values).filter(
|
|
(x) => toValue(list).findIndex((y) => compareFn(x, y)) === -1
|
|
)
|
|
);
|
|
return computed(() =>
|
|
symmetric ? [...toValue(diff1), ...toValue(diff2)] : toValue(diff1)
|
|
);
|
|
} else {
|
|
return diff1;
|
|
}
|
|
}
|
|
function useArrayEvery(list, fn) {
|
|
return computed(() =>
|
|
toValue(list).every((element, index, array) =>
|
|
fn(toValue(element), index, array)
|
|
)
|
|
);
|
|
}
|
|
function useArrayFilter(list, fn) {
|
|
return computed(() =>
|
|
toValue(list)
|
|
.map((i) => toValue(i))
|
|
.filter(fn)
|
|
);
|
|
}
|
|
function useArrayFind(list, fn) {
|
|
return computed(() =>
|
|
toValue(
|
|
toValue(list).find((element, index, array) =>
|
|
fn(toValue(element), index, array)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
function useArrayFindIndex(list, fn) {
|
|
return computed(() =>
|
|
toValue(list).findIndex((element, index, array) =>
|
|
fn(toValue(element), index, array)
|
|
)
|
|
);
|
|
}
|
|
function findLast(arr, cb) {
|
|
let index = arr.length;
|
|
while (index-- > 0) {
|
|
if (cb(arr[index], index, arr)) return arr[index];
|
|
}
|
|
return void 0;
|
|
}
|
|
function useArrayFindLast(list, fn) {
|
|
return computed(() =>
|
|
toValue(
|
|
!Array.prototype.findLast
|
|
? findLast(toValue(list), (element, index, array) =>
|
|
fn(toValue(element), index, array)
|
|
)
|
|
: toValue(list).findLast((element, index, array) =>
|
|
fn(toValue(element), index, array)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
function isArrayIncludesOptions(obj) {
|
|
return isObject(obj) && containsProp(obj, 'formIndex', 'comparator');
|
|
}
|
|
function useArrayIncludes(...args) {
|
|
var _a;
|
|
const list = args[0];
|
|
const value = args[1];
|
|
let comparator = args[2];
|
|
let formIndex = 0;
|
|
if (isArrayIncludesOptions(comparator)) {
|
|
formIndex = (_a = comparator.fromIndex) != null ? _a : 0;
|
|
comparator = comparator.comparator;
|
|
}
|
|
if (typeof comparator === 'string') {
|
|
const key = comparator;
|
|
comparator = (element, value2) => element[key] === toValue(value2);
|
|
}
|
|
comparator =
|
|
comparator != null
|
|
? comparator
|
|
: (element, value2) => element === toValue(value2);
|
|
return computed(() =>
|
|
toValue(list)
|
|
.slice(formIndex)
|
|
.some((element, index, array) =>
|
|
comparator(toValue(element), toValue(value), index, toValue(array))
|
|
)
|
|
);
|
|
}
|
|
function useArrayJoin(list, separator) {
|
|
return computed(() =>
|
|
toValue(list)
|
|
.map((i) => toValue(i))
|
|
.join(toValue(separator))
|
|
);
|
|
}
|
|
function useArrayMap(list, fn) {
|
|
return computed(() =>
|
|
toValue(list)
|
|
.map((i) => toValue(i))
|
|
.map(fn)
|
|
);
|
|
}
|
|
function useArrayReduce(list, reducer, ...args) {
|
|
const reduceCallback = (sum, value, index) =>
|
|
reducer(toValue(sum), toValue(value), index);
|
|
return computed(() => {
|
|
const resolved = toValue(list);
|
|
return args.length
|
|
? resolved.reduce(
|
|
reduceCallback,
|
|
typeof args[0] === 'function' ? toValue(args[0]()) : toValue(args[0])
|
|
)
|
|
: resolved.reduce(reduceCallback);
|
|
});
|
|
}
|
|
function useArraySome(list, fn) {
|
|
return computed(() =>
|
|
toValue(list).some((element, index, array) =>
|
|
fn(toValue(element), index, array)
|
|
)
|
|
);
|
|
}
|
|
function uniq(array) {
|
|
return Array.from(new Set(array));
|
|
}
|
|
function uniqueElementsBy(array, fn) {
|
|
return array.reduce((acc, v) => {
|
|
if (!acc.some((x) => fn(v, x, array))) acc.push(v);
|
|
return acc;
|
|
}, []);
|
|
}
|
|
function useArrayUnique(list, compareFn) {
|
|
return computed(() => {
|
|
const resolvedList = toValue(list).map((element) => toValue(element));
|
|
return compareFn
|
|
? uniqueElementsBy(resolvedList, compareFn)
|
|
: uniq(resolvedList);
|
|
});
|
|
}
|
|
function useCounter(initialValue = 0, options = {}) {
|
|
let _initialValue = unref(initialValue);
|
|
const count = shallowRef(initialValue);
|
|
const { max = Number.POSITIVE_INFINITY, min = Number.NEGATIVE_INFINITY } =
|
|
options;
|
|
const inc = (delta = 1) =>
|
|
(count.value = Math.max(Math.min(max, count.value + delta), min));
|
|
const dec = (delta = 1) =>
|
|
(count.value = Math.min(Math.max(min, count.value - delta), max));
|
|
const get2 = () => count.value;
|
|
const set2 = (val) => (count.value = Math.max(min, Math.min(max, val)));
|
|
const reset = (val = _initialValue) => {
|
|
_initialValue = val;
|
|
return set2(val);
|
|
};
|
|
return { count, inc, dec, get: get2, set: set2, reset };
|
|
}
|
|
var REGEX_PARSE =
|
|
/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[T\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/i;
|
|
var REGEX_FORMAT =
|
|
/[YMDHhms]o|\[([^\]]+)\]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a{1,2}|A{1,2}|m{1,2}|s{1,2}|Z{1,2}|z{1,4}|SSS/g;
|
|
function defaultMeridiem(hours, minutes, isLowercase, hasPeriod) {
|
|
let m = hours < 12 ? 'AM' : 'PM';
|
|
if (hasPeriod) m = m.split('').reduce((acc, curr) => (acc += `${curr}.`), '');
|
|
return isLowercase ? m.toLowerCase() : m;
|
|
}
|
|
function formatOrdinal(num) {
|
|
const suffixes = ['th', 'st', 'nd', 'rd'];
|
|
const v = num % 100;
|
|
return num + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);
|
|
}
|
|
function formatDate(date, formatStr, options = {}) {
|
|
var _a;
|
|
const years = date.getFullYear();
|
|
const month = date.getMonth();
|
|
const days = date.getDate();
|
|
const hours = date.getHours();
|
|
const minutes = date.getMinutes();
|
|
const seconds = date.getSeconds();
|
|
const milliseconds = date.getMilliseconds();
|
|
const day = date.getDay();
|
|
const meridiem = (_a = options.customMeridiem) != null ? _a : defaultMeridiem;
|
|
const stripTimeZone = (dateString) => {
|
|
var _a2;
|
|
return (_a2 = dateString.split(' ')[1]) != null ? _a2 : '';
|
|
};
|
|
const matches = {
|
|
Yo: () => formatOrdinal(years),
|
|
YY: () => String(years).slice(-2),
|
|
YYYY: () => years,
|
|
M: () => month + 1,
|
|
Mo: () => formatOrdinal(month + 1),
|
|
MM: () => `${month + 1}`.padStart(2, '0'),
|
|
MMM: () =>
|
|
date.toLocaleDateString(toValue(options.locales), { month: 'short' }),
|
|
MMMM: () =>
|
|
date.toLocaleDateString(toValue(options.locales), { month: 'long' }),
|
|
D: () => String(days),
|
|
Do: () => formatOrdinal(days),
|
|
DD: () => `${days}`.padStart(2, '0'),
|
|
H: () => String(hours),
|
|
Ho: () => formatOrdinal(hours),
|
|
HH: () => `${hours}`.padStart(2, '0'),
|
|
h: () => `${hours % 12 || 12}`.padStart(1, '0'),
|
|
ho: () => formatOrdinal(hours % 12 || 12),
|
|
hh: () => `${hours % 12 || 12}`.padStart(2, '0'),
|
|
m: () => String(minutes),
|
|
mo: () => formatOrdinal(minutes),
|
|
mm: () => `${minutes}`.padStart(2, '0'),
|
|
s: () => String(seconds),
|
|
so: () => formatOrdinal(seconds),
|
|
ss: () => `${seconds}`.padStart(2, '0'),
|
|
SSS: () => `${milliseconds}`.padStart(3, '0'),
|
|
d: () => day,
|
|
dd: () =>
|
|
date.toLocaleDateString(toValue(options.locales), { weekday: 'narrow' }),
|
|
ddd: () =>
|
|
date.toLocaleDateString(toValue(options.locales), { weekday: 'short' }),
|
|
dddd: () =>
|
|
date.toLocaleDateString(toValue(options.locales), { weekday: 'long' }),
|
|
A: () => meridiem(hours, minutes),
|
|
AA: () => meridiem(hours, minutes, false, true),
|
|
a: () => meridiem(hours, minutes, true),
|
|
aa: () => meridiem(hours, minutes, true, true),
|
|
z: () =>
|
|
stripTimeZone(
|
|
date.toLocaleDateString(toValue(options.locales), {
|
|
timeZoneName: 'shortOffset',
|
|
})
|
|
),
|
|
zz: () =>
|
|
stripTimeZone(
|
|
date.toLocaleDateString(toValue(options.locales), {
|
|
timeZoneName: 'shortOffset',
|
|
})
|
|
),
|
|
zzz: () =>
|
|
stripTimeZone(
|
|
date.toLocaleDateString(toValue(options.locales), {
|
|
timeZoneName: 'shortOffset',
|
|
})
|
|
),
|
|
zzzz: () =>
|
|
stripTimeZone(
|
|
date.toLocaleDateString(toValue(options.locales), {
|
|
timeZoneName: 'longOffset',
|
|
})
|
|
),
|
|
};
|
|
return formatStr.replace(REGEX_FORMAT, (match, $1) => {
|
|
var _a2, _b;
|
|
return (_b =
|
|
$1 != null
|
|
? $1
|
|
: (_a2 = matches[match]) == null
|
|
? void 0
|
|
: _a2.call(matches)) != null
|
|
? _b
|
|
: match;
|
|
});
|
|
}
|
|
function normalizeDate(date) {
|
|
if (date === null) return new Date(Number.NaN);
|
|
if (date === void 0) return /* @__PURE__ */ new Date();
|
|
if (date instanceof Date) return new Date(date);
|
|
if (typeof date === 'string' && !/Z$/i.test(date)) {
|
|
const d = date.match(REGEX_PARSE);
|
|
if (d) {
|
|
const m = d[2] - 1 || 0;
|
|
const ms = (d[7] || '0').substring(0, 3);
|
|
return new Date(d[1], m, d[3] || 1, d[4] || 0, d[5] || 0, d[6] || 0, ms);
|
|
}
|
|
}
|
|
return new Date(date);
|
|
}
|
|
function useDateFormat(date, formatStr = 'HH:mm:ss', options = {}) {
|
|
return computed(() =>
|
|
formatDate(normalizeDate(toValue(date)), toValue(formatStr), options)
|
|
);
|
|
}
|
|
function useIntervalFn(cb, interval = 1e3, options = {}) {
|
|
const { immediate = true, immediateCallback = false } = options;
|
|
let timer = null;
|
|
const isActive = shallowRef(false);
|
|
function clean() {
|
|
if (timer) {
|
|
clearInterval(timer);
|
|
timer = null;
|
|
}
|
|
}
|
|
function pause() {
|
|
isActive.value = false;
|
|
clean();
|
|
}
|
|
function resume() {
|
|
const intervalValue = toValue(interval);
|
|
if (intervalValue <= 0) return;
|
|
isActive.value = true;
|
|
if (immediateCallback) cb();
|
|
clean();
|
|
if (isActive.value) timer = setInterval(cb, intervalValue);
|
|
}
|
|
if (immediate && isClient) resume();
|
|
if (isRef(interval) || typeof interval === 'function') {
|
|
const stopWatch = watch(interval, () => {
|
|
if (isActive.value && isClient) resume();
|
|
});
|
|
tryOnScopeDispose(stopWatch);
|
|
}
|
|
tryOnScopeDispose(pause);
|
|
return {
|
|
isActive,
|
|
pause,
|
|
resume,
|
|
};
|
|
}
|
|
function useInterval(interval = 1e3, options = {}) {
|
|
const {
|
|
controls: exposeControls = false,
|
|
immediate = true,
|
|
callback,
|
|
} = options;
|
|
const counter = shallowRef(0);
|
|
const update = () => (counter.value += 1);
|
|
const reset = () => {
|
|
counter.value = 0;
|
|
};
|
|
const controls = useIntervalFn(
|
|
callback
|
|
? () => {
|
|
update();
|
|
callback(counter.value);
|
|
}
|
|
: update,
|
|
interval,
|
|
{ immediate }
|
|
);
|
|
if (exposeControls) {
|
|
return {
|
|
counter,
|
|
reset,
|
|
...controls,
|
|
};
|
|
} else {
|
|
return counter;
|
|
}
|
|
}
|
|
function useLastChanged(source, options = {}) {
|
|
var _a;
|
|
const ms = shallowRef((_a = options.initialValue) != null ? _a : null);
|
|
watch(source, () => (ms.value = timestamp()), options);
|
|
return ms;
|
|
}
|
|
function useTimeoutFn(cb, interval, options = {}) {
|
|
const { immediate = true, immediateCallback = false } = options;
|
|
const isPending = shallowRef(false);
|
|
let timer = null;
|
|
function clear() {
|
|
if (timer) {
|
|
clearTimeout(timer);
|
|
timer = null;
|
|
}
|
|
}
|
|
function stop() {
|
|
isPending.value = false;
|
|
clear();
|
|
}
|
|
function start(...args) {
|
|
if (immediateCallback) cb();
|
|
clear();
|
|
isPending.value = true;
|
|
timer = setTimeout(() => {
|
|
isPending.value = false;
|
|
timer = null;
|
|
cb(...args);
|
|
}, toValue(interval));
|
|
}
|
|
if (immediate) {
|
|
isPending.value = true;
|
|
if (isClient) start();
|
|
}
|
|
tryOnScopeDispose(stop);
|
|
return {
|
|
isPending: readonly(isPending),
|
|
start,
|
|
stop,
|
|
};
|
|
}
|
|
function useTimeout(interval = 1e3, options = {}) {
|
|
const { controls: exposeControls = false, callback } = options;
|
|
const controls = useTimeoutFn(
|
|
callback != null ? callback : noop,
|
|
interval,
|
|
options
|
|
);
|
|
const ready = computed(() => !controls.isPending.value);
|
|
if (exposeControls) {
|
|
return {
|
|
ready,
|
|
...controls,
|
|
};
|
|
} else {
|
|
return ready;
|
|
}
|
|
}
|
|
function useToNumber(value, options = {}) {
|
|
const { method = 'parseFloat', radix, nanToZero } = options;
|
|
return computed(() => {
|
|
let resolved = toValue(value);
|
|
if (typeof method === 'function') resolved = method(resolved);
|
|
else if (typeof resolved === 'string')
|
|
resolved = Number[method](resolved, radix);
|
|
if (nanToZero && Number.isNaN(resolved)) resolved = 0;
|
|
return resolved;
|
|
});
|
|
}
|
|
function useToString(value) {
|
|
return computed(() => `${toValue(value)}`);
|
|
}
|
|
function useToggle(initialValue = false, options = {}) {
|
|
const { truthyValue = true, falsyValue = false } = options;
|
|
const valueIsRef = isRef(initialValue);
|
|
const _value = shallowRef(initialValue);
|
|
function toggle(value) {
|
|
if (arguments.length) {
|
|
_value.value = value;
|
|
return _value.value;
|
|
} else {
|
|
const truthy = toValue(truthyValue);
|
|
_value.value = _value.value === truthy ? toValue(falsyValue) : truthy;
|
|
return _value.value;
|
|
}
|
|
}
|
|
if (valueIsRef) return toggle;
|
|
else return [_value, toggle];
|
|
}
|
|
function watchArray(source, cb, options) {
|
|
let oldList = (options == null ? void 0 : options.immediate)
|
|
? []
|
|
: [
|
|
...(typeof source === 'function'
|
|
? source()
|
|
: Array.isArray(source)
|
|
? source
|
|
: toValue(source)),
|
|
];
|
|
return watch(
|
|
source,
|
|
(newList, _, onCleanup) => {
|
|
const oldListRemains = Array.from({ length: oldList.length });
|
|
const added = [];
|
|
for (const obj of newList) {
|
|
let found = false;
|
|
for (let i = 0; i < oldList.length; i++) {
|
|
if (!oldListRemains[i] && obj === oldList[i]) {
|
|
oldListRemains[i] = true;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) added.push(obj);
|
|
}
|
|
const removed = oldList.filter((_2, i) => !oldListRemains[i]);
|
|
cb(newList, oldList, added, removed, onCleanup);
|
|
oldList = [...newList];
|
|
},
|
|
options
|
|
);
|
|
}
|
|
function watchAtMost(source, cb, options) {
|
|
const { count, ...watchOptions } = options;
|
|
const current = shallowRef(0);
|
|
const stop = watchWithFilter(
|
|
source,
|
|
(...args) => {
|
|
current.value += 1;
|
|
if (current.value >= toValue(count)) nextTick(() => stop());
|
|
cb(...args);
|
|
},
|
|
watchOptions
|
|
);
|
|
return { count: current, stop };
|
|
}
|
|
function watchDebounced(source, cb, options = {}) {
|
|
const { debounce = 0, maxWait = void 0, ...watchOptions } = options;
|
|
return watchWithFilter(source, cb, {
|
|
...watchOptions,
|
|
eventFilter: debounceFilter(debounce, { maxWait }),
|
|
});
|
|
}
|
|
function watchDeep(source, cb, options) {
|
|
return watch(source, cb, {
|
|
...options,
|
|
deep: true,
|
|
});
|
|
}
|
|
function watchIgnorable(source, cb, options = {}) {
|
|
const { eventFilter = bypassFilter, ...watchOptions } = options;
|
|
const filteredCb = createFilterWrapper(eventFilter, cb);
|
|
let ignoreUpdates;
|
|
let ignorePrevAsyncUpdates;
|
|
let stop;
|
|
if (watchOptions.flush === 'sync') {
|
|
const ignore = shallowRef(false);
|
|
ignorePrevAsyncUpdates = () => {};
|
|
ignoreUpdates = (updater) => {
|
|
ignore.value = true;
|
|
updater();
|
|
ignore.value = false;
|
|
};
|
|
stop = watch(
|
|
source,
|
|
(...args) => {
|
|
if (!ignore.value) filteredCb(...args);
|
|
},
|
|
watchOptions
|
|
);
|
|
} else {
|
|
const disposables = [];
|
|
const ignoreCounter = shallowRef(0);
|
|
const syncCounter = shallowRef(0);
|
|
ignorePrevAsyncUpdates = () => {
|
|
ignoreCounter.value = syncCounter.value;
|
|
};
|
|
disposables.push(
|
|
watch(
|
|
source,
|
|
() => {
|
|
syncCounter.value++;
|
|
},
|
|
{ ...watchOptions, flush: 'sync' }
|
|
)
|
|
);
|
|
ignoreUpdates = (updater) => {
|
|
const syncCounterPrev = syncCounter.value;
|
|
updater();
|
|
ignoreCounter.value += syncCounter.value - syncCounterPrev;
|
|
};
|
|
disposables.push(
|
|
watch(
|
|
source,
|
|
(...args) => {
|
|
const ignore =
|
|
ignoreCounter.value > 0 &&
|
|
ignoreCounter.value === syncCounter.value;
|
|
ignoreCounter.value = 0;
|
|
syncCounter.value = 0;
|
|
if (ignore) return;
|
|
filteredCb(...args);
|
|
},
|
|
watchOptions
|
|
)
|
|
);
|
|
stop = () => {
|
|
disposables.forEach((fn) => fn());
|
|
};
|
|
}
|
|
return { stop, ignoreUpdates, ignorePrevAsyncUpdates };
|
|
}
|
|
function watchImmediate(source, cb, options) {
|
|
return watch(source, cb, {
|
|
...options,
|
|
immediate: true,
|
|
});
|
|
}
|
|
function watchOnce(source, cb, options) {
|
|
const stop = watch(
|
|
source,
|
|
(...args) => {
|
|
nextTick(() => stop());
|
|
return cb(...args);
|
|
},
|
|
options
|
|
);
|
|
return stop;
|
|
}
|
|
function watchThrottled(source, cb, options = {}) {
|
|
const {
|
|
throttle = 0,
|
|
trailing = true,
|
|
leading = true,
|
|
...watchOptions
|
|
} = options;
|
|
return watchWithFilter(source, cb, {
|
|
...watchOptions,
|
|
eventFilter: throttleFilter(throttle, trailing, leading),
|
|
});
|
|
}
|
|
function watchTriggerable(source, cb, options = {}) {
|
|
let cleanupFn;
|
|
function onEffect() {
|
|
if (!cleanupFn) return;
|
|
const fn = cleanupFn;
|
|
cleanupFn = void 0;
|
|
fn();
|
|
}
|
|
function onCleanup(callback) {
|
|
cleanupFn = callback;
|
|
}
|
|
const _cb = (value, oldValue) => {
|
|
onEffect();
|
|
return cb(value, oldValue, onCleanup);
|
|
};
|
|
const res = watchIgnorable(source, _cb, options);
|
|
const { ignoreUpdates } = res;
|
|
const trigger = () => {
|
|
let res2;
|
|
ignoreUpdates(() => {
|
|
res2 = _cb(getWatchSources(source), getOldValue(source));
|
|
});
|
|
return res2;
|
|
};
|
|
return {
|
|
...res,
|
|
trigger,
|
|
};
|
|
}
|
|
function getWatchSources(sources) {
|
|
if (isReactive(sources)) return sources;
|
|
if (Array.isArray(sources)) return sources.map((item) => toValue(item));
|
|
return toValue(sources);
|
|
}
|
|
function getOldValue(source) {
|
|
return Array.isArray(source) ? source.map(() => void 0) : void 0;
|
|
}
|
|
function whenever(source, cb, options) {
|
|
const stop = watch(
|
|
source,
|
|
(v, ov, onInvalidate) => {
|
|
if (v) {
|
|
if (options == null ? void 0 : options.once) nextTick(() => stop());
|
|
cb(v, ov, onInvalidate);
|
|
}
|
|
},
|
|
{
|
|
...options,
|
|
once: false,
|
|
}
|
|
);
|
|
return stop;
|
|
}
|
|
|
|
// node_modules/@vueuse/core/index.mjs
|
|
function computedAsync(evaluationCallback, initialState, optionsOrRef) {
|
|
let options;
|
|
if (isRef(optionsOrRef)) {
|
|
options = {
|
|
evaluating: optionsOrRef,
|
|
};
|
|
} else {
|
|
options = optionsOrRef || {};
|
|
}
|
|
const {
|
|
lazy = false,
|
|
evaluating = void 0,
|
|
shallow = true,
|
|
onError = 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;
|
|
}
|
|
});
|
|
if (lazy) {
|
|
return computed(() => {
|
|
started.value = true;
|
|
return current.value;
|
|
});
|
|
} else {
|
|
return current;
|
|
}
|
|
}
|
|
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((ctx) => options(source, ctx));
|
|
} else {
|
|
return computed({
|
|
get: (ctx) => options.get(source, ctx),
|
|
set: options.set,
|
|
});
|
|
}
|
|
}
|
|
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 _a;
|
|
if (!render.value && true)
|
|
throw new Error(
|
|
'[VueUse] Failed to find the definition of reusable template'
|
|
);
|
|
const vnode =
|
|
(_a = render.value) == null
|
|
? void 0
|
|
: _a.call(render, {
|
|
...(options.props == null
|
|
? keysToCamelKebabCase(attrs)
|
|
: props),
|
|
$slots: slots,
|
|
});
|
|
return inheritAttrs && (vnode == null ? 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;
|
|
}
|
|
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 index2 = instances.value.indexOf(props);
|
|
if (index2 !== -1) instances.value.splice(index2, 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 _a;
|
|
return h(
|
|
Fragment,
|
|
{ key: props.key },
|
|
(_a = slots.default) == null ? void 0 : _a.call(slots, props)
|
|
);
|
|
});
|
|
if (options.transition)
|
|
return () => h(TransitionGroup, options.transition, renderList);
|
|
return renderList;
|
|
});
|
|
component.start = start;
|
|
return component;
|
|
}
|
|
function createUnrefFn(fn) {
|
|
return function (...args) {
|
|
return fn.apply(
|
|
this,
|
|
args.map((i) => toValue(i))
|
|
);
|
|
};
|
|
}
|
|
var defaultWindow = isClient ? window : void 0;
|
|
var defaultDocument = isClient ? window.document : void 0;
|
|
var defaultNavigator = isClient ? window.navigator : void 0;
|
|
var defaultLocation = isClient ? window.location : void 0;
|
|
function unrefElement(elRef) {
|
|
var _a;
|
|
const plain = toValue(elRef);
|
|
return (_a = plain == null ? void 0 : plain.$el) != null ? _a : plain;
|
|
}
|
|
function useEventListener(...args) {
|
|
const cleanups = [];
|
|
const cleanup = () => {
|
|
cleanups.forEach((fn) => fn());
|
|
cleanups.length = 0;
|
|
};
|
|
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;
|
|
});
|
|
const stopWatch = watchImmediate(
|
|
() => {
|
|
var _a, _b;
|
|
return [
|
|
(_b =
|
|
(_a = firstParamTargets.value) == null
|
|
? void 0
|
|
: _a.map((e) => unrefElement(e))) != null
|
|
? _b
|
|
: [defaultWindow].filter((e) => e != null),
|
|
toArray(toValue(firstParamTargets.value ? args[1] : args[0])),
|
|
toArray(unref(firstParamTargets.value ? args[2] : args[1])),
|
|
// @ts-expect-error - TypeScript gets the correct types, but somehow still complains
|
|
toValue(firstParamTargets.value ? args[3] : args[2]),
|
|
];
|
|
},
|
|
([raw_targets, raw_events, raw_listeners, raw_options]) => {
|
|
cleanup();
|
|
if (
|
|
!(raw_targets == null ? void 0 : raw_targets.length) ||
|
|
!(raw_events == null ? void 0 : raw_events.length) ||
|
|
!(raw_listeners == null ? void 0 : raw_listeners.length)
|
|
)
|
|
return;
|
|
const optionsClone = isObject(raw_options)
|
|
? { ...raw_options }
|
|
: raw_options;
|
|
cleanups.push(
|
|
...raw_targets.flatMap((el) =>
|
|
raw_events.flatMap((event) =>
|
|
raw_listeners.map((listener) =>
|
|
register(el, event, listener, optionsClone)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
},
|
|
{ flush: 'post' }
|
|
);
|
|
const stop = () => {
|
|
stopWatch();
|
|
cleanup();
|
|
};
|
|
tryOnScopeDispose(cleanup);
|
|
return stop;
|
|
}
|
|
var _iOSWorkaround = false;
|
|
function onClickOutside(target, handler, options = {}) {
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
ignore = [],
|
|
capture = true,
|
|
detectIframe = false,
|
|
controls = false,
|
|
} = options;
|
|
if (!window2) {
|
|
return controls ? { stop: noop, cancel: noop, trigger: noop } : noop;
|
|
}
|
|
if (isIOS && !_iOSWorkaround) {
|
|
_iOSWorkaround = true;
|
|
const listenerOptions = { passive: true };
|
|
Array.from(window2.document.body.children).forEach((el) =>
|
|
useEventListener(el, 'click', noop, listenerOptions)
|
|
);
|
|
useEventListener(
|
|
window2.document.documentElement,
|
|
'click',
|
|
noop,
|
|
listenerOptions
|
|
);
|
|
}
|
|
let shouldListen = true;
|
|
const shouldIgnore = (event) => {
|
|
return toValue(ignore).some((target2) => {
|
|
if (typeof target2 === 'string') {
|
|
return Array.from(window2.document.querySelectorAll(target2)).some(
|
|
(el) => el === event.target || event.composedPath().includes(el)
|
|
);
|
|
} else {
|
|
const el = unrefElement(target2);
|
|
return el && (event.target === el || event.composedPath().includes(el));
|
|
}
|
|
});
|
|
};
|
|
function hasMultipleRoots(target2) {
|
|
const vm = toValue(target2);
|
|
return vm && vm.$.subTree.shapeFlag === 16;
|
|
}
|
|
function checkMultipleRoots(target2, event) {
|
|
const vm = toValue(target2);
|
|
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(
|
|
window2,
|
|
'click',
|
|
(event) => {
|
|
if (!isProcessingClick) {
|
|
isProcessingClick = true;
|
|
setTimeout(() => {
|
|
isProcessingClick = false;
|
|
}, 0);
|
|
listener(event);
|
|
}
|
|
},
|
|
{ passive: true, capture }
|
|
),
|
|
useEventListener(
|
|
window2,
|
|
'pointerdown',
|
|
(e) => {
|
|
const el = unrefElement(target);
|
|
shouldListen =
|
|
!shouldIgnore(e) && !!(el && !e.composedPath().includes(el));
|
|
},
|
|
{ passive: true }
|
|
),
|
|
detectIframe &&
|
|
useEventListener(
|
|
window2,
|
|
'blur',
|
|
(event) => {
|
|
setTimeout(() => {
|
|
var _a;
|
|
const el = unrefElement(target);
|
|
if (
|
|
((_a = window2.document.activeElement) == null
|
|
? void 0
|
|
: _a.tagName) === 'IFRAME' &&
|
|
!(el == null
|
|
? void 0
|
|
: el.contains(window2.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;
|
|
}
|
|
function useMounted() {
|
|
const isMounted = shallowRef(false);
|
|
const instance = getCurrentInstance();
|
|
if (instance) {
|
|
onMounted(() => {
|
|
isMounted.value = true;
|
|
}, instance);
|
|
}
|
|
return isMounted;
|
|
}
|
|
function useSupported(callback) {
|
|
const isMounted = useMounted();
|
|
return computed(() => {
|
|
isMounted.value;
|
|
return Boolean(callback());
|
|
});
|
|
}
|
|
function useMutationObserver(target, callback, options = {}) {
|
|
const { window: window2 = defaultWindow, ...mutationOptions } = options;
|
|
let observer;
|
|
const isSupported = useSupported(
|
|
() => window2 && 'MutationObserver' in window2
|
|
);
|
|
const cleanup = () => {
|
|
if (observer) {
|
|
observer.disconnect();
|
|
observer = void 0;
|
|
}
|
|
};
|
|
const targets = computed(() => {
|
|
const value = toValue(target);
|
|
const items = toArray(value).map(unrefElement).filter(notNullish);
|
|
return new Set(items);
|
|
});
|
|
const stopWatch = watch(
|
|
() => targets.value,
|
|
(targets2) => {
|
|
cleanup();
|
|
if (isSupported.value && targets2.size) {
|
|
observer = new MutationObserver(callback);
|
|
targets2.forEach((el) => observer.observe(el, mutationOptions));
|
|
}
|
|
},
|
|
{ immediate: true, flush: 'post' }
|
|
);
|
|
const takeRecords = () => {
|
|
return observer == null ? void 0 : observer.takeRecords();
|
|
};
|
|
const stop = () => {
|
|
stopWatch();
|
|
cleanup();
|
|
};
|
|
tryOnScopeDispose(stop);
|
|
return {
|
|
isSupported,
|
|
stop,
|
|
takeRecords,
|
|
};
|
|
}
|
|
function onElementRemoval(target, callback, options = {}) {
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
document: document2 = window2 == null ? void 0 : window2.document,
|
|
flush = 'sync',
|
|
} = options;
|
|
if (!window2 || !document2) return noop;
|
|
let stopFn;
|
|
const cleanupAndUpdate = (fn) => {
|
|
stopFn == null ? void 0 : stopFn();
|
|
stopFn = fn;
|
|
};
|
|
const stopWatch = watchEffect(
|
|
() => {
|
|
const el = unrefElement(target);
|
|
if (el) {
|
|
const { stop } = useMutationObserver(
|
|
document2,
|
|
(mutationsList) => {
|
|
const targetRemoved = mutationsList
|
|
.map((mutation) => [...mutation.removedNodes])
|
|
.flat()
|
|
.some((node) => node === el || node.contains(el));
|
|
if (targetRemoved) {
|
|
callback(mutationsList);
|
|
}
|
|
},
|
|
{
|
|
window: window2,
|
|
childList: true,
|
|
subtree: true,
|
|
}
|
|
);
|
|
cleanupAndUpdate(stop);
|
|
}
|
|
},
|
|
{ flush }
|
|
);
|
|
const stopHandle = () => {
|
|
stopWatch();
|
|
cleanupAndUpdate();
|
|
};
|
|
tryOnScopeDispose(stopHandle);
|
|
return stopHandle;
|
|
}
|
|
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);
|
|
}
|
|
function onKeyDown(key, handler, options = {}) {
|
|
return onKeyStroke(key, handler, { ...options, eventName: 'keydown' });
|
|
}
|
|
function onKeyPressed(key, handler, options = {}) {
|
|
return onKeyStroke(key, handler, { ...options, eventName: 'keypress' });
|
|
}
|
|
function onKeyUp(key, handler, options = {}) {
|
|
return onKeyStroke(key, handler, { ...options, eventName: 'keyup' });
|
|
}
|
|
var DEFAULT_DELAY = 500;
|
|
var DEFAULT_THRESHOLD = 10;
|
|
function onLongPress(target, handler, options) {
|
|
var _a, _b;
|
|
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 onRelease(ev) {
|
|
var _a2, _b2, _c;
|
|
const [_startTimestamp, _posStart, _hasLongPressed] = [
|
|
startTimestamp,
|
|
posStart,
|
|
hasLongPressed,
|
|
];
|
|
clear();
|
|
if (
|
|
!(options == null ? void 0 : options.onMouseUp) ||
|
|
!_posStart ||
|
|
!_startTimestamp
|
|
)
|
|
return;
|
|
if (
|
|
((_a2 = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _a2.self) &&
|
|
ev.target !== elementRef.value
|
|
)
|
|
return;
|
|
if (
|
|
(_b2 = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _b2.prevent
|
|
)
|
|
ev.preventDefault();
|
|
if (
|
|
(_c = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _c.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 _a2, _b2, _c, _d;
|
|
if (
|
|
((_a2 = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _a2.self) &&
|
|
ev.target !== elementRef.value
|
|
)
|
|
return;
|
|
clear();
|
|
if (
|
|
(_b2 = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _b2.prevent
|
|
)
|
|
ev.preventDefault();
|
|
if (
|
|
(_c = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _c.stop
|
|
)
|
|
ev.stopPropagation();
|
|
posStart = {
|
|
x: ev.x,
|
|
y: ev.y,
|
|
};
|
|
startTimestamp = ev.timeStamp;
|
|
timeout = setTimeout(
|
|
() => {
|
|
hasLongPressed = true;
|
|
handler(ev);
|
|
},
|
|
(_d = options == null ? void 0 : options.delay) != null
|
|
? _d
|
|
: DEFAULT_DELAY
|
|
);
|
|
}
|
|
function onMove(ev) {
|
|
var _a2, _b2, _c, _d;
|
|
if (
|
|
((_a2 = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _a2.self) &&
|
|
ev.target !== elementRef.value
|
|
)
|
|
return;
|
|
if (
|
|
!posStart ||
|
|
(options == null ? void 0 : options.distanceThreshold) === false
|
|
)
|
|
return;
|
|
if (
|
|
(_b2 = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _b2.prevent
|
|
)
|
|
ev.preventDefault();
|
|
if (
|
|
(_c = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _c.stop
|
|
)
|
|
ev.stopPropagation();
|
|
const dx = ev.x - posStart.x;
|
|
const dy = ev.y - posStart.y;
|
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
if (
|
|
distance >=
|
|
((_d = options == null ? void 0 : options.distanceThreshold) != null
|
|
? _d
|
|
: DEFAULT_THRESHOLD)
|
|
)
|
|
clear();
|
|
}
|
|
const listenerOptions = {
|
|
capture:
|
|
(_a = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _a.capture,
|
|
once:
|
|
(_b = options == null ? void 0 : options.modifiers) == null
|
|
? void 0
|
|
: _b.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;
|
|
}
|
|
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;
|
|
}
|
|
function onStartTyping(callback, options = {}) {
|
|
const { document: document2 = defaultDocument } = options;
|
|
const keydown = (event) => {
|
|
if (!isFocusedElementEditable() && isTypedCharValid(event)) {
|
|
callback(event);
|
|
}
|
|
};
|
|
if (document2)
|
|
useEventListener(document2, 'keydown', keydown, { passive: true });
|
|
}
|
|
function templateRef(key, initialValue = null) {
|
|
const instance = getCurrentInstance();
|
|
let _trigger = () => {};
|
|
const element = customRef((track, trigger) => {
|
|
_trigger = trigger;
|
|
return {
|
|
get() {
|
|
var _a, _b;
|
|
track();
|
|
return (_b =
|
|
(_a = instance == null ? void 0 : instance.proxy) == null
|
|
? void 0
|
|
: _a.$refs[key]) != null
|
|
? _b
|
|
: initialValue;
|
|
},
|
|
set() {},
|
|
};
|
|
});
|
|
tryOnMounted(_trigger);
|
|
onUpdated(_trigger);
|
|
return element;
|
|
}
|
|
function useActiveElement(options = {}) {
|
|
var _a;
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
deep = true,
|
|
triggerOnRemoval = false,
|
|
} = options;
|
|
const document2 =
|
|
(_a = options.document) != null
|
|
? _a
|
|
: window2 == null
|
|
? void 0
|
|
: window2.document;
|
|
const getDeepActiveElement = () => {
|
|
var _a2;
|
|
let element = document2 == null ? void 0 : document2.activeElement;
|
|
if (deep) {
|
|
while (element == null ? void 0 : element.shadowRoot)
|
|
element =
|
|
(_a2 = element == null ? void 0 : element.shadowRoot) == null
|
|
? void 0
|
|
: _a2.activeElement;
|
|
}
|
|
return element;
|
|
};
|
|
const activeElement = shallowRef();
|
|
const trigger = () => {
|
|
activeElement.value = getDeepActiveElement();
|
|
};
|
|
if (window2) {
|
|
const listenerOptions = {
|
|
capture: true,
|
|
passive: true,
|
|
};
|
|
useEventListener(
|
|
window2,
|
|
'blur',
|
|
(event) => {
|
|
if (event.relatedTarget !== null) return;
|
|
trigger();
|
|
},
|
|
listenerOptions
|
|
);
|
|
useEventListener(window2, 'focus', trigger, listenerOptions);
|
|
}
|
|
if (triggerOnRemoval) {
|
|
onElementRemoval(activeElement, trigger, { document: document2 });
|
|
}
|
|
trigger();
|
|
return activeElement;
|
|
}
|
|
function useRafFn(fn, options = {}) {
|
|
const {
|
|
immediate = true,
|
|
fpsLimit = void 0,
|
|
window: window2 = 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(timestamp2) {
|
|
if (!isActive.value || !window2) return;
|
|
if (!previousFrameTimestamp) previousFrameTimestamp = timestamp2;
|
|
const delta = timestamp2 - previousFrameTimestamp;
|
|
if (intervalLimit.value && delta < intervalLimit.value) {
|
|
rafId = window2.requestAnimationFrame(loop);
|
|
return;
|
|
}
|
|
previousFrameTimestamp = timestamp2;
|
|
fn({ delta, timestamp: timestamp2 });
|
|
if (once) {
|
|
isActive.value = false;
|
|
rafId = null;
|
|
return;
|
|
}
|
|
rafId = window2.requestAnimationFrame(loop);
|
|
}
|
|
function resume() {
|
|
if (!isActive.value && window2) {
|
|
isActive.value = true;
|
|
previousFrameTimestamp = 0;
|
|
rafId = window2.requestAnimationFrame(loop);
|
|
}
|
|
}
|
|
function pause() {
|
|
isActive.value = false;
|
|
if (rafId != null && window2) {
|
|
window2.cancelAnimationFrame(rafId);
|
|
rafId = null;
|
|
}
|
|
}
|
|
if (immediate) resume();
|
|
tryOnScopeDispose(pause);
|
|
return {
|
|
isActive: readonly(isActive),
|
|
pause,
|
|
resume,
|
|
};
|
|
}
|
|
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: window2 = defaultWindow,
|
|
immediate = true,
|
|
commitStyles,
|
|
persist,
|
|
playbackRate: _playbackRate = 1,
|
|
onReady,
|
|
onError = (e) => {
|
|
console.error(e);
|
|
},
|
|
} = config;
|
|
const isSupported = useSupported(
|
|
() => window2 && 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 = () => {
|
|
var _a;
|
|
try {
|
|
(_a = animate.value) == null ? void 0 : _a.pause();
|
|
syncPause();
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
};
|
|
const reverse = () => {
|
|
var _a;
|
|
if (!animate.value) update();
|
|
try {
|
|
(_a = animate.value) == null ? void 0 : _a.reverse();
|
|
syncResume();
|
|
} catch (e) {
|
|
syncPause();
|
|
onError(e);
|
|
}
|
|
};
|
|
const finish = () => {
|
|
var _a;
|
|
try {
|
|
(_a = animate.value) == null ? void 0 : _a.finish();
|
|
syncPause();
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
};
|
|
const cancel = () => {
|
|
var _a;
|
|
try {
|
|
(_a = animate.value) == null ? void 0 : _a.cancel();
|
|
syncPause();
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
};
|
|
watch(
|
|
() => unrefElement(target),
|
|
(el) => {
|
|
if (el) {
|
|
update();
|
|
} 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 ? void 0 : onReady(animate.value);
|
|
}
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
animate,
|
|
['cancel', 'finish', 'remove'],
|
|
syncPause,
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
animate,
|
|
'finish',
|
|
() => {
|
|
var _a;
|
|
if (commitStyles)
|
|
(_a = animate.value) == null ? void 0 : _a.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 && window2) window2.requestAnimationFrame(pauseRef);
|
|
}
|
|
return {
|
|
isSupported,
|
|
animate,
|
|
// actions
|
|
play,
|
|
pause,
|
|
reverse,
|
|
finish,
|
|
cancel,
|
|
// state
|
|
pending,
|
|
playState,
|
|
replaceState,
|
|
startTime,
|
|
currentTime,
|
|
timeline,
|
|
playbackRate,
|
|
};
|
|
}
|
|
function useAsyncQueue(tasks, options) {
|
|
const {
|
|
interrupt = true,
|
|
onError = noop,
|
|
onFinished = noop,
|
|
signal,
|
|
} = options || {};
|
|
const promiseState = {
|
|
aborted: 'aborted',
|
|
fulfilled: 'fulfilled',
|
|
pending: 'pending',
|
|
rejected: 'rejected',
|
|
};
|
|
const initialResult = Array.from(
|
|
Array.from({ length: tasks.length }),
|
|
() => ({ state: promiseState.pending, data: null })
|
|
);
|
|
const result = reactive(initialResult);
|
|
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 _a;
|
|
if (signal == null ? void 0 : signal.aborted) {
|
|
updateResult(promiseState.aborted, new Error('aborted'));
|
|
return;
|
|
}
|
|
if (
|
|
((_a = result[activeIndex.value]) == null ? void 0 : _a.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 ? void 0 : signal.aborted) {
|
|
updateResult(promiseState.aborted, e);
|
|
return e;
|
|
}
|
|
updateResult(promiseState.rejected, e);
|
|
onError();
|
|
return e;
|
|
});
|
|
}, Promise.resolve());
|
|
return {
|
|
activeIndex,
|
|
result,
|
|
};
|
|
}
|
|
function whenAborted(signal) {
|
|
return new Promise((resolve, reject) => {
|
|
const error = new Error('aborted');
|
|
if (signal.aborted) reject(error);
|
|
else signal.addEventListener('abort', () => reject(error), { once: true });
|
|
});
|
|
}
|
|
function useAsyncState(promise, initialState, options) {
|
|
const {
|
|
immediate = true,
|
|
delay = 0,
|
|
onError = noop,
|
|
onSuccess = noop,
|
|
resetOnExecute = true,
|
|
shallow = true,
|
|
throwError,
|
|
} = options != null ? options : {};
|
|
const state = shallow ? shallowRef(initialState) : ref(initialState);
|
|
const isReady = shallowRef(false);
|
|
const isLoading = shallowRef(false);
|
|
const error = shallowRef(void 0);
|
|
async function execute(delay2 = 0, ...args) {
|
|
if (resetOnExecute) state.value = initialState;
|
|
error.value = void 0;
|
|
isReady.value = false;
|
|
isLoading.value = true;
|
|
if (delay2 > 0) await promiseTimeout(delay2);
|
|
const _promise = typeof promise === 'function' ? promise(...args) : promise;
|
|
try {
|
|
const data = await _promise;
|
|
state.value = data;
|
|
isReady.value = true;
|
|
onSuccess(data);
|
|
} catch (e) {
|
|
error.value = e;
|
|
onError(e);
|
|
if (throwError) throw e;
|
|
} finally {
|
|
isLoading.value = false;
|
|
}
|
|
return state.value;
|
|
}
|
|
if (immediate) {
|
|
execute(delay);
|
|
}
|
|
const shell = {
|
|
state,
|
|
isReady,
|
|
isLoading,
|
|
error,
|
|
execute,
|
|
};
|
|
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);
|
|
},
|
|
};
|
|
}
|
|
var 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;
|
|
}
|
|
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 ? void 0 : options.type,
|
|
options == null ? 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 ? void 0 : options.type,
|
|
options == null ? void 0 : options.quality
|
|
)
|
|
);
|
|
})
|
|
.catch(reject);
|
|
} else if (typeof _target === 'object') {
|
|
const _serializeFn =
|
|
(options == null ? void 0 : options.serializer) ||
|
|
getDefaultSerialization(_target);
|
|
const serialized = _serializeFn(_target);
|
|
return resolve(
|
|
blobToBase64(new Blob([serialized], { type: 'application/json' }))
|
|
);
|
|
} else {
|
|
reject(new Error('target is unsupported types'));
|
|
}
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
promise.value.then((res) => {
|
|
base64.value =
|
|
(options == null ? 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);
|
|
});
|
|
}
|
|
function useBattery(options = {}) {
|
|
const { navigator: navigator2 = defaultNavigator } = options;
|
|
const events2 = [
|
|
'chargingchange',
|
|
'chargingtimechange',
|
|
'dischargingtimechange',
|
|
'levelchange',
|
|
];
|
|
const isSupported = useSupported(
|
|
() =>
|
|
navigator2 &&
|
|
'getBattery' in navigator2 &&
|
|
typeof navigator2.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) {
|
|
navigator2.getBattery().then((_battery) => {
|
|
battery = _battery;
|
|
updateBatteryInfo.call(battery);
|
|
useEventListener(battery, events2, updateBatteryInfo, { passive: true });
|
|
});
|
|
}
|
|
return {
|
|
isSupported,
|
|
charging,
|
|
chargingTime,
|
|
dischargingTime,
|
|
level,
|
|
};
|
|
}
|
|
function useBluetooth(options) {
|
|
let { acceptAllDevices = false } = options || {};
|
|
const {
|
|
filters = void 0,
|
|
optionalServices = void 0,
|
|
navigator: navigator2 = defaultNavigator,
|
|
} = options || {};
|
|
const isSupported = useSupported(
|
|
() => navigator2 && 'bluetooth' in navigator2
|
|
);
|
|
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 (navigator2 == null
|
|
? void 0
|
|
: navigator2.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 _a;
|
|
if (device.value) (_a = device.value.gatt) == null ? void 0 : _a.connect();
|
|
});
|
|
tryOnScopeDispose(() => {
|
|
var _a;
|
|
if (device.value)
|
|
(_a = device.value.gatt) == null ? void 0 : _a.disconnect();
|
|
});
|
|
return {
|
|
isSupported,
|
|
isConnected: readonly(isConnected),
|
|
// Device:
|
|
device,
|
|
requestDevice,
|
|
// Server:
|
|
server,
|
|
// Errors:
|
|
error,
|
|
};
|
|
}
|
|
var ssrWidthSymbol = Symbol('vueuse-ssr-width');
|
|
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);
|
|
}
|
|
}
|
|
function useMediaQuery(query, options = {}) {
|
|
const { window: window2 = defaultWindow, ssrWidth = useSSRWidth() } = options;
|
|
const isSupported = useSupported(
|
|
() =>
|
|
window2 &&
|
|
'matchMedia' in window2 &&
|
|
typeof window2.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;
|
|
const queryStrings = toValue(query).split(',');
|
|
matches.value = queryStrings.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 = window2.matchMedia(toValue(query));
|
|
matches.value = mediaQuery.value.matches;
|
|
});
|
|
useEventListener(mediaQuery, 'change', handler, { passive: true });
|
|
return computed(() => matches.value);
|
|
}
|
|
var breakpointsTailwind = {
|
|
sm: 640,
|
|
md: 768,
|
|
lg: 1024,
|
|
xl: 1280,
|
|
'2xl': 1536,
|
|
};
|
|
var breakpointsBootstrapV5 = {
|
|
xs: 0,
|
|
sm: 576,
|
|
md: 768,
|
|
lg: 992,
|
|
xl: 1200,
|
|
xxl: 1400,
|
|
};
|
|
var breakpointsVuetifyV2 = {
|
|
xs: 0,
|
|
sm: 600,
|
|
md: 960,
|
|
lg: 1264,
|
|
xl: 1904,
|
|
};
|
|
var breakpointsVuetifyV3 = {
|
|
xs: 0,
|
|
sm: 600,
|
|
md: 960,
|
|
lg: 1280,
|
|
xl: 1920,
|
|
xxl: 2560,
|
|
};
|
|
var breakpointsVuetify = breakpointsVuetifyV2;
|
|
var breakpointsAntDesign = {
|
|
xs: 480,
|
|
sm: 576,
|
|
md: 768,
|
|
lg: 992,
|
|
xl: 1200,
|
|
xxl: 1600,
|
|
};
|
|
var breakpointsQuasar = {
|
|
xs: 0,
|
|
sm: 600,
|
|
md: 1024,
|
|
lg: 1440,
|
|
xl: 1920,
|
|
};
|
|
var breakpointsSematic = {
|
|
mobileS: 320,
|
|
mobileM: 375,
|
|
mobileL: 425,
|
|
tablet: 768,
|
|
laptop: 1024,
|
|
laptopL: 1440,
|
|
desktop4K: 2560,
|
|
};
|
|
var breakpointsMasterCss = {
|
|
'3xs': 360,
|
|
'2xs': 480,
|
|
xs: 600,
|
|
sm: 768,
|
|
md: 1024,
|
|
lg: 1280,
|
|
xl: 1440,
|
|
'2xl': 1600,
|
|
'3xl': 1920,
|
|
'4xl': 2560,
|
|
};
|
|
var breakpointsPrimeFlex = {
|
|
sm: 576,
|
|
md: 768,
|
|
lg: 992,
|
|
xl: 1200,
|
|
};
|
|
var breakpointsElement = {
|
|
xs: 0,
|
|
sm: 768,
|
|
md: 992,
|
|
lg: 1200,
|
|
xl: 1920,
|
|
};
|
|
function useBreakpoints(breakpoints, options = {}) {
|
|
function getValue2(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: window2 = defaultWindow,
|
|
strategy = 'min-width',
|
|
ssrWidth = useSSRWidth(),
|
|
} = options;
|
|
const ssrSupport = typeof ssrWidth === 'number';
|
|
const mounted = ssrSupport ? shallowRef(false) : { value: true };
|
|
if (ssrSupport) {
|
|
tryOnMounted(() => (mounted.value = !!window2));
|
|
}
|
|
function match(query, size) {
|
|
if (!mounted.value && ssrSupport) {
|
|
return query === 'min'
|
|
? ssrWidth >= pxValue(size)
|
|
: ssrWidth <= pxValue(size);
|
|
}
|
|
if (!window2) return false;
|
|
return window2.matchMedia(`(${query}-width: ${size})`).matches;
|
|
}
|
|
const greaterOrEqual = (k) => {
|
|
return useMediaQuery(() => `(min-width: ${getValue2(k)})`, options);
|
|
};
|
|
const smallerOrEqual = (k) => {
|
|
return useMediaQuery(() => `(max-width: ${getValue2(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(getValue2(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: ${getValue2(k, 0.1)})`, options);
|
|
},
|
|
smaller(k) {
|
|
return useMediaQuery(() => `(max-width: ${getValue2(k, -0.1)})`, options);
|
|
},
|
|
between(a, b) {
|
|
return useMediaQuery(
|
|
() =>
|
|
`(min-width: ${getValue2(a)}) and (max-width: ${getValue2(b, -0.1)})`,
|
|
options
|
|
);
|
|
},
|
|
isGreater(k) {
|
|
return match('min', getValue2(k, 0.1));
|
|
},
|
|
isGreaterOrEqual(k) {
|
|
return match('min', getValue2(k));
|
|
},
|
|
isSmaller(k) {
|
|
return match('max', getValue2(k, -0.1));
|
|
},
|
|
isSmallerOrEqual(k) {
|
|
return match('max', getValue2(k));
|
|
},
|
|
isInBetween(a, b) {
|
|
return match('min', getValue2(a)) && match('max', getValue2(b, -0.1));
|
|
},
|
|
current,
|
|
active() {
|
|
const bps = current();
|
|
return computed(() =>
|
|
bps.value.length === 0
|
|
? ''
|
|
: bps.value.at(strategy === 'min-width' ? -1 : 0)
|
|
);
|
|
},
|
|
});
|
|
}
|
|
function useBroadcastChannel(options) {
|
|
const { name, window: window2 = defaultWindow } = options;
|
|
const isSupported = useSupported(
|
|
() => window2 && 'BroadcastChannel' in window2
|
|
);
|
|
const isClosed = shallowRef(false);
|
|
const channel = ref();
|
|
const data = ref();
|
|
const error = shallowRef(null);
|
|
const post = (data2) => {
|
|
if (channel.value) channel.value.postMessage(data2);
|
|
};
|
|
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,
|
|
};
|
|
}
|
|
var WRITABLE_PROPERTIES = [
|
|
'hash',
|
|
'host',
|
|
'hostname',
|
|
'href',
|
|
'pathname',
|
|
'port',
|
|
'protocol',
|
|
'search',
|
|
];
|
|
function useBrowserLocation(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const refs = Object.fromEntries(
|
|
WRITABLE_PROPERTIES.map((key) => [key, ref()])
|
|
);
|
|
for (const [key, ref2] of objectEntries(refs)) {
|
|
watch(ref2, (value) => {
|
|
if (
|
|
!(window2 == null ? void 0 : window2.location) ||
|
|
window2.location[key] === value
|
|
)
|
|
return;
|
|
window2.location[key] = value;
|
|
});
|
|
}
|
|
const buildState = (trigger) => {
|
|
var _a;
|
|
const { state: state2, length } =
|
|
(window2 == null ? void 0 : window2.history) || {};
|
|
const { origin } = (window2 == null ? void 0 : window2.location) || {};
|
|
for (const key of WRITABLE_PROPERTIES)
|
|
refs[key].value =
|
|
(_a = window2 == null ? void 0 : window2.location) == null
|
|
? void 0
|
|
: _a[key];
|
|
return reactive({
|
|
trigger,
|
|
state: state2,
|
|
length,
|
|
origin,
|
|
...refs,
|
|
});
|
|
};
|
|
const state = ref(buildState('load'));
|
|
if (window2) {
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
window2,
|
|
'popstate',
|
|
() => (state.value = buildState('popstate')),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
window2,
|
|
'hashchange',
|
|
() => (state.value = buildState('hashchange')),
|
|
listenerOptions
|
|
);
|
|
}
|
|
return state;
|
|
}
|
|
function useCached(refValue, comparator = (a, b) => a === b, options) {
|
|
const { deepRefs = true, ...watchOptions } = options || {};
|
|
const cachedValue = createRef(refValue.value, deepRefs);
|
|
watch(
|
|
() => refValue.value,
|
|
(value) => {
|
|
if (!comparator(value, cachedValue.value)) cachedValue.value = value;
|
|
},
|
|
watchOptions
|
|
);
|
|
return cachedValue;
|
|
}
|
|
function usePermission(permissionDesc, options = {}) {
|
|
const { controls = false, navigator: navigator2 = defaultNavigator } =
|
|
options;
|
|
const isSupported = useSupported(
|
|
() => navigator2 && 'permissions' in navigator2
|
|
);
|
|
const permissionStatus = shallowRef();
|
|
const desc =
|
|
typeof permissionDesc === 'string'
|
|
? { name: permissionDesc }
|
|
: permissionDesc;
|
|
const state = shallowRef();
|
|
const update = () => {
|
|
var _a, _b;
|
|
state.value =
|
|
(_b = (_a = permissionStatus.value) == null ? void 0 : _a.state) != null
|
|
? _b
|
|
: 'prompt';
|
|
};
|
|
useEventListener(permissionStatus, 'change', update, { passive: true });
|
|
const query = createSingletonPromise(async () => {
|
|
if (!isSupported.value) return;
|
|
if (!permissionStatus.value) {
|
|
try {
|
|
permissionStatus.value = await navigator2.permissions.query(desc);
|
|
} catch (e) {
|
|
permissionStatus.value = void 0;
|
|
} finally {
|
|
update();
|
|
}
|
|
}
|
|
if (controls) return toRaw(permissionStatus.value);
|
|
});
|
|
query();
|
|
if (controls) {
|
|
return {
|
|
state,
|
|
isSupported,
|
|
query,
|
|
};
|
|
} else {
|
|
return state;
|
|
}
|
|
}
|
|
function useClipboard(options = {}) {
|
|
const {
|
|
navigator: navigator2 = defaultNavigator,
|
|
read = false,
|
|
source,
|
|
copiedDuring = 1500,
|
|
legacy = false,
|
|
} = options;
|
|
const isClipboardApiSupported = useSupported(
|
|
() => navigator2 && 'clipboard' in navigator2
|
|
);
|
|
const permissionRead = usePermission('clipboard-read');
|
|
const permissionWrite = usePermission('clipboard-write');
|
|
const isSupported = computed(() => isClipboardApiSupported.value || legacy);
|
|
const text = shallowRef('');
|
|
const copied = shallowRef(false);
|
|
const timeout = useTimeoutFn(() => (copied.value = false), copiedDuring, {
|
|
immediate: false,
|
|
});
|
|
async function updateText() {
|
|
let useLegacy = !(
|
|
isClipboardApiSupported.value && isAllowed(permissionRead.value)
|
|
);
|
|
if (!useLegacy) {
|
|
try {
|
|
text.value = await navigator2.clipboard.readText();
|
|
} catch (e) {
|
|
useLegacy = true;
|
|
}
|
|
}
|
|
if (useLegacy) {
|
|
text.value = legacyRead();
|
|
}
|
|
}
|
|
if (isSupported.value && read)
|
|
useEventListener(['copy', 'cut'], updateText, { passive: true });
|
|
async function copy(value = toValue(source)) {
|
|
if (isSupported.value && value != null) {
|
|
let useLegacy = !(
|
|
isClipboardApiSupported.value && isAllowed(permissionWrite.value)
|
|
);
|
|
if (!useLegacy) {
|
|
try {
|
|
await navigator2.clipboard.writeText(value);
|
|
} catch (e) {
|
|
useLegacy = true;
|
|
}
|
|
}
|
|
if (useLegacy) legacyCopy(value);
|
|
text.value = value;
|
|
copied.value = true;
|
|
timeout.start();
|
|
}
|
|
}
|
|
function legacyCopy(value) {
|
|
const ta = document.createElement('textarea');
|
|
ta.value = value != null ? value : '';
|
|
ta.style.position = 'absolute';
|
|
ta.style.opacity = '0';
|
|
document.body.appendChild(ta);
|
|
ta.select();
|
|
document.execCommand('copy');
|
|
ta.remove();
|
|
}
|
|
function legacyRead() {
|
|
var _a, _b, _c;
|
|
return (_c =
|
|
(_b =
|
|
(_a = document == null ? void 0 : document.getSelection) == null
|
|
? void 0
|
|
: _a.call(document)) == null
|
|
? void 0
|
|
: _b.toString()) != null
|
|
? _c
|
|
: '';
|
|
}
|
|
function isAllowed(status) {
|
|
return status === 'granted' || status === 'prompt';
|
|
}
|
|
return {
|
|
isSupported,
|
|
text,
|
|
copied,
|
|
copy,
|
|
};
|
|
}
|
|
function useClipboardItems(options = {}) {
|
|
const {
|
|
navigator: navigator2 = defaultNavigator,
|
|
read = false,
|
|
source,
|
|
copiedDuring = 1500,
|
|
} = options;
|
|
const isSupported = useSupported(
|
|
() => navigator2 && 'clipboard' in navigator2
|
|
);
|
|
const content = ref([]);
|
|
const copied = shallowRef(false);
|
|
const timeout = useTimeoutFn(() => (copied.value = false), copiedDuring, {
|
|
immediate: false,
|
|
});
|
|
function updateContent() {
|
|
if (isSupported.value) {
|
|
navigator2.clipboard.read().then((items) => {
|
|
content.value = items;
|
|
});
|
|
}
|
|
}
|
|
if (isSupported.value && read)
|
|
useEventListener(['copy', 'cut'], updateContent, { passive: true });
|
|
async function copy(value = toValue(source)) {
|
|
if (isSupported.value && value != null) {
|
|
await navigator2.clipboard.write(value);
|
|
content.value = value;
|
|
copied.value = true;
|
|
timeout.start();
|
|
}
|
|
}
|
|
return {
|
|
isSupported,
|
|
content,
|
|
copied,
|
|
copy,
|
|
};
|
|
}
|
|
function cloneFnJSON(source) {
|
|
return JSON.parse(JSON.stringify(source));
|
|
}
|
|
function useCloned(source, options = {}) {
|
|
const cloned = ref({});
|
|
const isModified = shallowRef(false);
|
|
let _lastSync = false;
|
|
const {
|
|
manual,
|
|
clone = cloneFnJSON,
|
|
// watch options
|
|
deep = true,
|
|
immediate = true,
|
|
} = options;
|
|
watch(
|
|
cloned,
|
|
() => {
|
|
if (_lastSync) {
|
|
_lastSync = false;
|
|
return;
|
|
}
|
|
isModified.value = true;
|
|
},
|
|
{
|
|
deep: true,
|
|
flush: 'sync',
|
|
}
|
|
);
|
|
function sync() {
|
|
_lastSync = true;
|
|
isModified.value = false;
|
|
cloned.value = clone(toValue(source));
|
|
}
|
|
if (!manual && (isRef(source) || typeof source === 'function')) {
|
|
watch(source, sync, {
|
|
...options,
|
|
deep,
|
|
immediate,
|
|
});
|
|
} else {
|
|
sync();
|
|
}
|
|
return { cloned, isModified, sync };
|
|
}
|
|
var _global =
|
|
typeof globalThis !== 'undefined'
|
|
? globalThis
|
|
: typeof window !== 'undefined'
|
|
? window
|
|
: typeof global !== 'undefined'
|
|
? global
|
|
: typeof self !== 'undefined'
|
|
? self
|
|
: {};
|
|
var globalKey = '__vueuse_ssr_handlers__';
|
|
var handlers = getHandlers();
|
|
function getHandlers() {
|
|
if (!(globalKey in _global)) _global[globalKey] = _global[globalKey] || {};
|
|
return _global[globalKey];
|
|
}
|
|
function getSSRHandler(key, fallback) {
|
|
return handlers[key] || fallback;
|
|
}
|
|
function setSSRHandler(key, fn) {
|
|
handlers[key] = fn;
|
|
}
|
|
function usePreferredDark(options) {
|
|
return useMediaQuery('(prefers-color-scheme: dark)', options);
|
|
}
|
|
function guessSerializerType(rawInit) {
|
|
return rawInit == null
|
|
? 'any'
|
|
: rawInit instanceof Set
|
|
? 'set'
|
|
: rawInit instanceof Map
|
|
? 'map'
|
|
: rawInit instanceof Date
|
|
? 'date'
|
|
: typeof rawInit === 'boolean'
|
|
? 'boolean'
|
|
: typeof rawInit === 'string'
|
|
? 'string'
|
|
: typeof rawInit === 'object'
|
|
? 'object'
|
|
: !Number.isNaN(rawInit)
|
|
? 'number'
|
|
: 'any';
|
|
}
|
|
var StorageSerializers = {
|
|
boolean: {
|
|
read: (v) => v === 'true',
|
|
write: (v) => String(v),
|
|
},
|
|
object: {
|
|
read: (v) => JSON.parse(v),
|
|
write: (v) => JSON.stringify(v),
|
|
},
|
|
number: {
|
|
read: (v) => Number.parseFloat(v),
|
|
write: (v) => String(v),
|
|
},
|
|
any: {
|
|
read: (v) => v,
|
|
write: (v) => String(v),
|
|
},
|
|
string: {
|
|
read: (v) => v,
|
|
write: (v) => String(v),
|
|
},
|
|
map: {
|
|
read: (v) => new Map(JSON.parse(v)),
|
|
write: (v) => JSON.stringify(Array.from(v.entries())),
|
|
},
|
|
set: {
|
|
read: (v) => new Set(JSON.parse(v)),
|
|
write: (v) => JSON.stringify(Array.from(v)),
|
|
},
|
|
date: {
|
|
read: (v) => new Date(v),
|
|
write: (v) => v.toISOString(),
|
|
},
|
|
};
|
|
var customStorageEventName = 'vueuse-storage';
|
|
function useStorage(key, defaults2, storage, options = {}) {
|
|
var _a;
|
|
const {
|
|
flush = 'pre',
|
|
deep = true,
|
|
listenToStorageChanges = true,
|
|
writeDefaults = true,
|
|
mergeDefaults = false,
|
|
shallow,
|
|
window: window2 = defaultWindow,
|
|
eventFilter,
|
|
onError = (e) => {
|
|
console.error(e);
|
|
},
|
|
initOnMounted,
|
|
} = options;
|
|
const data = (shallow ? shallowRef : ref)(
|
|
typeof defaults2 === 'function' ? defaults2() : defaults2
|
|
);
|
|
const keyComputed = computed(() => toValue(key));
|
|
if (!storage) {
|
|
try {
|
|
storage = getSSRHandler('getDefaultStorage', () => {
|
|
var _a2;
|
|
return (_a2 = defaultWindow) == null ? void 0 : _a2.localStorage;
|
|
})();
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
}
|
|
if (!storage) return data;
|
|
const rawInit = toValue(defaults2);
|
|
const type = guessSerializerType(rawInit);
|
|
const serializer =
|
|
(_a = options.serializer) != null ? _a : StorageSerializers[type];
|
|
const { pause: pauseWatch, resume: resumeWatch } = watchPausable(
|
|
data,
|
|
() => write(data.value),
|
|
{ flush, deep, eventFilter }
|
|
);
|
|
watch(keyComputed, () => update(), { flush });
|
|
if (window2 && listenToStorageChanges) {
|
|
tryOnMounted(() => {
|
|
if (storage instanceof Storage)
|
|
useEventListener(window2, 'storage', update, { passive: true });
|
|
else
|
|
useEventListener(
|
|
window2,
|
|
customStorageEventName,
|
|
updateFromCustomEvent
|
|
);
|
|
if (initOnMounted) update();
|
|
});
|
|
}
|
|
if (!initOnMounted) update();
|
|
function dispatchWriteEvent(oldValue, newValue) {
|
|
if (window2) {
|
|
const payload = {
|
|
key: keyComputed.value,
|
|
oldValue,
|
|
newValue,
|
|
storageArea: storage,
|
|
};
|
|
window2.dispatchEvent(
|
|
storage instanceof Storage
|
|
? new StorageEvent('storage', payload)
|
|
: new CustomEvent(customStorageEventName, {
|
|
detail: payload,
|
|
})
|
|
);
|
|
}
|
|
}
|
|
function write(v) {
|
|
try {
|
|
const oldValue = storage.getItem(keyComputed.value);
|
|
if (v == null) {
|
|
dispatchWriteEvent(oldValue, null);
|
|
storage.removeItem(keyComputed.value);
|
|
} else {
|
|
const serialized = serializer.write(v);
|
|
if (oldValue !== serialized) {
|
|
storage.setItem(keyComputed.value, serialized);
|
|
dispatchWriteEvent(oldValue, serialized);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
}
|
|
function read(event) {
|
|
const rawValue = event
|
|
? event.newValue
|
|
: storage.getItem(keyComputed.value);
|
|
if (rawValue == null) {
|
|
if (writeDefaults && rawInit != null)
|
|
storage.setItem(keyComputed.value, serializer.write(rawInit));
|
|
return rawInit;
|
|
} else if (!event && mergeDefaults) {
|
|
const value = serializer.read(rawValue);
|
|
if (typeof mergeDefaults === 'function')
|
|
return mergeDefaults(value, rawInit);
|
|
else if (type === 'object' && !Array.isArray(value))
|
|
return { ...rawInit, ...value };
|
|
return value;
|
|
} else if (typeof rawValue !== 'string') {
|
|
return rawValue;
|
|
} else {
|
|
return serializer.read(rawValue);
|
|
}
|
|
}
|
|
function update(event) {
|
|
if (event && event.storageArea !== storage) return;
|
|
if (event && event.key == null) {
|
|
data.value = rawInit;
|
|
return;
|
|
}
|
|
if (event && event.key !== keyComputed.value) return;
|
|
pauseWatch();
|
|
try {
|
|
if (
|
|
(event == null ? void 0 : event.newValue) !==
|
|
serializer.write(data.value)
|
|
)
|
|
data.value = read(event);
|
|
} catch (e) {
|
|
onError(e);
|
|
} finally {
|
|
if (event) nextTick(resumeWatch);
|
|
else resumeWatch();
|
|
}
|
|
}
|
|
function updateFromCustomEvent(event) {
|
|
update(event.detail);
|
|
}
|
|
return data;
|
|
}
|
|
var CSS_DISABLE_TRANS =
|
|
'*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}';
|
|
function useColorMode(options = {}) {
|
|
const {
|
|
selector = 'html',
|
|
attribute = 'class',
|
|
initialValue = 'auto',
|
|
window: window2 = defaultWindow,
|
|
storage,
|
|
storageKey = 'vueuse-color-scheme',
|
|
listenToStorageChanges = true,
|
|
storageRef,
|
|
emitAuto,
|
|
disableTransition = true,
|
|
} = options;
|
|
const modes = {
|
|
auto: '',
|
|
light: 'light',
|
|
dark: 'dark',
|
|
...(options.modes || {}),
|
|
};
|
|
const preferredDark = usePreferredDark({ window: window2 });
|
|
const system = computed(() => (preferredDark.value ? 'dark' : 'light'));
|
|
const store =
|
|
storageRef ||
|
|
(storageKey == null
|
|
? toRef2(initialValue)
|
|
: useStorage(storageKey, initialValue, storage, {
|
|
window: window2,
|
|
listenToStorageChanges,
|
|
}));
|
|
const state = computed(() =>
|
|
store.value === 'auto' ? system.value : store.value
|
|
);
|
|
const updateHTMLAttrs = getSSRHandler(
|
|
'updateHTMLAttrs',
|
|
(selector2, attribute2, value) => {
|
|
const el =
|
|
typeof selector2 === 'string'
|
|
? window2 == null
|
|
? void 0
|
|
: window2.document.querySelector(selector2)
|
|
: unrefElement(selector2);
|
|
if (!el) return;
|
|
const classesToAdd = /* @__PURE__ */ new Set();
|
|
const classesToRemove = /* @__PURE__ */ new Set();
|
|
let attributeToChange = null;
|
|
if (attribute2 === 'class') {
|
|
const current = value.split(/\s/g);
|
|
Object.values(modes)
|
|
.flatMap((i) => (i || '').split(/\s/g))
|
|
.filter(Boolean)
|
|
.forEach((v) => {
|
|
if (current.includes(v)) classesToAdd.add(v);
|
|
else classesToRemove.add(v);
|
|
});
|
|
} else {
|
|
attributeToChange = { key: attribute2, value };
|
|
}
|
|
if (
|
|
classesToAdd.size === 0 &&
|
|
classesToRemove.size === 0 &&
|
|
attributeToChange === null
|
|
)
|
|
return;
|
|
let style;
|
|
if (disableTransition) {
|
|
style = window2.document.createElement('style');
|
|
style.appendChild(document.createTextNode(CSS_DISABLE_TRANS));
|
|
window2.document.head.appendChild(style);
|
|
}
|
|
for (const c of classesToAdd) {
|
|
el.classList.add(c);
|
|
}
|
|
for (const c of classesToRemove) {
|
|
el.classList.remove(c);
|
|
}
|
|
if (attributeToChange) {
|
|
el.setAttribute(attributeToChange.key, attributeToChange.value);
|
|
}
|
|
if (disableTransition) {
|
|
window2.getComputedStyle(style).opacity;
|
|
document.head.removeChild(style);
|
|
}
|
|
}
|
|
);
|
|
function defaultOnChanged(mode) {
|
|
var _a;
|
|
updateHTMLAttrs(
|
|
selector,
|
|
attribute,
|
|
(_a = modes[mode]) != null ? _a : mode
|
|
);
|
|
}
|
|
function onChanged(mode) {
|
|
if (options.onChanged) options.onChanged(mode, defaultOnChanged);
|
|
else defaultOnChanged(mode);
|
|
}
|
|
watch(state, onChanged, { flush: 'post', immediate: true });
|
|
tryOnMounted(() => onChanged(state.value));
|
|
const auto = computed({
|
|
get() {
|
|
return emitAuto ? store.value : state.value;
|
|
},
|
|
set(v) {
|
|
store.value = v;
|
|
},
|
|
});
|
|
return Object.assign(auto, { store, system, state });
|
|
}
|
|
function useConfirmDialog(revealed = shallowRef(false)) {
|
|
const confirmHook = createEventHook();
|
|
const cancelHook = createEventHook();
|
|
const revealHook = createEventHook();
|
|
let _resolve = noop;
|
|
const reveal = (data) => {
|
|
revealHook.trigger(data);
|
|
revealed.value = true;
|
|
return new Promise((resolve) => {
|
|
_resolve = resolve;
|
|
});
|
|
};
|
|
const confirm = (data) => {
|
|
revealed.value = false;
|
|
confirmHook.trigger(data);
|
|
_resolve({ data, isCanceled: false });
|
|
};
|
|
const cancel = (data) => {
|
|
revealed.value = false;
|
|
cancelHook.trigger(data);
|
|
_resolve({ data, isCanceled: true });
|
|
};
|
|
return {
|
|
isRevealed: computed(() => revealed.value),
|
|
reveal,
|
|
confirm,
|
|
cancel,
|
|
onReveal: revealHook.on,
|
|
onConfirm: confirmHook.on,
|
|
onCancel: cancelHook.on,
|
|
};
|
|
}
|
|
function useCountdown(initialCountdown, options) {
|
|
var _a, _b;
|
|
const remaining = shallowRef(toValue(initialCountdown));
|
|
const intervalController = useIntervalFn(
|
|
() => {
|
|
var _a2, _b2;
|
|
const value = remaining.value - 1;
|
|
remaining.value = value < 0 ? 0 : value;
|
|
(_a2 = options == null ? void 0 : options.onTick) == null
|
|
? void 0
|
|
: _a2.call(options);
|
|
if (remaining.value <= 0) {
|
|
intervalController.pause();
|
|
(_b2 = options == null ? void 0 : options.onComplete) == null
|
|
? void 0
|
|
: _b2.call(options);
|
|
}
|
|
},
|
|
(_a = options == null ? void 0 : options.interval) != null ? _a : 1e3,
|
|
{
|
|
immediate:
|
|
(_b = options == null ? void 0 : options.immediate) != null
|
|
? _b
|
|
: false,
|
|
}
|
|
);
|
|
const reset = (countdown) => {
|
|
var _a2;
|
|
remaining.value =
|
|
(_a2 = toValue(countdown)) != null ? _a2 : toValue(initialCountdown);
|
|
};
|
|
const stop = () => {
|
|
intervalController.pause();
|
|
reset();
|
|
};
|
|
const resume = () => {
|
|
if (!intervalController.isActive.value) {
|
|
if (remaining.value > 0) {
|
|
intervalController.resume();
|
|
}
|
|
}
|
|
};
|
|
const start = (countdown) => {
|
|
reset(countdown);
|
|
intervalController.resume();
|
|
};
|
|
return {
|
|
remaining,
|
|
reset,
|
|
stop,
|
|
start,
|
|
pause: intervalController.pause,
|
|
resume,
|
|
isActive: intervalController.isActive,
|
|
};
|
|
}
|
|
function useCssVar(prop, target, options = {}) {
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
initialValue,
|
|
observe = false,
|
|
} = options;
|
|
const variable = shallowRef(initialValue);
|
|
const elRef = computed(() => {
|
|
var _a;
|
|
return (
|
|
unrefElement(target) ||
|
|
((_a = window2 == null ? void 0 : window2.document) == null
|
|
? void 0
|
|
: _a.documentElement)
|
|
);
|
|
});
|
|
function updateCssVar() {
|
|
var _a;
|
|
const key = toValue(prop);
|
|
const el = toValue(elRef);
|
|
if (el && window2 && key) {
|
|
const value =
|
|
(_a = window2.getComputedStyle(el).getPropertyValue(key)) == null
|
|
? void 0
|
|
: _a.trim();
|
|
variable.value = value || variable.value || initialValue;
|
|
}
|
|
}
|
|
if (observe) {
|
|
useMutationObserver(elRef, updateCssVar, {
|
|
attributeFilter: ['style', 'class'],
|
|
window: window2,
|
|
});
|
|
}
|
|
watch(
|
|
[elRef, () => toValue(prop)],
|
|
(_, old) => {
|
|
if (old[0] && old[1]) old[0].style.removeProperty(old[1]);
|
|
updateCssVar();
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
watch(
|
|
[variable, elRef],
|
|
([val, el]) => {
|
|
const raw_prop = toValue(prop);
|
|
if ((el == null ? void 0 : el.style) && raw_prop) {
|
|
if (val == null) el.style.removeProperty(raw_prop);
|
|
else el.style.setProperty(raw_prop, val);
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
return variable;
|
|
}
|
|
function useCurrentElement(rootComponent) {
|
|
const vm = getCurrentInstance();
|
|
const currentElement = computedWithControl(
|
|
() => null,
|
|
() => (rootComponent ? unrefElement(rootComponent) : vm.proxy.$el)
|
|
);
|
|
onUpdated(currentElement.trigger);
|
|
onMounted(currentElement.trigger);
|
|
return currentElement;
|
|
}
|
|
function useCycleList(list, options) {
|
|
const state = shallowRef(getInitialValue());
|
|
const listRef = toRef2(list);
|
|
const index = computed({
|
|
get() {
|
|
var _a;
|
|
const targetList = listRef.value;
|
|
let index2 = (options == null ? void 0 : options.getIndexOf)
|
|
? options.getIndexOf(state.value, targetList)
|
|
: targetList.indexOf(state.value);
|
|
if (index2 < 0)
|
|
index2 =
|
|
(_a = options == null ? void 0 : options.fallbackIndex) != null
|
|
? _a
|
|
: 0;
|
|
return index2;
|
|
},
|
|
set(v) {
|
|
set2(v);
|
|
},
|
|
});
|
|
function set2(i) {
|
|
const targetList = listRef.value;
|
|
const length = targetList.length;
|
|
const index2 = ((i % length) + length) % length;
|
|
const value = targetList[index2];
|
|
state.value = value;
|
|
return value;
|
|
}
|
|
function shift(delta = 1) {
|
|
return set2(index.value + delta);
|
|
}
|
|
function next(n = 1) {
|
|
return shift(n);
|
|
}
|
|
function prev(n = 1) {
|
|
return shift(-n);
|
|
}
|
|
function getInitialValue() {
|
|
var _a, _b;
|
|
return (_b = toValue(
|
|
(_a = options == null ? void 0 : options.initialValue) != null
|
|
? _a
|
|
: toValue(list)[0]
|
|
)) != null
|
|
? _b
|
|
: void 0;
|
|
}
|
|
watch(listRef, () => set2(index.value));
|
|
return {
|
|
state,
|
|
index,
|
|
next,
|
|
prev,
|
|
go: set2,
|
|
};
|
|
}
|
|
function useDark(options = {}) {
|
|
const { valueDark = 'dark', valueLight = '' } = options;
|
|
const mode = useColorMode({
|
|
...options,
|
|
onChanged: (mode2, defaultHandler) => {
|
|
var _a;
|
|
if (options.onChanged)
|
|
(_a = options.onChanged) == null
|
|
? void 0
|
|
: _a.call(options, mode2 === 'dark', defaultHandler, mode2);
|
|
else defaultHandler(mode2);
|
|
},
|
|
modes: {
|
|
dark: valueDark,
|
|
light: valueLight,
|
|
},
|
|
});
|
|
const system = computed(() => mode.system.value);
|
|
const isDark = computed({
|
|
get() {
|
|
return mode.value === 'dark';
|
|
},
|
|
set(v) {
|
|
const modeVal = v ? 'dark' : 'light';
|
|
if (system.value === modeVal) mode.value = 'auto';
|
|
else mode.value = modeVal;
|
|
},
|
|
});
|
|
return isDark;
|
|
}
|
|
function fnBypass(v) {
|
|
return v;
|
|
}
|
|
function fnSetSource(source, value) {
|
|
return (source.value = value);
|
|
}
|
|
function defaultDump(clone) {
|
|
return clone ? (typeof clone === 'function' ? clone : cloneFnJSON) : fnBypass;
|
|
}
|
|
function defaultParse(clone) {
|
|
return clone ? (typeof clone === 'function' ? clone : cloneFnJSON) : fnBypass;
|
|
}
|
|
function useManualRefHistory(source, options = {}) {
|
|
const {
|
|
clone = false,
|
|
dump = defaultDump(clone),
|
|
parse = defaultParse(clone),
|
|
setSource = fnSetSource,
|
|
} = options;
|
|
function _createHistoryRecord() {
|
|
return markRaw({
|
|
snapshot: dump(source.value),
|
|
timestamp: timestamp(),
|
|
});
|
|
}
|
|
const last = ref(_createHistoryRecord());
|
|
const undoStack = ref([]);
|
|
const redoStack = ref([]);
|
|
const _setSource = (record) => {
|
|
setSource(source, parse(record.snapshot));
|
|
last.value = record;
|
|
};
|
|
const commit = () => {
|
|
undoStack.value.unshift(last.value);
|
|
last.value = _createHistoryRecord();
|
|
if (options.capacity && undoStack.value.length > options.capacity)
|
|
undoStack.value.splice(options.capacity, Number.POSITIVE_INFINITY);
|
|
if (redoStack.value.length)
|
|
redoStack.value.splice(0, redoStack.value.length);
|
|
};
|
|
const clear = () => {
|
|
undoStack.value.splice(0, undoStack.value.length);
|
|
redoStack.value.splice(0, redoStack.value.length);
|
|
};
|
|
const undo = () => {
|
|
const state = undoStack.value.shift();
|
|
if (state) {
|
|
redoStack.value.unshift(last.value);
|
|
_setSource(state);
|
|
}
|
|
};
|
|
const redo = () => {
|
|
const state = redoStack.value.shift();
|
|
if (state) {
|
|
undoStack.value.unshift(last.value);
|
|
_setSource(state);
|
|
}
|
|
};
|
|
const reset = () => {
|
|
_setSource(last.value);
|
|
};
|
|
const history = computed(() => [last.value, ...undoStack.value]);
|
|
const canUndo = computed(() => undoStack.value.length > 0);
|
|
const canRedo = computed(() => redoStack.value.length > 0);
|
|
return {
|
|
source,
|
|
undoStack,
|
|
redoStack,
|
|
last,
|
|
history,
|
|
canUndo,
|
|
canRedo,
|
|
clear,
|
|
commit,
|
|
reset,
|
|
undo,
|
|
redo,
|
|
};
|
|
}
|
|
function useRefHistory(source, options = {}) {
|
|
const { deep = false, flush = 'pre', eventFilter } = options;
|
|
const {
|
|
eventFilter: composedFilter,
|
|
pause,
|
|
resume: resumeTracking,
|
|
isActive: isTracking,
|
|
} = pausableFilter(eventFilter);
|
|
const { ignoreUpdates, ignorePrevAsyncUpdates, stop } = watchIgnorable(
|
|
source,
|
|
commit,
|
|
{ deep, flush, eventFilter: composedFilter }
|
|
);
|
|
function setSource(source2, value) {
|
|
ignorePrevAsyncUpdates();
|
|
ignoreUpdates(() => {
|
|
source2.value = value;
|
|
});
|
|
}
|
|
const manualHistory = useManualRefHistory(source, {
|
|
...options,
|
|
clone: options.clone || deep,
|
|
setSource,
|
|
});
|
|
const { clear, commit: manualCommit } = manualHistory;
|
|
function commit() {
|
|
ignorePrevAsyncUpdates();
|
|
manualCommit();
|
|
}
|
|
function resume(commitNow) {
|
|
resumeTracking();
|
|
if (commitNow) commit();
|
|
}
|
|
function batch(fn) {
|
|
let canceled = false;
|
|
const cancel = () => (canceled = true);
|
|
ignoreUpdates(() => {
|
|
fn(cancel);
|
|
});
|
|
if (!canceled) commit();
|
|
}
|
|
function dispose() {
|
|
stop();
|
|
clear();
|
|
}
|
|
return {
|
|
...manualHistory,
|
|
isTracking,
|
|
pause,
|
|
resume,
|
|
commit,
|
|
batch,
|
|
dispose,
|
|
};
|
|
}
|
|
function useDebouncedRefHistory(source, options = {}) {
|
|
const filter = options.debounce ? debounceFilter(options.debounce) : void 0;
|
|
const history = useRefHistory(source, { ...options, eventFilter: filter });
|
|
return {
|
|
...history,
|
|
};
|
|
}
|
|
function useDeviceMotion(options = {}) {
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
requestPermissions = false,
|
|
eventFilter = bypassFilter,
|
|
} = options;
|
|
const isSupported = useSupported(
|
|
() => typeof DeviceMotionEvent !== 'undefined'
|
|
);
|
|
const requirePermissions = useSupported(
|
|
() =>
|
|
isSupported.value &&
|
|
'requestPermission' in DeviceMotionEvent &&
|
|
typeof DeviceMotionEvent.requestPermission === 'function'
|
|
);
|
|
const permissionGranted = shallowRef(false);
|
|
const acceleration = ref({ x: null, y: null, z: null });
|
|
const rotationRate = ref({ alpha: null, beta: null, gamma: null });
|
|
const interval = shallowRef(0);
|
|
const accelerationIncludingGravity = ref({
|
|
x: null,
|
|
y: null,
|
|
z: null,
|
|
});
|
|
function init() {
|
|
if (window2) {
|
|
const onDeviceMotion = createFilterWrapper(eventFilter, (event) => {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
acceleration.value = {
|
|
x: ((_a = event.acceleration) == null ? void 0 : _a.x) || null,
|
|
y: ((_b = event.acceleration) == null ? void 0 : _b.y) || null,
|
|
z: ((_c = event.acceleration) == null ? void 0 : _c.z) || null,
|
|
};
|
|
accelerationIncludingGravity.value = {
|
|
x:
|
|
((_d = event.accelerationIncludingGravity) == null
|
|
? void 0
|
|
: _d.x) || null,
|
|
y:
|
|
((_e = event.accelerationIncludingGravity) == null
|
|
? void 0
|
|
: _e.y) || null,
|
|
z:
|
|
((_f = event.accelerationIncludingGravity) == null
|
|
? void 0
|
|
: _f.z) || null,
|
|
};
|
|
rotationRate.value = {
|
|
alpha:
|
|
((_g = event.rotationRate) == null ? void 0 : _g.alpha) || null,
|
|
beta: ((_h = event.rotationRate) == null ? void 0 : _h.beta) || null,
|
|
gamma:
|
|
((_i = event.rotationRate) == null ? void 0 : _i.gamma) || null,
|
|
};
|
|
interval.value = event.interval;
|
|
});
|
|
useEventListener(window2, 'devicemotion', onDeviceMotion, {
|
|
passive: true,
|
|
});
|
|
}
|
|
}
|
|
const ensurePermissions = async () => {
|
|
if (!requirePermissions.value) permissionGranted.value = true;
|
|
if (permissionGranted.value) return;
|
|
if (requirePermissions.value) {
|
|
const requestPermission = DeviceMotionEvent.requestPermission;
|
|
try {
|
|
const response = await requestPermission();
|
|
if (response === 'granted') {
|
|
permissionGranted.value = true;
|
|
init();
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
};
|
|
if (isSupported.value) {
|
|
if (requestPermissions && requirePermissions.value) {
|
|
ensurePermissions().then(() => init());
|
|
} else {
|
|
init();
|
|
}
|
|
}
|
|
return {
|
|
acceleration,
|
|
accelerationIncludingGravity,
|
|
rotationRate,
|
|
interval,
|
|
isSupported,
|
|
requirePermissions,
|
|
ensurePermissions,
|
|
permissionGranted,
|
|
};
|
|
}
|
|
function useDeviceOrientation(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const isSupported = useSupported(
|
|
() => window2 && 'DeviceOrientationEvent' in window2
|
|
);
|
|
const isAbsolute = shallowRef(false);
|
|
const alpha = shallowRef(null);
|
|
const beta = shallowRef(null);
|
|
const gamma = shallowRef(null);
|
|
if (window2 && isSupported.value) {
|
|
useEventListener(
|
|
window2,
|
|
'deviceorientation',
|
|
(event) => {
|
|
isAbsolute.value = event.absolute;
|
|
alpha.value = event.alpha;
|
|
beta.value = event.beta;
|
|
gamma.value = event.gamma;
|
|
},
|
|
{ passive: true }
|
|
);
|
|
}
|
|
return {
|
|
isSupported,
|
|
isAbsolute,
|
|
alpha,
|
|
beta,
|
|
gamma,
|
|
};
|
|
}
|
|
function useDevicePixelRatio(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const pixelRatio = shallowRef(1);
|
|
const query = useMediaQuery(
|
|
() => `(resolution: ${pixelRatio.value}dppx)`,
|
|
options
|
|
);
|
|
let stop = noop;
|
|
if (window2) {
|
|
stop = watchImmediate(
|
|
query,
|
|
() => (pixelRatio.value = window2.devicePixelRatio)
|
|
);
|
|
}
|
|
return {
|
|
pixelRatio: readonly(pixelRatio),
|
|
stop,
|
|
};
|
|
}
|
|
function useDevicesList(options = {}) {
|
|
const {
|
|
navigator: navigator2 = defaultNavigator,
|
|
requestPermissions = false,
|
|
constraints = { audio: true, video: true },
|
|
onUpdated: onUpdated2,
|
|
} = options;
|
|
const devices = ref([]);
|
|
const videoInputs = computed(() =>
|
|
devices.value.filter((i) => i.kind === 'videoinput')
|
|
);
|
|
const audioInputs = computed(() =>
|
|
devices.value.filter((i) => i.kind === 'audioinput')
|
|
);
|
|
const audioOutputs = computed(() =>
|
|
devices.value.filter((i) => i.kind === 'audiooutput')
|
|
);
|
|
const isSupported = useSupported(
|
|
() =>
|
|
navigator2 &&
|
|
navigator2.mediaDevices &&
|
|
navigator2.mediaDevices.enumerateDevices
|
|
);
|
|
const permissionGranted = shallowRef(false);
|
|
let stream;
|
|
async function update() {
|
|
if (!isSupported.value) return;
|
|
devices.value = await navigator2.mediaDevices.enumerateDevices();
|
|
onUpdated2 == null ? void 0 : onUpdated2(devices.value);
|
|
if (stream) {
|
|
stream.getTracks().forEach((t) => t.stop());
|
|
stream = null;
|
|
}
|
|
}
|
|
async function ensurePermissions() {
|
|
const deviceName = constraints.video ? 'camera' : 'microphone';
|
|
if (!isSupported.value) return false;
|
|
if (permissionGranted.value) return true;
|
|
const { state, query } = usePermission(deviceName, { controls: true });
|
|
await query();
|
|
if (state.value !== 'granted') {
|
|
let granted = true;
|
|
try {
|
|
stream = await navigator2.mediaDevices.getUserMedia(constraints);
|
|
} catch (e) {
|
|
stream = null;
|
|
granted = false;
|
|
}
|
|
update();
|
|
permissionGranted.value = granted;
|
|
} else {
|
|
permissionGranted.value = true;
|
|
}
|
|
return permissionGranted.value;
|
|
}
|
|
if (isSupported.value) {
|
|
if (requestPermissions) ensurePermissions();
|
|
useEventListener(navigator2.mediaDevices, 'devicechange', update, {
|
|
passive: true,
|
|
});
|
|
update();
|
|
}
|
|
return {
|
|
devices,
|
|
ensurePermissions,
|
|
permissionGranted,
|
|
videoInputs,
|
|
audioInputs,
|
|
audioOutputs,
|
|
isSupported,
|
|
};
|
|
}
|
|
function useDisplayMedia(options = {}) {
|
|
var _a;
|
|
const enabled = shallowRef((_a = options.enabled) != null ? _a : false);
|
|
const video = options.video;
|
|
const audio = options.audio;
|
|
const { navigator: navigator2 = defaultNavigator } = options;
|
|
const isSupported = useSupported(() => {
|
|
var _a2;
|
|
return (_a2 = navigator2 == null ? void 0 : navigator2.mediaDevices) == null
|
|
? void 0
|
|
: _a2.getDisplayMedia;
|
|
});
|
|
const constraint = { audio, video };
|
|
const stream = shallowRef();
|
|
async function _start() {
|
|
var _a2;
|
|
if (!isSupported.value || stream.value) return;
|
|
stream.value = await navigator2.mediaDevices.getDisplayMedia(constraint);
|
|
(_a2 = stream.value) == null
|
|
? void 0
|
|
: _a2
|
|
.getTracks()
|
|
.forEach((t) =>
|
|
useEventListener(t, 'ended', stop, { passive: true })
|
|
);
|
|
return stream.value;
|
|
}
|
|
async function _stop() {
|
|
var _a2;
|
|
(_a2 = stream.value) == null
|
|
? void 0
|
|
: _a2.getTracks().forEach((t) => t.stop());
|
|
stream.value = void 0;
|
|
}
|
|
function stop() {
|
|
_stop();
|
|
enabled.value = false;
|
|
}
|
|
async function start() {
|
|
await _start();
|
|
if (stream.value) enabled.value = true;
|
|
return stream.value;
|
|
}
|
|
watch(
|
|
enabled,
|
|
(v) => {
|
|
if (v) _start();
|
|
else _stop();
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
return {
|
|
isSupported,
|
|
stream,
|
|
start,
|
|
stop,
|
|
enabled,
|
|
};
|
|
}
|
|
function useDocumentVisibility(options = {}) {
|
|
const { document: document2 = defaultDocument } = options;
|
|
if (!document2) return shallowRef('visible');
|
|
const visibility = shallowRef(document2.visibilityState);
|
|
useEventListener(
|
|
document2,
|
|
'visibilitychange',
|
|
() => {
|
|
visibility.value = document2.visibilityState;
|
|
},
|
|
{ passive: true }
|
|
);
|
|
return visibility;
|
|
}
|
|
function useDraggable(target, options = {}) {
|
|
var _a;
|
|
const {
|
|
pointerTypes,
|
|
preventDefault: preventDefault2,
|
|
stopPropagation,
|
|
exact,
|
|
onMove,
|
|
onEnd,
|
|
onStart,
|
|
initialValue,
|
|
axis = 'both',
|
|
draggingElement = defaultWindow,
|
|
containerElement,
|
|
handle: draggingHandle = target,
|
|
buttons = [0],
|
|
} = options;
|
|
const position = ref(
|
|
(_a = toValue(initialValue)) != null ? _a : { x: 0, y: 0 }
|
|
);
|
|
const pressedDelta = ref();
|
|
const filterEvent = (e) => {
|
|
if (pointerTypes) return pointerTypes.includes(e.pointerType);
|
|
return true;
|
|
};
|
|
const handleEvent = (e) => {
|
|
if (toValue(preventDefault2)) e.preventDefault();
|
|
if (toValue(stopPropagation)) e.stopPropagation();
|
|
};
|
|
const start = (e) => {
|
|
var _a2;
|
|
if (!toValue(buttons).includes(e.button)) return;
|
|
if (toValue(options.disabled) || !filterEvent(e)) return;
|
|
if (toValue(exact) && e.target !== toValue(target)) return;
|
|
const container = toValue(containerElement);
|
|
const containerRect =
|
|
(_a2 = container == null ? void 0 : container.getBoundingClientRect) ==
|
|
null
|
|
? void 0
|
|
: _a2.call(container);
|
|
const targetRect = toValue(target).getBoundingClientRect();
|
|
const pos = {
|
|
x:
|
|
e.clientX -
|
|
(container
|
|
? targetRect.left - containerRect.left + container.scrollLeft
|
|
: targetRect.left),
|
|
y:
|
|
e.clientY -
|
|
(container
|
|
? targetRect.top - containerRect.top + container.scrollTop
|
|
: targetRect.top),
|
|
};
|
|
if ((onStart == null ? void 0 : onStart(pos, e)) === false) return;
|
|
pressedDelta.value = pos;
|
|
handleEvent(e);
|
|
};
|
|
const move = (e) => {
|
|
if (toValue(options.disabled) || !filterEvent(e)) return;
|
|
if (!pressedDelta.value) return;
|
|
const container = toValue(containerElement);
|
|
const targetRect = toValue(target).getBoundingClientRect();
|
|
let { x, y } = position.value;
|
|
if (axis === 'x' || axis === 'both') {
|
|
x = e.clientX - pressedDelta.value.x;
|
|
if (container)
|
|
x = Math.min(Math.max(0, x), container.scrollWidth - targetRect.width);
|
|
}
|
|
if (axis === 'y' || axis === 'both') {
|
|
y = e.clientY - pressedDelta.value.y;
|
|
if (container)
|
|
y = Math.min(
|
|
Math.max(0, y),
|
|
container.scrollHeight - targetRect.height
|
|
);
|
|
}
|
|
position.value = {
|
|
x,
|
|
y,
|
|
};
|
|
onMove == null ? void 0 : onMove(position.value, e);
|
|
handleEvent(e);
|
|
};
|
|
const end = (e) => {
|
|
if (toValue(options.disabled) || !filterEvent(e)) return;
|
|
if (!pressedDelta.value) return;
|
|
pressedDelta.value = void 0;
|
|
onEnd == null ? void 0 : onEnd(position.value, e);
|
|
handleEvent(e);
|
|
};
|
|
if (isClient) {
|
|
const config = () => {
|
|
var _a2;
|
|
return {
|
|
capture: (_a2 = options.capture) != null ? _a2 : true,
|
|
passive: !toValue(preventDefault2),
|
|
};
|
|
};
|
|
useEventListener(draggingHandle, 'pointerdown', start, config);
|
|
useEventListener(draggingElement, 'pointermove', move, config);
|
|
useEventListener(draggingElement, 'pointerup', end, config);
|
|
}
|
|
return {
|
|
...toRefs2(position),
|
|
position,
|
|
isDragging: computed(() => !!pressedDelta.value),
|
|
style: computed(
|
|
() => `left:${position.value.x}px;top:${position.value.y}px;`
|
|
),
|
|
};
|
|
}
|
|
function useDropZone(target, options = {}) {
|
|
var _a, _b;
|
|
const isOverDropZone = shallowRef(false);
|
|
const files = shallowRef(null);
|
|
let counter = 0;
|
|
let isValid = true;
|
|
if (isClient) {
|
|
const _options =
|
|
typeof options === 'function' ? { onDrop: options } : options;
|
|
const multiple = (_a = _options.multiple) != null ? _a : true;
|
|
const preventDefaultForUnhandled =
|
|
(_b = _options.preventDefaultForUnhandled) != null ? _b : false;
|
|
const getFiles = (event) => {
|
|
var _a2, _b2;
|
|
const list = Array.from(
|
|
(_b2 = (_a2 = event.dataTransfer) == null ? void 0 : _a2.files) != null
|
|
? _b2
|
|
: []
|
|
);
|
|
return list.length === 0 ? null : multiple ? list : [list[0]];
|
|
};
|
|
const checkDataTypes = (types) => {
|
|
const dataTypes = unref(_options.dataTypes);
|
|
if (typeof dataTypes === 'function') return dataTypes(types);
|
|
if (!(dataTypes == null ? void 0 : dataTypes.length)) return true;
|
|
if (types.length === 0) return false;
|
|
return types.every((type) =>
|
|
dataTypes.some((allowedType) => type.includes(allowedType))
|
|
);
|
|
};
|
|
const checkValidity = (items) => {
|
|
const types = Array.from(items != null ? items : []).map(
|
|
(item) => item.type
|
|
);
|
|
const dataTypesValid = checkDataTypes(types);
|
|
const multipleFilesValid = multiple || items.length <= 1;
|
|
return dataTypesValid && multipleFilesValid;
|
|
};
|
|
const isSafari = () =>
|
|
/^(?:(?!chrome|android).)*safari/i.test(navigator.userAgent) &&
|
|
!('chrome' in window);
|
|
const handleDragEvent = (event, eventType) => {
|
|
var _a2, _b2, _c, _d, _e, _f;
|
|
const dataTransferItemList =
|
|
(_a2 = event.dataTransfer) == null ? void 0 : _a2.items;
|
|
isValid =
|
|
(_b2 = dataTransferItemList && checkValidity(dataTransferItemList)) !=
|
|
null
|
|
? _b2
|
|
: false;
|
|
if (preventDefaultForUnhandled) {
|
|
event.preventDefault();
|
|
}
|
|
if (!isSafari() && !isValid) {
|
|
if (event.dataTransfer) {
|
|
event.dataTransfer.dropEffect = 'none';
|
|
}
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
if (event.dataTransfer) {
|
|
event.dataTransfer.dropEffect = 'copy';
|
|
}
|
|
const currentFiles = getFiles(event);
|
|
switch (eventType) {
|
|
case 'enter':
|
|
counter += 1;
|
|
isOverDropZone.value = true;
|
|
(_c = _options.onEnter) == null
|
|
? void 0
|
|
: _c.call(_options, null, event);
|
|
break;
|
|
case 'over':
|
|
(_d = _options.onOver) == null
|
|
? void 0
|
|
: _d.call(_options, null, event);
|
|
break;
|
|
case 'leave':
|
|
counter -= 1;
|
|
if (counter === 0) isOverDropZone.value = false;
|
|
(_e = _options.onLeave) == null
|
|
? void 0
|
|
: _e.call(_options, null, event);
|
|
break;
|
|
case 'drop':
|
|
counter = 0;
|
|
isOverDropZone.value = false;
|
|
if (isValid) {
|
|
files.value = currentFiles;
|
|
(_f = _options.onDrop) == null
|
|
? void 0
|
|
: _f.call(_options, currentFiles, event);
|
|
}
|
|
break;
|
|
}
|
|
};
|
|
useEventListener(target, 'dragenter', (event) =>
|
|
handleDragEvent(event, 'enter')
|
|
);
|
|
useEventListener(target, 'dragover', (event) =>
|
|
handleDragEvent(event, 'over')
|
|
);
|
|
useEventListener(target, 'dragleave', (event) =>
|
|
handleDragEvent(event, 'leave')
|
|
);
|
|
useEventListener(target, 'drop', (event) => handleDragEvent(event, 'drop'));
|
|
}
|
|
return {
|
|
files,
|
|
isOverDropZone,
|
|
};
|
|
}
|
|
function useResizeObserver(target, callback, options = {}) {
|
|
const { window: window2 = defaultWindow, ...observerOptions } = options;
|
|
let observer;
|
|
const isSupported = useSupported(
|
|
() => window2 && 'ResizeObserver' in window2
|
|
);
|
|
const cleanup = () => {
|
|
if (observer) {
|
|
observer.disconnect();
|
|
observer = void 0;
|
|
}
|
|
};
|
|
const targets = computed(() => {
|
|
const _targets = toValue(target);
|
|
return Array.isArray(_targets)
|
|
? _targets.map((el) => unrefElement(el))
|
|
: [unrefElement(_targets)];
|
|
});
|
|
const stopWatch = watch(
|
|
targets,
|
|
(els) => {
|
|
cleanup();
|
|
if (isSupported.value && window2) {
|
|
observer = new ResizeObserver(callback);
|
|
for (const _el of els) {
|
|
if (_el) observer.observe(_el, observerOptions);
|
|
}
|
|
}
|
|
},
|
|
{ immediate: true, flush: 'post' }
|
|
);
|
|
const stop = () => {
|
|
cleanup();
|
|
stopWatch();
|
|
};
|
|
tryOnScopeDispose(stop);
|
|
return {
|
|
isSupported,
|
|
stop,
|
|
};
|
|
}
|
|
function useElementBounding(target, options = {}) {
|
|
const {
|
|
reset = true,
|
|
windowResize = true,
|
|
windowScroll = true,
|
|
immediate = true,
|
|
updateTiming = 'sync',
|
|
} = options;
|
|
const height = shallowRef(0);
|
|
const bottom = shallowRef(0);
|
|
const left = shallowRef(0);
|
|
const right = shallowRef(0);
|
|
const top = shallowRef(0);
|
|
const width = shallowRef(0);
|
|
const x = shallowRef(0);
|
|
const y = shallowRef(0);
|
|
function recalculate() {
|
|
const el = unrefElement(target);
|
|
if (!el) {
|
|
if (reset) {
|
|
height.value = 0;
|
|
bottom.value = 0;
|
|
left.value = 0;
|
|
right.value = 0;
|
|
top.value = 0;
|
|
width.value = 0;
|
|
x.value = 0;
|
|
y.value = 0;
|
|
}
|
|
return;
|
|
}
|
|
const rect = el.getBoundingClientRect();
|
|
height.value = rect.height;
|
|
bottom.value = rect.bottom;
|
|
left.value = rect.left;
|
|
right.value = rect.right;
|
|
top.value = rect.top;
|
|
width.value = rect.width;
|
|
x.value = rect.x;
|
|
y.value = rect.y;
|
|
}
|
|
function update() {
|
|
if (updateTiming === 'sync') recalculate();
|
|
else if (updateTiming === 'next-frame')
|
|
requestAnimationFrame(() => recalculate());
|
|
}
|
|
useResizeObserver(target, update);
|
|
watch(
|
|
() => unrefElement(target),
|
|
(ele) => !ele && update()
|
|
);
|
|
useMutationObserver(target, update, {
|
|
attributeFilter: ['style', 'class'],
|
|
});
|
|
if (windowScroll)
|
|
useEventListener('scroll', update, { capture: true, passive: true });
|
|
if (windowResize) useEventListener('resize', update, { passive: true });
|
|
tryOnMounted(() => {
|
|
if (immediate) update();
|
|
});
|
|
return {
|
|
height,
|
|
bottom,
|
|
left,
|
|
right,
|
|
top,
|
|
width,
|
|
x,
|
|
y,
|
|
update,
|
|
};
|
|
}
|
|
function useElementByPoint(options) {
|
|
const {
|
|
x,
|
|
y,
|
|
document: document2 = defaultDocument,
|
|
multiple,
|
|
interval = 'requestAnimationFrame',
|
|
immediate = true,
|
|
} = options;
|
|
const isSupported = useSupported(() => {
|
|
if (toValue(multiple)) return document2 && 'elementsFromPoint' in document2;
|
|
return document2 && 'elementFromPoint' in document2;
|
|
});
|
|
const element = shallowRef(null);
|
|
const cb = () => {
|
|
var _a, _b;
|
|
element.value = toValue(multiple)
|
|
? (_a =
|
|
document2 == null
|
|
? void 0
|
|
: document2.elementsFromPoint(toValue(x), toValue(y))) != null
|
|
? _a
|
|
: []
|
|
: (_b =
|
|
document2 == null
|
|
? void 0
|
|
: document2.elementFromPoint(toValue(x), toValue(y))) != null
|
|
? _b
|
|
: null;
|
|
};
|
|
const controls =
|
|
interval === 'requestAnimationFrame'
|
|
? useRafFn(cb, { immediate })
|
|
: useIntervalFn(cb, interval, { immediate });
|
|
return {
|
|
isSupported,
|
|
element,
|
|
...controls,
|
|
};
|
|
}
|
|
function useElementHover(el, options = {}) {
|
|
const {
|
|
delayEnter = 0,
|
|
delayLeave = 0,
|
|
triggerOnRemoval = false,
|
|
window: window2 = defaultWindow,
|
|
} = options;
|
|
const isHovered = shallowRef(false);
|
|
let timer;
|
|
const toggle = (entering) => {
|
|
const delay = entering ? delayEnter : delayLeave;
|
|
if (timer) {
|
|
clearTimeout(timer);
|
|
timer = void 0;
|
|
}
|
|
if (delay) timer = setTimeout(() => (isHovered.value = entering), delay);
|
|
else isHovered.value = entering;
|
|
};
|
|
if (!window2) return isHovered;
|
|
useEventListener(el, 'mouseenter', () => toggle(true), { passive: true });
|
|
useEventListener(el, 'mouseleave', () => toggle(false), { passive: true });
|
|
if (triggerOnRemoval) {
|
|
onElementRemoval(
|
|
computed(() => unrefElement(el)),
|
|
() => toggle(false)
|
|
);
|
|
}
|
|
return isHovered;
|
|
}
|
|
function useElementSize(
|
|
target,
|
|
initialSize = { width: 0, height: 0 },
|
|
options = {}
|
|
) {
|
|
const { window: window2 = defaultWindow, box = 'content-box' } = options;
|
|
const isSVG = computed(() => {
|
|
var _a, _b;
|
|
return (_b =
|
|
(_a = unrefElement(target)) == null ? void 0 : _a.namespaceURI) == null
|
|
? void 0
|
|
: _b.includes('svg');
|
|
});
|
|
const width = shallowRef(initialSize.width);
|
|
const height = shallowRef(initialSize.height);
|
|
const { stop: stop1 } = useResizeObserver(
|
|
target,
|
|
([entry]) => {
|
|
const boxSize =
|
|
box === 'border-box'
|
|
? entry.borderBoxSize
|
|
: box === 'content-box'
|
|
? entry.contentBoxSize
|
|
: entry.devicePixelContentBoxSize;
|
|
if (window2 && isSVG.value) {
|
|
const $elem = unrefElement(target);
|
|
if ($elem) {
|
|
const rect = $elem.getBoundingClientRect();
|
|
width.value = rect.width;
|
|
height.value = rect.height;
|
|
}
|
|
} else {
|
|
if (boxSize) {
|
|
const formatBoxSize = toArray(boxSize);
|
|
width.value = formatBoxSize.reduce(
|
|
(acc, { inlineSize }) => acc + inlineSize,
|
|
0
|
|
);
|
|
height.value = formatBoxSize.reduce(
|
|
(acc, { blockSize }) => acc + blockSize,
|
|
0
|
|
);
|
|
} else {
|
|
width.value = entry.contentRect.width;
|
|
height.value = entry.contentRect.height;
|
|
}
|
|
}
|
|
},
|
|
options
|
|
);
|
|
tryOnMounted(() => {
|
|
const ele = unrefElement(target);
|
|
if (ele) {
|
|
width.value = 'offsetWidth' in ele ? ele.offsetWidth : initialSize.width;
|
|
height.value =
|
|
'offsetHeight' in ele ? ele.offsetHeight : initialSize.height;
|
|
}
|
|
});
|
|
const stop2 = watch(
|
|
() => unrefElement(target),
|
|
(ele) => {
|
|
width.value = ele ? initialSize.width : 0;
|
|
height.value = ele ? initialSize.height : 0;
|
|
}
|
|
);
|
|
function stop() {
|
|
stop1();
|
|
stop2();
|
|
}
|
|
return {
|
|
width,
|
|
height,
|
|
stop,
|
|
};
|
|
}
|
|
function useIntersectionObserver(target, callback, options = {}) {
|
|
const {
|
|
root,
|
|
rootMargin = '0px',
|
|
threshold = 0,
|
|
window: window2 = defaultWindow,
|
|
immediate = true,
|
|
} = options;
|
|
const isSupported = useSupported(
|
|
() => window2 && 'IntersectionObserver' in window2
|
|
);
|
|
const targets = computed(() => {
|
|
const _target = toValue(target);
|
|
return toArray(_target).map(unrefElement).filter(notNullish);
|
|
});
|
|
let cleanup = noop;
|
|
const isActive = shallowRef(immediate);
|
|
const stopWatch = isSupported.value
|
|
? watch(
|
|
() => [targets.value, unrefElement(root), isActive.value],
|
|
([targets2, root2]) => {
|
|
cleanup();
|
|
if (!isActive.value) return;
|
|
if (!targets2.length) return;
|
|
const observer = new IntersectionObserver(callback, {
|
|
root: unrefElement(root2),
|
|
rootMargin,
|
|
threshold,
|
|
});
|
|
targets2.forEach((el) => el && observer.observe(el));
|
|
cleanup = () => {
|
|
observer.disconnect();
|
|
cleanup = noop;
|
|
};
|
|
},
|
|
{ immediate, flush: 'post' }
|
|
)
|
|
: noop;
|
|
const stop = () => {
|
|
cleanup();
|
|
stopWatch();
|
|
isActive.value = false;
|
|
};
|
|
tryOnScopeDispose(stop);
|
|
return {
|
|
isSupported,
|
|
isActive,
|
|
pause() {
|
|
cleanup();
|
|
isActive.value = false;
|
|
},
|
|
resume() {
|
|
isActive.value = true;
|
|
},
|
|
stop,
|
|
};
|
|
}
|
|
function useElementVisibility(element, options = {}) {
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
scrollTarget,
|
|
threshold = 0,
|
|
rootMargin,
|
|
once = false,
|
|
} = options;
|
|
const elementIsVisible = shallowRef(false);
|
|
const { stop } = useIntersectionObserver(
|
|
element,
|
|
(intersectionObserverEntries) => {
|
|
let isIntersecting = elementIsVisible.value;
|
|
let latestTime = 0;
|
|
for (const entry of intersectionObserverEntries) {
|
|
if (entry.time >= latestTime) {
|
|
latestTime = entry.time;
|
|
isIntersecting = entry.isIntersecting;
|
|
}
|
|
}
|
|
elementIsVisible.value = isIntersecting;
|
|
if (once) {
|
|
watchOnce(elementIsVisible, () => {
|
|
stop();
|
|
});
|
|
}
|
|
},
|
|
{
|
|
root: scrollTarget,
|
|
window: window2,
|
|
threshold,
|
|
rootMargin: toValue(rootMargin),
|
|
}
|
|
);
|
|
return elementIsVisible;
|
|
}
|
|
var events = /* @__PURE__ */ new Map();
|
|
function useEventBus(key) {
|
|
const scope = getCurrentScope();
|
|
function on(listener) {
|
|
var _a;
|
|
const listeners = events.get(key) || /* @__PURE__ */ new Set();
|
|
listeners.add(listener);
|
|
events.set(key, listeners);
|
|
const _off = () => off(listener);
|
|
(_a = scope == null ? void 0 : scope.cleanups) == null
|
|
? void 0
|
|
: _a.push(_off);
|
|
return _off;
|
|
}
|
|
function once(listener) {
|
|
function _listener(...args) {
|
|
off(_listener);
|
|
listener(...args);
|
|
}
|
|
return on(_listener);
|
|
}
|
|
function off(listener) {
|
|
const listeners = events.get(key);
|
|
if (!listeners) return;
|
|
listeners.delete(listener);
|
|
if (!listeners.size) reset();
|
|
}
|
|
function reset() {
|
|
events.delete(key);
|
|
}
|
|
function emit(event, payload) {
|
|
var _a;
|
|
(_a = events.get(key)) == null
|
|
? void 0
|
|
: _a.forEach((v) => v(event, payload));
|
|
}
|
|
return { on, once, off, emit, reset };
|
|
}
|
|
function resolveNestedOptions$1(options) {
|
|
if (options === true) return {};
|
|
return options;
|
|
}
|
|
function useEventSource(url, events2 = [], options = {}) {
|
|
const event = shallowRef(null);
|
|
const data = shallowRef(null);
|
|
const status = shallowRef('CONNECTING');
|
|
const eventSource = ref(null);
|
|
const error = shallowRef(null);
|
|
const urlRef = toRef2(url);
|
|
const lastEventId = shallowRef(null);
|
|
let explicitlyClosed = false;
|
|
let retried = 0;
|
|
const {
|
|
withCredentials = false,
|
|
immediate = true,
|
|
autoConnect = true,
|
|
autoReconnect,
|
|
} = options;
|
|
const close = () => {
|
|
if (isClient && eventSource.value) {
|
|
eventSource.value.close();
|
|
eventSource.value = null;
|
|
status.value = 'CLOSED';
|
|
explicitlyClosed = true;
|
|
}
|
|
};
|
|
const _init = () => {
|
|
if (explicitlyClosed || typeof urlRef.value === 'undefined') return;
|
|
const es = new EventSource(urlRef.value, { withCredentials });
|
|
status.value = 'CONNECTING';
|
|
eventSource.value = es;
|
|
es.onopen = () => {
|
|
status.value = 'OPEN';
|
|
error.value = null;
|
|
};
|
|
es.onerror = (e) => {
|
|
status.value = 'CLOSED';
|
|
error.value = e;
|
|
if (es.readyState === 2 && !explicitlyClosed && autoReconnect) {
|
|
es.close();
|
|
const {
|
|
retries = -1,
|
|
delay = 1e3,
|
|
onFailed,
|
|
} = resolveNestedOptions$1(autoReconnect);
|
|
retried += 1;
|
|
if (typeof retries === 'number' && (retries < 0 || retried < retries))
|
|
setTimeout(_init, delay);
|
|
else if (typeof retries === 'function' && retries())
|
|
setTimeout(_init, delay);
|
|
else onFailed == null ? void 0 : onFailed();
|
|
}
|
|
};
|
|
es.onmessage = (e) => {
|
|
event.value = null;
|
|
data.value = e.data;
|
|
lastEventId.value = e.lastEventId;
|
|
};
|
|
for (const event_name of events2) {
|
|
useEventListener(
|
|
es,
|
|
event_name,
|
|
(e) => {
|
|
event.value = event_name;
|
|
data.value = e.data || null;
|
|
},
|
|
{ passive: true }
|
|
);
|
|
}
|
|
};
|
|
const open = () => {
|
|
if (!isClient) return;
|
|
close();
|
|
explicitlyClosed = false;
|
|
retried = 0;
|
|
_init();
|
|
};
|
|
if (immediate) open();
|
|
if (autoConnect) watch(urlRef, open);
|
|
tryOnScopeDispose(close);
|
|
return {
|
|
eventSource,
|
|
event,
|
|
data,
|
|
status,
|
|
error,
|
|
open,
|
|
close,
|
|
lastEventId,
|
|
};
|
|
}
|
|
function useEyeDropper(options = {}) {
|
|
const { initialValue = '' } = options;
|
|
const isSupported = useSupported(
|
|
() => typeof window !== 'undefined' && 'EyeDropper' in window
|
|
);
|
|
const sRGBHex = shallowRef(initialValue);
|
|
async function open(openOptions) {
|
|
if (!isSupported.value) return;
|
|
const eyeDropper = new window.EyeDropper();
|
|
const result = await eyeDropper.open(openOptions);
|
|
sRGBHex.value = result.sRGBHex;
|
|
return result;
|
|
}
|
|
return { isSupported, sRGBHex, open };
|
|
}
|
|
function useFavicon(newIcon = null, options = {}) {
|
|
const {
|
|
baseUrl = '',
|
|
rel = 'icon',
|
|
document: document2 = defaultDocument,
|
|
} = options;
|
|
const favicon = toRef2(newIcon);
|
|
const applyIcon = (icon) => {
|
|
const elements =
|
|
document2 == null
|
|
? void 0
|
|
: document2.head.querySelectorAll(`link[rel*="${rel}"]`);
|
|
if (!elements || elements.length === 0) {
|
|
const link = document2 == null ? void 0 : document2.createElement('link');
|
|
if (link) {
|
|
link.rel = rel;
|
|
link.href = `${baseUrl}${icon}`;
|
|
link.type = `image/${icon.split('.').pop()}`;
|
|
document2 == null ? void 0 : document2.head.append(link);
|
|
}
|
|
return;
|
|
}
|
|
elements == null
|
|
? void 0
|
|
: elements.forEach((el) => (el.href = `${baseUrl}${icon}`));
|
|
};
|
|
watch(
|
|
favicon,
|
|
(i, o) => {
|
|
if (typeof i === 'string' && i !== o) applyIcon(i);
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
return favicon;
|
|
}
|
|
var payloadMapping = {
|
|
json: 'application/json',
|
|
text: 'text/plain',
|
|
};
|
|
function isFetchOptions(obj) {
|
|
return (
|
|
obj &&
|
|
containsProp(
|
|
obj,
|
|
'immediate',
|
|
'refetch',
|
|
'initialData',
|
|
'timeout',
|
|
'beforeFetch',
|
|
'afterFetch',
|
|
'onFetchError',
|
|
'fetch',
|
|
'updateDataOnError'
|
|
)
|
|
);
|
|
}
|
|
var reAbsolute = /^(?:[a-z][a-z\d+\-.]*:)?\/\//i;
|
|
function isAbsoluteURL(url) {
|
|
return reAbsolute.test(url);
|
|
}
|
|
function headersToObject(headers) {
|
|
if (typeof Headers !== 'undefined' && headers instanceof Headers)
|
|
return Object.fromEntries(headers.entries());
|
|
return headers;
|
|
}
|
|
function combineCallbacks(combination, ...callbacks) {
|
|
if (combination === 'overwrite') {
|
|
return async (ctx) => {
|
|
let callback;
|
|
for (let i = callbacks.length - 1; i >= 0; i--) {
|
|
if (callbacks[i] != null) {
|
|
callback = callbacks[i];
|
|
break;
|
|
}
|
|
}
|
|
if (callback) return { ...ctx, ...(await callback(ctx)) };
|
|
return ctx;
|
|
};
|
|
} else {
|
|
return async (ctx) => {
|
|
for (const callback of callbacks) {
|
|
if (callback) ctx = { ...ctx, ...(await callback(ctx)) };
|
|
}
|
|
return ctx;
|
|
};
|
|
}
|
|
}
|
|
function createFetch(config = {}) {
|
|
const _combination = config.combination || 'chain';
|
|
const _options = config.options || {};
|
|
const _fetchOptions = config.fetchOptions || {};
|
|
function useFactoryFetch(url, ...args) {
|
|
const computedUrl = computed(() => {
|
|
const baseUrl = toValue(config.baseUrl);
|
|
const targetUrl = toValue(url);
|
|
return baseUrl && !isAbsoluteURL(targetUrl)
|
|
? joinPaths(baseUrl, targetUrl)
|
|
: targetUrl;
|
|
});
|
|
let options = _options;
|
|
let fetchOptions = _fetchOptions;
|
|
if (args.length > 0) {
|
|
if (isFetchOptions(args[0])) {
|
|
options = {
|
|
...options,
|
|
...args[0],
|
|
beforeFetch: combineCallbacks(
|
|
_combination,
|
|
_options.beforeFetch,
|
|
args[0].beforeFetch
|
|
),
|
|
afterFetch: combineCallbacks(
|
|
_combination,
|
|
_options.afterFetch,
|
|
args[0].afterFetch
|
|
),
|
|
onFetchError: combineCallbacks(
|
|
_combination,
|
|
_options.onFetchError,
|
|
args[0].onFetchError
|
|
),
|
|
};
|
|
} else {
|
|
fetchOptions = {
|
|
...fetchOptions,
|
|
...args[0],
|
|
headers: {
|
|
...(headersToObject(fetchOptions.headers) || {}),
|
|
...(headersToObject(args[0].headers) || {}),
|
|
},
|
|
};
|
|
}
|
|
}
|
|
if (args.length > 1 && isFetchOptions(args[1])) {
|
|
options = {
|
|
...options,
|
|
...args[1],
|
|
beforeFetch: combineCallbacks(
|
|
_combination,
|
|
_options.beforeFetch,
|
|
args[1].beforeFetch
|
|
),
|
|
afterFetch: combineCallbacks(
|
|
_combination,
|
|
_options.afterFetch,
|
|
args[1].afterFetch
|
|
),
|
|
onFetchError: combineCallbacks(
|
|
_combination,
|
|
_options.onFetchError,
|
|
args[1].onFetchError
|
|
),
|
|
};
|
|
}
|
|
return useFetch(computedUrl, fetchOptions, options);
|
|
}
|
|
return useFactoryFetch;
|
|
}
|
|
function useFetch(url, ...args) {
|
|
var _a;
|
|
const supportsAbort = typeof AbortController === 'function';
|
|
let fetchOptions = {};
|
|
let options = {
|
|
immediate: true,
|
|
refetch: false,
|
|
timeout: 0,
|
|
updateDataOnError: false,
|
|
};
|
|
const config = {
|
|
method: 'GET',
|
|
type: 'text',
|
|
payload: void 0,
|
|
};
|
|
if (args.length > 0) {
|
|
if (isFetchOptions(args[0])) options = { ...options, ...args[0] };
|
|
else fetchOptions = args[0];
|
|
}
|
|
if (args.length > 1) {
|
|
if (isFetchOptions(args[1])) options = { ...options, ...args[1] };
|
|
}
|
|
const {
|
|
fetch = (_a = defaultWindow) == null ? void 0 : _a.fetch,
|
|
initialData,
|
|
timeout,
|
|
} = options;
|
|
const responseEvent = createEventHook();
|
|
const errorEvent = createEventHook();
|
|
const finallyEvent = createEventHook();
|
|
const isFinished = shallowRef(false);
|
|
const isFetching = shallowRef(false);
|
|
const aborted = shallowRef(false);
|
|
const statusCode = shallowRef(null);
|
|
const response = shallowRef(null);
|
|
const error = shallowRef(null);
|
|
const data = shallowRef(initialData || null);
|
|
const canAbort = computed(() => supportsAbort && isFetching.value);
|
|
let controller;
|
|
let timer;
|
|
const abort = () => {
|
|
if (supportsAbort) {
|
|
controller == null ? void 0 : controller.abort();
|
|
controller = new AbortController();
|
|
controller.signal.onabort = () => (aborted.value = true);
|
|
fetchOptions = {
|
|
...fetchOptions,
|
|
signal: controller.signal,
|
|
};
|
|
}
|
|
};
|
|
const loading = (isLoading) => {
|
|
isFetching.value = isLoading;
|
|
isFinished.value = !isLoading;
|
|
};
|
|
if (timeout) timer = useTimeoutFn(abort, timeout, { immediate: false });
|
|
let executeCounter = 0;
|
|
const execute = async (throwOnFailed = false) => {
|
|
var _a2, _b;
|
|
abort();
|
|
loading(true);
|
|
error.value = null;
|
|
statusCode.value = null;
|
|
aborted.value = false;
|
|
executeCounter += 1;
|
|
const currentExecuteCounter = executeCounter;
|
|
const defaultFetchOptions = {
|
|
method: config.method,
|
|
headers: {},
|
|
};
|
|
const payload = toValue(config.payload);
|
|
if (payload) {
|
|
const headers = headersToObject(defaultFetchOptions.headers);
|
|
const proto = Object.getPrototypeOf(payload);
|
|
if (
|
|
!config.payloadType &&
|
|
payload &&
|
|
(proto === Object.prototype || Array.isArray(proto)) &&
|
|
!(payload instanceof FormData)
|
|
)
|
|
config.payloadType = 'json';
|
|
if (config.payloadType)
|
|
headers['Content-Type'] =
|
|
(_a2 = payloadMapping[config.payloadType]) != null
|
|
? _a2
|
|
: config.payloadType;
|
|
defaultFetchOptions.body =
|
|
config.payloadType === 'json' ? JSON.stringify(payload) : payload;
|
|
}
|
|
let isCanceled = false;
|
|
const context = {
|
|
url: toValue(url),
|
|
options: {
|
|
...defaultFetchOptions,
|
|
...fetchOptions,
|
|
},
|
|
cancel: () => {
|
|
isCanceled = true;
|
|
},
|
|
};
|
|
if (options.beforeFetch)
|
|
Object.assign(context, await options.beforeFetch(context));
|
|
if (isCanceled || !fetch) {
|
|
loading(false);
|
|
return Promise.resolve(null);
|
|
}
|
|
let responseData = null;
|
|
if (timer) timer.start();
|
|
return fetch(context.url, {
|
|
...defaultFetchOptions,
|
|
...context.options,
|
|
headers: {
|
|
...headersToObject(defaultFetchOptions.headers),
|
|
...headersToObject(
|
|
(_b = context.options) == null ? void 0 : _b.headers
|
|
),
|
|
},
|
|
})
|
|
.then(async (fetchResponse) => {
|
|
response.value = fetchResponse;
|
|
statusCode.value = fetchResponse.status;
|
|
responseData = await fetchResponse.clone()[config.type]();
|
|
if (!fetchResponse.ok) {
|
|
data.value = initialData || null;
|
|
throw new Error(fetchResponse.statusText);
|
|
}
|
|
if (options.afterFetch) {
|
|
({ data: responseData } = await options.afterFetch({
|
|
data: responseData,
|
|
response: fetchResponse,
|
|
context,
|
|
execute,
|
|
}));
|
|
}
|
|
data.value = responseData;
|
|
responseEvent.trigger(fetchResponse);
|
|
return fetchResponse;
|
|
})
|
|
.catch(async (fetchError) => {
|
|
let errorData = fetchError.message || fetchError.name;
|
|
if (options.onFetchError) {
|
|
({ error: errorData, data: responseData } =
|
|
await options.onFetchError({
|
|
data: responseData,
|
|
error: fetchError,
|
|
response: response.value,
|
|
context,
|
|
execute,
|
|
}));
|
|
}
|
|
error.value = errorData;
|
|
if (options.updateDataOnError) data.value = responseData;
|
|
errorEvent.trigger(fetchError);
|
|
if (throwOnFailed) throw fetchError;
|
|
return null;
|
|
})
|
|
.finally(() => {
|
|
if (currentExecuteCounter === executeCounter) loading(false);
|
|
if (timer) timer.stop();
|
|
finallyEvent.trigger(null);
|
|
});
|
|
};
|
|
const refetch = toRef2(options.refetch);
|
|
watch([refetch, toRef2(url)], ([refetch2]) => refetch2 && execute(), {
|
|
deep: true,
|
|
});
|
|
const shell = {
|
|
isFinished: readonly(isFinished),
|
|
isFetching: readonly(isFetching),
|
|
statusCode,
|
|
response,
|
|
error,
|
|
data,
|
|
canAbort,
|
|
aborted,
|
|
abort,
|
|
execute,
|
|
onFetchResponse: responseEvent.on,
|
|
onFetchError: errorEvent.on,
|
|
onFetchFinally: finallyEvent.on,
|
|
// method
|
|
get: setMethod('GET'),
|
|
put: setMethod('PUT'),
|
|
post: setMethod('POST'),
|
|
delete: setMethod('DELETE'),
|
|
patch: setMethod('PATCH'),
|
|
head: setMethod('HEAD'),
|
|
options: setMethod('OPTIONS'),
|
|
// type
|
|
json: setType('json'),
|
|
text: setType('text'),
|
|
blob: setType('blob'),
|
|
arrayBuffer: setType('arrayBuffer'),
|
|
formData: setType('formData'),
|
|
};
|
|
function setMethod(method) {
|
|
return (payload, payloadType) => {
|
|
if (!isFetching.value) {
|
|
config.method = method;
|
|
config.payload = payload;
|
|
config.payloadType = payloadType;
|
|
if (isRef(config.payload)) {
|
|
watch(
|
|
[refetch, toRef2(config.payload)],
|
|
([refetch2]) => refetch2 && execute(),
|
|
{ deep: true }
|
|
);
|
|
}
|
|
return {
|
|
...shell,
|
|
then(onFulfilled, onRejected) {
|
|
return waitUntilFinished().then(onFulfilled, onRejected);
|
|
},
|
|
};
|
|
}
|
|
return void 0;
|
|
};
|
|
}
|
|
function waitUntilFinished() {
|
|
return new Promise((resolve, reject) => {
|
|
until(isFinished)
|
|
.toBe(true)
|
|
.then(() => resolve(shell))
|
|
.catch(reject);
|
|
});
|
|
}
|
|
function setType(type) {
|
|
return () => {
|
|
if (!isFetching.value) {
|
|
config.type = type;
|
|
return {
|
|
...shell,
|
|
then(onFulfilled, onRejected) {
|
|
return waitUntilFinished().then(onFulfilled, onRejected);
|
|
},
|
|
};
|
|
}
|
|
return void 0;
|
|
};
|
|
}
|
|
if (options.immediate) Promise.resolve().then(() => execute());
|
|
return {
|
|
...shell,
|
|
then(onFulfilled, onRejected) {
|
|
return waitUntilFinished().then(onFulfilled, onRejected);
|
|
},
|
|
};
|
|
}
|
|
function joinPaths(start, end) {
|
|
if (!start.endsWith('/') && !end.startsWith('/')) {
|
|
return `${start}/${end}`;
|
|
}
|
|
if (start.endsWith('/') && end.startsWith('/')) {
|
|
return `${start.slice(0, -1)}${end}`;
|
|
}
|
|
return `${start}${end}`;
|
|
}
|
|
var DEFAULT_OPTIONS = {
|
|
multiple: true,
|
|
accept: '*',
|
|
reset: false,
|
|
directory: false,
|
|
};
|
|
function prepareInitialFiles(files) {
|
|
if (!files) return null;
|
|
if (files instanceof FileList) return files;
|
|
const dt = new DataTransfer();
|
|
for (const file of files) {
|
|
dt.items.add(file);
|
|
}
|
|
return dt.files;
|
|
}
|
|
function useFileDialog(options = {}) {
|
|
const { document: document2 = defaultDocument } = options;
|
|
const files = ref(prepareInitialFiles(options.initialFiles));
|
|
const { on: onChange, trigger: changeTrigger } = createEventHook();
|
|
const { on: onCancel, trigger: cancelTrigger } = createEventHook();
|
|
let input;
|
|
if (document2) {
|
|
input = document2.createElement('input');
|
|
input.type = 'file';
|
|
input.onchange = (event) => {
|
|
const result = event.target;
|
|
files.value = result.files;
|
|
changeTrigger(files.value);
|
|
};
|
|
input.oncancel = () => {
|
|
cancelTrigger();
|
|
};
|
|
}
|
|
const reset = () => {
|
|
files.value = null;
|
|
if (input && input.value) {
|
|
input.value = '';
|
|
changeTrigger(null);
|
|
}
|
|
};
|
|
const open = (localOptions) => {
|
|
if (!input) return;
|
|
const _options = {
|
|
...DEFAULT_OPTIONS,
|
|
...options,
|
|
...localOptions,
|
|
};
|
|
input.multiple = _options.multiple;
|
|
input.accept = _options.accept;
|
|
input.webkitdirectory = _options.directory;
|
|
if (hasOwn(_options, 'capture')) input.capture = _options.capture;
|
|
if (_options.reset) reset();
|
|
input.click();
|
|
};
|
|
return {
|
|
files: readonly(files),
|
|
open,
|
|
reset,
|
|
onCancel,
|
|
onChange,
|
|
};
|
|
}
|
|
function useFileSystemAccess(options = {}) {
|
|
const { window: _window = defaultWindow, dataType = 'Text' } = options;
|
|
const window2 = _window;
|
|
const isSupported = useSupported(
|
|
() =>
|
|
window2 &&
|
|
'showSaveFilePicker' in window2 &&
|
|
'showOpenFilePicker' in window2
|
|
);
|
|
const fileHandle = shallowRef();
|
|
const data = shallowRef();
|
|
const file = shallowRef();
|
|
const fileName = computed(() => {
|
|
var _a, _b;
|
|
return (_b = (_a = file.value) == null ? void 0 : _a.name) != null
|
|
? _b
|
|
: '';
|
|
});
|
|
const fileMIME = computed(() => {
|
|
var _a, _b;
|
|
return (_b = (_a = file.value) == null ? void 0 : _a.type) != null
|
|
? _b
|
|
: '';
|
|
});
|
|
const fileSize = computed(() => {
|
|
var _a, _b;
|
|
return (_b = (_a = file.value) == null ? void 0 : _a.size) != null ? _b : 0;
|
|
});
|
|
const fileLastModified = computed(() => {
|
|
var _a, _b;
|
|
return (_b = (_a = file.value) == null ? void 0 : _a.lastModified) != null
|
|
? _b
|
|
: 0;
|
|
});
|
|
async function open(_options = {}) {
|
|
if (!isSupported.value) return;
|
|
const [handle] = await window2.showOpenFilePicker({
|
|
...toValue(options),
|
|
..._options,
|
|
});
|
|
fileHandle.value = handle;
|
|
await updateData();
|
|
}
|
|
async function create(_options = {}) {
|
|
if (!isSupported.value) return;
|
|
fileHandle.value = await window2.showSaveFilePicker({
|
|
...options,
|
|
..._options,
|
|
});
|
|
data.value = void 0;
|
|
await updateData();
|
|
}
|
|
async function save(_options = {}) {
|
|
if (!isSupported.value) return;
|
|
if (!fileHandle.value) return saveAs(_options);
|
|
if (data.value) {
|
|
const writableStream = await fileHandle.value.createWritable();
|
|
await writableStream.write(data.value);
|
|
await writableStream.close();
|
|
}
|
|
await updateFile();
|
|
}
|
|
async function saveAs(_options = {}) {
|
|
if (!isSupported.value) return;
|
|
fileHandle.value = await window2.showSaveFilePicker({
|
|
...options,
|
|
..._options,
|
|
});
|
|
if (data.value) {
|
|
const writableStream = await fileHandle.value.createWritable();
|
|
await writableStream.write(data.value);
|
|
await writableStream.close();
|
|
}
|
|
await updateFile();
|
|
}
|
|
async function updateFile() {
|
|
var _a;
|
|
file.value = await ((_a = fileHandle.value) == null
|
|
? void 0
|
|
: _a.getFile());
|
|
}
|
|
async function updateData() {
|
|
var _a, _b;
|
|
await updateFile();
|
|
const type = toValue(dataType);
|
|
if (type === 'Text')
|
|
data.value = await ((_a = file.value) == null ? void 0 : _a.text());
|
|
else if (type === 'ArrayBuffer')
|
|
data.value = await ((_b = file.value) == null
|
|
? void 0
|
|
: _b.arrayBuffer());
|
|
else if (type === 'Blob') data.value = file.value;
|
|
}
|
|
watch(() => toValue(dataType), updateData);
|
|
return {
|
|
isSupported,
|
|
data,
|
|
file,
|
|
fileName,
|
|
fileMIME,
|
|
fileSize,
|
|
fileLastModified,
|
|
open,
|
|
create,
|
|
save,
|
|
saveAs,
|
|
updateData,
|
|
};
|
|
}
|
|
function useFocus(target, options = {}) {
|
|
const {
|
|
initialValue = false,
|
|
focusVisible = false,
|
|
preventScroll = false,
|
|
} = options;
|
|
const innerFocused = shallowRef(false);
|
|
const targetElement = computed(() => unrefElement(target));
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
targetElement,
|
|
'focus',
|
|
(event) => {
|
|
var _a, _b;
|
|
if (
|
|
!focusVisible ||
|
|
((_b = (_a = event.target).matches) == null
|
|
? void 0
|
|
: _b.call(_a, ':focus-visible'))
|
|
)
|
|
innerFocused.value = true;
|
|
},
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
targetElement,
|
|
'blur',
|
|
() => (innerFocused.value = false),
|
|
listenerOptions
|
|
);
|
|
const focused = computed({
|
|
get: () => innerFocused.value,
|
|
set(value) {
|
|
var _a, _b;
|
|
if (!value && innerFocused.value)
|
|
(_a = targetElement.value) == null ? void 0 : _a.blur();
|
|
else if (value && !innerFocused.value)
|
|
(_b = targetElement.value) == null
|
|
? void 0
|
|
: _b.focus({ preventScroll });
|
|
},
|
|
});
|
|
watch(
|
|
targetElement,
|
|
() => {
|
|
focused.value = initialValue;
|
|
},
|
|
{ immediate: true, flush: 'post' }
|
|
);
|
|
return { focused };
|
|
}
|
|
var EVENT_FOCUS_IN = 'focusin';
|
|
var EVENT_FOCUS_OUT = 'focusout';
|
|
var PSEUDO_CLASS_FOCUS_WITHIN = ':focus-within';
|
|
function useFocusWithin(target, options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const targetElement = computed(() => unrefElement(target));
|
|
const _focused = shallowRef(false);
|
|
const focused = computed(() => _focused.value);
|
|
const activeElement = useActiveElement(options);
|
|
if (!window2 || !activeElement.value) {
|
|
return { focused };
|
|
}
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
targetElement,
|
|
EVENT_FOCUS_IN,
|
|
() => (_focused.value = true),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
targetElement,
|
|
EVENT_FOCUS_OUT,
|
|
() => {
|
|
var _a, _b, _c;
|
|
return (_focused.value =
|
|
(_c =
|
|
(_b = (_a = targetElement.value) == null ? void 0 : _a.matches) ==
|
|
null
|
|
? void 0
|
|
: _b.call(_a, PSEUDO_CLASS_FOCUS_WITHIN)) != null
|
|
? _c
|
|
: false);
|
|
},
|
|
listenerOptions
|
|
);
|
|
return { focused };
|
|
}
|
|
function useFps(options) {
|
|
var _a;
|
|
const fps = shallowRef(0);
|
|
if (typeof performance === 'undefined') return fps;
|
|
const every =
|
|
(_a = options == null ? void 0 : options.every) != null ? _a : 10;
|
|
let last = performance.now();
|
|
let ticks = 0;
|
|
useRafFn(() => {
|
|
ticks += 1;
|
|
if (ticks >= every) {
|
|
const now2 = performance.now();
|
|
const diff = now2 - last;
|
|
fps.value = Math.round(1e3 / (diff / ticks));
|
|
last = now2;
|
|
ticks = 0;
|
|
}
|
|
});
|
|
return fps;
|
|
}
|
|
var eventHandlers = [
|
|
'fullscreenchange',
|
|
'webkitfullscreenchange',
|
|
'webkitendfullscreen',
|
|
'mozfullscreenchange',
|
|
'MSFullscreenChange',
|
|
];
|
|
function useFullscreen(target, options = {}) {
|
|
const { document: document2 = defaultDocument, autoExit = false } = options;
|
|
const targetRef = computed(() => {
|
|
var _a;
|
|
return (_a = unrefElement(target)) != null
|
|
? _a
|
|
: document2 == null
|
|
? void 0
|
|
: document2.documentElement;
|
|
});
|
|
const isFullscreen = shallowRef(false);
|
|
const requestMethod = computed(() => {
|
|
return [
|
|
'requestFullscreen',
|
|
'webkitRequestFullscreen',
|
|
'webkitEnterFullscreen',
|
|
'webkitEnterFullScreen',
|
|
'webkitRequestFullScreen',
|
|
'mozRequestFullScreen',
|
|
'msRequestFullscreen',
|
|
].find(
|
|
(m) =>
|
|
(document2 && m in document2) ||
|
|
(targetRef.value && m in targetRef.value)
|
|
);
|
|
});
|
|
const exitMethod = computed(() => {
|
|
return [
|
|
'exitFullscreen',
|
|
'webkitExitFullscreen',
|
|
'webkitExitFullScreen',
|
|
'webkitCancelFullScreen',
|
|
'mozCancelFullScreen',
|
|
'msExitFullscreen',
|
|
].find(
|
|
(m) =>
|
|
(document2 && m in document2) ||
|
|
(targetRef.value && m in targetRef.value)
|
|
);
|
|
});
|
|
const fullscreenEnabled = computed(() => {
|
|
return [
|
|
'fullScreen',
|
|
'webkitIsFullScreen',
|
|
'webkitDisplayingFullscreen',
|
|
'mozFullScreen',
|
|
'msFullscreenElement',
|
|
].find(
|
|
(m) =>
|
|
(document2 && m in document2) ||
|
|
(targetRef.value && m in targetRef.value)
|
|
);
|
|
});
|
|
const fullscreenElementMethod = [
|
|
'fullscreenElement',
|
|
'webkitFullscreenElement',
|
|
'mozFullScreenElement',
|
|
'msFullscreenElement',
|
|
].find((m) => document2 && m in document2);
|
|
const isSupported = useSupported(
|
|
() =>
|
|
targetRef.value &&
|
|
document2 &&
|
|
requestMethod.value !== void 0 &&
|
|
exitMethod.value !== void 0 &&
|
|
fullscreenEnabled.value !== void 0
|
|
);
|
|
const isCurrentElementFullScreen = () => {
|
|
if (fullscreenElementMethod)
|
|
return (
|
|
(document2 == null ? void 0 : document2[fullscreenElementMethod]) ===
|
|
targetRef.value
|
|
);
|
|
return false;
|
|
};
|
|
const isElementFullScreen = () => {
|
|
if (fullscreenEnabled.value) {
|
|
if (document2 && document2[fullscreenEnabled.value] != null) {
|
|
return document2[fullscreenEnabled.value];
|
|
} else {
|
|
const target2 = targetRef.value;
|
|
if (
|
|
(target2 == null ? void 0 : target2[fullscreenEnabled.value]) != null
|
|
) {
|
|
return Boolean(target2[fullscreenEnabled.value]);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
async function exit() {
|
|
if (!isSupported.value || !isFullscreen.value) return;
|
|
if (exitMethod.value) {
|
|
if ((document2 == null ? void 0 : document2[exitMethod.value]) != null) {
|
|
await document2[exitMethod.value]();
|
|
} else {
|
|
const target2 = targetRef.value;
|
|
if ((target2 == null ? void 0 : target2[exitMethod.value]) != null)
|
|
await target2[exitMethod.value]();
|
|
}
|
|
}
|
|
isFullscreen.value = false;
|
|
}
|
|
async function enter() {
|
|
if (!isSupported.value || isFullscreen.value) return;
|
|
if (isElementFullScreen()) await exit();
|
|
const target2 = targetRef.value;
|
|
if (
|
|
requestMethod.value &&
|
|
(target2 == null ? void 0 : target2[requestMethod.value]) != null
|
|
) {
|
|
await target2[requestMethod.value]();
|
|
isFullscreen.value = true;
|
|
}
|
|
}
|
|
async function toggle() {
|
|
await (isFullscreen.value ? exit() : enter());
|
|
}
|
|
const handlerCallback = () => {
|
|
const isElementFullScreenValue = isElementFullScreen();
|
|
if (
|
|
!isElementFullScreenValue ||
|
|
(isElementFullScreenValue && isCurrentElementFullScreen())
|
|
)
|
|
isFullscreen.value = isElementFullScreenValue;
|
|
};
|
|
const listenerOptions = { capture: false, passive: true };
|
|
useEventListener(document2, eventHandlers, handlerCallback, listenerOptions);
|
|
useEventListener(
|
|
() => unrefElement(targetRef),
|
|
eventHandlers,
|
|
handlerCallback,
|
|
listenerOptions
|
|
);
|
|
if (autoExit) tryOnScopeDispose(exit);
|
|
return {
|
|
isSupported,
|
|
isFullscreen,
|
|
enter,
|
|
exit,
|
|
toggle,
|
|
};
|
|
}
|
|
function mapGamepadToXbox360Controller(gamepad) {
|
|
return computed(() => {
|
|
if (gamepad.value) {
|
|
return {
|
|
buttons: {
|
|
a: gamepad.value.buttons[0],
|
|
b: gamepad.value.buttons[1],
|
|
x: gamepad.value.buttons[2],
|
|
y: gamepad.value.buttons[3],
|
|
},
|
|
bumper: {
|
|
left: gamepad.value.buttons[4],
|
|
right: gamepad.value.buttons[5],
|
|
},
|
|
triggers: {
|
|
left: gamepad.value.buttons[6],
|
|
right: gamepad.value.buttons[7],
|
|
},
|
|
stick: {
|
|
left: {
|
|
horizontal: gamepad.value.axes[0],
|
|
vertical: gamepad.value.axes[1],
|
|
button: gamepad.value.buttons[10],
|
|
},
|
|
right: {
|
|
horizontal: gamepad.value.axes[2],
|
|
vertical: gamepad.value.axes[3],
|
|
button: gamepad.value.buttons[11],
|
|
},
|
|
},
|
|
dpad: {
|
|
up: gamepad.value.buttons[12],
|
|
down: gamepad.value.buttons[13],
|
|
left: gamepad.value.buttons[14],
|
|
right: gamepad.value.buttons[15],
|
|
},
|
|
back: gamepad.value.buttons[8],
|
|
start: gamepad.value.buttons[9],
|
|
};
|
|
}
|
|
return null;
|
|
});
|
|
}
|
|
function useGamepad(options = {}) {
|
|
const { navigator: navigator2 = defaultNavigator } = options;
|
|
const isSupported = useSupported(
|
|
() => navigator2 && 'getGamepads' in navigator2
|
|
);
|
|
const gamepads = ref([]);
|
|
const onConnectedHook = createEventHook();
|
|
const onDisconnectedHook = createEventHook();
|
|
const stateFromGamepad = (gamepad) => {
|
|
const hapticActuators = [];
|
|
const vibrationActuator =
|
|
'vibrationActuator' in gamepad ? gamepad.vibrationActuator : null;
|
|
if (vibrationActuator) hapticActuators.push(vibrationActuator);
|
|
if (gamepad.hapticActuators)
|
|
hapticActuators.push(...gamepad.hapticActuators);
|
|
return {
|
|
id: gamepad.id,
|
|
index: gamepad.index,
|
|
connected: gamepad.connected,
|
|
mapping: gamepad.mapping,
|
|
timestamp: gamepad.timestamp,
|
|
vibrationActuator: gamepad.vibrationActuator,
|
|
hapticActuators,
|
|
axes: gamepad.axes.map((axes) => axes),
|
|
buttons: gamepad.buttons.map((button) => ({
|
|
pressed: button.pressed,
|
|
touched: button.touched,
|
|
value: button.value,
|
|
})),
|
|
};
|
|
};
|
|
const updateGamepadState = () => {
|
|
const _gamepads =
|
|
(navigator2 == null ? void 0 : navigator2.getGamepads()) || [];
|
|
for (const gamepad of _gamepads) {
|
|
if (gamepad && gamepads.value[gamepad.index])
|
|
gamepads.value[gamepad.index] = stateFromGamepad(gamepad);
|
|
}
|
|
};
|
|
const { isActive, pause, resume } = useRafFn(updateGamepadState);
|
|
const onGamepadConnected = (gamepad) => {
|
|
if (!gamepads.value.some(({ index }) => index === gamepad.index)) {
|
|
gamepads.value.push(stateFromGamepad(gamepad));
|
|
onConnectedHook.trigger(gamepad.index);
|
|
}
|
|
resume();
|
|
};
|
|
const onGamepadDisconnected = (gamepad) => {
|
|
gamepads.value = gamepads.value.filter((x) => x.index !== gamepad.index);
|
|
onDisconnectedHook.trigger(gamepad.index);
|
|
};
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
'gamepadconnected',
|
|
(e) => onGamepadConnected(e.gamepad),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
'gamepaddisconnected',
|
|
(e) => onGamepadDisconnected(e.gamepad),
|
|
listenerOptions
|
|
);
|
|
tryOnMounted(() => {
|
|
const _gamepads =
|
|
(navigator2 == null ? void 0 : navigator2.getGamepads()) || [];
|
|
for (const gamepad of _gamepads) {
|
|
if (gamepad && gamepads.value[gamepad.index]) onGamepadConnected(gamepad);
|
|
}
|
|
});
|
|
pause();
|
|
return {
|
|
isSupported,
|
|
onConnected: onConnectedHook.on,
|
|
onDisconnected: onDisconnectedHook.on,
|
|
gamepads,
|
|
pause,
|
|
resume,
|
|
isActive,
|
|
};
|
|
}
|
|
function useGeolocation(options = {}) {
|
|
const {
|
|
enableHighAccuracy = true,
|
|
maximumAge = 3e4,
|
|
timeout = 27e3,
|
|
navigator: navigator2 = defaultNavigator,
|
|
immediate = true,
|
|
} = options;
|
|
const isSupported = useSupported(
|
|
() => navigator2 && 'geolocation' in navigator2
|
|
);
|
|
const locatedAt = shallowRef(null);
|
|
const error = shallowRef(null);
|
|
const coords = ref({
|
|
accuracy: 0,
|
|
latitude: Number.POSITIVE_INFINITY,
|
|
longitude: Number.POSITIVE_INFINITY,
|
|
altitude: null,
|
|
altitudeAccuracy: null,
|
|
heading: null,
|
|
speed: null,
|
|
});
|
|
function updatePosition(position) {
|
|
locatedAt.value = position.timestamp;
|
|
coords.value = position.coords;
|
|
error.value = null;
|
|
}
|
|
let watcher;
|
|
function resume() {
|
|
if (isSupported.value) {
|
|
watcher = navigator2.geolocation.watchPosition(
|
|
updatePosition,
|
|
(err) => (error.value = err),
|
|
{
|
|
enableHighAccuracy,
|
|
maximumAge,
|
|
timeout,
|
|
}
|
|
);
|
|
}
|
|
}
|
|
if (immediate) resume();
|
|
function pause() {
|
|
if (watcher && navigator2) navigator2.geolocation.clearWatch(watcher);
|
|
}
|
|
tryOnScopeDispose(() => {
|
|
pause();
|
|
});
|
|
return {
|
|
isSupported,
|
|
coords,
|
|
locatedAt,
|
|
error,
|
|
resume,
|
|
pause,
|
|
};
|
|
}
|
|
var defaultEvents$1 = [
|
|
'mousemove',
|
|
'mousedown',
|
|
'resize',
|
|
'keydown',
|
|
'touchstart',
|
|
'wheel',
|
|
];
|
|
var oneMinute = 6e4;
|
|
function useIdle(timeout = oneMinute, options = {}) {
|
|
const {
|
|
initialState = false,
|
|
listenForVisibilityChange = true,
|
|
events: events2 = defaultEvents$1,
|
|
window: window2 = defaultWindow,
|
|
eventFilter = throttleFilter(50),
|
|
} = options;
|
|
const idle = shallowRef(initialState);
|
|
const lastActive = shallowRef(timestamp());
|
|
let timer;
|
|
const reset = () => {
|
|
idle.value = false;
|
|
clearTimeout(timer);
|
|
timer = setTimeout(() => (idle.value = true), timeout);
|
|
};
|
|
const onEvent = createFilterWrapper(eventFilter, () => {
|
|
lastActive.value = timestamp();
|
|
reset();
|
|
});
|
|
if (window2) {
|
|
const document2 = window2.document;
|
|
const listenerOptions = { passive: true };
|
|
for (const event of events2)
|
|
useEventListener(window2, event, onEvent, listenerOptions);
|
|
if (listenForVisibilityChange) {
|
|
useEventListener(
|
|
document2,
|
|
'visibilitychange',
|
|
() => {
|
|
if (!document2.hidden) onEvent();
|
|
},
|
|
listenerOptions
|
|
);
|
|
}
|
|
reset();
|
|
}
|
|
return {
|
|
idle,
|
|
lastActive,
|
|
reset,
|
|
};
|
|
}
|
|
async function loadImage(options) {
|
|
return new Promise((resolve, reject) => {
|
|
const img = new Image();
|
|
const {
|
|
src,
|
|
srcset,
|
|
sizes,
|
|
class: clazz,
|
|
loading,
|
|
crossorigin,
|
|
referrerPolicy,
|
|
width,
|
|
height,
|
|
decoding,
|
|
fetchPriority,
|
|
ismap,
|
|
usemap,
|
|
} = options;
|
|
img.src = src;
|
|
if (srcset != null) img.srcset = srcset;
|
|
if (sizes != null) img.sizes = sizes;
|
|
if (clazz != null) img.className = clazz;
|
|
if (loading != null) img.loading = loading;
|
|
if (crossorigin != null) img.crossOrigin = crossorigin;
|
|
if (referrerPolicy != null) img.referrerPolicy = referrerPolicy;
|
|
if (width != null) img.width = width;
|
|
if (height != null) img.height = height;
|
|
if (decoding != null) img.decoding = decoding;
|
|
if (fetchPriority != null) img.fetchPriority = fetchPriority;
|
|
if (ismap != null) img.isMap = ismap;
|
|
if (usemap != null) img.useMap = usemap;
|
|
img.onload = () => resolve(img);
|
|
img.onerror = reject;
|
|
});
|
|
}
|
|
function useImage(options, asyncStateOptions = {}) {
|
|
const state = useAsyncState(() => loadImage(toValue(options)), void 0, {
|
|
resetOnExecute: true,
|
|
...asyncStateOptions,
|
|
});
|
|
watch(
|
|
() => toValue(options),
|
|
() => state.execute(asyncStateOptions.delay),
|
|
{ deep: true }
|
|
);
|
|
return state;
|
|
}
|
|
function resolveElement(el) {
|
|
if (typeof Window !== 'undefined' && el instanceof Window)
|
|
return el.document.documentElement;
|
|
if (typeof Document !== 'undefined' && el instanceof Document)
|
|
return el.documentElement;
|
|
return el;
|
|
}
|
|
var ARRIVED_STATE_THRESHOLD_PIXELS = 1;
|
|
function useScroll(element, options = {}) {
|
|
const {
|
|
throttle = 0,
|
|
idle = 200,
|
|
onStop = noop,
|
|
onScroll = noop,
|
|
offset = {
|
|
left: 0,
|
|
right: 0,
|
|
top: 0,
|
|
bottom: 0,
|
|
},
|
|
eventListenerOptions = {
|
|
capture: false,
|
|
passive: true,
|
|
},
|
|
behavior = 'auto',
|
|
window: window2 = defaultWindow,
|
|
onError = (e) => {
|
|
console.error(e);
|
|
},
|
|
} = options;
|
|
const internalX = shallowRef(0);
|
|
const internalY = shallowRef(0);
|
|
const x = computed({
|
|
get() {
|
|
return internalX.value;
|
|
},
|
|
set(x2) {
|
|
scrollTo(x2, void 0);
|
|
},
|
|
});
|
|
const y = computed({
|
|
get() {
|
|
return internalY.value;
|
|
},
|
|
set(y2) {
|
|
scrollTo(void 0, y2);
|
|
},
|
|
});
|
|
function scrollTo(_x, _y) {
|
|
var _a, _b, _c, _d;
|
|
if (!window2) return;
|
|
const _element = toValue(element);
|
|
if (!_element) return;
|
|
(_c = _element instanceof Document ? window2.document.body : _element) ==
|
|
null
|
|
? void 0
|
|
: _c.scrollTo({
|
|
top: (_a = toValue(_y)) != null ? _a : y.value,
|
|
left: (_b = toValue(_x)) != null ? _b : x.value,
|
|
behavior: toValue(behavior),
|
|
});
|
|
const scrollContainer =
|
|
((_d = _element == null ? void 0 : _element.document) == null
|
|
? void 0
|
|
: _d.documentElement) ||
|
|
(_element == null ? void 0 : _element.documentElement) ||
|
|
_element;
|
|
if (x != null) internalX.value = scrollContainer.scrollLeft;
|
|
if (y != null) internalY.value = scrollContainer.scrollTop;
|
|
}
|
|
const isScrolling = shallowRef(false);
|
|
const arrivedState = reactive({
|
|
left: true,
|
|
right: false,
|
|
top: true,
|
|
bottom: false,
|
|
});
|
|
const directions = reactive({
|
|
left: false,
|
|
right: false,
|
|
top: false,
|
|
bottom: false,
|
|
});
|
|
const onScrollEnd = (e) => {
|
|
if (!isScrolling.value) return;
|
|
isScrolling.value = false;
|
|
directions.left = false;
|
|
directions.right = false;
|
|
directions.top = false;
|
|
directions.bottom = false;
|
|
onStop(e);
|
|
};
|
|
const onScrollEndDebounced = useDebounceFn(onScrollEnd, throttle + idle);
|
|
const setArrivedState = (target) => {
|
|
var _a;
|
|
if (!window2) return;
|
|
const el =
|
|
((_a = target == null ? void 0 : target.document) == null
|
|
? void 0
|
|
: _a.documentElement) ||
|
|
(target == null ? void 0 : target.documentElement) ||
|
|
unrefElement(target);
|
|
const { display, flexDirection, direction } = getComputedStyle(el);
|
|
const directionMultipler = direction === 'rtl' ? -1 : 1;
|
|
const scrollLeft = el.scrollLeft;
|
|
directions.left = scrollLeft < internalX.value;
|
|
directions.right = scrollLeft > internalX.value;
|
|
const left =
|
|
Math.abs(scrollLeft * directionMultipler) <= (offset.left || 0);
|
|
const right =
|
|
Math.abs(scrollLeft * directionMultipler) + el.clientWidth >=
|
|
el.scrollWidth - (offset.right || 0) - ARRIVED_STATE_THRESHOLD_PIXELS;
|
|
if (display === 'flex' && flexDirection === 'row-reverse') {
|
|
arrivedState.left = right;
|
|
arrivedState.right = left;
|
|
} else {
|
|
arrivedState.left = left;
|
|
arrivedState.right = right;
|
|
}
|
|
internalX.value = scrollLeft;
|
|
let scrollTop = el.scrollTop;
|
|
if (target === window2.document && !scrollTop)
|
|
scrollTop = window2.document.body.scrollTop;
|
|
directions.top = scrollTop < internalY.value;
|
|
directions.bottom = scrollTop > internalY.value;
|
|
const top = Math.abs(scrollTop) <= (offset.top || 0);
|
|
const bottom =
|
|
Math.abs(scrollTop) + el.clientHeight >=
|
|
el.scrollHeight - (offset.bottom || 0) - ARRIVED_STATE_THRESHOLD_PIXELS;
|
|
if (display === 'flex' && flexDirection === 'column-reverse') {
|
|
arrivedState.top = bottom;
|
|
arrivedState.bottom = top;
|
|
} else {
|
|
arrivedState.top = top;
|
|
arrivedState.bottom = bottom;
|
|
}
|
|
internalY.value = scrollTop;
|
|
};
|
|
const onScrollHandler = (e) => {
|
|
var _a;
|
|
if (!window2) return;
|
|
const eventTarget = (_a = e.target.documentElement) != null ? _a : e.target;
|
|
setArrivedState(eventTarget);
|
|
isScrolling.value = true;
|
|
onScrollEndDebounced(e);
|
|
onScroll(e);
|
|
};
|
|
useEventListener(
|
|
element,
|
|
'scroll',
|
|
throttle
|
|
? useThrottleFn(onScrollHandler, throttle, true, false)
|
|
: onScrollHandler,
|
|
eventListenerOptions
|
|
);
|
|
tryOnMounted(() => {
|
|
try {
|
|
const _element = toValue(element);
|
|
if (!_element) return;
|
|
setArrivedState(_element);
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
});
|
|
useEventListener(element, 'scrollend', onScrollEnd, eventListenerOptions);
|
|
return {
|
|
x,
|
|
y,
|
|
isScrolling,
|
|
arrivedState,
|
|
directions,
|
|
measure() {
|
|
const _element = toValue(element);
|
|
if (window2 && _element) setArrivedState(_element);
|
|
},
|
|
};
|
|
}
|
|
function useInfiniteScroll(element, onLoadMore, options = {}) {
|
|
var _a;
|
|
const {
|
|
direction = 'bottom',
|
|
interval = 100,
|
|
canLoadMore = () => true,
|
|
} = options;
|
|
const state = reactive(
|
|
useScroll(element, {
|
|
...options,
|
|
offset: {
|
|
[direction]: (_a = options.distance) != null ? _a : 0,
|
|
...options.offset,
|
|
},
|
|
})
|
|
);
|
|
const promise = ref();
|
|
const isLoading = computed(() => !!promise.value);
|
|
const observedElement = computed(() => {
|
|
return resolveElement(toValue(element));
|
|
});
|
|
const isElementVisible = useElementVisibility(observedElement);
|
|
function checkAndLoad() {
|
|
state.measure();
|
|
if (
|
|
!observedElement.value ||
|
|
!isElementVisible.value ||
|
|
!canLoadMore(observedElement.value)
|
|
)
|
|
return;
|
|
const { scrollHeight, clientHeight, scrollWidth, clientWidth } =
|
|
observedElement.value;
|
|
const isNarrower =
|
|
direction === 'bottom' || direction === 'top'
|
|
? scrollHeight <= clientHeight
|
|
: scrollWidth <= clientWidth;
|
|
if (state.arrivedState[direction] || isNarrower) {
|
|
if (!promise.value) {
|
|
promise.value = Promise.all([
|
|
onLoadMore(state),
|
|
new Promise((resolve) => setTimeout(resolve, interval)),
|
|
]).finally(() => {
|
|
promise.value = null;
|
|
nextTick(() => checkAndLoad());
|
|
});
|
|
}
|
|
}
|
|
}
|
|
const stop = watch(
|
|
() => [state.arrivedState[direction], isElementVisible.value],
|
|
checkAndLoad,
|
|
{ immediate: true }
|
|
);
|
|
tryOnUnmounted(stop);
|
|
return {
|
|
isLoading,
|
|
reset() {
|
|
nextTick(() => checkAndLoad());
|
|
},
|
|
};
|
|
}
|
|
var defaultEvents = ['mousedown', 'mouseup', 'keydown', 'keyup'];
|
|
function useKeyModifier(modifier, options = {}) {
|
|
const {
|
|
events: events2 = defaultEvents,
|
|
document: document2 = defaultDocument,
|
|
initial = null,
|
|
} = options;
|
|
const state = shallowRef(initial);
|
|
if (document2) {
|
|
events2.forEach((listenerEvent) => {
|
|
useEventListener(
|
|
document2,
|
|
listenerEvent,
|
|
(evt) => {
|
|
if (typeof evt.getModifierState === 'function')
|
|
state.value = evt.getModifierState(modifier);
|
|
},
|
|
{ passive: true }
|
|
);
|
|
});
|
|
}
|
|
return state;
|
|
}
|
|
function useLocalStorage(key, initialValue, options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
return useStorage(
|
|
key,
|
|
initialValue,
|
|
window2 == null ? void 0 : window2.localStorage,
|
|
options
|
|
);
|
|
}
|
|
var DefaultMagicKeysAliasMap = {
|
|
ctrl: 'control',
|
|
command: 'meta',
|
|
cmd: 'meta',
|
|
option: 'alt',
|
|
up: 'arrowup',
|
|
down: 'arrowdown',
|
|
left: 'arrowleft',
|
|
right: 'arrowright',
|
|
};
|
|
function useMagicKeys(options = {}) {
|
|
const {
|
|
reactive: useReactive = false,
|
|
target = defaultWindow,
|
|
aliasMap = DefaultMagicKeysAliasMap,
|
|
passive = true,
|
|
onEventFired = noop,
|
|
} = options;
|
|
const current = reactive(/* @__PURE__ */ new Set());
|
|
const obj = {
|
|
toJSON() {
|
|
return {};
|
|
},
|
|
current,
|
|
};
|
|
const refs = useReactive ? reactive(obj) : obj;
|
|
const metaDeps = /* @__PURE__ */ new Set();
|
|
const usedKeys = /* @__PURE__ */ new Set();
|
|
function setRefs(key, value) {
|
|
if (key in refs) {
|
|
if (useReactive) refs[key] = value;
|
|
else refs[key].value = value;
|
|
}
|
|
}
|
|
function reset() {
|
|
current.clear();
|
|
for (const key of usedKeys) setRefs(key, false);
|
|
}
|
|
function updateRefs(e, value) {
|
|
var _a, _b;
|
|
const key = (_a = e.key) == null ? void 0 : _a.toLowerCase();
|
|
const code = (_b = e.code) == null ? void 0 : _b.toLowerCase();
|
|
const values = [code, key].filter(Boolean);
|
|
if (key) {
|
|
if (value) current.add(key);
|
|
else current.delete(key);
|
|
}
|
|
for (const key2 of values) {
|
|
usedKeys.add(key2);
|
|
setRefs(key2, value);
|
|
}
|
|
if (key === 'meta' && !value) {
|
|
metaDeps.forEach((key2) => {
|
|
current.delete(key2);
|
|
setRefs(key2, false);
|
|
});
|
|
metaDeps.clear();
|
|
} else if (
|
|
typeof e.getModifierState === 'function' &&
|
|
e.getModifierState('Meta') &&
|
|
value
|
|
) {
|
|
[...current, ...values].forEach((key2) => metaDeps.add(key2));
|
|
}
|
|
}
|
|
useEventListener(
|
|
target,
|
|
'keydown',
|
|
(e) => {
|
|
updateRefs(e, true);
|
|
return onEventFired(e);
|
|
},
|
|
{ passive }
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'keyup',
|
|
(e) => {
|
|
updateRefs(e, false);
|
|
return onEventFired(e);
|
|
},
|
|
{ passive }
|
|
);
|
|
useEventListener('blur', reset, { passive });
|
|
useEventListener('focus', reset, { passive });
|
|
const proxy = new Proxy(refs, {
|
|
get(target2, prop, rec) {
|
|
if (typeof prop !== 'string') return Reflect.get(target2, prop, rec);
|
|
prop = prop.toLowerCase();
|
|
if (prop in aliasMap) prop = aliasMap[prop];
|
|
if (!(prop in refs)) {
|
|
if (/[+_-]/.test(prop)) {
|
|
const keys2 = prop.split(/[+_-]/g).map((i) => i.trim());
|
|
refs[prop] = computed(() =>
|
|
keys2.map((key) => toValue(proxy[key])).every(Boolean)
|
|
);
|
|
} else {
|
|
refs[prop] = shallowRef(false);
|
|
}
|
|
}
|
|
const r = Reflect.get(target2, prop, rec);
|
|
return useReactive ? toValue(r) : r;
|
|
},
|
|
});
|
|
return proxy;
|
|
}
|
|
function usingElRef(source, cb) {
|
|
if (toValue(source)) cb(toValue(source));
|
|
}
|
|
function timeRangeToArray(timeRanges) {
|
|
let ranges = [];
|
|
for (let i = 0; i < timeRanges.length; ++i)
|
|
ranges = [...ranges, [timeRanges.start(i), timeRanges.end(i)]];
|
|
return ranges;
|
|
}
|
|
function tracksToArray(tracks) {
|
|
return Array.from(tracks).map(
|
|
(
|
|
{
|
|
label,
|
|
kind,
|
|
language,
|
|
mode,
|
|
activeCues,
|
|
cues,
|
|
inBandMetadataTrackDispatchType,
|
|
},
|
|
id
|
|
) => ({
|
|
id,
|
|
label,
|
|
kind,
|
|
language,
|
|
mode,
|
|
activeCues,
|
|
cues,
|
|
inBandMetadataTrackDispatchType,
|
|
})
|
|
);
|
|
}
|
|
var defaultOptions = {
|
|
src: '',
|
|
tracks: [],
|
|
};
|
|
function useMediaControls(target, options = {}) {
|
|
target = toRef2(target);
|
|
options = {
|
|
...defaultOptions,
|
|
...options,
|
|
};
|
|
const { document: document2 = defaultDocument } = options;
|
|
const listenerOptions = { passive: true };
|
|
const currentTime = shallowRef(0);
|
|
const duration = shallowRef(0);
|
|
const seeking = shallowRef(false);
|
|
const volume = shallowRef(1);
|
|
const waiting = shallowRef(false);
|
|
const ended = shallowRef(false);
|
|
const playing = shallowRef(false);
|
|
const rate = shallowRef(1);
|
|
const stalled = shallowRef(false);
|
|
const buffered = ref([]);
|
|
const tracks = ref([]);
|
|
const selectedTrack = shallowRef(-1);
|
|
const isPictureInPicture = shallowRef(false);
|
|
const muted = shallowRef(false);
|
|
const supportsPictureInPicture =
|
|
document2 && 'pictureInPictureEnabled' in document2;
|
|
const sourceErrorEvent = createEventHook();
|
|
const playbackErrorEvent = createEventHook();
|
|
const disableTrack = (track) => {
|
|
usingElRef(target, (el) => {
|
|
if (track) {
|
|
const id = typeof track === 'number' ? track : track.id;
|
|
el.textTracks[id].mode = 'disabled';
|
|
} else {
|
|
for (let i = 0; i < el.textTracks.length; ++i)
|
|
el.textTracks[i].mode = 'disabled';
|
|
}
|
|
selectedTrack.value = -1;
|
|
});
|
|
};
|
|
const enableTrack = (track, disableTracks = true) => {
|
|
usingElRef(target, (el) => {
|
|
const id = typeof track === 'number' ? track : track.id;
|
|
if (disableTracks) disableTrack();
|
|
el.textTracks[id].mode = 'showing';
|
|
selectedTrack.value = id;
|
|
});
|
|
};
|
|
const togglePictureInPicture = () => {
|
|
return new Promise((resolve, reject) => {
|
|
usingElRef(target, async (el) => {
|
|
if (supportsPictureInPicture) {
|
|
if (!isPictureInPicture.value) {
|
|
el.requestPictureInPicture().then(resolve).catch(reject);
|
|
} else {
|
|
document2.exitPictureInPicture().then(resolve).catch(reject);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
};
|
|
watchEffect(() => {
|
|
if (!document2) return;
|
|
const el = toValue(target);
|
|
if (!el) return;
|
|
const src = toValue(options.src);
|
|
let sources = [];
|
|
if (!src) return;
|
|
if (typeof src === 'string') sources = [{ src }];
|
|
else if (Array.isArray(src)) sources = src;
|
|
else if (isObject(src)) sources = [src];
|
|
el.querySelectorAll('source').forEach((e) => {
|
|
e.remove();
|
|
});
|
|
sources.forEach(({ src: src2, type, media }) => {
|
|
const source = document2.createElement('source');
|
|
source.setAttribute('src', src2);
|
|
source.setAttribute('type', type || '');
|
|
source.setAttribute('media', media || '');
|
|
useEventListener(
|
|
source,
|
|
'error',
|
|
sourceErrorEvent.trigger,
|
|
listenerOptions
|
|
);
|
|
el.appendChild(source);
|
|
});
|
|
el.load();
|
|
});
|
|
watch([target, volume], () => {
|
|
const el = toValue(target);
|
|
if (!el) return;
|
|
el.volume = volume.value;
|
|
});
|
|
watch([target, muted], () => {
|
|
const el = toValue(target);
|
|
if (!el) return;
|
|
el.muted = muted.value;
|
|
});
|
|
watch([target, rate], () => {
|
|
const el = toValue(target);
|
|
if (!el) return;
|
|
el.playbackRate = rate.value;
|
|
});
|
|
watchEffect(() => {
|
|
if (!document2) return;
|
|
const textTracks = toValue(options.tracks);
|
|
const el = toValue(target);
|
|
if (!textTracks || !textTracks.length || !el) return;
|
|
el.querySelectorAll('track').forEach((e) => e.remove());
|
|
textTracks.forEach(
|
|
({ default: isDefault, kind, label, src, srcLang }, i) => {
|
|
const track = document2.createElement('track');
|
|
track.default = isDefault || false;
|
|
track.kind = kind;
|
|
track.label = label;
|
|
track.src = src;
|
|
track.srclang = srcLang;
|
|
if (track.default) selectedTrack.value = i;
|
|
el.appendChild(track);
|
|
}
|
|
);
|
|
});
|
|
const { ignoreUpdates: ignoreCurrentTimeUpdates } = watchIgnorable(
|
|
currentTime,
|
|
(time) => {
|
|
const el = toValue(target);
|
|
if (!el) return;
|
|
el.currentTime = time;
|
|
}
|
|
);
|
|
const { ignoreUpdates: ignorePlayingUpdates } = watchIgnorable(
|
|
playing,
|
|
(isPlaying) => {
|
|
const el = toValue(target);
|
|
if (!el) return;
|
|
if (isPlaying) {
|
|
el.play().catch((e) => {
|
|
playbackErrorEvent.trigger(e);
|
|
throw e;
|
|
});
|
|
} else {
|
|
el.pause();
|
|
}
|
|
}
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'timeupdate',
|
|
() =>
|
|
ignoreCurrentTimeUpdates(
|
|
() => (currentTime.value = toValue(target).currentTime)
|
|
),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'durationchange',
|
|
() => (duration.value = toValue(target).duration),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'progress',
|
|
() => (buffered.value = timeRangeToArray(toValue(target).buffered)),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'seeking',
|
|
() => (seeking.value = true),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'seeked',
|
|
() => (seeking.value = false),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
['waiting', 'loadstart'],
|
|
() => {
|
|
waiting.value = true;
|
|
ignorePlayingUpdates(() => (playing.value = false));
|
|
},
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'loadeddata',
|
|
() => (waiting.value = false),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'playing',
|
|
() => {
|
|
waiting.value = false;
|
|
ended.value = false;
|
|
ignorePlayingUpdates(() => (playing.value = true));
|
|
},
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'ratechange',
|
|
() => (rate.value = toValue(target).playbackRate),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'stalled',
|
|
() => (stalled.value = true),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'ended',
|
|
() => (ended.value = true),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'pause',
|
|
() => ignorePlayingUpdates(() => (playing.value = false)),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'play',
|
|
() => ignorePlayingUpdates(() => (playing.value = true)),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'enterpictureinpicture',
|
|
() => (isPictureInPicture.value = true),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'leavepictureinpicture',
|
|
() => (isPictureInPicture.value = false),
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'volumechange',
|
|
() => {
|
|
const el = toValue(target);
|
|
if (!el) return;
|
|
volume.value = el.volume;
|
|
muted.value = el.muted;
|
|
},
|
|
listenerOptions
|
|
);
|
|
const listeners = [];
|
|
const stop = watch([target], () => {
|
|
const el = toValue(target);
|
|
if (!el) return;
|
|
stop();
|
|
listeners[0] = useEventListener(
|
|
el.textTracks,
|
|
'addtrack',
|
|
() => (tracks.value = tracksToArray(el.textTracks)),
|
|
listenerOptions
|
|
);
|
|
listeners[1] = useEventListener(
|
|
el.textTracks,
|
|
'removetrack',
|
|
() => (tracks.value = tracksToArray(el.textTracks)),
|
|
listenerOptions
|
|
);
|
|
listeners[2] = useEventListener(
|
|
el.textTracks,
|
|
'change',
|
|
() => (tracks.value = tracksToArray(el.textTracks)),
|
|
listenerOptions
|
|
);
|
|
});
|
|
tryOnScopeDispose(() => listeners.forEach((listener) => listener()));
|
|
return {
|
|
currentTime,
|
|
duration,
|
|
waiting,
|
|
seeking,
|
|
ended,
|
|
stalled,
|
|
buffered,
|
|
playing,
|
|
rate,
|
|
// Volume
|
|
volume,
|
|
muted,
|
|
// Tracks
|
|
tracks,
|
|
selectedTrack,
|
|
enableTrack,
|
|
disableTrack,
|
|
// Picture in Picture
|
|
supportsPictureInPicture,
|
|
togglePictureInPicture,
|
|
isPictureInPicture,
|
|
// Events
|
|
onSourceError: sourceErrorEvent.on,
|
|
onPlaybackError: playbackErrorEvent.on,
|
|
};
|
|
}
|
|
function useMemoize(resolver, options) {
|
|
const initCache = () => {
|
|
if (options == null ? void 0 : options.cache)
|
|
return shallowReactive(options.cache);
|
|
return shallowReactive(/* @__PURE__ */ new Map());
|
|
};
|
|
const cache = initCache();
|
|
const generateKey = (...args) =>
|
|
(options == null ? void 0 : options.getKey)
|
|
? options.getKey(...args)
|
|
: JSON.stringify(args);
|
|
const _loadData = (key, ...args) => {
|
|
cache.set(key, resolver(...args));
|
|
return cache.get(key);
|
|
};
|
|
const loadData = (...args) => _loadData(generateKey(...args), ...args);
|
|
const deleteData = (...args) => {
|
|
cache.delete(generateKey(...args));
|
|
};
|
|
const clearData = () => {
|
|
cache.clear();
|
|
};
|
|
const memoized = (...args) => {
|
|
const key = generateKey(...args);
|
|
if (cache.has(key)) return cache.get(key);
|
|
return _loadData(key, ...args);
|
|
};
|
|
memoized.load = loadData;
|
|
memoized.delete = deleteData;
|
|
memoized.clear = clearData;
|
|
memoized.generateKey = generateKey;
|
|
memoized.cache = cache;
|
|
return memoized;
|
|
}
|
|
function useMemory(options = {}) {
|
|
const memory = ref();
|
|
const isSupported = useSupported(
|
|
() => typeof performance !== 'undefined' && 'memory' in performance
|
|
);
|
|
if (isSupported.value) {
|
|
const { interval = 1e3 } = options;
|
|
useIntervalFn(
|
|
() => {
|
|
memory.value = performance.memory;
|
|
},
|
|
interval,
|
|
{
|
|
immediate: options.immediate,
|
|
immediateCallback: options.immediateCallback,
|
|
}
|
|
);
|
|
}
|
|
return { isSupported, memory };
|
|
}
|
|
var UseMouseBuiltinExtractors = {
|
|
page: (event) => [event.pageX, event.pageY],
|
|
client: (event) => [event.clientX, event.clientY],
|
|
screen: (event) => [event.screenX, event.screenY],
|
|
movement: (event) =>
|
|
event instanceof MouseEvent ? [event.movementX, event.movementY] : null,
|
|
};
|
|
function useMouse(options = {}) {
|
|
const {
|
|
type = 'page',
|
|
touch = true,
|
|
resetOnTouchEnds = false,
|
|
initialValue = { x: 0, y: 0 },
|
|
window: window2 = defaultWindow,
|
|
target = window2,
|
|
scroll = true,
|
|
eventFilter,
|
|
} = options;
|
|
let _prevMouseEvent = null;
|
|
let _prevScrollX = 0;
|
|
let _prevScrollY = 0;
|
|
const x = shallowRef(initialValue.x);
|
|
const y = shallowRef(initialValue.y);
|
|
const sourceType = shallowRef(null);
|
|
const extractor =
|
|
typeof type === 'function' ? type : UseMouseBuiltinExtractors[type];
|
|
const mouseHandler = (event) => {
|
|
const result = extractor(event);
|
|
_prevMouseEvent = event;
|
|
if (result) {
|
|
[x.value, y.value] = result;
|
|
sourceType.value = 'mouse';
|
|
}
|
|
if (window2) {
|
|
_prevScrollX = window2.scrollX;
|
|
_prevScrollY = window2.scrollY;
|
|
}
|
|
};
|
|
const touchHandler = (event) => {
|
|
if (event.touches.length > 0) {
|
|
const result = extractor(event.touches[0]);
|
|
if (result) {
|
|
[x.value, y.value] = result;
|
|
sourceType.value = 'touch';
|
|
}
|
|
}
|
|
};
|
|
const scrollHandler = () => {
|
|
if (!_prevMouseEvent || !window2) return;
|
|
const pos = extractor(_prevMouseEvent);
|
|
if (_prevMouseEvent instanceof MouseEvent && pos) {
|
|
x.value = pos[0] + window2.scrollX - _prevScrollX;
|
|
y.value = pos[1] + window2.scrollY - _prevScrollY;
|
|
}
|
|
};
|
|
const reset = () => {
|
|
x.value = initialValue.x;
|
|
y.value = initialValue.y;
|
|
};
|
|
const mouseHandlerWrapper = eventFilter
|
|
? (event) => eventFilter(() => mouseHandler(event), {})
|
|
: (event) => mouseHandler(event);
|
|
const touchHandlerWrapper = eventFilter
|
|
? (event) => eventFilter(() => touchHandler(event), {})
|
|
: (event) => touchHandler(event);
|
|
const scrollHandlerWrapper = eventFilter
|
|
? () => eventFilter(() => scrollHandler(), {})
|
|
: () => scrollHandler();
|
|
if (target) {
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
target,
|
|
['mousemove', 'dragover'],
|
|
mouseHandlerWrapper,
|
|
listenerOptions
|
|
);
|
|
if (touch && type !== 'movement') {
|
|
useEventListener(
|
|
target,
|
|
['touchstart', 'touchmove'],
|
|
touchHandlerWrapper,
|
|
listenerOptions
|
|
);
|
|
if (resetOnTouchEnds)
|
|
useEventListener(target, 'touchend', reset, listenerOptions);
|
|
}
|
|
if (scroll && type === 'page')
|
|
useEventListener(
|
|
window2,
|
|
'scroll',
|
|
scrollHandlerWrapper,
|
|
listenerOptions
|
|
);
|
|
}
|
|
return {
|
|
x,
|
|
y,
|
|
sourceType,
|
|
};
|
|
}
|
|
function useMouseInElement(target, options = {}) {
|
|
const { handleOutside = true, window: window2 = defaultWindow } = options;
|
|
const type = options.type || 'page';
|
|
const { x, y, sourceType } = useMouse(options);
|
|
const targetRef = shallowRef(
|
|
target != null ? target : window2 == null ? void 0 : window2.document.body
|
|
);
|
|
const elementX = shallowRef(0);
|
|
const elementY = shallowRef(0);
|
|
const elementPositionX = shallowRef(0);
|
|
const elementPositionY = shallowRef(0);
|
|
const elementHeight = shallowRef(0);
|
|
const elementWidth = shallowRef(0);
|
|
const isOutside = shallowRef(true);
|
|
let stop = () => {};
|
|
if (window2) {
|
|
stop = watch(
|
|
[targetRef, x, y],
|
|
() => {
|
|
const el = unrefElement(targetRef);
|
|
if (!el || !(el instanceof Element)) return;
|
|
const { left, top, width, height } = el.getBoundingClientRect();
|
|
elementPositionX.value =
|
|
left + (type === 'page' ? window2.pageXOffset : 0);
|
|
elementPositionY.value =
|
|
top + (type === 'page' ? window2.pageYOffset : 0);
|
|
elementHeight.value = height;
|
|
elementWidth.value = width;
|
|
const elX = x.value - elementPositionX.value;
|
|
const elY = y.value - elementPositionY.value;
|
|
isOutside.value =
|
|
width === 0 ||
|
|
height === 0 ||
|
|
elX < 0 ||
|
|
elY < 0 ||
|
|
elX > width ||
|
|
elY > height;
|
|
if (handleOutside || !isOutside.value) {
|
|
elementX.value = elX;
|
|
elementY.value = elY;
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
useEventListener(document, 'mouseleave', () => (isOutside.value = true), {
|
|
passive: true,
|
|
});
|
|
}
|
|
return {
|
|
x,
|
|
y,
|
|
sourceType,
|
|
elementX,
|
|
elementY,
|
|
elementPositionX,
|
|
elementPositionY,
|
|
elementHeight,
|
|
elementWidth,
|
|
isOutside,
|
|
stop,
|
|
};
|
|
}
|
|
function useMousePressed(options = {}) {
|
|
const {
|
|
touch = true,
|
|
drag = true,
|
|
capture = false,
|
|
initialValue = false,
|
|
window: window2 = defaultWindow,
|
|
} = options;
|
|
const pressed = shallowRef(initialValue);
|
|
const sourceType = shallowRef(null);
|
|
if (!window2) {
|
|
return {
|
|
pressed,
|
|
sourceType,
|
|
};
|
|
}
|
|
const onPressed = (srcType) => (event) => {
|
|
var _a;
|
|
pressed.value = true;
|
|
sourceType.value = srcType;
|
|
(_a = options.onPressed) == null ? void 0 : _a.call(options, event);
|
|
};
|
|
const onReleased = (event) => {
|
|
var _a;
|
|
pressed.value = false;
|
|
sourceType.value = null;
|
|
(_a = options.onReleased) == null ? void 0 : _a.call(options, event);
|
|
};
|
|
const target = computed(() => unrefElement(options.target) || window2);
|
|
const listenerOptions = { passive: true, capture };
|
|
useEventListener(target, 'mousedown', onPressed('mouse'), listenerOptions);
|
|
useEventListener(window2, 'mouseleave', onReleased, listenerOptions);
|
|
useEventListener(window2, 'mouseup', onReleased, listenerOptions);
|
|
if (drag) {
|
|
useEventListener(target, 'dragstart', onPressed('mouse'), listenerOptions);
|
|
useEventListener(window2, 'drop', onReleased, listenerOptions);
|
|
useEventListener(window2, 'dragend', onReleased, listenerOptions);
|
|
}
|
|
if (touch) {
|
|
useEventListener(target, 'touchstart', onPressed('touch'), listenerOptions);
|
|
useEventListener(window2, 'touchend', onReleased, listenerOptions);
|
|
useEventListener(window2, 'touchcancel', onReleased, listenerOptions);
|
|
}
|
|
return {
|
|
pressed,
|
|
sourceType,
|
|
};
|
|
}
|
|
function useNavigatorLanguage(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const navigator2 = window2 == null ? void 0 : window2.navigator;
|
|
const isSupported = useSupported(
|
|
() => navigator2 && 'language' in navigator2
|
|
);
|
|
const language = shallowRef(
|
|
navigator2 == null ? void 0 : navigator2.language
|
|
);
|
|
useEventListener(
|
|
window2,
|
|
'languagechange',
|
|
() => {
|
|
if (navigator2) language.value = navigator2.language;
|
|
},
|
|
{ passive: true }
|
|
);
|
|
return {
|
|
isSupported,
|
|
language,
|
|
};
|
|
}
|
|
function useNetwork(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const navigator2 = window2 == null ? void 0 : window2.navigator;
|
|
const isSupported = useSupported(
|
|
() => navigator2 && 'connection' in navigator2
|
|
);
|
|
const isOnline = shallowRef(true);
|
|
const saveData = shallowRef(false);
|
|
const offlineAt = shallowRef(void 0);
|
|
const onlineAt = shallowRef(void 0);
|
|
const downlink = shallowRef(void 0);
|
|
const downlinkMax = shallowRef(void 0);
|
|
const rtt = shallowRef(void 0);
|
|
const effectiveType = shallowRef(void 0);
|
|
const type = shallowRef('unknown');
|
|
const connection = isSupported.value && navigator2.connection;
|
|
function updateNetworkInformation() {
|
|
if (!navigator2) return;
|
|
isOnline.value = navigator2.onLine;
|
|
offlineAt.value = isOnline.value ? void 0 : Date.now();
|
|
onlineAt.value = isOnline.value ? Date.now() : void 0;
|
|
if (connection) {
|
|
downlink.value = connection.downlink;
|
|
downlinkMax.value = connection.downlinkMax;
|
|
effectiveType.value = connection.effectiveType;
|
|
rtt.value = connection.rtt;
|
|
saveData.value = connection.saveData;
|
|
type.value = connection.type;
|
|
}
|
|
}
|
|
const listenerOptions = { passive: true };
|
|
if (window2) {
|
|
useEventListener(
|
|
window2,
|
|
'offline',
|
|
() => {
|
|
isOnline.value = false;
|
|
offlineAt.value = Date.now();
|
|
},
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
window2,
|
|
'online',
|
|
() => {
|
|
isOnline.value = true;
|
|
onlineAt.value = Date.now();
|
|
},
|
|
listenerOptions
|
|
);
|
|
}
|
|
if (connection)
|
|
useEventListener(
|
|
connection,
|
|
'change',
|
|
updateNetworkInformation,
|
|
listenerOptions
|
|
);
|
|
updateNetworkInformation();
|
|
return {
|
|
isSupported,
|
|
isOnline: readonly(isOnline),
|
|
saveData: readonly(saveData),
|
|
offlineAt: readonly(offlineAt),
|
|
onlineAt: readonly(onlineAt),
|
|
downlink: readonly(downlink),
|
|
downlinkMax: readonly(downlinkMax),
|
|
effectiveType: readonly(effectiveType),
|
|
rtt: readonly(rtt),
|
|
type: readonly(type),
|
|
};
|
|
}
|
|
function useNow(options = {}) {
|
|
const {
|
|
controls: exposeControls = false,
|
|
interval = 'requestAnimationFrame',
|
|
} = options;
|
|
const now2 = ref(/* @__PURE__ */ new Date());
|
|
const update = () => (now2.value = /* @__PURE__ */ new Date());
|
|
const controls =
|
|
interval === 'requestAnimationFrame'
|
|
? useRafFn(update, { immediate: true })
|
|
: useIntervalFn(update, interval, { immediate: true });
|
|
if (exposeControls) {
|
|
return {
|
|
now: now2,
|
|
...controls,
|
|
};
|
|
} else {
|
|
return now2;
|
|
}
|
|
}
|
|
function useObjectUrl(object) {
|
|
const url = shallowRef();
|
|
const release = () => {
|
|
if (url.value) URL.revokeObjectURL(url.value);
|
|
url.value = void 0;
|
|
};
|
|
watch(
|
|
() => toValue(object),
|
|
(newObject) => {
|
|
release();
|
|
if (newObject) url.value = URL.createObjectURL(newObject);
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
tryOnScopeDispose(release);
|
|
return readonly(url);
|
|
}
|
|
function useClamp(value, min, max) {
|
|
if (typeof value === 'function' || isReadonly(value))
|
|
return computed(() => clamp(toValue(value), toValue(min), toValue(max)));
|
|
const _value = ref(value);
|
|
return computed({
|
|
get() {
|
|
return (_value.value = clamp(_value.value, toValue(min), toValue(max)));
|
|
},
|
|
set(value2) {
|
|
_value.value = clamp(value2, toValue(min), toValue(max));
|
|
},
|
|
});
|
|
}
|
|
function useOffsetPagination(options) {
|
|
const {
|
|
total = Number.POSITIVE_INFINITY,
|
|
pageSize = 10,
|
|
page = 1,
|
|
onPageChange = noop,
|
|
onPageSizeChange = noop,
|
|
onPageCountChange = noop,
|
|
} = options;
|
|
const currentPageSize = useClamp(pageSize, 1, Number.POSITIVE_INFINITY);
|
|
const pageCount = computed(() =>
|
|
Math.max(1, Math.ceil(toValue(total) / toValue(currentPageSize)))
|
|
);
|
|
const currentPage = useClamp(page, 1, pageCount);
|
|
const isFirstPage = computed(() => currentPage.value === 1);
|
|
const isLastPage = computed(() => currentPage.value === pageCount.value);
|
|
if (isRef(page)) {
|
|
syncRef(page, currentPage, {
|
|
direction: isReadonly(page) ? 'ltr' : 'both',
|
|
});
|
|
}
|
|
if (isRef(pageSize)) {
|
|
syncRef(pageSize, currentPageSize, {
|
|
direction: isReadonly(pageSize) ? 'ltr' : 'both',
|
|
});
|
|
}
|
|
function prev() {
|
|
currentPage.value--;
|
|
}
|
|
function next() {
|
|
currentPage.value++;
|
|
}
|
|
const returnValue = {
|
|
currentPage,
|
|
currentPageSize,
|
|
pageCount,
|
|
isFirstPage,
|
|
isLastPage,
|
|
prev,
|
|
next,
|
|
};
|
|
watch(currentPage, () => {
|
|
onPageChange(reactive(returnValue));
|
|
});
|
|
watch(currentPageSize, () => {
|
|
onPageSizeChange(reactive(returnValue));
|
|
});
|
|
watch(pageCount, () => {
|
|
onPageCountChange(reactive(returnValue));
|
|
});
|
|
return returnValue;
|
|
}
|
|
function useOnline(options = {}) {
|
|
const { isOnline } = useNetwork(options);
|
|
return isOnline;
|
|
}
|
|
function usePageLeave(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const isLeft = shallowRef(false);
|
|
const handler = (event) => {
|
|
if (!window2) return;
|
|
event = event || window2.event;
|
|
const from = event.relatedTarget || event.toElement;
|
|
isLeft.value = !from;
|
|
};
|
|
if (window2) {
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(window2, 'mouseout', handler, listenerOptions);
|
|
useEventListener(window2.document, 'mouseleave', handler, listenerOptions);
|
|
useEventListener(window2.document, 'mouseenter', handler, listenerOptions);
|
|
}
|
|
return isLeft;
|
|
}
|
|
function useScreenOrientation(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const isSupported = useSupported(
|
|
() => window2 && 'screen' in window2 && 'orientation' in window2.screen
|
|
);
|
|
const screenOrientation = isSupported.value ? window2.screen.orientation : {};
|
|
const orientation = ref(screenOrientation.type);
|
|
const angle = shallowRef(screenOrientation.angle || 0);
|
|
if (isSupported.value) {
|
|
useEventListener(
|
|
window2,
|
|
'orientationchange',
|
|
() => {
|
|
orientation.value = screenOrientation.type;
|
|
angle.value = screenOrientation.angle;
|
|
},
|
|
{ passive: true }
|
|
);
|
|
}
|
|
const lockOrientation = (type) => {
|
|
if (isSupported.value && typeof screenOrientation.lock === 'function')
|
|
return screenOrientation.lock(type);
|
|
return Promise.reject(new Error('Not supported'));
|
|
};
|
|
const unlockOrientation = () => {
|
|
if (isSupported.value && typeof screenOrientation.unlock === 'function')
|
|
screenOrientation.unlock();
|
|
};
|
|
return {
|
|
isSupported,
|
|
orientation,
|
|
angle,
|
|
lockOrientation,
|
|
unlockOrientation,
|
|
};
|
|
}
|
|
function useParallax(target, options = {}) {
|
|
const {
|
|
deviceOrientationTiltAdjust = (i) => i,
|
|
deviceOrientationRollAdjust = (i) => i,
|
|
mouseTiltAdjust = (i) => i,
|
|
mouseRollAdjust = (i) => i,
|
|
window: window2 = defaultWindow,
|
|
} = options;
|
|
const orientation = reactive(useDeviceOrientation({ window: window2 }));
|
|
const screenOrientation = reactive(useScreenOrientation({ window: window2 }));
|
|
const {
|
|
elementX: x,
|
|
elementY: y,
|
|
elementWidth: width,
|
|
elementHeight: height,
|
|
} = useMouseInElement(target, { handleOutside: false, window: window2 });
|
|
const source = computed(() => {
|
|
if (
|
|
orientation.isSupported &&
|
|
((orientation.alpha != null && orientation.alpha !== 0) ||
|
|
(orientation.gamma != null && orientation.gamma !== 0))
|
|
) {
|
|
return 'deviceOrientation';
|
|
}
|
|
return 'mouse';
|
|
});
|
|
const roll = computed(() => {
|
|
if (source.value === 'deviceOrientation') {
|
|
let value;
|
|
switch (screenOrientation.orientation) {
|
|
case 'landscape-primary':
|
|
value = orientation.gamma / 90;
|
|
break;
|
|
case 'landscape-secondary':
|
|
value = -orientation.gamma / 90;
|
|
break;
|
|
case 'portrait-primary':
|
|
value = -orientation.beta / 90;
|
|
break;
|
|
case 'portrait-secondary':
|
|
value = orientation.beta / 90;
|
|
break;
|
|
default:
|
|
value = -orientation.beta / 90;
|
|
}
|
|
return deviceOrientationRollAdjust(value);
|
|
} else {
|
|
const value = -(y.value - height.value / 2) / height.value;
|
|
return mouseRollAdjust(value);
|
|
}
|
|
});
|
|
const tilt = computed(() => {
|
|
if (source.value === 'deviceOrientation') {
|
|
let value;
|
|
switch (screenOrientation.orientation) {
|
|
case 'landscape-primary':
|
|
value = orientation.beta / 90;
|
|
break;
|
|
case 'landscape-secondary':
|
|
value = -orientation.beta / 90;
|
|
break;
|
|
case 'portrait-primary':
|
|
value = orientation.gamma / 90;
|
|
break;
|
|
case 'portrait-secondary':
|
|
value = -orientation.gamma / 90;
|
|
break;
|
|
default:
|
|
value = orientation.gamma / 90;
|
|
}
|
|
return deviceOrientationTiltAdjust(value);
|
|
} else {
|
|
const value = (x.value - width.value / 2) / width.value;
|
|
return mouseTiltAdjust(value);
|
|
}
|
|
});
|
|
return { roll, tilt, source };
|
|
}
|
|
function useParentElement(element = useCurrentElement()) {
|
|
const parentElement = shallowRef();
|
|
const update = () => {
|
|
const el = unrefElement(element);
|
|
if (el) parentElement.value = el.parentElement;
|
|
};
|
|
tryOnMounted(update);
|
|
watch(() => toValue(element), update);
|
|
return parentElement;
|
|
}
|
|
function usePerformanceObserver(options, callback) {
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
immediate = true,
|
|
...performanceOptions
|
|
} = options;
|
|
const isSupported = useSupported(
|
|
() => window2 && 'PerformanceObserver' in window2
|
|
);
|
|
let observer;
|
|
const stop = () => {
|
|
observer == null ? void 0 : observer.disconnect();
|
|
};
|
|
const start = () => {
|
|
if (isSupported.value) {
|
|
stop();
|
|
observer = new PerformanceObserver(callback);
|
|
observer.observe(performanceOptions);
|
|
}
|
|
};
|
|
tryOnScopeDispose(stop);
|
|
if (immediate) start();
|
|
return {
|
|
isSupported,
|
|
start,
|
|
stop,
|
|
};
|
|
}
|
|
var defaultState = {
|
|
x: 0,
|
|
y: 0,
|
|
pointerId: 0,
|
|
pressure: 0,
|
|
tiltX: 0,
|
|
tiltY: 0,
|
|
width: 0,
|
|
height: 0,
|
|
twist: 0,
|
|
pointerType: null,
|
|
};
|
|
var keys = Object.keys(defaultState);
|
|
function usePointer(options = {}) {
|
|
const { target = defaultWindow } = options;
|
|
const isInside = shallowRef(false);
|
|
const state = ref(options.initialValue || {});
|
|
Object.assign(state.value, defaultState, state.value);
|
|
const handler = (event) => {
|
|
isInside.value = true;
|
|
if (
|
|
options.pointerTypes &&
|
|
!options.pointerTypes.includes(event.pointerType)
|
|
)
|
|
return;
|
|
state.value = objectPick(event, keys, false);
|
|
};
|
|
if (target) {
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
target,
|
|
['pointerdown', 'pointermove', 'pointerup'],
|
|
handler,
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
target,
|
|
'pointerleave',
|
|
() => (isInside.value = false),
|
|
listenerOptions
|
|
);
|
|
}
|
|
return {
|
|
...toRefs2(state),
|
|
isInside,
|
|
};
|
|
}
|
|
function usePointerLock(target, options = {}) {
|
|
const { document: document2 = defaultDocument } = options;
|
|
const isSupported = useSupported(
|
|
() => document2 && 'pointerLockElement' in document2
|
|
);
|
|
const element = shallowRef();
|
|
const triggerElement = shallowRef();
|
|
let targetElement;
|
|
if (isSupported.value) {
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
document2,
|
|
'pointerlockchange',
|
|
() => {
|
|
var _a;
|
|
const currentElement =
|
|
(_a = document2.pointerLockElement) != null ? _a : element.value;
|
|
if (targetElement && currentElement === targetElement) {
|
|
element.value = document2.pointerLockElement;
|
|
if (!element.value) targetElement = triggerElement.value = null;
|
|
}
|
|
},
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
document2,
|
|
'pointerlockerror',
|
|
() => {
|
|
var _a;
|
|
const currentElement =
|
|
(_a = document2.pointerLockElement) != null ? _a : element.value;
|
|
if (targetElement && currentElement === targetElement) {
|
|
const action = document2.pointerLockElement ? 'release' : 'acquire';
|
|
throw new Error(`Failed to ${action} pointer lock.`);
|
|
}
|
|
},
|
|
listenerOptions
|
|
);
|
|
}
|
|
async function lock(e) {
|
|
var _a;
|
|
if (!isSupported.value)
|
|
throw new Error('Pointer Lock API is not supported by your browser.');
|
|
triggerElement.value = e instanceof Event ? e.currentTarget : null;
|
|
targetElement =
|
|
e instanceof Event
|
|
? (_a = unrefElement(target)) != null
|
|
? _a
|
|
: triggerElement.value
|
|
: unrefElement(e);
|
|
if (!targetElement) throw new Error('Target element undefined.');
|
|
targetElement.requestPointerLock();
|
|
return await until(element).toBe(targetElement);
|
|
}
|
|
async function unlock() {
|
|
if (!element.value) return false;
|
|
document2.exitPointerLock();
|
|
await until(element).toBeNull();
|
|
return true;
|
|
}
|
|
return {
|
|
isSupported,
|
|
element,
|
|
triggerElement,
|
|
lock,
|
|
unlock,
|
|
};
|
|
}
|
|
function usePointerSwipe(target, options = {}) {
|
|
const targetRef = toRef2(target);
|
|
const {
|
|
threshold = 50,
|
|
onSwipe,
|
|
onSwipeEnd,
|
|
onSwipeStart,
|
|
disableTextSelect = false,
|
|
} = options;
|
|
const posStart = reactive({ x: 0, y: 0 });
|
|
const updatePosStart = (x, y) => {
|
|
posStart.x = x;
|
|
posStart.y = y;
|
|
};
|
|
const posEnd = reactive({ x: 0, y: 0 });
|
|
const updatePosEnd = (x, y) => {
|
|
posEnd.x = x;
|
|
posEnd.y = y;
|
|
};
|
|
const distanceX = computed(() => posStart.x - posEnd.x);
|
|
const distanceY = computed(() => posStart.y - posEnd.y);
|
|
const { max, abs } = Math;
|
|
const isThresholdExceeded = computed(
|
|
() => max(abs(distanceX.value), abs(distanceY.value)) >= threshold
|
|
);
|
|
const isSwiping = shallowRef(false);
|
|
const isPointerDown = shallowRef(false);
|
|
const direction = computed(() => {
|
|
if (!isThresholdExceeded.value) return 'none';
|
|
if (abs(distanceX.value) > abs(distanceY.value)) {
|
|
return distanceX.value > 0 ? 'left' : 'right';
|
|
} else {
|
|
return distanceY.value > 0 ? 'up' : 'down';
|
|
}
|
|
});
|
|
const eventIsAllowed = (e) => {
|
|
var _a, _b, _c;
|
|
const isReleasingButton = e.buttons === 0;
|
|
const isPrimaryButton = e.buttons === 1;
|
|
return (_c =
|
|
(_b =
|
|
(_a = options.pointerTypes) == null
|
|
? void 0
|
|
: _a.includes(e.pointerType)) != null
|
|
? _b
|
|
: isReleasingButton || isPrimaryButton) != null
|
|
? _c
|
|
: true;
|
|
};
|
|
const listenerOptions = { passive: true };
|
|
const stops = [
|
|
useEventListener(
|
|
target,
|
|
'pointerdown',
|
|
(e) => {
|
|
if (!eventIsAllowed(e)) return;
|
|
isPointerDown.value = true;
|
|
const eventTarget = e.target;
|
|
eventTarget == null
|
|
? void 0
|
|
: eventTarget.setPointerCapture(e.pointerId);
|
|
const { clientX: x, clientY: y } = e;
|
|
updatePosStart(x, y);
|
|
updatePosEnd(x, y);
|
|
onSwipeStart == null ? void 0 : onSwipeStart(e);
|
|
},
|
|
listenerOptions
|
|
),
|
|
useEventListener(
|
|
target,
|
|
'pointermove',
|
|
(e) => {
|
|
if (!eventIsAllowed(e)) return;
|
|
if (!isPointerDown.value) return;
|
|
const { clientX: x, clientY: y } = e;
|
|
updatePosEnd(x, y);
|
|
if (!isSwiping.value && isThresholdExceeded.value)
|
|
isSwiping.value = true;
|
|
if (isSwiping.value) onSwipe == null ? void 0 : onSwipe(e);
|
|
},
|
|
listenerOptions
|
|
),
|
|
useEventListener(
|
|
target,
|
|
'pointerup',
|
|
(e) => {
|
|
if (!eventIsAllowed(e)) return;
|
|
if (isSwiping.value)
|
|
onSwipeEnd == null ? void 0 : onSwipeEnd(e, direction.value);
|
|
isPointerDown.value = false;
|
|
isSwiping.value = false;
|
|
},
|
|
listenerOptions
|
|
),
|
|
];
|
|
tryOnMounted(() => {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
(_b = (_a = targetRef.value) == null ? void 0 : _a.style) == null
|
|
? void 0
|
|
: _b.setProperty('touch-action', 'none');
|
|
if (disableTextSelect) {
|
|
(_d = (_c = targetRef.value) == null ? void 0 : _c.style) == null
|
|
? void 0
|
|
: _d.setProperty('-webkit-user-select', 'none');
|
|
(_f = (_e = targetRef.value) == null ? void 0 : _e.style) == null
|
|
? void 0
|
|
: _f.setProperty('-ms-user-select', 'none');
|
|
(_h = (_g = targetRef.value) == null ? void 0 : _g.style) == null
|
|
? void 0
|
|
: _h.setProperty('user-select', 'none');
|
|
}
|
|
});
|
|
const stop = () => stops.forEach((s) => s());
|
|
return {
|
|
isSwiping: readonly(isSwiping),
|
|
direction: readonly(direction),
|
|
posStart: readonly(posStart),
|
|
posEnd: readonly(posEnd),
|
|
distanceX,
|
|
distanceY,
|
|
stop,
|
|
};
|
|
}
|
|
function usePreferredColorScheme(options) {
|
|
const isLight = useMediaQuery('(prefers-color-scheme: light)', options);
|
|
const isDark = useMediaQuery('(prefers-color-scheme: dark)', options);
|
|
return computed(() => {
|
|
if (isDark.value) return 'dark';
|
|
if (isLight.value) return 'light';
|
|
return 'no-preference';
|
|
});
|
|
}
|
|
function usePreferredContrast(options) {
|
|
const isMore = useMediaQuery('(prefers-contrast: more)', options);
|
|
const isLess = useMediaQuery('(prefers-contrast: less)', options);
|
|
const isCustom = useMediaQuery('(prefers-contrast: custom)', options);
|
|
return computed(() => {
|
|
if (isMore.value) return 'more';
|
|
if (isLess.value) return 'less';
|
|
if (isCustom.value) return 'custom';
|
|
return 'no-preference';
|
|
});
|
|
}
|
|
function usePreferredLanguages(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
if (!window2) return ref(['en']);
|
|
const navigator2 = window2.navigator;
|
|
const value = ref(navigator2.languages);
|
|
useEventListener(
|
|
window2,
|
|
'languagechange',
|
|
() => {
|
|
value.value = navigator2.languages;
|
|
},
|
|
{ passive: true }
|
|
);
|
|
return value;
|
|
}
|
|
function usePreferredReducedMotion(options) {
|
|
const isReduced = useMediaQuery('(prefers-reduced-motion: reduce)', options);
|
|
return computed(() => {
|
|
if (isReduced.value) return 'reduce';
|
|
return 'no-preference';
|
|
});
|
|
}
|
|
function usePreferredReducedTransparency(options) {
|
|
const isReduced = useMediaQuery(
|
|
'(prefers-reduced-transparency: reduce)',
|
|
options
|
|
);
|
|
return computed(() => {
|
|
if (isReduced.value) return 'reduce';
|
|
return 'no-preference';
|
|
});
|
|
}
|
|
function usePrevious(value, initialValue) {
|
|
const previous = shallowRef(initialValue);
|
|
watch(
|
|
toRef2(value),
|
|
(_, oldValue) => {
|
|
previous.value = oldValue;
|
|
},
|
|
{ flush: 'sync' }
|
|
);
|
|
return readonly(previous);
|
|
}
|
|
var topVarName = '--vueuse-safe-area-top';
|
|
var rightVarName = '--vueuse-safe-area-right';
|
|
var bottomVarName = '--vueuse-safe-area-bottom';
|
|
var leftVarName = '--vueuse-safe-area-left';
|
|
function useScreenSafeArea() {
|
|
const top = shallowRef('');
|
|
const right = shallowRef('');
|
|
const bottom = shallowRef('');
|
|
const left = shallowRef('');
|
|
if (isClient) {
|
|
const topCssVar = useCssVar(topVarName);
|
|
const rightCssVar = useCssVar(rightVarName);
|
|
const bottomCssVar = useCssVar(bottomVarName);
|
|
const leftCssVar = useCssVar(leftVarName);
|
|
topCssVar.value = 'env(safe-area-inset-top, 0px)';
|
|
rightCssVar.value = 'env(safe-area-inset-right, 0px)';
|
|
bottomCssVar.value = 'env(safe-area-inset-bottom, 0px)';
|
|
leftCssVar.value = 'env(safe-area-inset-left, 0px)';
|
|
update();
|
|
useEventListener('resize', useDebounceFn(update), { passive: true });
|
|
}
|
|
function update() {
|
|
top.value = getValue(topVarName);
|
|
right.value = getValue(rightVarName);
|
|
bottom.value = getValue(bottomVarName);
|
|
left.value = getValue(leftVarName);
|
|
}
|
|
return {
|
|
top,
|
|
right,
|
|
bottom,
|
|
left,
|
|
update,
|
|
};
|
|
}
|
|
function getValue(position) {
|
|
return getComputedStyle(document.documentElement).getPropertyValue(position);
|
|
}
|
|
function useScriptTag(src, onLoaded = noop, options = {}) {
|
|
const {
|
|
immediate = true,
|
|
manual = false,
|
|
type = 'text/javascript',
|
|
async = true,
|
|
crossOrigin,
|
|
referrerPolicy,
|
|
noModule,
|
|
defer,
|
|
document: document2 = defaultDocument,
|
|
attrs = {},
|
|
} = options;
|
|
const scriptTag = shallowRef(null);
|
|
let _promise = null;
|
|
const loadScript = (waitForScriptLoad) =>
|
|
new Promise((resolve, reject) => {
|
|
const resolveWithElement = (el2) => {
|
|
scriptTag.value = el2;
|
|
resolve(el2);
|
|
return el2;
|
|
};
|
|
if (!document2) {
|
|
resolve(false);
|
|
return;
|
|
}
|
|
let shouldAppend = false;
|
|
let el = document2.querySelector(`script[src="${toValue(src)}"]`);
|
|
if (!el) {
|
|
el = document2.createElement('script');
|
|
el.type = type;
|
|
el.async = async;
|
|
el.src = toValue(src);
|
|
if (defer) el.defer = defer;
|
|
if (crossOrigin) el.crossOrigin = crossOrigin;
|
|
if (noModule) el.noModule = noModule;
|
|
if (referrerPolicy) el.referrerPolicy = referrerPolicy;
|
|
Object.entries(attrs).forEach(([name, value]) =>
|
|
el == null ? void 0 : el.setAttribute(name, value)
|
|
);
|
|
shouldAppend = true;
|
|
} else if (el.hasAttribute('data-loaded')) {
|
|
resolveWithElement(el);
|
|
}
|
|
const listenerOptions = {
|
|
passive: true,
|
|
};
|
|
useEventListener(el, 'error', (event) => reject(event), listenerOptions);
|
|
useEventListener(el, 'abort', (event) => reject(event), listenerOptions);
|
|
useEventListener(
|
|
el,
|
|
'load',
|
|
() => {
|
|
el.setAttribute('data-loaded', 'true');
|
|
onLoaded(el);
|
|
resolveWithElement(el);
|
|
},
|
|
listenerOptions
|
|
);
|
|
if (shouldAppend) el = document2.head.appendChild(el);
|
|
if (!waitForScriptLoad) resolveWithElement(el);
|
|
});
|
|
const load = (waitForScriptLoad = true) => {
|
|
if (!_promise) _promise = loadScript(waitForScriptLoad);
|
|
return _promise;
|
|
};
|
|
const unload = () => {
|
|
if (!document2) return;
|
|
_promise = null;
|
|
if (scriptTag.value) scriptTag.value = null;
|
|
const el = document2.querySelector(`script[src="${toValue(src)}"]`);
|
|
if (el) document2.head.removeChild(el);
|
|
};
|
|
if (immediate && !manual) tryOnMounted(load);
|
|
if (!manual) tryOnUnmounted(unload);
|
|
return { scriptTag, load, unload };
|
|
}
|
|
function checkOverflowScroll(ele) {
|
|
const style = window.getComputedStyle(ele);
|
|
if (
|
|
style.overflowX === 'scroll' ||
|
|
style.overflowY === 'scroll' ||
|
|
(style.overflowX === 'auto' && ele.clientWidth < ele.scrollWidth) ||
|
|
(style.overflowY === 'auto' && ele.clientHeight < ele.scrollHeight)
|
|
) {
|
|
return true;
|
|
} else {
|
|
const parent = ele.parentNode;
|
|
if (!parent || parent.tagName === 'BODY') return false;
|
|
return checkOverflowScroll(parent);
|
|
}
|
|
}
|
|
function preventDefault(rawEvent) {
|
|
const e = rawEvent || window.event;
|
|
const _target = e.target;
|
|
if (checkOverflowScroll(_target)) return false;
|
|
if (e.touches.length > 1) return true;
|
|
if (e.preventDefault) e.preventDefault();
|
|
return false;
|
|
}
|
|
var elInitialOverflow = /* @__PURE__ */ new WeakMap();
|
|
function useScrollLock(element, initialState = false) {
|
|
const isLocked = shallowRef(initialState);
|
|
let stopTouchMoveListener = null;
|
|
let initialOverflow = '';
|
|
watch(
|
|
toRef2(element),
|
|
(el) => {
|
|
const target = resolveElement(toValue(el));
|
|
if (target) {
|
|
const ele = target;
|
|
if (!elInitialOverflow.get(ele))
|
|
elInitialOverflow.set(ele, ele.style.overflow);
|
|
if (ele.style.overflow !== 'hidden')
|
|
initialOverflow = ele.style.overflow;
|
|
if (ele.style.overflow === 'hidden') return (isLocked.value = true);
|
|
if (isLocked.value) return (ele.style.overflow = 'hidden');
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
}
|
|
);
|
|
const lock = () => {
|
|
const el = resolveElement(toValue(element));
|
|
if (!el || isLocked.value) return;
|
|
if (isIOS) {
|
|
stopTouchMoveListener = useEventListener(
|
|
el,
|
|
'touchmove',
|
|
(e) => {
|
|
preventDefault(e);
|
|
},
|
|
{ passive: false }
|
|
);
|
|
}
|
|
el.style.overflow = 'hidden';
|
|
isLocked.value = true;
|
|
};
|
|
const unlock = () => {
|
|
const el = resolveElement(toValue(element));
|
|
if (!el || !isLocked.value) return;
|
|
if (isIOS) stopTouchMoveListener == null ? void 0 : stopTouchMoveListener();
|
|
el.style.overflow = initialOverflow;
|
|
elInitialOverflow.delete(el);
|
|
isLocked.value = false;
|
|
};
|
|
tryOnScopeDispose(unlock);
|
|
return computed({
|
|
get() {
|
|
return isLocked.value;
|
|
},
|
|
set(v) {
|
|
if (v) lock();
|
|
else unlock();
|
|
},
|
|
});
|
|
}
|
|
function useSessionStorage(key, initialValue, options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
return useStorage(
|
|
key,
|
|
initialValue,
|
|
window2 == null ? void 0 : window2.sessionStorage,
|
|
options
|
|
);
|
|
}
|
|
function useShare(shareOptions = {}, options = {}) {
|
|
const { navigator: navigator2 = defaultNavigator } = options;
|
|
const _navigator = navigator2;
|
|
const isSupported = useSupported(
|
|
() => _navigator && 'canShare' in _navigator
|
|
);
|
|
const share = async (overrideOptions = {}) => {
|
|
if (isSupported.value) {
|
|
const data = {
|
|
...toValue(shareOptions),
|
|
...toValue(overrideOptions),
|
|
};
|
|
let granted = true;
|
|
if (data.files && _navigator.canShare)
|
|
granted = _navigator.canShare({ files: data.files });
|
|
if (granted) return _navigator.share(data);
|
|
}
|
|
};
|
|
return {
|
|
isSupported,
|
|
share,
|
|
};
|
|
}
|
|
var defaultSortFn = (source, compareFn) => source.sort(compareFn);
|
|
var defaultCompare = (a, b) => a - b;
|
|
function useSorted(...args) {
|
|
var _a, _b, _c, _d;
|
|
const [source] = args;
|
|
let compareFn = defaultCompare;
|
|
let options = {};
|
|
if (args.length === 2) {
|
|
if (typeof args[1] === 'object') {
|
|
options = args[1];
|
|
compareFn = (_a = options.compareFn) != null ? _a : defaultCompare;
|
|
} else {
|
|
compareFn = (_b = args[1]) != null ? _b : defaultCompare;
|
|
}
|
|
} else if (args.length > 2) {
|
|
compareFn = (_c = args[1]) != null ? _c : defaultCompare;
|
|
options = (_d = args[2]) != null ? _d : {};
|
|
}
|
|
const { dirty = false, sortFn = defaultSortFn } = options;
|
|
if (!dirty) return computed(() => sortFn([...toValue(source)], compareFn));
|
|
watchEffect(() => {
|
|
const result = sortFn(toValue(source), compareFn);
|
|
if (isRef(source)) source.value = result;
|
|
else source.splice(0, source.length, ...result);
|
|
});
|
|
return source;
|
|
}
|
|
function useSpeechRecognition(options = {}) {
|
|
const {
|
|
interimResults = true,
|
|
continuous = true,
|
|
maxAlternatives = 1,
|
|
window: window2 = defaultWindow,
|
|
} = options;
|
|
const lang = toRef2(options.lang || 'en-US');
|
|
const isListening = shallowRef(false);
|
|
const isFinal = shallowRef(false);
|
|
const result = shallowRef('');
|
|
const error = shallowRef(void 0);
|
|
let recognition;
|
|
const start = () => {
|
|
isListening.value = true;
|
|
};
|
|
const stop = () => {
|
|
isListening.value = false;
|
|
};
|
|
const toggle = (value = !isListening.value) => {
|
|
if (value) {
|
|
start();
|
|
} else {
|
|
stop();
|
|
}
|
|
};
|
|
const SpeechRecognition =
|
|
window2 && (window2.SpeechRecognition || window2.webkitSpeechRecognition);
|
|
const isSupported = useSupported(() => SpeechRecognition);
|
|
if (isSupported.value) {
|
|
recognition = new SpeechRecognition();
|
|
recognition.continuous = continuous;
|
|
recognition.interimResults = interimResults;
|
|
recognition.lang = toValue(lang);
|
|
recognition.maxAlternatives = maxAlternatives;
|
|
recognition.onstart = () => {
|
|
isListening.value = true;
|
|
isFinal.value = false;
|
|
};
|
|
watch(lang, (lang2) => {
|
|
if (recognition && !isListening.value) recognition.lang = lang2;
|
|
});
|
|
recognition.onresult = (event) => {
|
|
const currentResult = event.results[event.resultIndex];
|
|
const { transcript } = currentResult[0];
|
|
isFinal.value = currentResult.isFinal;
|
|
result.value = transcript;
|
|
error.value = void 0;
|
|
};
|
|
recognition.onerror = (event) => {
|
|
error.value = event;
|
|
};
|
|
recognition.onend = () => {
|
|
isListening.value = false;
|
|
recognition.lang = toValue(lang);
|
|
};
|
|
watch(isListening, (newValue, oldValue) => {
|
|
if (newValue === oldValue) return;
|
|
if (newValue) recognition.start();
|
|
else recognition.stop();
|
|
});
|
|
}
|
|
tryOnScopeDispose(() => {
|
|
stop();
|
|
});
|
|
return {
|
|
isSupported,
|
|
isListening,
|
|
isFinal,
|
|
recognition,
|
|
result,
|
|
error,
|
|
toggle,
|
|
start,
|
|
stop,
|
|
};
|
|
}
|
|
function useSpeechSynthesis(text, options = {}) {
|
|
const {
|
|
pitch = 1,
|
|
rate = 1,
|
|
volume = 1,
|
|
window: window2 = defaultWindow,
|
|
} = options;
|
|
const synth = window2 && window2.speechSynthesis;
|
|
const isSupported = useSupported(() => synth);
|
|
const isPlaying = shallowRef(false);
|
|
const status = shallowRef('init');
|
|
const spokenText = toRef2(text || '');
|
|
const lang = toRef2(options.lang || 'en-US');
|
|
const error = shallowRef(void 0);
|
|
const toggle = (value = !isPlaying.value) => {
|
|
isPlaying.value = value;
|
|
};
|
|
const bindEventsForUtterance = (utterance2) => {
|
|
utterance2.lang = toValue(lang);
|
|
utterance2.voice = toValue(options.voice) || null;
|
|
utterance2.pitch = toValue(pitch);
|
|
utterance2.rate = toValue(rate);
|
|
utterance2.volume = volume;
|
|
utterance2.onstart = () => {
|
|
isPlaying.value = true;
|
|
status.value = 'play';
|
|
};
|
|
utterance2.onpause = () => {
|
|
isPlaying.value = false;
|
|
status.value = 'pause';
|
|
};
|
|
utterance2.onresume = () => {
|
|
isPlaying.value = true;
|
|
status.value = 'play';
|
|
};
|
|
utterance2.onend = () => {
|
|
isPlaying.value = false;
|
|
status.value = 'end';
|
|
};
|
|
utterance2.onerror = (event) => {
|
|
error.value = event;
|
|
};
|
|
};
|
|
const utterance = computed(() => {
|
|
isPlaying.value = false;
|
|
status.value = 'init';
|
|
const newUtterance = new SpeechSynthesisUtterance(spokenText.value);
|
|
bindEventsForUtterance(newUtterance);
|
|
return newUtterance;
|
|
});
|
|
const speak = () => {
|
|
synth.cancel();
|
|
if (utterance) synth.speak(utterance.value);
|
|
};
|
|
const stop = () => {
|
|
synth.cancel();
|
|
isPlaying.value = false;
|
|
};
|
|
if (isSupported.value) {
|
|
bindEventsForUtterance(utterance.value);
|
|
watch(lang, (lang2) => {
|
|
if (utterance.value && !isPlaying.value) utterance.value.lang = lang2;
|
|
});
|
|
if (options.voice) {
|
|
watch(options.voice, () => {
|
|
synth.cancel();
|
|
});
|
|
}
|
|
watch(isPlaying, () => {
|
|
if (isPlaying.value) synth.resume();
|
|
else synth.pause();
|
|
});
|
|
}
|
|
tryOnScopeDispose(() => {
|
|
isPlaying.value = false;
|
|
});
|
|
return {
|
|
isSupported,
|
|
isPlaying,
|
|
status,
|
|
utterance,
|
|
error,
|
|
stop,
|
|
toggle,
|
|
speak,
|
|
};
|
|
}
|
|
function useStepper(steps, initialStep) {
|
|
const stepsRef = ref(steps);
|
|
const stepNames = computed(() =>
|
|
Array.isArray(stepsRef.value) ? stepsRef.value : Object.keys(stepsRef.value)
|
|
);
|
|
const index = ref(
|
|
stepNames.value.indexOf(
|
|
initialStep != null ? initialStep : stepNames.value[0]
|
|
)
|
|
);
|
|
const current = computed(() => at(index.value));
|
|
const isFirst = computed(() => index.value === 0);
|
|
const isLast = computed(() => index.value === stepNames.value.length - 1);
|
|
const next = computed(() => stepNames.value[index.value + 1]);
|
|
const previous = computed(() => stepNames.value[index.value - 1]);
|
|
function at(index2) {
|
|
if (Array.isArray(stepsRef.value)) return stepsRef.value[index2];
|
|
return stepsRef.value[stepNames.value[index2]];
|
|
}
|
|
function get2(step) {
|
|
if (!stepNames.value.includes(step)) return;
|
|
return at(stepNames.value.indexOf(step));
|
|
}
|
|
function goTo(step) {
|
|
if (stepNames.value.includes(step))
|
|
index.value = stepNames.value.indexOf(step);
|
|
}
|
|
function goToNext() {
|
|
if (isLast.value) return;
|
|
index.value++;
|
|
}
|
|
function goToPrevious() {
|
|
if (isFirst.value) return;
|
|
index.value--;
|
|
}
|
|
function goBackTo(step) {
|
|
if (isAfter(step)) goTo(step);
|
|
}
|
|
function isNext(step) {
|
|
return stepNames.value.indexOf(step) === index.value + 1;
|
|
}
|
|
function isPrevious(step) {
|
|
return stepNames.value.indexOf(step) === index.value - 1;
|
|
}
|
|
function isCurrent(step) {
|
|
return stepNames.value.indexOf(step) === index.value;
|
|
}
|
|
function isBefore(step) {
|
|
return index.value < stepNames.value.indexOf(step);
|
|
}
|
|
function isAfter(step) {
|
|
return index.value > stepNames.value.indexOf(step);
|
|
}
|
|
return {
|
|
steps: stepsRef,
|
|
stepNames,
|
|
index,
|
|
current,
|
|
next,
|
|
previous,
|
|
isFirst,
|
|
isLast,
|
|
at,
|
|
get: get2,
|
|
goTo,
|
|
goToNext,
|
|
goToPrevious,
|
|
goBackTo,
|
|
isNext,
|
|
isPrevious,
|
|
isCurrent,
|
|
isBefore,
|
|
isAfter,
|
|
};
|
|
}
|
|
function useStorageAsync(key, initialValue, storage, options = {}) {
|
|
var _a;
|
|
const {
|
|
flush = 'pre',
|
|
deep = true,
|
|
listenToStorageChanges = true,
|
|
writeDefaults = true,
|
|
mergeDefaults = false,
|
|
shallow,
|
|
window: window2 = defaultWindow,
|
|
eventFilter,
|
|
onError = (e) => {
|
|
console.error(e);
|
|
},
|
|
} = options;
|
|
const rawInit = toValue(initialValue);
|
|
const type = guessSerializerType(rawInit);
|
|
const data = (shallow ? shallowRef : ref)(toValue(initialValue));
|
|
const serializer =
|
|
(_a = options.serializer) != null ? _a : StorageSerializers[type];
|
|
if (!storage) {
|
|
try {
|
|
storage = getSSRHandler('getDefaultStorageAsync', () => {
|
|
var _a2;
|
|
return (_a2 = defaultWindow) == null ? void 0 : _a2.localStorage;
|
|
})();
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
}
|
|
async function read(event) {
|
|
if (!storage || (event && event.key !== key)) return;
|
|
try {
|
|
const rawValue = event ? event.newValue : await storage.getItem(key);
|
|
if (rawValue == null) {
|
|
data.value = rawInit;
|
|
if (writeDefaults && rawInit !== null)
|
|
await storage.setItem(key, await serializer.write(rawInit));
|
|
} else if (mergeDefaults) {
|
|
const value = await serializer.read(rawValue);
|
|
if (typeof mergeDefaults === 'function')
|
|
data.value = mergeDefaults(value, rawInit);
|
|
else if (type === 'object' && !Array.isArray(value))
|
|
data.value = { ...rawInit, ...value };
|
|
else data.value = value;
|
|
} else {
|
|
data.value = await serializer.read(rawValue);
|
|
}
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
}
|
|
read();
|
|
if (window2 && listenToStorageChanges)
|
|
useEventListener(
|
|
window2,
|
|
'storage',
|
|
(e) => Promise.resolve().then(() => read(e)),
|
|
{ passive: true }
|
|
);
|
|
if (storage) {
|
|
watchWithFilter(
|
|
data,
|
|
async () => {
|
|
try {
|
|
if (data.value == null) await storage.removeItem(key);
|
|
else await storage.setItem(key, await serializer.write(data.value));
|
|
} catch (e) {
|
|
onError(e);
|
|
}
|
|
},
|
|
{
|
|
flush,
|
|
deep,
|
|
eventFilter,
|
|
}
|
|
);
|
|
}
|
|
return data;
|
|
}
|
|
var _id = 0;
|
|
function useStyleTag(css, options = {}) {
|
|
const isLoaded = shallowRef(false);
|
|
const {
|
|
document: document2 = defaultDocument,
|
|
immediate = true,
|
|
manual = false,
|
|
id = `vueuse_styletag_${++_id}`,
|
|
} = options;
|
|
const cssRef = shallowRef(css);
|
|
let stop = () => {};
|
|
const load = () => {
|
|
if (!document2) return;
|
|
const el = document2.getElementById(id) || document2.createElement('style');
|
|
if (!el.isConnected) {
|
|
el.id = id;
|
|
if (options.media) el.media = options.media;
|
|
document2.head.appendChild(el);
|
|
}
|
|
if (isLoaded.value) return;
|
|
stop = watch(
|
|
cssRef,
|
|
(value) => {
|
|
el.textContent = value;
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
isLoaded.value = true;
|
|
};
|
|
const unload = () => {
|
|
if (!document2 || !isLoaded.value) return;
|
|
stop();
|
|
document2.head.removeChild(document2.getElementById(id));
|
|
isLoaded.value = false;
|
|
};
|
|
if (immediate && !manual) tryOnMounted(load);
|
|
if (!manual) tryOnScopeDispose(unload);
|
|
return {
|
|
id,
|
|
css: cssRef,
|
|
unload,
|
|
load,
|
|
isLoaded: readonly(isLoaded),
|
|
};
|
|
}
|
|
function useSwipe(target, options = {}) {
|
|
const {
|
|
threshold = 50,
|
|
onSwipe,
|
|
onSwipeEnd,
|
|
onSwipeStart,
|
|
passive = true,
|
|
} = options;
|
|
const coordsStart = reactive({ x: 0, y: 0 });
|
|
const coordsEnd = reactive({ x: 0, y: 0 });
|
|
const diffX = computed(() => coordsStart.x - coordsEnd.x);
|
|
const diffY = computed(() => coordsStart.y - coordsEnd.y);
|
|
const { max, abs } = Math;
|
|
const isThresholdExceeded = computed(
|
|
() => max(abs(diffX.value), abs(diffY.value)) >= threshold
|
|
);
|
|
const isSwiping = shallowRef(false);
|
|
const direction = computed(() => {
|
|
if (!isThresholdExceeded.value) return 'none';
|
|
if (abs(diffX.value) > abs(diffY.value)) {
|
|
return diffX.value > 0 ? 'left' : 'right';
|
|
} else {
|
|
return diffY.value > 0 ? 'up' : 'down';
|
|
}
|
|
});
|
|
const getTouchEventCoords = (e) => [
|
|
e.touches[0].clientX,
|
|
e.touches[0].clientY,
|
|
];
|
|
const updateCoordsStart = (x, y) => {
|
|
coordsStart.x = x;
|
|
coordsStart.y = y;
|
|
};
|
|
const updateCoordsEnd = (x, y) => {
|
|
coordsEnd.x = x;
|
|
coordsEnd.y = y;
|
|
};
|
|
const listenerOptions = { passive, capture: !passive };
|
|
const onTouchEnd = (e) => {
|
|
if (isSwiping.value)
|
|
onSwipeEnd == null ? void 0 : onSwipeEnd(e, direction.value);
|
|
isSwiping.value = false;
|
|
};
|
|
const stops = [
|
|
useEventListener(
|
|
target,
|
|
'touchstart',
|
|
(e) => {
|
|
if (e.touches.length !== 1) return;
|
|
const [x, y] = getTouchEventCoords(e);
|
|
updateCoordsStart(x, y);
|
|
updateCoordsEnd(x, y);
|
|
onSwipeStart == null ? void 0 : onSwipeStart(e);
|
|
},
|
|
listenerOptions
|
|
),
|
|
useEventListener(
|
|
target,
|
|
'touchmove',
|
|
(e) => {
|
|
if (e.touches.length !== 1) return;
|
|
const [x, y] = getTouchEventCoords(e);
|
|
updateCoordsEnd(x, y);
|
|
if (
|
|
listenerOptions.capture &&
|
|
!listenerOptions.passive &&
|
|
Math.abs(diffX.value) > Math.abs(diffY.value)
|
|
)
|
|
e.preventDefault();
|
|
if (!isSwiping.value && isThresholdExceeded.value)
|
|
isSwiping.value = true;
|
|
if (isSwiping.value) onSwipe == null ? void 0 : onSwipe(e);
|
|
},
|
|
listenerOptions
|
|
),
|
|
useEventListener(
|
|
target,
|
|
['touchend', 'touchcancel'],
|
|
onTouchEnd,
|
|
listenerOptions
|
|
),
|
|
];
|
|
const stop = () => stops.forEach((s) => s());
|
|
return {
|
|
isSwiping,
|
|
direction,
|
|
coordsStart,
|
|
coordsEnd,
|
|
lengthX: diffX,
|
|
lengthY: diffY,
|
|
stop,
|
|
// TODO: Remove in the next major version
|
|
isPassiveEventSupported: true,
|
|
};
|
|
}
|
|
function useTemplateRefsList() {
|
|
const refs = ref([]);
|
|
refs.value.set = (el) => {
|
|
if (el) refs.value.push(el);
|
|
};
|
|
onBeforeUpdate(() => {
|
|
refs.value.length = 0;
|
|
});
|
|
return refs;
|
|
}
|
|
function useTextDirection(options = {}) {
|
|
const {
|
|
document: document2 = defaultDocument,
|
|
selector = 'html',
|
|
observe = false,
|
|
initialValue = 'ltr',
|
|
} = options;
|
|
function getValue2() {
|
|
var _a, _b;
|
|
return (_b =
|
|
(_a = document2 == null ? void 0 : document2.querySelector(selector)) ==
|
|
null
|
|
? void 0
|
|
: _a.getAttribute('dir')) != null
|
|
? _b
|
|
: initialValue;
|
|
}
|
|
const dir = ref(getValue2());
|
|
tryOnMounted(() => (dir.value = getValue2()));
|
|
if (observe && document2) {
|
|
useMutationObserver(
|
|
document2.querySelector(selector),
|
|
() => (dir.value = getValue2()),
|
|
{ attributes: true }
|
|
);
|
|
}
|
|
return computed({
|
|
get() {
|
|
return dir.value;
|
|
},
|
|
set(v) {
|
|
var _a, _b;
|
|
dir.value = v;
|
|
if (!document2) return;
|
|
if (dir.value)
|
|
(_a = document2.querySelector(selector)) == null
|
|
? void 0
|
|
: _a.setAttribute('dir', dir.value);
|
|
else
|
|
(_b = document2.querySelector(selector)) == null
|
|
? void 0
|
|
: _b.removeAttribute('dir');
|
|
},
|
|
});
|
|
}
|
|
function getRangesFromSelection(selection) {
|
|
var _a;
|
|
const rangeCount = (_a = selection.rangeCount) != null ? _a : 0;
|
|
return Array.from({ length: rangeCount }, (_, i) => selection.getRangeAt(i));
|
|
}
|
|
function useTextSelection(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
const selection = ref(null);
|
|
const text = computed(() => {
|
|
var _a, _b;
|
|
return (_b = (_a = selection.value) == null ? void 0 : _a.toString()) !=
|
|
null
|
|
? _b
|
|
: '';
|
|
});
|
|
const ranges = computed(() =>
|
|
selection.value ? getRangesFromSelection(selection.value) : []
|
|
);
|
|
const rects = computed(() =>
|
|
ranges.value.map((range) => range.getBoundingClientRect())
|
|
);
|
|
function onSelectionChange() {
|
|
selection.value = null;
|
|
if (window2) selection.value = window2.getSelection();
|
|
}
|
|
if (window2)
|
|
useEventListener(window2.document, 'selectionchange', onSelectionChange, {
|
|
passive: true,
|
|
});
|
|
return {
|
|
text,
|
|
rects,
|
|
ranges,
|
|
selection,
|
|
};
|
|
}
|
|
function tryRequestAnimationFrame(window2 = defaultWindow, fn) {
|
|
if (window2 && typeof window2.requestAnimationFrame === 'function') {
|
|
window2.requestAnimationFrame(fn);
|
|
} else {
|
|
fn();
|
|
}
|
|
}
|
|
function useTextareaAutosize(options = {}) {
|
|
var _a, _b;
|
|
const { window: window2 = defaultWindow } = options;
|
|
const textarea = toRef2(options == null ? void 0 : options.element);
|
|
const input = toRef2(
|
|
(_a = options == null ? void 0 : options.input) != null ? _a : ''
|
|
);
|
|
const styleProp =
|
|
(_b = options == null ? void 0 : options.styleProp) != null ? _b : 'height';
|
|
const textareaScrollHeight = shallowRef(1);
|
|
const textareaOldWidth = shallowRef(0);
|
|
function triggerResize() {
|
|
var _a2;
|
|
if (!textarea.value) return;
|
|
let height = '';
|
|
textarea.value.style[styleProp] = '1px';
|
|
textareaScrollHeight.value =
|
|
(_a2 = textarea.value) == null ? void 0 : _a2.scrollHeight;
|
|
const _styleTarget = toValue(
|
|
options == null ? void 0 : options.styleTarget
|
|
);
|
|
if (_styleTarget)
|
|
_styleTarget.style[styleProp] = `${textareaScrollHeight.value}px`;
|
|
else height = `${textareaScrollHeight.value}px`;
|
|
textarea.value.style[styleProp] = height;
|
|
}
|
|
watch([input, textarea], () => nextTick(triggerResize), { immediate: true });
|
|
watch(textareaScrollHeight, () => {
|
|
var _a2;
|
|
return (_a2 = options == null ? void 0 : options.onResize) == null
|
|
? void 0
|
|
: _a2.call(options);
|
|
});
|
|
useResizeObserver(textarea, ([{ contentRect }]) => {
|
|
if (textareaOldWidth.value === contentRect.width) return;
|
|
tryRequestAnimationFrame(window2, () => {
|
|
textareaOldWidth.value = contentRect.width;
|
|
triggerResize();
|
|
});
|
|
});
|
|
if (options == null ? void 0 : options.watch)
|
|
watch(options.watch, triggerResize, { immediate: true, deep: true });
|
|
return {
|
|
textarea,
|
|
input,
|
|
triggerResize,
|
|
};
|
|
}
|
|
function useThrottledRefHistory(source, options = {}) {
|
|
const { throttle = 200, trailing = true } = options;
|
|
const filter = throttleFilter(throttle, trailing);
|
|
const history = useRefHistory(source, { ...options, eventFilter: filter });
|
|
return {
|
|
...history,
|
|
};
|
|
}
|
|
var DEFAULT_UNITS = [
|
|
{ max: 6e4, value: 1e3, name: 'second' },
|
|
{ max: 276e4, value: 6e4, name: 'minute' },
|
|
{ max: 72e6, value: 36e5, name: 'hour' },
|
|
{ max: 5184e5, value: 864e5, name: 'day' },
|
|
{ max: 24192e5, value: 6048e5, name: 'week' },
|
|
{ max: 28512e6, value: 2592e6, name: 'month' },
|
|
{ max: Number.POSITIVE_INFINITY, value: 31536e6, name: 'year' },
|
|
];
|
|
var DEFAULT_MESSAGES = {
|
|
justNow: 'just now',
|
|
past: (n) => (n.match(/\d/) ? `${n} ago` : n),
|
|
future: (n) => (n.match(/\d/) ? `in ${n}` : n),
|
|
month: (n, past) =>
|
|
n === 1
|
|
? past
|
|
? 'last month'
|
|
: 'next month'
|
|
: `${n} month${n > 1 ? 's' : ''}`,
|
|
year: (n, past) =>
|
|
n === 1
|
|
? past
|
|
? 'last year'
|
|
: 'next year'
|
|
: `${n} year${n > 1 ? 's' : ''}`,
|
|
day: (n, past) =>
|
|
n === 1 ? (past ? 'yesterday' : 'tomorrow') : `${n} day${n > 1 ? 's' : ''}`,
|
|
week: (n, past) =>
|
|
n === 1
|
|
? past
|
|
? 'last week'
|
|
: 'next week'
|
|
: `${n} week${n > 1 ? 's' : ''}`,
|
|
hour: (n) => `${n} hour${n > 1 ? 's' : ''}`,
|
|
minute: (n) => `${n} minute${n > 1 ? 's' : ''}`,
|
|
second: (n) => `${n} second${n > 1 ? 's' : ''}`,
|
|
invalid: '',
|
|
};
|
|
function DEFAULT_FORMATTER(date) {
|
|
return date.toISOString().slice(0, 10);
|
|
}
|
|
function useTimeAgo(time, options = {}) {
|
|
const { controls: exposeControls = false, updateInterval = 3e4 } = options;
|
|
const { now: now2, ...controls } = useNow({
|
|
interval: updateInterval,
|
|
controls: true,
|
|
});
|
|
const timeAgo = computed(() =>
|
|
formatTimeAgo(new Date(toValue(time)), options, toValue(now2))
|
|
);
|
|
if (exposeControls) {
|
|
return {
|
|
timeAgo,
|
|
...controls,
|
|
};
|
|
} else {
|
|
return timeAgo;
|
|
}
|
|
}
|
|
function formatTimeAgo(from, options = {}, now2 = Date.now()) {
|
|
var _a;
|
|
const {
|
|
max,
|
|
messages = DEFAULT_MESSAGES,
|
|
fullDateFormatter = DEFAULT_FORMATTER,
|
|
units = DEFAULT_UNITS,
|
|
showSecond = false,
|
|
rounding = 'round',
|
|
} = options;
|
|
const roundFn =
|
|
typeof rounding === 'number' ? (n) => +n.toFixed(rounding) : Math[rounding];
|
|
const diff = +now2 - +from;
|
|
const absDiff = Math.abs(diff);
|
|
function getValue2(diff2, unit) {
|
|
return roundFn(Math.abs(diff2) / unit.value);
|
|
}
|
|
function format(diff2, unit) {
|
|
const val = getValue2(diff2, unit);
|
|
const past = diff2 > 0;
|
|
const str = applyFormat(unit.name, val, past);
|
|
return applyFormat(past ? 'past' : 'future', str, past);
|
|
}
|
|
function applyFormat(name, val, isPast) {
|
|
const formatter = messages[name];
|
|
if (typeof formatter === 'function') return formatter(val, isPast);
|
|
return formatter.replace('{0}', val.toString());
|
|
}
|
|
if (absDiff < 6e4 && !showSecond) return messages.justNow;
|
|
if (typeof max === 'number' && absDiff > max)
|
|
return fullDateFormatter(new Date(from));
|
|
if (typeof max === 'string') {
|
|
const unitMax =
|
|
(_a = units.find((i) => i.name === max)) == null ? void 0 : _a.max;
|
|
if (unitMax && absDiff > unitMax) return fullDateFormatter(new Date(from));
|
|
}
|
|
for (const [idx, unit] of units.entries()) {
|
|
const val = getValue2(diff, unit);
|
|
if (val <= 0 && units[idx - 1]) return format(diff, units[idx - 1]);
|
|
if (absDiff < unit.max) return format(diff, unit);
|
|
}
|
|
return messages.invalid;
|
|
}
|
|
function useTimeoutPoll(fn, interval, options = {}) {
|
|
const { immediate = true, immediateCallback = false } = options;
|
|
const { start } = useTimeoutFn(loop, interval, { immediate });
|
|
const isActive = shallowRef(false);
|
|
async function loop() {
|
|
if (!isActive.value) return;
|
|
await fn();
|
|
start();
|
|
}
|
|
function resume() {
|
|
if (!isActive.value) {
|
|
isActive.value = true;
|
|
if (immediateCallback) fn();
|
|
start();
|
|
}
|
|
}
|
|
function pause() {
|
|
isActive.value = false;
|
|
}
|
|
if (immediate && isClient) resume();
|
|
tryOnScopeDispose(pause);
|
|
return {
|
|
isActive,
|
|
pause,
|
|
resume,
|
|
};
|
|
}
|
|
function useTimestamp(options = {}) {
|
|
const {
|
|
controls: exposeControls = false,
|
|
offset = 0,
|
|
immediate = true,
|
|
interval = 'requestAnimationFrame',
|
|
callback,
|
|
} = options;
|
|
const ts = shallowRef(timestamp() + offset);
|
|
const update = () => (ts.value = timestamp() + offset);
|
|
const cb = callback
|
|
? () => {
|
|
update();
|
|
callback(ts.value);
|
|
}
|
|
: update;
|
|
const controls =
|
|
interval === 'requestAnimationFrame'
|
|
? useRafFn(cb, { immediate })
|
|
: useIntervalFn(cb, interval, { immediate });
|
|
if (exposeControls) {
|
|
return {
|
|
timestamp: ts,
|
|
...controls,
|
|
};
|
|
} else {
|
|
return ts;
|
|
}
|
|
}
|
|
function useTitle(newTitle = null, options = {}) {
|
|
var _a, _b, _c;
|
|
const { document: document2 = defaultDocument, restoreOnUnmount = (t) => t } =
|
|
options;
|
|
const originalTitle =
|
|
(_a = document2 == null ? void 0 : document2.title) != null ? _a : '';
|
|
const title = toRef2(
|
|
(_b =
|
|
newTitle != null
|
|
? newTitle
|
|
: document2 == null
|
|
? void 0
|
|
: document2.title) != null
|
|
? _b
|
|
: null
|
|
);
|
|
const isReadonly2 = !!(newTitle && typeof newTitle === 'function');
|
|
function format(t) {
|
|
if (!('titleTemplate' in options)) return t;
|
|
const template = options.titleTemplate || '%s';
|
|
return typeof template === 'function'
|
|
? template(t)
|
|
: toValue(template).replace(/%s/g, t);
|
|
}
|
|
watch(
|
|
title,
|
|
(newValue, oldValue) => {
|
|
if (newValue !== oldValue && document2)
|
|
document2.title = format(newValue != null ? newValue : '');
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
if (options.observe && !options.titleTemplate && document2 && !isReadonly2) {
|
|
useMutationObserver(
|
|
(_c = document2.head) == null ? void 0 : _c.querySelector('title'),
|
|
() => {
|
|
if (document2 && document2.title !== title.value)
|
|
title.value = format(document2.title);
|
|
},
|
|
{ childList: true }
|
|
);
|
|
}
|
|
tryOnScopeDispose(() => {
|
|
if (restoreOnUnmount) {
|
|
const restoredTitle = restoreOnUnmount(originalTitle, title.value || '');
|
|
if (restoredTitle != null && document2) document2.title = restoredTitle;
|
|
}
|
|
});
|
|
return title;
|
|
}
|
|
var _TransitionPresets = {
|
|
easeInSine: [0.12, 0, 0.39, 0],
|
|
easeOutSine: [0.61, 1, 0.88, 1],
|
|
easeInOutSine: [0.37, 0, 0.63, 1],
|
|
easeInQuad: [0.11, 0, 0.5, 0],
|
|
easeOutQuad: [0.5, 1, 0.89, 1],
|
|
easeInOutQuad: [0.45, 0, 0.55, 1],
|
|
easeInCubic: [0.32, 0, 0.67, 0],
|
|
easeOutCubic: [0.33, 1, 0.68, 1],
|
|
easeInOutCubic: [0.65, 0, 0.35, 1],
|
|
easeInQuart: [0.5, 0, 0.75, 0],
|
|
easeOutQuart: [0.25, 1, 0.5, 1],
|
|
easeInOutQuart: [0.76, 0, 0.24, 1],
|
|
easeInQuint: [0.64, 0, 0.78, 0],
|
|
easeOutQuint: [0.22, 1, 0.36, 1],
|
|
easeInOutQuint: [0.83, 0, 0.17, 1],
|
|
easeInExpo: [0.7, 0, 0.84, 0],
|
|
easeOutExpo: [0.16, 1, 0.3, 1],
|
|
easeInOutExpo: [0.87, 0, 0.13, 1],
|
|
easeInCirc: [0.55, 0, 1, 0.45],
|
|
easeOutCirc: [0, 0.55, 0.45, 1],
|
|
easeInOutCirc: [0.85, 0, 0.15, 1],
|
|
easeInBack: [0.36, 0, 0.66, -0.56],
|
|
easeOutBack: [0.34, 1.56, 0.64, 1],
|
|
easeInOutBack: [0.68, -0.6, 0.32, 1.6],
|
|
};
|
|
var TransitionPresets = Object.assign(
|
|
{},
|
|
{ linear: identity },
|
|
_TransitionPresets
|
|
);
|
|
function createEasingFunction([p0, p1, p2, p3]) {
|
|
const a = (a1, a2) => 1 - 3 * a2 + 3 * a1;
|
|
const b = (a1, a2) => 3 * a2 - 6 * a1;
|
|
const c = (a1) => 3 * a1;
|
|
const calcBezier = (t, a1, a2) =>
|
|
((a(a1, a2) * t + b(a1, a2)) * t + c(a1)) * t;
|
|
const getSlope = (t, a1, a2) =>
|
|
3 * a(a1, a2) * t * t + 2 * b(a1, a2) * t + c(a1);
|
|
const getTforX = (x) => {
|
|
let aGuessT = x;
|
|
for (let i = 0; i < 4; ++i) {
|
|
const currentSlope = getSlope(aGuessT, p0, p2);
|
|
if (currentSlope === 0) return aGuessT;
|
|
const currentX = calcBezier(aGuessT, p0, p2) - x;
|
|
aGuessT -= currentX / currentSlope;
|
|
}
|
|
return aGuessT;
|
|
};
|
|
return (x) => (p0 === p1 && p2 === p3 ? x : calcBezier(getTforX(x), p1, p3));
|
|
}
|
|
function lerp(a, b, alpha) {
|
|
return a + alpha * (b - a);
|
|
}
|
|
function toVec(t) {
|
|
return (typeof t === 'number' ? [t] : t) || [];
|
|
}
|
|
function executeTransition(source, from, to, options = {}) {
|
|
var _a, _b;
|
|
const fromVal = toValue(from);
|
|
const toVal = toValue(to);
|
|
const v1 = toVec(fromVal);
|
|
const v2 = toVec(toVal);
|
|
const duration = (_a = toValue(options.duration)) != null ? _a : 1e3;
|
|
const startedAt = Date.now();
|
|
const endAt = Date.now() + duration;
|
|
const trans =
|
|
typeof options.transition === 'function'
|
|
? options.transition
|
|
: (_b = toValue(options.transition)) != null
|
|
? _b
|
|
: identity;
|
|
const ease =
|
|
typeof trans === 'function' ? trans : createEasingFunction(trans);
|
|
return new Promise((resolve) => {
|
|
source.value = fromVal;
|
|
const tick = () => {
|
|
var _a2;
|
|
if ((_a2 = options.abort) == null ? void 0 : _a2.call(options)) {
|
|
resolve();
|
|
return;
|
|
}
|
|
const now2 = Date.now();
|
|
const alpha = ease((now2 - startedAt) / duration);
|
|
const arr = toVec(source.value).map((n, i) => lerp(v1[i], v2[i], alpha));
|
|
if (Array.isArray(source.value))
|
|
source.value = arr.map((n, i) => {
|
|
var _a3, _b2;
|
|
return lerp(
|
|
(_a3 = v1[i]) != null ? _a3 : 0,
|
|
(_b2 = v2[i]) != null ? _b2 : 0,
|
|
alpha
|
|
);
|
|
});
|
|
else if (typeof source.value === 'number') source.value = arr[0];
|
|
if (now2 < endAt) {
|
|
requestAnimationFrame(tick);
|
|
} else {
|
|
source.value = toVal;
|
|
resolve();
|
|
}
|
|
};
|
|
tick();
|
|
});
|
|
}
|
|
function useTransition(source, options = {}) {
|
|
let currentId = 0;
|
|
const sourceVal = () => {
|
|
const v = toValue(source);
|
|
return typeof v === 'number' ? v : v.map(toValue);
|
|
};
|
|
const outputRef = ref(sourceVal());
|
|
watch(
|
|
sourceVal,
|
|
async (to) => {
|
|
var _a, _b;
|
|
if (toValue(options.disabled)) return;
|
|
const id = ++currentId;
|
|
if (options.delay) await promiseTimeout(toValue(options.delay));
|
|
if (id !== currentId) return;
|
|
const toVal = Array.isArray(to) ? to.map(toValue) : toValue(to);
|
|
(_a = options.onStarted) == null ? void 0 : _a.call(options);
|
|
await executeTransition(outputRef, outputRef.value, toVal, {
|
|
...options,
|
|
abort: () => {
|
|
var _a2;
|
|
return (
|
|
id !== currentId ||
|
|
((_a2 = options.abort) == null ? void 0 : _a2.call(options))
|
|
);
|
|
},
|
|
});
|
|
(_b = options.onFinished) == null ? void 0 : _b.call(options);
|
|
},
|
|
{ deep: true }
|
|
);
|
|
watch(
|
|
() => toValue(options.disabled),
|
|
(disabled) => {
|
|
if (disabled) {
|
|
currentId++;
|
|
outputRef.value = sourceVal();
|
|
}
|
|
}
|
|
);
|
|
tryOnScopeDispose(() => {
|
|
currentId++;
|
|
});
|
|
return computed(() =>
|
|
toValue(options.disabled) ? sourceVal() : outputRef.value
|
|
);
|
|
}
|
|
function useUrlSearchParams(mode = 'history', options = {}) {
|
|
const {
|
|
initialValue = {},
|
|
removeNullishValues = true,
|
|
removeFalsyValues = false,
|
|
write: enableWrite = true,
|
|
writeMode = 'replace',
|
|
window: window2 = defaultWindow,
|
|
} = options;
|
|
if (!window2) return reactive(initialValue);
|
|
const state = reactive({});
|
|
function getRawParams() {
|
|
if (mode === 'history') {
|
|
return window2.location.search || '';
|
|
} else if (mode === 'hash') {
|
|
const hash = window2.location.hash || '';
|
|
const index = hash.indexOf('?');
|
|
return index > 0 ? hash.slice(index) : '';
|
|
} else {
|
|
return (window2.location.hash || '').replace(/^#/, '');
|
|
}
|
|
}
|
|
function constructQuery(params) {
|
|
const stringified = params.toString();
|
|
if (mode === 'history')
|
|
return `${stringified ? `?${stringified}` : ''}${window2.location.hash || ''}`;
|
|
if (mode === 'hash-params')
|
|
return `${window2.location.search || ''}${stringified ? `#${stringified}` : ''}`;
|
|
const hash = window2.location.hash || '#';
|
|
const index = hash.indexOf('?');
|
|
if (index > 0)
|
|
return `${window2.location.search || ''}${hash.slice(0, index)}${stringified ? `?${stringified}` : ''}`;
|
|
return `${window2.location.search || ''}${hash}${stringified ? `?${stringified}` : ''}`;
|
|
}
|
|
function read() {
|
|
return new URLSearchParams(getRawParams());
|
|
}
|
|
function updateState(params) {
|
|
const unusedKeys = new Set(Object.keys(state));
|
|
for (const key of params.keys()) {
|
|
const paramsForKey = params.getAll(key);
|
|
state[key] =
|
|
paramsForKey.length > 1 ? paramsForKey : params.get(key) || '';
|
|
unusedKeys.delete(key);
|
|
}
|
|
Array.from(unusedKeys).forEach((key) => delete state[key]);
|
|
}
|
|
const { pause, resume } = watchPausable(
|
|
state,
|
|
() => {
|
|
const params = new URLSearchParams('');
|
|
Object.keys(state).forEach((key) => {
|
|
const mapEntry = state[key];
|
|
if (Array.isArray(mapEntry))
|
|
mapEntry.forEach((value) => params.append(key, value));
|
|
else if (removeNullishValues && mapEntry == null) params.delete(key);
|
|
else if (removeFalsyValues && !mapEntry) params.delete(key);
|
|
else params.set(key, mapEntry);
|
|
});
|
|
write(params, false);
|
|
},
|
|
{ deep: true }
|
|
);
|
|
function write(params, shouldUpdate) {
|
|
pause();
|
|
if (shouldUpdate) updateState(params);
|
|
if (writeMode === 'replace') {
|
|
window2.history.replaceState(
|
|
window2.history.state,
|
|
window2.document.title,
|
|
window2.location.pathname + constructQuery(params)
|
|
);
|
|
} else {
|
|
window2.history.pushState(
|
|
window2.history.state,
|
|
window2.document.title,
|
|
window2.location.pathname + constructQuery(params)
|
|
);
|
|
}
|
|
resume();
|
|
}
|
|
function onChanged() {
|
|
if (!enableWrite) return;
|
|
write(read(), true);
|
|
}
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(window2, 'popstate', onChanged, listenerOptions);
|
|
if (mode !== 'history')
|
|
useEventListener(window2, 'hashchange', onChanged, listenerOptions);
|
|
const initial = read();
|
|
if (initial.keys().next().value) updateState(initial);
|
|
else Object.assign(state, initialValue);
|
|
return state;
|
|
}
|
|
function useUserMedia(options = {}) {
|
|
var _a, _b;
|
|
const enabled = shallowRef((_a = options.enabled) != null ? _a : false);
|
|
const autoSwitch = shallowRef((_b = options.autoSwitch) != null ? _b : true);
|
|
const constraints = ref(options.constraints);
|
|
const { navigator: navigator2 = defaultNavigator } = options;
|
|
const isSupported = useSupported(() => {
|
|
var _a2;
|
|
return (_a2 = navigator2 == null ? void 0 : navigator2.mediaDevices) == null
|
|
? void 0
|
|
: _a2.getUserMedia;
|
|
});
|
|
const stream = shallowRef();
|
|
function getDeviceOptions(type) {
|
|
switch (type) {
|
|
case 'video': {
|
|
if (constraints.value) return constraints.value.video || false;
|
|
break;
|
|
}
|
|
case 'audio': {
|
|
if (constraints.value) return constraints.value.audio || false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
async function _start() {
|
|
if (!isSupported.value || stream.value) return;
|
|
stream.value = await navigator2.mediaDevices.getUserMedia({
|
|
video: getDeviceOptions('video'),
|
|
audio: getDeviceOptions('audio'),
|
|
});
|
|
return stream.value;
|
|
}
|
|
function _stop() {
|
|
var _a2;
|
|
(_a2 = stream.value) == null
|
|
? void 0
|
|
: _a2.getTracks().forEach((t) => t.stop());
|
|
stream.value = void 0;
|
|
}
|
|
function stop() {
|
|
_stop();
|
|
enabled.value = false;
|
|
}
|
|
async function start() {
|
|
await _start();
|
|
if (stream.value) enabled.value = true;
|
|
return stream.value;
|
|
}
|
|
async function restart() {
|
|
_stop();
|
|
return await start();
|
|
}
|
|
watch(
|
|
enabled,
|
|
(v) => {
|
|
if (v) _start();
|
|
else _stop();
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
watch(
|
|
constraints,
|
|
() => {
|
|
if (autoSwitch.value && stream.value) restart();
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
tryOnScopeDispose(() => {
|
|
stop();
|
|
});
|
|
return {
|
|
isSupported,
|
|
stream,
|
|
start,
|
|
stop,
|
|
restart,
|
|
constraints,
|
|
enabled,
|
|
autoSwitch,
|
|
};
|
|
}
|
|
function useVModel(props, key, emit, options = {}) {
|
|
var _a, _b, _c;
|
|
const {
|
|
clone = false,
|
|
passive = false,
|
|
eventName,
|
|
deep = false,
|
|
defaultValue,
|
|
shouldEmit,
|
|
} = options;
|
|
const vm = getCurrentInstance();
|
|
const _emit =
|
|
emit ||
|
|
(vm == null ? void 0 : vm.emit) ||
|
|
((_a = vm == null ? void 0 : vm.$emit) == null ? void 0 : _a.bind(vm)) ||
|
|
((_c = (_b = vm == null ? void 0 : vm.proxy) == null ? void 0 : _b.$emit) ==
|
|
null
|
|
? void 0
|
|
: _c.bind(vm == null ? void 0 : vm.proxy));
|
|
let event = eventName;
|
|
if (!key) {
|
|
key = 'modelValue';
|
|
}
|
|
event = event || `update:${key.toString()}`;
|
|
const cloneFn = (val) =>
|
|
!clone ? val : typeof clone === 'function' ? clone(val) : cloneFnJSON(val);
|
|
const getValue2 = () =>
|
|
isDef(props[key]) ? cloneFn(props[key]) : defaultValue;
|
|
const triggerEmit = (value) => {
|
|
if (shouldEmit) {
|
|
if (shouldEmit(value)) _emit(event, value);
|
|
} else {
|
|
_emit(event, value);
|
|
}
|
|
};
|
|
if (passive) {
|
|
const initialValue = getValue2();
|
|
const proxy = ref(initialValue);
|
|
let isUpdating = false;
|
|
watch(
|
|
() => props[key],
|
|
(v) => {
|
|
if (!isUpdating) {
|
|
isUpdating = true;
|
|
proxy.value = cloneFn(v);
|
|
nextTick(() => (isUpdating = false));
|
|
}
|
|
}
|
|
);
|
|
watch(
|
|
proxy,
|
|
(v) => {
|
|
if (!isUpdating && (v !== props[key] || deep)) triggerEmit(v);
|
|
},
|
|
{ deep }
|
|
);
|
|
return proxy;
|
|
} else {
|
|
return computed({
|
|
get() {
|
|
return getValue2();
|
|
},
|
|
set(value) {
|
|
triggerEmit(value);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
function useVModels(props, emit, options = {}) {
|
|
const ret = {};
|
|
for (const key in props) {
|
|
ret[key] = useVModel(props, key, emit, options);
|
|
}
|
|
return ret;
|
|
}
|
|
function useVibrate(options) {
|
|
const {
|
|
pattern = [],
|
|
interval = 0,
|
|
navigator: navigator2 = defaultNavigator,
|
|
} = options || {};
|
|
const isSupported = useSupported(
|
|
() => typeof navigator2 !== 'undefined' && 'vibrate' in navigator2
|
|
);
|
|
const patternRef = toRef2(pattern);
|
|
let intervalControls;
|
|
const vibrate = (pattern2 = patternRef.value) => {
|
|
if (isSupported.value) navigator2.vibrate(pattern2);
|
|
};
|
|
const stop = () => {
|
|
if (isSupported.value) navigator2.vibrate(0);
|
|
intervalControls == null ? void 0 : intervalControls.pause();
|
|
};
|
|
if (interval > 0) {
|
|
intervalControls = useIntervalFn(vibrate, interval, {
|
|
immediate: false,
|
|
immediateCallback: false,
|
|
});
|
|
}
|
|
return {
|
|
isSupported,
|
|
pattern,
|
|
intervalControls,
|
|
vibrate,
|
|
stop,
|
|
};
|
|
}
|
|
function useVirtualList(list, options) {
|
|
const {
|
|
containerStyle,
|
|
wrapperProps,
|
|
scrollTo,
|
|
calculateRange,
|
|
currentList,
|
|
containerRef,
|
|
} =
|
|
'itemHeight' in options
|
|
? useVerticalVirtualList(options, list)
|
|
: useHorizontalVirtualList(options, list);
|
|
return {
|
|
list: currentList,
|
|
scrollTo,
|
|
containerProps: {
|
|
ref: containerRef,
|
|
onScroll: () => {
|
|
calculateRange();
|
|
},
|
|
style: containerStyle,
|
|
},
|
|
wrapperProps,
|
|
};
|
|
}
|
|
function useVirtualListResources(list) {
|
|
const containerRef = shallowRef(null);
|
|
const size = useElementSize(containerRef);
|
|
const currentList = ref([]);
|
|
const source = shallowRef(list);
|
|
const state = ref({ start: 0, end: 10 });
|
|
return { state, source, currentList, size, containerRef };
|
|
}
|
|
function createGetViewCapacity(state, source, itemSize) {
|
|
return (containerSize) => {
|
|
if (typeof itemSize === 'number')
|
|
return Math.ceil(containerSize / itemSize);
|
|
const { start = 0 } = state.value;
|
|
let sum = 0;
|
|
let capacity = 0;
|
|
for (let i = start; i < source.value.length; i++) {
|
|
const size = itemSize(i);
|
|
sum += size;
|
|
capacity = i;
|
|
if (sum > containerSize) break;
|
|
}
|
|
return capacity - start;
|
|
};
|
|
}
|
|
function createGetOffset(source, itemSize) {
|
|
return (scrollDirection) => {
|
|
if (typeof itemSize === 'number')
|
|
return Math.floor(scrollDirection / itemSize) + 1;
|
|
let sum = 0;
|
|
let offset = 0;
|
|
for (let i = 0; i < source.value.length; i++) {
|
|
const size = itemSize(i);
|
|
sum += size;
|
|
if (sum >= scrollDirection) {
|
|
offset = i;
|
|
break;
|
|
}
|
|
}
|
|
return offset + 1;
|
|
};
|
|
}
|
|
function createCalculateRange(
|
|
type,
|
|
overscan,
|
|
getOffset,
|
|
getViewCapacity,
|
|
{ containerRef, state, currentList, source }
|
|
) {
|
|
return () => {
|
|
const element = containerRef.value;
|
|
if (element) {
|
|
const offset = getOffset(
|
|
type === 'vertical' ? element.scrollTop : element.scrollLeft
|
|
);
|
|
const viewCapacity = getViewCapacity(
|
|
type === 'vertical' ? element.clientHeight : element.clientWidth
|
|
);
|
|
const from = offset - overscan;
|
|
const to = offset + viewCapacity + overscan;
|
|
state.value = {
|
|
start: from < 0 ? 0 : from,
|
|
end: to > source.value.length ? source.value.length : to,
|
|
};
|
|
currentList.value = source.value
|
|
.slice(state.value.start, state.value.end)
|
|
.map((ele, index) => ({
|
|
data: ele,
|
|
index: index + state.value.start,
|
|
}));
|
|
}
|
|
};
|
|
}
|
|
function createGetDistance(itemSize, source) {
|
|
return (index) => {
|
|
if (typeof itemSize === 'number') {
|
|
const size2 = index * itemSize;
|
|
return size2;
|
|
}
|
|
const size = source.value
|
|
.slice(0, index)
|
|
.reduce((sum, _, i) => sum + itemSize(i), 0);
|
|
return size;
|
|
};
|
|
}
|
|
function useWatchForSizes(size, list, containerRef, calculateRange) {
|
|
watch([size.width, size.height, list, containerRef], () => {
|
|
calculateRange();
|
|
});
|
|
}
|
|
function createComputedTotalSize(itemSize, source) {
|
|
return computed(() => {
|
|
if (typeof itemSize === 'number') return source.value.length * itemSize;
|
|
return source.value.reduce((sum, _, index) => sum + itemSize(index), 0);
|
|
});
|
|
}
|
|
var scrollToDictionaryForElementScrollKey = {
|
|
horizontal: 'scrollLeft',
|
|
vertical: 'scrollTop',
|
|
};
|
|
function createScrollTo(type, calculateRange, getDistance, containerRef) {
|
|
return (index) => {
|
|
if (containerRef.value) {
|
|
containerRef.value[scrollToDictionaryForElementScrollKey[type]] =
|
|
getDistance(index);
|
|
calculateRange();
|
|
}
|
|
};
|
|
}
|
|
function useHorizontalVirtualList(options, list) {
|
|
const resources = useVirtualListResources(list);
|
|
const { state, source, currentList, size, containerRef } = resources;
|
|
const containerStyle = { overflowX: 'auto' };
|
|
const { itemWidth, overscan = 5 } = options;
|
|
const getViewCapacity = createGetViewCapacity(state, source, itemWidth);
|
|
const getOffset = createGetOffset(source, itemWidth);
|
|
const calculateRange = createCalculateRange(
|
|
'horizontal',
|
|
overscan,
|
|
getOffset,
|
|
getViewCapacity,
|
|
resources
|
|
);
|
|
const getDistanceLeft = createGetDistance(itemWidth, source);
|
|
const offsetLeft = computed(() => getDistanceLeft(state.value.start));
|
|
const totalWidth = createComputedTotalSize(itemWidth, source);
|
|
useWatchForSizes(size, list, containerRef, calculateRange);
|
|
const scrollTo = createScrollTo(
|
|
'horizontal',
|
|
calculateRange,
|
|
getDistanceLeft,
|
|
containerRef
|
|
);
|
|
const wrapperProps = computed(() => {
|
|
return {
|
|
style: {
|
|
height: '100%',
|
|
width: `${totalWidth.value - offsetLeft.value}px`,
|
|
marginLeft: `${offsetLeft.value}px`,
|
|
display: 'flex',
|
|
},
|
|
};
|
|
});
|
|
return {
|
|
scrollTo,
|
|
calculateRange,
|
|
wrapperProps,
|
|
containerStyle,
|
|
currentList,
|
|
containerRef,
|
|
};
|
|
}
|
|
function useVerticalVirtualList(options, list) {
|
|
const resources = useVirtualListResources(list);
|
|
const { state, source, currentList, size, containerRef } = resources;
|
|
const containerStyle = { overflowY: 'auto' };
|
|
const { itemHeight, overscan = 5 } = options;
|
|
const getViewCapacity = createGetViewCapacity(state, source, itemHeight);
|
|
const getOffset = createGetOffset(source, itemHeight);
|
|
const calculateRange = createCalculateRange(
|
|
'vertical',
|
|
overscan,
|
|
getOffset,
|
|
getViewCapacity,
|
|
resources
|
|
);
|
|
const getDistanceTop = createGetDistance(itemHeight, source);
|
|
const offsetTop = computed(() => getDistanceTop(state.value.start));
|
|
const totalHeight = createComputedTotalSize(itemHeight, source);
|
|
useWatchForSizes(size, list, containerRef, calculateRange);
|
|
const scrollTo = createScrollTo(
|
|
'vertical',
|
|
calculateRange,
|
|
getDistanceTop,
|
|
containerRef
|
|
);
|
|
const wrapperProps = computed(() => {
|
|
return {
|
|
style: {
|
|
width: '100%',
|
|
height: `${totalHeight.value - offsetTop.value}px`,
|
|
marginTop: `${offsetTop.value}px`,
|
|
},
|
|
};
|
|
});
|
|
return {
|
|
calculateRange,
|
|
scrollTo,
|
|
containerStyle,
|
|
wrapperProps,
|
|
currentList,
|
|
containerRef,
|
|
};
|
|
}
|
|
function useWakeLock(options = {}) {
|
|
const {
|
|
navigator: navigator2 = defaultNavigator,
|
|
document: document2 = defaultDocument,
|
|
} = options;
|
|
const requestedType = shallowRef(false);
|
|
const sentinel = shallowRef(null);
|
|
const documentVisibility = useDocumentVisibility({ document: document2 });
|
|
const isSupported = useSupported(
|
|
() => navigator2 && 'wakeLock' in navigator2
|
|
);
|
|
const isActive = computed(
|
|
() => !!sentinel.value && documentVisibility.value === 'visible'
|
|
);
|
|
if (isSupported.value) {
|
|
useEventListener(
|
|
sentinel,
|
|
'release',
|
|
() => {
|
|
var _a, _b;
|
|
requestedType.value =
|
|
(_b = (_a = sentinel.value) == null ? void 0 : _a.type) != null
|
|
? _b
|
|
: false;
|
|
},
|
|
{ passive: true }
|
|
);
|
|
whenever(
|
|
() =>
|
|
documentVisibility.value === 'visible' &&
|
|
(document2 == null ? void 0 : document2.visibilityState) ===
|
|
'visible' &&
|
|
requestedType.value,
|
|
(type) => {
|
|
requestedType.value = false;
|
|
forceRequest(type);
|
|
}
|
|
);
|
|
}
|
|
async function forceRequest(type) {
|
|
var _a;
|
|
await ((_a = sentinel.value) == null ? void 0 : _a.release());
|
|
sentinel.value = isSupported.value
|
|
? await navigator2.wakeLock.request(type)
|
|
: null;
|
|
}
|
|
async function request(type) {
|
|
if (documentVisibility.value === 'visible') await forceRequest(type);
|
|
else requestedType.value = type;
|
|
}
|
|
async function release() {
|
|
requestedType.value = false;
|
|
const s = sentinel.value;
|
|
sentinel.value = null;
|
|
await (s == null ? void 0 : s.release());
|
|
}
|
|
return {
|
|
sentinel,
|
|
isSupported,
|
|
isActive,
|
|
request,
|
|
forceRequest,
|
|
release,
|
|
};
|
|
}
|
|
function useWebNotification(options = {}) {
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
requestPermissions: _requestForPermissions = true,
|
|
} = options;
|
|
const defaultWebNotificationOptions = options;
|
|
const isSupported = useSupported(() => {
|
|
if (!window2 || !('Notification' in window2)) return false;
|
|
if (Notification.permission === 'granted') return true;
|
|
try {
|
|
const notification2 = new Notification('');
|
|
notification2.onshow = () => {
|
|
notification2.close();
|
|
};
|
|
} catch (e) {
|
|
if (e.name === 'TypeError') return false;
|
|
}
|
|
return true;
|
|
});
|
|
const permissionGranted = shallowRef(
|
|
isSupported.value &&
|
|
'permission' in Notification &&
|
|
Notification.permission === 'granted'
|
|
);
|
|
const notification = ref(null);
|
|
const ensurePermissions = async () => {
|
|
if (!isSupported.value) return;
|
|
if (!permissionGranted.value && Notification.permission !== 'denied') {
|
|
const result = await Notification.requestPermission();
|
|
if (result === 'granted') permissionGranted.value = true;
|
|
}
|
|
return permissionGranted.value;
|
|
};
|
|
const { on: onClick, trigger: clickTrigger } = createEventHook();
|
|
const { on: onShow, trigger: showTrigger } = createEventHook();
|
|
const { on: onError, trigger: errorTrigger } = createEventHook();
|
|
const { on: onClose, trigger: closeTrigger } = createEventHook();
|
|
const show = async (overrides) => {
|
|
if (!isSupported.value || !permissionGranted.value) return;
|
|
const options2 = Object.assign(
|
|
{},
|
|
defaultWebNotificationOptions,
|
|
overrides
|
|
);
|
|
notification.value = new Notification(options2.title || '', options2);
|
|
notification.value.onclick = clickTrigger;
|
|
notification.value.onshow = showTrigger;
|
|
notification.value.onerror = errorTrigger;
|
|
notification.value.onclose = closeTrigger;
|
|
return notification.value;
|
|
};
|
|
const close = () => {
|
|
if (notification.value) notification.value.close();
|
|
notification.value = null;
|
|
};
|
|
if (_requestForPermissions) tryOnMounted(ensurePermissions);
|
|
tryOnScopeDispose(close);
|
|
if (isSupported.value && window2) {
|
|
const document2 = window2.document;
|
|
useEventListener(document2, 'visibilitychange', (e) => {
|
|
e.preventDefault();
|
|
if (document2.visibilityState === 'visible') {
|
|
close();
|
|
}
|
|
});
|
|
}
|
|
return {
|
|
isSupported,
|
|
notification,
|
|
ensurePermissions,
|
|
permissionGranted,
|
|
show,
|
|
close,
|
|
onClick,
|
|
onShow,
|
|
onError,
|
|
onClose,
|
|
};
|
|
}
|
|
var DEFAULT_PING_MESSAGE = 'ping';
|
|
function resolveNestedOptions(options) {
|
|
if (options === true) return {};
|
|
return options;
|
|
}
|
|
function useWebSocket(url, options = {}) {
|
|
const {
|
|
onConnected,
|
|
onDisconnected,
|
|
onError,
|
|
onMessage,
|
|
immediate = true,
|
|
autoConnect = true,
|
|
autoClose = true,
|
|
protocols = [],
|
|
} = options;
|
|
const data = ref(null);
|
|
const status = shallowRef('CLOSED');
|
|
const wsRef = ref();
|
|
const urlRef = toRef2(url);
|
|
let heartbeatPause;
|
|
let heartbeatResume;
|
|
let explicitlyClosed = false;
|
|
let retried = 0;
|
|
let bufferedData = [];
|
|
let retryTimeout;
|
|
let pongTimeoutWait;
|
|
const _sendBuffer = () => {
|
|
if (bufferedData.length && wsRef.value && status.value === 'OPEN') {
|
|
for (const buffer of bufferedData) wsRef.value.send(buffer);
|
|
bufferedData = [];
|
|
}
|
|
};
|
|
const resetRetry = () => {
|
|
if (retryTimeout != null) {
|
|
clearTimeout(retryTimeout);
|
|
retryTimeout = void 0;
|
|
}
|
|
};
|
|
const resetHeartbeat = () => {
|
|
clearTimeout(pongTimeoutWait);
|
|
pongTimeoutWait = void 0;
|
|
};
|
|
const close = (code = 1e3, reason) => {
|
|
resetRetry();
|
|
if ((!isClient && !isWorker) || !wsRef.value) return;
|
|
explicitlyClosed = true;
|
|
resetHeartbeat();
|
|
heartbeatPause == null ? void 0 : heartbeatPause();
|
|
wsRef.value.close(code, reason);
|
|
wsRef.value = void 0;
|
|
};
|
|
const send = (data2, useBuffer = true) => {
|
|
if (!wsRef.value || status.value !== 'OPEN') {
|
|
if (useBuffer) bufferedData.push(data2);
|
|
return false;
|
|
}
|
|
_sendBuffer();
|
|
wsRef.value.send(data2);
|
|
return true;
|
|
};
|
|
const _init = () => {
|
|
if (explicitlyClosed || typeof urlRef.value === 'undefined') return;
|
|
const ws = new WebSocket(urlRef.value, protocols);
|
|
wsRef.value = ws;
|
|
status.value = 'CONNECTING';
|
|
ws.onopen = () => {
|
|
status.value = 'OPEN';
|
|
retried = 0;
|
|
onConnected == null ? void 0 : onConnected(ws);
|
|
heartbeatResume == null ? void 0 : heartbeatResume();
|
|
_sendBuffer();
|
|
};
|
|
ws.onclose = (ev) => {
|
|
status.value = 'CLOSED';
|
|
resetHeartbeat();
|
|
heartbeatPause == null ? void 0 : heartbeatPause();
|
|
onDisconnected == null ? void 0 : onDisconnected(ws, ev);
|
|
if (
|
|
!explicitlyClosed &&
|
|
options.autoReconnect &&
|
|
(wsRef.value == null || ws === wsRef.value)
|
|
) {
|
|
const {
|
|
retries = -1,
|
|
delay = 1e3,
|
|
onFailed,
|
|
} = resolveNestedOptions(options.autoReconnect);
|
|
const checkRetires =
|
|
typeof retries === 'function'
|
|
? retries
|
|
: () =>
|
|
typeof retries === 'number' &&
|
|
(retries < 0 || retried < retries);
|
|
if (checkRetires(retried)) {
|
|
retried += 1;
|
|
retryTimeout = setTimeout(_init, delay);
|
|
} else {
|
|
onFailed == null ? void 0 : onFailed();
|
|
}
|
|
}
|
|
};
|
|
ws.onerror = (e) => {
|
|
onError == null ? void 0 : onError(ws, e);
|
|
};
|
|
ws.onmessage = (e) => {
|
|
if (options.heartbeat) {
|
|
resetHeartbeat();
|
|
const { message = DEFAULT_PING_MESSAGE, responseMessage = message } =
|
|
resolveNestedOptions(options.heartbeat);
|
|
if (e.data === toValue(responseMessage)) return;
|
|
}
|
|
data.value = e.data;
|
|
onMessage == null ? void 0 : onMessage(ws, e);
|
|
};
|
|
};
|
|
if (options.heartbeat) {
|
|
const {
|
|
message = DEFAULT_PING_MESSAGE,
|
|
interval = 1e3,
|
|
pongTimeout = 1e3,
|
|
} = resolveNestedOptions(options.heartbeat);
|
|
const { pause, resume } = useIntervalFn(
|
|
() => {
|
|
send(toValue(message), false);
|
|
if (pongTimeoutWait != null) return;
|
|
pongTimeoutWait = setTimeout(() => {
|
|
close();
|
|
explicitlyClosed = false;
|
|
}, pongTimeout);
|
|
},
|
|
interval,
|
|
{ immediate: false }
|
|
);
|
|
heartbeatPause = pause;
|
|
heartbeatResume = resume;
|
|
}
|
|
if (autoClose) {
|
|
if (isClient)
|
|
useEventListener('beforeunload', () => close(), { passive: true });
|
|
tryOnScopeDispose(close);
|
|
}
|
|
const open = () => {
|
|
if (!isClient && !isWorker) return;
|
|
close();
|
|
explicitlyClosed = false;
|
|
retried = 0;
|
|
_init();
|
|
};
|
|
if (immediate) open();
|
|
if (autoConnect) watch(urlRef, open);
|
|
return {
|
|
data,
|
|
status,
|
|
close,
|
|
send,
|
|
open,
|
|
ws: wsRef,
|
|
};
|
|
}
|
|
function useWebWorker(arg0, workerOptions, options) {
|
|
const { window: window2 = defaultWindow } = options != null ? options : {};
|
|
const data = ref(null);
|
|
const worker = shallowRef();
|
|
const post = (...args) => {
|
|
if (!worker.value) return;
|
|
worker.value.postMessage(...args);
|
|
};
|
|
const terminate = function terminate2() {
|
|
if (!worker.value) return;
|
|
worker.value.terminate();
|
|
};
|
|
if (window2) {
|
|
if (typeof arg0 === 'string')
|
|
worker.value = new Worker(arg0, workerOptions);
|
|
else if (typeof arg0 === 'function') worker.value = arg0();
|
|
else worker.value = arg0;
|
|
worker.value.onmessage = (e) => {
|
|
data.value = e.data;
|
|
};
|
|
tryOnScopeDispose(() => {
|
|
if (worker.value) worker.value.terminate();
|
|
});
|
|
}
|
|
return {
|
|
data,
|
|
post,
|
|
terminate,
|
|
worker,
|
|
};
|
|
}
|
|
function depsParser(deps, localDeps) {
|
|
if (deps.length === 0 && localDeps.length === 0) return '';
|
|
const depsString = deps.map((dep) => `'${dep}'`).toString();
|
|
const depsFunctionString = localDeps
|
|
.filter((dep) => typeof dep === 'function')
|
|
.map((fn) => {
|
|
const str = fn.toString();
|
|
if (str.trim().startsWith('function')) {
|
|
return str;
|
|
} else {
|
|
const name = fn.name;
|
|
return `const ${name} = ${str}`;
|
|
}
|
|
})
|
|
.join(';');
|
|
const importString = `importScripts(${depsString});`;
|
|
return `${depsString.trim() === '' ? '' : importString} ${depsFunctionString}`;
|
|
}
|
|
function jobRunner(userFunc) {
|
|
return (e) => {
|
|
const userFuncArgs = e.data[0];
|
|
return Promise.resolve(userFunc.apply(void 0, userFuncArgs))
|
|
.then((result) => {
|
|
postMessage(['SUCCESS', result]);
|
|
})
|
|
.catch((error) => {
|
|
postMessage(['ERROR', error]);
|
|
});
|
|
};
|
|
}
|
|
function createWorkerBlobUrl(fn, deps, localDeps) {
|
|
const blobCode = `${depsParser(deps, localDeps)}; onmessage=(${jobRunner})(${fn})`;
|
|
const blob = new Blob([blobCode], { type: 'text/javascript' });
|
|
const url = URL.createObjectURL(blob);
|
|
return url;
|
|
}
|
|
function useWebWorkerFn(fn, options = {}) {
|
|
const {
|
|
dependencies = [],
|
|
localDependencies = [],
|
|
timeout,
|
|
window: window2 = defaultWindow,
|
|
} = options;
|
|
const worker = ref();
|
|
const workerStatus = shallowRef('PENDING');
|
|
const promise = ref({});
|
|
const timeoutId = shallowRef();
|
|
const workerTerminate = (status = 'PENDING') => {
|
|
if (worker.value && worker.value._url && window2) {
|
|
worker.value.terminate();
|
|
URL.revokeObjectURL(worker.value._url);
|
|
promise.value = {};
|
|
worker.value = void 0;
|
|
window2.clearTimeout(timeoutId.value);
|
|
workerStatus.value = status;
|
|
}
|
|
};
|
|
workerTerminate();
|
|
tryOnScopeDispose(workerTerminate);
|
|
const generateWorker = () => {
|
|
const blobUrl = createWorkerBlobUrl(fn, dependencies, localDependencies);
|
|
const newWorker = new Worker(blobUrl);
|
|
newWorker._url = blobUrl;
|
|
newWorker.onmessage = (e) => {
|
|
const { resolve = () => {}, reject = () => {} } = promise.value;
|
|
const [status, result] = e.data;
|
|
switch (status) {
|
|
case 'SUCCESS':
|
|
resolve(result);
|
|
workerTerminate(status);
|
|
break;
|
|
default:
|
|
reject(result);
|
|
workerTerminate('ERROR');
|
|
break;
|
|
}
|
|
};
|
|
newWorker.onerror = (e) => {
|
|
const { reject = () => {} } = promise.value;
|
|
e.preventDefault();
|
|
reject(e);
|
|
workerTerminate('ERROR');
|
|
};
|
|
if (timeout) {
|
|
timeoutId.value = setTimeout(
|
|
() => workerTerminate('TIMEOUT_EXPIRED'),
|
|
timeout
|
|
);
|
|
}
|
|
return newWorker;
|
|
};
|
|
const callWorker = (...fnArgs) =>
|
|
new Promise((resolve, reject) => {
|
|
var _a;
|
|
promise.value = {
|
|
resolve,
|
|
reject,
|
|
};
|
|
(_a = worker.value) == null ? void 0 : _a.postMessage([[...fnArgs]]);
|
|
workerStatus.value = 'RUNNING';
|
|
});
|
|
const workerFn = (...fnArgs) => {
|
|
if (workerStatus.value === 'RUNNING') {
|
|
console.error(
|
|
'[useWebWorkerFn] You can only run one instance of the worker at a time.'
|
|
);
|
|
return Promise.reject();
|
|
}
|
|
worker.value = generateWorker();
|
|
return callWorker(...fnArgs);
|
|
};
|
|
return {
|
|
workerFn,
|
|
workerStatus,
|
|
workerTerminate,
|
|
};
|
|
}
|
|
function useWindowFocus(options = {}) {
|
|
const { window: window2 = defaultWindow } = options;
|
|
if (!window2) return shallowRef(false);
|
|
const focused = shallowRef(window2.document.hasFocus());
|
|
const listenerOptions = { passive: true };
|
|
useEventListener(
|
|
window2,
|
|
'blur',
|
|
() => {
|
|
focused.value = false;
|
|
},
|
|
listenerOptions
|
|
);
|
|
useEventListener(
|
|
window2,
|
|
'focus',
|
|
() => {
|
|
focused.value = true;
|
|
},
|
|
listenerOptions
|
|
);
|
|
return focused;
|
|
}
|
|
function useWindowScroll(options = {}) {
|
|
const { window: window2 = defaultWindow, ...rest } = options;
|
|
return useScroll(window2, rest);
|
|
}
|
|
function useWindowSize(options = {}) {
|
|
const {
|
|
window: window2 = defaultWindow,
|
|
initialWidth = Number.POSITIVE_INFINITY,
|
|
initialHeight = Number.POSITIVE_INFINITY,
|
|
listenOrientation = true,
|
|
includeScrollbar = true,
|
|
type = 'inner',
|
|
} = options;
|
|
const width = shallowRef(initialWidth);
|
|
const height = shallowRef(initialHeight);
|
|
const update = () => {
|
|
if (window2) {
|
|
if (type === 'outer') {
|
|
width.value = window2.outerWidth;
|
|
height.value = window2.outerHeight;
|
|
} else if (type === 'visual' && window2.visualViewport) {
|
|
const {
|
|
width: visualViewportWidth,
|
|
height: visualViewportHeight,
|
|
scale,
|
|
} = window2.visualViewport;
|
|
width.value = Math.round(visualViewportWidth * scale);
|
|
height.value = Math.round(visualViewportHeight * scale);
|
|
} else if (includeScrollbar) {
|
|
width.value = window2.innerWidth;
|
|
height.value = window2.innerHeight;
|
|
} else {
|
|
width.value = window2.document.documentElement.clientWidth;
|
|
height.value = window2.document.documentElement.clientHeight;
|
|
}
|
|
}
|
|
};
|
|
update();
|
|
tryOnMounted(update);
|
|
const listenerOptions = { passive: true };
|
|
useEventListener('resize', update, listenerOptions);
|
|
if (window2 && type === 'visual' && window2.visualViewport) {
|
|
useEventListener(window2.visualViewport, 'resize', update, listenerOptions);
|
|
}
|
|
if (listenOrientation) {
|
|
const matches = useMediaQuery('(orientation: portrait)');
|
|
watch(matches, () => update());
|
|
}
|
|
return { width, height };
|
|
}
|
|
|
|
export {
|
|
computedEager,
|
|
computedWithControl,
|
|
tryOnScopeDispose,
|
|
createEventHook,
|
|
createGlobalState,
|
|
injectLocal,
|
|
provideLocal,
|
|
createInjectionState,
|
|
createRef,
|
|
createSharedComposable,
|
|
extendRef,
|
|
get,
|
|
isDefined,
|
|
makeDestructurable,
|
|
reactify,
|
|
reactifyObject,
|
|
toReactive,
|
|
reactiveComputed,
|
|
reactiveOmit,
|
|
isClient,
|
|
isWorker,
|
|
isDef,
|
|
notNullish,
|
|
assert,
|
|
isObject,
|
|
now,
|
|
timestamp,
|
|
clamp,
|
|
noop,
|
|
rand,
|
|
hasOwn,
|
|
isIOS,
|
|
createFilterWrapper,
|
|
bypassFilter,
|
|
debounceFilter,
|
|
throttleFilter,
|
|
pausableFilter,
|
|
hyphenate,
|
|
camelize,
|
|
promiseTimeout,
|
|
identity,
|
|
createSingletonPromise,
|
|
invoke,
|
|
containsProp,
|
|
increaseWithUnit,
|
|
pxValue,
|
|
objectPick,
|
|
objectOmit,
|
|
objectEntries,
|
|
getLifeCycleTarget,
|
|
toArray,
|
|
toRef2 as toRef,
|
|
resolveRef,
|
|
reactivePick,
|
|
refAutoReset,
|
|
useDebounceFn,
|
|
refDebounced,
|
|
refDefault,
|
|
useThrottleFn,
|
|
refThrottled,
|
|
refWithControl,
|
|
controlledRef,
|
|
set,
|
|
watchWithFilter,
|
|
watchPausable,
|
|
syncRef,
|
|
syncRefs,
|
|
toRefs2 as toRefs,
|
|
toValue2 as toValue,
|
|
resolveUnref,
|
|
tryOnBeforeMount,
|
|
tryOnBeforeUnmount,
|
|
tryOnMounted,
|
|
tryOnUnmounted,
|
|
until,
|
|
useArrayDifference,
|
|
useArrayEvery,
|
|
useArrayFilter,
|
|
useArrayFind,
|
|
useArrayFindIndex,
|
|
useArrayFindLast,
|
|
useArrayIncludes,
|
|
useArrayJoin,
|
|
useArrayMap,
|
|
useArrayReduce,
|
|
useArraySome,
|
|
useArrayUnique,
|
|
useCounter,
|
|
formatDate,
|
|
normalizeDate,
|
|
useDateFormat,
|
|
useIntervalFn,
|
|
useInterval,
|
|
useLastChanged,
|
|
useTimeoutFn,
|
|
useTimeout,
|
|
useToNumber,
|
|
useToString,
|
|
useToggle,
|
|
watchArray,
|
|
watchAtMost,
|
|
watchDebounced,
|
|
watchDeep,
|
|
watchIgnorable,
|
|
watchImmediate,
|
|
watchOnce,
|
|
watchThrottled,
|
|
watchTriggerable,
|
|
whenever,
|
|
computedAsync,
|
|
computedInject,
|
|
createReusableTemplate,
|
|
createTemplatePromise,
|
|
createUnrefFn,
|
|
defaultWindow,
|
|
defaultDocument,
|
|
defaultNavigator,
|
|
defaultLocation,
|
|
unrefElement,
|
|
useEventListener,
|
|
onClickOutside,
|
|
useMounted,
|
|
useSupported,
|
|
useMutationObserver,
|
|
onElementRemoval,
|
|
onKeyStroke,
|
|
onKeyDown,
|
|
onKeyPressed,
|
|
onKeyUp,
|
|
onLongPress,
|
|
onStartTyping,
|
|
templateRef,
|
|
useActiveElement,
|
|
useRafFn,
|
|
useAnimate,
|
|
useAsyncQueue,
|
|
useAsyncState,
|
|
useBase64,
|
|
useBattery,
|
|
useBluetooth,
|
|
useSSRWidth,
|
|
provideSSRWidth,
|
|
useMediaQuery,
|
|
breakpointsTailwind,
|
|
breakpointsBootstrapV5,
|
|
breakpointsVuetifyV2,
|
|
breakpointsVuetifyV3,
|
|
breakpointsVuetify,
|
|
breakpointsAntDesign,
|
|
breakpointsQuasar,
|
|
breakpointsSematic,
|
|
breakpointsMasterCss,
|
|
breakpointsPrimeFlex,
|
|
breakpointsElement,
|
|
useBreakpoints,
|
|
useBroadcastChannel,
|
|
useBrowserLocation,
|
|
useCached,
|
|
usePermission,
|
|
useClipboard,
|
|
useClipboardItems,
|
|
cloneFnJSON,
|
|
useCloned,
|
|
getSSRHandler,
|
|
setSSRHandler,
|
|
usePreferredDark,
|
|
StorageSerializers,
|
|
customStorageEventName,
|
|
useStorage,
|
|
useColorMode,
|
|
useConfirmDialog,
|
|
useCountdown,
|
|
useCssVar,
|
|
useCurrentElement,
|
|
useCycleList,
|
|
useDark,
|
|
useManualRefHistory,
|
|
useRefHistory,
|
|
useDebouncedRefHistory,
|
|
useDeviceMotion,
|
|
useDeviceOrientation,
|
|
useDevicePixelRatio,
|
|
useDevicesList,
|
|
useDisplayMedia,
|
|
useDocumentVisibility,
|
|
useDraggable,
|
|
useDropZone,
|
|
useResizeObserver,
|
|
useElementBounding,
|
|
useElementByPoint,
|
|
useElementHover,
|
|
useElementSize,
|
|
useIntersectionObserver,
|
|
useElementVisibility,
|
|
useEventBus,
|
|
useEventSource,
|
|
useEyeDropper,
|
|
useFavicon,
|
|
createFetch,
|
|
useFetch,
|
|
useFileDialog,
|
|
useFileSystemAccess,
|
|
useFocus,
|
|
useFocusWithin,
|
|
useFps,
|
|
useFullscreen,
|
|
mapGamepadToXbox360Controller,
|
|
useGamepad,
|
|
useGeolocation,
|
|
useIdle,
|
|
useImage,
|
|
useScroll,
|
|
useInfiniteScroll,
|
|
useKeyModifier,
|
|
useLocalStorage,
|
|
DefaultMagicKeysAliasMap,
|
|
useMagicKeys,
|
|
useMediaControls,
|
|
useMemoize,
|
|
useMemory,
|
|
useMouse,
|
|
useMouseInElement,
|
|
useMousePressed,
|
|
useNavigatorLanguage,
|
|
useNetwork,
|
|
useNow,
|
|
useObjectUrl,
|
|
useOffsetPagination,
|
|
useOnline,
|
|
usePageLeave,
|
|
useScreenOrientation,
|
|
useParallax,
|
|
useParentElement,
|
|
usePerformanceObserver,
|
|
usePointer,
|
|
usePointerLock,
|
|
usePointerSwipe,
|
|
usePreferredColorScheme,
|
|
usePreferredContrast,
|
|
usePreferredLanguages,
|
|
usePreferredReducedMotion,
|
|
usePreferredReducedTransparency,
|
|
usePrevious,
|
|
useScreenSafeArea,
|
|
useScriptTag,
|
|
useScrollLock,
|
|
useSessionStorage,
|
|
useShare,
|
|
useSorted,
|
|
useSpeechRecognition,
|
|
useSpeechSynthesis,
|
|
useStepper,
|
|
useStorageAsync,
|
|
useStyleTag,
|
|
useSwipe,
|
|
useTemplateRefsList,
|
|
useTextDirection,
|
|
useTextSelection,
|
|
useTextareaAutosize,
|
|
useThrottledRefHistory,
|
|
useTimeAgo,
|
|
formatTimeAgo,
|
|
useTimeoutPoll,
|
|
useTimestamp,
|
|
useTitle,
|
|
TransitionPresets,
|
|
executeTransition,
|
|
useTransition,
|
|
useUrlSearchParams,
|
|
useUserMedia,
|
|
useVModel,
|
|
useVModels,
|
|
useVibrate,
|
|
useVirtualList,
|
|
useWakeLock,
|
|
useWebNotification,
|
|
useWebSocket,
|
|
useWebWorker,
|
|
useWebWorkerFn,
|
|
useWindowFocus,
|
|
useWindowScroll,
|
|
useWindowSize,
|
|
};
|
|
//# sourceMappingURL=chunk-BRNHR3LR.js.map
|