{"mappings":"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","sources":["packages/react-aria/src/overlays/usePreventScroll.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {chain} from '../utils/chain';\n\nimport {getActiveElement, getEventTarget} from '../utils/shadowdom/DOMFunctions';\nimport {getNonce} from '../utils/getNonce';\nimport {getScrollParent} from '../utils/getScrollParent';\nimport {isIOS} from '../utils/platform';\nimport {isScrollable} from '../utils/isScrollable';\nimport {useLayoutEffect} from '../utils/useLayoutEffect';\nimport {willOpenKeyboard} from '../utils/keyboard';\n\ninterface PreventScrollOptions {\n  /** Whether the scroll lock is disabled. */\n  isDisabled?: boolean\n}\n\nconst visualViewport = typeof document !== 'undefined' && window.visualViewport;\n\n// The number of active usePreventScroll calls. Used to determine whether to revert back to the original page style/scroll position\nlet preventScrollCount = 0;\nlet restore;\n\n/**\n * Prevents scrolling on the document body on mount, and\n * restores it on unmount. Also ensures that content does not\n * shift due to the scrollbars disappearing.\n */\nexport function usePreventScroll(options: PreventScrollOptions = {}): void {\n  let {isDisabled} = options;\n\n  useLayoutEffect(() => {\n    if (isDisabled) {\n      return;\n    }\n\n    preventScrollCount++;\n    if (preventScrollCount === 1) {\n      if (isIOS()) {\n        restore = preventScrollMobileSafari();\n      } else {\n        restore = preventScrollStandard();\n      }\n    }\n\n    return () => {\n      preventScrollCount--;\n      if (preventScrollCount === 0) {\n        restore();\n      }\n    };\n  }, [isDisabled]);\n}\n\n// For most browsers, all we need to do is set `overflow: hidden` on the root element, and\n// add some padding to prevent the page from shifting when the scrollbar is hidden.\nfunction preventScrollStandard() {\n  let scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n  return chain(\n    scrollbarWidth > 0 &&\n      // Use scrollbar-gutter when supported because it also works for fixed positioned elements.\n      ('scrollbarGutter' in document.documentElement.style\n        ? setStyle(document.documentElement, 'scrollbarGutter', 'stable')\n        : setStyle(document.documentElement, 'paddingRight', `${scrollbarWidth}px`)),\n    setStyle(document.documentElement, 'overflow', 'hidden')\n  );\n}\n\n// Mobile Safari is a whole different beast. Even with overflow: hidden,\n// it still scrolls the page in many situations:\n//\n// 1. When the bottom toolbar and address bar are collapsed, page scrolling is always allowed.\n// 2. When the keyboard is visible, the viewport does not resize. Instead, the keyboard covers part of\n//    it, so it becomes scrollable.\n// 3. When tapping on an input, the page always scrolls so that the input is centered in the visual viewport.\n//    This may cause even fixed position elements to scroll off the screen.\n// 4. When using the next/previous buttons in the keyboard to navigate between inputs, the whole page always\n//    scrolls, even if the input is inside a nested scrollable element that could be scrolled instead.\n//\n// In order to work around these cases, and prevent scrolling without jankiness, we do a few things:\n//\n// 1. Prevent default on `touchmove` events that are not in a scrollable element. This prevents touch scrolling\n//    on the window.\n// 2. Set `overscroll-behavior: contain` on nested scrollable regions so they do not scroll the page when at\n//    the top or bottom. Work around a bug where this does not work when the element does not actually overflow\n//    by preventing default in a `touchmove` event. This is best effort: we can't prevent default when pinch\n//    zooming or when an element contains text selection, which may allow scrolling in some cases.\n// 3. Prevent default on `touchend` events on input elements and handle focusing the element ourselves.\n// 4. When focus moves to an input, create an off screen input and focus that temporarily. This prevents\n//    Safari from scrolling the page. After a small delay, focus the real input and scroll it into view\n//    ourselves, without scrolling the whole page.\nfunction preventScrollMobileSafari() {\n  // Set overflow hidden so scrollIntoViewport() (useSelectableCollection) sees isScrollPrevented and\n  // scrolls only scroll parents instead of calling native scrollIntoView() which moves the window.\n  let restoreOverflow = setStyle(document.documentElement, 'overflow', 'hidden');\n\n  let scrollable: Element;\n  let allowTouchMove = false;\n  let onTouchStart = (e: TouchEvent) => {\n    // Store the nearest scrollable parent element from the element that the user touched.\n    let target = getEventTarget(e) as Element;\n    scrollable = isScrollable(target) ? target : getScrollParent(target, true);\n    allowTouchMove = false;\n\n    // If the target is selected, don't preventDefault in touchmove to allow user to adjust selection.\n    let selection = target.ownerDocument.defaultView!.getSelection();\n    if (selection && !selection.isCollapsed && selection.containsNode(target, true)) {\n      allowTouchMove = true;\n    }\n\n    // If this is a range input, allow touch move to allow user to adjust the slider value\n    if (e.composedPath().some((el) =>\n      el instanceof HTMLInputElement &&\n      el.type === 'range'\n    )) {\n      allowTouchMove = true;\n    }\n\n    // If this is a focused input element with a selected range, allow user to drag the selection handles.\n    if (\n      'selectionStart' in target &&\n      'selectionEnd' in target &&\n      (target.selectionStart as number) < (target.selectionEnd as number) &&\n      target.ownerDocument.activeElement === target\n    ) {\n      allowTouchMove = true;\n    }\n  };\n\n  // Prevent scrolling up when at the top and scrolling down when at the bottom\n  // of a nested scrollable area, otherwise mobile Safari will start scrolling\n  // the window instead.\n  // This must be applied before the touchstart event as of iOS 26, so inject it as a <style> element.\n  let style = document.createElement('style');\n  let nonce = getNonce();\n  if (nonce) {\n    style.nonce = nonce;\n  }\n  style.textContent = `\n@layer {\n  * {\n    overscroll-behavior: contain;\n  }\n}`.trim();\n  document.head.prepend(style);\n\n  let onTouchMove = (e: TouchEvent) => {\n    // Allow pinch-zooming.\n    if (e.touches.length === 2 || allowTouchMove) {\n      return;\n    }\n\n    // Prevent scrolling the window.\n    if (!scrollable || scrollable === document.documentElement || scrollable === document.body) {\n      e.preventDefault();\n      return;\n    }\n\n    // overscroll-behavior should prevent scroll chaining, but currently does not\n    // if the element doesn't actually overflow. https://bugs.webkit.org/show_bug.cgi?id=243452\n    // This checks that both the width and height do not overflow, otherwise we might\n    // block horizontal scrolling too. In that case, adding `touch-action: pan-x` to\n    // the element will prevent vertical page scrolling. We can't add that automatically\n    // because it must be set before the touchstart event.\n    if (scrollable.scrollHeight === scrollable.clientHeight && scrollable.scrollWidth === scrollable.clientWidth) {\n      e.preventDefault();\n    }\n  };\n\n  let onBlur = (e: FocusEvent) => {\n    let target = getEventTarget(e) as HTMLElement;\n    let relatedTarget = e.relatedTarget as HTMLElement | null;\n    if (relatedTarget && willOpenKeyboard(relatedTarget)) {\n      // Focus without scrolling the whole page, and then scroll into view manually.\n      relatedTarget.focus({preventScroll: true});\n      scrollIntoViewWhenReady(relatedTarget, willOpenKeyboard(target));\n    } else if (!relatedTarget) {\n      // When tapping the Done button on the keyboard, focus moves to the body.\n      // FocusScope will then restore focus back to the input. Later when tapping\n      // the same input again, it is already focused, so no blur event will fire,\n      // resulting in the flow above never running and Safari's native scrolling occurring.\n      // Instead, move focus to the parent focusable element (e.g. the dialog).\n      let focusable = target.parentElement?.closest('[tabindex]') as HTMLElement | null;\n      focusable?.focus({preventScroll: true});\n    }\n  };\n\n  // Override programmatic focus to scroll into view without scrolling the whole page.\n  let focus = HTMLElement.prototype.focus;\n  HTMLElement.prototype.focus = function (opts) {\n    // Track whether the keyboard was already visible before.\n    let activeElement = getActiveElement();\n    let wasKeyboardVisible = activeElement != null && willOpenKeyboard(activeElement);\n\n    // Focus the element without scrolling the page.\n    focus.call(this, {...opts, preventScroll: true});\n\n    if (!opts || !opts.preventScroll) {\n      scrollIntoViewWhenReady(this, wasKeyboardVisible);\n    }\n  };\n\n  let removeEvents = chain(\n    addEvent(document, 'touchstart', onTouchStart, {passive: false, capture: true}),\n    addEvent(document, 'touchmove', onTouchMove, {passive: false, capture: true}),\n    addEvent(document, 'blur', onBlur, true)\n  );\n\n  return () => {\n    restoreOverflow();\n    removeEvents();\n    style.remove();\n    HTMLElement.prototype.focus = focus;\n  };\n}\n\n// Sets a CSS property on an element, and returns a function to revert it to the previous value.\nfunction setStyle(element: HTMLElement, style: string, value: string) {\n  let cur = element.style[style];\n  element.style[style] = value;\n\n  return () => {\n    element.style[style] = cur;\n  };\n}\n\n// Adds an event listener to an element, and returns a function to remove it.\nfunction addEvent<K extends keyof GlobalEventHandlersEventMap>(\n  target: Document | Window,\n  event: K,\n  handler: (this: Document | Window, ev: GlobalEventHandlersEventMap[K]) => any,\n  options?: boolean | AddEventListenerOptions\n) {\n  // internal function, so it's ok to ignore the difficult to fix type error\n  // @ts-ignore\n  target.addEventListener(event, handler, options);\n  return () => {\n    // @ts-ignore\n    target.removeEventListener(event, handler, options);\n  };\n}\n\nfunction scrollIntoViewWhenReady(target: Element, wasKeyboardVisible: boolean) {\n  if (wasKeyboardVisible || !visualViewport) {\n    // If the keyboard was already visible, scroll the target into view immediately.\n    scrollIntoView(target);\n  } else {\n    // Otherwise, wait for the visual viewport to resize before scrolling so we can\n    // measure the correct position to scroll to.\n    visualViewport.addEventListener('resize', () => scrollIntoView(target), {once: true});\n  }\n}\n\nfunction scrollIntoView(target: Element) {\n  let root = document.scrollingElement || document.documentElement;\n  let nextTarget: Element | null = target;\n  while (nextTarget && nextTarget !== root) {\n    // Find the parent scrollable element and adjust the scroll position if the target is not already in view.\n    let scrollable = getScrollParent(nextTarget);\n    if (scrollable !== document.documentElement && scrollable !== document.body && scrollable !== nextTarget) {\n      let scrollableRect = scrollable.getBoundingClientRect();\n      let targetRect = nextTarget.getBoundingClientRect();\n      if (targetRect.top < scrollableRect.top || targetRect.bottom > scrollableRect.top + nextTarget.clientHeight) {\n        let bottom = scrollableRect.bottom;\n        if (visualViewport) {\n          bottom = Math.min(bottom, visualViewport.offsetTop + visualViewport.height);\n        }\n\n        // Center within the viewport.\n        let adjustment = (targetRect.top - scrollableRect.top) - ((bottom - scrollableRect.top) / 2 - targetRect.height / 2);\n        scrollable.scrollTo({\n          // Clamp to the valid range to prevent over-scrolling.\n          top: Math.max(0, Math.min(scrollable.scrollHeight - scrollable.clientHeight, scrollable.scrollTop + adjustment)),\n          behavior: 'smooth'\n        });\n      }\n    }\n\n    nextTarget = scrollable.parentElement;\n  }\n}\n"],"names":[],"version":3,"file":"usePreventScroll.cjs.map"}