// eslint-disable-next-line import/no-extraneous-dependencies import { useMemoObject } from '@graphcommerce/next-ui/hooks/useMemoObject' import useEventCallback from '@mui/utils/useEventCallback' import type { DebouncedFunc, DebouncedFuncLeading, DebounceSettings, DebounceSettingsLeading, } from 'lodash' import debounce from 'lodash/debounce' import { useMemo } from 'react' export type { DebounceSettings, DebounceSettingsLeading, DebouncedFunc, DebouncedFuncLeading } /** * Creates a debounced function that delays invoking func until after wait milliseconds have elapsed * since the last time the debounced function was invoked. The debounced function comes with a * cancel method to cancel delayed invocations and a flush method to immediately invoke them. * Provide an options object to indicate that func should be invoked on the leading and/or trailing * edge of the wait timeout. Subsequent calls to the debounced function return the result of the * last func invocation. * * Note: If leading and trailing options are true, func is invoked on the trailing edge of the * timeout only if the the debounced function is invoked more than once during the wait timeout. * * See David Corbacho’s article for details over the differences between _.debounce and _.throttle. * * @param func The function to debounce. * @param wait The number of milliseconds to delay. * @param options The options object. * @param options.leading Specify invoking on the leading edge of the timeout. * @param options.maxWait The maximum time func is allowed to be delayed before it’s invoked. * @param options.trailing Specify invoking on the trailing edge of the timeout. * @returns Returns the new debounced function. */ export function useDebounce unknown>( func: T, wait: number | undefined, options: DebounceSettingsLeading, ): DebouncedFuncLeading export function useDebounce unknown>( func: T, wait?: number, options?: DebounceSettings, ): DebouncedFunc export function useDebounce unknown>( func: T, wait?: number, options?: DebounceSettings, ): DebouncedFunc { const cb = useEventCallback(func) const opts = useMemoObject( Object.fromEntries(Object.entries(options ?? {}).filter(([, v]) => v !== undefined)), ) return useMemo(() => debounce(cb, wait, opts), [cb, opts, wait]) } export { debounce }