@dolusoft/vue3-datatable
Version:
Vue3 Datatable - fully customizable & easy to use datatable library
1,499 lines • 305 kB
JavaScript
import { isRef, onMounted, nextTick, getCurrentScope, onScopeDispose, unref, getCurrentInstance, computed, ref, watch, useSlots, onBeforeUnmount, provide, openBlock, createBlock, resolveDynamicComponent, inject, createElementBlock, normalizeStyle, renderSlot, h as h$2, defineComponent, toRef, Fragment, withModifiers, createVNode, pushScopeId, popScopeId, normalizeClass, normalizeProps, guardReactiveProps, withScopeId, resolveComponent, withKeys, createElementVNode, createCommentVNode, mergeProps, withCtx, toDisplayString, withDirectives, renderList, vModelSelect, createTextVNode, vModelText, vShow, onUnmounted, createSlots, vModelCheckbox } from "vue";
function tryOnScopeDispose(fn) {
if (getCurrentScope()) {
onScopeDispose(fn);
return true;
}
return false;
}
function toValue(r2) {
return typeof r2 === "function" ? r2() : unref(r2);
}
const isClient = typeof window !== "undefined" && typeof document !== "undefined";
typeof WorkerGlobalScope !== "undefined" && globalThis instanceof WorkerGlobalScope;
const toString = Object.prototype.toString;
const isObject = (val) => toString.call(val) === "[object Object]";
const noop = () => {
};
const isIOS = /* @__PURE__ */ 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;
}
function debounceFilter(ms, options = {}) {
let timer;
let maxTimer;
let lastRejector = noop;
const _clearTimeout = (timer2) => {
clearTimeout(timer2);
lastRejector();
lastRejector = noop;
};
const filter = (invoke) => {
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(invoke());
}
return new Promise((resolve, reject) => {
lastRejector = options.rejectOnCancel ? reject : resolve;
if (maxDuration && !maxTimer) {
maxTimer = setTimeout(() => {
if (timer)
_clearTimeout(timer);
maxTimer = null;
resolve(invoke());
}, maxDuration);
}
timer = setTimeout(() => {
if (maxTimer)
_clearTimeout(maxTimer);
maxTimer = null;
resolve(invoke());
}, 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 invoke = () => {
return lastValue = _invoke();
};
clear();
if (duration <= 0) {
lastExec = Date.now();
return invoke();
}
if (elapsed > duration && (leading || !isLeading)) {
lastExec = Date.now();
invoke();
} else if (trailing) {
lastValue = new Promise((resolve, reject) => {
lastRejector = rejectOnCancel ? reject : resolve;
timer = setTimeout(() => {
lastExec = Date.now();
isLeading = true;
resolve(invoke());
clear();
}, Math.max(0, duration - elapsed));
});
}
if (!leading && !timer)
timer = setTimeout(() => isLeading = true, duration);
isLeading = false;
return lastValue;
};
return filter;
}
function getLifeCycleTarget(target) {
return getCurrentInstance();
}
function useDebounceFn(fn, ms = 200, options = {}) {
return createFilterWrapper(
debounceFilter(ms, options),
fn
);
}
function useThrottleFn(fn, ms = 200, trailing = false, leading = true, rejectOnCancel = false) {
return createFilterWrapper(
throttleFilter(ms, trailing, leading, rejectOnCancel),
fn
);
}
function tryOnMounted(fn, sync = true, target) {
const instance = getLifeCycleTarget();
if (instance)
onMounted(fn, target);
else if (sync)
fn();
else
nextTick(fn);
}
function unrefElement(elRef) {
var _a;
const plain = toValue(elRef);
return (_a = plain == null ? void 0 : plain.$el) != null ? _a : plain;
}
const defaultWindow = isClient ? window : void 0;
function useEventListener(...args) {
let target;
let events;
let listeners;
let options;
if (typeof args[0] === "string" || Array.isArray(args[0])) {
[events, listeners, options] = args;
target = defaultWindow;
} else {
[target, events, listeners, options] = args;
}
if (!target)
return noop;
if (!Array.isArray(events))
events = [events];
if (!Array.isArray(listeners))
listeners = [listeners];
const cleanups = [];
const cleanup = () => {
cleanups.forEach((fn) => fn());
cleanups.length = 0;
};
const register = (el, event, listener, options2) => {
el.addEventListener(event, listener, options2);
return () => el.removeEventListener(event, listener, options2);
};
const stopWatch = watch(
() => [unrefElement(target), toValue(options)],
([el, options2]) => {
cleanup();
if (!el)
return;
const optionsClone = isObject(options2) ? { ...options2 } : options2;
cleanups.push(
...events.flatMap((event) => {
return listeners.map((listener) => register(el, event, listener, optionsClone));
})
);
},
{ immediate: true, flush: "post" }
);
const stop = () => {
stopWatch();
cleanup();
};
tryOnScopeDispose(stop);
return stop;
}
let _iOSWorkaround = false;
function onClickOutside(target, handler, options = {}) {
const { window: window2 = defaultWindow, ignore = [], capture = true, detectIframe = false } = options;
if (!window2)
return noop;
if (isIOS && !_iOSWorkaround) {
_iOSWorkaround = true;
Array.from(window2.document.body.children).forEach((el) => el.addEventListener("click", noop));
window2.document.documentElement.addEventListener("click", noop);
}
let shouldListen = true;
const shouldIgnore = (event) => {
return 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));
}
});
};
const listener = (event) => {
const el = unrefElement(target);
if (!el || el === event.target || event.composedPath().includes(el))
return;
if (event.detail === 0)
shouldListen = !shouldIgnore(event);
if (!shouldListen) {
shouldListen = true;
return;
}
handler(event);
};
const cleanup = [
useEventListener(window2, "click", listener, { 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);
})
].filter(Boolean);
const stop = () => cleanup.forEach((fn) => fn());
return stop;
}
function useMounted() {
const isMounted = ref(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 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(() => Array.isArray(target) ? target.map((el) => unrefElement(el)) : [unrefElement(target)]);
const stopWatch = watch(
targets,
(els) => {
cleanup();
if (isSupported.value && window2) {
observer = new ResizeObserver(callback);
for (const _el of els)
_el && observer.observe(_el, observerOptions);
}
},
{ immediate: true, flush: "post" }
);
const stop = () => {
cleanup();
stopWatch();
};
tryOnScopeDispose(stop);
return {
isSupported,
stop
};
}
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 = ref(initialSize.width);
const height = ref(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 = Array.isArray(boxSize) ? boxSize : [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
};
}
const Pe$1 = {
__name: "splitpanes",
props: {
horizontal: { type: Boolean, default: false },
pushOtherPanes: { type: Boolean, default: true },
maximizePanes: { type: Boolean, default: true },
// Maximize pane on splitter double click/tap.
rtl: { type: Boolean, default: false },
// Right to left direction.
firstSplitter: { type: Boolean, default: false }
},
emits: [
"ready",
"resize",
"resized",
"pane-click",
"pane-maximize",
"pane-add",
"pane-remove",
"splitter-click",
"splitter-dblclick"
],
setup(D2, { emit: h2 }) {
const y2 = h2, u2 = D2, E2 = useSlots(), l2 = ref([]), M = computed(() => l2.value.reduce((e, n2) => (e[~~n2.id] = n2) && e, {})), m2 = computed(() => l2.value.length), x2 = ref(null), S2 = ref(false), c2 = ref({
mouseDown: false,
dragging: false,
activeSplitter: null,
cursorOffset: 0
// Cursor offset within the splitter.
}), f2 = ref({
// Used to detect double click on touch devices.
splitter: null,
timeoutId: null
}), _2 = computed(() => ({
[`splitpanes splitpanes--${u2.horizontal ? "horizontal" : "vertical"}`]: true,
"splitpanes--dragging": c2.value.dragging
})), R2 = () => {
document.addEventListener("mousemove", r2, { passive: false }), document.addEventListener("mouseup", P2), "ontouchstart" in window && (document.addEventListener("touchmove", r2, { passive: false }), document.addEventListener("touchend", P2));
}, O2 = () => {
document.removeEventListener("mousemove", r2, { passive: false }), document.removeEventListener("mouseup", P2), "ontouchstart" in window && (document.removeEventListener("touchmove", r2, { passive: false }), document.removeEventListener("touchend", P2));
}, b2 = (e, n2) => {
const t = e.target.closest(".splitpanes__splitter");
if (t) {
const { left: i2, top: a2 } = t.getBoundingClientRect(), { clientX: s2, clientY: o2 } = "ontouchstart" in window && e.touches ? e.touches[0] : e;
c2.value.cursorOffset = u2.horizontal ? o2 - a2 : s2 - i2;
}
R2(), c2.value.mouseDown = true, c2.value.activeSplitter = n2;
}, r2 = (e) => {
c2.value.mouseDown && (e.preventDefault(), c2.value.dragging = true, requestAnimationFrame(() => {
K2(I(e)), d2("resize", { event: e }, true);
}));
}, P2 = (e) => {
c2.value.dragging && d2("resized", { event: e }, true), c2.value.mouseDown = false, c2.value.activeSplitter = null, setTimeout(() => {
c2.value.dragging = false, O2();
}, 100);
}, A2 = (e, n2) => {
"ontouchstart" in window && (e.preventDefault(), f2.value.splitter === n2 ? (clearTimeout(f2.value.timeoutId), f2.value.timeoutId = null, U(e, n2), f2.value.splitter = null) : (f2.value.splitter = n2, f2.value.timeoutId = setTimeout(() => f2.value.splitter = null, 500))), c2.value.dragging || d2("splitter-click", { event: e, index: n2 }, true);
}, U = (e, n2) => {
if (d2("splitter-dblclick", { event: e, index: n2 }, true), u2.maximizePanes) {
let t = 0;
l2.value = l2.value.map((i2, a2) => (i2.size = a2 === n2 ? i2.max : i2.min, a2 !== n2 && (t += i2.min), i2)), l2.value[n2].size -= t, d2("pane-maximize", { event: e, index: n2, pane: l2.value[n2] }), d2("resized", { event: e, index: n2 }, true);
}
}, W2 = (e, n2) => {
d2("pane-click", {
event: e,
index: M.value[n2].index,
pane: M.value[n2]
});
}, I = (e) => {
const n2 = x2.value.getBoundingClientRect(), { clientX: t, clientY: i2 } = "ontouchstart" in window && e.touches ? e.touches[0] : e;
return {
x: t - (u2.horizontal ? 0 : c2.value.cursorOffset) - n2.left,
y: i2 - (u2.horizontal ? c2.value.cursorOffset : 0) - n2.top
};
}, J = (e) => {
e = e[u2.horizontal ? "y" : "x"];
const n2 = x2.value[u2.horizontal ? "clientHeight" : "clientWidth"];
return u2.rtl && !u2.horizontal && (e = n2 - e), e * 100 / n2;
}, K2 = (e) => {
const n2 = c2.value.activeSplitter;
let t = {
prevPanesSize: $2(n2),
nextPanesSize: N(n2),
prevReachedMinPanes: 0,
nextReachedMinPanes: 0
};
const i2 = 0 + (u2.pushOtherPanes ? 0 : t.prevPanesSize), a2 = 100 - (u2.pushOtherPanes ? 0 : t.nextPanesSize), s2 = Math.max(Math.min(J(e), a2), i2);
let o2 = [n2, n2 + 1], v2 = l2.value[o2[0]] || null, p2 = l2.value[o2[1]] || null;
const H2 = v2.max < 100 && s2 >= v2.max + t.prevPanesSize, ue2 = p2.max < 100 && s2 <= 100 - (p2.max + N(n2 + 1));
if (H2 || ue2) {
H2 ? (v2.size = v2.max, p2.size = Math.max(100 - v2.max - t.prevPanesSize - t.nextPanesSize, 0)) : (v2.size = Math.max(100 - p2.max - t.prevPanesSize - N(n2 + 1), 0), p2.size = p2.max);
return;
}
if (u2.pushOtherPanes) {
const j = Q2(t, s2);
if (!j) return;
({ sums: t, panesToResize: o2 } = j), v2 = l2.value[o2[0]] || null, p2 = l2.value[o2[1]] || null;
}
v2 !== null && (v2.size = Math.min(Math.max(s2 - t.prevPanesSize - t.prevReachedMinPanes, v2.min), v2.max)), p2 !== null && (p2.size = Math.min(Math.max(100 - s2 - t.nextPanesSize - t.nextReachedMinPanes, p2.min), p2.max));
}, Q2 = (e, n2) => {
const t = c2.value.activeSplitter, i2 = [t, t + 1];
return n2 < e.prevPanesSize + l2.value[i2[0]].min && (i2[0] = V(t).index, e.prevReachedMinPanes = 0, i2[0] < t && l2.value.forEach((a2, s2) => {
s2 > i2[0] && s2 <= t && (a2.size = a2.min, e.prevReachedMinPanes += a2.min);
}), e.prevPanesSize = $2(i2[0]), i2[0] === void 0) ? (e.prevReachedMinPanes = 0, l2.value[0].size = l2.value[0].min, l2.value.forEach((a2, s2) => {
s2 > 0 && s2 <= t && (a2.size = a2.min, e.prevReachedMinPanes += a2.min);
}), l2.value[i2[1]].size = 100 - e.prevReachedMinPanes - l2.value[0].min - e.prevPanesSize - e.nextPanesSize, null) : n2 > 100 - e.nextPanesSize - l2.value[i2[1]].min && (i2[1] = Z2(t).index, e.nextReachedMinPanes = 0, i2[1] > t + 1 && l2.value.forEach((a2, s2) => {
s2 > t && s2 < i2[1] && (a2.size = a2.min, e.nextReachedMinPanes += a2.min);
}), e.nextPanesSize = N(i2[1] - 1), i2[1] === void 0) ? (e.nextReachedMinPanes = 0, l2.value.forEach((a2, s2) => {
s2 < m2.value - 1 && s2 >= t + 1 && (a2.size = a2.min, e.nextReachedMinPanes += a2.min);
}), l2.value[i2[0]].size = 100 - e.prevPanesSize - N(i2[0] - 1), null) : { sums: e, panesToResize: i2 };
}, $2 = (e) => l2.value.reduce((n2, t, i2) => n2 + (i2 < e ? t.size : 0), 0), N = (e) => l2.value.reduce((n2, t, i2) => n2 + (i2 > e + 1 ? t.size : 0), 0), V = (e) => [...l2.value].reverse().find((t) => t.index < e && t.size > t.min) || {}, Z2 = (e) => l2.value.find((t) => t.index > e + 1 && t.size > t.min) || {}, ee2 = () => {
var n2;
const e = Array.from(((n2 = x2.value) == null ? void 0 : n2.children) || []);
for (const t of e) {
const i2 = t.classList.contains("splitpanes__pane"), a2 = t.classList.contains("splitpanes__splitter");
!i2 && !a2 && (t.remove(), console.warn("Splitpanes: Only <pane> elements are allowed at the root of <splitpanes>. One of your DOM nodes was removed."));
}
}, F2 = (e, n2, t = false) => {
const i2 = e - 1, a2 = document.createElement("div");
a2.classList.add("splitpanes__splitter"), t || (a2.onmousedown = (s2) => b2(s2, i2), typeof window < "u" && "ontouchstart" in window && (a2.ontouchstart = (s2) => b2(s2, i2)), a2.onclick = (s2) => A2(s2, i2 + 1)), a2.ondblclick = (s2) => U(s2, i2 + 1), n2.parentNode.insertBefore(a2, n2);
}, ne = (e) => {
e.onmousedown = void 0, e.onclick = void 0, e.ondblclick = void 0, e.remove();
}, C2 = () => {
var t;
const e = Array.from(((t = x2.value) == null ? void 0 : t.children) || []);
for (const i2 of e)
i2.className.includes("splitpanes__splitter") && ne(i2);
let n2 = 0;
for (const i2 of e)
i2.className.includes("splitpanes__pane") && (!n2 && u2.firstSplitter ? F2(n2, i2, true) : n2 && F2(n2, i2), n2++);
}, ie = ({ uid: e, ...n2 }) => {
const t = M.value[e];
for (const [i2, a2] of Object.entries(n2)) t[i2] = a2;
}, te2 = (e) => {
var t;
let n2 = -1;
Array.from(((t = x2.value) == null ? void 0 : t.children) || []).some((i2) => (i2.className.includes("splitpanes__pane") && n2++, i2.isSameNode(e.el))), l2.value.splice(n2, 0, { ...e, index: n2 }), l2.value.forEach((i2, a2) => i2.index = a2), S2.value && nextTick(() => {
C2(), L2({ addedPane: l2.value[n2] }), d2("pane-add", { pane: l2.value[n2] });
});
}, ae2 = (e) => {
const n2 = l2.value.findIndex((i2) => i2.id === e);
l2.value[n2].el = null;
const t = l2.value.splice(n2, 1)[0];
l2.value.forEach((i2, a2) => i2.index = a2), nextTick(() => {
C2(), d2("pane-remove", { pane: t }), L2({ removedPane: { ...t } });
});
}, L2 = (e = {}) => {
!e.addedPane && !e.removedPane ? le2() : l2.value.some((n2) => n2.givenSize !== null || n2.min || n2.max < 100) ? oe(e) : se(), S2.value && d2("resized");
}, se = () => {
const e = 100 / m2.value;
let n2 = 0;
const t = [], i2 = [];
for (const a2 of l2.value)
a2.size = Math.max(Math.min(e, a2.max), a2.min), n2 -= a2.size, a2.size >= a2.max && t.push(a2.id), a2.size <= a2.min && i2.push(a2.id);
n2 > 0.1 && q2(n2, t, i2);
}, le2 = () => {
let e = 100;
const n2 = [], t = [];
let i2 = 0;
for (const s2 of l2.value)
e -= s2.size, s2.givenSize !== null && i2++, s2.size >= s2.max && n2.push(s2.id), s2.size <= s2.min && t.push(s2.id);
let a2 = 100;
if (e > 0.1) {
for (const s2 of l2.value)
s2.givenSize === null && (s2.size = Math.max(Math.min(e / (m2.value - i2), s2.max), s2.min)), a2 -= s2.size;
a2 > 0.1 && q2(a2, n2, t);
}
}, oe = ({ addedPane: e, removedPane: n2 } = {}) => {
let t = 100 / m2.value, i2 = 0;
const a2 = [], s2 = [];
((e == null ? void 0 : e.givenSize) ?? null) !== null && (t = (100 - e.givenSize) / (m2.value - 1));
for (const o2 of l2.value)
i2 -= o2.size, o2.size >= o2.max && a2.push(o2.id), o2.size <= o2.min && s2.push(o2.id);
if (!(Math.abs(i2) < 0.1)) {
for (const o2 of l2.value)
(e == null ? void 0 : e.givenSize) !== null && (e == null ? void 0 : e.id) === o2.id || (o2.size = Math.max(Math.min(t, o2.max), o2.min)), i2 -= o2.size, o2.size >= o2.max && a2.push(o2.id), o2.size <= o2.min && s2.push(o2.id);
i2 > 0.1 && q2(i2, a2, s2);
}
}, q2 = (e, n2, t) => {
let i2;
e > 0 ? i2 = e / (m2.value - n2.length) : i2 = e / (m2.value - t.length), l2.value.forEach((a2, s2) => {
if (e > 0 && !n2.includes(a2.id)) {
const o2 = Math.max(Math.min(a2.size + i2, a2.max), a2.min), v2 = o2 - a2.size;
e -= v2, a2.size = o2;
} else if (!t.includes(a2.id)) {
const o2 = Math.max(Math.min(a2.size + i2, a2.max), a2.min), v2 = o2 - a2.size;
e -= v2, a2.size = o2;
}
}), Math.abs(e) > 0.1 && nextTick(() => {
S2.value && console.warn("Splitpanes: Could not resize panes correctly due to their constraints.");
});
}, d2 = (e, n2 = void 0, t = false) => {
const i2 = (n2 == null ? void 0 : n2.index) ?? c2.value.activeSplitter ?? null;
y2(e, {
...n2,
...i2 !== null && { index: i2 },
...t && i2 !== null && {
prevPane: l2.value[i2 - (u2.firstSplitter ? 1 : 0)],
nextPane: l2.value[i2 + (u2.firstSplitter ? 0 : 1)]
},
panes: l2.value.map((a2) => ({ min: a2.min, max: a2.max, size: a2.size }))
});
};
watch(() => u2.firstSplitter, () => C2()), onMounted(() => {
ee2(), C2(), L2(), d2("ready"), S2.value = true;
}), onBeforeUnmount(() => S2.value = false);
const re2 = () => {
var e;
return h$2(
"div",
{ ref: x2, class: _2.value },
(e = E2.default) == null ? void 0 : e.call(E2)
);
};
return provide("panes", l2), provide("indexedPanes", M), provide("horizontal", computed(() => u2.horizontal)), provide("requestUpdate", ie), provide("onPaneAdd", te2), provide("onPaneRemove", ae2), provide("onPaneClick", W2), (e, n2) => (openBlock(), createBlock(resolveDynamicComponent(re2)));
}
}, ge = {
__name: "pane",
props: {
size: { type: [Number, String] },
minSize: { type: [Number, String], default: 0 },
maxSize: { type: [Number, String], default: 100 }
},
setup(D2) {
var b2;
const h2 = D2, y2 = inject("requestUpdate"), u2 = inject("onPaneAdd"), E2 = inject("horizontal"), l2 = inject("onPaneRemove"), M = inject("onPaneClick"), m2 = (b2 = getCurrentInstance()) == null ? void 0 : b2.uid, x2 = inject("indexedPanes"), S2 = computed(() => x2.value[m2]), c2 = ref(null), f2 = computed(() => {
const r2 = isNaN(h2.size) || h2.size === void 0 ? 0 : parseFloat(h2.size);
return Math.max(Math.min(r2, R2.value), _2.value);
}), _2 = computed(() => {
const r2 = parseFloat(h2.minSize);
return isNaN(r2) ? 0 : r2;
}), R2 = computed(() => {
const r2 = parseFloat(h2.maxSize);
return isNaN(r2) ? 100 : r2;
}), O2 = computed(() => {
var r2;
return `${E2.value ? "height" : "width"}: ${(r2 = S2.value) == null ? void 0 : r2.size}%`;
});
return watch(() => f2.value, (r2) => y2({ uid: m2, size: r2 })), watch(() => _2.value, (r2) => y2({ uid: m2, min: r2 })), watch(() => R2.value, (r2) => y2({ uid: m2, max: r2 })), onMounted(() => {
u2({
id: m2,
el: c2.value,
min: _2.value,
max: R2.value,
// The given size (useful to know the user intention).
givenSize: h2.size === void 0 ? null : f2.value,
size: f2.value
// The computed current size at any time.
});
}), onBeforeUnmount(() => l2(m2)), (r2, P2) => (openBlock(), createElementBlock("div", {
ref_key: "paneEl",
ref: c2,
class: "splitpanes__pane",
onClick: P2[0] || (P2[0] = (A2) => unref(M)(A2, r2._.uid)),
style: normalizeStyle(O2.value)
}, [
renderSlot(r2.$slots, "default")
], 4));
}
};
const matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/;
const stringToIcon = (value, validate, allowSimpleName, provider = "") => {
const colonSeparated = value.split(":");
if (value.slice(0, 1) === "@") {
if (colonSeparated.length < 2 || colonSeparated.length > 3) {
return null;
}
provider = colonSeparated.shift().slice(1);
}
if (colonSeparated.length > 3 || !colonSeparated.length) {
return null;
}
if (colonSeparated.length > 1) {
const name2 = colonSeparated.pop();
const prefix = colonSeparated.pop();
const result = {
// Allow provider without '@': "provider:prefix:name"
provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,
prefix,
name: name2
};
return validate && !validateIconName(result) ? null : result;
}
const name = colonSeparated[0];
const dashSeparated = name.split("-");
if (dashSeparated.length > 1) {
const result = {
provider,
prefix: dashSeparated.shift(),
name: dashSeparated.join("-")
};
return validate && !validateIconName(result) ? null : result;
}
if (allowSimpleName && provider === "") {
const result = {
provider,
prefix: "",
name
};
return validate && !validateIconName(result, allowSimpleName) ? null : result;
}
return null;
};
const validateIconName = (icon, allowSimpleName) => {
if (!icon) {
return false;
}
return !!((icon.provider === "" || icon.provider.match(matchIconName)) && (allowSimpleName && icon.prefix === "" || icon.prefix.match(matchIconName)) && icon.name.match(matchIconName));
};
const defaultIconDimensions = Object.freeze(
{
left: 0,
top: 0,
width: 16,
height: 16
}
);
const defaultIconTransformations = Object.freeze({
rotate: 0,
vFlip: false,
hFlip: false
});
const defaultIconProps = Object.freeze({
...defaultIconDimensions,
...defaultIconTransformations
});
const defaultExtendedIconProps = Object.freeze({
...defaultIconProps,
body: "",
hidden: false
});
function mergeIconTransformations(obj1, obj2) {
const result = {};
if (!obj1.hFlip !== !obj2.hFlip) {
result.hFlip = true;
}
if (!obj1.vFlip !== !obj2.vFlip) {
result.vFlip = true;
}
const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4;
if (rotate) {
result.rotate = rotate;
}
return result;
}
function mergeIconData(parent, child) {
const result = mergeIconTransformations(parent, child);
for (const key in defaultExtendedIconProps) {
if (key in defaultIconTransformations) {
if (key in parent && !(key in result)) {
result[key] = defaultIconTransformations[key];
}
} else if (key in child) {
result[key] = child[key];
} else if (key in parent) {
result[key] = parent[key];
}
}
return result;
}
function getIconsTree(data, names) {
const icons = data.icons;
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
const resolved = /* @__PURE__ */ Object.create(null);
function resolve(name) {
if (icons[name]) {
return resolved[name] = [];
}
if (!(name in resolved)) {
resolved[name] = null;
const parent = aliases[name] && aliases[name].parent;
const value = parent && resolve(parent);
if (value) {
resolved[name] = [parent].concat(value);
}
}
return resolved[name];
}
Object.keys(icons).concat(Object.keys(aliases)).forEach(resolve);
return resolved;
}
function internalGetIconData(data, name, tree) {
const icons = data.icons;
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
let currentProps = {};
function parse(name2) {
currentProps = mergeIconData(
icons[name2] || aliases[name2],
currentProps
);
}
parse(name);
tree.forEach(parse);
return mergeIconData(data, currentProps);
}
function parseIconSet(data, callback) {
const names = [];
if (typeof data !== "object" || typeof data.icons !== "object") {
return names;
}
if (data.not_found instanceof Array) {
data.not_found.forEach((name) => {
callback(name, null);
names.push(name);
});
}
const tree = getIconsTree(data);
for (const name in tree) {
const item = tree[name];
if (item) {
callback(name, internalGetIconData(data, name, item));
names.push(name);
}
}
return names;
}
const optionalPropertyDefaults = {
provider: "",
aliases: {},
not_found: {},
...defaultIconDimensions
};
function checkOptionalProps(item, defaults) {
for (const prop in defaults) {
if (prop in item && typeof item[prop] !== typeof defaults[prop]) {
return false;
}
}
return true;
}
function quicklyValidateIconSet(obj) {
if (typeof obj !== "object" || obj === null) {
return null;
}
const data = obj;
if (typeof data.prefix !== "string" || !obj.icons || typeof obj.icons !== "object") {
return null;
}
if (!checkOptionalProps(obj, optionalPropertyDefaults)) {
return null;
}
const icons = data.icons;
for (const name in icons) {
const icon = icons[name];
if (!name.match(matchIconName) || typeof icon.body !== "string" || !checkOptionalProps(
icon,
defaultExtendedIconProps
)) {
return null;
}
}
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
for (const name in aliases) {
const icon = aliases[name];
const parent = icon.parent;
if (!name.match(matchIconName) || typeof parent !== "string" || !icons[parent] && !aliases[parent] || !checkOptionalProps(
icon,
defaultExtendedIconProps
)) {
return null;
}
}
return data;
}
const dataStorage = /* @__PURE__ */ Object.create(null);
function newStorage(provider, prefix) {
return {
provider,
prefix,
icons: /* @__PURE__ */ Object.create(null),
missing: /* @__PURE__ */ new Set()
};
}
function getStorage(provider, prefix) {
const providerStorage = dataStorage[provider] || (dataStorage[provider] = /* @__PURE__ */ Object.create(null));
return providerStorage[prefix] || (providerStorage[prefix] = newStorage(provider, prefix));
}
function addIconSet(storage2, data) {
if (!quicklyValidateIconSet(data)) {
return [];
}
return parseIconSet(data, (name, icon) => {
if (icon) {
storage2.icons[name] = icon;
} else {
storage2.missing.add(name);
}
});
}
function addIconToStorage(storage2, name, icon) {
try {
if (typeof icon.body === "string") {
storage2.icons[name] = { ...icon };
return true;
}
} catch (err) {
}
return false;
}
let simpleNames = false;
function allowSimpleNames(allow) {
if (typeof allow === "boolean") {
simpleNames = allow;
}
return simpleNames;
}
function getIconData(name) {
const icon = typeof name === "string" ? stringToIcon(name, true, simpleNames) : name;
if (icon) {
const storage2 = getStorage(icon.provider, icon.prefix);
const iconName = icon.name;
return storage2.icons[iconName] || (storage2.missing.has(iconName) ? null : void 0);
}
}
function addIcon(name, data) {
const icon = stringToIcon(name, true, simpleNames);
if (!icon) {
return false;
}
const storage2 = getStorage(icon.provider, icon.prefix);
return addIconToStorage(storage2, icon.name, data);
}
function addCollection(data, provider) {
if (typeof data !== "object") {
return false;
}
if (typeof provider !== "string") {
provider = data.provider || "";
}
if (simpleNames && !provider && !data.prefix) {
let added = false;
if (quicklyValidateIconSet(data)) {
data.prefix = "";
parseIconSet(data, (name, icon) => {
if (icon && addIcon(name, icon)) {
added = true;
}
});
}
return added;
}
const prefix = data.prefix;
if (!validateIconName({
provider,
prefix,
name: "a"
})) {
return false;
}
const storage2 = getStorage(provider, prefix);
return !!addIconSet(storage2, data);
}
const defaultIconSizeCustomisations = Object.freeze({
width: null,
height: null
});
const defaultIconCustomisations = Object.freeze({
// Dimensions
...defaultIconSizeCustomisations,
// Transformations
...defaultIconTransformations
});
const unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g;
const unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g;
function calculateSize(size2, ratio, precision) {
if (ratio === 1) {
return size2;
}
precision = precision || 100;
if (typeof size2 === "number") {
return Math.ceil(size2 * ratio * precision) / precision;
}
if (typeof size2 !== "string") {
return size2;
}
const oldParts = size2.split(unitsSplit);
if (oldParts === null || !oldParts.length) {
return size2;
}
const newParts = [];
let code = oldParts.shift();
let isNumber = unitsTest.test(code);
while (true) {
if (isNumber) {
const num = parseFloat(code);
if (isNaN(num)) {
newParts.push(code);
} else {
newParts.push(Math.ceil(num * ratio * precision) / precision);
}
} else {
newParts.push(code);
}
code = oldParts.shift();
if (code === void 0) {
return newParts.join("");
}
isNumber = !isNumber;
}
}
function splitSVGDefs(content, tag = "defs") {
let defs = "";
const index = content.indexOf("<" + tag);
while (index >= 0) {
const start = content.indexOf(">", index);
const end = content.indexOf("</" + tag);
if (start === -1 || end === -1) {
break;
}
const endEnd = content.indexOf(">", end);
if (endEnd === -1) {
break;
}
defs += content.slice(start + 1, end).trim();
content = content.slice(0, index).trim() + content.slice(endEnd + 1);
}
return {
defs,
content
};
}
function mergeDefsAndContent(defs, content) {
return defs ? "<defs>" + defs + "</defs>" + content : content;
}
function wrapSVGContent(body, start, end) {
const split = splitSVGDefs(body);
return mergeDefsAndContent(split.defs, start + split.content + end);
}
const isUnsetKeyword = (value) => value === "unset" || value === "undefined" || value === "none";
function iconToSVG(icon, customisations) {
const fullIcon = {
...defaultIconProps,
...icon
};
const fullCustomisations = {
...defaultIconCustomisations,
...customisations
};
const box = {
left: fullIcon.left,
top: fullIcon.top,
width: fullIcon.width,
height: fullIcon.height
};
let body = fullIcon.body;
[fullIcon, fullCustomisations].forEach((props) => {
const transformations = [];
const hFlip = props.hFlip;
const vFlip = props.vFlip;
let rotation = props.rotate;
if (hFlip) {
if (vFlip) {
rotation += 2;
} else {
transformations.push(
"translate(" + (box.width + box.left).toString() + " " + (0 - box.top).toString() + ")"
);
transformations.push("scale(-1 1)");
box.top = box.left = 0;
}
} else if (vFlip) {
transformations.push(
"translate(" + (0 - box.left).toString() + " " + (box.height + box.top).toString() + ")"
);
transformations.push("scale(1 -1)");
box.top = box.left = 0;
}
let tempValue;
if (rotation < 0) {
rotation -= Math.floor(rotation / 4) * 4;
}
rotation = rotation % 4;
switch (rotation) {
case 1:
tempValue = box.height / 2 + box.top;
transformations.unshift(
"rotate(90 " + tempValue.toString() + " " + tempValue.toString() + ")"
);
break;
case 2:
transformations.unshift(
"rotate(180 " + (box.width / 2 + box.left).toString() + " " + (box.height / 2 + box.top).toString() + ")"
);
break;
case 3:
tempValue = box.width / 2 + box.left;
transformations.unshift(
"rotate(-90 " + tempValue.toString() + " " + tempValue.toString() + ")"
);
break;
}
if (rotation % 2 === 1) {
if (box.left !== box.top) {
tempValue = box.left;
box.left = box.top;
box.top = tempValue;
}
if (box.width !== box.height) {
tempValue = box.width;
box.width = box.height;
box.height = tempValue;
}
}
if (transformations.length) {
body = wrapSVGContent(
body,
'<g transform="' + transformations.join(" ") + '">',
"</g>"
);
}
});
const customisationsWidth = fullCustomisations.width;
const customisationsHeight = fullCustomisations.height;
const boxWidth = box.width;
const boxHeight = box.height;
let width;
let height;
if (customisationsWidth === null) {
height = customisationsHeight === null ? "1em" : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
width = calculateSize(height, boxWidth / boxHeight);
} else {
width = customisationsWidth === "auto" ? boxWidth : customisationsWidth;
height = customisationsHeight === null ? calculateSize(width, boxHeight / boxWidth) : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
}
const attributes = {};
const setAttr = (prop, value) => {
if (!isUnsetKeyword(value)) {
attributes[prop] = value.toString();
}
};
setAttr("width", width);
setAttr("height", height);
const viewBox = [box.left, box.top, boxWidth, boxHeight];
attributes.viewBox = viewBox.join(" ");
return {
attributes,
viewBox,
body
};
}
const regex = /\sid="(\S+)"/g;
const randomPrefix = "IconifyId" + Date.now().toString(16) + (Math.random() * 16777216 | 0).toString(16);
let counter = 0;
function replaceIDs(body, prefix = randomPrefix) {
const ids = [];
let match;
while (match = regex.exec(body)) {
ids.push(match[1]);
}
if (!ids.length) {
return body;
}
const suffix = "suffix" + (Math.random() * 16777216 | Date.now()).toString(16);
ids.forEach((id) => {
const newID = typeof prefix === "function" ? prefix(id) : prefix + (counter++).toString();
const escapedID = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
body = body.replace(
// Allowed characters before id: [#;"]
// Allowed characters after id: [)"], .[a-z]
new RegExp('([#;"])(' + escapedID + ')([")]|\\.[a-z])', "g"),
"$1" + newID + suffix + "$3"
);
});
body = body.replace(new RegExp(suffix, "g"), "");
return body;
}
const storage = /* @__PURE__ */ Object.create(null);
function setAPIModule(provider, item) {
storage[provider] = item;
}
function getAPIModule(provider) {
return storage[provider] || storage[""];
}
function createAPIConfig(source) {
let resources;
if (typeof source.resources === "string") {
resources = [source.resources];
} else {
resources = source.resources;
if (!(resources instanceof Array) || !resources.length) {
return null;
}
}
const result = {
// API hosts
resources,
// Root path
path: source.path || "/",
// URL length limit
maxURL: source.maxURL || 500,
// Timeout before next host is used.
rotate: source.rotate || 750,
// Timeout before failing query.
timeout: source.timeout || 5e3,
// Randomise default API end point.
random: source.random === true,
// Start index
index: source.index || 0,
// Receive data after time out (used if time out kicks in first, then API module sends data anyway).
dataAfterTimeout: source.dataAfterTimeout !== false
};
return result;
}
const configStorage = /* @__PURE__ */ Object.create(null);
const fallBackAPISources = [
"https://api.simplesvg.com",
"https://api.unisvg.com"
];
const fallBackAPI = [];
while (fallBackAPISources.length > 0) {
if (fallBackAPISources.length === 1) {
fallBackAPI.push(fallBackAPISources.shift());
} else {
if (Math.random() > 0.5) {
fallBackAPI.push(fallBackAPISources.shift());
} else {
fallBackAPI.push(fallBackAPISources.pop());
}
}
}
configStorage[""] = createAPIConfig({
resources: ["https://api.iconify.design"].concat(fallBackAPI)
});
function addAPIProvider(provider, customConfig) {
const config = createAPIConfig(customConfig);
if (config === null) {
return false;
}
configStorage[provider] = config;
return true;
}
function getAPIConfig(provider) {
return configStorage[provider];
}
const detectFetch = () => {
let callback;
try {
callback = fetch;
if (typeof callback === "function") {
return callback;
}
} catch (err) {
}
};
let fetchModule = detectFetch();
function calculateMaxLength(provider, prefix) {
const config = getAPIConfig(provider);
if (!config) {
return 0;
}
let result;
if (!config.maxURL) {
result = 0;
} else {
let maxHostLength = 0;
config.resources.forEach((item) => {
const host = item;
maxHostLength = Math.max(maxHostLength, host.length);
});
const url = prefix + ".json?icons=";
result = config.maxURL - maxHostLength - config.path.length - url.length;
}
return result;
}
function shouldAbort(status) {
return status === 404;
}
const prepare = (provider, prefix, icons) => {
const results = [];
const maxLength = calculateMaxLength(provider, prefix);
const type = "icons";
let item = {
type,
provider,
prefix,
icons: []
};
let length = 0;
icons.forEach((name, index) => {
length += name.length + 1;
if (length >= maxLength && index > 0) {
results.push(item);
item = {
type,
provider,
prefix,
icons: []
};
length = name.length;
}
item.icons.push(name);
});
results.push(item);
return results;
};
function getPath(provider) {
if (typeof provider === "string") {
const config = getAPIConfig(provider);
if (config) {
return config.path;
}
}
return "/";
}
const send = (host, params, callback) => {
if (!fetchModule) {
callback("abort", 424);
return;
}
let path = getPath(params.provider);
switch (params.type) {
case "icons": {
const prefix = params.prefix;
const icons = params.icons;
const iconsList = icons.join(",");
const urlParams = new URLSearchParams({
icons: iconsList
});
path += prefix + ".json?" + urlParams.toString();
break;
}
case "custom": {
const uri = params.uri;
path += uri.slice(0, 1) === "/" ? uri.slice(1) : uri;
break;
}
default:
callback("abort", 400);
return;
}
let defaultError = 503;
fetchModule(host + path).then((response) => {
const status = response.status;
if (status !== 200) {
setTimeout(() => {
callback(shouldAbort(status) ? "abort" : "next", status);
});
return;
}
defaultError = 501;
return response.json();
}).then((data) => {
if (typeof data !== "object" || data === null) {
setTimeout(() => {
if (data === 404) {
callback("abort", data);
} else {
callback("next", defaultError);
}
});
return;
}
setTimeout(() => {
callback("success", data);
});
}).catch(() => {
callback("next", defaultError);
});
};
const fetchAPIModule = {
prepare,
send
};
function sortIcons(icons) {
const result = {
loaded: [],
missing: [],
pending: []
};
const storage2 = /* @__PURE__ */ Object.create(null);
icons.sort((a2, b2) => {
if (a2.provider !== b2.provider) {
return a2.provider.localeCompare(b2.provider);
}
if (a2.prefix !== b2.prefix) {
return a2.prefix.localeCompare(b2.prefix);
}
return a2.name.localeCompare(b2.name);
});
let lastIcon = {
provider: "",
prefix: "",
name: ""
};
icons.forEach((icon) => {
if (lastIcon.name === icon.name && lastIcon.prefix === icon.prefix && lastIcon.provider === icon.provider) {
return;
}
lastIcon = icon;
const provider = icon.provider;
const prefix = icon.prefix;
const name = icon.name;
const providerStorage = storage2[provider] || (storage2[provider] = /* @__PURE__ */ Object.create(null));
const localStorage = providerStorage[prefix] || (providerStorage[prefix] = getStorage(provider, prefix));
let list;
if (name in localStorage.icons) {
list = result.loaded;
} else if (prefix === "" || localStorage.missing.has(name)) {
list = result.missing;
} else {
list = result.pending;
}
const item = {
provider,
prefix,
name
};
list.push(item);
});
return result;
}
function removeCallback(storages, id) {
storages.forEach((storage2) => {
const items = storage2.loaderCallbacks;
if (items) {
storage2.loaderCallbacks = items.filter((row) => row.id !== id);
}
});
}
function updateCallbacks(storage2) {
if (!storage2.pendingCallbacksFlag) {
storage2.pendingCallbacksFlag = true;
setTimeout(() => {
storage2.pendingCallbacksFlag = false;
const items = storage2.loaderCallbacks ? storage2.loaderCallbacks.slice(0) : [];
if (!items.length) {
return;
}
let hasPending = false;
const provider = storage2.provider;
const prefix = storage2.prefix;
items.forEach((item) => {
const icons = item.icons;
const oldLength = icons.pending.length;
icons.pending = icons.pending.filter((icon) => {
if (icon.prefix !== prefix) {
return true;
}
const name = icon.name;
if (storage2.icons[name]) {
icons.loaded.push({
provider,
prefix,
name
});
} else if (storage2.missing.has(name)) {
icons.missing.push({
provider,
prefix,
name
});
} else {
hasPending = true;
return true;
}
return false;
});
if (icons.pending.length !== oldLength) {
if (!hasPending) {
removeCallback([storage2], item.id);
}
item.callback(
icons.loaded.slice(0),
icons.missing.slice(0),
icons.pending.slice(0),
item.abort
);
}
});
});
}
}
let idCounter = 0;
function storeCallback(callback, icons, pendingSources) {
const id = idCounter++;
const abort = removeCallback.bind(null, pendingSources, id);
if (!icons.pending.length) {
return abort;
}
const item = {
id,
icons,
callback,
abort
};
pendingSources.forEach((storage2) => {
(storage2.loaderCallbacks || (storage2.loaderCallbacks = [])).push(item);
});
return abort;
}
function listToIcons(list, validate = true, simpleNames2 = false) {
const result = [];
list.forEach((item) => {
const icon = typeof item === "string" ? stringToIcon(item, validate, simpleNames2) : item;
if (icon) {
result.push(icon);
}
});
return result;
}
var defaultConfig = {
resources: [],
index: 0,
timeout: 2e3,
rotate: 750,
random: false,
dataAfterTimeout: false
};
function sendQuery(config, payload, query, done) {
const resourcesCount = config.resources.length;
const startIndex = config.random ? Math.floor(Math.random() * resourcesCount) : config.index;
let resources;
if (config.random) {
let list = config.resources.slice(0);
resources = [];
while (list.length > 1) {
const nextIndex = Math.floor(Math.random() * list.length);
resources.push(list[nextIndex]);
list = list.slice(0, nextIndex).concat(list.slice(nextIndex + 1));
}
resources = resources.concat(list);
} else {
resources = config.resources.slice(startIndex).concat(config.resources.slice(0, startIndex));
}
const startTime = Date.now();
let status = "pending";
let queriesSent = 0;
let lastError;
let timer = null;
let queue = [];
let doneCallbacks = [];
if (typeof done === "function") {
doneCallbacks.push(done);
}
function resetTimer() {
if (timer) {
clearTimeout(timer);
timer