{"version":3,"sources":["../src/body-scroll-lock.ts"],"names":[],"mappings":"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","file":"body-scroll-lock.mjs","sourcesContent":["import { IN_WINDOW } from '@fastkit/helpers';\n\nexport interface BodyScrollOptions {\n  reserveScrollBarGap?: boolean;\n  allowTouchMove?: (el: EventTarget) => boolean;\n}\n\ninterface Lock {\n  targetElement: any;\n  options: BodyScrollOptions;\n}\n\nconst isIosDevice =\n  IN_WINDOW &&\n  !!window.navigator &&\n  !!window.navigator.platform &&\n  /iP(ad|hone|od)/.test(window.navigator.platform);\ntype HandleScrollEvent = TouchEvent;\n\nlet locks: Array<Lock> = [];\nlet documentListenerAdded = false;\nlet initialClientY = -1;\nlet previousBodyOverflowSetting: string | undefined;\nlet previousBodyPaddingRight: string | undefined;\n\n// returns true if `el` should be allowed to receive touchmove events.\nconst allowTouchMove = (el: EventTarget): boolean =>\n  locks.some((lock) => {\n    if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) {\n      return true;\n    }\n\n    return false;\n  });\n\nconst preventDefault = (rawEvent: HandleScrollEvent): boolean => {\n  const e = rawEvent || window.event;\n\n  // For the case whereby consumers adds a touchmove event listener to document.\n  // Recall that we do document.addEventListener('touchmove', preventDefault, { passive: false })\n  // in disableBodyScroll - so if we provide this opportunity to allowTouchMove, then\n  // the touchmove event on document will break.\n  if (allowTouchMove((e as any).target)) {\n    return true;\n  }\n\n  // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom).\n  if (e.touches.length > 1) return true;\n\n  if (e.preventDefault) e.preventDefault();\n\n  return false;\n};\n\nconst setOverflowHidden = (options?: BodyScrollOptions) => {\n  // Setting overflow on body/documentElement synchronously in Desktop Safari slows down\n  // the responsiveness for some reason. Setting within a setTimeout fixes this.\n  setTimeout(() => {\n    // If previousBodyPaddingRight is already set, don't set it again.\n    if (previousBodyPaddingRight === undefined) {\n      const reserveScrollBarGap =\n        !!options && options.reserveScrollBarGap === true;\n      const scrollBarGap =\n        window.innerWidth - document.documentElement.clientWidth;\n\n      if (reserveScrollBarGap && scrollBarGap > 0) {\n        previousBodyPaddingRight = document.body.style.paddingRight;\n        document.body.style.paddingRight = `${scrollBarGap}px`;\n      }\n    }\n\n    // If previousBodyOverflowSetting is already set, don't set it again.\n    if (previousBodyOverflowSetting === undefined) {\n      previousBodyOverflowSetting = document.body.style.overflow;\n      document.body.style.overflow = 'hidden';\n    }\n  });\n};\n\nconst restoreOverflowSetting = () => {\n  // Setting overflow on body/documentElement synchronously in Desktop Safari slows down\n  // the responsiveness for some reason. Setting within a setTimeout fixes this.\n  setTimeout(() => {\n    if (previousBodyPaddingRight !== undefined) {\n      document.body.style.paddingRight = previousBodyPaddingRight;\n\n      // Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it\n      // can be set again.\n      previousBodyPaddingRight = undefined;\n    }\n\n    if (previousBodyOverflowSetting !== undefined) {\n      document.body.style.overflow = previousBodyOverflowSetting;\n\n      // Restore previousBodyOverflowSetting to undefined\n      // so setOverflowHidden knows it can be set again.\n      previousBodyOverflowSetting = undefined;\n    }\n  });\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions\nconst isTargetElementTotallyScrolled = (targetElement: any): boolean =>\n  targetElement\n    ? targetElement.scrollHeight - targetElement.scrollTop <=\n      targetElement.clientHeight\n    : false;\n\nconst handleScroll = (\n  event: HandleScrollEvent,\n  targetElement: any,\n): boolean => {\n  const clientY = event.targetTouches[0].clientY - initialClientY;\n\n  if (allowTouchMove(event.target as any)) {\n    return false;\n  }\n\n  if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {\n    // element is at the top of its scroll.\n    return preventDefault(event);\n  }\n\n  if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) {\n    // element is at the top of its scroll.\n    return preventDefault(event);\n  }\n\n  event.stopPropagation();\n  return true;\n};\n\nexport const disableBodyScroll = (\n  targetElement: any,\n  options?: BodyScrollOptions,\n): void => {\n  if (!IN_WINDOW) return;\n\n  if (isIosDevice) {\n    // targetElement must be provided, and disableBodyScroll must not have been\n    // called on this targetElement before.\n    if (!targetElement) {\n      // eslint-disable-next-line no-console\n      console.error(\n        'disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.',\n      );\n      return;\n    }\n\n    if (\n      targetElement &&\n      !locks.some((lock) => lock.targetElement === targetElement)\n    ) {\n      const lock = {\n        targetElement,\n        options: options || {},\n      };\n\n      locks = [...locks, lock];\n\n      targetElement.ontouchstart = (event: HandleScrollEvent) => {\n        if (event.targetTouches.length === 1) {\n          // detect single touch.\n          initialClientY = event.targetTouches[0].clientY;\n        }\n      };\n      targetElement.ontouchmove = (event: HandleScrollEvent) => {\n        if (event.targetTouches.length === 1) {\n          // detect single touch.\n          handleScroll(event, targetElement);\n        }\n      };\n\n      if (!documentListenerAdded) {\n        document.addEventListener('touchmove', preventDefault, {\n          passive: false,\n        });\n        documentListenerAdded = true;\n      }\n    }\n  } else {\n    setOverflowHidden(options);\n    const lock = {\n      targetElement,\n      options: options || {},\n    };\n\n    locks = [...locks, lock];\n  }\n};\n\nexport const clearAllBodyScrollLocks = (): void => {\n  if (!IN_WINDOW) return;\n\n  if (isIosDevice) {\n    // Clear all locks ontouchstart/ontouchmove handlers, and the references.\n    locks.forEach((lock: Lock) => {\n      lock.targetElement.ontouchstart = null;\n      lock.targetElement.ontouchmove = null;\n    });\n\n    if (documentListenerAdded) {\n      document.removeEventListener(\n        'touchmove',\n        preventDefault as any,\n        { passive: false } as any,\n      );\n      documentListenerAdded = false;\n    }\n\n    locks = [];\n\n    // Reset initial clientY.\n    initialClientY = -1;\n  } else {\n    restoreOverflowSetting();\n    locks = [];\n  }\n};\n\nexport const enableBodyScroll = (targetElement: any): void => {\n  if (!IN_WINDOW) return;\n\n  if (isIosDevice) {\n    if (!targetElement) {\n      // eslint-disable-next-line no-console\n      console.error(\n        'enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.',\n      );\n      return;\n    }\n\n    targetElement.ontouchstart = null;\n    targetElement.ontouchmove = null;\n\n    locks = locks.filter((lock) => lock.targetElement !== targetElement);\n\n    if (documentListenerAdded && locks.length === 0) {\n      document.removeEventListener(\n        'touchmove',\n        preventDefault as any,\n        { passive: false } as any,\n      );\n\n      documentListenerAdded = false;\n    }\n  } else {\n    locks = locks.filter((lock) => lock.targetElement !== targetElement);\n    if (!locks.length) {\n      restoreOverflowSetting();\n    }\n  }\n};\n"]}