UNPKG

@varlet/use

Version:
465 lines (464 loc) 12.8 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); let _varlet_shared = require("@varlet/shared"); let vue = require("vue"); //#region src/onSmartMounted.ts function onSmartMounted(hook) { let isMounted = false; (0, vue.onMounted)(() => { hook(); (0, vue.nextTick)(() => { isMounted = true; }); }); (0, vue.onActivated)(() => { if (!isMounted) return; hook(); }); } //#endregion //#region src/useEventListener.ts function useEventListener(target, type, listener, options = {}) { if (!(0, _varlet_shared.inBrowser)()) return; const { passive = false, capture = false } = options; let listening = false; let cleaned = false; const getElement = (target) => (0, _varlet_shared.isFunction)(target) ? target() : (0, vue.unref)(target); const add = (target) => { if (listening || cleaned) return; const element = getElement(target); if (element) { element.addEventListener(type, listener, { passive, capture }); listening = true; } }; const remove = (target) => { if (!listening || cleaned) return; const element = getElement(target); if (element) { element.removeEventListener(type, listener, { capture }); listening = false; } }; let watchStopHandle; if ((0, vue.isRef)(target)) watchStopHandle = (0, vue.watch)(() => target.value, (newValue, oldValue) => { remove(oldValue); add(newValue); }); const cleanup = () => { watchStopHandle?.(); remove(target); cleaned = true; }; onSmartMounted(() => { add(target); }); (0, vue.onBeforeUnmount)(() => { remove(target); }); (0, vue.onDeactivated)(() => { remove(target); }); return cleanup; } //#endregion //#region src/useClickOutside.ts function useClickOutside(target, type, listener) { if (!(0, _varlet_shared.inBrowser)()) return; const handler = (event) => { const element = (0, _varlet_shared.isFunction)(target) ? target() : (0, vue.unref)(target); if (element && !element.contains(event.target)) listener(event); }; useEventListener(document, type, handler); } //#endregion //#region src/onSmartUnmounted.ts function onSmartUnmounted(hook) { let keepalive = false; (0, vue.onDeactivated)(() => { keepalive = true; hook(); }); (0, vue.onUnmounted)(() => { if (keepalive) return; hook(); }); } //#endregion //#region src/useParent.ts function keyInProvides(key) { return key in (0, vue.getCurrentInstance)().provides; } function useParent(key) { if (!keyInProvides(key)) return { index: null, parentProvider: null, bindParent: null }; const { childInstances, collect, clear, ...parentProvider } = (0, vue.inject)(key); const childInstance = (0, vue.getCurrentInstance)(); const index = (0, vue.computed)(() => childInstances.indexOf(childInstance)); const bindParent = (childProvider) => { (0, vue.onMounted)(() => { (0, vue.nextTick)().then(() => { collect(childInstance, childProvider); }); }); (0, vue.onBeforeUnmount)(() => { (0, vue.nextTick)().then(() => { clear(childInstance, childProvider); }); }); }; return { index, parentProvider, bindParent }; } //#endregion //#region src/useChildren.ts function flatVNodes(subTree) { const vNodes = []; const flat = (subTree) => { if (subTree?.component) { flat(subTree?.component.subTree); return; } if ((0, _varlet_shared.isArray)(subTree?.children)) subTree.children.forEach((child) => { if ((0, vue.isVNode)(child)) { vNodes.push(child); flat(child); } }); }; flat(subTree); return vNodes; } function useChildren(key) { const parentInstance = (0, vue.getCurrentInstance)(); const childInstances = (0, vue.reactive)([]); const childProviders = []; const length = (0, vue.computed)(() => childInstances.length); const sortInstances = () => { const vNodes = flatVNodes(parentInstance.subTree); const pairs = childInstances.map((instance, index) => ({ instance, provider: childProviders[index] })); const getVNodeIndex = (instance) => { const index = vNodes.indexOf(instance.vnode); return index === -1 ? Number.MAX_SAFE_INTEGER : index; }; pairs.sort((a, b) => getVNodeIndex(a.instance) - getVNodeIndex(b.instance)); childInstances.splice(0, childInstances.length, ...pairs.map(({ instance }) => instance)); childProviders.splice(0, childProviders.length, ...pairs.map(({ provider }) => provider)); }; const collect = (childInstance, childProvider) => { childInstances.push(childInstance); childProviders.push(childProvider); sortInstances(); }; const clear = (childInstance, childProvider) => { (0, _varlet_shared.removeItem)(childInstances, childInstance); (0, _varlet_shared.removeItem)(childProviders, childProvider); }; const bindChildren = (parentProvider) => { (0, vue.provide)(key, { childInstances, collect, clear, ...parentProvider }); }; (0, vue.onUpdated)(sortInstances); return { length, childInstances, childProviders, bindChildren }; } //#endregion //#region src/onWindowResize.ts function onWindowResize(listener) { useEventListener(() => window, "resize", listener, { passive: true }); useEventListener(() => window, "orientationchange", listener, { passive: true }); } //#endregion //#region src/useInitialized.ts function useInitialized(source, value) { const initialized = (0, vue.ref)(false); (0, vue.watch)(source, (newValue) => { if (value === newValue) initialized.value = true; }, { immediate: true }); return initialized; } //#endregion //#region src/useTouch.ts function getDirection(x, y) { if (x > y) return "horizontal"; if (y > x) return "vertical"; } function useTouch() { const startX = (0, vue.ref)(0); const startY = (0, vue.ref)(0); const deltaX = (0, vue.ref)(0); const deltaY = (0, vue.ref)(0); const offsetX = (0, vue.ref)(0); const offsetY = (0, vue.ref)(0); const prevX = (0, vue.ref)(0); const prevY = (0, vue.ref)(0); const moveX = (0, vue.ref)(0); const moveY = (0, vue.ref)(0); const direction = (0, vue.ref)(); const touching = (0, vue.ref)(false); const dragging = (0, vue.ref)(false); const startTime = (0, vue.ref)(0); const distance = (0, vue.ref)(0); let draggingAnimationFrame = null; const resetTouch = () => { startX.value = 0; startY.value = 0; deltaX.value = 0; deltaY.value = 0; offsetX.value = 0; offsetY.value = 0; prevX.value = 0; prevY.value = 0; moveX.value = 0; moveY.value = 0; direction.value = void 0; touching.value = false; dragging.value = false; startTime.value = 0; distance.value = 0; }; const startTouch = (event) => { resetTouch(); const { clientX: x, clientY: y } = event.touches[0]; startX.value = x; startY.value = y; prevX.value = x; prevY.value = y; touching.value = true; startTime.value = performance.now(); dragging.value = false; if (draggingAnimationFrame) window.cancelAnimationFrame(draggingAnimationFrame); }; const moveTouch = (event) => { const { clientX: x, clientY: y } = event.touches[0]; dragging.value = true; deltaX.value = x - startX.value; deltaY.value = y - startY.value; offsetX.value = Math.abs(deltaX.value); offsetY.value = Math.abs(deltaY.value); distance.value = Math.sqrt(offsetX.value ** 2 + offsetY.value ** 2); moveX.value = x - prevX.value; moveY.value = y - prevY.value; if (!direction.value) direction.value = getDirection(offsetX.value, offsetY.value); prevX.value = x; prevY.value = y; }; const endTouch = () => { touching.value = false; draggingAnimationFrame = window.requestAnimationFrame(() => { dragging.value = false; }); }; const isReachTop = (element) => { return (0, _varlet_shared.getScrollTop)(element) === 0 && deltaY.value > 0; }; const isReachBottom = (element, offset = 1) => { const { scrollHeight, clientHeight, scrollTop } = element; const offsetBottom = Math.abs(scrollHeight - scrollTop - clientHeight); return deltaY.value < 0 && offsetBottom <= offset; }; return { startX, startY, deltaX, deltaY, offsetX, offsetY, prevX, prevY, moveX, moveY, direction, touching, dragging, startTime, distance, resetTouch, startTouch, moveTouch, endTouch, isReachTop, isReachBottom }; } //#endregion //#region src/useId.ts function useId() { const id = (0, vue.ref)(); const instance = (0, vue.getCurrentInstance)(); const name = (0, _varlet_shared.kebabCase)(instance.type.name); id.value = process.env.NODE_ENV === "test" ? `${name}-mock-id` : `${name}-${instance.uid}`; return id; } //#endregion //#region src/useClientId.ts function useClientId() { const instance = (0, vue.getCurrentInstance)(); const name = (0, _varlet_shared.kebabCase)(instance.type.name); const id = (0, vue.ref)(process.env.NODE_ENV === "test" ? `${name}-mock-id` : void 0); (0, vue.onMounted)(() => { if (process.env.NODE_ENV !== "test") id.value = `${name}-${instance.uid}`; }); return id; } //#endregion //#region src/useWindowSize.ts function useWindowSize(options = {}) { const { initialWidth = 0, initialHeight = 0 } = options; const width = (0, vue.ref)(initialWidth); const height = (0, vue.ref)(initialHeight); const update = () => { if (!(0, _varlet_shared.inBrowser)()) return; width.value = window.innerWidth; height.value = window.innerHeight; }; onSmartMounted(update); onWindowResize(update); return { width, height }; } //#endregion //#region src/useVModel.ts function useVModel(props, key, options = {}) { const { passive = true, eventName, defaultValue, emit } = options; const event = eventName ?? `onUpdate:${key.toString()}`; const getValue = () => props[key] ?? defaultValue; if (!passive) return (0, vue.computed)({ get() { return getValue(); }, set(value) { emit ? emit(event, value) : (0, _varlet_shared.call)(props[event], value); } }); const proxy = (0, vue.ref)(getValue()); let shouldEmit = true; (0, vue.watch)(() => props[key], () => { shouldEmit = false; proxy.value = getValue(); (0, vue.nextTick)(() => { shouldEmit = true; }); }); (0, vue.watch)(() => proxy.value, (newValue) => { if (!shouldEmit) return; emit ? emit(event, newValue) : (0, _varlet_shared.call)(props[event], newValue); }); return proxy; } //#endregion //#region src/useMotion.ts function useMotion(options) { const value = (0, vue.ref)(getter(options.from)); const state = (0, vue.ref)("pending"); let ctx = createMotionContext(); function getter(value) { return (0, _varlet_shared.isFunction)(value) ? value() : value; } function reset() { ctx.reset(); value.value = getter(options.from); state.value = "pending"; ctx = createMotionContext(); } function start() { ctx.start(); } function pause() { ctx.pause(); } function createMotionContext() { return (0, _varlet_shared.motion)({ from: getter(options.from), to: getter(options.to), duration: options.duration ? getter(options.duration) : 300, timingFunction: options.timingFunction, onStateChange(newState) { state.value = newState; }, frame({ value: newValue, done }) { value.value = newValue; if (done) options.onFinished?.(value.value); } }); } return { value, state, start, pause, reset }; } //#endregion //#region src/useResizeObserver.ts function useResizeObserver(target, callback) { if (!(0, _varlet_shared.inBrowser)() || typeof ResizeObserver === "undefined") return; let observer; let observedElement; let cleaned = false; const getElement = (target) => (0, _varlet_shared.isFunction)(target) ? target() : (0, vue.unref)(target); const observe = (target) => { if (cleaned) return; const element = getElement(target); if (!element || element === observedElement) return; unobserve(); observer = new ResizeObserver(callback); observer.observe(element); observedElement = element; }; const unobserve = () => { observer?.disconnect(); observer = void 0; observedElement = void 0; }; let watchStopHandle; if ((0, vue.isRef)(target)) watchStopHandle = (0, vue.watch)(() => target.value, () => observe(target)); const cleanup = () => { watchStopHandle?.(); unobserve(); cleaned = true; }; onSmartMounted(() => observe(target)); (0, vue.onBeforeUnmount)(unobserve); (0, vue.onDeactivated)(unobserve); return cleanup; } //#endregion exports.keyInProvides = keyInProvides; exports.onSmartMounted = onSmartMounted; exports.onSmartUnmounted = onSmartUnmounted; exports.onWindowResize = onWindowResize; exports.useChildren = useChildren; exports.useClickOutside = useClickOutside; exports.useClientId = useClientId; exports.useEventListener = useEventListener; exports.useId = useId; exports.useInitialized = useInitialized; exports.useMotion = useMotion; exports.useParent = useParent; exports.useResizeObserver = useResizeObserver; exports.useTouch = useTouch; exports.useVModel = useVModel; exports.useWindowSize = useWindowSize;