{
  "name": "use-scroll-lock",
  "author": "Brendan Dash (https://shadcn-hooks.com)",
  "description": "A hook to lock the scroll of the body",
  "registryDependencies": [
    "@shadcnhooks/use-isomorphic-layout-effect",
    "@shadcnhooks/is-browser"
  ],
  "files": [
    {
      "path": "registry/hooks/use-scroll-lock.ts",
      "content": "import { useCallback, useRef, useState } from 'react'\nimport { useIsomorphicLayoutEffect } from '@/registry/hooks/use-isomorphic-layout-effect'\nimport { isBrowser } from '@/registry/lib/is-browser'\n\ninterface UseScrollLockOptions {\n  autoLock?: boolean\n  lockTarget?: HTMLElement | string\n  widthReflow?: boolean\n}\n\ninterface UseScrollLockReturn {\n  isLocked: boolean\n  lock: () => void\n  unlock: () => void\n}\n\ninterface OriginalStyle {\n  overflow: CSSStyleDeclaration['overflow']\n  paddingRight: CSSStyleDeclaration['paddingRight']\n}\n\nexport function useScrollLock(\n  options: UseScrollLockOptions = {},\n): UseScrollLockReturn {\n  const { autoLock = true, lockTarget, widthReflow = true } = options\n  const [isLocked, setIsLocked] = useState(false)\n  const target = useRef<HTMLElement | null>(null)\n  const originalStyle = useRef<OriginalStyle | null>(null)\n\n  const lock = useCallback(() => {\n    if (target.current) {\n      const { overflow, paddingRight } = target.current.style\n\n      // Save the original styles\n      originalStyle.current = { overflow, paddingRight }\n\n      // Prevent width reflow\n      if (widthReflow) {\n        // Use window inner width if body is the target as global scrollbar isn't part of the document\n        const offsetWidth =\n          target.current === document.body\n            ? window.innerWidth\n            : target.current.offsetWidth\n        // Get current computed padding right in pixels\n        const currentPaddingRight =\n          Number.parseInt(\n            window.getComputedStyle(target.current).paddingRight,\n            10,\n          ) || 0\n\n        const scrollbarWidth = offsetWidth - target.current.scrollWidth\n        target.current.style.paddingRight = `${scrollbarWidth + currentPaddingRight}px`\n      }\n\n      // Lock the scroll\n      target.current.style.overflow = 'hidden'\n\n      setIsLocked(true)\n    }\n  }, [widthReflow])\n\n  const unlock = useCallback(() => {\n    if (target.current && originalStyle.current) {\n      target.current.style.overflow = originalStyle.current.overflow\n\n      // Only reset padding right if we changed it\n      if (widthReflow) {\n        target.current.style.paddingRight = originalStyle.current.paddingRight\n      }\n    }\n\n    setIsLocked(false)\n  }, [widthReflow])\n\n  useIsomorphicLayoutEffect(() => {\n    if (!isBrowser) return\n\n    if (lockTarget) {\n      target.current =\n        typeof lockTarget === 'string'\n          ? document.querySelector(lockTarget)\n          : lockTarget\n    }\n\n    if (!target.current) {\n      target.current = document.body\n    }\n\n    if (autoLock) {\n      lock()\n    }\n\n    return () => {\n      unlock()\n    }\n  }, [autoLock, lockTarget, widthReflow])\n\n  return { isLocked, lock, unlock }\n}\n",
      "type": "registry:hook"
    }
  ],
  "type": "registry:hook"
}
