{"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"]}