UNPKG

alistair

Version:
213 lines (209 loc) 5.63 kB
'use strict'; var chunkEJMHPV5F_cjs = require('./chunk-EJMHPV5F.cjs'); var react = require('react'); // Copyright 2025 Alistair Smith https://github.com/alii/alistair function useAsyncFunction(execute) { const [state, setState] = react.useState({ loading: false, result: { type: "initial" } }); const isInFlight = react.useRef(false); const run = chunkEJMHPV5F_cjs.useEvent(async (...args) => { if (isInFlight.current) { throw new Error("Cannot execute while currently in flight"); } setState((old) => ({ ...old, loading: true })); isInFlight.current = true; try { const data = await execute(...args); setState({ loading: false, result: { type: "success", data } }); return { type: "success", data }; } catch (error) { setState({ loading: false, result: { type: "error", error } }); return { type: "error", error }; } finally { isInFlight.current = false; } }); const reset = react.useCallback(() => { setState({ loading: false, result: { type: "initial" } }); }, []); return [state, run, reset]; } function useInterval(callback, delay, options) { const runImmediately = options?.runImmediately ?? false; const savedCallback = react.useRef(callback); react.useEffect(() => { savedCallback.current = callback; }, [callback]); react.useEffect(() => { if (delay === null) { return; } const tick = () => { savedCallback.current(); }; const id = setInterval(tick, delay); if (runImmediately) { tick(); } return () => { clearInterval(id); }; }, [delay]); } function useIsOnline() { return react.useSyncExternalStore( (notify) => { window.addEventListener("online", notify); window.addEventListener("offline", notify); return () => { window.removeEventListener("online", notify); window.removeEventListener("offline", notify); }; }, () => navigator.onLine, () => false ); } function useIsTabFocused() { return react.useSyncExternalStore( (notify) => { const listener = () => { notify(); }; document.addEventListener("visibilitychange", listener); return () => { document.removeEventListener("visibilitychange", listener); }; }, () => document.visibilityState === "visible", () => false ); } var useTabFocused = useIsTabFocused; var SENTINEL = {}; function useLazyRef(init) { const ref = react.useRef(SENTINEL); if (ref.current === SENTINEL) { ref.current = init(); } return ref; } function useLocalStorage(key, init) { const stableInit = react.useRef(init); react.useEffect(() => { stableInit.current = init; }, [init]); const write = react.useCallback( (value2) => { window.localStorage.setItem(key, JSON.stringify(value2)); return value2; }, [key] ); const getOrInit = react.useCallback(() => { if (typeof window === "undefined") { return stableInit.current(); } const value2 = window.localStorage.getItem(key); if (value2 === null) { const initialised = stableInit.current(); return write(initialised); } return JSON.parse(value2); }, [key, write]); const [value, setValue] = react.useState(() => getOrInit()); const notify = react.useCallback(() => { setValue(getOrInit()); }, []); react.useEffect(() => { const listener = (event) => { if (event.key === key) { notify(); } }; window.addEventListener("storage", listener); return () => { window.removeEventListener("storage", listener); }; }, []); const set = react.useCallback( (action) => { const current = getOrInit(); let next; if (action instanceof Function) { next = write(action(current)); } else { next = write(action); } window.dispatchEvent( new StorageEvent("storage", { key, oldValue: JSON.stringify(current), newValue: JSON.stringify(next), storageArea: window.localStorage, url: window.location.href }) ); }, [getOrInit, write] ); return [value, set]; } function useThrottle(value, limit = 1e3) { const [throttledValue, setThrottledValue] = react.useState(value); const lastRan = react.useRef(Date.now()); react.useEffect(() => { const handler = setTimeout(() => { if (Date.now() - lastRan.current >= limit) { setThrottledValue(value); lastRan.current = Date.now(); } }, limit - (Date.now() - lastRan.current)); return () => { clearTimeout(handler); }; }, [value, limit]); return throttledValue; } function useToggle(initialState = false) { const [state, setState] = react.useState(initialState); const handlers = { on: react.useCallback(() => setState(true), []), off: react.useCallback(() => setState(false), []), toggle: react.useCallback(() => setState((state2) => !state2), []), reset: react.useCallback(() => setState(initialState), [initialState]) }; return [state, handlers]; } exports.useAsyncFunction = useAsyncFunction; exports.useInterval = useInterval; exports.useIsOnline = useIsOnline; exports.useIsTabFocused = useIsTabFocused; exports.useLazyRef = useLazyRef; exports.useLocalStorage = useLocalStorage; exports.useTabFocused = useTabFocused; exports.useThrottle = useThrottle; exports.useToggle = useToggle;