[
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Typescript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# dotenv environment variables file\n.env\n\n\n# Mac files\n.DS_Store\n\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 ui.dev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![useHooks](https://usehooks.com/meta/og.jpg)\n\n# useHooks\n\nA collection of modern, server-safe React hooks – from the [ui.dev](https://ui.dev) team.\n\nCompatible with React v18.0.0+.\n\n## Standard\n\n### Install\n\n`npm i @uidotdev/usehooks`\n\n### Hooks\n\n- [useBattery](https://usehooks.com/usebattery)\n- [useClickAway](https://usehooks.com/useclickaway)\n- [useCopyToClipboard](https://usehooks.com/usecopytoclipboard)\n- [useCounter](https://usehooks.com/usecounter)\n- [useDebounce](https://usehooks.com/usedebounce)\n- [useDefault](https://usehooks.com/usedefault)\n- [useDocumentTitle](https://usehooks.com/usedocumenttitle)\n- [useFavicon](https://usehooks.com/usefavicon)\n- [useGeolocation](https://usehooks.com/usegeolocation)\n- [useHistoryState](https://usehooks.com/usehistorystate)\n- [useHover](https://usehooks.com/usehover)\n- [useIdle](https://usehooks.com/useidle)\n- [useIntersectionObserver](https://usehooks.com/useintersectionobserver)\n- [useIsClient](https://usehooks.com/useisclient)\n- [useIsFirstRender](https://usehooks.com/useisfirstrender)\n- [useList](https://usehooks.com/uselist)\n- [useLocalStorage](https://usehooks.com/uselocalstorage)\n- [useLockBodyScroll](https://usehooks.com/uselockbodyscroll)\n- [useLongPress](https://usehooks.com/uselongpress)\n- [useMap](https://usehooks.com/usemap)\n- [useMeasure](https://usehooks.com/usemeasure)\n- [useMediaQuery](https://usehooks.com/usemediaquery)\n- [useMouse](https://usehooks.com/usemouse)\n- [useNetworkState](https://usehooks.com/usenetworkstate)\n- [useObjectState](https://usehooks.com/useobjectstate)\n- [useOrientation](https://usehooks.com/useorientation)\n- [usePreferredLanguage](https://usehooks.com/usepreferredlanguage)\n- [usePrevious](https://usehooks.com/useprevious)\n- [useQueue](https://usehooks.com/usequeue)\n- [useRenderCount](https://usehooks.com/userendercount)\n- [useRenderInfo](https://usehooks.com/userenderinfo)\n- [useScript](https://usehooks.com/usescript)\n- [useSessionStorage](https://usehooks.com/usesessionstorage)\n- [useSet](https://usehooks.com/useset)\n- [useThrottle](https://usehooks.com/usethrottle)\n- [useToggle](https://usehooks.com/usetoggle)\n- [useVisibilityChange](https://usehooks.com/usevisibilitychange)\n- [useWindowScroll](https://usehooks.com/usewindowscroll)\n- [useWindowSize](https://usehooks.com/usewindowsize)\n\n## Experimental\n\n### Install\n\n`npm i @uidotdev/usehooks@experimental react@experimental react-dom@experimental`\n\n### Hooks\n\n- [useContinuousRetry](https://usehooks.com/usecontinuousretry)\n- [useCountdown](https://usehooks.com/usecountdown)\n- [useEventListener](https://usehooks.com/useeventlistener)\n- [useFetch](https://usehooks.com/usefetch)\n- [useInterval](https://usehooks.com/useinterval)\n- [useIntervalWhen](https://usehooks.com/useintervalwhen)\n- [useKeyPress](https://usehooks.com/usekeypress)\n- [useLogger](https://usehooks.com/uselogger)\n- [usePageLeave](https://usehooks.com/usepageleave)\n- [useRandomInterval](https://usehooks.com/userandominterval)\n- [useTimeout](https://usehooks.com/usetimeout)\n"
  },
  {
    "path": "index.d.ts",
    "content": "import * as React from \"react\";\n\nexport type BatteryManager = {\n  supported: boolean;\n  loading: boolean;\n  level: number | null;\n  charging: boolean | null;\n  chargingTime: number | null;\n  dischargingTime: number | null;\n};\n\nexport type GeolocationState = {\n  loading: boolean;\n  accuracy: number | null;\n  altitude: number | null;\n  altitudeAccuracy: number | null;\n  heading: number | null;\n  latitude: number | null;\n  longitude: number | null;\n  speed: number | null;\n  timestamp: number | null;\n  error: GeolocationPositionError | null;\n};\n\nexport type HistoryState<T> = {\n  state: T;\n  set: (newPresent: T) => void;\n  undo: () => void;\n  redo: () => void;\n  clear: () => void;\n  canUndo: boolean;\n  canRedo: boolean;\n};\n\nexport type LongPressOptions = {\n  threshold?: number;\n  onStart?: (e: Event) => void;\n  onFinish?: (e: Event) => void;\n  onCancel?: (e: Event) => void;\n};\n\nexport type LongPressFns = {\n  onMouseDown: (e: React.MouseEvent) => void;\n  onMouseUp: (e: React.MouseEvent) => void;\n  onMouseLeave: (e: React.MouseEvent) => void;\n  onTouchStart: (e: React.TouchEvent) => void;\n  onTouchEnd: (e: React.TouchEvent) => void;\n};\n\nexport type MousePosition = {\n  x: number;\n  y: number;\n  elementX: number;\n  elementY: number;\n  elementPositionX: number;\n  elementPositionY: number;\n};\n\nexport type NetworkState = {\n  online: boolean;\n  downlink: number | null;\n  downlinkMax: number | null;\n  effectiveType: string | null;\n  rtt: number | null;\n  saveData: boolean | null;\n  type: string | null;\n};\n\nexport type CustomList<T> = {\n  set: (l: T[]) => void;\n  push: (element: T) => void;\n  removeAt: (index: number) => void;\n  insertAt: (index: number, element: T) => void;\n  updateAt: (index: number, element: T) => void;\n  clear: () => void;\n};\n\nexport type CustomQueue<T> = {\n  add: (element: T) => void;\n  remove: () => T | undefined;\n  clear: () => void;\n  first: T | undefined;\n  last: T | undefined;\n  size: number;\n  queue: T[];\n};\n\nexport type RenderInfo = {\n  name: string;\n  renders: number;\n  sinceLastRender: number;\n  timestamp: number;\n};\n\nexport type SpeechOptions = {\n  lang?: string;\n  voice?: {\n    lang?: string;\n    name?: string;\n  };\n  rate?: number;\n  pitch?: number;\n  volume?: number;\n};\n\nexport type SpeechState = {\n  isPlaying: boolean;\n  status: \"init\" | \"play\" | \"pause\" | \"stop\";\n  lang: string;\n  voiceInfo: {\n    lang: string;\n    name: string;\n  };\n  rate: number;\n  pitch: number;\n  volume: number;\n};\n\ndeclare module \"@uidotdev/usehooks\" {\n  export function useBattery(): BatteryManager;\n\n  export function useClickAway<T extends Element>(\n    cb: (e: Event) => void\n  ): React.MutableRefObject<T>;\n\n  export function useCopyToClipboard(): [\n    string | null,\n    (value: string) => Promise<void>\n  ];\n\n  export function useCounter(\n    startingValue?: number,\n    options?: {\n      min?: number;\n      max?: number;\n    }\n  ): [\n    number,\n    {\n      increment: () => void;\n      decrement: () => void;\n      set: (nextCount: number) => void;\n      reset: () => void;\n    }\n  ];\n\n  export function useDebounce<T>(value: T, delay: number): T;\n\n  export function useDefault<T>(\n    initialValue: T,\n    defaultValue: T\n  ): [T, React.Dispatch<React.SetStateAction<T>>];\n\n  export function useDocumentTitle(title: string): void;\n\n  export function useFavicon(url: string): void;\n\n  export function useGeolocation(options?: PositionOptions): GeolocationState;\n\n  export function useHistoryState<T>(initialPresent?: T): HistoryState<T>;\n\n  export function useHover<T extends Element>(): [\n    React.RefCallback<T>,\n    boolean\n  ];\n\n  export function useIdle(ms?: number): boolean;\n\n  export function useIntersectionObserver<T extends Element>(\n    options?: IntersectionObserverInit\n  ): [React.RefCallback<T>, IntersectionObserverEntry | null];\n\n  export function useIsClient(): boolean;\n\n  export function useIsFirstRender(): boolean;\n\n  export function useList<T>(defaultList?: T[]): [T[], CustomList<T>];\n\n  export function useLocalStorage<T>(\n    key: string,\n    initialValue?: T\n  ): [T, React.Dispatch<React.SetStateAction<T>>];\n\n  export function useLockBodyScroll(): void;\n\n  export function useLongPress(\n    callback: (e: Event) => void,\n    options?: LongPressOptions\n  ): LongPressFns;\n\n  export function useMap<T>(initialState?: T): Map<T, any>;\n\n  export function useMeasure<T extends Element>(): [\n    React.RefCallback<T>,\n    {\n      width: number | null;\n      height: number | null;\n    }\n  ];\n\n  export function useMediaQuery(query: string): boolean;\n\n  export function useMouse<T extends Element>(): [\n    MousePosition,\n    React.MutableRefObject<T>\n  ];\n\n  export function useNetworkState(): NetworkState;\n\n  export function useObjectState<T>(initialValue: T): [T, (arg: T) => void];\n\n  export function useOrientation(): {\n    angle: number;\n    type: string;\n  };\n\n  export function usePreferredLanguage(): string;\n\n  export function usePrevious<T>(newValue: T): T;\n\n  export function useQueue<T>(initialValue?: T[]): CustomQueue<T>;\n\n  export function useRenderCount(): number;\n\n  export function useRenderInfo(name?: string): RenderInfo | undefined;\n\n  export function useScript(\n    src: string,\n    options?: {\n      removeOnUnmount?: boolean;\n    }\n  ): \"unknown\" | \"loading\" | \"ready\" | \"error\";\n\n  export function useSessionStorage<T>(\n    key: string,\n    initialValue: T\n  ): [T, React.Dispatch<React.SetStateAction<T>>];\n\n  export function useSet<T>(values?: T[]): Set<T>;\n\n  export function useSpeech(text: string, options?: SpeechOptions): SpeechState;\n\n  export function useThrottle<T>(value: T, delay: number): T;\n\n  export function useToggle(\n    initialValue?: boolean\n  ): [boolean, (newValue?: boolean) => void];\n\n  export function useVisibilityChange(): boolean;\n\n  export function useWindowScroll(): [\n    {\n      x: number | null;\n      y: number | null;\n    },\n    (args: unknown) => void\n  ];\n\n  export function useWindowSize(): {\n    width: number | null;\n    height: number | null;\n  };\n}\n"
  },
  {
    "path": "index.js",
    "content": "import * as React from \"react\";\n\nfunction isShallowEqual(object1, object2) {\n  const keys1 = Object.keys(object1);\n  const keys2 = Object.keys(object2);\n\n  if (keys1.length !== keys2.length) {\n    return false;\n  }\n\n  for (let key of keys1) {\n    if (object1[key] !== object2[key]) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nfunction isTouchEvent({ nativeEvent }) {\n  return window.TouchEvent\n    ? nativeEvent instanceof TouchEvent\n    : \"touches\" in nativeEvent;\n}\n\nfunction isMouseEvent(event) {\n  return event.nativeEvent instanceof MouseEvent;\n}\n\nfunction throttle(cb, ms) {\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\nfunction isPlainObject(value) {\n  return Object.prototype.toString.call(value) === \"[object Object]\";\n}\n\nfunction dispatchStorageEvent(key, newValue) {\n  window.dispatchEvent(new StorageEvent(\"storage\", { key, newValue }));\n}\n\nexport function useBattery() {\n  const [state, setState] = React.useState({\n    supported: true,\n    loading: true,\n    level: null,\n    charging: null,\n    chargingTime: null,\n    dischargingTime: null,\n  });\n\n  React.useEffect(() => {\n    if (!navigator.getBattery) {\n      setState((s) => ({\n        ...s,\n        supported: false,\n        loading: false,\n      }));\n      return;\n    }\n\n    let battery = null;\n\n    const handleChange = () => {\n      setState({\n        supported: true,\n        loading: false,\n        level: battery.level,\n        charging: battery.charging,\n        chargingTime: battery.chargingTime,\n        dischargingTime: battery.dischargingTime,\n      });\n    };\n\n    navigator.getBattery().then((b) => {\n      battery = b;\n      handleChange();\n\n      b.addEventListener(\"levelchange\", handleChange);\n      b.addEventListener(\"chargingchange\", handleChange);\n      b.addEventListener(\"chargingtimechange\", handleChange);\n      b.addEventListener(\"dischargingtimechange\", handleChange);\n    });\n\n    return () => {\n      if (battery) {\n        battery.removeEventListener(\"levelchange\", handleChange);\n        battery.removeEventListener(\"chargingchange\", handleChange);\n        battery.removeEventListener(\"chargingtimechange\", handleChange);\n        battery.removeEventListener(\"dischargingtimechange\", handleChange);\n      }\n    };\n  }, []);\n\n  return state;\n}\n\nexport function useClickAway(cb) {\n  const ref = React.useRef(null);\n  const refCb = React.useRef(cb);\n\n  React.useLayoutEffect(() => {\n    refCb.current = cb;\n  });\n\n  React.useEffect(() => {\n    const handler = (e) => {\n      const element = ref.current;\n      if (element && !element.contains(e.target)) {\n        refCb.current(e);\n      }\n    };\n\n    document.addEventListener(\"mousedown\", handler);\n    document.addEventListener(\"touchstart\", handler);\n\n    return () => {\n      document.removeEventListener(\"mousedown\", handler);\n      document.removeEventListener(\"touchstart\", handler);\n    };\n  }, []);\n\n  return ref;\n}\n\nfunction oldSchoolCopy(text) {\n  const tempTextArea = document.createElement(\"textarea\");\n  tempTextArea.value = text;\n  document.body.appendChild(tempTextArea);\n  tempTextArea.select();\n  document.execCommand(\"copy\");\n  document.body.removeChild(tempTextArea);\n}\n\nexport function useCopyToClipboard() {\n  const [state, setState] = React.useState(null);\n\n  const copyToClipboard = React.useCallback((value) => {\n    const handleCopy = async () => {\n      try {\n        if (navigator?.clipboard?.writeText) {\n          await navigator.clipboard.writeText(value);\n          setState(value);\n        } else {\n          throw new Error(\"writeText not supported\");\n        }\n      } catch (e) {\n        oldSchoolCopy(value);\n        setState(value);\n      }\n    };\n\n    handleCopy();\n  }, []);\n\n  return [state, copyToClipboard];\n}\n\nexport function useCounter(startingValue = 0, options = {}) {\n  const { min, max } = options;\n\n  if (typeof min === \"number\" && startingValue < min) {\n    throw new Error(\n      `Your starting value of ${startingValue} is less than your min of ${min}.`\n    );\n  }\n\n  if (typeof max === \"number\" && startingValue > max) {\n    throw new Error(\n      `Your starting value of ${startingValue} is greater than your max of ${max}.`\n    );\n  }\n\n  const [count, setCount] = React.useState(startingValue);\n\n  const increment = React.useCallback(() => {\n    setCount((c) => {\n      const nextCount = c + 1;\n\n      if (typeof max === \"number\" && nextCount > max) {\n        return c;\n      }\n\n      return nextCount;\n    });\n  }, [max]);\n\n  const decrement = React.useCallback(() => {\n    setCount((c) => {\n      const nextCount = c - 1;\n\n      if (typeof min === \"number\" && nextCount < min) {\n        return c;\n      }\n\n      return nextCount;\n    });\n  }, [min]);\n\n  const set = React.useCallback(\n    (nextCount) => {\n      setCount((c) => {\n        if (typeof max === \"number\" && nextCount > max) {\n          return c;\n        }\n\n        if (typeof min === \"number\" && nextCount < min) {\n          return c;\n        }\n\n        return nextCount;\n      });\n    },\n    [max, min]\n  );\n\n  const reset = React.useCallback(() => {\n    setCount(startingValue);\n  }, [startingValue]);\n\n  return [\n    count,\n    {\n      increment,\n      decrement,\n      set,\n      reset,\n    },\n  ];\n}\n\nexport function useDebounce(value, delay) {\n  const [debouncedValue, setDebouncedValue] = React.useState(value);\n\n  React.useEffect(() => {\n    const handler = setTimeout(() => {\n      setDebouncedValue(value);\n    }, delay);\n\n    return () => {\n      clearTimeout(handler);\n    };\n  }, [value, delay]);\n\n  return debouncedValue;\n}\n\nexport function useDefault(initialValue, defaultValue) {\n  const [state, setState] = React.useState(initialValue);\n\n  if (typeof state === \"undefined\" || state === null) {\n    return [defaultValue, setState];\n  }\n\n  return [state, setState];\n}\n\nexport function useDocumentTitle(title) {\n  React.useEffect(() => {\n    document.title = title;\n  }, [title]);\n}\n\nexport function useFavicon(url) {\n  React.useEffect(() => {\n    let link = document.querySelector(`link[rel~=\"icon\"]`);\n\n    if (!link) {\n      link = document.createElement(\"link\");\n      link.type = \"image/x-icon\";\n      link.rel = \"icon\";\n      link.href = url;\n      document.head.appendChild(link);\n    } else {\n      link.href = url;\n    }\n  }, [url]);\n}\n\nexport function useGeolocation(options = {}) {\n  const [state, setState] = React.useState({\n    loading: true,\n    accuracy: null,\n    altitude: null,\n    altitudeAccuracy: null,\n    heading: null,\n    latitude: null,\n    longitude: null,\n    speed: null,\n    timestamp: null,\n    error: null,\n  });\n\n  const optionsRef = React.useRef(options);\n\n  React.useEffect(() => {\n    const onEvent = ({ coords, timestamp }) => {\n      setState({\n        loading: false,\n        timestamp,\n        latitude: coords.latitude,\n        longitude: coords.longitude,\n        altitude: coords.altitude,\n        accuracy: coords.accuracy,\n        altitudeAccuracy: coords.altitudeAccuracy,\n        heading: coords.heading,\n        speed: coords.speed,\n      });\n    };\n\n    const onEventError = (error) => {\n      setState((s) => ({\n        ...s,\n        loading: false,\n        error,\n      }));\n    };\n\n    navigator.geolocation.getCurrentPosition(\n      onEvent,\n      onEventError,\n      optionsRef.current\n    );\n\n    const watchId = navigator.geolocation.watchPosition(\n      onEvent,\n      onEventError,\n      optionsRef.current\n    );\n\n    return () => {\n      navigator.geolocation.clearWatch(watchId);\n    };\n  }, []);\n\n  return state;\n}\n\nconst initialUseHistoryStateState = {\n  past: [],\n  present: null,\n  future: [],\n};\n\nconst useHistoryStateReducer = (state, action) => {\n  const { past, present, future } = state;\n\n  if (action.type === \"UNDO\") {\n    return {\n      past: past.slice(0, past.length - 1),\n      present: past[past.length - 1],\n      future: [present, ...future],\n    };\n  } else if (action.type === \"REDO\") {\n    return {\n      past: [...past, present],\n      present: future[0],\n      future: future.slice(1),\n    };\n  } else if (action.type === \"SET\") {\n    const { newPresent } = action;\n\n    if (action.newPresent === present) {\n      return state;\n    }\n\n    return {\n      past: [...past, present],\n      present: newPresent,\n      future: [],\n    };\n  } else if (action.type === \"CLEAR\") {\n    return {\n      ...initialUseHistoryStateState,\n      present: action.initialPresent,\n    };\n  } else {\n    throw new Error(\"Unsupported action type\");\n  }\n};\n\nexport function useHistoryState(initialPresent = {}) {\n  const initialPresentRef = React.useRef(initialPresent);\n\n  const [state, dispatch] = React.useReducer(useHistoryStateReducer, {\n    ...initialUseHistoryStateState,\n    present: initialPresentRef.current,\n  });\n\n  const canUndo = state.past.length !== 0;\n  const canRedo = state.future.length !== 0;\n\n  const undo = React.useCallback(() => {\n    if (canUndo) {\n      dispatch({ type: \"UNDO\" });\n    }\n  }, [canUndo]);\n\n  const redo = React.useCallback(() => {\n    if (canRedo) {\n      dispatch({ type: \"REDO\" });\n    }\n  }, [canRedo]);\n\n  const set = React.useCallback(\n    (newPresent) => dispatch({ type: \"SET\", newPresent }),\n    []\n  );\n\n  const clear = React.useCallback(\n    () =>\n      dispatch({ type: \"CLEAR\", initialPresent: initialPresentRef.current }),\n    []\n  );\n\n  return { state: state.present, set, undo, redo, clear, canUndo, canRedo };\n}\n\nexport function useHover() {\n  const [hovering, setHovering] = React.useState(false);\n  const previousNode = React.useRef(null);\n\n  const handleMouseEnter = React.useCallback(() => {\n    setHovering(true);\n  }, []);\n\n  const handleMouseLeave = React.useCallback(() => {\n    setHovering(false);\n  }, []);\n\n  const customRef = React.useCallback(\n    (node) => {\n      if (previousNode.current?.nodeType === Node.ELEMENT_NODE) {\n        previousNode.current.removeEventListener(\n          \"mouseenter\",\n          handleMouseEnter\n        );\n        previousNode.current.removeEventListener(\n          \"mouseleave\",\n          handleMouseLeave\n        );\n      }\n\n      if (node?.nodeType === Node.ELEMENT_NODE) {\n        node.addEventListener(\"mouseenter\", handleMouseEnter);\n        node.addEventListener(\"mouseleave\", handleMouseLeave);\n      }\n\n      previousNode.current = node;\n    },\n    [handleMouseEnter, handleMouseLeave]\n  );\n\n  return [customRef, hovering];\n}\n\nexport function useIdle(ms = 1000 * 60) {\n  const [idle, setIdle] = React.useState(false);\n\n  React.useEffect(() => {\n    let timeoutId;\n\n    const handleTimeout = () => {\n      setIdle(true);\n    };\n\n    const handleEvent = throttle((e) => {\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\nexport function useIntersectionObserver(options = {}) {\n  const { threshold = 1, root = null, rootMargin = \"0px\" } = options;\n  const [entry, setEntry] = React.useState(null);\n\n  const previousObserver = React.useRef(null);\n\n  const customRef = React.useCallback(\n    (node) => {\n      if (previousObserver.current) {\n        previousObserver.current.disconnect();\n        previousObserver.current = null;\n      }\n\n      if (node?.nodeType === Node.ELEMENT_NODE) {\n        const observer = new IntersectionObserver(\n          ([entry]) => {\n            setEntry(entry);\n          },\n          { threshold, root, rootMargin }\n        );\n\n        observer.observe(node);\n        previousObserver.current = observer;\n      }\n    },\n    [threshold, root, rootMargin]\n  );\n\n  return [customRef, entry];\n}\n\nexport function useIsClient() {\n  const [isClient, setIsClient] = React.useState(false);\n\n  React.useEffect(() => {\n    setIsClient(true);\n  }, []);\n\n  return isClient;\n}\n\nexport function useIsFirstRender() {\n  const renderRef = React.useRef(true);\n\n  if (renderRef.current === true) {\n    renderRef.current = false;\n    return true;\n  }\n\n  return renderRef.current;\n}\n\nexport function useList(defaultList = []) {\n  const [list, setList] = React.useState(defaultList);\n\n  const set = React.useCallback((l) => {\n    setList(l);\n  }, []);\n\n  const push = React.useCallback((element) => {\n    setList((l) => [...l, element]);\n  }, []);\n\n  const removeAt = React.useCallback((index) => {\n    setList((l) => [...l.slice(0, index), ...l.slice(index + 1)]);\n  }, []);\n\n  const insertAt = React.useCallback((index, element) => {\n    setList((l) => [...l.slice(0, index), element, ...l.slice(index)]);\n  }, []);\n\n  const updateAt = React.useCallback((index, element) => {\n    setList((l) => l.map((e, i) => (i === index ? element : e)));\n  }, []);\n\n  const clear = React.useCallback(() => setList([]), []);\n\n  return [list, { set, push, removeAt, insertAt, updateAt, clear }];\n}\n\nconst setLocalStorageItem = (key, value) => {\n  const stringifiedValue = JSON.stringify(value);\n  window.localStorage.setItem(key, stringifiedValue);\n  dispatchStorageEvent(key, stringifiedValue);\n};\n\nconst removeLocalStorageItem = (key) => {\n  window.localStorage.removeItem(key);\n  dispatchStorageEvent(key, null);\n};\n\nconst getLocalStorageItem = (key) => {\n  return window.localStorage.getItem(key);\n};\n\nconst useLocalStorageSubscribe = (callback) => {\n  window.addEventListener(\"storage\", callback);\n  return () => window.removeEventListener(\"storage\", callback);\n};\n\nconst getLocalStorageServerSnapshot = () => {\n  throw Error(\"useLocalStorage is a client-only hook\");\n};\n\nexport function useLocalStorage(key, initialValue) {\n  const getSnapshot = () => getLocalStorageItem(key);\n\n  const store = React.useSyncExternalStore(\n    useLocalStorageSubscribe,\n    getSnapshot,\n    getLocalStorageServerSnapshot\n  );\n\n  const setState = React.useCallback(\n    (v) => {\n      try {\n        const nextState = typeof v === \"function\" ? v(JSON.parse(store)) : v;\n\n        if (nextState === undefined || nextState === null) {\n          removeLocalStorageItem(key);\n        } else {\n          setLocalStorageItem(key, nextState);\n        }\n      } catch (e) {\n        console.warn(e);\n      }\n    },\n    [key, store]\n  );\n\n  React.useEffect(() => {\n    if (\n      getLocalStorageItem(key) === null &&\n      typeof initialValue !== \"undefined\"\n    ) {\n      setLocalStorageItem(key, initialValue);\n    }\n  }, [key, initialValue]);\n\n  return [store ? JSON.parse(store) : initialValue, setState];\n}\n\nexport function useLockBodyScroll() {\n  React.useLayoutEffect(() => {\n    const originalStyle = window.getComputedStyle(document.body).overflow;\n    document.body.style.overflow = \"hidden\";\n    return () => {\n      document.body.style.overflow = originalStyle;\n    };\n  }, []);\n}\n\nexport function useLongPress(callback, options = {}) {\n  const { threshold = 400, onStart, onFinish, onCancel } = options;\n  const isLongPressActive = React.useRef(false);\n  const isPressed = React.useRef(false);\n  const timerId = React.useRef();\n\n  return React.useMemo(() => {\n    if (typeof callback !== \"function\") {\n      return {};\n    }\n\n    const start = (event) => {\n      if (!isMouseEvent(event) && !isTouchEvent(event)) return;\n\n      if (onStart) {\n        onStart(event);\n      }\n\n      isPressed.current = true;\n      timerId.current = setTimeout(() => {\n        callback(event);\n        isLongPressActive.current = true;\n      }, threshold);\n    };\n\n    const cancel = (event) => {\n      if (!isMouseEvent(event) && !isTouchEvent(event)) return;\n\n      if (isLongPressActive.current) {\n        if (onFinish) {\n          onFinish(event);\n        }\n      } else if (isPressed.current) {\n        if (onCancel) {\n          onCancel(event);\n        }\n      }\n\n      isLongPressActive.current = false;\n      isPressed.current = false;\n\n      if (timerId.current) {\n        window.clearTimeout(timerId.current);\n      }\n    };\n\n    const mouseHandlers = {\n      onMouseDown: start,\n      onMouseUp: cancel,\n      onMouseLeave: cancel,\n    };\n\n    const touchHandlers = {\n      onTouchStart: start,\n      onTouchEnd: cancel,\n    };\n\n    return {\n      ...mouseHandlers,\n      ...touchHandlers,\n    };\n  }, [callback, threshold, onCancel, onFinish, onStart]);\n}\n\nexport function useMap(initialState) {\n  const mapRef = React.useRef(new Map(initialState));\n  const [, reRender] = React.useReducer((x) => x + 1, 0);\n\n  mapRef.current.set = (...args) => {\n    Map.prototype.set.apply(mapRef.current, args);\n    reRender();\n    return mapRef.current;\n  };\n\n  mapRef.current.clear = (...args) => {\n    Map.prototype.clear.apply(mapRef.current, args);\n    reRender();\n  };\n\n  mapRef.current.delete = (...args) => {\n    const res = Map.prototype.delete.apply(mapRef.current, args);\n    reRender();\n\n    return res;\n  };\n\n  return mapRef.current;\n}\n\nexport function useMeasure() {\n  const [dimensions, setDimensions] = React.useState({\n    width: null,\n    height: null,\n  });\n\n  const previousObserver = React.useRef(null);\n\n  const customRef = React.useCallback((node) => {\n    if (previousObserver.current) {\n      previousObserver.current.disconnect();\n      previousObserver.current = null;\n    }\n\n    if (node?.nodeType === Node.ELEMENT_NODE) {\n      const observer = new ResizeObserver(([entry]) => {\n        if (entry && entry.borderBoxSize) {\n          const { inlineSize: width, blockSize: height } =\n            entry.borderBoxSize[0];\n\n          setDimensions({ width, height });\n        }\n      });\n\n      observer.observe(node);\n      previousObserver.current = observer;\n    }\n  }, []);\n\n  return [customRef, dimensions];\n}\n\nexport function useMediaQuery(query) {\n  const subscribe = React.useCallback(\n    (callback) => {\n      const matchMedia = window.matchMedia(query);\n\n      matchMedia.addEventListener(\"change\", callback);\n      return () => {\n        matchMedia.removeEventListener(\"change\", callback);\n      };\n    },\n    [query]\n  );\n\n  const getSnapshot = () => {\n    return window.matchMedia(query).matches;\n  };\n\n  const getServerSnapshot = () => {\n    throw Error(\"useMediaQuery is a client-only hook\");\n  };\n\n  return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\nexport function useMouse() {\n  const [state, setState] = React.useState({\n    x: 0,\n    y: 0,\n    elementX: 0,\n    elementY: 0,\n    elementPositionX: 0,\n    elementPositionY: 0,\n  });\n\n  const ref = React.useRef(null);\n\n  React.useLayoutEffect(() => {\n    const handleMouseMove = (event) => {\n      let newState = {\n        x: event.pageX,\n        y: event.pageY,\n      };\n\n      if (ref.current?.nodeType === Node.ELEMENT_NODE) {\n        const { left, top } = ref.current.getBoundingClientRect();\n        const elementPositionX = left + window.scrollX;\n        const elementPositionY = top + window.scrollY;\n        const elementX = event.pageX - elementPositionX;\n        const elementY = event.pageY - elementPositionY;\n\n        newState.elementX = elementX;\n        newState.elementY = elementY;\n        newState.elementPositionX = elementPositionX;\n        newState.elementPositionY = elementPositionY;\n      }\n\n      setState((s) => {\n        return {\n          ...s,\n          ...newState,\n        };\n      });\n    };\n\n    document.addEventListener(\"mousemove\", handleMouseMove);\n\n    return () => {\n      document.removeEventListener(\"mousemove\", handleMouseMove);\n    };\n  }, []);\n\n  return [state, ref];\n}\n\nconst getConnection = () => {\n  return (\n    navigator?.connection ||\n    navigator?.mozConnection ||\n    navigator?.webkitConnection\n  );\n};\n\nconst useNetworkStateSubscribe = (callback) => {\n  window.addEventListener(\"online\", callback, { passive: true });\n  window.addEventListener(\"offline\", callback, { passive: true });\n\n  const connection = getConnection();\n\n  if (connection) {\n    connection.addEventListener(\"change\", callback, { passive: true });\n  }\n\n  return () => {\n    window.removeEventListener(\"online\", callback);\n    window.removeEventListener(\"offline\", callback);\n\n    if (connection) {\n      connection.removeEventListener(\"change\", callback);\n    }\n  };\n};\n\nconst getNetworkStateServerSnapshot = () => {\n  throw Error(\"useNetworkState is a client-only hook\");\n};\n\nexport function useNetworkState() {\n  const cache = React.useRef({});\n\n  const getSnapshot = () => {\n    const online = navigator.onLine;\n    const connection = getConnection();\n\n    const nextState = {\n      online,\n      downlink: connection?.downlink,\n      downlinkMax: connection?.downlinkMax,\n      effectiveType: connection?.effectiveType,\n      rtt: connection?.rtt,\n      saveData: connection?.saveData,\n      type: connection?.type,\n    };\n\n    if (isShallowEqual(cache.current, nextState)) {\n      return cache.current;\n    } else {\n      cache.current = nextState;\n      return nextState;\n    }\n  };\n\n  return React.useSyncExternalStore(\n    useNetworkStateSubscribe,\n    getSnapshot,\n    getNetworkStateServerSnapshot\n  );\n}\n\nexport function useObjectState(initialValue) {\n  const [state, setState] = React.useState(initialValue);\n\n  const handleUpdate = React.useCallback((arg) => {\n    if (typeof arg === \"function\") {\n      setState((s) => {\n        const newState = arg(s);\n\n        if (isPlainObject(newState)) {\n          return {\n            ...s,\n            ...newState,\n          };\n        }\n      });\n    }\n\n    if (isPlainObject(arg)) {\n      setState((s) => ({\n        ...s,\n        ...arg,\n      }));\n    }\n  }, []);\n\n  return [state, handleUpdate];\n}\n\nexport function useOrientation() {\n  const [orientation, setOrientation] = React.useState({\n    angle: 0,\n    type: \"landscape-primary\",\n  });\n\n  React.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(\n          \"orientationchange\",\n          handle_orientationchange\n        );\n      }\n    };\n  }, []);\n\n  return orientation;\n}\n\nconst usePreferredLanguageSubscribe = (cb) => {\n  window.addEventListener(\"languagechange\", cb);\n  return () => window.removeEventListener(\"languagechange\", cb);\n};\n\nconst getPreferredLanguageSnapshot = () => {\n  return navigator.language;\n};\n\nconst getPreferredLanguageServerSnapshot = () => {\n  throw Error(\"usePreferredLanguage is a client-only hook\");\n};\n\nexport function usePreferredLanguage() {\n  return React.useSyncExternalStore(\n    usePreferredLanguageSubscribe,\n    getPreferredLanguageSnapshot,\n    getPreferredLanguageServerSnapshot\n  );\n}\n\nexport function usePrevious(value) {\n  const [current, setCurrent] = React.useState(value);\n  const [previous, setPrevious] = React.useState(null);\n\n  if (value !== current) {\n    setPrevious(current);\n    setCurrent(value);\n  }\n\n  return previous;\n}\n\nexport function useQueue(initialValue = []) {\n  const [queue, setQueue] = React.useState(initialValue);\n\n  const add = React.useCallback((element) => {\n    setQueue((q) => [...q, element]);\n  }, []);\n\n  const remove = React.useCallback(() => {\n    let removedElement;\n\n    setQueue(([first, ...q]) => {\n      removedElement = first;\n      return q;\n    });\n\n    return removedElement;\n  }, []);\n\n  const clear = React.useCallback(() => {\n    setQueue([]);\n  }, []);\n\n  return {\n    add,\n    remove,\n    clear,\n    first: queue[0],\n    last: queue[queue.length - 1],\n    size: queue.length,\n    queue,\n  };\n}\n\nexport function useRenderCount() {\n  const count = React.useRef(0);\n\n  count.current++;\n\n  return count.current;\n}\n\nexport function useRenderInfo(name = \"Unknown\") {\n  const count = React.useRef(0);\n  const lastRender = React.useRef();\n  const now = Date.now();\n\n  count.current++;\n\n  React.useEffect(() => {\n    lastRender.current = Date.now();\n  });\n\n  const sinceLastRender = lastRender.current ? now - lastRender.current : 0;\n\n  if (process.env.NODE_ENV !== \"production\") {\n    const info = {\n      name,\n      renders: count.current,\n      sinceLastRender,\n      timestamp: now,\n    };\n\n    console.log(info);\n\n    return info;\n  }\n}\n\nexport function useScript(src, options = {}) {\n  const [status, setStatus] = React.useState(\"loading\");\n  const optionsRef = React.useRef(options);\n\n  React.useEffect(() => {\n    let script = document.querySelector(`script[src=\"${src}\"]`);\n\n    const domStatus = script?.getAttribute(\"data-status\");\n    if (domStatus) {\n      setStatus(domStatus);\n      return;\n    }\n\n    if (script === null) {\n      script = document.createElement(\"script\");\n      script.src = src;\n      script.async = true;\n      script.setAttribute(\"data-status\", \"loading\");\n      document.body.appendChild(script);\n\n      const handleScriptLoad = () => {\n        script.setAttribute(\"data-status\", \"ready\");\n        setStatus(\"ready\");\n        removeEventListeners();\n      };\n\n      const handleScriptError = () => {\n        script.setAttribute(\"data-status\", \"error\");\n        setStatus(\"error\");\n        removeEventListeners();\n      };\n\n      const removeEventListeners = () => {\n        script.removeEventListener(\"load\", handleScriptLoad);\n        script.removeEventListener(\"error\", handleScriptError);\n      };\n\n      script.addEventListener(\"load\", handleScriptLoad);\n      script.addEventListener(\"error\", handleScriptError);\n\n      const removeOnUnmount = optionsRef.current.removeOnUnmount;\n\n      return () => {\n        if (removeOnUnmount === true) {\n          script.remove();\n          removeEventListeners();\n        }\n      };\n    } else {\n      setStatus(\"unknown\");\n    }\n  }, [src]);\n\n  return status;\n}\n\nconst setSessionStorageItem = (key, value) => {\n  const stringifiedValue = JSON.stringify(value);\n  window.sessionStorage.setItem(key, stringifiedValue);\n  dispatchStorageEvent(key, stringifiedValue);\n};\n\nconst removeSessionStorageItem = (key) => {\n  window.sessionStorage.removeItem(key);\n  dispatchStorageEvent(key, null);\n};\n\nconst getSessionStorageItem = (key) => {\n  return window.sessionStorage.getItem(key);\n};\n\nconst useSessionStorageSubscribe = (callback) => {\n  window.addEventListener(\"storage\", callback);\n  return () => window.removeEventListener(\"storage\", callback);\n};\n\nconst getSessionStorageServerSnapshot = () => {\n  throw Error(\"useSessionStorage is a client-only hook\");\n};\n\nexport function useSessionStorage(key, initialValue) {\n  const getSnapshot = () => getSessionStorageItem(key);\n\n  const store = React.useSyncExternalStore(\n    useSessionStorageSubscribe,\n    getSnapshot,\n    getSessionStorageServerSnapshot\n  );\n\n  const setState = React.useCallback(\n    (v) => {\n      try {\n        const nextState = typeof v === \"function\" ? v(JSON.parse(store)) : v;\n\n        if (nextState === undefined || nextState === null) {\n          removeSessionStorageItem(key);\n        } else {\n          setSessionStorageItem(key, nextState);\n        }\n      } catch (e) {\n        console.warn(e);\n      }\n    },\n    [key, store]\n  );\n\n  React.useEffect(() => {\n    if (\n      getSessionStorageItem(key) === null &&\n      typeof initialValue !== \"undefined\"\n    ) {\n      setSessionStorageItem(key, initialValue);\n    }\n  }, [key, initialValue]);\n\n  return [store ? JSON.parse(store) : initialValue, setState];\n}\n\nexport function useSet(values) {\n  const setRef = React.useRef(new Set(values));\n  const [, reRender] = React.useReducer((x) => x + 1, 0);\n\n  setRef.current.add = (...args) => {\n    const res = Set.prototype.add.apply(setRef.current, args);\n    reRender();\n\n    return res;\n  };\n\n  setRef.current.clear = (...args) => {\n    Set.prototype.clear.apply(setRef.current, args);\n    reRender();\n  };\n\n  setRef.current.delete = (...args) => {\n    const res = Set.prototype.delete.apply(setRef.current, args);\n    reRender();\n\n    return res;\n  };\n\n  return setRef.current;\n}\n\nexport function useThrottle(value, interval = 500) {\n  const [throttledValue, setThrottledValue] = React.useState(value);\n  const lastUpdated = React.useRef(null);\n\n  React.useEffect(() => {\n    const now = Date.now();\n\n    if (lastUpdated.current && now >= lastUpdated.current + interval) {\n      lastUpdated.current = now;\n      setThrottledValue(value);\n    } else {\n      const id = window.setTimeout(() => {\n        lastUpdated.current = now;\n        setThrottledValue(value);\n      }, interval);\n\n      return () => window.clearTimeout(id);\n    }\n  }, [value, interval]);\n\n  return throttledValue;\n}\n\nexport function useToggle(initialValue) {\n  const [on, setOn] = React.useState(() => {\n    if (typeof initialValue === \"boolean\") {\n      return initialValue;\n    }\n\n    return Boolean(initialValue);\n  });\n\n  const handleToggle = React.useCallback((value) => {\n    if (typeof value === \"boolean\") {\n      return setOn(value);\n    }\n\n    return setOn((v) => !v);\n  }, []);\n\n  return [on, handleToggle];\n}\n\nconst useVisibilityChangeSubscribe = (callback) => {\n  document.addEventListener(\"visibilitychange\", callback);\n\n  return () => {\n    document.removeEventListener(\"visibilitychange\", callback);\n  };\n};\n\nconst getVisibilityChangeSnapshot = () => {\n  return document.visibilityState;\n};\n\nconst getVisibilityChangeServerSnapshot = () => {\n  throw Error(\"useVisibilityChange is a client-only hook\");\n};\n\nexport function useVisibilityChange() {\n  const visibilityState = React.useSyncExternalStore(\n    useVisibilityChangeSubscribe,\n    getVisibilityChangeSnapshot,\n    getVisibilityChangeServerSnapshot\n  );\n\n  return visibilityState === \"visible\";\n}\n\nexport function useWindowScroll() {\n  const [state, setState] = React.useState({\n    x: null,\n    y: null,\n  });\n\n  const scrollTo = React.useCallback((...args) => {\n    if (typeof args[0] === \"object\") {\n      window.scrollTo(args[0]);\n    } else if (typeof args[0] === \"number\" && typeof args[1] === \"number\") {\n      window.scrollTo(args[0], args[1]);\n    } else {\n      throw new Error(\n        `Invalid arguments passed to scrollTo. See here for more info. https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo`\n      );\n    }\n  }, []);\n\n  React.useLayoutEffect(() => {\n    const handleScroll = () => {\n      setState({ x: window.scrollX, y: window.scrollY });\n    };\n\n    handleScroll();\n    window.addEventListener(\"scroll\", handleScroll);\n\n    return () => {\n      window.removeEventListener(\"scroll\", handleScroll);\n    };\n  }, []);\n\n  return [state, scrollTo];\n}\n\nexport function useWindowSize() {\n  const [size, setSize] = React.useState({\n    width: null,\n    height: null,\n  });\n\n  React.useLayoutEffect(() => {\n    const handleResize = () => {\n      setSize({\n        width: window.innerWidth,\n        height: window.innerHeight,\n      });\n    };\n\n    handleResize();\n    window.addEventListener(\"resize\", handleResize);\n\n    return () => {\n      window.removeEventListener(\"resize\", handleResize);\n    };\n  }, []);\n\n  return size;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@uidotdev/usehooks\",\n  \"version\": \"2.4.1\",\n  \"description\": \"A collection of modern, server-safe React hooks – from the ui.dev team\",\n  \"type\": \"module\",\n  \"repository\": \"uidotdev/usehooks\",\n  \"devDependencies\": {\n    \"@types/react\": \"^18.2.20\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"typescript\": \"^5.1.6\"\n  },\n  \"exports\": {\n    \"default\": \"./index.js\"\n  },\n  \"engines\": {\n    \"node\": \">=16\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\"\n  ],\n  \"types\": \"index.d.ts\",\n  \"peerDependencies\": {\n    \"react\": \">=18.0.0\",\n    \"react-dom\": \">=18.0.0\"\n  },\n  \"author\": \"Tyler McGinnis, Ben Adam\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"module\": \"ESNext\",\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"noImplicitAny\": true,\n    \"allowJs\": true,\n    \"outDir\": \"./irrelevant/unused\"\n  }\n}\n"
  },
  {
    "path": "usehooks.com/.astro/types.d.ts",
    "content": "declare module 'astro:content' {\n\tinterface Render {\n\t\t'.mdx': Promise<{\n\t\t\tContent: import('astro').MarkdownInstance<{}>['Content'];\n\t\t\theadings: import('astro').MarkdownHeading[];\n\t\t\tremarkPluginFrontmatter: Record<string, any>;\n\t\t}>;\n\t}\n}\n\ndeclare module 'astro:content' {\n\tinterface Render {\n\t\t'.md': Promise<{\n\t\t\tContent: import('astro').MarkdownInstance<{}>['Content'];\n\t\t\theadings: import('astro').MarkdownHeading[];\n\t\t\tremarkPluginFrontmatter: Record<string, any>;\n\t\t}>;\n\t}\n}\n\ndeclare module 'astro:content' {\n\texport { z } from 'astro/zod';\n\texport type CollectionEntry<C extends keyof AnyEntryMap> = AnyEntryMap[C][keyof AnyEntryMap[C]];\n\n\t// TODO: Remove this when having this fallback is no longer relevant. 2.3? 3.0? - erika, 2023-04-04\n\t/**\n\t * @deprecated\n\t * `astro:content` no longer provide `image()`.\n\t *\n\t * Please use it through `schema`, like such:\n\t * ```ts\n\t * import { defineCollection, z } from \"astro:content\";\n\t *\n\t * defineCollection({\n\t *   schema: ({ image }) =>\n\t *     z.object({\n\t *       image: image(),\n\t *     }),\n\t * });\n\t * ```\n\t */\n\texport const image: never;\n\n\t// This needs to be in sync with ImageMetadata\n\texport type ImageFunction = () => import('astro/zod').ZodObject<{\n\t\tsrc: import('astro/zod').ZodString;\n\t\twidth: import('astro/zod').ZodNumber;\n\t\theight: import('astro/zod').ZodNumber;\n\t\tformat: import('astro/zod').ZodUnion<\n\t\t\t[\n\t\t\t\timport('astro/zod').ZodLiteral<'png'>,\n\t\t\t\timport('astro/zod').ZodLiteral<'jpg'>,\n\t\t\t\timport('astro/zod').ZodLiteral<'jpeg'>,\n\t\t\t\timport('astro/zod').ZodLiteral<'tiff'>,\n\t\t\t\timport('astro/zod').ZodLiteral<'webp'>,\n\t\t\t\timport('astro/zod').ZodLiteral<'gif'>,\n\t\t\t\timport('astro/zod').ZodLiteral<'svg'>\n\t\t\t]\n\t\t>;\n\t}>;\n\n\ttype BaseSchemaWithoutEffects =\n\t\t| import('astro/zod').AnyZodObject\n\t\t| import('astro/zod').ZodUnion<import('astro/zod').AnyZodObject[]>\n\t\t| import('astro/zod').ZodDiscriminatedUnion<string, import('astro/zod').AnyZodObject[]>\n\t\t| import('astro/zod').ZodIntersection<\n\t\t\t\timport('astro/zod').AnyZodObject,\n\t\t\t\timport('astro/zod').AnyZodObject\n\t\t  >;\n\n\ttype BaseSchema =\n\t\t| BaseSchemaWithoutEffects\n\t\t| import('astro/zod').ZodEffects<BaseSchemaWithoutEffects>;\n\n\texport type SchemaContext = { image: ImageFunction };\n\n\ttype DataCollectionConfig<S extends BaseSchema> = {\n\t\ttype: 'data';\n\t\tschema?: S | ((context: SchemaContext) => S);\n\t};\n\n\ttype ContentCollectionConfig<S extends BaseSchema> = {\n\t\ttype?: 'content';\n\t\tschema?: S | ((context: SchemaContext) => S);\n\t};\n\n\ttype CollectionConfig<S> = ContentCollectionConfig<S> | DataCollectionConfig<S>;\n\n\texport function defineCollection<S extends BaseSchema>(\n\t\tinput: CollectionConfig<S>\n\t): CollectionConfig<S>;\n\n\ttype AllValuesOf<T> = T extends any ? T[keyof T] : never;\n\ttype ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<\n\t\tContentEntryMap[C]\n\t>['slug'];\n\n\texport function getEntryBySlug<\n\t\tC extends keyof ContentEntryMap,\n\t\tE extends ValidContentEntrySlug<C> | (string & {})\n\t>(\n\t\tcollection: C,\n\t\t// Note that this has to accept a regular string too, for SSR\n\t\tentrySlug: E\n\t): E extends ValidContentEntrySlug<C>\n\t\t? Promise<CollectionEntry<C>>\n\t\t: Promise<CollectionEntry<C> | undefined>;\n\n\texport function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(\n\t\tcollection: C,\n\t\tentryId: E\n\t): Promise<CollectionEntry<C>>;\n\n\texport function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(\n\t\tcollection: C,\n\t\tfilter?: (entry: CollectionEntry<C>) => entry is E\n\t): Promise<E[]>;\n\texport function getCollection<C extends keyof AnyEntryMap>(\n\t\tcollection: C,\n\t\tfilter?: (entry: CollectionEntry<C>) => unknown\n\t): Promise<CollectionEntry<C>[]>;\n\n\texport function getEntry<\n\t\tC extends keyof ContentEntryMap,\n\t\tE extends ValidContentEntrySlug<C> | (string & {})\n\t>(entry: {\n\t\tcollection: C;\n\t\tslug: E;\n\t}): E extends ValidContentEntrySlug<C>\n\t\t? Promise<CollectionEntry<C>>\n\t\t: Promise<CollectionEntry<C> | undefined>;\n\texport function getEntry<\n\t\tC extends keyof DataEntryMap,\n\t\tE extends keyof DataEntryMap[C] | (string & {})\n\t>(entry: {\n\t\tcollection: C;\n\t\tid: E;\n\t}): E extends keyof DataEntryMap[C]\n\t\t? Promise<DataEntryMap[C][E]>\n\t\t: Promise<CollectionEntry<C> | undefined>;\n\texport function getEntry<\n\t\tC extends keyof ContentEntryMap,\n\t\tE extends ValidContentEntrySlug<C> | (string & {})\n\t>(\n\t\tcollection: C,\n\t\tslug: E\n\t): E extends ValidContentEntrySlug<C>\n\t\t? Promise<CollectionEntry<C>>\n\t\t: Promise<CollectionEntry<C> | undefined>;\n\texport function getEntry<\n\t\tC extends keyof DataEntryMap,\n\t\tE extends keyof DataEntryMap[C] | (string & {})\n\t>(\n\t\tcollection: C,\n\t\tid: E\n\t): E extends keyof DataEntryMap[C]\n\t\t? Promise<DataEntryMap[C][E]>\n\t\t: Promise<CollectionEntry<C> | undefined>;\n\n\t/** Resolve an array of entry references from the same collection */\n\texport function getEntries<C extends keyof ContentEntryMap>(\n\t\tentries: {\n\t\t\tcollection: C;\n\t\t\tslug: ValidContentEntrySlug<C>;\n\t\t}[]\n\t): Promise<CollectionEntry<C>[]>;\n\texport function getEntries<C extends keyof DataEntryMap>(\n\t\tentries: {\n\t\t\tcollection: C;\n\t\t\tid: keyof DataEntryMap[C];\n\t\t}[]\n\t): Promise<CollectionEntry<C>[]>;\n\n\texport function reference<C extends keyof AnyEntryMap>(\n\t\tcollection: C\n\t): import('astro/zod').ZodEffects<\n\t\timport('astro/zod').ZodString,\n\t\tC extends keyof ContentEntryMap\n\t\t\t? {\n\t\t\t\t\tcollection: C;\n\t\t\t\t\tslug: ValidContentEntrySlug<C>;\n\t\t\t  }\n\t\t\t: {\n\t\t\t\t\tcollection: C;\n\t\t\t\t\tid: keyof DataEntryMap[C];\n\t\t\t  }\n\t>;\n\t// Allow generic `string` to avoid excessive type errors in the config\n\t// if `dev` is not running to update as you edit.\n\t// Invalid collection names will be caught at build time.\n\texport function reference<C extends string>(\n\t\tcollection: C\n\t): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;\n\n\ttype ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;\n\ttype InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<\n\t\tReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>\n\t>;\n\n\ttype ContentEntryMap = {\n\t\t\"hooks\": {\n\"useBattery.mdx\": {\n\tid: \"useBattery.mdx\";\n  slug: \"usebattery\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useClickAway.mdx\": {\n\tid: \"useClickAway.mdx\";\n  slug: \"useclickaway\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useContinuousRetry.mdx\": {\n\tid: \"useContinuousRetry.mdx\";\n  slug: \"usecontinuousretry\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useCopyToClipboard.mdx\": {\n\tid: \"useCopyToClipboard.mdx\";\n  slug: \"usecopytoclipboard\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useCountdown.mdx\": {\n\tid: \"useCountdown.mdx\";\n  slug: \"usecountdown\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useCounter.mdx\": {\n\tid: \"useCounter.mdx\";\n  slug: \"usecounter\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useDebounce.mdx\": {\n\tid: \"useDebounce.mdx\";\n  slug: \"usedebounce\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useDefault.mdx\": {\n\tid: \"useDefault.mdx\";\n  slug: \"usedefault\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useDocumentTitle.mdx\": {\n\tid: \"useDocumentTitle.mdx\";\n  slug: \"usedocumenttitle\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useEventListener.mdx\": {\n\tid: \"useEventListener.mdx\";\n  slug: \"useeventlistener\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useFavicon.mdx\": {\n\tid: \"useFavicon.mdx\";\n  slug: \"usefavicon\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useFetch.mdx\": {\n\tid: \"useFetch.mdx\";\n  slug: \"usefetch\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useGeolocation.mdx\": {\n\tid: \"useGeolocation.mdx\";\n  slug: \"usegeolocation\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useHistoryState.mdx\": {\n\tid: \"useHistoryState.mdx\";\n  slug: \"usehistorystate\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useHover.mdx\": {\n\tid: \"useHover.mdx\";\n  slug: \"usehover\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useIdle.mdx\": {\n\tid: \"useIdle.mdx\";\n  slug: \"useidle\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useIntersectionObserver.mdx\": {\n\tid: \"useIntersectionObserver.mdx\";\n  slug: \"useintersectionobserver\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useInterval.mdx\": {\n\tid: \"useInterval.mdx\";\n  slug: \"useinterval\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useIntervalWhen.mdx\": {\n\tid: \"useIntervalWhen.mdx\";\n  slug: \"useintervalwhen\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useIsClient.mdx\": {\n\tid: \"useIsClient.mdx\";\n  slug: \"useisclient\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useIsFirstRender.mdx\": {\n\tid: \"useIsFirstRender.mdx\";\n  slug: \"useisfirstrender\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useKeyPress.mdx\": {\n\tid: \"useKeyPress.mdx\";\n  slug: \"usekeypress\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useList.mdx\": {\n\tid: \"useList.mdx\";\n  slug: \"uselist\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useLocalStorage.mdx\": {\n\tid: \"useLocalStorage.mdx\";\n  slug: \"uselocalstorage\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useLockBodyScroll.mdx\": {\n\tid: \"useLockBodyScroll.mdx\";\n  slug: \"uselockbodyscroll\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useLogger.mdx\": {\n\tid: \"useLogger.mdx\";\n  slug: \"uselogger\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useLongPress.mdx\": {\n\tid: \"useLongPress.mdx\";\n  slug: \"uselongpress\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useMap.mdx\": {\n\tid: \"useMap.mdx\";\n  slug: \"usemap\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useMeasure.mdx\": {\n\tid: \"useMeasure.mdx\";\n  slug: \"usemeasure\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useMediaQuery.mdx\": {\n\tid: \"useMediaQuery.mdx\";\n  slug: \"usemediaquery\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useMouse.mdx\": {\n\tid: \"useMouse.mdx\";\n  slug: \"usemouse\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useNetworkState.mdx\": {\n\tid: \"useNetworkState.mdx\";\n  slug: \"usenetworkstate\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useObjectState.mdx\": {\n\tid: \"useObjectState.mdx\";\n  slug: \"useobjectstate\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useOrientation.mdx\": {\n\tid: \"useOrientation.mdx\";\n  slug: \"useorientation\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"usePageLeave.mdx\": {\n\tid: \"usePageLeave.mdx\";\n  slug: \"usepageleave\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"usePreferredLanguage.mdx\": {\n\tid: \"usePreferredLanguage.mdx\";\n  slug: \"usepreferredlanguage\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"usePrevious.mdx\": {\n\tid: \"usePrevious.mdx\";\n  slug: \"useprevious\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useQueue.mdx\": {\n\tid: \"useQueue.mdx\";\n  slug: \"usequeue\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useRandomInterval.mdx\": {\n\tid: \"useRandomInterval.mdx\";\n  slug: \"userandominterval\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useRenderCount.mdx\": {\n\tid: \"useRenderCount.mdx\";\n  slug: \"userendercount\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useRenderInfo.mdx\": {\n\tid: \"useRenderInfo.mdx\";\n  slug: \"userenderinfo\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useScript.mdx\": {\n\tid: \"useScript.mdx\";\n  slug: \"usescript\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useSessionStorage.mdx\": {\n\tid: \"useSessionStorage.mdx\";\n  slug: \"usesessionstorage\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useSet.mdx\": {\n\tid: \"useSet.mdx\";\n  slug: \"useset\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useThrottle.mdx\": {\n\tid: \"useThrottle.mdx\";\n  slug: \"usethrottle\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useTimeout.mdx\": {\n\tid: \"useTimeout.mdx\";\n  slug: \"usetimeout\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useToggle.mdx\": {\n\tid: \"useToggle.mdx\";\n  slug: \"usetoggle\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useVisibilityChange.mdx\": {\n\tid: \"useVisibilityChange.mdx\";\n  slug: \"usevisibilitychange\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useWindowScroll.mdx\": {\n\tid: \"useWindowScroll.mdx\";\n  slug: \"usewindowscroll\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n\"useWindowSize.mdx\": {\n\tid: \"useWindowSize.mdx\";\n  slug: \"usewindowsize\";\n  body: string;\n  collection: \"hooks\";\n  data: InferEntrySchema<\"hooks\">\n} & { render(): Render[\".mdx\"] };\n};\n\n\t};\n\n\ttype DataEntryMap = {\n\t\t\n\t};\n\n\ttype AnyEntryMap = ContentEntryMap & DataEntryMap;\n\n\ttype ContentConfig = typeof import(\"../src/content/config\");\n}\n"
  },
  {
    "path": "usehooks.com/.eslintrc.json",
    "content": "{\n  \"extends\": \"next/core-web-vitals\"\n}\n"
  },
  {
    "path": "usehooks.com/.gitignore",
    "content": "node_modules\n/node_modules\n.DS_Store\n.env\n.env.*\n.next\ndist/*\n/dist\npublic/meta/*\n!public/meta/og.jpg"
  },
  {
    "path": "usehooks.com/.prettierrc",
    "content": "{}"
  },
  {
    "path": "usehooks.com/README.md",
    "content": "# usehooks.com\n\n## 🚀 Project Structure\n\nInside this project, you'll see the following folders and files:\n\n```\n/\n├── public/\n│   └── favicon.png\n│   └── img\n├── src/\n│   ├── components/\n│   │   └── Button.astro\n│   ├── layouts/\n│   │   └── Layout.astro\n│   ├── pages/\n│   │   └── index.astro\n│   ├── sections/\n│   │   └── HomeHero.astro\n└── package.json\n```\n\nAstro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.\n\nThere's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.\n\nAny static assets, like images, can be placed in the `public/` directory.\n\n## 🧞 Commands\n\nAll commands are run from the root of the project, from a terminal:\n\n| Command                | Action                                           |\n| :--------------------- | :----------------------------------------------- |\n| `npm install`          | Installs dependencies                            |\n| `npm run dev`          | Starts local dev server at `localhost:3000`      |\n| `npm run build`        | Build your production site to `./dist/`          |\n| `npm run preview`      | Preview your build locally, before deploying     |\n| `npm run astro ...`    | Run CLI commands like `astro add`, `astro check` |\n| `npm run astro --help` | Get help using the Astro CLI                     |\n\nCheck out [Astro documentation](https://docs.astro.build)."
  },
  {
    "path": "usehooks.com/astro.config.mjs",
    "content": "import { defineConfig } from \"astro/config\";\nimport react from \"@astrojs/react\";\nimport customTheme from \"./theme.json\";\nimport tailwind from \"@astrojs/tailwind\";\n\n// import vercel from \"@astrojs/vercel/edge\";\n\nimport mdx from \"@astrojs/mdx\";\n\n// https://astro.build/config\nimport sitemap from \"@astrojs/sitemap\";\n\n// https://astro.build/config\nexport default defineConfig({\n  site: \"https://usehooks.com\",\n  trailingSlash: \"never\",\n  integrations: [react(), tailwind(), mdx(), sitemap()],\n  output: \"static\",\n  // adapter: vercel(),\n  markdown: {\n    shikiConfig: {\n      // Choose from Shiki's built-in themes (or add your own)\n      // https://github.com/shikijs/shiki/blob/main/docs/themes.md\n      theme: customTheme,\n      // Add custom languages\n      // Note: Shiki has countless langs built-in, including .astro!\n      // https://github.com/shikijs/shiki/blob/main/docs/languages.md\n      langs: [],\n      // Enable word wrap to prevent horizontal scrolling\n      wrap: false\n    }\n  }\n});"
  },
  {
    "path": "usehooks.com/generate-og-images.mjs",
    "content": "import { readdir, readFile, writeFile } from \"fs/promises\";\nimport { join, extname } from \"path\";\nimport matter from \"gray-matter\";\nimport { Resvg } from \"@resvg/resvg-js\";\nimport { html } from \"satori-html\";\nimport satori from \"satori\";\n\nconst dir = \"./src/content/hooks\";\ntry {\n  const files = await readdir(dir);\n  const logo = await readFile(\n    new URL(\"./public/img/logo-useHooks.svg\", import.meta.url),\n    {\n      encoding: \"base64\",\n      width: 300,\n      height: 44,\n    }\n  );\n\n  for (const file of files) {\n    if (extname(file) !== \".mdx\") {\n      continue;\n    }\n\n    const content = await readFile(join(dir, file), \"utf8\");\n    const result = matter(content);\n\n    await generateOgImage({\n      title: result.data.name,\n      slug: result.data.name.toLowerCase(),\n      description: result.data.tagline,\n      logo\n    });\n  }\n} catch (err) {\n  console.error(\"Error:\", err);\n}\n\nasync function generateOgImage({ title, slug, description, logo }) {\n  const svg = await satori(\n    html` <style>\n        div {\n          display: flex;\n        }\n\n        .wrapper {\n          display: flex;\n          flex-direction: column;\n          background-color: #0f0d0e;\n          height: 630px;\n          padding: 80px;\n        }\n\n        .top {\n          display: flex;\n          justify-content: space-between;\n          align-items: center;\n        }\n\n        .bottom {\n          display: flex;\n          flex-direction: column;\n          justify-content: flex-end;\n          flex-basis: 100%;\n          width: 90%;\n          padding-bottom: 40px;\n        }\n\n        .logo {\n          width: 300px;\n          height: 44px;\n        }\n\n        .install {\n          font-size: 32px;\n          font-family: \"Fira Code\";\n          color: #f9f4da;\n        }\n\n        .install span {\n          color: #0ba95b;\n          padding-right: 16px;\n        }\n\n        .title {\n          margin-top: 16px;\n          font-size: 64px;\n          font-family: \"Outfit Bold\";\n          font-weight: 700;\n          color: #12b5e5;\n        }\n\n        .description {\n          margin-top: 16px;\n          color: #f9f4da;\n          font-family: \"Outfit\";\n          font-size: 40px;\n          font-weight: 400;\n        }\n      </style>\n      <div class=\"wrapper\">\n        <div class=\"top\">\n          <img class=\"logo\" src=\"data:image/svg+xml;base64,${logo}\" />\n          <div class=\"install\"><span>></span> npm i @uidotdev/usehooks</div>\n        </div>\n        <div class=\"bottom\">\n          <div class=\"title\">${title}</div>\n          <div class\"description\">${description}</div>\n        </div>\n      </div>`,\n    {\n      fonts: [\n        {\n          name: \"Outfit\",\n          data: await readFile(\n            new URL(\"./public/fonts/outfit-regular.ttf\", import.meta.url)\n          ),\n          weight: \"400\",\n          style: \"normal\",\n        },\n        {\n          name: \"Outfit Bold\",\n          data: await readFile(\n            new URL(\"./public/fonts/outfit-bold.ttf\", import.meta.url)\n          ),\n          weight: \"700\",\n          style: \"normal\",\n        },\n        {\n          name: \"Fira Code\",\n          data: await readFile(\n            new URL(\"./public/fonts/firacode-regular.ttf\", import.meta.url)\n          ),\n          weight: \"400\",\n          style: \"normal\",\n        },\n      ],\n      width: 1200,\n      height: 630,\n    }\n  );\n\n  const resvg = new Resvg(svg, {\n    fitTo: {\n      mode: \"original\",\n    },\n  });\n  const pngData = resvg.render();\n  const pngBuffer = pngData.asPng();\n  await writeFile(\n    new URL(`./public/meta/${slug}.png`, import.meta.url),\n    pngBuffer\n  );\n  console.log(\"✅\", slug);\n}\n"
  },
  {
    "path": "usehooks.com/package.json",
    "content": "{\n  \"name\": \"reacthooks.com\",\n  \"type\": \"module\",\n  \"version\": \"2.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"astro dev\",\n    \"start\": \"astro dev\",\n    \"build\": \"node ./generate-og-images.mjs && astro build\",\n    \"preview\": \"astro preview\",\n    \"astro\": \"astro\"\n  },\n  \"dependencies\": {\n    \"@astrojs/mdx\": \"^0.19.3\",\n    \"@astrojs/react\": \"^2.2.0\",\n    \"@astrojs/sitemap\": \"^1.3.1\",\n    \"@astrojs/tailwind\": \"^3.1.3\",\n    \"@astrojs/ts-plugin\": \"^1.0.6\",\n    \"@codesandbox/sandpack-react\": \"^2.6.6\",\n    \"@types/react\": \"^18.2.7\",\n    \"@types/react-dom\": \"^18.2.4\",\n    \"astro\": \"^2.5.2\",\n    \"classnames\": \"^2.3.2\",\n    \"framer-motion\": \"^10.9.1\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"tailwindcss\": \"^3.2.7\"\n  },\n  \"devDependencies\": {\n    \"@resvg/resvg-js\": \"^2.4.1\",\n    \"satori\": \"^0.9.1\",\n    \"satori-html\": \"^0.3.2\"\n  }\n}\n"
  },
  {
    "path": "usehooks.com/src/components/Button.astro",
    "content": "---\nexport interface Props {\n\ttext: string;\n\tsize: string;\n\thref?: string;\n\ttype: \"link\" | \"button\" | \"submit\" | \"reset\";\n\tcolor: string;\n\tclass?: string;\n}\n\nconst { type, href, text, size, color } = Astro.props;\nconst { class: className } = Astro.props;\n---\n\n{ type === \"link\" ? <a class={`button ${size} ${color} ${className}`} href={href}>{text}</a> : <button type={type} class={`button ${size} ${color} ${className}`}>{text}</button> }\n\n<style>\n\t.button {\n\t\tpadding: 1em 2em;\n\t\tbackground-color: var(--yellow);\n\t\tborder-radius: 9999px;\n\t\tborder: var(--border-dark);\n\t \tfont-family: var(--font-outfit);\n\t\tfont-size: clamp(.8rem, 1.5vw, 1rem);\n\t\tfont-weight: 700;\n\t\ttext-transform: uppercase;\n\t\ttext-decoration: none;\n\t\tcolor: var(--charcoal);\n\t\tcursor: pointer;\n\t\tbox-shadow: 1px 1px 0 var(--charcoal);\n\t\ttransition: box-shadow 150ms ease-in-out;\n\t}\n\n\t.button.large {\n\t\tpadding: 1em 2em;\n\t}\n\n\t.button.small {\n\t\tpadding: .5em 1em;\n\t}\n\n\t.button.yellow {\n\t\tbackground-color: var(--yellow);\n\t}\n\n\t.button.green {\n\t\tbackground-color: var(--green);\n\t}\n\n\t.button.pink {\n\t\tbackground-color: var(--pink);\n\t}\n\n\t.button::selection {\n\t\tbackground-color: var(--purple);\n\t}\n\n\t.button:not(:disabled):focus-visible,\n\t.button:not(:disabled):hover {\n\t\toutline: none;\n\t\tbox-shadow: var(--focus-object);\n\t}\n\n\t.button:disabled {\n\t\topacity: .5;\n\t\tcursor: not-allowed;\n\t}\n\t\n</style>\n"
  },
  {
    "path": "usehooks.com/src/components/CodePreview.astro",
    "content": "---\nimport CodePreview from \"./codepreview/CodePreview\";\nimport { getFiles } from \"./codepreview/utils\";\n\nconst { sandboxId, previewHeight } = Astro.props;\nconst files = await getFiles({ id: sandboxId });\n---\n\n<div>\n  <h2>Demo:</h2>\n  <div style={{ height: previewHeight }}>\n    <CodePreview client:only files={files} previewHeight={previewHeight} />\n  </div>\n</div>\n"
  },
  {
    "path": "usehooks.com/src/components/CountdownTimer.tsx",
    "content": "import { Fragment, useEffect, useState } from \"react\";\n\ninterface CountdownProps {\n  targetDate: string; // YYYY-MM-DD format\n}\n\ninterface TimeLeft {\n  days: number;\n  hours: number;\n  minutes: number;\n  seconds: number;\n}\n\nfunction calculateTimeLeft(targetDate: string): TimeLeft {\n  const target = new Date(`${targetDate}T00:00:00-08:00`);\n  const now = new Date();\n  const difference = +target - +now;\n\n  if (difference <= 0) {\n    return {\n      days: 0,\n      hours: 0,\n      minutes: 0,\n      seconds: 0,\n    };\n  }\n\n  return {\n    days: Math.floor(difference / (1000 * 60 * 60 * 24)),\n    hours: Math.floor((difference / (1000 * 60 * 60)) % 24),\n    minutes: Math.floor((difference / 1000 / 60) % 60),\n    seconds: Math.floor((difference / 1000) % 60),\n  };\n}\n\nconst formatNumber = (number: number) => number.toString().padStart(2, \"0\");\n\nconst Countdown: React.FC<CountdownProps> = ({ targetDate }) => {\n  const [timeLeft, setTimeLeft] = useState<TimeLeft>(\n    calculateTimeLeft(targetDate)\n  );\n\n  useEffect(() => {\n    const timer = setInterval(() => {\n      const newTimeLeft = calculateTimeLeft(targetDate);\n      setTimeLeft(newTimeLeft);\n      if (\n        newTimeLeft.days === 0 &&\n        newTimeLeft.hours === 0 &&\n        newTimeLeft.minutes === 0 &&\n        newTimeLeft.seconds === 0\n      ) {\n        clearInterval(timer);\n      }\n    }, 1000);\n\n    return () => clearInterval(timer);\n  }, [targetDate]);\n\n  if (\n    timeLeft.days === 0 &&\n    timeLeft.hours === 0 &&\n    timeLeft.minutes === 0 &&\n    timeLeft.seconds === 0\n  ) {\n    return null;\n  }\n\n  return (\n    <div className=\"countdown flex gap-1 justify-center text-md\">\n      {[\"days\", \"hours\", \"minutes\", \"seconds\"].map((unit, index) => (\n        <Fragment key={unit}>\n          {index > 0 && <span className=\"countdown-colon pt-1 grid justify-center\">:</span>}\n          <div className={`${unit} grid grid-cols-2 gap-x-1 gap-y-1.5`}>\n            <span className=\"countdown-number h-[2.2em] aspect-[6/7] grid place-content-center rounded-sm bg-brand-beige font-semibold\">\n              {formatNumber(timeLeft[unit as keyof TimeLeft]).charAt(0)}\n            </span>\n            <span className=\"countdown-number h-[2.2em] aspect-[6/7] grid place-content-center rounded-sm bg-brand-beige font-semibold\">\n              {formatNumber(timeLeft[unit as keyof TimeLeft]).charAt(1)}\n            </span>\n            <p className=\"countdown-label col-span-full text-sm\">{unit}</p>\n          </div>\n        </Fragment>\n      ))}\n    </div>\n  );\n};\n\nexport default Countdown;\n"
  },
  {
    "path": "usehooks.com/src/components/HookDescription.astro",
    "content": "---\nimport Button from \"./Button.astro\";\nconst { name } = Astro.props;\n---\n\n<div class=\"description\">\n  <div>\n    <h2>Description:</h2>\n    <slot />\n  </div>\n  <aside class=\"callout\">\n    <img\n      src=\"/img/react-gg-logo.svg\"\n      width=\"464\"\n      height=\"85\"\n      class=\"logo\"\n      alt=\"React.gg\"\n    />\n    <p>\n      Want to learn how to build {name} yourself? Check out <a\n        href=\"https://react.gg?s=usehooks\">react.gg</a\n      > – the interactive way to master modern React.\n    </p>\n    <Button\n      text=\"Learn More\"\n      size=\"small\"\n      href=\"https://react.gg?s=usehooks\"\n      type=\"link\"\n      color=\"green\"\n      class=\"get-started\"\n    />\n  </aside>\n</div>\n\n<style>\n  .description {\n    --callout-width: 300px;\n    display: grid;\n    gap: 1.5rem 2rem;\n    font-size: clamp(1.1rem, 2.2vw, 1.3rem);\n  }\n\n  @media screen and (min-width: 811px) {\n    .description {\n      grid-template-columns: 1fr var(--callout-width);\n    }\n  }\n\n  .callout {\n    margin: 1rem 0 1.5rem;\n    align-self: start;\n    padding: 1.5rem;\n    padding-bottom: 0;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    gap: 1rem;\n    border: var(--border-dark);\n    border-color: var(--coal);\n    border-radius: 0.5rem;\n    font-size: clamp(0.9rem, 2vw, 1.1rem);\n    color: var(--white);\n    text-decoration: none;\n    text-align: center;\n    transition: all 200ms ease-in-out;\n  }\n\n  .callout img.logo {\n    max-width: 150px;\n  }\n\n  .callout .button {\n    transform: translateY(50%);\n  }\n\n  .callout p {\n    max-width: 40ch;\n  }\n\n  @media screen and (min-width: 811px) {\n    .callout {\n      max-width: var(--callout-width);\n      margin-bottom: 0;\n    }\n  }\n</style>\n"
  },
  {
    "path": "usehooks.com/src/components/Install.astro",
    "content": "---\nconst { text } = Astro.props;\nconst { class: className } = Astro.props;\n---\n\n<div class={`install ${className}`}>\n  <code class={className}>{text}</code>\n  <button class={`copy-btn ${className}`}>Copy</button>\n</div>\n\n<script>\n  const copyButton = document.querySelector(`.copy-btn`);\n  const copyText = document.querySelector(`.install code`).textContent;\n\n  copyButton.addEventListener(\"click\", async () => {\n    try {\n      if (navigator?.clipboard?.writeText) {\n        await navigator.clipboard.writeText(copyText);\n        copyButton.textContent = \"Copied!\";\n        setTimeout(() => {\n          copyButton.textContent = \"Copy\";\n        }, 3000);\n      } else {\n        throw new Error(\"writeText not supported\");\n      }\n    } catch (e) {\n      oldSchoolCopy(copyText);\n    }\n  });\n\n  function oldSchoolCopy(text) {\n    const tempTextArea = document.createElement(\"textarea\");\n    tempTextArea.value = text;\n    document.body.appendChild(tempTextArea);\n    tempTextArea.select();\n    document.execCommand(\"copy\");\n    document.body.removeChild(tempTextArea);\n  }\n</script>\n\n<style>\n  .install {\n    width: 100%;\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    gap: clamp(0.7rem, 3vw, 2rem);\n    background-color: var(--charcoal);\n    padding: clamp(1rem, 4vw, 1.3rem) clamp(1rem, 4vw, 1.5rem);\n    border-radius: 0.5rem;\n  }\n\n  .install code {\n    margin-top: 0.3rem;\n    padding: 0;\n    font-size: clamp(0.8rem, 3vw, 1.2rem) !important;\n  }\n\n  .install code::before {\n    content: \">\";\n    display: inline-block;\n    margin-right: 0.5rem;\n    color: var(--green);\n  }\n\n  .copy-btn {\n    padding: 0.2rem 0.4rem;\n    padding-left: 1.7rem;\n    background: no-repeat url(\"/img/icon-copy.svg\") 0.4rem 50% / 0.9rem auto;\n    border: var(--border-light);\n    border-radius: 0.3rem;\n    font-size: clamp(0.7rem, 2vw, 0.9rem);\n    font-weight: 500;\n    transition: all 200ms ease-in-out;\n  }\n\n  .copy-btn:hover,\n  .copy-btn:focus-visible {\n    background-color: var(--coal);\n    color: var(--white);\n  }\n</style>\n"
  },
  {
    "path": "usehooks.com/src/components/Logo.astro",
    "content": "---\nconst { class: className } = Astro.props;\n---\n\n<a href=\"https://ui.dev\" class={`logo ui-logo image ${className}`}>\n\t<img src=\"/img/ui-logo.svg\" width=\"62\" height=\"62\" alt=\"ui.dev\" />\n</a>\n\n<style>\n\t.ui-logo {\n\t\tdisplay: inline-flex;\n\t\tborder-radius: 50%;\n\t}\n\n\t.ui-logo:hover {\n\t\ttransform: scale(1.1);\n\t}\n\n\t.ui-logo img {\n\t\twidth: clamp(3rem, 10vw, 4rem);\n\t\tdisplay: block;\n\t\theight: auto;\n\t}\n</style>"
  },
  {
    "path": "usehooks.com/src/components/LogoGithub.astro",
    "content": "---\nconst { class: className } = Astro.props;\n---\n\n<a href=\"https://github.com/uidotdev/usehooks\" class={`logo image github ${className}`}>\n\t<img src=\"/img/icon-github.svg\" alt=\"GitHub\" width=\"48\" height=\"48\" />\n</a>\n\n<style>\n\t.github {\n\t\tdisplay: inline-flex;\n\t\tborder-radius: 50%;\n\t}\n\n\t.github:focus-visible {\n\t\tbackground-color: transparent;\n\t}\n\n\t.github:hover {\n\t\ttransform: scale(1.1);\n\t}\n\n\t.github img {\n\t\twidth: clamp(1.8rem, 7vw, 2.8rem);\n\t\tdisplay: block;\n\t\theight: auto;\n\t}\n</style>"
  },
  {
    "path": "usehooks.com/src/components/QueryGGBanner.astro",
    "content": "---\nimport Button from \"./Button.astro\";\nimport CountdownTimer from \"./CountdownTimer\";\n---\n\n<aside class=\"reactgg-container container\">\n  <div class=\"reactgg-banner\">\n    <a href=\"https://react.gg?s=usehooks\" class=\"reactgg-header\">\n      <img\n        src={\"/img/banner-sale-reactgg.svg\"}\n        alt=\"react.gg - The interactive way to master modern React\"\n        class=\"reactgg-headline\"\n      />\n    </a>\n    <div class=\"reactgg-spacer\"></div>\n    <div class=\"reactgg-cta\">\n      <div class=\"reactgg-cta-container\">\n        <h2>react.gg Launch Sale</h2>\n        <p>Get 30% off through May 23rd</p>\n        <CountdownTimer client:only targetDate=\"2025-05-24\" />\n        <Button\n          text=\"Join Now\"\n          size=\"small\"\n          href=\"https://react.gg?s=usehooks\"\n          type=\"link\"\n          color=\"yellow\"\n          class=\"join-now mt-4 mb-1 lg:mb-2 inline-block\"\n        />\n      </div>\n    </div>\n  </div>\n</aside>\n\n<style>\n  .reactgg-container {\n    width: 100%;\n    max-width: 1300px;\n    margin: 0 auto 30px;\n  }\n\n  .reactgg-banner {\n    width: 100%;\n    background-color: var(--brand-charcoal);\n    border: 2px solid var(--brand-charcoal);\n    border-radius: 8px;\n    box-shadow: 0.2rem 0.2rem 0 var(--brand-charcoal);\n    overflow: hidden;\n    @media (min-width: 1024px) {\n      display: grid;\n      grid-template-columns: 1fr 40px 1fr;\n    }\n  }\n\n  .reactgg-header {\n    display: grid;\n    align-self: center;\n    place-items: center;\n    align-content: center;\n    height: 190px;\n    overflow: hidden;\n    @media (min-width: 1024px) {\n      height: 280px;\n      grid-column: 1 / 3;\n      grid-row: 1;\n    }\n  }\n\n  .reactgg-headline {\n    width: 110%;\n    max-width: none;\n  }\n\n  .reactgg-spacer {\n    width: 40px;\n    margin-left: 20px;\n    display: none;\n    background-color: var(--brand-green);\n    z-index: 0;\n    transform: skew(-7deg);\n    @media (min-width: 1024px) {\n      display: block;\n      grid-column: 2;\n      grid-row: 1;\n      height: 100%;\n    }\n  }\n\n  .reactgg-cta {\n    padding: 0.5rem;\n    display: grid;\n    justify-content: center;\n    background-color: var(--brand-green);\n    color: var(--brand-charcoal);\n    z-index: 10;\n    @media (min-width: 1024px) {\n      padding-bottom: 0;\n      grid-row: 1;\n      grid-column: 3;\n    }\n  }\n\n  .reactgg-cta-container {\n    margin-top: 0.5rem;\n    margin-bottom: 0.5rem;\n    place-self: center;\n    text-align: center;\n    text-transform: uppercase;\n\n    h2 {\n      margin-top: 0;\n      margin-bottom: 0.5rem;\n      font-size: 1.25rem;\n      line-height: 1.75rem;\n      font-weight: 600;\n      color: var(--brand-coal);\n      @media (min-width: 1024px) {\n        font-size: 1.5rem;\n        line-height: 2rem;\n      }\n      @media (min-width: 1280px) {\n        font-size: 1.875rem;\n        line-height: 2.25rem;\n      }\n    }\n\n    h2 + p {\n      margin-top: 0;\n      margin-bottom: 1.2rem;\n      text-transform: none;\n      font-size: 90%;\n    }\n  }\n\n  :global(.countdown-colon),\n  :global(.countdown-number) {\n    font-size: clamp(1rem, 4vw, 1.5rem);\n  }\n</style>\n"
  },
  {
    "path": "usehooks.com/src/components/RelatedHook.astro",
    "content": "---\nimport { getEntry } from \"astro:content\";\nimport HookCard from \"./search/HookCard\";\n\nconst { slug } = Astro.props;\nconst relatedHook = await getEntry(\"hooks\", slug);\nconst { name, tagline } = relatedHook.data;\n---\n\n<HookCard name={name} tagline={tagline} />"
  },
  {
    "path": "usehooks.com/src/components/StaticCodeContainer.astro",
    "content": "---\nimport CodeWrapper from './codepreview/CodeWrapper'\n---\n<div>\n  <h2>Example:</h2>\n  <div class=\"min-h-[500px]\">\n    <CodeWrapper client:only>\n      <slot />\n    </CodeWrapper>\n  </div>\n</div>\n\n<noscript>\n  <slot />\n</noscript>"
  },
  {
    "path": "usehooks.com/src/components/Svg.astro",
    "content": "---\nexport interface Props {\n  name: string;\n}\n\nconst { name } = Astro.props as Props;\nconst { default: innerHTML } = await import(`../svg/${name}.svg?raw`);\n---\n\n<Fragment set:html={innerHTML} />"
  },
  {
    "path": "usehooks.com/src/components/codepreview/CodePreview.tsx",
    "content": "import {\n  SandpackProvider,\n  SandpackPreview,\n  SandpackStack,\n  SandpackFiles,\n} from \"@codesandbox/sandpack-react\";\nimport cx from \"classnames\";\n\nexport type PreviewProps = {\n  previewHeight?: string;\n  files?: SandpackFiles | undefined;\n};\n\nexport default function CodePreview({\n  previewHeight = \"250px\",\n  files,\n}: PreviewProps) {\n  const sandpackProviderProps = {\n    files,\n    initMode: \"user-visible\",\n    autorun: false,\n    logLevel: 0,\n  };\n\n  return (\n    <div className=\"editor-wrapper code-preview border-solid border border-brand-coal rounded-[.5rem] overflow-hidden not-prose\">\n      <SandpackProvider\n        template=\"react\"\n        theme={{\n          colors: {\n            surface1: \"var(--coal)\",\n            surface2: \"var(--coal)\",\n          },\n        }}\n        {...sandpackProviderProps}\n      >\n        <SandpackStack className=\"relative\">\n          <SandpackPreview\n            showOpenInCodeSandbox={false}\n            showRefreshButton={false}\n            style={{ height: previewHeight }}\n            className={cx(\"visible h-full\")}\n          />\n        </SandpackStack>\n      </SandpackProvider>\n    </div>\n  );\n}\n"
  },
  {
    "path": "usehooks.com/src/components/codepreview/CodeWrapper.tsx",
    "content": "import { useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { set } from \"astro/zod\";\n\nconst springConfig = {\n  damping: 20,\n  stiffness: 120,\n  mass: 0.15,\n};\n\nexport default function CodeWrapper({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  const [expanded, setExpanded] = useState(false);\n  const [hideExpand, setHideExpand] = useState(false);\n\n  return (\n    <div className=\"relative bg-brand-coal rounded-[.5rem]\">\n      <motion.div\n        variants={{\n          expanded: {\n            height: \"auto\",\n          },\n          collapsed: {\n            height: \"500px\",\n          },\n        }}\n        transition={springConfig}\n        initial=\"collapsed\"\n        animate={expanded ? \"expanded\" : \"collapsed\"}\n        className=\"relative overflow-auto \"\n      >\n        <div\n          ref={(el) => {\n            if (el) {\n              const { height } = el.getBoundingClientRect();\n              if (height < 500) {\n                setExpanded(true);\n                setHideExpand(true);\n              }\n            }\n          }}\n        >\n          {children}\n        </div>\n      </motion.div>\n      {!hideExpand && (\n        <div\n          className={`${\n            expanded ? \"relative\" : \"absolute\"\n          } bottom-0 w-full p-4`}\n        >\n          <button\n            className=\"font-bold uppercase rounded-full px-4 py-1 flex text-xs items-center justify-center bg-brand-charcoal text-brand-beige gap-2 hover:shadow-sm hover:bg-brand-green hover:text-brand-charcoal border border-brand-charcoal transition-all\"\n            onClick={() => setExpanded(!expanded)}\n          >\n            {expanded ? \"Collapse\" : \"Expand\"}\n          </button>\n        </div>\n      )}\n    </div>\n  );\n}\n"
  },
  {
    "path": "usehooks.com/src/components/codepreview/utils.ts",
    "content": "import { SandpackFile } from \"@codesandbox/sandpack-react\";\n\nexport async function getFiles({ id }: { id: string }) {\n  const configUrl = `https://codesandbox.io/api/v1/sandboxes/${id}/sandpack`;\n  const response = await fetch(configUrl);\n  if (response.ok) {\n    const data = await response.json();\n    // This hardcodes the active file, we should find a better way to do this\n    return updateFiles(data.files);\n  }\n  return {};\n}\n\n// https://codesandbox.io/s/challenge-ui-test-zurc8s\n\nfunction getChallengeConfig(json: string) {\n  const csb = JSON.parse(json);\n\n  if (csb?.previewConfig) {\n    return csb.previewConfig;\n  }\n\n  return {\n    visibleFiles: [],\n    activeFile: \"/src/App.js\",\n  };\n}\n\nexport function updateFiles(files: { [key: string]: SandpackFile }) {\n  const previewConfig = getChallengeConfig(files[\"/package.json\"].code);\n  Object.keys(files).map((key) => {\n    if (key === previewConfig.activeFile) {\n      files[key].active = true;\n    }\n    if (!previewConfig.visibleFiles.includes(key)) {\n      files[key].hidden = true;\n    }\n  });\n  return files;\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/Callout.module.css",
    "content": ".callout :global(a) {\n  height: 100%;\n  padding: var(--body-padding);\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 1rem;\n  border: var(--border-dark);\n  border-radius: 0.5rem;\n  font-size: clamp(0.9rem, 2vw, 1.1rem);\n  text-align: center;\n  transition: all 200ms ease-in-out;\n}\n\n.callout :global(a:hover) {\n  transform: scale(1.03);\n}\n\n.callout :global(img:not(.logo)) {\n  max-width: 120px;\n  margin-top: calc(var(--body-padding) * -1.2);\n  margin-bottom: 0.5rem;\n}\n\n.callout :global(img.d20) {\n  width: 70px;\n}\n\n.callout :global(img.money) {\n  width: 110px;\n}\n\n.callout :global(img.spinner) {\n  width: 80px;\n}\n\n.callout :global(img.hot-sauce) {\n  width: 80px;\n}\n\n.callout :global(img.logo) {\n  max-width: 150px;\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/Callout.tsx",
    "content": "import styles from \"./Callout.module.css\";\n\ntype Props = {\n  image: string;\n  imageWidth: string;\n  imageHeight: string;\n  imageAlt: string;\n  pitch: string;\n};\n\nexport default function Callout({\n  image,\n  imageWidth,\n  imageHeight,\n  imageAlt,\n  pitch,\n}) {\n  return (\n    <li className={styles.callout}>\n      <a href=\"https://react.gg?s=usehooks\" className=\"logo image\">\n        <img\n          src={`/img/${image}.svg`}\n          width={imageWidth}\n          height={imageHeight}\n          className={image}\n          alt={imageAlt}\n        />\n        <img\n          src=\"/img/react-gg-logo.svg\"\n          width=\"464\"\n          height=\"85\"\n          className=\"logo\"\n          alt=\"React.gg\"\n        />\n        <p>{pitch}</p>\n      </a>\n    </li>\n  );\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/HookCard.module.css",
    "content": ".hook > :global(a) {\n  height: 100%;\n  padding: var(--body-padding);\n  display: flex;\n  flex-direction: column;\n  gap: 0.6rem;\n  background-color: var(--charcoal);\n  border-radius: 0.5rem;\n  transition: transform 200ms ease-in-out;\n}\n\n.hook > :global(a:hover) {\n  transform: scale(1.03);\n}\n\n.card-title {\n  color: var(--blue);\n  text-transform: none;\n  font-family: var(--font-outfit);\n  font-size: clamp(1.1rem, 3vw, 1.4rem);\n  font-weight: 600;\n}\n\n.card-description {\n  margin-bottom: 0.5rem;\n  font-size: clamp(0.9rem, 2vw, 1.1rem);\n}\n\n.arrow {\n  width: 28px;\n  aspect-ratio: 3 / 2;\n  margin-top: auto;\n  align-self: flex-end;\n  transition: all 200ms ease-in-out;\n}\n\n:global(a:hover) .arrow {\n  transform: translateX(0.6rem);\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/HookCard.tsx",
    "content": "import styles from './HookCard.module.css';\n\nexport default function HookCard({\n  name,\n  tagline,\n}: {\n  name: string;\n  tagline: string;\n}) {\n  return (\n    <li className={styles.hook}>\n      <a href={`/${name.toLowerCase()}`}>\n        <h3 className={styles[\"card-title\"]}>{name}</h3>\n        <p className={styles[\"card-description\"]}>{tagline}</p>\n        <svg\n          xmlns=\"http://www.w3.org/2000/svg\"\n          className={styles.arrow}\n          viewBox=\"0 0 36 24\"\n        >\n          <path\n            fill=\"none\"\n            stroke=\"#12b2e2\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            strokeWidth=\"2\"\n            d=\"M1.86 12h30.18M21.31 1.15 34.14 12 21.31 22.85\"\n          />\n        </svg>\n      </a>\n    </li>\n  );\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/HookSearch.module.css",
    "content": ".hooks-search {\n  position: relative;\n  align-self: flex-start;\n}\n\n.input {\n  padding: 0.4rem 1rem;\n  padding-right: 2rem;\n  background-color: var(--coal);\n  border: var(--border-light);\n  border-radius: 1.5rem;\n  font-size: clamp(0.8rem, 2vw, 1rem);\n  color: var(--white);\n  transition: all 150ms ease-in-out;\n}\n\n.input:focus {\n  outline: none;\n  border-color: var(--charcoal);\n  box-shadow: var(--focus-object);\n}\n\n.input + :global(button) {\n  position: absolute;\n  right: 0.8rem;\n  top: 50%;\n  transform: translateY(-50%);\n  font-size: 1rem;\n  transition: all 150ms ease-in-out;\n}\n\n:global(input[type=\"search\"]::-webkit-search-decoration),\n:global(input[type=\"search\"]::-webkit-search-cancel-button),\n:global(input[type=\"search\"]::-webkit-search-results-button),\n:global(input[type=\"search\"]::-webkit-search-results-decoration) {\n  display: none;\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/HookSearch.tsx",
    "content": "import styles from \"./HookSearch.module.css\";\n\nexport default function HookSearch({\n  handleChange,\n  handleClear,\n  value,\n}: {\n  handleClear: () => void;\n  handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n  value: string;\n}) {\n  return (\n    <div className={styles[\"hooks-search\"]}>\n      <input\n        onChange={handleChange}\n        className={styles.input}\n        value={value}\n        type=\"search\"\n        id=\"search\"\n        placeholder=\"Search\"\n      />\n      <button id=\"search-cancel\" aria-label=\"Clear\" onClick={handleClear}>\n        ✕\n      </button>\n    </div>\n  );\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/HookSort.module.css",
    "content": ".toggle {\n  padding: 0.2rem 0.4rem;\n  border: var(--border-light);\n  border-radius: 0.3rem;\n  font-size: clamp(0.7rem, 2vw, 0.9rem);\n  font-weight: 500;\n  transition: all 200ms ease-in-out;\n}\n\n.toggle.active {\n  background-color: var(--yellow);\n  border-color: var(--yellow);\n  color: var(--charcoal);\n  cursor: default;\n}\n\n.toggle:not(.active):hover {\n  background-color: var(--charcoal);\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/HookSort.tsx",
    "content": "import styles from \"./HookSort.module.css\";\n\nexport default function HookSort({\n  setSort,\n  value,\n}: {\n  setSort: (value: \"name\" | \"popular\") => void;\n  value: \"name\" | \"popular\";\n}) {\n  return (\n    <div className=\"hooks-sort flex items-center gap-2\">\n      <small>Sort:</small>\n      <button\n        onClick={() => setSort(\"popular\")}\n        className={`${styles.toggle} ${\n          value === \"popular\" ? styles.active : \"\"\n        }`}\n      >\n        Popular\n      </button>\n      <button\n        onClick={() => setSort(\"name\")}\n        className={`${styles.toggle} ${value === \"name\" ? styles.active : \"\"}`}\n      >\n        Name\n      </button>\n    </div>\n  );\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/HooksList.module.css",
    "content": ".hooks-grid {\n  max-width: 980px;\n  margin: 2rem auto;\n}\n\n.hooks-controls {\n  padding: 1rem var(--body-padding);\n  display: flex;\n  justify-content: flex-end;\n}\n\n.hooks-list {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n  align-items: stretch;\n  gap: 1.6rem;\n}\n"
  },
  {
    "path": "usehooks.com/src/components/search/HooksList.tsx",
    "content": "import { useState } from \"react\";\nimport Callout from \"./Callout\";\nimport HookCard from \"./HookCard\";\nimport HookSort from \"./HookSort\";\nimport styles from \"./HooksList.module.css\";\n\nfunction insertAtIntervals(arr, items) {\n  let newArr = [...arr]; // create a copy of the array\n  let step = Math.ceil(newArr.length / items.length);\n\n  // Insert the first item at the beginning of the array\n  newArr.unshift(items[0]);\n\n  for (let i = 1; i < items.length; i++) {\n    let position = i * step + 1; // +1 to account for the first item\n    newArr.splice(position, 0, items[i]);\n  }\n\n  return newArr;\n}\n\nfunction sortAlphabetical(a, b) {\n  if (a.data.name < b.data.name) {\n    return -1;\n  }\n  if (a.data.name > b.data.name) {\n    return 1;\n  }\n  return 0;\n}\n\nfunction sortByPopularity(a, b) {\n  if (a.data.rank < b.data.rank) {\n    return -1;\n  }\n  if (a.data.rank > b.data.rank) {\n    return 1;\n  }\n  return 0;\n}\n\nconst sortMap = {\n  name: sortAlphabetical,\n  popular: sortByPopularity,\n};\n\nexport default function HooksList({ hooks }) {\n  const [sort, setSort] = useState<\"name\" | \"popular\">(\"popular\");\n\n  const list = hooks.sort(sortMap[sort]);\n  const listWithCallouts = insertAtIntervals(list, [\n    {\n      id: \"Callout 1\",\n      image: \"d20\",\n      imageWidth: \"222\",\n      imageHeight: \"206\",\n      imageAlt: \"20-sided die\",\n      pitch:\n        \"It’s dangerous to go alone! Master React by learning how to build useHooks yourself.\",\n    },\n    {\n      id: \"Callout 2\",\n      image: \"spinner\",\n      imageWidth: \"284\",\n      imageHeight: \"180\",\n      imageAlt: \"board game spinner and all options are React\",\n      pitch:\n        \"There’s no better way to learn useHooks than by building it yourself.\",\n    },\n    {\n      id: \"Callout 3\",\n      image: \"money\",\n      imageWidth: \"210\",\n      imageHeight: \"210\",\n      imageAlt: \"$100 Monopoly-style money\",\n      pitch:\n        \"Please give us your money.\",\n    },\n    {\n      id: \"Callout 4\",\n      image: \"hot-sauce\",\n      imageWidth: \"206\",\n      imageHeight: \"224\",\n      imageAlt: \"travel-style postcard from React that says “Enjoy the views!\",\n      pitch:\n        \"The all new interactive way to master modern React (for fun and profit).\",\n    }\n  ]);\n\n  return (\n    <section className={styles[\"hooks-grid\"]}>\n      <div className={styles[\"hooks-controls\"]}>\n        <HookSort setSort={setSort} value={sort} />\n      </div>\n      <ul className={styles[\"hooks-list\"]}>\n        {listWithCallouts.map(\n          ({ data, id, image, imageWidth, imageHeight, imageAlt, pitch }) => {\n            if (!data) {\n              return (\n                <Callout\n                  key={id}\n                  image={image}\n                  imageWidth={imageWidth}\n                  imageHeight={imageHeight}\n                  imageAlt={imageAlt}\n                  pitch={pitch}\n                />\n              );\n            }\n            return (\n              <HookCard key={id} name={data.name} tagline={data.tagline} />\n            );\n          }\n        )}\n      </ul>\n    </section>\n  );\n}\n"
  },
  {
    "path": "usehooks.com/src/content/config.ts",
    "content": "import { defineCollection, z, reference } from 'astro:content';\n\nexport const collections = {\n  hooks: defineCollection({\n    schema: z.object({\n      experimental: z.boolean().optional(),\n      draft: z.boolean().default(false),\n      sandboxId: z.string().optional(),\n      previewHeight: z.string().optional(),\n      name: z.string(),\n      tagline: z.string(),\n      ogImage: z.string().optional(),\n      rank: z.number(),\n      relatedHooks: z.array(\n        reference('hooks').optional()\n      ).optional(),\n    }),\n  }),\n};"
  },
  {
    "path": "usehooks.com/src/content/hooks/useBattery.mdx",
    "content": "---\nname: useBattery\nrank: 32\ntagline: Track the battery status of a user’s device with useBattery.\nsandboxId: usebattery-o8js1p\npreviewHeight: 320px\nrelatedHooks:\n  - usenetworkstate\n  - usepreferredlanguage\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useBattery hook is useful for accessing and monitoring the battery status\n  of the user’s device in a React application. By using this hook, you can\n  easily retrieve information such as the battery level, charging status, and\n  estimated charging and discharging times. It provides a state object that\n  includes properties like supported, loading, level, charging, chargingTime,\n  and dischargingTime.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Values\n  The hook returns an object containing the following properties:\n\n  <div class=\"table-container\">\n  | Name             | Type    | Description |\n  | ---------------- | ------- | ----------- |\n  | supported        | boolean | Indicates whether the Battery Status API is supported in the user’s browser. |\n  | loading          | boolean | Indicates if the battery information is still loading. |\n  | level            | number  | Represents the level of the system’s battery. 0.0 means that the system’s battery is completely discharged, and 1.0 means the battery is completely charged. |\n  | charging         | boolean | Represents whether the system’s battery is charging. `true` means the battery is charging, `false` means it’s not. |\n  | chargingTime     | number  | Represents the time remaining in seconds until the system’s battery is fully charged. |\n  | dischargingTime  | number  | Represents the time remaining in seconds until the system’s battery is completely discharged and the system is about to be suspended. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport { useBattery } from \"@uidotdev/usehooks\";\nimport Battery from \"./Battery\";\n\nexport default function App() {\n  const { loading, level, charging, chargingTime, dischargingTime } =\n    useBattery();\n  return (\n    <>\n      <div className=\"wrapper\">\n        <h1>useBattery</h1>\n        {!loading ? (\n          <Battery\n            level={level * 100}\n            charging={charging}\n            chargingTime={chargingTime}\n            dischargingTime={dischargingTime}\n          />\n        ) : (\n          <h2>Loading...</h2>\n        )}\n      </div>\n    </>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useClickAway.mdx",
    "content": "---\nname: useClickAway\nrank: 47\ntagline: Detect clicks outside of specific component with useClickAway.\nsandboxId: useclickaway-p4hl4m\npreviewHeight: 250px\nrelatedHooks:\n  - uselongpress\n  - usehover\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useClickAway hook is a useful for detecting clicks outside a specific\n  component. It allows you to pass a callback function that will be triggered\n  whenever a click occurs outside the component’s area. This hook is\n  particularly helpful when implementing dropdown menus, modals, or any other UI\n  elements that need to be closed when the user clicks outside of them. By\n  attaching event listeners to the document, the hook checks if the click target\n  is within the component’s reference, and if not, it invokes the provided\n  callback function.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name | Type     | Description |\n  | ---- | -------- | ----------- |\n  | callback | function | The callback function that is provided as an argument to `useClickAway`. This function is invoked whenever a click event is detected outside of the referenced element. The event object from the click is passed to this callback function. |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name | Type         | Description |\n  | ---- | ------------ | ----------- |\n  | ref  | React ref    | This is a ref object returned by the hook. It should be attached to a React element to monitor click events. The ref provides a way to access the properties of the element it is attached to. |\n  </div>\n</div>\n\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useClickAway } from \"@uidotdev/usehooks\";\nimport { closeIcon } from \"./icons\";\n\nexport default function App() {\n  const [isOpen, setIsOpen] = React.useState(false);\n  const ref = useClickAway(() => {\n    setIsOpen(false);\n  });\n\n  const handleOpenModal = () => {\n    if (isOpen === false) {\n      setIsOpen(true);\n    }\n  };\n\n  return (\n    <>\n      <section>\n        <h1>useClickAway</h1>\n        <button className=\"link\" onClick={handleOpenModal}>\n          Open Modal\n        </button>\n      </section>\n      {isOpen && (\n        <dialog ref={ref}>\n          <button onClick={() => setIsOpen(false)}>{closeIcon}</button>\n          <h2>Modal</h2>\n          <p>\n            Click outside the modal to close (or use the button) whatever you\n            prefer.\n          </p>\n        </dialog>\n      )}\n    </>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useContinuousRetry.mdx",
    "content": "---\nname: useContinuousRetry\nexperimental: true\nrank: 12\ntagline: Automates retries of a callback function until it succeeds with useContinuousRetry\nsandboxId: usecontinuousretry-v0uf1n\npreviewHeight: 380px\nrelatedHooks:\n  - usesessionstorage\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useContinuousRetry hook allows you to repeatedly call a specified callback\n  function at a defined interval until the callback returns a truthy value,\n  indicating a successful resolution. This hook is particularly handy when\n  dealing with asynchronous operations or API calls that may fail temporarily\n  and need to be retried automatically. It encapsulates the logic of retrying\n  and provides a clean interface to handle retry-related states, such as whether\n  the retry process has resolved or not.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name     | Type     | Description                                                                                                                                                  |\n  | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------|\n  | callback | function | The callback function to be executed repeatedly until it returns a truthy value.                                                                             |\n  | interval | number   | (Optional) The interval in milliseconds at which the callback function is executed. Default value is 100 milliseconds.                                       |\n  | options  | object   | (Optional) An object containing a `maxRetries` property which tells `useContinuousRetry` the maximum amount of retry attempts it should make before stopping |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Type    | Description                                                                                |\n  | ------- | ------------------------------------------------------------------------------------------ |\n  | boolean | `true` if the callback function has resolved (returned a truthy value), `false` otherwise. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useContinuousRetry } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [count, setCount] = React.useState(0);\n  const hasResolved = useContinuousRetry(() => {\n    console.log(\"retrying\");\n    return count > 10;\n  }, 1000);\n\n  return (\n    <section>\n      <h1>useContinuousRetry</h1>\n      <button className=\"primary\" onClick={() => setCount(count + 1)}>\n        {count}\n      </button>\n      <pre>{JSON.stringify({ hasResolved, count }, null, 2)}</pre>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useCopyToClipboard.mdx",
    "content": "---\nname: useCopyToClipboard\nrank: 31\ntagline: Copy text to the clipboard using useCopyToClipboard.\nsandboxId: usecopytoclipboard-y22r6w\npreviewHeight: 300px\nrelatedHooks:\n  - usemap\n  - usequeue\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useCopyToClipboard hook is useful because it abstracts the complexity of\n  copying text to the clipboard in a cross-browser compatible manner. It\n  utilizes the modern navigator.clipboard.writeText method if available, which\n  provides a more efficient and secure way to copy text. In case the writeText\n  method is not supported by the browser, it falls back to a traditional method\n  using the document.execCommand(\"copy\") approach.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  The `useCopyToClipboard` hook returns an array with the following elements:\n\n  <div class=\"table-container\">\n  | Index | Type     | Description                                            |\n  | ----- | -------- | ------------------------------------------------------ |\n  | 0     | string   | The value that was last copied to the clipboard.       |\n  | 1     | function | A function to copy a specified value to the clipboard. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useCopyToClipboard } from \"@uidotdev/usehooks\";\nimport { copyIcon, checkIcon } from \"./icons\";\n\nconst randomHash = crypto.randomUUID();\n\nexport default function App() {\n  const [copiedText, copyToClipboard] = useCopyToClipboard();\n  const hasCopiedText = Boolean(copiedText);\n  return (\n    <section>\n      <h1>useCopyToClipboard</h1>\n      <article>\n        <label>Fake API Key</label>\n        <pre>\n          <code>{randomHash}</code>\n          <button\n            disabled={hasCopiedText}\n            className=\"link\"\n            onClick={() => copyToClipboard(randomHash)}\n          >\n            {hasCopiedText ? checkIcon : copyIcon}\n          </button>\n        </pre>\n      </article>\n      {hasCopiedText && (\n        <dialog open={hasCopiedText}>\n          <h4>\n            Copied{\" \"}\n            <span role=\"img\" aria-label=\"Celebrate Emoji\">\n              🎉\n            </span>\n          </h4>\n          <textarea placeholder=\"Paste your copied text\" />\n        </dialog>\n      )}\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useCountdown.mdx",
    "content": "---\nname: useCountdown\nexperimental: true\nrank: 21\ntagline: Create countdown timers using useCountdown.\nsandboxId: usecountdown-6gzbhg\npreviewHeight: 340px\nrelatedHooks:\n  - useinterval\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useCountdown hook is useful for creating a countdown timer. By specifying\n  an endTime and various options such as the interval between ticks and callback\n  functions for each tick and completion, the hook sets up an interval that\n  updates the count and triggers the appropriate callbacks until the countdown\n  reaches zero. The countdown value is returned, allowing you to easily\n  incorporate and display the countdown in your components.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name    | Type   | Description                                                                                                                                                                                                                                                                                                         |\n  | ------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n  | endTime | number | The end time of the countdown in milliseconds since the Unix epoch.                                                                                                                                                                                                                                                 |\n  | options | object | An object containing the following options:<ul><li>`interval`: The interval in milliseconds at which the countdown should tick.</li><li>`onComplete`: A callback function to be called when the countdown reaches zero.</li><li>`onTick`: A callback function to be called on each tick of the countdown.</li></ul> |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name  | Type   | Description                         |\n  | ----- | ------ | ----------------------------------- |\n  | count | number | The current count of the countdown. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useCountdown } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [endTime, setEndTime] = React.useState(new Date(Date.now() + 10000));\n  const [complete, setComplete] = React.useState(false);\n\n  const count = useCountdown(endTime, {\n    interval: 1000,\n    onTick: () => console.log(\"tick\"),\n    onComplete: (time) => setComplete(true),\n  });\n\n  const handleClick = (time) => {\n    if (complete === true) return;\n    const nextTime = endTime.getTime() + time;\n    setEndTime(new Date(nextTime));\n  };\n\n  return (\n    <section>\n      <header>\n        <h1>useCountdown</h1>\n      </header>\n      <span className=\"countdown\">{count}</span>\n      {complete === false && (\n        <div className=\"button-row\">\n          <button onClick={() => handleClick(5000)}>+5s</button>\n          <button onClick={() => handleClick(10000)}>+10s</button>\n          <button onClick={() => handleClick(15000)}>+15s</button>\n        </div>\n      )}\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useCounter.mdx",
    "content": "---\nname: useCounter\nrank: 49\ntagline: Manage a counter value with minimum and maximum limits with useCounter.\nsandboxId: usecounter-ddeo74\npreviewHeight: 450px\nrelatedHooks:\n  - usecountdown\n  - useprevious\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useCounter hook is useful for managing a counter value with additional\n  options for minimum and maximum limits. The hook takes a starting value and\n  options object as parameters, which can specify minimum and maximum limits for\n  the counter. If the starting value falls outside the specified limits, an\n  error is thrown. The hook returns the current count value and an object\n  containing functions to increment, decrement, set a specific count, and reset\n  the counter.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name          | Type   | Description                                        |\n  | ------------- | ------ | -------------------------------------------------- |\n  | startingValue | number | The initial value for the counter. Default is `0`. |\n  | options       | object | Additional options for the counter.                |\n  | options.min   | number | The minimum value allowed for the counter.         |\n  | options.max   | number | The maximum value allowed for the counter.         |\n  </div>\n\n  ### Return Value\n\n  The `useCounter` hook returns an array with two elements:\n\n  <div class=\"table-container\">\n  | Name            | Parameters        | Description                                          |\n  | --------------- | ----------------- | ---------------------------------------------------- |\n  | `[0]`           |                   | The current value of the counter.                    |\n  | `[1].increment` |                   | Increments the counter by 1.                         |\n  | `[1].decrement` |                   | Decrements the counter by 1.                         |\n  | `[1].set`       | nextCount: number | Sets the counter to the specified `nextCount` value. |\n  | `[1].reset`     |                   | Resets the counter to the initial `startingValue`.   |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useCounter } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [count, { increment, decrement, set, reset }] = useCounter(5, {\n    min: 5,\n    max: 10,\n  });\n\n  return (\n    <section>\n      <h1>UseCounter</h1>\n      <h6>with optional min / max</h6>\n      <button disabled={count >= 10} className=\"link\" onClick={increment}>\n        Increment\n      </button>\n      <button disabled={count <= 5} className=\"link\" onClick={decrement}>\n        Decrement\n      </button>\n      <button className=\"link\" onClick={() => set(6)}>\n        Set to 6\n      </button>\n      <button className=\"link\" onClick={reset}>\n        Reset\n      </button>\n      <p>{count}</p>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useDebounce.mdx",
    "content": "---\nname: useDebounce\nrank: 1\ntagline: Delay the execution of function or state update with useDebounce.\nsandboxId: usedebounce-hmo7m3\npreviewHeight: 1000px\nrelatedHooks:\n  - usethrottle\n  - usefetch\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useDebounce hook is useful for delaying the execution of functions or\n  state updates until a specified time period has passed without any further\n  changes to the input value. This is especially useful in scenarios such as\n  handling user input or triggering network requests, where it effectively\n  reduces unnecessary computations and ensures that resource-intensive\n  operations are only performed after a pause in the input activity.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name  | Type   | Description |\n  | ----- | ------ | ----------- |\n  | value | any    | The value that you want to debounce. This can be of any type. |\n  | delay | number | The delay time in milliseconds. After this amount of time, the latest value is used. |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name          | Type | Description |\n  | ------------- | ---- | ----------- |\n  | debouncedValue| any  | The debounced value. After the delay time has passed without the `value` changing, this will be updated to the latest `value`. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useDebounce } from \"@uidotdev/usehooks\";\nimport searchHackerNews from \"./searchHackerNews\";\nimport SearchResults from \"./SearchResults\";\n\nexport default function App() {\n  const [searchTerm, setSearchTerm] = React.useState(\"js\");\n  const [results, setResults] = React.useState([]);\n  const [isSearching, setIsSearching] = React.useState(false);\n  const debouncedSearchTerm = useDebounce(searchTerm, 300);\n\n  const handleChange = (e) => {\n    setSearchTerm(e.target.value);\n  };\n\n  const handleSubmit = (e) => {\n    e.preventDefault();\n    const formData = new FormData(e.target);\n    setSearchTerm(formData.get(\"search\"));\n    e.target.reset();\n    e.target.focus();\n  };\n\n  React.useEffect(() => {\n    const searchHN = async () => {\n      let results = [];\n      setIsSearching(true);\n      if (debouncedSearchTerm) {\n        const data = await searchHackerNews(debouncedSearchTerm);\n        results = data?.hits || [];\n      }\n\n      setIsSearching(false);\n      setResults(results);\n    };\n\n    searchHN();\n  }, [debouncedSearchTerm]);\n\n  return (\n    <section>\n      <header>\n        <h1>useDebounce</h1>\n        <form onSubmit={handleSubmit}>\n          <input\n            name=\"search\"\n            placeholder=\"Search HN\"\n            style={{ background: \"var(--charcoal)\" }}\n            onChange={handleChange}\n          />\n          <button className=\"primary\" disabled={isSearching} type=\"submit\">\n            {isSearching ? \"...\" : \"Search\"}\n          </button>\n        </form>\n      </header>\n      <SearchResults results={results} />\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useDefault.mdx",
    "content": "---\nname: useDefault\nrank: 44\ntagline: Manage state with default values using useDefault.\nsandboxId: usedefault-5c0pyt\npreviewHeight: 250px\nrelatedHooks:\n  - useprevious\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The `useDefault` hook behaves similar to `useState` but with one difference – if the state of the hook is `undefined` or `null`, `useDefault` will default the state to a provided default value.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name         | Type     | Description |\n  | ------------ | -------- | ----------- |\n  | initialValue | any      | The initial value of the state returned from `useDefault` |\n  | defaultValue | any      | The default value to be used if the state is `undefined` or `null`. |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name     | Type            | Description |\n  | -------- | --------------- | ----------- |\n  | state    | any             | The current state. If the state is `undefined` or `null`, `defaultValue` is returned instead. |\n  | setState | function        | The state setter function returned from `React.useState()`. This can be called to update the state. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useDefault } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const initialState = { name: \"Tyler\" };\n  const defaultState = { name: \"Ben\" };\n\n  const [user, setUser] = useDefault(initialState, defaultState);\n\n  return (\n    <section>\n      <h1>useDefault</h1>\n\n      <button\n        title=\"Sets the value to Lynn\"\n        className=\"link\"\n        onClick={() => setUser({ name: \"Lynn\" })}\n      >\n        Lynn\n      </button>\n      <button\n        title=\"Sets the value to Tyler\"\n        className=\"link\"\n        onClick={() => setUser({ name: \"Tyler\" })}\n      >\n        Tyler\n      </button>\n      <button\n        title=\"Sets the value to null causing it to use the default value\"\n        className=\"link\"\n        onClick={() => setUser(null)}\n      >\n        Null\n      </button>\n      <pre>\n        <code>{JSON.stringify(user)}</code>\n      </pre>\n    </section>\n  );\n}\n\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useDocumentTitle.mdx",
    "content": "---\nname: useDocumentTitle\nrank: 40\ntagline: Dynamically update the title of a webpage with useDocumentTitle.\nsandboxId: usedocumenttitle-6vmc1n\npreviewHeight: 300px\nrelatedHooks:\n  - usefavicon\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useDocumentTitle hook is useful for dynamically updating the title of a\n  webpage based on the current state or data. This hook proves beneficial in\n  scenarios where the title needs to be dynamically updated, such as displaying\n  the name of the currently selected item or reflecting changes in application\n  state.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name  | Type   | Description                           |\n  | ----- | ------ | ------------------------------------- |\n  | title | string | The title to be set for the document. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useDocumentTitle } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [count, setCount] = React.useState(0);\n\n  useDocumentTitle(`Clicked ${count} times.`);\n  return (\n    <section>\n      <h1>useDocumentTitle</h1>\n      <h6>\n        <a\n          className=\"link\"\n          href=\"https://6vmc1n.csb.app/\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          Try in a new tab\n        </a>\n      </h6>\n      <button className=\"primary\" onClick={() => setCount(count + 1)}>\n        Increment Count: {count}\n      </button>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useEventListener.mdx",
    "content": "---\nname: useEventListener\nexperimental: true\nrank: 26\ntagline: Listen for events on a target element with useEventListener.\nsandboxId: useeventlistener-51h645\npreviewHeight: 250px\nrelatedHooks:\n  - usescript\n  - usehover\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useEventListener hook enables you to add event listeners to a target\n  element within a React component. By using useEventListener, you can handle\n  various types of events, such as mouse events or keyboard events, and specify\n  the target element, event name, event handler function, and additional\n  options. applications.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name            | Type               | Description                                                                                                         |\n  | --------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------- |\n  | target          | ref or DOM element | The target element to attach the event listener to. It can be either a ref object (`ref.current`) or a DOM element. |\n  | eventName       | string             | The name of the event to listen for.                                                                                |\n  | handler         | function           | The event handler function to be executed when the event is triggered.                                              |\n  | options         | object             | (Optional) Additional options for the event listener.                                                               |\n  | options.capture | boolean            | Specifies whether the event should be captured during the capturing phase. Default is `false`.                      |\n  | options.passive | boolean            | Specifies whether the event listener will not call `preventDefault()`. Default is `false`.                          |\n  | options.once    | boolean            | Specifies whether the event listener should only be invoked once. Default is `false`.                               |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useEventListener } from \"@uidotdev/usehooks\";\nimport { closeIcon } from \"./icons\";\n\nexport default function App() {\n  const ref = React.useRef(null);\n  const [isOpen, setIsOpen] = React.useState(false);\n\n  const handleClick = (e) => {\n    const element = ref.current;\n    if (element && !element.contains(e.target)) {\n      setIsOpen(false);\n    }\n  };\n\n  useEventListener(document, \"mousedown\", handleClick);\n\n  return (\n    <section>\n      <h1>useEventListener</h1>\n      <div style={{ minHeight: \"200vh\" }}>\n        <button className=\"link\" onClick={() => setIsOpen(true)}>\n          Click me\n        </button>\n      </div>\n      {isOpen && (\n        <dialog ref={ref}>\n          <button onClick={() => setIsOpen(false)}>{closeIcon}</button>\n          <h2>Modal</h2>\n          <p>\n            Click outside the modal to close (or use the button) whatever you\n            prefer.\n          </p>\n        </dialog>\n      )}\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useFavicon.mdx",
    "content": "---\nname: useFavicon\nrank: 43\ntagline: Dynamically update the favicon with useFavicon.\nsandboxId: usefavicon-xckn4k\npreviewHeight: 200px\nrelatedHooks:\n  - usedocumenttitle\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useFavicon hook is a useful for dynamically update the favicon (shortcut icon) of a web page. By using this hook, you can easily change the favicon by providing a new URL as a parameter. It creates a new link element with the specified URL, sets its type and relationship attributes appropriately, and appends it to the `<head>` section of the document.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name | Type   | Description                                        |\n  | ---- | ------ | -------------------------------------------------- |\n  | url  | string | The URL of the favicon to be set for the document. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useFavicon } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [favicon, setFavicon] = React.useState(\n    \"https://ui.dev/favicon/favicon-32x32.png\"\n  );\n\n  useFavicon(favicon);\n\n  return (\n    <section>\n      <h1>useFavicon</h1>\n\n      <button\n        title=\"Set the favicon to Bytes' logo\"\n        className=\"link\"\n        onClick={() =>\n          setFavicon(\"https://bytes.dev/favicon/favicon-32x32.png\")\n        }\n      >\n        Bytes\n      </button>\n      <button\n        title=\"Set the favicon to React Newsletter's logo\"\n        className=\"link\"\n        onClick={() =>\n          setFavicon(\"https://reactnewsletter.com/favicon/favicon-32x32.png\")\n        }\n      >\n        React Newsletter\n      </button>\n\n      <button\n        title=\"Set the favicon to uidotdev's logo\"\n        className=\"link\"\n        onClick={() => setFavicon(\"https://ui.dev/favicon/favicon-32x32.png\")}\n      >\n        ui.dev\n      </button>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useFetch.mdx",
    "content": "---\nname: useFetch\nexperimental: true\nrank: 11\ntagline: Fetch data with accurate states, caching, and no stale responses using useFetch.\nsandboxId: usefetch-yky89o\npreviewHeight: 670px\nrelatedHooks:\n  - useintersectionobserver\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useFetch React hook is useful for handling data fetching and state\n  management in React components. It allows you to easily fetch data from a\n  specified URL using the fetch API and provides a consistent pattern for\n  handling loading, success, and error states. It also incorporates an internal\n  caching mechanism to store and retrieve previously fetched data, improving\n  performance by reducing redundant network requests. Additionally, it includes\n  a mechanism to ignore stale responses if the component unmounts or if a new\n  request is made before the previous one completes.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name    | Type   | Description                                                                              |\n  | ------- | ------ | ---------------------------------------------------------------------------------------- |\n  | url     | string | The URL to fetch data from.                                                              |\n  | options | object | (Optional) Additional options for the fetch request, such as headers or request methods. |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name        | Type               | Description                                                                    |\n  | ----------- | ------------------ | ------------------------------------------------------------------------------ |\n  | state       | object             | The state object containing the fetched data and error status.                 |\n  | state.error | error \\| undefined | The error object if an error occurred during the fetch, otherwise `undefined`. |\n  | state.data  | any \\| undefined   | The fetched data if the fetch was successful, otherwise `undefined`.           |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useFetch } from \"@uidotdev/usehooks\";\nimport Card from \"./Card\";\n\nexport default function App() {\n  const [count, setCount] = React.useState(1);\n\n  const { error, data } = useFetch(\n    `https://pokeapi.co/api/v2/pokemon/${count}`\n  );\n\n  return (\n    <section>\n      <h1>useFetch</h1>\n      <button\n        disabled={count < 2}\n        className=\"link\"\n        onClick={() => setCount((c) => c - 1)}\n      >\n        Prev\n      </button>\n      <button className=\"link\" onClick={() => setCount((c) => c + 1)}>\n        Next\n      </button>\n      <Card loading={!data} error={error} data={data} />\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useGeolocation.mdx",
    "content": "---\nname: useGeolocation\nrank: 36\ntagline: Access and monitor a user's geolocation (after they give permission) with useGeolocation.\nsandboxId: usegeolocation-3f1d0f\npreviewHeight: 900px\nrelatedHooks:\n  - usemap\n  - useset\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useGeolocation hook is useful for accessing and monitoring the user's\n  geolocation (after they give permission) in a React application. By utilizing\n  the hook, developers can easily retrieve the user's current position,\n  including latitude, longitude, altitude, accuracy, heading, speed, and\n  timestamp.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n<div class=\"table-container\">\n| Name    | Type   | Description |\n| ------- | ------ | ----------- |\n| options | object | This is an optional configuration object provided when calling `useGeolocation`. It is used when calling `navigator.geolocation.getCurrentPosition()` and `navigator.geolocation.watchPosition()`. Some of the attributes it accepts are `enableHighAccuracy`, `timeout`, and `maximumAge`. |\n</div>\n\n### Return Values\n\nThe hook returns an object containing the following properties:\n\n  <div class=\"table-container\">\n  | Name              | Type    | Description |\n  | ----------------- | ------- | ----------- |\n  | loading           | boolean | A boolean indicating if the geolocation data is currently being fetched. |\n  | accuracy          | number  | The accuracy of the latitude and longitude properties in meters. |\n  | altitude          | number  | The altitude in meters above the mean sea level. |\n  | altitudeAccuracy  | number  | The accuracy of altitude in meters. |\n  | heading           | number  | The direction in which the device is traveling. This value, specified in degrees, indicates how far off from heading true north the device is. |\n  | latitude          | number  | The latitude in decimal degrees. |\n  | longitude         | number  | The longitude in decimal degrees. |\n  | speed             | number  | The current ground speed of the device, specified in meters per second. |\n  | timestamp         | number  | The timestamp at which the geolocation data was retrieved. |\n  | error             | object  | An error object, if an error occurred while retrieving the geolocation data. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useGeolocation } from \"@uidotdev/usehooks\";\nimport Demo from \"./Demo\";\n\nexport default function App() {\n  return (\n    <section>\n      <h1>useGeolocation</h1>\n      <Location />\n    </section>\n  );\n}\n\nfunction Location() {\n  const state = useGeolocation();\n\n  if (state.loading) {\n    return <p>loading... (you may need to enable permissions)</p>;\n  }\n\n  if (state.error) {\n    return <p>Enable permissions to access your location data</p>;\n  }\n\n  return <Demo state={state} />;\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useHistoryState.mdx",
    "content": "---\nname: useHistoryState\nrank: 35\ntagline: Add undo / redo functionality with useHistoryState.\nsandboxId: usehistorystate-tubwyj\npreviewHeight: 400px\nrelatedHooks:\n  - usemap\n  - useset\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useHistoryState hook is useful for managing state with undo and redo\n  capabilities in React components. The hook offers functions like undo, redo,\n  set, and clear to interact with the state as well as other state related\n  values like canUndo and canRedo.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name           | Type   | Description                                        |\n  | -------------- | ------ | -------------------------------------------------- |\n  | initialPresent | object | (Optional) The initial state value. Default: `{}`. |\n  </div>\n\n  ### Return Value\n\n  The `useHistoryState` hook returns an object with the following properties and functions:\n\n  <div class=\"table-container\">\n  | Name    | Type     | Description                                                |\n  | ------- | -------- | ---------------------------------------------------------- |\n  | state   | any      | The current state value.                                   |\n  | set     | function | A function to set the state value.                         |\n  | undo    | function | A function to undo the previous state.                     |\n  | redo    | function | A function to redo the next state.                         |\n  | clear   | function | A function to clear the state history and reset the state. |\n  | canUndo | boolean  | Indicates whether an undo action is available.             |\n  | canRedo | boolean  | Indicates whether a redo action is available.              |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport Form from \"./Form\";\nimport { useHistoryState } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const { state, set, undo, redo, clear, canUndo, canRedo } = useHistoryState({\n    items: [],\n  });\n\n  const addTodo = (val) => {\n    set({\n      ...state,\n      items: state.items.concat({ id: crypto.randomUUID(), name: val }),\n    });\n  };\n\n  const removeTodo = (id) => {\n    set({\n      ...state,\n      items: state.items.filter((item) => item.id !== id),\n    });\n  };\n\n  return (\n    <section>\n      <header>\n        <h1>useHistoryState</h1>\n        <div>\n          <button disabled={!canUndo} className=\"link\" onClick={undo}>\n            Undo\n          </button>\n          <button disabled={!canRedo} className=\"link\" onClick={redo}>\n            Redo\n          </button>\n\n          <button\n            disabled={!state.items.length}\n            className=\"link\"\n            onClick={clear}\n          >\n            Clear\n          </button>\n        </div>\n        <Form addItem={addTodo} />\n      </header>\n\n      <ul>\n        {state.items.map((item, index) => {\n          return (\n            <li key={index}>\n              <span>{item.name}</span>\n              <button className=\"link\" onClick={() => removeTodo(item.id)}>\n                Delete\n              </button>\n            </li>\n          );\n        })}\n      </ul>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useHover.mdx",
    "content": "---\nname: useHover\nrank: 24\ntagline: Track whether an element is being hovered over with useHover.\nsandboxId: usehover-9lxxmo\npreviewHeight: 420px\nrelatedHooks:\n  - uselockbodyscroll\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useHover hook allows you to track whether an element is being hovered over\n  or not. The hook returns a reference to attach to the target element and the\n  current hovering status, enabling you to apply conditional rendering or\n  perform any desired actions based on the hover state.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  The `useHover` hook returns an array with the following elements:\n\n  <div class=\"table-container\">\n  | Index | Type    | Description                                                                |\n  | ----- | ------- | -------------------------------------------------------------------------- |\n  | 0     | ref     | A ref object that can be attached to the element intended to be hovered.   |\n  | 1     | boolean | A boolean value indicating whether the element is currently being hovered. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useHover } from \"@uidotdev/usehooks\";\n\nfunction getRandomColor() {\n  const colors = [\"green\", \"blue\", \"purple\", \"red\", \"pink\"];\n  return colors[Math.floor(Math.random() * colors.length)];\n}\n\nexport default function App() {\n  const [ref, hovering] = useHover();\n\n  const backgroundColor = hovering\n    ? `var(--${getRandomColor()})`\n    : \"var(--charcoal)\";\n\n  return (\n    <section>\n      <h1>useHover</h1>\n      <article ref={ref} style={{ backgroundColor }}>\n        Hovering? {hovering ? \"Yes\" : \"No\"}\n      </article>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useIdle.mdx",
    "content": "---\nname: useIdle\nrank: 33\ntagline: Detect user inactivity with useIdle.\nsandboxId: useidle-myg19f\npreviewHeight: 200px\nrelatedHooks:\n  - usevisibilitychange\n  - usebattery\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useIdle hook is a useful tool for detecting user inactivity within a web\n  application. It tracks user interaction and determines if a specified duration\n  of time has passed without any activity. This hook is particularly handy for\n  implementing features like automatic logout, displaying notifications after a\n  period of inactivity, or adjusting UI elements based on user engagement.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name | Type   | Description |\n  | ---- | ------ | ----------- |\n  | ms   | number | This is the duration of idle time (in milliseconds) after which the `idle` state will be set to `true`. The default value is `20 * 1000` (20 seconds). |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name | Type    | Description |\n  | ---- | ------- | ----------- |\n  | idle | boolean | A boolean indicating if the user is idle. It is `true` if the user has been idle for at least `ms` milliseconds. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useIdle } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const idle = useIdle(5000);\n  return (\n    <section>\n      <h1>useIdle</h1>\n      <div>\n        <span className={idle ? \"idle\" : \"\"} />\n        <label>Status: {idle ? \"Idle\" : \"Active\"}</label>\n      </div>\n      {idle ? <p>Time to move your mouse</p> : <p>Hold still and wait</p>}\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useIntersectionObserver.mdx",
    "content": "---\nname: useIntersectionObserver\nrank: 5\ntagline: Track and manage the visibility of your DOM elements within the viewport with useIntersectionObserver.\nsandboxId: useintersectionobserver-uxlxkn\npreviewHeight: 500px\nrelatedHooks:\n  - usemeasure\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useIntersectionObserver hook is useful because it provides a\n  straightforward, built-in method for tracking the visibility and position of a\n  DOM element in relation to the viewport. By leveraging the Intersection\n  Observer API, it can greatly optimize performance and provide efficient,\n  real-time updates for lazy-loading, infinite scrolling, or other\n  visibility-dependent elements. With customizable thresholds and root margins,\n  developers have fine-grained control over when the hook triggers, improving\n  the user experience by dynamically loading content only when necessary.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name       | Type    | Default | Description                                                                                                                                                                                                                                                |\n  | ---------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n  | threshold  | number  | 1       | Either a single number or an array of numbers between 0 and 1, indicating at what percentage of the target’s visibility the observer’s callback should be executed.                                                                                        |\n  | root       | element | null    | The Element that is used as the viewport for checking visibility of the target. Defaults to the browser viewport if not specified or if null.                                                                                                              |\n  | rootMargin | string  | \"0%\"    | Margin around the root. Can have values similar to the CSS margin property. The values can be percentages. This set of values serves to grow or shrink each side of the root element’s bounding box before computing intersections. Defaults to all zeros. |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name  | Type             | Description                                                                                                     |\n  | ----- | ---------------- | --------------------------------------------------------------------------------------------------------------- |\n  | ref   | React ref object | A React reference that can be attached to a DOM element to observe.                                             |\n  | entry | object           | An object containing information about the intersection. This object is similar to `IntersectionObserverEntry`. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useIntersectionObserver } from \"@uidotdev/usehooks\";\nimport demoData from \"./demoData\";\n\nconst Section = ({ imgUrl, caption, href }) => {\n  const [ref, entry] = useIntersectionObserver({\n    threshold: 0,\n    root: null,\n    rootMargin: \"0px\",\n  });\n\n  return (\n    <section>\n      <figure ref={ref}>\n        {entry?.isIntersecting && (\n          <>\n            <img src={imgUrl} alt={caption} />\n            <figcaption>\n              <a href={href} alt={caption} target=\"_blank\" rel=\"noreferrer\">\n                {caption}\n              </a>\n            </figcaption>\n          </>\n        )}\n      </figure>\n    </section>\n  );\n};\n\nexport default function App() {\n  return (\n    <main>\n      <header>\n        <h1>useIntersectionObserver</h1>\n        <h6>\n          (Memes from <a href=\"https://bytes.dev\">bytes.dev</a>)\n        </h6>\n      </header>\n\n      {demoData.map(({ imgUrl, href, caption }, index) => {\n        return (\n          <Section key={index} imgUrl={imgUrl} href={href} caption={caption} />\n        );\n      })}\n    </main>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useInterval.mdx",
    "content": "---\nname: useInterval\nexperimental: true\nrank: 19\ntagline: Schedule periodic actions like data polling or animations with useInterval.\nsandboxId: useinterval-81c43g\npreviewHeight: 500px\nrelatedHooks:\n  - useintervalwhen\n  - usecontinuousretry\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useInterval hook provides a convenient way to create and manage intervals.\n  The hook sets up an interval that repeatedly invokes the callback function at\n  the specified interval. The interval is automatically cleared when the\n  component unmounts or when the interval duration changes. This hook is useful\n  for scenarios where you need to perform a certain action or update the\n  component periodically, such as polling for data updates or implementing\n  animations.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name | Type     | Description                                                     |\n  | ---- | -------- | --------------------------------------------------------------- |\n  | cb   | function | The callback function to be executed at the specified interval. |\n  | ms   | number   | The interval duration in milliseconds.                          |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name          | Type     | Description                                              |\n  | ------------- | -------- | -------------------------------------------------------- |\n  | clearInterval | function | A function to clear the interval and stop the execution. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useInterval } from \"@uidotdev/usehooks\";\n\nconst colors = [\"green\", \"blue\", \"purple\", \"red\", \"pink\", \"beige\", \"yellow\"];\n\nexport default function App() {\n  const [running, setIsRunning] = React.useState(true);\n  const [index, setIndex] = React.useState(0);\n\n  const clear = useInterval(() => {\n    setIndex(index + 1);\n  }, 1000);\n\n  const handleStop = () => {\n    clear();\n    setIsRunning(false);\n  };\n\n  const color = colors[index % colors.length];\n  return (\n    <section>\n      <h1>useInterval</h1>\n      <button disabled={!running} className=\"link\" onClick={handleStop}>\n        {running ? \"Stop\" : \"Stopped\"}\n      </button>\n      <div style={{ backgroundColor: `var(--${color})` }} />\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useIntervalWhen.mdx",
    "content": "---\nname: useIntervalWhen\nexperimental: true\nrank: 18\ntagline: Create dynamic timers that can be started, paused, or resumed with useIntervalWhen.\nsandboxId: useintervalwhen-cp7e31\npreviewHeight: 400px\nrelatedHooks:\n  - userandominterval\n  - usecontinuousretry\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useIntervalWhen hook is useful for creating an interval timer that can be\n  controlled based on certain conditions. It allows you to specify a callback\n  function to be executed at a regular interval specified by the ms parameter.\n  Additionally, you can choose whether the interval should start immediately or\n  wait for a trigger by setting the startImmediately parameter. This hook is\n  particularly handy when you need to create dynamic timers that can be started,\n  paused, or resumed based on specific conditions.\n</HookDescription>\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name                     | Type     | Description                                                                                         |\n  | ------------------------ | -------- | --------------------------------------------------------------------------------------------------- |\n  | cb                       | function | The callback function to be executed at the specified interval when the condition is met.           |\n  | options                  | object   | An object containing the following options.                                                         |\n  | options.ms               | number   | The interval duration in milliseconds.                                                              |\n  | options.when             | boolean  | The condition that determines whether the interval should be active (`true`) or paused (`false`).   |\n  | options.startImmediately | boolean  | (Optional) Whether to start the interval immediately when the condition is met. Default is `false`. |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Type     | Description                                               |\n  | -------- | --------------------------------------------------------- |\n  | function | A function to clear the interval and pause the execution. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useIntervalWhen } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [count, setCount] = React.useState(0);\n  const [when, setWhen] = React.useState(false);\n\n  useIntervalWhen(\n    () => {\n      setCount((c) => c + 0.1);\n    },\n    { ms: 100, when, startImmediately: true }\n  );\n\n  return (\n    <section>\n      <h1>useIntervalWhen</h1>\n      <button title=\"Click to toggle the timer\" onClick={() => setWhen(!when)}>\n        {count.toLocaleString(\"en-US\", {\n          maximumFractionDigits: 2,\n          minimumFractionDigits: 2,\n        })}\n        <span className=\"btn link\">{when ? \"stop\" : \"start\"}</span>\n      </button>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useIsClient.mdx",
    "content": "---\nname: useIsClient\nrank: 22\ntagline: Determine whether the code is running on the client-side or server-side with useIsClient.\nsandboxId: useisclient-4edyux\npreviewHeight: 240px\nrelatedHooks:\n  - userenderinfo\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  useIsClient is useful for determining if it's safe to run certain client-only hooks like useMediaQuery or useLocalStorage. It returns a boolean determining if React's useEffect hook has finished running (which means the app is being rendered on the client and it's safe to use browser specific APIs).\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  The `useIsClient` hook does not accept any parameters.\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name     | Type    | Description                                                        |\n  | -------- | ------- | ------------------------------------------------------------------ |\n  | isClient | boolean | `true` if running in a client-side environment, `false` otherwise. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useIsClient } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const isClient = useIsClient();\n\n  return (\n    <section>\n      <h1>useIsClient</h1>\n      <h6>Is Client? </h6>\n      <p>{isClient ? \"If you can see this ... you already know\" : \"No\"}</p>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useIsFirstRender.mdx",
    "content": "---\nname: useIsFirstRender\nrank: 41\ntagline: Differentiate between the first and subsequent renders with useIsFirstRender.\nsandboxId: useisfirstrender-rny2tm\npreviewHeight: 300px\nrelatedHooks:\n  - userendercount\n  - uselogger\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useIsFirstRender hook is a useful for determining whether the current\n  render is the first render of a component. This hook is particularly valuable\n  when you want to conditionally execute certain logic or render specific\n  components only on the initial render, providing an efficient way to\n  differentiate between the first and subsequent renders.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name          | Type    | Description                                      |\n  | ------------- | ------- | ------------------------------------------------ |\n  | isFirstRender | boolean | `true` for the first render, `false` for others. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useIsFirstRender } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const isFirstRender = useIsFirstRender();\n  const [count, rerender] = React.useReducer((x) => x + 1, 1);\n\n  return (\n    <section>\n      <h1>useIsFirstRender</h1>\n      <h2>First Render? {isFirstRender ? \"Yes\" : \"No\"}</h2>\n      <button className=\"primary\" onClick={rerender}>\n        re-render\n      </button>\n      <p>Render Count: {count}</p>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useKeyPress.mdx",
    "content": "---\nname: useKeyPress\nexperimental: true\nrank: 27\ntagline: Detect and perform actions on key press events with useKeyPress.\nsandboxId: usekeypress-7vgzwf\npreviewHeight: 350px\nrelatedHooks:\n  - useeventlistener\n  - usehover\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useKeyPress hook is a useful for detecting key presses and performing\n  specific actions based on the pressed key. By calling useKeyPress with the\n  desired key and callback function, the hook sets up an event listener that\n  triggers the callback when the specified key is pressed.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name                 | Type                  | Description                                                                                            |\n  | -------------------- | --------------------- | ------------------------------------------------------------------------------------------------------ |\n  | key                  | string                | The key to listen for.                                                                                 |\n  | cb                   | function              | The callback function to be executed when the key is pressed.                                          |\n  | options              | object                | (Optional) Additional options for the key press event.                                                 |\n  | options.event        | string                | (Optional) The event type to listen for. Default is `\"keydown\"`.                                       |\n  | options.target       | DOM element or window | (Optional) The target element or `window` object to attach the event listener to. Default is `window`. |\n  | options.eventOptions | object                | (Optional) Additional options for the event listener.                                                  |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useKeyPress } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [activeKey, setActiveKey] = React.useState(\"\");\n\n  useKeyPress(\"ArrowRight\", onKeyPress);\n  useKeyPress(\"ArrowLeft\", onKeyPress);\n  useKeyPress(\"ArrowUp\", onKeyPress);\n  useKeyPress(\"ArrowDown\", onKeyPress);\n\n  function onKeyPress(e) {\n    e.preventDefault();\n    setActiveKey(e.key);\n    setTimeout(() => {\n      setActiveKey(\"\");\n    }, 600);\n  }\n\n  return (\n    <section>\n      <h1>useKeyPress</h1>\n      <p>Press one of the arrow keys on your keyboard</p>\n      <article>\n        <button className={activeKey === \"ArrowUp\" ? \"pressed\" : \"\"}>\n          <span>&uarr;</span>\n        </button>\n        <button className={activeKey === \"ArrowLeft\" ? \"pressed\" : \"\"}>\n          <span>&larr;</span>\n        </button>\n        <button className={activeKey === \"ArrowDown\" ? \"pressed\" : \"\"}>\n          <span>&darr;</span>\n        </button>\n        <button className={activeKey === \"ArrowRight\" ? \"pressed\" : \"\"}>\n          <span>&rarr;</span>\n        </button>\n      </article>\n      {Boolean(activeKey) && <label>{activeKey} was pressed</label>}\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useList.mdx",
    "content": "---\nname: useList\nrank: 48\ntagline: Manage and manipulate lists with useList.\nsandboxId: uselist-5mmpw2\npreviewHeight: 550px\nrelatedHooks:\n  - usehistorystate\n  - useprevious\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useList hook is useful for managing and manipulating lists in a React\n  component. It encapsulates the list state and provides a set of convenient\n  methods to modify the list. By using this hook, you can easily initialize a\n  list with a default value and access various methods to add, remove, update,\n  or clear elements within the list.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name        | Type  | Description                                              |\n  | ----------- | ----- | -------------------------------------------------------- |\n  | defaultList | array | The initial list of elements. Default is an empty array. |\n  </div>\n\n  ### Return Value\n\n  The `useList` hook returns an array with two elements:\n\n  <div class=\"table-container\">\n  | Name           | Parameters                  | Description                                                       |\n  | -------------- | --------------------------- | ----------------------------------------------------------------- |\n  | `[0]`          |                             | The current list of elements.                                     |\n  | `[1].set`      | l: array                    | Replaces the entire list with a new array `l`.                    |\n  | `[1].push`     | element: any                | Appends the `element` to the end of the list.                     |\n  | `[1].removeAt` | index: number               | Removes the element at the specified `index` from the list.       |\n  | `[1].insertAt` | index: number, element: any | Inserts the `element` at the specified `index` in the list.       |\n  | `[1].updateAt` | index: number, element: any | Replaces the element at the specified `index` with the `element`. |\n  | `[1].clear`    |                             | Removes all elements from the list.                               |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport { useList } from \"@uidotdev/usehooks\";\nimport ListDemo from \"./ListDemo\";\n\nexport default function App() {\n  const [list, { set, push, removeAt, insertAt, updateAt, clear }] = useList([\n    \"First\",\n    \"Second\",\n    \"Third\",\n  ]);\n\n  return (\n    <section>\n      <header>\n        <h1>UseList</h1>\n        <button\n          disabled={list.length < 1}\n          className=\"link\"\n          onClick={() => insertAt(1, \"woo\")}\n        >\n          Insert After First\n        </button>\n        <button\n          disabled={list.length < 2}\n          className=\"link\"\n          onClick={() => removeAt(1)}\n        >\n          Remove Second Item\n        </button>\n        <button className=\"link\" onClick={() => set([1, 2, 3])}>\n          Reset\n        </button>\n        <button className=\"link\" onClick={() => clear()}>\n          Clear\n        </button>\n      </header>\n      <ListDemo\n        list={list}\n        updateAt={updateAt}\n        push={push}\n        removeAt={removeAt}\n      />\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useLocalStorage.mdx",
    "content": "---\nname: useLocalStorage\nrank: 2\ntagline: Store, retrieve, and synchronize data from the browser’s localStorage API with useLocalStorage\nsandboxId: uselocalstorage-e6v6ey\npreviewHeight: 670px\nrelatedHooks:\n  - usesessionstorage\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useLocalStorage hook provides a convenient way to synchronize the state of\n  a component with the data stored in local storage. It automatically reads the\n  initial value from local storage when the component mounts and updates the\n  local storage whenever the state changes. Additionally, it listens for changes\n  in local storage made by other tabs or windows and keeps the component’s state\n  up to date.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name | Type | Description |\n  |------|------|-------------|\n  | key | string | The key used to access the local storage value. |\n  | initialValue | any | The initial value to use if there is no item in the local storage with the provided key. |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name | Type | Description |\n  |------|------|-------------|\n  | localState | any | The current state of the value stored in local storage. |\n  | handleSetState | function | A function to set the state of the value in the local storage. This function accepts a new value or a function that returns a new value. The value is also saved in the local storage under the provided key. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useLocalStorage } from \"@uidotdev/usehooks\";\nimport createDrawing from \"./createDrawing\";\n\nexport default function App() {\n  const [drawing, saveDrawing] = useLocalStorage(\"drawing\", null);\n  const ref = React.useRef(null);\n  React.useEffect(() => {\n    createDrawing(ref.current, drawing, saveDrawing);\n  }, [drawing, saveDrawing]);\n\n  return (\n    <section>\n      <header>\n        <h1>useLocalStorage</h1>\n\n        <button className=\"link\" onClick={() => window.location.reload()}>\n          Reload Window\n        </button>\n        <button\n          className=\"link\"\n          onClick={() => {\n            window.localStorage.clear();\n            window.location.reload();\n          }}\n        >\n          Clear Local Storage\n        </button>\n      </header>\n      <figure>\n        <canvas ref={ref} width={800} height={800} />\n        <figcaption>(draw something)</figcaption>\n      </figure>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useLockBodyScroll.mdx",
    "content": "---\nname: useLockBodyScroll\nrank: 20\ntagline: Temporarily disable scrolling on the document body with useLockBodyScroll.\nsandboxId: uselockbodyscroll-on17pi\npreviewHeight: 500px\nrelatedHooks:\n  - usescript\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useLockBodyScroll hook temporarily disables scrolling on the document\n  body. This can be beneficial in scenarios where you want to restrict scrolling\n  while displaying a modal, a dropdown menu, or any other component that\n  requires the user’s focus. Once the component using this hook is unmounted or\n  no longer needed, the hook returns a cleanup function that restores the\n  original overflow style, ensuring that the scroll behavior is reverted to its\n  previous state.\n</HookDescription>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useLockBodyScroll } from \"@uidotdev/usehooks\";\nimport { closeIcon } from \"./icons\";\nimport DemoContent from \"./DemoContent\";\n\nfunction Modal({ handleClose }) {\n  useLockBodyScroll();\n\n  return (\n    <div>\n      <dialog>\n        <header>\n          <button onClick={handleClose}>{closeIcon}</button>\n          <h2>Modal</h2>\n        </header>\n        <section>\n          <DemoContent />\n        </section>\n      </dialog>\n    </div>\n  );\n}\n\nexport default function App() {\n  const [isOpen, setIsOpen] = React.useState(false);\n  return (\n    <>\n      {isOpen && <Modal handleClose={() => setIsOpen(false)} />}\n      <main>\n        <header>\n          <h1>useLockBodyScroll</h1>\n        </header>\n        {[\"red\", \"blue\", \"green\", \"pink\", \"purple\", \"yellow\"].map((color) => {\n          return (\n            <section\n              style={{\n                backgroundColor: `var(--${color})`,\n                width: \"100%\",\n                height: \"50vh\",\n              }}\n            />\n          );\n        })}\n        <button className=\"primary\" onClick={() => setIsOpen(true)}>\n          openModal\n        </button>\n      </main>\n    </>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useLogger.mdx",
    "content": "---\nname: useLogger\nexperimental: true\nrank: 39\ntagline: Debug lifecycle events with useLogger.\nsandboxId: uselogger-o2e03i\npreviewHeight: 500px\nrelatedHooks:\n  - userendercount\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useLogger hook is useful for logging various lifecycle events in a React\n  component. This custom hook accepts a name parameter and additional arguments,\n  and it logs the lifecycle events (mounted, updated, and unmounted) along with\n  the provided name and arguments. This useLogger hook can be employed to\n  facilitate debugging, monitoring, or performance optimization by providing\n  insights into when and how a component’s lifecycle events occur.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name    | Type   | Description                            |\n  | ------- | ------ | -------------------------------------- |\n  | name    | string | The name or identifier for the logger. |\n  | ...rest | any    | Additional arguments to be logged.     |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useLogger } from \"@uidotdev/usehooks\";\n\nfunction FirstChild(props) {\n  useLogger(props.name, props);\n  return (\n    <li className={props.isActive ? \"active\" : \"\"}>\n      <h5>{props.name}</h5>\n      <p>{props.count}</p>\n    </li>\n  );\n}\n\nexport default function App() {\n  const [count, setCount] = React.useState(0);\n\n  const handleClick = () => setCount(count + 1);\n\n  return (\n    <section>\n      <h1>useLogger</h1>\n      <h6>(Check the console)</h6>\n      <button className=\"primary\" onClick={handleClick}>\n        Increment Count\n      </button>\n      <ul>\n        {[\"First\", \"Second\", \"Third\"].map((item, index) => {\n          const isActive = count % 3 === index;\n          return (\n            <FirstChild\n              key={index}\n              name={item}\n              isActive={isActive}\n              count={count}\n            />\n          );\n        })}\n      </ul>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useLongPress.mdx",
    "content": "---\nname: useLongPress\nrank: 42\ntagline: Enable precise control of long-press interactions for both touch and mouse events with useLongPress.\nsandboxId: uselongpress-0fpxj6\npreviewHeight: 240px\nrelatedHooks:\n  - usemeasure\n  - usetoggle\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useLongPress hook enhances React applications by managing long-press\n  interactions for both mouse and touch events, thereby ensuring a consistent\n  user experience across devices. This hook not only broadens user interactivity\n  but also allows for customization, providing developers the flexibility to\n  adjust the long-press functionality according to their application needs.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name                 | Type     | Description |\n  | -------------------- | -------- | ----------- |\n  | callback             | function | This is the function to be executed when a long press event is detected. |\n  | options              | object   | This is an optional configuration object provided when calling `useLongPress`. |\n  | options.threshold    | number   | This is the time (in milliseconds) the user must press and hold to trigger a long press event. Default value is `400`. |\n  | options.onStart      | function | This function is called when the user starts pressing. |\n  | options.onFinish     | function | This function is called when a long press event finishes successfully (the user releases after the threshold). |\n  | options.onCancel     | function | This function is called when a press event is cancelled (the user releases before the threshold). |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name         | Type     | Description |\n  | ------------ | -------- | ----------- |\n  | onMouseDown  | function | This is the mouse down event handler. |\n  | onMouseUp    | function | This is the mouse up event handler. |\n  | onMouseLeave | function | This is the mouse leave event handler. |\n  | onTouchStart | function | This is the touch start event handler. |\n  | onTouchEnd   | function | This is the touch end event handler. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useLongPress } from \"@uidotdev/usehooks\";\nimport { closeIcon } from \"./icons\";\n\nexport default function App() {\n  const [isOpen, setIsOpen] = React.useState(false);\n  const attrs = useLongPress(\n    () => {\n      setIsOpen(true);\n    },\n    {\n      onStart: (event) => console.log(\"Press started\"),\n      onFinish: (event) => console.log(\"Press Finished\"),\n      onCancel: (event) => console.log(\"Press cancelled\"),\n      threshold: 500,\n    }\n  );\n\n  return (\n    <section>\n      <h1>useLongPress</h1>\n      <button {...attrs} className=\"primary\">\n        Press Me\n      </button>\n      {isOpen && (\n        <dialog>\n          <button onClick={() => setIsOpen(false)}>{closeIcon}</button>\n          <h2>Modal</h2>\n          <p>This is a modal triggered by a long press.</p>\n        </dialog>\n      )}\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useMap.mdx",
    "content": "---\nname: useMap\nrank: 28\ntagline: Synchronize and update state based on the Map data structure with useMap.\nsandboxId: usemap-ev8nd1\npreviewHeight: 300px\nrelatedHooks:\n  - usequeue\n  - useset\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useMap hook provides a wrapper around the JavaScript Map object and allows\n  you to easily update and synchronize the map state with the component’s\n  rendering. By using this hook, you can add, delete, or clear entries in the\n  map while ensuring that the component re-renders whenever these operations are\n  performed.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name | Type       | Description                                            |\n  | ---- | ---------- | ------------------------------------------------------ |\n  | map  | map object | An instance of the `Map` object with enhanced methods. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useMap } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const map = useMap([\n    [\"Jazz\", 32],\n    [\"Suns\", 50],\n  ]);\n\n  return (\n    <section>\n      <h1>useMap</h1>\n      <table>\n        <thead>\n          <tr>\n            <th colSpan={4}>Jazz vs Suns</th>\n          </tr>\n        </thead>\n        <tbody>\n          {Array.from(map.keys()).map((team) => {\n            const score = map.get(team);\n            return (\n              <tr key={team}>\n                <th style={{ width: \"25%\" }}>{team}</th>\n                <td style={{ width: \"50%\" }}>{score}</td>\n                <td style={{ width: \"12.5%\" }}>\n                  <button\n                    className=\"link\"\n                    onClick={() => {\n                      map.set(team, score + 2);\n                    }}\n                  >\n                    + 2\n                  </button>\n                </td>\n                <td style={{ width: \"12.5%\" }}>\n                  <button\n                    className=\"link\"\n                    onClick={() => {\n                      map.set(team, score + 3);\n                    }}\n                  >\n                    + 3\n                  </button>\n                </td>\n              </tr>\n            );\n          })}\n        </tbody>\n      </table>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useMeasure.mdx",
    "content": "---\nname: useMeasure\nrank: 46\ntagline: Effortlessly measure and track your component’s dimensions with useMeasure.\nsandboxId: usemeasure-3kyegb\npreviewHeight: 300px\nrelatedHooks:\n  - usepreferredlanguage\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useMeasure hook provides a convenient and efficient way to monitor and\n  respond to changes in the size of a React component. This custom hook uses the\n  ResizeObserver API to actively track changes in the component’s dimensions,\n  such as width and height, and keeps them available as state. The returned ref\n  is used on the element whose dimensions you want to measure, making it a\n  valuable tool for responsive design and dynamic layout adjustments.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name | Type | Description |\n  | --- | --- | --- |\n  | ref | React ref object | A React reference that can be attached to a DOM element to observe. |\n  | rect | object | An object containing the width and height of the observed element. |\n  </div>\n\n  ### rect Object Properties\n\n  <div class=\"table-container\">\n  | Property | Type | Description |\n  | --- | --- | --- |\n  | width | number | Width of the observed element. |\n  | height | number | Height of the observed element. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useMeasure } from \"@uidotdev/usehooks\";\n\nfunction Measure({ type = \"horizontal\" }) {\n  const [ref, { width, height }] = useMeasure();\n\n  return (\n    <figure>\n      <figcaption>\n        <span>{type}</span>\n      </figcaption>\n      <article\n        ref={ref}\n        className={type}\n        style={{\n          resize: type\n        }}\n      >\n        {type === \"horizontal\" ? (\n          <label>width: {Math.floor(width)}</label>\n        ) : (\n          <label>height: {Math.floor(height)}</label>\n        )}\n      </article>\n    </figure>\n  );\n}\n\nexport default function App() {\n  return (\n    <section>\n      <h1>useMeasure</h1>\n      <p>(Resize the rulers)</p>\n      <Measure />\n    </section>\n  );\n}\n\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useMediaQuery.mdx",
    "content": "---\nname: useMediaQuery\nrank: 7\ntagline: Subscribe and respond to media query changes with useMediaQuery.\nsandboxId: usemediaquery-qu6bcp\npreviewHeight: 400px\nrelatedHooks:\n  - useintersectionobserver\n  - usemeasure\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useMediaQuery hook leverages the window.matchMedia API to subscribe to CSS\n  media query changes, thereby providing real-time responsiveness to dynamic\n  changes in the viewport or screen orientation. It allows the component to\n  rerender whenever the media query’s result changes. It throws an error if\n  attempted to be used on the server-side (media queries only work in the\n  browser).\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name  | Type   | Description                       |\n  | ----- | ------ | --------------------------------- |\n  | query | string | The media query to listen changes |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Type    | Description                                                                                         |\n  | ------- | --------------------------------------------------------------------------------------------------- |\n  | boolean | Returns a boolean value indicating whether the media query matches the current state of the device. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useMediaQuery } from \"@uidotdev/usehooks\";\nimport { phone, tablet, laptop, desktop } from \"./icons\";\n\nexport default function App() {\n  const isSmallDevice = useMediaQuery(\"only screen and (max-width : 768px)\");\n  const isMediumDevice = useMediaQuery(\n    \"only screen and (min-width : 769px) and (max-width : 992px)\"\n  );\n  const isLargeDevice = useMediaQuery(\n    \"only screen and (min-width : 993px) and (max-width : 1200px)\"\n  );\n  const isExtraLargeDevice = useMediaQuery(\n    \"only screen and (min-width : 1201px)\"\n  );\n\n  return (\n    <section>\n      <h1>useMediaQuery</h1>\n      Resize your browser windows to see changes.\n      <article>\n        <figure className={isSmallDevice ? \"active\" : \"\"}>\n          {phone}\n          <figcaption>Small</figcaption>\n        </figure>\n        <figure className={isMediumDevice ? \"active\" : \"\"}>\n          {tablet}\n          <figcaption>Medium</figcaption>\n        </figure>\n        <figure className={isLargeDevice ? \"active\" : \"\"}>\n          {laptop}\n          <figcaption>Large</figcaption>\n        </figure>\n        <figure className={isExtraLargeDevice ? \"active\" : \"\"}>\n          {desktop}\n          <figcaption>Extra Large</figcaption>\n        </figure>\n      </article>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useMouse.mdx",
    "content": "---\nname: useMouse\nrank: 50\ntagline: Track and retrieve the position of the mouse cursor with useMouse.\nsandboxId: usemouse-8yu3mi\npreviewHeight: 450px\nrelatedHooks:\n  - usehover\n  - useeventlistener\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useMouse hook is useful for tracking and retrieving the position of the\n  mouse cursor within a component. By utilizing this hook, developers can easily\n  access information such as the current coordinates of the mouse cursor (x and\n  y), the position of the mouse cursor relative to an element within the\n  component (elementX and elementY), and the position of that element on the\n  page (elementPositionX and elementPositionY).\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  None.\n\n  ### Return Value\n\n  The `useMouse` hook returns an array with two elements:\n\n  <div class=\"table-container\">\n  | Name    | Type   | Description                                                                      |\n  | ------- | ------ | -------------------------------------------------------------------------------- |\n  | `state` | object | An object representing the current mouse position and element information.       |\n  | `ref`   | object | A ref object that can be used to track the mouse position on a specific element. |\n  </div>\n\n  The `state` object has the following properties:\n\n  <div class=\"table-container\">\n  | Name                     | Type   | Description                                                                             |\n  | ------------------------ | ------ | --------------------------------------------------------------------------------------- |\n  | `state.x`                | number | The current horizontal position of the mouse relative to the page.                      |\n  | `state.y`                | number | The current vertical position of the mouse relative to the page.                        |\n  | `state.elementX`         | number | The current horizontal position of the mouse relative to the element’s top-left corner. |\n  | `state.elementY`         | number | The current vertical position of the mouse relative to the element’s top-left corner.   |\n  | `state.elementPositionX` | number | The current horizontal position of the element relative to the page.                    |\n  | `state.elementPositionY` | number | The current vertical position of the element relative to the page.                      |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useMouse } from \"@uidotdev/usehooks\";\nimport Demo from \"./Demo\";\n\nexport default function App() {\n  const [mouse, ref] = useMouse();\n\n  const xIntersecting = mouse.elementX > 0 && mouse.elementX < 300;\n  const yIntersecting = mouse.elementY > 0 && mouse.elementY < 300;\n  const isIntersecting = xIntersecting && yIntersecting;\n\n  return (\n    <section>\n      <h1>useMouse</h1>\n      <article\n        ref={ref}\n        style={{ width: \"300px\", height: \"300px\" }}\n        className={isIntersecting ? \"active\" : \"\"}\n      >\n        Use a ref to add coords relative to the element\n      </article>\n      <Demo {...mouse} />\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useNetworkState.mdx",
    "content": "---\nname: useNetworkState\nrank: 6\ntagline: Monitor and adapt to network conditions seamlessly with useNetworkState.\nsandboxId: usenetworkstate-k4t3qt\npreviewHeight: 400px\nrelatedHooks:\n  - usepreferredlanguage\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useNetworkState React hook delivers real-time insights about the network\n  status in your application, helping to adapt app behavior to varying\n  connectivity conditions. It offers up-to-date snapshots of the network state,\n  such as online/offline status, connection speed, and type. Through its use,\n  you can respond effectively to network changes, fostering a seamless user\n  experience even under unstable or varying connectivity. Please note, this hook\n  is intended for client-side use only.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  The `useNetworkState` hook returns an object representing the current network state with the following properties:\n\n  <div class=\"table-container\">\n  | Name          | Type    | Description                                                                                                                                                                                          |\n  | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n  | online        | boolean | Indicates whether the browser is online or offline.                                                                                                                                                  |\n  | downlink      | number  | The effective bandwidth estimate in megabits per second, rounded to the nearest multiple of 25 kilobits per seconds.                                                                                 |\n  | downlinkMax   | number  | The maximum downlink speed, in megabits per second (Mbps), for the underlying connection technology.                                                                                                 |\n  | effectiveType | string  | The effective type of the connection for general web browsing purposes (either 'slow-2g', '2g', '3g', or '4g').                                                                                      |\n  | rtt           | number  | The estimated round-trip latency of the connection, in milliseconds.                                                                                                                                 |\n  | saveData      | boolean | Whether the user has requested a reduced data usage mode from the user agent.                                                                                                                        |\n  | type          | string  | The type of connection a device is using to communicate with the network. It could be one of the following values: 'bluetooth', 'cellular', 'ethernet', 'none', 'wifi', 'wimax', 'other', 'unknown'. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useNetworkState } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const network = useNetworkState();\n\n  return (\n    <section>\n      <h1>useNetworkState</h1>\n      <table>\n        <tbody>\n          {Object.keys(network).map((key) => {\n            return (\n              <tr key={key} className={key}>\n                <th>{key}</th>\n                <td>{`${network[key]}`}</td>\n              </tr>\n            );\n          })}\n        </tbody>\n      </table>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useObjectState.mdx",
    "content": "---\nname: useObjectState\nrank: 38\ntagline: Manage complex state objects with useObjectState.\nsandboxId: useobjectstate-75lmg2\npreviewHeight: 350px\nrelatedHooks:\n  - usevisibilitychange\n  - useset\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useObjectState hook is useful for managing complex state objects. It\n  provides a convenient way to initialize and update state values using a single\n  hook. By using this hook, you can easily create and maintain state objects\n  with initial values, and then update them through a flexible \"handleUpdate\"\n  function. This function accepts either a callback function or an object,\n  allowing you to merge new values into the existing state object.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name         | Type   | Description                         |\n  | ------------ | ------ | ----------------------------------- |\n  | initialValue | object | (Optional) The initial state value. |\n  </div>\n\n  ### Return Value\n\n  The `useObjectState` hook returns an array with the following elements:\n\n  <div class=\"table-container\">\n  | Index | Type     | Description                            |\n  | ----- | -------- | -------------------------------------- |\n  | 0     | object   | The current state object.              |\n  | 1     | function | A function to update the state object. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useObjectState } from \"@uidotdev/usehooks\";\n\nconst initialState = {\n  team: \"Utah Jazz\",\n  wins: 2138,\n  losses: 1789,\n  championships: 0,\n};\n\nexport default function App() {\n  const [stats, setStats] = useObjectState(initialState);\n\n  const addWin = () => {\n    setStats((s) => ({\n      wins: s.wins + 1,\n    }));\n  };\n\n  const addLoss = () => {\n    setStats((s) => ({\n      losses: s.losses + 1,\n    }));\n  };\n\n  const reset = () => {\n    setStats(initialState);\n  };\n\n  return (\n    <section>\n      <h1>useObjectState</h1>\n\n      <button className=\"link\" onClick={addWin}>\n        Add Win\n      </button>\n      <button className=\"link\" onClick={addLoss}>\n        Add Loss\n      </button>\n\n      <button className=\"link\" onClick={() => alert(\"lol\")}>\n        Add Championship\n      </button>\n      <button className=\"link\" onClick={reset}>\n        Reset\n      </button>\n\n      <table>\n        <thead>\n          <tr>\n            {Object.keys(stats).map((key) => {\n              return <th>{key}</th>;\n            })}\n          </tr>\n        </thead>\n        <tbody>\n          <tr>\n            {Object.keys(stats).map((key) => {\n              return <td>{`${stats[key]}`}</td>;\n            })}\n          </tr>\n        </tbody>\n      </table>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useOrientation.mdx",
    "content": "---\nname: useOrientation\nrank: 8\ntagline: Manage and respond to changes in device orientation with useOrientation.\nsandboxId: useorientation-f04nej\npreviewHeight: 400px\nrelatedHooks:\n  - usenetworkstate\n  - usemediaquery\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useOrientation React Hook simplifies the management of a device’s\n  orientation within a React application. It wraps the complexity of listening\n  for, handling, and cleaning up after orientation changes into a reusable hook.\n  By abstracting this logic, the hook allows you to easily track device\n  orientation, resulting in cleaner and more readable code. It adapts to both\n  the Screen Orientation API and the deprecated window.orientation property,\n  providing flexibility across different browser capabilities.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  This hook doesn’t accept any parameters.\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name  | Type   | Description                                                                                                                                                                                 |\n  | ----- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n  | angle | number | The current orientation angle of the device in degrees.                                                                                                                                     |\n  | type  | string | The current orientation type of the device (e.g., 'portrait-primary', 'landscape-primary', 'portrait-secondary', 'landscape-secondary'). If the type cannot be determined, it is 'UNKNOWN'. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useOrientation } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const orientation = useOrientation();\n\n  return (\n    <section>\n      <h1>useOrientation</h1>\n\n      <article\n        style={{ \"--angle\": `${orientation.angle}deg` }}\n        className={orientation.type.toLocaleLowerCase()}\n      />\n      <table>\n        <tbody>\n          {Object.keys(orientation).map((key) => {\n            return (\n              <tr key={key}>\n                <th>{key}</th>\n                <td>{orientation[key]}</td>\n              </tr>\n            );\n          })}\n        </tbody>\n      </table>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/usePageLeave.mdx",
    "content": "---\nname: usePageLeave\nexperimental: true\nrank: 37\ntagline: Track when a user navigates away from a webpage with usePageLeave.\nsandboxId: usepageleave-p8hjp3\npreviewHeight: 300px\nrelatedHooks:\n  - usevisibilitychange\n  - useset\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The usePageLeave hook is useful for tracking when a user leaves a webpage or\n  navigates away from it. When the mouseout event is triggered, the callback\n  function is executed only if the user’s cursor moves outside the webpage or\n  onto an element outside the webpage (e.g., the browser’s address bar). This\n  hook is beneficial for scenarios where you need to perform specific actions\n  when a user leaves your webpage, such as saving user progress, displaying a\n  confirmation prompt, or triggering analytics events.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name | Type     | Description                          |\n  | ---- | -------- | ------------------------------------ |\n  | cb   | function | The callback function to be invoked. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { usePageLeave } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [distractions, setDistractions] = React.useState(0);\n\n  usePageLeave(() => {\n    setDistractions((d) => d + 1);\n  });\n\n  return (\n    <section>\n      <h1>usePageLeave</h1>\n      <p>(Mouse out of the page)</p>\n      <h3>\n        You've been distracted {distractions}{\" \"}\n        {distractions === 1 ? \"time\" : \"times\"}.\n      </h3>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/usePreferredLanguage.mdx",
    "content": "---\nname: usePreferredLanguage\nrank: 10\ntagline: Adapt to user language preferences dynamically with usePreferredLanguage.\nsandboxId: usepreferredlanguage-v3dcoh\npreviewHeight: 300px\nrelatedHooks:\n  - usetoggle\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The usePreferredLanguage hook automatically adapts to the preferred language\n  of the user. The hook reactively returns a string that represents the\n  preferred language of the user, as set in the browser settings.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name          | Type   | Description                                                                                                   |\n  | ------------- | ------ | ------------------------------------------------------------------------------------------------------------- |\n  | language | string | The hook returns a string that represents the preferred language of the user, as set in the browser settings. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { usePreferredLanguage } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const language = usePreferredLanguage();\n\n  return (\n    <section>\n      <h1>usePreferredLanguage</h1>\n      <p>Change language here - chrome://settings/languages</p>\n      <h2>\n        The correct date format for <pre>{language}</pre> is{\" \"}\n        <time>{new Date(Date.now()).toLocaleDateString(language)}</time>\n      </h2>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/usePrevious.mdx",
    "content": "---\nname: usePrevious\nrank: 4\ntagline: Track the previous value of a variable with usePrevious.\nsandboxId: useprevious-diev3s\npreviewHeight: 600px\nrelatedHooks:\n  - usehistorystate\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The usePrevious hook is a useful tool for tracking the previous value of a\n  variable in a functional component. This can be particularly handy in\n  scenarios where it is necessary to compare the current value with the previous\n  one, such as triggering actions or rendering based on changes.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name     | Type | Description                                        |\n  | -------- | ---- | -------------------------------------------------- |\n  | newValue | any  | The new value to track and return the previous of. |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name          | Type | Description                                    |\n  | ------------- | ---- | ---------------------------------------------- |\n  | previousValue | any  | The previous value of the provided `newValue`. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { usePrevious } from \"@uidotdev/usehooks\";\n\nfunction getRandomColor() {\n  const colors = [\"green\", \"blue\", \"purple\", \"red\", \"pink\"];\n  return colors[Math.floor(Math.random() * colors.length)];\n}\n\nexport default function App() {\n  const [color, setColor] = React.useState(getRandomColor());\n  const previousColor = usePrevious(color);\n\n  const handleClick = () => {\n    function getNewColor() {\n      const newColor = getRandomColor();\n      if (color === newColor) {\n        getNewColor();\n      } else {\n        setColor(newColor);\n      }\n    }\n    getNewColor();\n  };\n\n  return (\n    <section>\n      <h1>usePrevious</h1>\n      <button className=\"link\" onClick={handleClick}>\n        Next\n      </button>\n      <article>\n        <figure>\n          <p style={{ background: `var(--${previousColor})` }} />\n          <figcaption>Previous: {previousColor}</figcaption>\n        </figure>\n        <figure>\n          <p style={{ background: `var(--${color})` }} />\n          <figcaption>Current: {color}</figcaption>\n        </figure>\n      </article>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useQueue.mdx",
    "content": "---\nname: useQueue\nrank: 23\ntagline: Add, remove, and clear element from a queue data structure with useQueue.\nsandboxId: usequeue-s7x0yg\npreviewHeight: 400px\nrelatedHooks:\n  - usemap\n  - useset\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useQueue hook is a useful tool for managing a queue of elements within a\n  functional component. It allows you to easily add, remove, and clear elements\n  from the queue while maintaining the necessary state updates. The hook returns\n  an object that includes the functions for manipulating the queue (add, remove,\n  and clear), as well as additional properties such as first, last, size, and\n  queue.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name         | Type  | Description                                                            |\n  | ------------ | ----- | ---------------------------------------------------------------------- |\n  | initialValue | array | (Optional) The initial value for the queue. Default is an empty array. |\n  </div>\n\n  ### Return Value\n\n  The `useQueue` hook returns an object with the following properties and methods:\n\n  <div class=\"table-container\">\n  | Name   | Type     | Description                                           |\n  | ------ | -------- | ----------------------------------------------------- |\n  | add    | function | Adds an element to the end of the queue.              |\n  | remove | function | Removes and returns the first element from the queue. |\n  | clear  | function | Clears the queue, removing all elements.              |\n  | first  | any      | The first element in the queue.                       |\n  | last   | any      | The last element in the queue.                        |\n  | size   | number   | The number of elements in the queue.                  |\n  | queue  | array    | The current array representing the queue.             |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useQueue } from \"@uidotdev/usehooks\";\n\nfunction QueueDemo({ first, last, size, queue }) {\n  return (\n    <figure>\n      <article>\n        <p>Front</p>\n        <ul>\n          {queue.map((item, i) => {\n            const isFirst = first === item;\n            const isLast = last === item;\n            if (isFirst) {\n              return <li key={i}>First: {item}</li>;\n            }\n            if (isLast) {\n              return <li key={i}>Last: {item}</li>;\n            }\n            return <li key={i}>Item: {item}</li>;\n          })}\n        </ul>\n        <p>Back</p>\n      </article>\n      <figcaption>{size} items in the queue</figcaption>\n    </figure>\n  );\n}\n\nexport default function App() {\n  const { add, remove, clear, first, last, size, queue } = useQueue([1, 2, 3]);\n\n  return (\n    <div>\n      <header>\n        <h1>UseQueue</h1>\n        <button className=\"link\" onClick={() => add((last || 0) + 1)}>\n          Add\n        </button>\n        <button disabled={size === 0} className=\"link\" onClick={() => remove()}>\n          Remove\n        </button>\n        <button disabled={size === 0} className=\"link\" onClick={() => clear()}>\n          Clear\n        </button>\n      </header>\n      <QueueDemo queue={queue} size={size} first={first} last={last} />\n    </div>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useRandomInterval.mdx",
    "content": "---\nname: useRandomInterval\nexperimental: true\nrank: 17\ntagline: Execute a callback function at a random interval with useRandomInterval.\nsandboxId: userandominterval-rh8q99\npreviewHeight: 500px\nrelatedHooks:\n  - usecontinuousretry\n  - useintervalwhen\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useRandomInterval hook is useful for executing a callback function at\n  random intervals within a specified range. It provides a way to create an\n  interval that varies dynamically based on minimum and maximum delay values. By\n  using this hook, you can easily implement features such as periodic data\n  updates, animations, or any other functionality that requires dynamic and\n  random timing. The hook manages the interval internally, ensuring that it is\n  cleared when the component unmounts or when the delay values change.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name             | Type     | Description                                                         |\n  | ---------------- | -------- | ------------------------------------------------------------------- |\n  | cb               | function | The callback function to be executed at random intervals.           |\n  | options          | object   | An object containing the following options.                         |\n  | options.minDelay | number   | The minimum delay in milliseconds between each callback invocation. |\n  | options.maxDelay | number   | The maximum delay in milliseconds between each callback invocation. |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Type     | Description                                                             |\n  | -------- | ----------------------------------------------------------------------- |\n  | function | A function to clear the timeout and stop the random interval execution. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useRandomInterval } from \"@uidotdev/usehooks\";\nimport HeartsDemo from \"./Heart\";\n\nexport default function App() {\n  const demo = React.useRef(new HeartsDemo());\n  const clear = useRandomInterval(\n    () => {\n      demo.current.addHeart();\n    },\n    { minDelay: 50, maxDelay: 3000 }\n  );\n\n  React.useEffect(() => {\n    demo.current.loop();\n  }, []);\n\n  return (\n    <section>\n      <h1>useRandomInterval</h1>\n      <button className=\"link\" onClick={clear}>\n        Stop\n      </button>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useRenderCount.mdx",
    "content": "---\nname: useRenderCount\nrank: 16\ntagline: Identify unnecessary re-renders and monitor update frequency with useRenderCount.\nsandboxId: userendercount-ghn1dg\npreviewHeight: 320px\nrelatedHooks:\n  - userenderinfo\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useRenderCount hook is a useful tool for tracking the number of times a\n  component renders or re-renders. Each time the component renders, the count\n  value is incremented, allowing you to keep track of the render count. This can\n  be helpful in optimizing performance, identifying unnecessary re-renders, or\n  monitoring how frequently a component is being updated. The hook provides a\n  simple and efficient way to gain insights into the rendering behavior of your\n  components.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n  <div class=\"table-container\">\n  | Name        | Type   | Description                                     |\n  | ----------- | ------ | ----------------------------------------------- |\n  | renderCount | number | The number of times the component has rendered. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useRenderCount } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const renderCount = useRenderCount();\n  const [count, setCount] = React.useState(0);\n\n  return (\n    <section>\n      <header>\n        <h1>useRenderCount</h1>\n        <h6>(strict mode on)</h6>\n      </header>\n      <button className=\"primary\" onClick={() => setCount((c) => c + 1)}>\n        Increment\n      </button>\n      <p>Count: {count}</p>\n      <p>Render Count: {renderCount}</p>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useRenderInfo.mdx",
    "content": "---\nname: useRenderInfo\nrank: 15\ntagline: Debug renders and improve performance with useRenderInfo.\nsandboxId: userenderinfo-njhqlg\npreviewHeight: 400px\nrelatedHooks:\n  - userendercount\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useRenderInfo hook is useful for tracking and logging rendering\n  information in a component. It keeps track of the number of renders, the time\n  elapsed since the last render, and the timestamp of the current render. This\n  hook is particularly helpful during development as it provides insights into\n  the rendering behavior of a component, allowing developers to optimize\n  performance and identify potential issues.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name                 | Type   | Description                                                       |\n  | -------------------- | ------ | ----------------------------------------------------------------- |\n  | info                 | object | An object containing information about the component’s rendering. |\n  | info.name            | string | The name of the component.                                        |\n  | info.renders         | number | The number of times the component has rendered.                   |\n  | info.sinceLastRender | number | The time elapsed in milliseconds since the last render.           |\n  | info.timestamp       | number | The timestamp of the current render.                              |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useRenderInfo } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const info = useRenderInfo(\"App\");\n\n  const [count, setCount] = React.useState(0);\n\n  return (\n    <section>\n      <h1>useRenderInfo</h1>\n      <button className=\"primary\" onClick={() => setCount(count + 1)}>\n        Re-Render\n      </button>\n      <table>\n        <thead>\n          <tr>\n            <th colSpan={2}>Render Info</th>\n          </tr>\n        </thead>\n        <tbody>\n          {Object.keys(info).map((key) => {\n            return (\n              <tr key={key}>\n                <th>{key}</th>\n                <td>{info[key]}</td>\n              </tr>\n            );\n          })}\n        </tbody>\n      </table>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useScript.mdx",
    "content": "---\nname: useScript\nrank: 14\ntagline: Load and manage external JavaScript scripts with useScript.\nsandboxId: usescript-dux91r\npreviewHeight: 300px\nrelatedHooks:\n  - usefetch\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useScript hook is useful for dynamically loading external JavaScript\n  scripts into a React component. It manages the loading and status of the\n  script, allowing you to conditionally render components or perform actions\n  based on whether the script has been successfully loaded or encountered an\n  error. The hook keeps track of the script’s status and provides this status as a return value. Additionally,\n  it offers options to remove the script when the component is unmounted,\n  ensuring proper cleanup.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name             | Type   | Description |\n  | ---------------- | ------ | ----------- |\n  | src              | string | This is the URL source of the script to be loaded. |\n  | options          | object | This is an optional configuration object provided when calling `useScript`. It currently accepts one property `removeOnUnmount` which when set to `true`, will remove the script tag from the document body on component unmount. |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name   | Type   | Description |\n  | ------ | ------ | ----------- |\n  | status | string | This represents the status of the script load, `loading`, `ready`, `error`, or `unknown`. An `unknown` script is one that previously exists in the document, but was not added via `useScript`.  |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useScript } from \"@uidotdev/usehooks\";\nimport ScriptMeta from './ScriptMeta'\n\nexport default function App() {\n  const status = useScript(\n    `https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.js`,\n    {\n      removeOnUnmount: false,\n    }\n  );\n\n  React.useEffect(() => {\n    if (typeof window.$$ !== \"undefined\") {\n      const id = document.id(\"moo\");\n      id.setStyle(\"background-color\", \"var(--green)\");\n    }\n  }, [status]);\n\n  const isReady = status === \"ready\";\n\n  return (\n    <section>\n      <h1>useScript</h1>\n      <p>\n        <span id=\"moo\" className={isReady ? \"ready\" : \"\"} />\n        <label>Status: {status}</label>\n      </p>\n      {status === \"ready\" && (\n        <ScriptMeta title=\"MooTools\" status={status} meta={window.MooTools} />\n      )}\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useSessionStorage.mdx",
    "content": "---\nname: useSessionStorage\nrank: 9\ntagline: Store, retrieve, and synchronize data from the browser’s session storage with useSessionStorage.\nsandboxId: usesessionstorage-yoodu4\npreviewHeight: 400px\nrelatedHooks:\n  - uselocalstorage\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useSessionStorage hook allows you to store and retrieve data in the\n  browser’s session storage, providing a way to persist data across multiple\n  page views or browser refreshes. The hook utilizes the window.sessionStorage\n  API to store and retrieve data in the session storage. It automatically\n  synchronizes the stored data with the local state of the component using the\n  hook. Additionally, it listens for changes in the session storage and updates\n  the local state accordingly, ensuring that the component reflects the latest\n  stored values.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name         | Type   | Description                                                                                |\n  | ------------ | ------ | ------------------------------------------------------------------------------------------ |\n  | key          | string | The key used to access the session storage value.                                          |\n  | initialValue | any    | The initial value to use if there is no item in the session storage with the provided key. |\n  </div>\n\n  ### Return Values\n\n  <div class=\"table-container\">\n  | Name           | Type     | Description                                                                                                                                                                                                       |\n  | -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n  | localState     | any      | The current state of the value stored in session storage.                                                                                                                                                         |\n  | handleSetState | function | A function to set the state of the value in the session storage. This function accepts a new value or a function that returns a new value. The value is also saved in the session storage under the provided key. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useSessionStorage } from \"@uidotdev/usehooks\";\nimport { cart } from \"./icons\";\n\nexport default function App() {\n  const [count, setCount] = useSessionStorage(\"woot\", 0);\n\n  return (\n    <section>\n      <h1>useSessionStorage</h1>\n      <div>\n        <button className=\"link\" onClick={() => setCount(0)}>\n          Clear Cart\n        </button>\n        <button\n          className=\"link\"\n          onClick={() => {\n            window.location.reload();\n          }}\n        >\n          Reload Window\n        </button>\n        <button\n          className=\"link\"\n          onClick={() => {\n            window.sessionStorage.clear();\n            window.location.reload();\n          }}\n        >\n          Clear Session\n        </button>\n      </div>\n      <button className=\"primary\" onClick={() => setCount(count + 1)}>\n        <span>{cart}</span> Add To Cart\n      </button>\n      <button className=\"cart\">\n        <span>{cart}</span>{\" \"}\n        <span\n          key={count}\n          className={`cart-count ${count > 0 ? \"animate\" : \"\"}`}\n        >\n          {count}\n        </span>\n      </button>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useSet.mdx",
    "content": "---\nname: useSet\nrank: 30\ntagline: Synchronize and update state based on the Set data structure with useSet.\nsandboxId: useset-2jx1ou\npreviewHeight: 500px\nrelatedHooks:\n  - usemap\n  - usequeue\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useSet hook is useful for managing and manipulating the Set data structure\n  within a React component. It provides a way to create and maintain a set of\n  values, offering additional functionality through custom methods like \"add,\"\n  \"clear,\" and \"delete.\" By utilizing this hook, developers can easily update\n  and track changes to the set, triggering re-renders of the component whenever\n  modifications occur.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name   | Type  | Description                            |\n  | ------ | ----- | -------------------------------------- |\n  | values | array | (Optional) Initial values for the set. |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name | Type | Description                                            |\n  | ---- | ---- | ------------------------------------------------------ |\n  | set  | set  | An instance of the `Set` object with enhanced methods. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useSet } from \"@uidotdev/usehooks\";\n\nfunction format(val) {\n  return val.toLocaleLowerCase().replace(/\\s/g, \"\");\n}\n\nexport default function App() {\n  const [value, setValue] = React.useState(\"\");\n  const set = useSet([\n    \"benadam11\",\n    \"tylermcginnis\",\n    \"lynnandtonic\",\n    \"alexbrown40\",\n    \"uidotdev\",\n    \"bytesdotdev\",\n    \"reactnewsletter\",\n  ]);\n\n  const handleSubmit = (e) => {\n    e.preventDefault();\n    const formData = new FormData(e.target);\n    const username = formData.get(\"username\");\n    set.add(format(username));\n    setValue(\"\");\n    e.target.reset();\n    e.target.focus();\n  };\n\n  const hasError = set.has(value);\n\n  return (\n    <section>\n      <h1>useSet</h1>\n      <p>Check if your username is available</p>\n      <article>\n        <form className={hasError ? \"error\" : \"\"} onSubmit={handleSubmit}>\n          <span>@</span>\n          <input\n            type=\"text\"\n            name=\"username\"\n            placeholder=\"Enter a username\"\n            onChange={(e) => {\n              setValue(format(e.target.value));\n            }}\n          />\n        </form>\n        {hasError && <label>Woops that user is taken</label>}\n      </article>\n\n      <table>\n        <tbody>\n          {Array.from(set.values()).map((username) => {\n            const match = username === value;\n            return (\n              <tr key={username}>\n                <th>username</th>\n                <td\n                  style={{\n                    borderColor: match ? \"var(--red)\" : \"var(--charcoal)\",\n                  }}\n                >\n                  {username}\n                </td>\n              </tr>\n            );\n          })}\n        </tbody>\n      </table>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useThrottle.mdx",
    "content": "---\nname: useThrottle\nrank: 29\ntagline: Throttle computationally expensive operations with useThrottle.\nsandboxId: usethrottle-xzfoz7\npreviewHeight: 300px\nrelatedHooks:\n  - usefetch\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useThrottle hook offers a controlled way to manage execution frequency in\n  a React application. By accepting a value and an optional interval, it ensures\n  that the value is updated at most every interval milliseconds. This is\n  particularly helpful for limiting API calls, reducing UI updates, or\n  mitigating performance issues by throttling computationally expensive\n  operations.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name     | Type   | Description                                              |\n  | -------- | ------ | -------------------------------------------------------- |\n  | value    | any    | The value to throttle.                                   |\n  | interval | number | (Optional) The interval in milliseconds. Default: 500ms. |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name           | Type | Description                                                    |\n  | -------------- | ---- | -------------------------------------------------------------- |\n  | throttledValue | any  | The throttled value that is updated at most once per interval. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useThrottle } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [val, setVal] = React.useState(\"\");\n  const throttledValue = useThrottle(val);\n\n  return (\n    <section>\n      <h1>useThrottle</h1>\n      <input\n        placeholder=\"Type some text\"\n        style={{ background: \"var(--charcoal)\" }}\n        type=\"text\"\n        value={val}\n        onChange={(e) => {\n          setVal(e.target.value);\n        }}\n      />\n      <p>Val: {val}</p>\n      <p>Throttled: {throttledValue}</p>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useTimeout.mdx",
    "content": "---\nname: useTimeout\nexperimental: true\nrank: 25\ntagline: Create delayed actions or timed events using useTimeout.\nsandboxId: usetimeout-7fcfr1\npreviewHeight: 450px\nrelatedHooks:\n  - useinterval\n  - useintervalwhen\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useTimeout hook allows you to set up a timed callback in your components.\n  The hook returns a function (handleClearInterval) that can be used to manually\n  cancel or clear the timer if needed. This hook is beneficial for scenarios\n  where delayed actions or timed events are required, such as implementing\n  loading delays, animations, or auto-updating components.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name | Type     | Description                                                       |\n  | ---- | -------- | ----------------------------------------------------------------- |\n  | cb   | function | The callback function to be executed after the specified timeout. |\n  | ms   | number   | The duration of the timeout in milliseconds.                      |\n  </div>\n\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name         | Type     | Description                                                               |\n  | ------------ | -------- | ------------------------------------------------------------------------- |\n  | clearTimeout | function | A function to clear the timeout and cancel the execution of the callback. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useTimeout } from \"@uidotdev/usehooks\";\n\nfunction Bomb({ hasExploded, hasDefused, handleClick }) {\n  if (hasExploded) {\n    return (\n      <figure>\n        <span role=\"img\" aria-label=\"Explosion Emoji\">\n          💥\n        </span>\n        <figcaption>You lose</figcaption>\n      </figure>\n    );\n  }\n\n  if (hasDefused) {\n    return (\n      <figure>\n        <span role=\"img\" aria-label=\"Explosion Emoji\">\n          🎉\n        </span>\n        <figcaption>You Win</figcaption>\n      </figure>\n    );\n  }\n\n  return (\n    <button className=\"bomb\" onClick={handleClick}>\n      <span role=\"img\" aria-label=\"Dynamite Emoji\">\n        🧨\n      </span>\n    </button>\n  );\n}\n\nexport default function App() {\n  const [hasDefused, setHasDefused] = React.useState(false);\n  const [hasExploded, setHasExploded] = React.useState(false);\n\n  const clear = useTimeout(() => {\n    setHasExploded(!hasExploded);\n  }, 1000);\n\n  const handleClick = () => {\n    clear();\n    setHasDefused(true);\n  };\n\n  return (\n    <section>\n      <h1>useTimeout</h1>\n      <p>You have 1s to defuse (click) the bomb or it will explode </p>\n      <button\n        className=\"link\"\n        onClick={() => {\n          window.location.reload();\n        }}\n      >\n        Reload\n      </button>\n      <Bomb\n        hasDefused={hasDefused}\n        hasExploded={hasExploded}\n        handleClick={handleClick}\n      />\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useToggle.mdx",
    "content": "---\nname: useToggle\nrank: 34\ntagline: A hook to toggle a boolean value with useToggle.\nsandboxId: usetoggle-tcj48q\npreviewHeight: 300px\nrelatedHooks:\n  - uselongpress\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  Basically, what this hook does is that, it takes a parameter with value true\n  or false and toggles that value to opposite. It’s useful when we want to take\n  some action into its opposite action, for example: show and hide modal, show\n  more/show less text, open/close side menu.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Parameters\n\n  <div class=\"table-container\">\n  | Name         | Type    | Description                                       |\n  | ------------ | ------- | ------------------------------------------------- |\n  | initialValue | boolean | (Optional) The initial value of the toggle state. |\n  </div>\n\n  ### Return Value\n\n  The `useToggle` hook returns an array with the following elements:\n\n  <div class=\"table-container\">\n  | Index | Type     | Description                                   |\n  | ----- | -------- | --------------------------------------------- |\n  | 0     | boolean  | The current state of the toggle.              |\n  | 1     | function | A function to toggle the state of the toggle. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useToggle } from \"@uidotdev/usehooks\";\n\nfunction ToggleDemo({ on, toggle }) {\n  return (\n    <div>\n      <label className=\"toggle\">\n        <input\n          onChange={toggle}\n          className=\"toggle-checkbox\"\n          type=\"checkbox\"\n          checked={on}\n        />\n        <div className=\"toggle-switch\"></div>\n        <span className=\"toggle-label\">{on ? \"On\" : \"Off\"}</span>\n      </label>\n    </div>\n  );\n}\n\nexport default function App() {\n  const [on, toggle] = useToggle(true);\n\n  return (\n    <section>\n      <h1>UseToggle</h1>\n      <button disabled={on} className=\"link\" onClick={() => toggle(true)}>\n        Turn On\n      </button>\n      <button disabled={!on} className=\"link\" onClick={() => toggle(false)}>\n        Turn Off\n      </button>\n      <button className=\"link\" onClick={toggle}>\n        Toggle\n      </button>\n      <button className=\"link\" onClick={() => toggle(\"nope\")}>\n        (Also toggles)\n      </button>\n      <ToggleDemo toggle={toggle} on={on} />\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useVisibilityChange.mdx",
    "content": "---\nname: useVisibilityChange\nrank: 13\ntagline: Track document visibility and respond to changes with useVisibilityChange.\nsandboxId: usevisibilitychange-8yxnwy\npreviewHeight: 200px\nrelatedHooks:\n  - useorientation\n  - usenetworkstate\n  - usemediaquery\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useVisibilityChange hook is useful for tracking the visibility state of a\n  document or web page. It allows you to easily detect when the document is\n  visible or hidden, and perform certain actions based on that information. The\n  hook returns a boolean value indicating whether the document is currently\n  visible or not, allowing components to react accordingly and update their\n  rendering or behavior based on the visibility state.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  <div class=\"table-container\">\n  | Name            | Type    | Description                                                     |\n  | --------------- | ------- | --------------------------------------------------------------- |\n  | documentVisible | boolean | `true` if the document is currently visible, `false` otherwise. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useVisibilityChange } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const documentVisible = useVisibilityChange();\n  const [tabAwayCount, setTabAwayCount] = React.useState(0);\n\n  React.useEffect(() => {\n    if (documentVisible === false) {\n      setTabAwayCount((c) => c + 1);\n    }\n  }, [documentVisible]);\n\n  return (\n    <section>\n      <h1>useVisibilityChange</h1>\n      <div>Tab Away Count: {tabAwayCount}</div>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useWindowScroll.mdx",
    "content": "---\nname: useWindowScroll\nrank: 45\ntagline: Track and manipulate the scroll position of a web page with useWindowScroll.\nsandboxId: usewindowscroll-pdw6f9\npreviewHeight: 600px\nrelatedHooks:\n  - usemeasure\n  - usewindowsize\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useWindowScroll hook is useful for tracking and manipulating the scroll\n  position of a web page within a React component. It allows you to easily\n  access the current scroll coordinates (x and y) through the \"state\" object\n  returned by the hook. Additionally, the hook provides a \"scrollTo\" function\n  that can be used to programmatically scroll to a specific position on the\n  page. This hook is helpful when building components that require dynamic\n  behavior based on the scroll position, such as lazy-loading content, infinite\n  scrolling, or implementing smooth scrolling animations.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  The `useWindowScroll` hook returns an array with two elements:\n\n  <div class=\"table-container\">\n  | Name       | Type     | Description                                                              |\n  | ---------- | -------- | ------------------------------------------------------------------------ |\n  | `state`    | object   | An object representing the current window scroll position.               |\n  | `scrollTo` | function | A function that can be used to scroll the window to a specific position. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useWindowScroll } from \"@uidotdev/usehooks\";\n\nexport default function App() {\n  const [{ x, y }, scrollTo] = useWindowScroll();\n  return (\n    <section>\n      <header>\n        <h1>useWindowScroll</h1>\n        <button className=\"link\" onClick={() => scrollTo(0, 1000)}>\n          Scroll To (0, 1000)\n        </button>\n        <button\n          className=\"link\"\n          onClick={() => scrollTo({ left: 0, top: 2000, behavior: \"smooth\" })}\n        >\n          Scroll To (0, 2000) (Smoothly)\n        </button>\n        <button\n          className=\"link\"\n          onClick={() => scrollTo({ left: 0, top: 0, behavior: \"smooth\" })}\n        >\n          Back To The Top\n        </button>\n      </header>\n\n      {new Array(50).fill().map((_, index) => {\n        return <p key={index}>{index}</p>;\n      })}\n      <aside style={{ position: \"fixed\", bottom: 0, right: 0 }}>\n        Coordinates <span className=\"x\">x: {x}</span>{\" \"}\n        <span className=\"y\">y: {y}</span>{\" \"}\n      </aside>\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/content/hooks/useWindowSize.mdx",
    "content": "---\nname: useWindowSize\nrank: 3\ntagline: Track the dimensions of the browser window with useWindowSize.\nsandboxId: usewindowsize-vxk6xf\npreviewHeight: 500px\nrelatedHooks:\n  - usemeasure\n  - usewindowscroll\n---\n\nimport CodePreview from \"../../components/CodePreview.astro\";\nimport HookDescription from \"../../components/HookDescription.astro\";\nimport StaticCodeContainer from \"../../components/StaticCodeContainer.astro\";\n\n<HookDescription name={frontmatter.name}>\n  The useWindowSize hook is a useful for retrieving and tracking the dimensions\n  of the browser window within a React component. It attaches an event listener\n  to the \"resize\" event, ensuring that the size is updated dynamically whenever\n  the window is resized. The hook returns the \"size\" object, enabling components\n  to access and utilize the window dimensions for various purposes, such as\n  responsive layout adjustments, conditional rendering, or calculations based on\n  the available space.\n</HookDescription>\n\n<div class=\"reference\">\n  ### Return Value\n\n  The `useWindowSize` hook returns an object with the following properties:\n\n  <div class=\"table-container\">\n  | Name   | Type   | Description                                  |\n  | ------ | ------ | -------------------------------------------- |\n  | width  | number | The current width of the window, in pixels.  |\n  | height | number | The current height of the window, in pixels. |\n  </div>\n</div>\n\n<CodePreview\n  sandboxId={frontmatter.sandboxId}\n  previewHeight={frontmatter.previewHeight}\n/>\n\n<StaticCodeContainer>\n\n```jsx\nimport * as React from \"react\";\nimport { useWindowSize } from \"@uidotdev/usehooks\";\n\nfunction Browser({ size }) {\n  return (\n    <div\n      data-testid=\"browser\"\n      className=\"browser\"\n      style={{ width: size.width / 4, height: size.height / 4 }}\n    />\n  );\n}\n\nexport default function App() {\n  const size = useWindowSize();\n\n  return (\n    <section>\n      <h1>useWindowSize</h1>\n      <p>Resize the window</p>\n      <table>\n        <tbody>\n          <tr>\n            <th>width</th>\n            <td>{size.width}</td>\n          </tr>\n          <tr>\n            <th>height</th>\n            <td>{size.height}</td>\n          </tr>\n        </tbody>\n      </table>\n      <Browser size={size} />\n    </section>\n  );\n}\n```\n\n</StaticCodeContainer>\n"
  },
  {
    "path": "usehooks.com/src/env.d.ts",
    "content": "/// <reference path=\"../.astro/types.d.ts\" />\n/// <reference types=\"astro/client\" />\n"
  },
  {
    "path": "usehooks.com/src/layouts/Layout.astro",
    "content": "---\nimport \"../styles/globals.css\";\nexport interface Props {\n  title: string;\n  description: string;\n  ogImage?: URL;\n  url?: URL;\n}\n\nconst {\n  title,\n  description,\n  ogImage = new URL(\"/meta/og.jpg\", Astro.url),\n} = Astro.props;\n\nconst pathname = Astro.url.pathname;\n\nconst url =\n  pathname[pathname.length - 1] === \"/\"\n    ? new URL(pathname.slice(0, pathname.length - 1), Astro.site)\n    : new URL(Astro.url.pathname, Astro.site);\n---\n\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <link rel=\"icon\" href=\"/favicon.png\" />\n    <meta name=\"generator\" content={Astro.generator} />\n    <title>{title}</title>\n    <meta name=\"description\" content={description} />\n    <meta name=\"author\" content=\"ui.dev\" />\n    <meta property=\"og:type\" content=\"website\" />\n    <meta name=\"twitter:card\" content=\"summary_large_image\" />\n    <meta content=\"@uidotdev\" name=\"twitter:site\" />\n    <meta content=\"@uidotdev\" name=\"twitter:creator\" />\n    <meta\n      content={description}\n      name=\"twitter:description\"\n      property=\"og:description\"\n    />\n    <meta content={url} property=\"og:url\" />\n    <meta content={url} property=\"twitter:url\" />\n    <meta content={title} name=\"twitter:title\" property=\"og:title\" />\n    <meta content={ogImage} property=\"og:image\" />\n    <meta content={ogImage} name=\"twitter:image\" />\n    <link rel=\"canonical\" href={url} />\n    <link\n      rel=\"preload\"\n      href=\"/fonts/outfit-v4-latin-regular.woff2\"\n      as=\"font\"\n      crossorigin=\"anonymous\"\n    />\n    <link\n      rel=\"preload\"\n      href=\"/fonts/outfit-v4-latin-500.woff2\"\n      as=\"font\"\n      crossorigin=\"anonymous\"\n    />\n    <link\n      rel=\"preload\"\n      href=\"/fonts/outfit-v4-latin-700.woff2\"\n      as=\"font\"\n      crossorigin=\"anonymous\"\n    />\n    <link\n      rel=\"preload\"\n      href=\"/fonts/outfit-v4-latin-900.woff2\"\n      as=\"font\"\n      crossorigin=\"anonymous\"\n    />\n    <link\n      rel=\"preload\"\n      href=\"/fonts/paytone-one-v16-latin-regular.woff2\"\n      as=\"font\"\n      crossorigin=\"anonymous\"\n    />\n\n    <link\n      rel=\"preload\"\n      href=\"/fonts/firacode-regular.woff2\"\n      as=\"font\"\n      crossorigin=\"anonymous\"\n    />\n\n    <script\n      defer\n      src=\"/stats/js/script.js\"\n      data-api=\"/stats/api/event\"\n      data-domain=\"usehooks.com\"\n    ></script>\n\n    <script defer>\n      !(function (f, b, e, v, n, t, s) {\n        if (f.fbq) return;\n        n = f.fbq = function () {\n          n.callMethod\n            ? n.callMethod.apply(n, arguments)\n            : n.queue.push(arguments);\n        };\n        if (!f._fbq) f._fbq = n;\n        n.push = n;\n        n.loaded = !0;\n        n.version = \"2.0\";\n        n.queue = [];\n        t = b.createElement(e);\n        t.async = !0;\n        t.src = v;\n        s = b.getElementsByTagName(e)[0];\n        s.parentNode.insertBefore(t, s);\n      })(\n        window,\n        document,\n        \"script\",\n        \"https://connect.facebook.net/en_US/fbevents.js\"\n      );\n      fbq(\"init\", \"186849069509023\");\n      fbq(\"track\", \"PageView\");\n    </script>\n  </head>\n  <body>\n    <slot />\n  </body>\n</html>\n"
  },
  {
    "path": "usehooks.com/src/pages/404.astro",
    "content": "---\nimport Layout from '../layouts/Layout.astro';\nimport NavInternal from '../sections/NavInternal.astro';\nimport Footer from '../sections/Footer.astro';\n---\n\n<Layout\n\ttitle=\"Page not found.\"\n\tdescription=\"A collection of modern, server-safe React hooks – from the ui.dev team\"\n>\n\t<NavInternal />\n\t<main>\n\t\t<h1>404</h1>\n\t\t<p>If you think this page should exist, email <a href=\"mailto:hi@ui.dev\">hi@ui.dev</a>.</p>\n\t</main>\n\t<Footer />\n</Layout>\n\n<style>\n\tbody {\n\t\tmin-height: 100lvh;\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tjustify-content: space-between;\n\t}\n\tmain {\n\t\twidth: 100%;\n\t\tmax-width: 960px;\n\t\tmargin-top: 1rem;\n\t\tpadding: 1rem 0;\n\t\ttext-align: center;\n\t}\n\tmain h1 {\n\t\twidth: 100%;\n\t\tmargin-bottom: 2rem;\n\t\tfont-size: var(--font-lg);\n\t}\n</style>\n"
  },
  {
    "path": "usehooks.com/src/pages/[hook].astro",
    "content": "---\nimport { CollectionEntry, getCollection } from \"astro:content\";\nimport Layout from \"../layouts/Layout.astro\";\nimport NavInternal from \"../sections/NavInternal.astro\";\nimport Footer from \"../sections/Footer.astro\";\nimport Install from \"../components/Install.astro\";\nimport HooksList from \"../components/search/HooksList\";\n\nexport async function getStaticPaths() {\n  const hooks = await getCollection(\"hooks\");\n\n  return hooks.map((hook) => {\n    return {\n      params: {\n        hook: hook.slug,\n      },\n      props: {\n        hook,\n      },\n    };\n  });\n}\n\ninterface Props {\n  hook: CollectionEntry<\"hooks\">;\n}\n\nconst { hook } = Astro.props;\nconst { Content } = await hook.render();\nconst { name, tagline, experimental } = hook.data;\nconst ogImage = new URL(`/meta/${name.toLowerCase()}.png`, Astro.url);\nconst installSnippet = experimental\n  ? `npm i @uidotdev/usehooks@experimental react@experimental react-dom@experimental`\n  : `npm i @uidotdev/usehooks`;\n\nconst hooks = await getCollection(\"hooks\").then((hooks) => {\n  return hooks.filter((h) => {\n    return h.slug !== hook.slug;\n  });\n});\n---\n\n<Layout\n  title={`${name} React Hook – useHooks`}\n  description={tagline}\n  ogImage={ogImage}\n>\n  <NavInternal />\n  <main>\n    <section>\n      <a href=\"/\" class=\"logo-useHooks logo image\">\n        <img\n          src=\"/img/logo-useHooks.svg\"\n          width=\"546\"\n          height=\"80\"\n          alt=\"useHooks\"\n          class=\"logo-useHooks\"\n        />\n      </a>\n      <header>\n        <h1 class=\"title\">{name}</h1>\n        <p class=\"tagline\">{tagline}</p>\n      </header>\n      <div>\n        <h2>Install:</h2>\n        {\n          experimental && (\n            <p class=\"experimental\">\n              Note: This hook depends on React’s experimental useEffectEvent.\n            </p>\n          )\n        }\n        <Install text={installSnippet} />\n      </div>\n      <Content />\n    </section>\n    <div class=\"mt-12\">\n      <h2>More Hooks:</h2>\n      <HooksList client:load hooks={hooks} />\n    </div>\n  </main>\n  <Footer />\n\n  <style>\n    body {\n      min-height: 100lvh;\n      display: flex;\n      flex-direction: column;\n    }\n\n    main {\n      width: 100%;\n      max-width: 980px;\n      margin: 4rem auto;\n    }\n\n    section {\n      padding: clamp(0.5rem, 4vw, 3rem);\n      padding-top: 0;\n      display: flex;\n      flex-direction: column;\n      gap: clamp(1.2rem, 6vw, 3rem);\n      background-color: var(--charcoal);\n      border-radius: 0.8rem;\n    }\n\n    header {\n      display: grid;\n      justify-content: space-between;\n      align-items: center;\n      gap: 0.5rem 1rem;\n    }\n\n    .tagline {\n      max-width: 42ch;\n    }\n\n    .logo-useHooks {\n      width: 180px;\n      height: auto;\n      transform: translateY(-30%);\n    }\n\n    .title {\n      color: var(--blue);\n      text-transform: none;\n      font-family: var(--font-outfit);\n      font-size: clamp(1.6rem, 5vw, 2.6rem);\n      font-weight: 600;\n    }\n\n    .install,\n    .install code {\n      background-color: var(--coal);\n    }\n\n    .install .copy-btn:hover,\n    .install .copy-btn:focus-visible {\n      background-color: var(--charcoal);\n    }\n\n    main :global(h2) {\n      font-size: clamp(1rem, 2.2vw, 1.2rem);\n      margin-bottom: 1rem;\n    }\n\n    main :global(code) {\n      background-color: var(--coal);\n    }\n\n    .experimental {\n      font-size: 1.1rem;\n      font-style: italic;\n      margin-bottom: 1rem;\n    }\n\n    @media screen and (max-width: 500px) {\n      .experimental ~ .install {\n        flex-direction: column;\n        align-items: flex-start;\n      }\n    }\n\n    :global(.reference) {\n      font-size: clamp(1.1rem, 2.2vw, 1.3rem);\n    }\n\n    :global(.reference > * + *) {\n      margin-top: 1.5rem;\n    }\n\n    :global(.reference h3) {\n      font-size: clamp(0.9rem, 2vw, 1.1rem);\n    }\n\n    :global(.reference .table-container) {\n      width: 100%;\n      overflow-x: auto;\n      -webkit-overflow-scrolling: touch;\n      border: 0.07rem solid rgba(249, 244, 218, 0.1);\n    }\n\n    :global(.reference table) {\n      border-radius: 0.9rem;\n      font-size: clamp(1rem, 2.1vw, 1.2rem);\n    }\n\n    :global(.reference h3:not(:first-child)) {\n      margin-top: 2rem;\n    }\n\n    :global(.reference thead) {\n      /* border-bottom: 0.07rem solid rgba(249, 244, 218, 0.1); */\n      background-color: rgba(249, 244, 218, 0.1);\n      font-size: var(--font-sm);\n      text-align: left;\n    }\n\n    :global(.reference tr:not(:last-of-type)) {\n      border-bottom: 0.07rem solid rgba(249, 244, 218, 0.1);\n    }\n\n    :global(.reference td),\n    :global(.reference th) {\n      padding: 0.5rem 1.2rem 0.5rem 0.75rem;\n    }\n\n    :global(.reference td:not(:last-of-type)),\n    :global(.reference th:not(:last-of-type)) {\n      min-width: 10ch;\n    }\n\n    :global(.reference td:last-of-type),\n    :global(.reference th:last-of-type) {\n      width: 100%;\n      min-width: 300px;\n    }\n\n    :global(.sp-preview-container),\n    :global(.sp-preview-container iframe) {\n      background: var(--coal) !important;\n    }\n\n    :global(pre) {\n      overflow: auto;\n      width: 100%;\n      background-color: transparent !important;\n      padding: 2rem;\n      border-radius: 0.5rem;\n    }\n\n    :global(pre code) {\n      font-size: 1rem;\n      display: block;\n      font-family: \"Fira Code\", monospace;\n    }\n  </style>\n</Layout>\n"
  },
  {
    "path": "usehooks.com/src/pages/index.astro",
    "content": "---\nimport { getCollection } from \"astro:content\";\nimport Layout from \"../layouts/Layout.astro\";\nimport NavMain from \"../sections/NavMain.astro\";\nimport HomeHero from \"../sections/HomeHero.astro\";\nimport HooksList from \"../components/search/HooksList\";\nimport Footer from \"../sections/Footer.astro\";\n\nconst hooks = await getCollection(\"hooks\");\n---\n\n<Layout\n  title=\"useHooks – The React Hooks Library\"\n  description=\"A collection of modern, server-safe React hooks – from the ui.dev team\"\n>\n  <NavMain />\n  <HomeHero />\n  <HooksList client:load hooks={hooks} />\n  <Footer />\n</Layout>\n"
  },
  {
    "path": "usehooks.com/src/sections/Footer.astro",
    "content": "---\n---\n\n<footer class=\"main-footer\">\n  <a href=\"/\" class=\"logo image\">\n    <img src=\"/img/logo-useHooks.svg\" width=\"546\" height=\"80\" alt=\"useHooks\" />\n  </a>\n  <a href=\"https://ui.dev\" class=\"byline\">by ui.dev</a>\n  <nav>\n    <a href=\"https://github.com/uidotdev/usehooks\">View the Repo</a>\n    <a href=\"https://bytes.dev\">JavaScript Newsletter</a>\n    <a href=\"https://reactnewsletter.com\">React Newsletter</a>\n    <a href=\"https://react.gg?s=usehooks\">Learn React</a>\n    <a href=\"https://query.gg\">Learn React Query</a>\n  </nav>\n</footer>\n\n<style>\n  .main-footer {\n    width: 100%;\n    margin-top: 4rem;\n    padding: var(--body-padding);\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    gap: 2rem;\n    border-radius: 0.5rem;\n    border: var(--border-dark);\n    font-size: var(--font-sm);\n  }\n\n  nav {\n    display: flex;\n    flex-wrap: wrap;\n    justify-content: center;\n    gap: 1rem 2rem;\n    text-align: center;\n  }\n\n  .logo {\n    width: 180px;\n  }\n\n  .byline {\n    margin-top: -0.5rem;\n    padding: 0.3em 0.5em;\n    display: inline-block;\n    border-radius: 0.3em;\n    background-color: var(--charcoal);\n  }\n\n  .byline:hover {\n    background-color: var(--yellow);\n    color: var(--charcoal);\n  }\n\n  nav a:hover {\n    text-decoration: underline;\n  }\n</style>\n"
  },
  {
    "path": "usehooks.com/src/sections/HomeHero.astro",
    "content": "---\nimport Install from '../components/Install.astro';\nimport { getCollection } from 'astro:content';\nconst hooksMarquee1 = (await getCollection('hooks')).slice(0,25);\nconst hooksMarquee2 = (await getCollection('hooks')).slice(25,50);\n---\n\n<header class=\"hero\">\n\t<img src=\"/img/logo-useHooks.svg\" width=\"546\" height=\"80\" alt=\"useHooks\" />\n\t<h1>A collection of modern, server-safe React hooks – from the ui.dev team</h1>\n\t<Install text=\"npm i @uidotdev/usehooks\" />\n\n\t<div class=\"marquee marquee-left\">\n\t\t<ul class=\"marquee-content\">\n\t\t\t{hooksMarquee1.map(hook => (\n\t\t\t\t<li>\n\t\t\t\t\t<a href={`/${hook.slug}`} tabindex=\"-1\">{hook.data.name}</a>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t\t<ul class=\"marquee-content\">\n\t\t\t{hooksMarquee1.map(hook => (\n\t\t\t\t<li>\n\t\t\t\t\t<a href={`/${hook.slug}`} tabindex=\"-1\">{hook.data.name}</a>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t</div>\n\t<div class=\"marquee marquee-right\">\n\t\t<ul class=\"marquee-content\">\n\t\t\t{hooksMarquee2.map(hook => (\n\t\t\t\t<li>\n\t\t\t\t\t<a href={`/${hook.slug}`} tabindex=\"-1\">{hook.data.name}</a>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t\t<ul class=\"marquee-content\">\n\t\t\t{hooksMarquee2.map(hook => (\n\t\t\t\t<li>\n\t\t\t\t\t<a href={`/${hook.slug}`} tabindex=\"-1\">{hook.data.name}</a>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t</div>\n</header>\n\n<style>\n\t.hero {\n\t\tpadding: 2em 0;\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tflex-direction: column;\n\t}\n\n\t.hero h1 {\n\t\tmargin: 1.2em 0;\n\t\tmax-width: 27ch;\n\t\ttext-align: center;\n\t\tfont-family: outfit;\n\t\tfont-size: clamp(1.2rem, 2.5vw, 1.5rem);\n\t\tfont-weight: 400;\n\t\ttext-transform: none;\n\t}\n\n\t.hero p {\n\t\tfont-size: 20px;\n\t\tmargin-top: .5rem;\n\t\tmargin-bottom: .75rem;\n\t}\n\n\t.hero img {\n\t\twidth: clamp(20rem, 50vw, 30rem);\n\t}\n\n\t.hero .install {\n\t\tmax-width: 40rem;\n\t\tmargin: 2.5rem 0 4rem;\n\t}\n\n\t.marquee {\n\t\t--gap: 1rem;\n\t\twidth: calc(100% + var(--body-padding) * 2);\n\t\tpadding: .7rem 0;\n\t\tdisplay: flex;\n\t\toverflow: hidden;\n\t\tuser-select: none;\n\t\tgap: var(--gap);\n\t}\n\n\t.marquee-content {\n\t\tflex-shrink: 0;\n\t\tdisplay: flex;\n\t\tjustify-content: space-around;\n\t\tmin-width: 100%;\n\t\tgap: var(--gap);\n\t\tanimation: scroll 200s linear infinite;\n\t}\n\n\t@media (prefers-reduced-motion) {\n\t\t.marquee-content {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.marquee-right .marquee-content {\n\t\tanimation-direction: reverse;\n\t}\n\n\t.marquee-content li a {\n\t\tpadding: .3rem .6rem;\n\t\tbackground-color: var(--white);\n\t\tborder-radius: .3rem;\n\t\tborder: var(--border-dark);\n\t\tbox-shadow: 0 .5rem 0 -.1rem var(--yellow),\n\t\t\t\t\t0 .55rem 0 var(--charcoal);\n\t\tcolor: var(--charcoal);\n\t\tfont-size: .9rem;\n\t}\n\n\t.marquee:hover .marquee-content {\n\t\tanimation-play-state: paused;\n\t}\n\n\t@keyframes scroll {\n\t\tfrom {\n\t\t\ttransform: translateX(0);\n\t\t}\n\t\tto {\n\t\t\ttransform: translateX(calc(-100% - var(--gap)));\n\t\t}\n\t}\n</style>\n"
  },
  {
    "path": "usehooks.com/src/sections/NavInternal.astro",
    "content": "---\nimport LogoGithub from '../components/LogoGithub.astro';\n---\n\n<nav class=\"nav-internal\">\n\t<a href=\"/\" class=\"back image\">\n\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" id=\"b\" viewBox=\"0 0 36 24\"><path fill=\"none\" stroke=\"#f6f1d7\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M34.14 12H3.96M14.69 22.85 1.86 12 14.69 1.15\"/></svg>\n\t\tAll hooks\n\t</a>\n\t<LogoGithub />\n</nav>\n\n<style>\n\t.nav-internal {\n\t\twidth: 100%;\n\t\theight: var(--nav-height);\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n\t\talign-items: center;\n\t}\n\n\t.back {\n\t\tdisplay: flex;\n\t\tgap: .6rem;\n\t\tfont-size: clamp(1rem, 3vw, 1.3rem);\n\t}\n\n\t.back:hover {\n\t\ttext-decoration: underline;\n\t}\n\n\t.back svg {\n\t\twidth: 1.5rem;\n\t\theight: auto;\n\t}\n</style>\n"
  },
  {
    "path": "usehooks.com/src/sections/NavMain.astro",
    "content": "---\nimport Logo from '../components/Logo.astro';\nimport LogoGithub from '../components/LogoGithub.astro';\n---\n\n<nav class=\"nav-main\">\n\t<Logo />\n\t<LogoGithub />\n</nav>\n\n<style>\n\t.nav-main {\n\t\theight: var(--nav-height);\n\t\tdisplay: flex;\n\t\tjustify-content: space-between;\n\t\talign-items: center;\n\t}\n</style>\n"
  },
  {
    "path": "usehooks.com/src/styles/globals.css",
    "content": "*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\nhtml,\nbody,\ndiv,\nspan,\napplet,\nobject,\niframe,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\np,\nblockquote,\npre,\na,\nabbr,\nacronym,\naddress,\nbig,\ncite,\ncode,\ndel,\ndfn,\nem,\nimg,\nins,\nkbd,\nq,\ns,\nsamp,\nsmall,\nstrike,\nstrong,\nsub,\nsup,\ntt,\nvar,\nb,\nu,\ni,\ncenter,\ndl,\ndt,\ndd,\nol,\nul,\nli,\nfieldset,\nform,\nlabel,\nlegend,\ntable,\ncaption,\ntbody,\ntfoot,\nthead,\ntr,\nth,\ntd,\narticle,\naside,\ncanvas,\ndetails,\nembed,\nfigure,\nfigcaption,\nfooter,\nheader,\nhgroup,\nmenu,\nnav,\noutput,\nruby,\nsection,\nsummary,\ntime,\nmark,\naudio,\nvideo {\n  margin: 0;\n  padding: 0;\n  border: 0;\n  font-size: 100%;\n  font: inherit;\n  vertical-align: baseline;\n}\n\n::selection {\n  background-color: var(--pink);\n  color: var(--coal);\n}\n\n@font-face {\n  font-family: \"Outfit\";\n  font-style: normal;\n  font-weight: 400;\n  src: local(\"\"), url(\"/fonts/outfit-v4-latin-regular.woff2\") format(\"woff2\");\n}\n/* outfit-500 - latin */\n@font-face {\n  font-family: \"Outfit\";\n  font-style: normal;\n  font-weight: 500;\n  src: local(\"\"), url(\"/fonts/outfit-v4-latin-500.woff2\") format(\"woff2\");\n}\n/* outfit-700 - latin */\n@font-face {\n  font-family: \"Outfit\";\n  font-style: normal;\n  font-weight: 700;\n  src: local(\"\"), url(\"/fonts/outfit-v4-latin-700.woff2\") format(\"woff2\");\n}\n/* outfit-900 - latin */\n@font-face {\n  font-family: \"Outfit\";\n  font-style: normal;\n  font-weight: 900;\n  src: local(\"\"), url(\"/fonts/outfit-v4-latin-900.woff2\") format(\"woff2\");\n}\n\n@font-face {\n  font-family: \"Paytone One\";\n  font-style: normal;\n  font-weight: 400;\n  src: local(\"\"),\n    url(\"/fonts/paytone-one-v16-latin-regular.woff2\") format(\"woff2\");\n}\n\n@font-face {\n  font-family: \"Fira Code\";\n  font-style: normal;\n  font-weight: 400;\n  src: local(\"\"), url(\"/fonts/firacode-regular.woff2\") format(\"woff2\");\n}\n\n:root {\n  --gray-light: #1b1d23;\n  --gray-dark: #131519;\n  --gray-darkest: #0d0f11;\n  --brand-coal: #0f0d0e;\n  --brand-charcoal: #231f20;\n  --brand-gray: #262522;\n  --brand-yellow: #fcba28;\n  --brand-pink: #f38ba3;\n  --brand-green: #0ba95b;\n  --brand-purple: #7b5ea7;\n  --brand-beige: #f9f4da;\n  --brand-blue: #12b5e5;\n  --brand-orange: #fc7428;\n  --brand-red: #ed203d;\n  --brand-white: #ffffff;\n  --gentlePeachLol: #f99157;\n  --magesticPurple: #9d7dce;\n\n  --red: var(--brand-red);\n  --white: var(--brand-beige);\n  --purple: var(--brand-purple);\n  --black: var(--brand-coal);\n  --blue: var(--brand-blue);\n  --pink: var(--brand-pink);\n  --gold: var(--brand-yellow);\n  --aqua: var(--brand-blue);\n  --gray: var(--brand-gray);\n  --yellow: var(--brand-yellow);\n  --green: var(--brand-green);\n  --orange: var(--brand-orange);\n  --charcoal: var(--brand-charcoal);\n  --coal: var(--brand-coal);\n\n  --border-dark: 0.12rem solid var(--charcoal);\n  --border-dark-shadow: 0 0 0 0.1rem var(--charcoal);\n  --border-light: 0.07rem solid rgba(249, 244, 218, 0.5);\n\n  --body-padding: 2rem;\n  --body-border: 1.3rem;\n\n  --font-outfit: Outfit, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,\n    Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif;\n  --font-paytone: \"Paytone One\", Outfit, -apple-system, BlinkMacSystemFont,\n    Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif;\n\n  --font-lg: clamp(2rem, 8vw, 4rem);\n  --font-md: clamp(1.6rem, 4vw, 2.1rem);\n  --font-base: clamp(1.2rem, 2.5vw, 1.5rem);\n  --font-sm: clamp(0.8rem, 2vw, 1rem);\n\n  --focus-object: 0 0 0 0.2rem var(--blue), 0 0 0 0.27rem var(--white);\n  --focus-text: 0 0 0 0.2rem var(--charcoal), 0 0 0 0.27rem var(--blue);\n\n  --nav-height: 4rem;\n}\n\nhtml {\n  font-size: 1em;\n  scroll-behavior: smooth;\n}\n\nbody {\n  padding: var(--body-padding);\n  background-color: var(--coal);\n  border: var(--body-border) solid var(--charcoal);\n  font-size: var(--font-base);\n  font-family: var(--font-outfit);\n  text-rendering: optimizeLegibility;\n  -webkit-font-smoothing: antialiased;\n  line-height: 1.4;\n  color: var(--white);\n}\n\n@media screen and (max-width: 700px) {\n  :root {\n    --body-padding: 1rem;\n    --body-border: 0.7rem;\n  }\n}\n\n:not(pre) > code {\n  padding: .3rem .4rem;\n  background-color: var(--brand-charcoal);\n  border-radius: 3px;\n  font-size: var(--font-sm);\n  font-family: Fira Code;\n  letter-spacing: -0.2px;\n}\n\nh1,\nh2,\nh3,\nh4 {\n  font-family: var(--font-paytone);\n  text-transform: uppercase;\n  line-height: 1.2;\n}\n\nh1 {\n  font-size: var(--font-lg);\n}\n\nh2 {\n  font-size: var(--font-md);\n}\n\nsmall {\n  font-size: var(--font-sm);\n}\n\nimg {\n  height: auto;\n  display: block;\n}\n\n\na {\n  transition: all 150ms ease-in-out;\n}\n\np a {\n  color: var(--yellow);\n  text-decoration: underline;\n}\n\np a:not(.logo):hover {\n  background-color: var(--yellow);\n  color: var(--coal);\n}\n\na:focus-visible {\n  outline: none;\n}\n\na:not(.image):focus-visible {\n  color: var(--coal);\n  background-color: var(--yellow);\n  box-shadow: var(--focus-text);\n}\n\na.image:focus-visible {\n  box-shadow: var(--focus-object);\n}\n\nbutton:focus-visible {\n  outline: none;\n  background-color: var(--yellow);\n  color: var(--coal);\n  box-shadow: var(--focus-object);\n}\n\nul {\n  list-style: none;\n}\n\np + p {\n  margin-top: 1.5em;\n}\n"
  },
  {
    "path": "usehooks.com/tailwind.config.cjs",
    "content": "/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n  content: [\"./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}\"],\n  theme: {\n    extend: {\n      boxShadow: {\n        sm: \"var(--focus-object)\",\n      },\n      colors: {\n        brand: {\n          coal: \"#0f0d0e\",\n          gray: \"#262522\",\n          charcoal: \"#231F20\",\n          charcoalMuted: \"#1B1918\",\n          orange: \"#FC7428\",\n          yellow: \"#FCBA28\",\n          pink: \"#F38BA3\",\n          green: \"#0BA95B\",\n          purple: \"#7B5EA7\",\n          beige: \"#F9F4DA\",\n          blue: \"#12B5E5\",\n          red: \"#ED203D\",\n          white: \"#FFFFFF\",\n        },\n      },\n    },\n  },\n  plugins: [],\n};\n"
  },
  {
    "path": "usehooks.com/theme.json",
    "content": "{\n  \"name\": \"uidotdev\",\n  \"type\": \"dark\",\n  \"semanticHighlighting\": true,\n  \"semanticTokenColors\": {\n    \"enumMember\": {\n      \"foreground\": \"#12b5e5\"\n    },\n    \"variable.constant\": {\n      \"foreground\": \"#fcba28\"\n    },\n    \"variable.defaultLibrary\": {\n      \"foreground\": \"#12b5e5\"\n    }\n  },\n  \"tokenColors\": [\n    {\n      \"name\": \"Text\",\n      \"scope\": \"variable.parameter.function\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"js/ts punctuation separator key-value\",\n      \"scope\": \"punctuation.separator.key-value\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"js/ts import keyword\",\n      \"scope\": \"keyword.operator.expression.import\",\n      \"settings\": {\n        \"foreground\": \"#9d7dce\"\n      }\n    },\n    {\n      \"name\": \"math js/ts\",\n      \"scope\": \"support.constant.math\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"math property js/ts\",\n      \"scope\": \"support.constant.property.math\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    {\n      \"name\": \"js/ts variable.other.constant\",\n      \"scope\": \"variable.other.constant\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"operator logical\",\n      \"scope\": \"keyword.operator.logical\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"operator bitwise\",\n      \"scope\": \"keyword.operator.bitwise\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"operator channel\",\n      \"scope\": \"keyword.operator.channel\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"support.constant.property-value.scss\",\n      \"scope\": \"support.constant.property-value.scss,support.constant.property-value.css\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    \n    {\n      \"name\": \"js/ts module\",\n      \"scope\": \"support.module.node,support.type.object.module,support.module.node\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"entity.name.type.module\",\n      \"scope\": \"entity.name.type.module\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"js variable readwrite\",\n      \"scope\": \"variable.other.readwrite,meta.object-literal.key,support.variable.property,support.variable.object.process,support.variable.object.node\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"js/ts json\",\n      \"scope\": \"support.constant.json\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    {\n      \"name\": \"js/ts Keyword\",\n      \"scope\": [\n        \"keyword.operator.expression.instanceof\",\n        \"keyword.operator.new\",\n        \"keyword.operator.ternary\",\n        \"keyword.operator.optional\",\n        \"keyword.operator.expression.keyof\"\n      ],\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"js/ts console\",\n      \"scope\": \"support.type.object.console\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"js/ts support.variable.property.process\",\n      \"scope\": \"support.variable.property.process\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    {\n      \"name\": \"js console function\",\n      \"scope\": \"entity.name.function,support.function.console\",\n      \"settings\": {\n        \"foreground\": \"#9d7dce\"\n      }\n    },\n    {\n      \"name\": \"operator\",\n      \"scope\": \"keyword.operator.delete\",\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"js dom\",\n      \"scope\": \"support.type.object.dom\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"js dom variable\",\n      \"scope\": \"support.variable.dom,support.variable.property.dom\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"keyword.operator\",\n      \"scope\": \"keyword.operator.arithmetic,keyword.operator.comparison,keyword.operator.decrement,keyword.operator.increment,keyword.operator.relational\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Punctuation\",\n      \"scope\": \"punctuation.separator.delimiter\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"Operators\",\n      \"scope\": \"keyword.operator\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"Compound Assignment Operators\",\n      \"scope\": \"keyword.operator.assignment.compound\",\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"Compound Assignment Operators js/ts\",\n      \"scope\": \"keyword.operator.assignment.compound.js,keyword.operator.assignment.compound.ts\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Keywords\",\n      \"scope\": \"keyword\",\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"Namespaces\",\n      \"scope\": \"entity.name.namespace\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Variables\",\n      \"scope\": \"variable\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"Language variables\",\n      \"scope\": \"variable.language\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Packages\",\n      \"scope\": \"token.package.keyword\",\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"Packages\",\n      \"scope\": \"token.package\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"Functions\",\n      \"scope\": [\n        \"entity.name.function\",\n        \"meta.require\",\n        \"support.function.any-method\",\n        \"variable.function\"\n      ],\n      \"settings\": {\n        \"foreground\": \"#9d7dce\"\n      }\n    },\n    {\n      \"name\": \"Classes\",\n      \"scope\": \"entity.name.type.namespace\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Classes\",\n      \"scope\": \"support.class, entity.name.type.class\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Class name\",\n      \"scope\": \"entity.name.class.identifier.namespace.type\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Class name\",\n      \"scope\": [\n        \"entity.name.class\",\n        \"variable.other.class.js\",\n        \"variable.other.class.ts\"\n      ],\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Type Name\",\n      \"scope\": \"entity.name.type\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Keyword Control\",\n      \"scope\": \"keyword.control\",\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"Control Elements\",\n      \"scope\": \"control.elements, keyword.operator.less\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    {\n      \"name\": \"Methods\",\n      \"scope\": \"keyword.other.special-method\",\n      \"settings\": {\n        \"foreground\": \"#9d7dce\"\n      }\n    },\n    {\n      \"name\": \"Storage\",\n      \"scope\": \"storage\",\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"Storage JS TS\",\n      \"scope\": \"token.storage\",\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"Source Js Keyword Operator Delete,source Js Keyword Operator In,source Js Keyword Operator Of,source Js Keyword Operator Instanceof,source Js Keyword Operator New,source Js Keyword Operator Typeof,source Js Keyword Operator Void\",\n      \"scope\": \"keyword.operator.expression.delete,keyword.operator.expression.in,keyword.operator.expression.of,keyword.operator.expression.instanceof,keyword.operator.new,keyword.operator.expression.typeof,keyword.operator.expression.void\",\n      \"settings\": {\n        \"foreground\": \"#f38ba3\"\n      }\n    },\n    {\n      \"name\": \"Support\",\n      \"scope\": \"support.function\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Support type\",\n      \"scope\": \"support.type.property-name\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"Support type\",\n      \"scope\": \"support.constant.property-value\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"Support type\",\n      \"scope\": \"support.constant.font-name\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    {\n      \"name\": \"Meta tag\",\n      \"scope\": \"meta.tag\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"Strings\",\n      \"scope\": \"string\",\n      \"settings\": {\n        \"foreground\": \"#f99157\"\n      }\n    },\n    {\n      \"name\": \"Inherited Class\",\n      \"scope\": \"entity.other.inherited-class\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Constant other symbol\",\n      \"scope\": \"constant.other.symbol\",\n      \"settings\": {\n        \"foreground\": \"#12b5e5\"\n      }\n    },\n    {\n      \"name\": \"Integers\",\n      \"scope\": \"constant.numeric\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    {\n      \"name\": \"Constants\",\n      \"scope\": \"constant\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    {\n      \"name\": \"Tags\",\n      \"scope\": \"entity.name.tag\",\n      \"settings\": {\n        \"foreground\": \"#f9f4da\"\n      }\n    },\n    {\n      \"name\": \"Attributes\",\n      \"scope\": \"entity.other.attribute-name\",\n      \"settings\": {\n        \"foreground\": \"#fcba28\"\n      }\n    },\n    {\n      \"name\": \"Attribute IDs\",\n      \"scope\": \"entity.other.attribute-name.id\",\n      \"settings\": {\n        \"fontStyle\": \"normal\",\n        \"foreground\": \"#9d7dce\"\n      }\n    },\n    {\n      \"name\": \"js/ts italic\",\n      \"scope\": \"entity.other.attribute-name.js,entity.other.attribute-name.ts,entity.other.attribute-name.jsx,entity.other.attribute-name.tsx,variable.parameter,variable.language.super\",\n      \"settings\": {\n        \"fontStyle\": \"italic\"\n      }\n    },\n    {\n      \"name\": \"comment\",\n      \"scope\": \"comment.line.double-slash,comment.block.documentation\",\n      \"settings\": {\n        \"fontStyle\": \"italic\"\n      }\n    }\n  ],\n  \"colors\": {\n    \"foreground\": \"#f9f4da\",\n    \"editor.background\": \"#231f20\",\n    \"editor.foreground\": \"#f9f4da\"\n  }\n}\n"
  },
  {
    "path": "usehooks.com/tsconfig.json",
    "content": "{\n  \"extends\": \"astro/tsconfigs/base\",\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"jsxImportSource\": \"react\",\n    \"plugins\": [\n      {\n        \"name\": \"@astrojs/ts-plugin\"\n      },\n    ]\n  },\n}"
  },
  {
    "path": "usehooks.com/vercel.json",
    "content": "{\n  \"trailingSlash\": false,\n  \"rewrites\": [\n    {\n      \"source\": \"/stats/js/script.js\",\n      \"destination\": \"https://plausible.io/js/script.js\"\n    },\n    {\n      \"source\": \"/stats/api/event\",\n      \"destination\": \"https://plausible.io/api/event\"\n    }\n  ],\n  \"redirects\": [\n    {\n      \"source\": \"/useOnClickOutside\",\n      \"destination\": \"/useclickaway\"\n    },\n    {\n      \"source\": \"/useOnScreen\",\n      \"destination\": \"/useintersectionobserver\"\n    },\n    {\n      \"source\": \"/useWhyDidYouUpdate\",\n      \"destination\": \"/userenderinfo\"\n    },\n    {\n      \"source\": \"/useSize\",\n      \"destination\": \"/usemeasure\"\n    },\n    {\n      \"source\": \"/useDebounce\",\n      \"destination\": \"/usedebounce\"\n    },\n    {\n      \"source\": \"/useThrottle\",\n      \"destination\": \"/usethrottle\"\n    },\n    {\n      \"source\": \"/usePrevious\",\n      \"destination\": \"/useprevious\"\n    },\n    {\n      \"source\": \"/useEventListener\",\n      \"destination\": \"/useeventlistener\"\n    },\n    {\n      \"source\": \"/useLockBodyScroll\",\n      \"destination\": \"/uselockbodyscroll\"\n    },\n    {\n      \"source\": \"/useToggle\",\n      \"destination\": \"/usetoggle\"\n    },\n    {\n      \"source\": \"/useKeyPress\",\n      \"destination\": \"/usekeypress\"\n    },\n    {\n      \"source\": \"/useScript\",\n      \"destination\": \"/usescript\"\n    },\n    {\n      \"source\": \"/useMemoCompare\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useMedia\",\n      \"destination\": \"/usemediaquery\"\n    },\n    {\n      \"source\": \"/useHistory\",\n      \"destination\": \"/usehistorystate\"\n    },\n    {\n      \"source\": \"/useWindowSize\",\n      \"destination\": \"/usewindowsize\"\n    },\n    {\n      \"source\": \"/useHover\",\n      \"destination\": \"/usehover\"\n    },\n    {\n      \"source\": \"/useLocalStorage\",\n      \"destination\": \"/uselocalstorage\"\n    },\n    {\n      \"source\": \"/useAnimation\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useSpring\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useAuth\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useRequireAuth\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useFirestoreQuery\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useRouter\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useMemo\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useTheme\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useDarkMode\",\n      \"destination\": \"/\"\n    },\n    {\n      \"source\": \"/useAsync\",\n      \"destination\": \"/\"\n    }\n  ]\n}\n"
  }
]