// copy from https://github.dev/vueuse/vueuse import type { Ref, WatchOptions, WatchStopHandle } from 'vue'; import { unref, watch } from 'vue'; type MaybeRef = T | Ref; type Fn = () => void; export type FunctionArgs = (...args: Args) => Return; export interface FunctionWrapperOptions { fn: FunctionArgs; args: Args; thisArg: This; } export type EventFilter = ( invoke: Fn, options: FunctionWrapperOptions, ) => void; const bypassFilter: EventFilter = invoke => { return invoke(); }; /** * Create an EventFilter that debounce the events * * @param ms */ export function debounceFilter(ms: MaybeRef) { let timer: ReturnType | undefined; const filter: EventFilter = invoke => { const duration = unref(ms); if (timer) clearTimeout(timer); if (duration <= 0) return invoke(); timer = setTimeout(invoke, duration); }; return filter; } export interface DebouncedWatchOptions extends WatchOptions { debounce?: MaybeRef; } interface ConfigurableEventFilter { eventFilter?: EventFilter; } /** * @internal */ function createFilterWrapper(filter: EventFilter, fn: T) { function wrapper(this: any, ...args: any[]) { filter(() => fn.apply(this, args), { fn, thisArg: this, args }); } return wrapper as any as T; } export interface WatchWithFilterOptions extends WatchOptions, ConfigurableEventFilter {} // implementation export function watchWithFilter = false>( source: any, cb: any, options: WatchWithFilterOptions = {}, ): WatchStopHandle { const { eventFilter = bypassFilter, ...watchOptions } = options; return watch(source, createFilterWrapper(eventFilter, cb), watchOptions); } // implementation export default function debouncedWatch = false>( source: any, cb: any, options: DebouncedWatchOptions = {}, ): WatchStopHandle { const { debounce = 0, ...watchOptions } = options; return watchWithFilter(source, cb, { ...watchOptions, eventFilter: debounceFilter(debounce), }); }