@studio-lumio/hooks
Version:
a compilation of react hooks we use to make our magic
1 lines • 62.1 kB
Source Map (JSON)
{"version":3,"file":"hooks.mjs","sources":["../src/hooks/useOnClickOutside.ts","../src/hooks/useIsClient.ts","../src/hooks/use-debug.ts","../src/hooks/use-document-ready-state.ts","../src/hooks/use-frame.ts","../src/hooks/useIsomorphicLayoutEffect.ts","../src/hooks/useInterval.ts","../src/hooks/use-is-touch-device.js","../src/hooks/use-is-visible.ts","../src/hooks/use-media-query.ts","../src/hooks/use-rect.ts","../src/hooks/use-slots.ts","../src/hooks/useEventListener.ts","../src/hooks/useWindowSize.ts","../src/hooks/useIntersectionObserver.ts","../src/hooks/useCopyToClipboard.ts","../src/hooks/useDebounce.ts","../src/hooks/useEffectOnce.ts","../src/hooks/useFirstMountState.ts","../src/hooks/useUpdateEffect.ts","../src/hooks/useIsMounted.ts","../src/hooks/useLocalStorage.ts","../src/hooks/useSessionStorage.ts","../src/hooks/useFoucFix.ts","../src/hooks/useIOSToolbarState.ts","../src/hooks/useScript.ts","../src/hooks/useKeySequence.ts","../src/hooks/useFavicon.ts","../src/hooks/useIdle.ts","../src/utils.ts","../src/hooks/useDocumentTitle.ts","../src/hooks/useHover.ts","../src/hooks/usePageLeave.ts","../src/hooks/useOrientation.ts","../src/hooks/useList.ts","../src/hooks/useCookie.ts","../src/hooks/useUnmount.ts","../src/hooks/useThrottle.ts","../src/hooks/useDebounceFn.ts","../src/hooks/useResizeObserver.ts","../src/hooks/useRealViewport.tsx"],"sourcesContent":["import { RefObject } from 'react'\nimport { useEventListener } from '..'\n\ntype Handler = (event: MouseEvent) => void\n\nexport function useOnClickOutside<T extends HTMLElement = HTMLElement>(\n ref: RefObject<T>,\n handler: Handler,\n mouseEvent: 'mousedown' | 'mouseup' = 'mousedown'\n): void {\n useEventListener(mouseEvent, (event) => {\n const el = ref?.current\n\n // Do nothing if clicking ref's element or descendent elements\n if (!el || el.contains(event.target as Node)) {\n return\n }\n\n handler(event)\n })\n}\n","// This component is used to check if the window object is present.\nimport { useEffect, useState } from 'react'\n\nexport function useIsClient() {\n const [isClient, setClient] = useState(false)\n\n useEffect(() => {\n setClient(true)\n }, [])\n\n return isClient\n}\n","/**\n * @summary A hook that returns true if the current window URL contains the\n * string #debug or if we're in development mode.\n * @returns {Boolean} True if current window URL contains the string #debug or\n * if we're in development mode, false otherwise.\n */\n\nimport { useMemo } from 'react'\nimport { useIsClient } from './useIsClient'\n\nexport function useDebug() {\n const isClient = useIsClient()\n const debug = useMemo(\n () =>\n isClient &&\n (window.location.href.includes('#debug') || process.env.NODE_ENV === 'development') &&\n !window.location.href.includes('#production'),\n [isClient]\n )\n\n return debug\n}\n","// useDocumentReadyState.js\n// This code is a custom hook that returns the current document.readyState\n// The useLayoutEffect hook is used to set the state of the document\n// The useEffect hook is used to set the state of the document to 'complete' when the document is ready\n\nimport { useEffect, useState } from 'react'\n\nexport function useDocumentReadyState() {\n const [readyState, setReadyState] = useState(() => {\n if (typeof document !== 'undefined') {\n return document.readyState\n }\n return 'loading'\n })\n\n useEffect(() => {\n if (typeof document === 'undefined') return\n\n setReadyState(document.readyState)\n\n function onStateChange() {\n setReadyState(document.readyState)\n }\n\n document.addEventListener('readystatechange', onStateChange, false)\n\n return () => document.removeEventListener('readystatechange', onStateChange, false)\n }, [])\n\n return readyState\n}\n","/**\n * Creates a requestAnimationFrame loop and manages the lifecycle of the callback.\n * @param {Function} callback - A function that is called every frame.\n * @param {Number} priority - A number that determines the order in which the callback is called.\n */\nimport { raf } from '@studio-freight/tempus'\nimport { useEffect } from 'react'\n\nexport function useFrame(callback, priority = 0) {\n useEffect(() => {\n if (callback) {\n raf.add(callback, priority)\n\n return () => raf.remove(callback)\n }\n }, [callback, priority])\n}\n","import { useEffect, useLayoutEffect } from 'react'\n\nexport const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect\n","import { useEffect, useRef } from 'react'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\n\nexport function useInterval(callback: () => void, delay: number | null) {\n const savedCallback = useRef(callback)\n\n useIsomorphicLayoutEffect(() => {\n savedCallback.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!delay && delay !== 0) {\n return\n }\n\n const id = setInterval(() => savedCallback.current(), delay)\n\n return () => clearInterval(id)\n }, [delay])\n}\n","import { useCallback, useEffect, useState } from 'react'\n\nexport const useIsTouchDevice = () => {\n const [isTouchDevice, setIsTouchDevice] = useState(false)\n\n const check = useCallback(() => {\n let hasTouchScreen = false\n\n if ('maxTouchPoints' in navigator) {\n hasTouchScreen = navigator.maxTouchPoints > 0\n } else {\n const mediaQueryList = window.matchMedia('(pointer:coarse)')\n if (mediaQueryList && mediaQueryList.media === '(pointer:coarse)') {\n hasTouchScreen = !!mediaQueryList.matches\n } else {\n\n const UA = window.navigator.userAgent\n hasTouchScreen =\n /\\b(BlackBerry|webOS|iPhone|IEMobile)\\b/i.test(UA) || /\\b(Android|Windows Phone|iPad|iPod)\\b/i.test(UA)\n }\n }\n if (hasTouchScreen) {\n setIsTouchDevice(true)\n } else {\n setIsTouchDevice(false)\n }\n }, [])\n\n const onResize = useCallback(() => {\n check()\n }, [check])\n\n useEffect(() => {\n onResize()\n window.addEventListener('resize', onResize, { passive: true })\n\n return () => {\n window.removeEventListener('resize', onResize)\n }\n }, [onResize])\n\n return isTouchDevice\n}\n","// useIsVisible is a custom hook that allows you to detect when an element is\n// visible on the screen. It takes an object as an argument, and returns an object\n// with two properties: setRef and inView.\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\nexport function useIsVisible({\n root = null,\n rootMargin = '0px',\n threshold = 1.0,\n once = false,\n}: {\n root?: Element | Document | null\n rootMargin?: string\n threshold?: number\n once?: boolean\n}) {\n const observer = useRef<any>(null)\n const ref = useRef<any>(null)\n const [inView, setInView] = useState(false)\n\n const setRef = useCallback((node) => {\n if (!ref.current) {\n ref.current = node\n }\n }, [])\n\n const callbackFunction = useCallback((entries) => {\n const [entry] = entries\n setInView(entry.isIntersecting)\n }, [])\n\n useEffect(() => {\n if (ref.current) {\n observer.current = new IntersectionObserver(callbackFunction, {\n root,\n rootMargin,\n threshold,\n })\n observer.current.observe(ref.current)\n }\n return () => {\n if (observer.current) {\n observer.current.disconnect()\n }\n }\n }, [callbackFunction])\n\n useEffect(() => {\n if (once && inView) {\n observer.current.disconnect()\n }\n }, [inView])\n\n return { setRef, inView }\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useIsClient } from './useIsClient'\n\n/**\n * @name useMediaQuery\n * @description A React hook that detects whether a media query is true or false.\n * @param {string} queryString - The media query to test against.\n * @returns {boolean} - Whether the media query is true or false.\n */\n\nexport function useMediaQuery(queryString: string) {\n const isClient = useIsClient()\n\n const mediaQuery = useMemo(() => {\n if (isClient) {\n try {\n return window.matchMedia(queryString)\n } catch (error) {\n if (process.env.NODE_ENV !== 'production') {\n console.error(error)\n }\n }\n }\n\n return null\n }, [queryString, isClient])\n\n const [isMatch, setIsMatch] = useState(undefined)\n\n const onChange = useCallback(({ matches }: any) => {\n setIsMatch(matches)\n }, [])\n\n useEffect(() => {\n if (mediaQuery) {\n onChange(mediaQuery)\n\n mediaQuery.addEventListener('change', onChange, { passive: true })\n\n return () => {\n mediaQuery.removeEventListener('change', onChange)\n }\n }\n }, [mediaQuery, onChange, isClient])\n\n return isMatch\n}\n","import { useLayoutEffect, useCallback, useState, MutableRefObject } from 'react'\n\nexport const useRect = (ref: MutableRefObject<any>) => {\n const [rect, setRect] = useState(getRect(ref ? ref.current : null))\n\n const handleResize = useCallback(() => {\n if (!ref.current) {\n return\n }\n\n // Update client rect\n setRect(getRect(ref.current))\n }, [ref])\n\n useLayoutEffect(() => {\n const element = ref.current\n if (!element) {\n return\n }\n\n handleResize()\n\n if (typeof ResizeObserver === 'function') {\n let resizeObserver = new ResizeObserver(() => handleResize())\n resizeObserver.observe(element)\n\n return () => {\n if (!resizeObserver) {\n return\n }\n\n resizeObserver.disconnect()\n resizeObserver = null\n }\n } else {\n // Browser support, remove freely\n window.addEventListener('resize', handleResize)\n\n return () => {\n window.removeEventListener('resize', handleResize)\n }\n }\n }, [ref.current])\n\n return rect\n}\n\nfunction getRect(element) {\n if (!element) {\n return {\n bottom: 0,\n height: 0,\n left: 0,\n right: 0,\n top: 0,\n width: 0,\n }\n }\n\n return element.getBoundingClientRect()\n}\n","// This code is used to extract the contents of a component's children and return them as an array.\n// The code accepts two arguments, the names of the components that it should extract, and the children to extract from.\n// The code returns an array of the children of the components passed in the types argument.\n// based on:\n// https://medium.com/swlh/bring-vue-named-slots-to-react-87684188f18e\n\nimport { useMemo } from 'react'\n\nexport function useSlots(types: any[] = [], children: any[] = []) {\n const _children = useMemo(() => children && [children].flat(), [children])\n const _types = useMemo(() => types && [types].flat(), [types])\n const slots = useMemo(() => {\n if (!_children || !_types) {\n return\n }\n\n const slots = _types.map((type) => _children.find((el) => el.type === type)?.props.children)\n\n return types[0] ? slots : slots[0]\n }, [_children, _types])\n\n return slots\n}\n","import { RefObject, useEffect, useRef } from 'react'\nimport { useIsomorphicLayoutEffect } from '..'\n\n// MediaQueryList Event based useEventListener interface\nexport function useEventListener<K extends keyof MediaQueryListEventMap>(\n eventName: K,\n handler: (event: MediaQueryListEventMap[K]) => void,\n element: RefObject<MediaQueryList>,\n options?: boolean | AddEventListenerOptions\n): void\n\n// Window Event based useEventListener interface\nexport function useEventListener<K extends keyof WindowEventMap>(\n eventName: K,\n handler: (event: WindowEventMap[K]) => void,\n element?: undefined,\n options?: boolean | AddEventListenerOptions\n): void\n\n// Element Event based useEventListener interface\nexport function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = HTMLDivElement>(\n eventName: K,\n handler: (event: HTMLElementEventMap[K]) => void,\n element: RefObject<T>,\n options?: boolean | AddEventListenerOptions\n): void\n\n// Document Event based useEventListener interface\nexport function useEventListener<K extends keyof DocumentEventMap>(\n eventName: K,\n handler: (event: DocumentEventMap[K]) => void,\n element: RefObject<Document>,\n options?: boolean | AddEventListenerOptions\n): void\n\nexport function useEventListener<\n KW extends keyof WindowEventMap,\n KH extends keyof HTMLElementEventMap,\n KM extends keyof MediaQueryListEventMap,\n T extends HTMLElement | MediaQueryList | void = void\n>(\n eventName: KW | KH | KM,\n handler: (event: WindowEventMap[KW] | HTMLElementEventMap[KH] | MediaQueryListEventMap[KM] | Event) => void,\n element?: RefObject<T>,\n options?: boolean | AddEventListenerOptions\n) {\n // Create a ref that stores handler\n const savedHandler = useRef(handler)\n\n useIsomorphicLayoutEffect(() => {\n savedHandler.current = handler\n }, [handler])\n\n useEffect(() => {\n // Define the listening target\n const targetElement: T | Window = element?.current ?? window\n\n if (!(targetElement && targetElement.addEventListener)) return\n\n // Create event listener that calls handler function stored in ref\n const listener: typeof handler = (event) => savedHandler.current(event)\n\n targetElement.addEventListener(eventName, listener, options)\n\n // Remove event listener on cleanup\n return () => {\n targetElement.removeEventListener(eventName, listener, options)\n }\n }, [eventName, element, options])\n}\n","import { useState } from 'react'\nimport { useEventListener } from './useEventListener'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\n\ninterface WindowSize {\n width: number\n height: number\n}\n\nexport const useWindowSize = (): WindowSize => {\n const [windowSize, setWindowSize] = useState<WindowSize>({\n width: 0,\n height: 0,\n })\n\n const handleSize = () => {\n setWindowSize({\n width: window.innerWidth,\n height: window.innerHeight,\n })\n }\n\n useEventListener('resize', handleSize)\n\n // Set size at the first client-side load\n useIsomorphicLayoutEffect(() => {\n handleSize()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n return windowSize\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\n\ninterface UseIntersectionObserverProps {\n root?: HTMLElement | null\n rootMargin?: string\n threshold?: number\n once?: boolean\n lazy?: boolean\n callback?: (entry: IntersectionObserverEntry) => void\n}\n\ntype UseIntersectionObserverReturn = [\n (element: HTMLElement | null) => void,\n IntersectionObserverEntry | (() => IntersectionObserverEntry | undefined)\n]\n\n/**\n * useIntersectionObserver - A React hook that observes element visibility using IntersectionObserver.\n * @param {object} props - Configuration options\n * @param {HTMLElement} props.root - The element that is used as the viewport for checking visibility.\n * @param {string} props.rootMargin - Margin around the root.\n * @param {number} props.threshold - Number from 0 to 1 indicating the percentage of the target's visibility.\n * @param {boolean} props.once - Whether to disconnect after first intersection.\n * @param {boolean} props.lazy - Whether to update state lazily.\n * @param {function} props.callback - Function to call when the intersection changes.\n * @param {array} deps - Dependency array for the effect.\n * @returns {array} [setElement, entry]\n */\n\nexport function useIntersectionObserver(\n {\n root = null,\n rootMargin = '0px',\n threshold = 0,\n once = false,\n lazy = false,\n callback = () => {},\n }: UseIntersectionObserverProps = {},\n deps: any[] = []\n): UseIntersectionObserverReturn {\n const entryRef = useRef<IntersectionObserverEntry>()\n const [entry, setEntry] = useState<IntersectionObserverEntry>()\n const [element, setElement] = useState<HTMLElement | null>(null)\n\n useEffect(() => {\n if (!element) return\n\n const intersection = new IntersectionObserver(\n ([entry]) => {\n if (lazy) {\n entryRef.current = entry\n } else {\n setEntry(entry)\n }\n\n callback(entry)\n\n if (once && entry.isIntersecting) intersection.disconnect()\n },\n {\n root,\n rootMargin,\n threshold,\n }\n )\n intersection.observe(element)\n\n return () => {\n intersection.disconnect()\n }\n }, [element, root, rootMargin, threshold, lazy, once, ...deps])\n\n const get = useCallback(() => entryRef.current, [])\n\n return [setElement, lazy ? get : entry]\n}\n","import { useState } from 'react'\n\ntype CopiedValue = string | null\ntype CopyFn = (text: string, callback: () => any) => Promise<boolean>\n\nexport function useCopyToClipboard(): [CopiedValue, CopyFn] {\n const [copiedText, setCopiedText] = useState<CopiedValue>(null)\n\n const copy: CopyFn = async (text, callback) => {\n if (!navigator?.clipboard) {\n console.warn('Clipboard not supported')\n return false\n }\n\n try {\n await navigator.clipboard.writeText(text)\n setCopiedText(text)\n callback()\n return true\n } catch (error) {\n console.warn('Copy failed', error)\n setCopiedText(null)\n return false\n }\n }\n\n return [copiedText, copy]\n}\n","import { useEffect, useState } from 'react'\n\nexport function useDebounce<T>(value: T, delay?: number): T {\n const [debouncedValue, setDebouncedValue] = useState<T>(value)\n\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedValue(value), delay || 500)\n\n return () => {\n clearTimeout(timer)\n }\n }, [value, delay])\n\n return debouncedValue\n}\n","import { useEffect, useRef, useState } from 'react'\n\nexport const useEffectOnce = (effect: () => void | (() => void)) => {\n const effectFn = useRef<() => void | (() => void)>(effect)\n const destroyFn = useRef<void | (() => void)>()\n const effectCalled = useRef(false)\n const rendered = useRef(false)\n const [, setVal] = useState<number>(0)\n\n if (effectCalled.current) {\n rendered.current = true\n }\n\n useEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFn.current = effectFn.current()\n effectCalled.current = true\n }\n\n // this forces one render after the effect is run\n setVal((val) => val + 1)\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!rendered.current) {\n return\n }\n\n // otherwise this is not a dummy destroy, so call the destroy func\n if (destroyFn.current) {\n destroyFn.current()\n }\n }\n }, [])\n}\n","import { useRef } from 'react'\n\n/**\n * @description React state hook that returns true if component is just mounted.\n */\nexport function useFirstMountState(): boolean {\n const isFirst = useRef(true)\n\n if (isFirst.current) {\n isFirst.current = false\n\n return true\n }\n\n return isFirst.current\n}\n","import { useEffect } from 'react'\nimport { useFirstMountState } from './useFirstMountState'\n\n/**\n *@description React effect hook that ignores the first call (e.g. on mount)\n */\nexport const useUpdateEffect: typeof useEffect = (effect, deps) => {\n const isFirstMount = useFirstMountState()\n\n useEffect(() => {\n if (!isFirstMount) {\n return effect()\n }\n }, deps)\n}\n","import { useCallback, useEffect, useRef } from 'react'\n\n/**\n *@description will return a callback that returns true if the component is mounted\n */\nexport function useIsMounted(): () => boolean {\n const mountedRef = useRef<boolean>(false)\n const get = useCallback(() => mountedRef.current, [])\n\n useEffect(() => {\n mountedRef.current = true\n\n return () => {\n mountedRef.current = false\n }\n }, [])\n\n return get\n}\n","import { useState } from 'react'\n\n// Define the type for the initial value\ntype InitialValueType = string | number | boolean | object | null | any\ntype StoredValue = InitialValueType\ntype SetValue = (value: InitialValueType | ((val: InitialValueType) => InitialValueType)) => void\ntype RemoveValue = () => void\n\nexport function useLocalStorage(\n key: string,\n initialValue?: InitialValueType\n): Readonly<[StoredValue, SetValue, RemoveValue]> {\n const [storedValue, setStoredValue] = useState<InitialValueType>(() => {\n if (typeof window === 'undefined') {\n return initialValue\n }\n try {\n const item = window.localStorage.getItem(key)\n\n return item ? JSON.parse(item) : initialValue\n } catch (error) {\n console.log(error)\n return initialValue\n }\n })\n\n const setValue = (value: InitialValueType | ((val: InitialValueType) => InitialValueType)) => {\n try {\n const valueToStore = value instanceof Function ? value(storedValue) : value\n\n setStoredValue(valueToStore)\n\n if (typeof window !== 'undefined') {\n window.localStorage.setItem(key, JSON.stringify(valueToStore))\n }\n } catch (error) {\n console.log(error)\n }\n }\n\n const removeValue = () => {\n try {\n if (typeof window !== 'undefined') {\n window.localStorage.removeItem(key)\n }\n } catch (error) {\n console.log(error)\n }\n }\n\n return [storedValue, setValue, removeValue] as const\n}\n","import { useState } from 'react'\n\n// Define the type for the initial value\ntype InitialValueType = string | number | boolean | object | null | any\ntype StoredValue = InitialValueType\ntype SetValue = (value: InitialValueType | ((val: InitialValueType) => InitialValueType)) => void\ntype RemoveValue = () => void\n\nexport function useSessionStorage(\n key: string,\n initialValue?: InitialValueType\n): Readonly<[StoredValue, SetValue, RemoveValue]> {\n const [storedValue, setStoredValue] = useState<InitialValueType>(() => {\n if (typeof window === 'undefined') {\n return initialValue\n }\n try {\n const item = window.sessionStorage.getItem(key)\n\n return item ? JSON.parse(item) : initialValue\n } catch (error) {\n console.log(error)\n return initialValue\n }\n })\n\n const setValue = (value: InitialValueType | ((val: InitialValueType) => InitialValueType)) => {\n try {\n const valueToStore = value instanceof Function ? value(storedValue) : value\n\n setStoredValue(valueToStore)\n\n if (typeof window !== 'undefined') {\n window.sessionStorage.setItem(key, JSON.stringify(valueToStore))\n }\n } catch (error) {\n console.log(error)\n }\n }\n\n const removeValue = () => {\n try {\n if (typeof window !== 'undefined') {\n window.sessionStorage.removeItem(key)\n }\n } catch (error) {\n console.log(error)\n }\n }\n\n return [storedValue, setValue, removeValue] as const\n}\n","import { useEffect } from 'react'\n\n// Temporary fix to avoid flash of unstyled content (FOUC) during route transitions.\n// Keep an eye on this issue and remove this code when resolved: https://github.com/vercel/next.js/issues/17464\nexport const useFoucFix = () =>\n useEffect(() => {\n console.debug(\n 'WARNING: Still using FOUC temp fix on route change. Has the Next.js bug not been fixed? See https://github.com/vercel/next.js/issues/17464'\n )\n\n // Gather all server-side rendered stylesheet entries.\n let stylesheets = Array.from(document.querySelectorAll('link[rel=\"stylesheet\"][data-n-p]')).map((element) => ({\n element,\n href: element.getAttribute('href'),\n }))\n\n // Remove the `data-n-p` attribute to prevent Next.js from removing it early.\n stylesheets.forEach(({ element }) => element.removeAttribute('data-n-p'))\n\n const hrefs = []\n\n const mutationHandler = (mutations) => {\n // Gather all <style data-n-href=\"/...\"> elements.\n const entries = mutations\n .filter(({ target }) => target.nodeName === 'STYLE' && target.hasAttribute('data-n-href'))\n .map(({ target }) => ({\n element: target,\n href: target.getAttribute('data-n-href'),\n }))\n\n // Cycle through them and either:\n // - Remove the `data-n-href` attribute to prevent Next.js from removing it early.\n // - Remove the element if it's already present.\n entries.forEach(({ element, href }) => {\n const exists = hrefs.includes(href)\n\n if (exists) {\n element.remove()\n } else {\n element.setAttribute('data-fouc-fix-n-href', href)\n element.removeAttribute('data-n-href')\n hrefs.push(href)\n }\n })\n\n // Cycle through the server-side rendered stylesheets and remove the ones that\n // are already present as inline <style> tags added by Next.js, so that we don't have duplicate styles.\n stylesheets = stylesheets.reduce((entries, entry) => {\n const { element, href } = entry\n const exists = hrefs.includes(href)\n\n if (exists) {\n element.remove()\n } else {\n entries.push(entry)\n }\n\n return entries\n }, [])\n }\n\n const observer = new MutationObserver(mutationHandler)\n\n observer.observe(document.head, {\n subtree: true,\n attributeFilter: ['media'],\n })\n\n return () => observer.disconnect()\n }, [])\n","import { useEffect, useState } from 'react'\n\nexport const useIOSToolbarState = () => {\n const [isVisible, setIsVisible] = useState<boolean>()\n\n useEffect(() => {\n const ua = window.navigator ? window.navigator.userAgent : ''\n const iOS = ua.match(/iPad/i) || ua.match(/iPhone/i)\n const webkit = ua.match(/WebKit/i)\n const iOSSafari = iOS && webkit && !ua.match(/CriOS/i)\n const baseWindowHeight = window.innerHeight\n\n function handleScroll() {\n const newWindowHeight = window.innerHeight\n if (newWindowHeight - 50 > baseWindowHeight) {\n setIsVisible(false)\n } else {\n setIsVisible(true)\n }\n }\n\n // the toolbar issue only happens on iOS Safari\n if (iOSSafari) {\n if ('standalone' in window.navigator && (window.navigator as any)['standalone']) {\n // if it's iOS' standalone mode (added to home screen)\n // the toolbar is always \"hidden\"\n setIsVisible(false)\n } else {\n // iOS Safari\n document.addEventListener('scroll', handleScroll)\n\n return () => {\n document.removeEventListener('scroll', handleScroll)\n }\n }\n }\n }, [])\n\n return { isVisible }\n}\n","import { useEffect } from 'react'\n\nexport const useScript = (url: string) => {\n useEffect(() => {\n const script = document.createElement('script')\n\n script.src = url\n script.async = true\n\n document.body.appendChild(script)\n\n return () => {\n document.body.removeChild(script)\n }\n }, [url])\n}\n\nexport default useScript\n","export const useKeySequence = ({ sequence, callback }: { sequence: string; callback: () => void }) => {\n function keyMapper(options) {\n const eventType = (options && options.eventType) || 'keydown'\n const keystrokeDelay = (options && options.keystrokeDelay) || 1000\n let buffer = []\n let lastKeyTime = Date.now()\n\n document.addEventListener(eventType, (event) => {\n const key = event.key.toLowerCase()\n\n const currentTime = Date.now()\n\n if (currentTime - lastKeyTime > keystrokeDelay) {\n buffer = []\n }\n\n buffer.push(key)\n lastKeyTime = currentTime\n\n if (sequence === buffer.join('')) {\n callback()\n }\n })\n }\n\n const options = {\n eventType: 'keydown',\n keystrokeDelay: 1000,\n }\n\n keyMapper(options)\n\n return null\n}\n\nexport default useKeySequence\n","import { useEffect } from 'react'\n\nexport function useFavicon(url: string) {\n useEffect(() => {\n const link: Element | any = document.querySelector(\"link[rel*='icon']\") || document.createElement('link')\n link.type = 'image/x-icon'\n link.rel = 'shortcut icon'\n link.href = url\n document.getElementsByTagName('head')[0].appendChild(link)\n }, [url])\n}\n","import { throttle } from '../utils'\nimport { useState, useEffect } from 'react'\n\nexport function useIdle(ms = 1000 * 60) {\n const [idle, setIdle] = useState(false)\n\n useEffect(() => {\n let timeoutId\n\n const handleTimeout = () => {\n setIdle(true)\n }\n\n const handleEvent = throttle(() => {\n setIdle(false)\n\n window.clearTimeout(timeoutId)\n timeoutId = window.setTimeout(handleTimeout, ms)\n }, 500)\n\n const handleVisibilityChange = () => {\n if (!document.hidden) {\n handleEvent()\n }\n }\n\n timeoutId = window.setTimeout(handleTimeout, ms)\n\n window.addEventListener('mousemove', handleEvent)\n window.addEventListener('mousedown', handleEvent)\n window.addEventListener('resize', handleEvent)\n window.addEventListener('keydown', handleEvent)\n window.addEventListener('touchstart', handleEvent)\n window.addEventListener('wheel', handleEvent)\n document.addEventListener('visibilitychange', handleVisibilityChange)\n\n return () => {\n window.removeEventListener('mousemove', handleEvent)\n window.removeEventListener('mousedown', handleEvent)\n window.removeEventListener('resize', handleEvent)\n window.removeEventListener('keydown', handleEvent)\n window.removeEventListener('touchstart', handleEvent)\n window.removeEventListener('wheel', handleEvent)\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n window.clearTimeout(timeoutId)\n }\n }, [ms])\n\n return idle\n}\n","export function throttle(cb: { (e: any): void; (): void }, ms: number) {\n let lastTime = 0\n return () => {\n const now = Date.now()\n if (now - lastTime >= ms) {\n cb()\n lastTime = now\n }\n }\n}\n\ntype DebouncedFunction<T extends (...args: any[]) => any> = T & {\n cancel: () => void\n flush: () => void\n}\n\nexport function debounce<T extends (...args: any[]) => any>(\n fn: T,\n wait: number,\n callFirst?: boolean\n): DebouncedFunction<T> {\n let timeout: ReturnType<typeof setTimeout> | null = null\n let debouncedFn: (() => void) | null = null\n\n const clear = () => {\n if (timeout) {\n clearTimeout(timeout)\n debouncedFn = null\n timeout = null\n }\n }\n\n const flush = () => {\n const call = debouncedFn\n clear()\n if (call) {\n call()\n }\n }\n\n const debounceWrapper = function (this: any, ...args: any[]) {\n if (!wait) {\n return fn.apply(this, args)\n }\n\n const context = this\n const callNow = callFirst && !timeout\n clear()\n\n debouncedFn = function () {\n fn.apply(context, args)\n }\n\n timeout = setTimeout(() => {\n timeout = null\n if (!callNow) {\n const call = debouncedFn\n debouncedFn = null\n return call && call()\n }\n }, wait)\n\n if (callNow) {\n return debouncedFn()\n }\n } as DebouncedFunction<T>\n\n debounceWrapper.cancel = clear\n debounceWrapper.flush = flush\n\n return debounceWrapper\n}\n\nexport const noop = () => {}\n\nexport function on<T extends Window | Document | HTMLElement | EventTarget>(\n obj: T | null,\n ...args: Parameters<T['addEventListener']> | [string, Function | null, ...any]\n): void {\n if (obj && obj.addEventListener) {\n obj.addEventListener(...(args as Parameters<HTMLElement['addEventListener']>))\n }\n}\n\nexport function off<T extends Window | Document | HTMLElement | EventTarget>(\n obj: T | null,\n ...args: Parameters<T['removeEventListener']> | [string, Function | null, ...any]\n): void {\n if (obj && obj.removeEventListener) {\n obj.removeEventListener(...(args as Parameters<HTMLElement['removeEventListener']>))\n }\n}\n\nexport const isBrowser = typeof window !== 'undefined'\n\nexport const isNavigator = typeof navigator !== 'undefined'\n","import { useEffect } from 'react'\n\nexport function useDocumentTitle(title: string) {\n useEffect(() => {\n document.title = title\n }, [title])\n}\n","import { useState, useRef, useEffect } from 'react'\n\nexport function useHover() {\n const [hovering, setHovering] = useState(false)\n const ref = useRef(null)\n\n useEffect(() => {\n const node = ref.current\n\n if (!node) return\n\n const handleMouseEnter = () => {\n setHovering(true)\n }\n\n const handleMouseLeave = () => {\n setHovering(false)\n }\n\n node.addEventListener('mouseenter', handleMouseEnter)\n node.addEventListener('mouseleave', handleMouseLeave)\n\n return () => {\n node.removeEventListener('mouseenter', handleMouseEnter)\n node.removeEventListener('mouseleave', handleMouseLeave)\n }\n }, [])\n\n return [ref, hovering]\n}\n","import { off, on } from '../utils'\nimport { useEffect } from 'react'\n\nexport const usePageLeave = (onPageLeave, args = []) => {\n useEffect(() => {\n if (!onPageLeave) {\n return\n }\n\n const handler = (event) => {\n event = event ? event : (window.event as any)\n const from = event.relatedTarget || event.toElement\n if (!from || (from as any).nodeName === 'HTML') {\n onPageLeave()\n }\n }\n\n on(document, 'mouseout', handler)\n return () => {\n off(document, 'mouseout', handler)\n }\n }, args)\n}\n","import { useState, useLayoutEffect } from 'react'\n\nexport function useOrientation() {\n const [orientation, setOrientation] = useState({\n angle: 0,\n type: 'landscape-primary',\n })\n\n useLayoutEffect(() => {\n const handleChange = () => {\n const { angle, type } = window.screen.orientation\n setOrientation({\n angle,\n type,\n })\n }\n\n const handle_orientationchange = () => {\n setOrientation({\n type: 'UNKNOWN',\n angle: window.orientation,\n })\n }\n\n if (window.screen?.orientation) {\n handleChange()\n window.screen.orientation.addEventListener('change', handleChange)\n } else {\n handle_orientationchange()\n window.addEventListener('orientationchange', handle_orientationchange)\n }\n\n return () => {\n if (window.screen?.orientation) {\n window.screen.orientation.removeEventListener('change', handleChange)\n } else {\n window.removeEventListener('orientationchange', handle_orientationchange)\n }\n }\n }, [])\n\n return orientation\n}\n","import { useCallback, useState } from 'react'\n\nexport function useList(defaultList = []) {\n const [list, setList] = useState(defaultList)\n\n const set = useCallback((l) => {\n setList(l)\n }, [])\n\n const push = useCallback((element) => {\n setList((l) => [...l, element])\n }, [])\n\n const removeAt = useCallback((index) => {\n setList((l) => [...l.slice(0, index), ...l.slice(index + 1)])\n }, [])\n\n const insertAt = useCallback((index, element) => {\n setList((l) => [...l.slice(0, index), element, ...l.slice(index)])\n }, [])\n\n const updateAt = useCallback((index, element) => {\n setList((l) => l.map((e, i) => (i === index ? element : e)))\n }, [])\n\n const clear = useCallback(() => setList([]), [])\n\n return [list, { set, push, removeAt, insertAt, updateAt, clear }]\n}\n","import { useCallback, useState } from 'react'\nimport Cookies from 'js-cookie'\n\nexport const useCookie = (\n cookieName: string\n): [string | null, (newValue: string, options?: Cookies.CookieAttributes) => void, () => void] => {\n const [value, setValue] = useState<string | null>(() => Cookies.get(cookieName) || null)\n\n const updateCookie = useCallback(\n (newValue: string, options?: Cookies.CookieAttributes) => {\n Cookies.set(cookieName, newValue, options)\n setValue(newValue)\n },\n [cookieName]\n )\n\n const deleteCookie = useCallback(() => {\n Cookies.remove(cookieName)\n setValue(null)\n }, [cookieName])\n\n return [value, updateCookie, deleteCookie]\n}\n","import { useRef } from 'react'\nimport { useEffectOnce } from './useEffectOnce'\n\nexport const useUnmount = (fn: () => any): void => {\n const fnRef = useRef(fn)\n\n // update the ref each render so if it change the newest callback will be invoked\n fnRef.current = fn\n\n useEffectOnce(() => () => fnRef.current())\n}\n\nexport default useUnmount\n","import { useEffect, useRef, useState } from 'react'\nimport { useUnmount } from './useUnmount'\n\nexport const useThrottle = <T>(value: T, ms: number = 200) => {\n const [state, setState] = useState<T>(value)\n const timeout = useRef<ReturnType<typeof setTimeout>>()\n const nextValue = useRef(null) as any\n const hasNextValue = useRef(0) as any\n\n useEffect(() => {\n if (!timeout.current) {\n setState(value)\n const timeoutCallback = () => {\n if (hasNextValue.current) {\n hasNextValue.current = false\n setState(nextValue.current)\n timeout.current = setTimeout(timeoutCallback, ms)\n } else {\n timeout.current = undefined\n }\n }\n timeout.current = setTimeout(timeoutCallback, ms)\n } else {\n nextValue.current = value\n hasNextValue.current = true\n }\n }, [value])\n\n useUnmount(() => {\n timeout.current && clearTimeout(timeout.current)\n })\n\n return state\n}\n\nexport default useThrottle\n","import { useEffect, useRef } from 'react'\n\nexport function useDebounceFn(fn: (...args: any[]) => any, delay: number): (...args: any[]) => void {\n const timeoutRef = useRef<NodeJS.Timeout | null>(null)\n const functionRef = useRef(fn)\n\n useEffect(() => {\n functionRef.current = fn\n }, [fn])\n\n return (...args: any[]) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n\n timeoutRef.current = setTimeout(() => {\n functionRef.current(...args)\n }, delay)\n }\n}\n","import { debounce } from '../utils'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\n/**\n * useResizeObserver - observe elements dimensions using ResizeObserver\n * @param {Boolean} lazy - should return a state or not\n * @param {Number} debounce - minimum delay between two ResizeObserver computations\n * @param {String} box - ResizeObserver parameter\n * @param {Function} callback - called on value change\n */\n\ninterface ResizeObserverProps {\n lazy?: boolean\n debounce?: number\n box?: ResizeObserverBoxOptions\n callback?: (entry: ResizeObserverEntry) => void\n}\n\ntype UseResizeObserverReturn = [\n (element: HTMLElement | null) => void,\n ResizeObserverEntry | (() => ResizeObserverEntry | undefined)\n]\n\nexport function useResizeObserver({\n lazy = false,\n debounce: debounceDelay = 500,\n box = 'border-box',\n callback = () => {},\n}: ResizeObserverProps = {}): UseResizeObserverReturn {\n const entryRef = useRef<ResizeObserverEntry | null>(null)\n const [entry, setEntry] = useState<ResizeObserverEntry>(null)\n const [element, setElement] = useState<Element | null>(null)\n const needsUpdateRef = useRef(false)\n\n const debouncedSetEntry = useMemo(() => debounce(setEntry, debounceDelay), [debounceDelay])\n\n const onResize = useCallback(\n ([entry]: ResizeObserverEntry[]) => {\n entryRef.current = entry\n\n callback(entry)\n\n if (!lazy) {\n if (needsUpdateRef.current) {\n setEntry(entry)\n } else {\n debouncedSetEntry(entry)\n }\n }\n\n needsUpdateRef.current = false\n },\n [lazy, debouncedSetEntry, callback]\n )\n\n useEffect(() => {\n if (!element) return\n\n needsUpdateRef.current = true // set to true to force update on first render when element has changed\n\n const resizeObserver = new ResizeObserver(onResize)\n resizeObserver.observe(element, { box })\n\n return () => {\n resizeObserver.disconnect()\n debouncedSetEntry.cancel()\n }\n }, [element, debounceDelay, box, onResize, debouncedSetEntry])\n\n const get = useCallback(() => entryRef.current, [])\n\n return [setElement, lazy ? get : entry]\n}\n","'use client'\n\nimport { useCallback, useLayoutEffect } from 'react'\n\nexport function useRealViewport() {\n const onWindowResize = useCallback(() => {\n document.documentElement.style.setProperty('--vw', document.documentElement.clientWidth * 0.01 + 'px')\n\n document.documentElement.style.setProperty('--dvh', window.innerHeight * 0.01 + 'px')\n\n document.documentElement.style.setProperty('--svh', document.documentElement.clientHeight * 0.01 + 'px')\n\n document.documentElement.style.setProperty('--lvh', '1vh')\n }, [])\n\n useLayoutEffect(() => {\n window.addEventListener('resize', onWindowResize, false)\n onWindowResize()\n\n return () => {\n window.removeEventListener('resize', onWindowResize, false)\n }\n }, [onWindowResize])\n\n return null\n}\n"],"names":["useOnClickOutside","ref","handler","mouseEvent","useEventListener","event","el","current","contains","target","useIsClient","_useState","useState","isClient","setClient","useEffect","useDebug","useMemo","window","location","href","includes","process","env","NODE_ENV","useDocumentReadyState","document","readyState","setReadyState","addEventListener","onStateChange","removeEventListener","useFrame","callback","priority","raf","add","remove","useIsomorphicLayoutEffect","useLayoutEffect","useInterval","delay","savedCallback","useRef","id","setInterval","clearInterval","useIsTouchDevice","isTouchDevice","setIsTouchDevice","check","useCallback","hasTouchScreen","navigator","maxTouchPoints","mediaQueryList","matchMedia","media","matches","UA","userAgent","test","onResize","passive","useIsVisible","_ref","_ref$root","root","_ref$rootMargin","rootMargin","_ref$threshold","threshold","_ref$once","once","observer","inView","setInView","setRef","node","callbackFunction","entries","isIntersecting","IntersectionObserver","observe","disconnect","useMediaQuery","queryString","mediaQuery","error","console","undefined","isMatch","setIsMatch","onChange","useRect","getRect","rect","setRect","handleResize","element","ResizeObserver","resizeObserver","getBoundingClientRect","bottom","height","left","right","top","width","useSlots","types","children","_children","flat","_types","slots","map","type","_children$find","find","props","eventName","options","savedHandler","_element$current","targetElement","listener","useWindowSize","windowSize","setWindowSize","handleSize","innerWidth","innerHeight","useIntersectionObserver","_temp","deps","_ref$lazy","lazy","_ref$callback","entryRef","entry","setEntry","_useState2","setElement","intersection","_ref2","concat","get","useCopyToClipboard","setCopiedText","text","_navigator","clipboard","Promise","resolve","writeText","then","_catch","warn","e","reject","useDebounce","value","debouncedValue","setDebouncedValue","timer","setTimeout","clearTimeout","useEffectOnce","effect","effectFn","destroyFn","effectCalled","rendered","setVal","val","useFirstMountState","isFirst","useUpdateEffect","isFirstMount","useIsMounted","mountedRef","useLocalStorage","key","initialValue","item","localStorage","getItem","JSON","parse","log","storedValue","setStoredValue","valueToStore","Function","setItem","stringify","removeItem","useSessionStorage","sessionStorage","useFoucFix","debug","stylesheets","Array","from","querySelectorAll","getAttribute","forEach","removeAttribute","hrefs","MutationObserver","mutations","filter","nodeName","hasAttribute","_ref3","_ref4","setAttribute","push","reduce","head","subtree","attributeFilter","useIOSToolbarState","isVisible","setIsVisible","ua","iOS","match","webkit","iOSSafari","baseWindowHeight","handleScroll","newWindowHeight","useScript","url","script","createElement","src","async","body","appendChild","removeChild","useKeySequence","eventType","keystrokeDelay","buffer","lastKeyTime","sequence","Date","now","toLowerCase","currentTime","join","useFavicon","link","querySelector","rel","getElementsByTagName","useIdle","ms","idle","setIdle","timeoutId","cb","lastTime","handleTimeout","handleEvent","handleVisibilityChange","hidden","useDocumentTitle","title","useHover","hovering","setHovering","handleMouseEnter","handleMouseLeave","usePageLeave","onPageLeave","args","relatedTarget","toElement","obj","apply","slice","call","arguments","on","off","useOrientation","angle","orientation","setOrientation","_window$screen","handleChange","_window$screen$orient","screen","handle_orientationchange","_window$screen2","useList","defaultList","setList","set","l","removeAt","index","insertAt","updateAt","i","clear","useCookie","cookieName","Cookies","setValue","newValue","useUnmount","fn","fnRef","useThrottle","state","setState","timeout","nextValue","hasNextValue","timeoutCallback","useDebounceFn","timeoutRef","functionRef","_arguments","useResizeObserver","_ref$debounce","debounce","debounceDelay","_ref$box","box","needsUpdateRef","debouncedSetEntry","wait","debouncedFn","debounceWrapper","this","context","cancel","flush","useRealViewport","onWindowResize","documentElement","style","setProperty","clientWidth","clientHeight"],"mappings":"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