react-aria 3.51.0 → 3.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/exports/index.cjs +1 -0
  2. package/dist/exports/index.cjs.map +1 -1
  3. package/dist/exports/index.js +2 -2
  4. package/dist/exports/index.js.map +1 -1
  5. package/dist/exports/index.mjs +2 -2
  6. package/dist/exports/index.mjs.map +1 -1
  7. package/dist/exports/private/utils/domHelpers.cjs +1 -0
  8. package/dist/exports/private/utils/domHelpers.cjs.map +1 -1
  9. package/dist/exports/private/utils/domHelpers.js +2 -2
  10. package/dist/exports/private/utils/domHelpers.js.map +1 -1
  11. package/dist/exports/private/utils/domHelpers.mjs +2 -2
  12. package/dist/exports/private/utils/domHelpers.mjs.map +1 -1
  13. package/dist/exports/useFocusVisible.cjs +1 -0
  14. package/dist/exports/useFocusVisible.cjs.map +1 -1
  15. package/dist/exports/useFocusVisible.js +2 -2
  16. package/dist/exports/useFocusVisible.js.map +1 -1
  17. package/dist/exports/useFocusVisible.mjs +2 -2
  18. package/dist/exports/useFocusVisible.mjs.map +1 -1
  19. package/dist/private/actiongroup/useActionGroup.cjs +3 -1
  20. package/dist/private/actiongroup/useActionGroup.cjs.map +1 -1
  21. package/dist/private/actiongroup/useActionGroup.js +3 -1
  22. package/dist/private/actiongroup/useActionGroup.js.map +1 -1
  23. package/dist/private/actiongroup/useActionGroup.mjs +3 -1
  24. package/dist/private/actiongroup/useActionGroup.mjs.map +1 -1
  25. package/dist/private/calendar/useRangeCalendar.cjs +1 -1
  26. package/dist/private/calendar/useRangeCalendar.cjs.map +1 -1
  27. package/dist/private/calendar/useRangeCalendar.js +2 -2
  28. package/dist/private/calendar/useRangeCalendar.js.map +1 -1
  29. package/dist/private/calendar/useRangeCalendar.mjs +2 -2
  30. package/dist/private/calendar/useRangeCalendar.mjs.map +1 -1
  31. package/dist/private/color/useColorField.cjs +26 -4
  32. package/dist/private/color/useColorField.cjs.map +1 -1
  33. package/dist/private/color/useColorField.js +26 -4
  34. package/dist/private/color/useColorField.js.map +1 -1
  35. package/dist/private/color/useColorField.mjs +26 -4
  36. package/dist/private/color/useColorField.mjs.map +1 -1
  37. package/dist/private/combobox/useComboBox.cjs +1 -1
  38. package/dist/private/combobox/useComboBox.cjs.map +1 -1
  39. package/dist/private/combobox/useComboBox.js +1 -1
  40. package/dist/private/combobox/useComboBox.js.map +1 -1
  41. package/dist/private/combobox/useComboBox.mjs +1 -1
  42. package/dist/private/combobox/useComboBox.mjs.map +1 -1
  43. package/dist/private/focus/FocusScope.cjs +7 -2
  44. package/dist/private/focus/FocusScope.cjs.map +1 -1
  45. package/dist/private/focus/FocusScope.js +7 -2
  46. package/dist/private/focus/FocusScope.js.map +1 -1
  47. package/dist/private/focus/FocusScope.mjs +7 -2
  48. package/dist/private/focus/FocusScope.mjs.map +1 -1
  49. package/dist/private/interactions/useFocusVisible.cjs +15 -3
  50. package/dist/private/interactions/useFocusVisible.cjs.map +1 -1
  51. package/dist/private/interactions/useFocusVisible.js +15 -3
  52. package/dist/private/interactions/useFocusVisible.js.map +1 -1
  53. package/dist/private/interactions/useFocusVisible.mjs +15 -3
  54. package/dist/private/interactions/useFocusVisible.mjs.map +1 -1
  55. package/dist/private/interactions/utils.cjs +23 -13
  56. package/dist/private/interactions/utils.cjs.map +1 -1
  57. package/dist/private/interactions/utils.js +25 -15
  58. package/dist/private/interactions/utils.js.map +1 -1
  59. package/dist/private/interactions/utils.mjs +25 -15
  60. package/dist/private/interactions/utils.mjs.map +1 -1
  61. package/dist/private/overlays/calculatePosition.cjs +3 -2
  62. package/dist/private/overlays/calculatePosition.cjs.map +1 -1
  63. package/dist/private/overlays/calculatePosition.js +5 -2
  64. package/dist/private/overlays/calculatePosition.js.map +1 -1
  65. package/dist/private/overlays/calculatePosition.mjs +3 -2
  66. package/dist/private/overlays/calculatePosition.mjs.map +1 -1
  67. package/dist/private/overlays/useOverlayPosition.cjs +5 -0
  68. package/dist/private/overlays/useOverlayPosition.cjs.map +1 -1
  69. package/dist/private/overlays/useOverlayPosition.js +6 -1
  70. package/dist/private/overlays/useOverlayPosition.js.map +1 -1
  71. package/dist/private/overlays/useOverlayPosition.mjs +6 -1
  72. package/dist/private/overlays/useOverlayPosition.mjs.map +1 -1
  73. package/dist/private/overlays/usePreventScroll.cjs +27 -35
  74. package/dist/private/overlays/usePreventScroll.cjs.map +1 -1
  75. package/dist/private/overlays/usePreventScroll.js +27 -35
  76. package/dist/private/overlays/usePreventScroll.js.map +1 -1
  77. package/dist/private/overlays/usePreventScroll.mjs +27 -35
  78. package/dist/private/overlays/usePreventScroll.mjs.map +1 -1
  79. package/dist/private/selection/useSelectableCollection.cjs +1 -0
  80. package/dist/private/selection/useSelectableCollection.cjs.map +1 -1
  81. package/dist/private/selection/useSelectableCollection.js +1 -0
  82. package/dist/private/selection/useSelectableCollection.js.map +1 -1
  83. package/dist/private/selection/useSelectableCollection.mjs +1 -0
  84. package/dist/private/selection/useSelectableCollection.mjs.map +1 -1
  85. package/dist/private/tabs/TabsKeyboardDelegate.cjs +3 -1
  86. package/dist/private/tabs/TabsKeyboardDelegate.cjs.map +1 -1
  87. package/dist/private/tabs/TabsKeyboardDelegate.js +3 -1
  88. package/dist/private/tabs/TabsKeyboardDelegate.js.map +1 -1
  89. package/dist/private/tabs/TabsKeyboardDelegate.mjs +3 -1
  90. package/dist/private/tabs/TabsKeyboardDelegate.mjs.map +1 -1
  91. package/dist/private/tokenfield/useToken.cjs +19 -4
  92. package/dist/private/tokenfield/useToken.cjs.map +1 -1
  93. package/dist/private/tokenfield/useToken.js +20 -4
  94. package/dist/private/tokenfield/useToken.js.map +1 -1
  95. package/dist/private/tokenfield/useToken.mjs +19 -4
  96. package/dist/private/tokenfield/useToken.mjs.map +1 -1
  97. package/dist/private/tokenfield/useTokenField.cjs +172 -43
  98. package/dist/private/tokenfield/useTokenField.cjs.map +1 -1
  99. package/dist/private/tokenfield/useTokenField.js +175 -45
  100. package/dist/private/tokenfield/useTokenField.js.map +1 -1
  101. package/dist/private/tokenfield/useTokenField.mjs +173 -44
  102. package/dist/private/tokenfield/useTokenField.mjs.map +1 -1
  103. package/dist/private/utils/domHelpers.cjs +21 -0
  104. package/dist/private/utils/domHelpers.cjs.map +1 -1
  105. package/dist/private/utils/domHelpers.js +20 -1
  106. package/dist/private/utils/domHelpers.js.map +1 -1
  107. package/dist/private/utils/domHelpers.mjs +20 -1
  108. package/dist/private/utils/domHelpers.mjs.map +1 -1
  109. package/dist/private/utils/getMetaValue.cjs +36 -0
  110. package/dist/private/utils/getMetaValue.cjs.map +1 -0
  111. package/dist/private/utils/getMetaValue.js +31 -0
  112. package/dist/private/utils/getMetaValue.js.map +1 -0
  113. package/dist/private/utils/getMetaValue.mjs +31 -0
  114. package/dist/private/utils/getMetaValue.mjs.map +1 -0
  115. package/dist/private/utils/getNonce.cjs +6 -10
  116. package/dist/private/utils/getNonce.cjs.map +1 -1
  117. package/dist/private/utils/getNonce.js +7 -11
  118. package/dist/private/utils/getNonce.js.map +1 -1
  119. package/dist/private/utils/getNonce.mjs +7 -11
  120. package/dist/private/utils/getNonce.mjs.map +1 -1
  121. package/dist/private/utils/scrollIntoView.cjs +6 -2
  122. package/dist/private/utils/scrollIntoView.cjs.map +1 -1
  123. package/dist/private/utils/scrollIntoView.js +6 -3
  124. package/dist/private/utils/scrollIntoView.js.map +1 -1
  125. package/dist/private/utils/scrollIntoView.mjs +6 -3
  126. package/dist/private/utils/scrollIntoView.mjs.map +1 -1
  127. package/dist/private/utils/useEvent.cjs +7 -9
  128. package/dist/private/utils/useEvent.cjs.map +1 -1
  129. package/dist/private/utils/useEvent.js +7 -9
  130. package/dist/private/utils/useEvent.js.map +1 -1
  131. package/dist/private/utils/useEvent.mjs +7 -9
  132. package/dist/private/utils/useEvent.mjs.map +1 -1
  133. package/dist/types/exports/index.d.ts +2 -2
  134. package/dist/types/exports/private/utils/domHelpers.d.ts +1 -1
  135. package/dist/types/exports/useFocusVisible.d.ts +2 -1
  136. package/dist/types/src/tokenfield/useTokenField.d.ts +3 -2
  137. package/dist/types/src/utils/domHelpers.d.ts +6 -2
  138. package/dist/types/src/utils/getMetaValue.d.ts +7 -0
  139. package/dist/types/src/utils/scrollIntoView.d.ts +1 -0
  140. package/dist/types/src/utils/useEvent.d.ts +2 -2
  141. package/dist/types/src/virtualizer/Virtualizer.d.ts +3 -3
  142. package/package.json +6 -5
@@ -1 +1 @@
1
- {"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, isWebKit} 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() && isWebKit()) {\n restore = preventScrollMobileWebKit();\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.\nfunction preventScrollMobileWebKit() {\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 => el instanceof HTMLInputElement && el.type === 'range')) {\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 (\n scrollable.scrollHeight === scrollable.clientHeight &&\n scrollable.scrollWidth === scrollable.clientWidth\n ) {\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 (\n scrollable !== document.documentElement &&\n scrollable !== document.body &&\n scrollable !== nextTarget\n ) {\n let scrollableRect = scrollable.getBoundingClientRect();\n let targetRect = nextTarget.getBoundingClientRect();\n if (\n targetRect.top < scrollableRect.top ||\n targetRect.bottom > scrollableRect.top + nextTarget.clientHeight\n ) {\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 =\n targetRect.top -\n scrollableRect.top -\n ((bottom - scrollableRect.top) / 2 - targetRect.height / 2);\n scrollable.scrollTo({\n // Clamp to the valid range to prevent over-scrolling.\n top: Math.max(\n 0,\n Math.min(\n scrollable.scrollHeight - scrollable.clientHeight,\n scrollable.scrollTop + adjustment\n )\n ),\n behavior: 'smooth'\n });\n }\n }\n\n nextTarget = scrollable.parentElement;\n }\n}\n"],"names":[],"version":3,"file":"usePreventScroll.js.map"}
1
+ {"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 {addEvent} from '../utils/domHelpers';\nimport {chain} from '../utils/chain';\nimport {getActiveElement, getEventTarget} from '../utils/shadowdom/DOMFunctions';\nimport {getNonce} from '../utils/getNonce';\nimport {getScrollParent} from '../utils/getScrollParent';\nimport {isIOS, isWebKit} from '../utils/platform';\nimport {isScrollable} from '../utils/isScrollable';\nimport {setStyle} from '../utils/domHelpers';\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() && isWebKit()) {\n restore = preventScrollMobileWebKit();\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, 'scrollbar-gutter', 'stable')\n : setStyle(document.documentElement, 'padding-right', `${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.\nfunction preventScrollMobileWebKit() {\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 => el instanceof HTMLInputElement && el.type === 'range')) {\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 (\n scrollable.scrollHeight === scrollable.clientHeight &&\n scrollable.scrollWidth === scrollable.clientWidth\n ) {\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 Reflect.defineProperty(HTMLElement.prototype, 'focus', {\n configurable: true,\n writable: true,\n value: function (opts?: FocusOptions) {\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\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 Reflect.defineProperty(HTMLElement.prototype, 'focus', {\n configurable: true,\n writable: true,\n value: focus\n });\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 (\n scrollable !== document.documentElement &&\n scrollable !== document.body &&\n scrollable !== nextTarget\n ) {\n let scrollableRect = scrollable.getBoundingClientRect();\n let targetRect = nextTarget.getBoundingClientRect();\n if (\n targetRect.top < scrollableRect.top ||\n targetRect.bottom > scrollableRect.top + nextTarget.clientHeight\n ) {\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 =\n targetRect.top -\n scrollableRect.top -\n ((bottom - scrollableRect.top) / 2 - targetRect.height / 2);\n scrollable.scrollTo({\n // Clamp to the valid range to prevent over-scrolling.\n top: Math.max(\n 0,\n Math.min(\n scrollable.scrollHeight - scrollable.clientHeight,\n scrollable.scrollTop + adjustment\n )\n ),\n behavior: 'smooth'\n });\n }\n }\n\n nextTarget = scrollable.parentElement;\n }\n}\n"],"names":[],"version":3,"file":"usePreventScroll.js.map"}
@@ -1,3 +1,4 @@
1
+ import {addEvent as $d447af545b77c9f1$export$f531f92e2a15358f, setStyle as $d447af545b77c9f1$export$37a5fde709c1db82} from "../utils/domHelpers.mjs";
1
2
  import {chain as $a4e76a5424781910$export$e08e3b67e392101e} from "../utils/chain.mjs";
2
3
  import {getActiveElement as $23f2114a1b82827e$export$cd4e5573fbe2b576, getEventTarget as $23f2114a1b82827e$export$e58f029f0fbfdb29} from "../utils/shadowdom/DOMFunctions.mjs";
3
4
  import {getNonce as $2b2d34ff061957fb$export$2b85b721e524d74b} from "../utils/getNonce.mjs";
@@ -25,6 +26,7 @@ import {willOpenKeyboard as $bb39c0fc1c19b34c$export$c57958e35f31ed73} from "../
25
26
 
26
27
 
27
28
 
29
+
28
30
  const $0644e3663365bfe5$var$visualViewport = typeof document !== 'undefined' && window.visualViewport;
29
31
  // The number of active usePreventScroll calls. Used to determine whether to revert back to the original page style/scroll position
30
32
  let $0644e3663365bfe5$var$preventScrollCount = 0;
@@ -51,7 +53,7 @@ function $0644e3663365bfe5$export$ee0f7cc6afcd1c18(options = {}) {
51
53
  function $0644e3663365bfe5$var$preventScrollStandard() {
52
54
  let scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
53
55
  return (0, $a4e76a5424781910$export$e08e3b67e392101e)(scrollbarWidth > 0 && // Use scrollbar-gutter when supported because it also works for fixed positioned elements.
54
- ('scrollbarGutter' in document.documentElement.style ? $0644e3663365bfe5$var$setStyle(document.documentElement, 'scrollbarGutter', 'stable') : $0644e3663365bfe5$var$setStyle(document.documentElement, 'paddingRight', `${scrollbarWidth}px`)), $0644e3663365bfe5$var$setStyle(document.documentElement, 'overflow', 'hidden'));
56
+ ('scrollbarGutter' in document.documentElement.style ? (0, $d447af545b77c9f1$export$37a5fde709c1db82)(document.documentElement, 'scrollbar-gutter', 'stable') : (0, $d447af545b77c9f1$export$37a5fde709c1db82)(document.documentElement, 'padding-right', `${scrollbarWidth}px`)), (0, $d447af545b77c9f1$export$37a5fde709c1db82)(document.documentElement, 'overflow', 'hidden'));
55
57
  }
56
58
  // Mobile Safari is a whole different beast. Even with overflow: hidden,
57
59
  // it still scrolls the page in many situations:
@@ -76,7 +78,7 @@ function $0644e3663365bfe5$var$preventScrollStandard() {
76
78
  function $0644e3663365bfe5$var$preventScrollMobileWebKit() {
77
79
  // Set overflow hidden so scrollIntoViewport() (useSelectableCollection) sees isScrollPrevented and
78
80
  // scrolls only scroll parents instead of calling native scrollIntoView() which moves the window.
79
- let restoreOverflow = $0644e3663365bfe5$var$setStyle(document.documentElement, 'overflow', 'hidden');
81
+ let restoreOverflow = (0, $d447af545b77c9f1$export$37a5fde709c1db82)(document.documentElement, 'overflow', 'hidden');
80
82
  let scrollable;
81
83
  let allowTouchMove = false;
82
84
  let onTouchStart = (e)=>{
@@ -145,47 +147,37 @@ function $0644e3663365bfe5$var$preventScrollMobileWebKit() {
145
147
  };
146
148
  // Override programmatic focus to scroll into view without scrolling the whole page.
147
149
  let focus = HTMLElement.prototype.focus;
148
- HTMLElement.prototype.focus = function(opts) {
149
- // Track whether the keyboard was already visible before.
150
- let activeElement = (0, $23f2114a1b82827e$export$cd4e5573fbe2b576)();
151
- let wasKeyboardVisible = activeElement != null && (0, $bb39c0fc1c19b34c$export$c57958e35f31ed73)(activeElement);
152
- // Focus the element without scrolling the page.
153
- focus.call(this, {
154
- ...opts,
155
- preventScroll: true
156
- });
157
- if (!opts || !opts.preventScroll) $0644e3663365bfe5$var$scrollIntoViewWhenReady(this, wasKeyboardVisible);
158
- };
159
- let removeEvents = (0, $a4e76a5424781910$export$e08e3b67e392101e)($0644e3663365bfe5$var$addEvent(document, 'touchstart', onTouchStart, {
150
+ Reflect.defineProperty(HTMLElement.prototype, 'focus', {
151
+ configurable: true,
152
+ writable: true,
153
+ value: function(opts) {
154
+ // Track whether the keyboard was already visible before.
155
+ let activeElement = (0, $23f2114a1b82827e$export$cd4e5573fbe2b576)();
156
+ let wasKeyboardVisible = activeElement != null && (0, $bb39c0fc1c19b34c$export$c57958e35f31ed73)(activeElement);
157
+ // Focus the element without scrolling the page.
158
+ focus.call(this, {
159
+ ...opts,
160
+ preventScroll: true
161
+ });
162
+ if (!opts || !opts.preventScroll) $0644e3663365bfe5$var$scrollIntoViewWhenReady(this, wasKeyboardVisible);
163
+ }
164
+ });
165
+ let removeEvents = (0, $a4e76a5424781910$export$e08e3b67e392101e)((0, $d447af545b77c9f1$export$f531f92e2a15358f)(document, 'touchstart', onTouchStart, {
160
166
  passive: false,
161
167
  capture: true
162
- }), $0644e3663365bfe5$var$addEvent(document, 'touchmove', onTouchMove, {
168
+ }), (0, $d447af545b77c9f1$export$f531f92e2a15358f)(document, 'touchmove', onTouchMove, {
163
169
  passive: false,
164
170
  capture: true
165
- }), $0644e3663365bfe5$var$addEvent(document, 'blur', onBlur, true));
171
+ }), (0, $d447af545b77c9f1$export$f531f92e2a15358f)(document, 'blur', onBlur, true));
166
172
  return ()=>{
167
173
  restoreOverflow();
168
174
  removeEvents();
169
175
  style.remove();
170
- HTMLElement.prototype.focus = focus;
171
- };
172
- }
173
- // Sets a CSS property on an element, and returns a function to revert it to the previous value.
174
- function $0644e3663365bfe5$var$setStyle(element, style, value) {
175
- let cur = element.style[style];
176
- element.style[style] = value;
177
- return ()=>{
178
- element.style[style] = cur;
179
- };
180
- }
181
- // Adds an event listener to an element, and returns a function to remove it.
182
- function $0644e3663365bfe5$var$addEvent(target, event, handler, options) {
183
- // internal function, so it's ok to ignore the difficult to fix type error
184
- // @ts-ignore
185
- target.addEventListener(event, handler, options);
186
- return ()=>{
187
- // @ts-ignore
188
- target.removeEventListener(event, handler, options);
176
+ Reflect.defineProperty(HTMLElement.prototype, 'focus', {
177
+ configurable: true,
178
+ writable: true,
179
+ value: focus
180
+ });
189
181
  };
190
182
  }
191
183
  function $0644e3663365bfe5$var$scrollIntoViewWhenReady(target, wasKeyboardVisible) {
@@ -1 +1 @@
1
- {"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, isWebKit} 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() && isWebKit()) {\n restore = preventScrollMobileWebKit();\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.\nfunction preventScrollMobileWebKit() {\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 => el instanceof HTMLInputElement && el.type === 'range')) {\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 (\n scrollable.scrollHeight === scrollable.clientHeight &&\n scrollable.scrollWidth === scrollable.clientWidth\n ) {\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 (\n scrollable !== document.documentElement &&\n scrollable !== document.body &&\n scrollable !== nextTarget\n ) {\n let scrollableRect = scrollable.getBoundingClientRect();\n let targetRect = nextTarget.getBoundingClientRect();\n if (\n targetRect.top < scrollableRect.top ||\n targetRect.bottom > scrollableRect.top + nextTarget.clientHeight\n ) {\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 =\n targetRect.top -\n scrollableRect.top -\n ((bottom - scrollableRect.top) / 2 - targetRect.height / 2);\n scrollable.scrollTo({\n // Clamp to the valid range to prevent over-scrolling.\n top: Math.max(\n 0,\n Math.min(\n scrollable.scrollHeight - scrollable.clientHeight,\n scrollable.scrollTop + adjustment\n )\n ),\n behavior: 'smooth'\n });\n }\n }\n\n nextTarget = scrollable.parentElement;\n }\n}\n"],"names":[],"version":3,"file":"usePreventScroll.mjs.map"}
1
+ {"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 {addEvent} from '../utils/domHelpers';\nimport {chain} from '../utils/chain';\nimport {getActiveElement, getEventTarget} from '../utils/shadowdom/DOMFunctions';\nimport {getNonce} from '../utils/getNonce';\nimport {getScrollParent} from '../utils/getScrollParent';\nimport {isIOS, isWebKit} from '../utils/platform';\nimport {isScrollable} from '../utils/isScrollable';\nimport {setStyle} from '../utils/domHelpers';\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() && isWebKit()) {\n restore = preventScrollMobileWebKit();\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, 'scrollbar-gutter', 'stable')\n : setStyle(document.documentElement, 'padding-right', `${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.\nfunction preventScrollMobileWebKit() {\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 => el instanceof HTMLInputElement && el.type === 'range')) {\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 (\n scrollable.scrollHeight === scrollable.clientHeight &&\n scrollable.scrollWidth === scrollable.clientWidth\n ) {\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 Reflect.defineProperty(HTMLElement.prototype, 'focus', {\n configurable: true,\n writable: true,\n value: function (opts?: FocusOptions) {\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\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 Reflect.defineProperty(HTMLElement.prototype, 'focus', {\n configurable: true,\n writable: true,\n value: focus\n });\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 (\n scrollable !== document.documentElement &&\n scrollable !== document.body &&\n scrollable !== nextTarget\n ) {\n let scrollableRect = scrollable.getBoundingClientRect();\n let targetRect = nextTarget.getBoundingClientRect();\n if (\n targetRect.top < scrollableRect.top ||\n targetRect.bottom > scrollableRect.top + nextTarget.clientHeight\n ) {\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 =\n targetRect.top -\n scrollableRect.top -\n ((bottom - scrollableRect.top) / 2 - targetRect.height / 2);\n scrollable.scrollTo({\n // Clamp to the valid range to prevent over-scrolling.\n top: Math.max(\n 0,\n Math.min(\n scrollable.scrollHeight - scrollable.clientHeight,\n scrollable.scrollTop + adjustment\n )\n ),\n behavior: 'smooth'\n });\n }\n }\n\n nextTarget = scrollable.parentElement;\n }\n}\n"],"names":[],"version":3,"file":"usePreventScroll.mjs.map"}
@@ -395,6 +395,7 @@ function $df9ba3e9a7210056$export$d6daf82dcd84e87c(options) {
395
395
  }
396
396
  manager.setFocused(true);
397
397
  manager.setFocusedKey(focusedKey);
398
+ if (focusedKey != null && selectOnFocus && !selectedKeys.size && manager.canSelectItem(focusedKey)) manager.replaceSelection(focusedKey);
398
399
  // If no default focus key is selected, focus the collection itself.
399
400
  if (focusedKey == null && !shouldUseVirtualFocus && ref.current) (0, $4a053a4bf25e52fb$exports.focusSafely)(ref.current);
400
401
  // Wait until the collection has items to autofocus.
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/react-aria/src/selection/useSelectableCollection.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 {CLEAR_FOCUS_EVENT, FOCUS_EVENT} from '../utils/constants';\n\nimport {dispatchVirtualFocus, moveVirtualFocus} from '../focus/virtualFocus';\nimport {\n DOMAttributes,\n FocusableElement,\n FocusStrategy,\n Key,\n KeyboardDelegate,\n KeyboardEvent,\n RefObject\n} from '@react-types/shared';\nimport {flushSync} from 'react-dom';\nimport {FocusEvent, useEffect, useRef} from 'react';\nimport {focusSafely} from '../interactions/focusSafely';\nimport {focusWithoutScrolling} from '../utils/focusWithoutScrolling';\nimport {\n getActiveElement,\n getEventTarget,\n isFocusWithin,\n nodeContains\n} from '../utils/shadowdom/DOMFunctions';\nimport {getFocusableTreeWalker} from '../focus/FocusScope';\nimport {getInteractionModality} from '../interactions/useFocusVisible';\nimport {getItemElement, isNonContiguousSelectionModifier, useCollectionId} from './utils';\nimport {isCtrlKeyPressed} from '../utils/keyboard';\nimport {isMac} from '../utils/platform';\nimport {isTabbable} from '../utils/isFocusable';\nimport {mergeProps} from '../utils/mergeProps';\nimport {MultipleSelectionManager} from 'react-stately/useMultipleSelectionState';\nimport {scrollIntoView, scrollIntoViewport} from '../utils/scrollIntoView';\nimport {useEvent} from '../utils/useEvent';\nimport {useKeyboard} from '../interactions/useKeyboard';\nimport {useLocale} from '../i18n/I18nProvider';\nimport {useRouter} from '../utils/openLink';\nimport {useTypeSelect} from './useTypeSelect';\nimport {useUpdateLayoutEffect} from '../utils/useUpdateLayoutEffect';\n\nexport interface AriaSelectableCollectionOptions {\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager;\n /**\n * A delegate object that implements behavior for keyboard focus movement.\n */\n keyboardDelegate: KeyboardDelegate;\n /**\n * The ref attached to the element representing the collection.\n */\n ref: RefObject<HTMLElement | null>;\n /**\n * Whether the collection or one of its items should be automatically focused upon render.\n *\n * @default false\n */\n autoFocus?: boolean | FocusStrategy;\n /**\n * Whether focus should wrap around when the end/start is reached.\n *\n * @default false\n */\n shouldFocusWrap?: boolean;\n /**\n * Whether the collection allows empty selection.\n *\n * @default false\n */\n disallowEmptySelection?: boolean;\n /**\n * Whether the collection allows the user to select all items via keyboard shortcut.\n *\n * @default false\n */\n disallowSelectAll?: boolean;\n /**\n * Whether pressing the Escape should clear selection in the collection or not.\n *\n * @default 'clearSelection'\n */\n escapeKeyBehavior?: 'clearSelection' | 'none';\n /**\n * Whether selection should occur automatically on focus.\n *\n * @default false\n */\n selectOnFocus?: boolean;\n /**\n * Whether typeahead is disabled.\n *\n * @default false\n */\n disallowTypeAhead?: boolean;\n /**\n * Whether the collection items should use virtual focus instead of being focused directly.\n */\n shouldUseVirtualFocus?: boolean;\n /**\n * Whether navigation through tab key is enabled.\n */\n allowsTabNavigation?: boolean;\n /**\n * Whether the collection items are contained in a virtual scroller.\n */\n isVirtualized?: boolean;\n /**\n * The ref attached to the scrollable body. Used to provide automatic scrolling on item focus for\n * non-virtualized collections. If not provided, defaults to the collection ref.\n */\n scrollRef?: RefObject<HTMLElement | null>;\n /**\n * The behavior of links in the collection.\n * - 'action': link behaves like onAction.\n * - 'selection': link follows selection interactions (e.g. if URL drives selection).\n * - 'override': links override all other interactions (link items are not selectable).\n *\n * @default 'action'\n */\n linkBehavior?: 'action' | 'selection' | 'override';\n /**\n * Which item in the collection to focus when tabbing into the collection. Overrides default\n * roving tab index like behavior.\n *\n * @private\n */\n UNSTABLE_focusOnEntry?: 'first' | 'last';\n}\n\nexport interface SelectableCollectionAria {\n /** Props for the collection element. */\n collectionProps: DOMAttributes;\n}\n\n/**\n * Handles interactions with selectable collections.\n */\nexport function useSelectableCollection(\n options: AriaSelectableCollectionOptions\n): SelectableCollectionAria {\n let {\n selectionManager: manager,\n keyboardDelegate: delegate,\n ref,\n autoFocus = false,\n shouldFocusWrap = false,\n disallowEmptySelection = false,\n disallowSelectAll = false,\n escapeKeyBehavior = 'clearSelection',\n selectOnFocus = manager.selectionBehavior === 'replace',\n disallowTypeAhead = false,\n shouldUseVirtualFocus,\n allowsTabNavigation = false,\n // If no scrollRef is provided, assume the collection ref is the scrollable region\n scrollRef = ref,\n linkBehavior = 'action',\n UNSTABLE_focusOnEntry\n } = options;\n let {direction} = useLocale();\n let router = useRouter();\n\n const navigateToKey = (\n e: KeyboardEvent,\n key: Key | undefined,\n childFocus?: FocusStrategy\n ): boolean | void => {\n if (key != null) {\n if (\n manager.isLink(key) &&\n linkBehavior === 'selection' &&\n selectOnFocus &&\n !isNonContiguousSelectionModifier(e)\n ) {\n // Set focused key and re-render synchronously to bring item into view if needed.\n flushSync(() => {\n manager.setFocusedKey(key, childFocus);\n });\n\n let item = getItemElement(ref, key);\n let itemProps = manager.getItemProps(key);\n if (item) {\n router.open(item, e, itemProps.href, itemProps.routerOptions);\n return;\n }\n\n return false;\n }\n\n manager.setFocusedKey(key, childFocus);\n\n if (manager.isLink(key) && linkBehavior === 'override') {\n return false;\n }\n\n if (e.shiftKey && manager.selectionMode === 'multiple') {\n manager.extendSelection(key);\n return;\n } else if (selectOnFocus && !isNonContiguousSelectionModifier(e)) {\n manager.replaceSelection(key);\n return;\n }\n }\n return false;\n };\n\n let arrowDown = (e: KeyboardEvent) => {\n if (delegate.getKeyBelow) {\n let nextKey =\n manager.focusedKey != null\n ? delegate.getKeyBelow?.(manager.focusedKey)\n : delegate.getFirstKey?.();\n if (nextKey == null && shouldFocusWrap) {\n nextKey = delegate.getFirstKey?.(manager.focusedKey);\n }\n if (nextKey != null) {\n navigateToKey(e, nextKey);\n return;\n }\n }\n return false;\n };\n\n let arrowUp = (e: KeyboardEvent) => {\n if (delegate.getKeyAbove) {\n let nextKey =\n manager.focusedKey != null\n ? delegate.getKeyAbove?.(manager.focusedKey)\n : delegate.getLastKey?.();\n if (nextKey == null && shouldFocusWrap) {\n nextKey = delegate.getLastKey?.(manager.focusedKey);\n }\n if (nextKey != null) {\n navigateToKey(e, nextKey);\n return;\n }\n }\n return false;\n };\n\n let home = (e: KeyboardEvent) => {\n if (delegate.getFirstKey) {\n if (manager.focusedKey === null && e.shiftKey) {\n return false;\n }\n // TODO: should Home and End also be reversed in column reverse aka Home goes to top? Or should Home always to to the \"first\" (bottom)\n let firstKey: Key | null = delegate.getFirstKey(manager.focusedKey, isCtrlKeyPressed(e));\n manager.setFocusedKey(firstKey);\n if (firstKey != null) {\n if (isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {\n manager.extendSelection(firstKey);\n return;\n } else if (selectOnFocus) {\n manager.replaceSelection(firstKey);\n return;\n }\n }\n }\n return false;\n };\n\n let arrowLeft = (e: KeyboardEvent) => {\n if (delegate.getKeyLeftOf) {\n let nextKey: Key | undefined | null =\n manager.focusedKey != null\n ? delegate.getKeyLeftOf?.(manager.focusedKey)\n : delegate.getFirstKey?.();\n if (nextKey == null && shouldFocusWrap) {\n nextKey =\n direction === 'rtl'\n ? delegate.getFirstKey?.(manager.focusedKey)\n : delegate.getLastKey?.(manager.focusedKey);\n }\n if (nextKey != null) {\n navigateToKey(e, nextKey, direction === 'rtl' ? 'first' : 'last');\n return;\n }\n }\n return false;\n };\n\n let arrowRight = (e: KeyboardEvent) => {\n if (delegate.getKeyRightOf) {\n let nextKey: Key | undefined | null =\n manager.focusedKey != null\n ? delegate.getKeyRightOf?.(manager.focusedKey)\n : delegate.getFirstKey?.();\n if (nextKey == null && shouldFocusWrap) {\n nextKey =\n direction === 'rtl'\n ? delegate.getLastKey?.(manager.focusedKey)\n : delegate.getFirstKey?.(manager.focusedKey);\n }\n if (nextKey != null) {\n navigateToKey(e, nextKey, direction === 'rtl' ? 'last' : 'first');\n return;\n }\n }\n return false;\n };\n\n let end = (e: KeyboardEvent) => {\n if (delegate.getLastKey) {\n if (manager.focusedKey === null && e.shiftKey) {\n return false;\n }\n let lastKey = delegate.getLastKey(manager.focusedKey, isCtrlKeyPressed(e));\n manager.setFocusedKey(lastKey);\n if (lastKey != null) {\n if (isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {\n manager.extendSelection(lastKey);\n return;\n } else if (selectOnFocus) {\n manager.replaceSelection(lastKey);\n return;\n }\n }\n }\n return false;\n };\n\n let pageDown = (e: KeyboardEvent) => {\n if (delegate.getKeyPageBelow && manager.focusedKey != null) {\n let nextKey = delegate.getKeyPageBelow(manager.focusedKey);\n if (nextKey != null) {\n return navigateToKey(e, nextKey);\n }\n }\n return false;\n };\n\n let pageUp = (e: KeyboardEvent) => {\n if (delegate.getKeyPageAbove && manager.focusedKey != null) {\n let nextKey = delegate.getKeyPageAbove(manager.focusedKey);\n if (nextKey != null) {\n return navigateToKey(e, nextKey);\n }\n }\n return false;\n };\n\n let aHandler = () => {\n if (manager.selectionMode === 'multiple' && disallowSelectAll !== true) {\n manager.selectAll();\n return;\n }\n return false;\n };\n\n let escape = () => {\n if (\n escapeKeyBehavior === 'clearSelection' &&\n !disallowEmptySelection &&\n manager.selectedKeys.size !== 0\n ) {\n manager.clearSelection();\n return;\n }\n return false;\n };\n\n let tab = () => {\n if (!allowsTabNavigation && ref.current) {\n // There may be elements that are \"tabbable\" inside a collection (e.g. in a grid cell).\n // However, collections should be treated as a single tab stop, with arrow key navigation internally.\n // We don't control the rendering of these, so we can't override the tabIndex to prevent tabbing.\n // Instead, we handle the Tab key, and move focus manually to the first/last tabbable element\n // in the collection, so that the browser default behavior will apply starting from that element\n // rather than the currently focused one.\n\n let walker = getFocusableTreeWalker(ref.current, {tabbable: true});\n let next: FocusableElement | undefined = undefined;\n let last: FocusableElement;\n do {\n last = walker.lastChild() as FocusableElement;\n if (last) {\n next = last;\n }\n } while (last);\n\n // If the active element is NOT tabbable but is contained by an element that IS tabbable (aka the cell), the browser will actually move focus to\n // the containing element. We need to special case this so that tab will move focus out of the grid instead of looping between\n // focusing the containing cell and back to the non-tabbable child element\n let activeElement = getActiveElement();\n if (next && (!isFocusWithin(next) || (activeElement && !isTabbable(activeElement)))) {\n focusWithoutScrolling(next);\n }\n }\n return {shouldContinuePropagation: true, shouldPreventDefault: false};\n };\n\n let shiftTab = () => {\n if (!allowsTabNavigation && ref.current) {\n ref.current.focus();\n }\n return {shouldContinuePropagation: true, shouldPreventDefault: false};\n };\n\n let withShiftSel = (key, callback) => {\n return {\n [isMac() ? key + '+Shift+Alt' : key + '+Shift+Control']: callback,\n [key + '+Shift']: callback,\n [isMac() ? key + '+Alt' : key + '+Control']: callback,\n [key]: callback\n };\n };\n // oxlint-disable react/react-compiler\n let {keyboardProps: repeatKeyboardProps} = useKeyboard({\n shortcuts: {\n ...withShiftSel('ArrowDown', arrowDown),\n ...withShiftSel('ArrowUp', arrowUp),\n ...withShiftSel('ArrowLeft', arrowLeft),\n ...withShiftSel('ArrowRight', arrowRight),\n ...withShiftSel('PageDown', pageDown),\n ...withShiftSel('PageUp', pageUp)\n },\n allowRepeats: true\n });\n // oxlint-disable react/react-compiler\n let {keyboardProps} = useKeyboard({\n shortcuts: {\n ...withShiftSel('Home', home),\n ...withShiftSel('End', end),\n 'Mod+A': aHandler,\n Escape: escape,\n Tab: tab,\n 'Tab+Shift': shiftTab\n }\n });\n // oxlint-enable react/react-compiler\n\n // Store the scroll position so we can restore it later.\n /// TODO: should this happen all the time??\n let scrollPos = useRef({top: 0, left: 0});\n useEvent(scrollRef, 'scroll', () => {\n scrollPos.current = {\n top: scrollRef.current?.scrollTop ?? 0,\n left: scrollRef.current?.scrollLeft ?? 0\n };\n });\n\n let onFocus = (e: FocusEvent) => {\n if (manager.isFocused) {\n // If a focus event bubbled through a portal, reset focus state.\n if (!nodeContains(e.currentTarget, getEventTarget(e))) {\n manager.setFocused(false);\n }\n return;\n }\n\n // Focus events can bubble through portals. Ignore these events.\n if (!nodeContains(e.currentTarget, getEventTarget(e))) {\n return;\n }\n\n let modality = getInteractionModality();\n manager.setFocused(true);\n let navigateToKey = (key: Key | undefined | null) => {\n if (key != null) {\n manager.setFocusedKey(key);\n if (selectOnFocus && !manager.isSelected(key)) {\n manager.replaceSelection(key);\n }\n }\n };\n\n // we need the \"virtual\" modality case checks here because shift tabbing from the prompt field's attachment card back into the\n // thread is a virtual focus event (the tab handler in onKeyDown focuses the ref of the attachmentList aka TagGroup via a focus() call, hence the virtual modality)\n if (UNSTABLE_focusOnEntry && (modality === 'keyboard' || modality === 'virtual')) {\n // always go to the first item in the Thread when tabbing forwards/backwards into the collection\n // since it is probably more important to the user to see the new prompt reply rather than go to the last focused key\n navigateToKey(\n UNSTABLE_focusOnEntry === 'first' ? delegate.getFirstKey?.() : delegate.getLastKey?.()\n );\n } else if (manager.focusedKey == null) {\n // If the user hasn't yet interacted with the collection, there will be no focusedKey set.\n // Attempt to detect whether the user is tabbing forward or backward into the collection\n // and either focus the first or last item accordingly.\n let relatedTarget = e.relatedTarget as Element;\n if (\n relatedTarget &&\n e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING\n ) {\n navigateToKey(manager.lastSelectedKey ?? delegate.getLastKey?.());\n } else {\n navigateToKey(manager.firstSelectedKey ?? delegate.getFirstKey?.());\n }\n } else if (scrollRef.current) {\n // Restore the scroll position to what it was before.\n scrollRef.current.scrollTop = scrollPos.current.top;\n scrollRef.current.scrollLeft = scrollPos.current.left;\n }\n\n if (manager.focusedKey != null && scrollRef.current) {\n // Refocus and scroll the focused item into view if it exists within the scrollable region.\n let element = getItemElement(ref, manager.focusedKey);\n if (element instanceof HTMLElement) {\n // This prevents a flash of focus on the first/last element in the collection, or the collection itself.\n if (!isFocusWithin(element) && !shouldUseVirtualFocus) {\n focusWithoutScrolling(element);\n }\n\n if (modality === 'keyboard' || (UNSTABLE_focusOnEntry && modality === 'virtual')) {\n scrollIntoViewport(element, {containingElement: ref.current});\n }\n }\n }\n };\n\n let onBlur = e => {\n // Don't set blurred and then focused again if moving focus within the collection.\n if (!nodeContains(e.currentTarget, e.relatedTarget as HTMLElement)) {\n manager.setFocused(false);\n }\n };\n\n // Ref to track whether the first item in the collection should be automatically focused. Specifically used for autocomplete when user types\n // to focus the first key AFTER the collection updates.\n // TODO: potentially expand the usage of this\n let shouldVirtualFocusFirst = useRef(false);\n // Add event listeners for custom virtual events. These handle updating the focused key in response to various keyboard events\n // at the autocomplete level\n // TODO: fix type later\n useEvent(\n ref,\n FOCUS_EVENT,\n !shouldUseVirtualFocus\n ? undefined\n : (e: any) => {\n let {detail} = e;\n e.stopPropagation();\n manager.setFocused(true);\n // If the user is typing forwards, autofocus the first option in the list.\n if (detail?.focusStrategy === 'first') {\n shouldVirtualFocusFirst.current = true;\n }\n }\n );\n\n // update active descendant\n let firstKey = delegate.getFirstKey?.() ?? null;\n useUpdateLayoutEffect(() => {\n if (shouldVirtualFocusFirst.current) {\n // If no focusable items exist in the list, make sure to clear any activedescendant that may still exist and move focus back to\n // the original active element (e.g. the autocomplete input)\n if (firstKey == null) {\n let previousActiveElement = getActiveElement();\n moveVirtualFocus(ref.current);\n dispatchVirtualFocus(previousActiveElement!, null);\n\n // If there wasn't a focusable key but the collection had items, then that means we aren't in an intermediate load state and all keys are disabled.\n // Reset shouldVirtualFocusFirst so that we don't erronously autofocus an item when the collection is filtered again.\n if (manager.collection.size > 0) {\n shouldVirtualFocusFirst.current = false;\n }\n } else {\n manager.setFocusedKey(firstKey);\n // Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key\n // If there wasn't a key to focus, we might be in a temporary loading state so we'll want to still focus the first key\n // after the collection updates after load\n shouldVirtualFocusFirst.current = false;\n }\n }\n }, [firstKey, manager.collection.size]);\n\n // reset focus first flag\n useUpdateLayoutEffect(() => {\n // If user causes the focused key to change in any other way, clear shouldVirtualFocusFirst so we don't\n // accidentally move focus from under them. Skip this if the collection was empty because we might be in a load\n // state and will still want to focus the first item after load\n if (manager.collection.size > 0) {\n shouldVirtualFocusFirst.current = false;\n }\n }, [manager.focusedKey]);\n\n useEvent(\n ref,\n CLEAR_FOCUS_EVENT,\n !shouldUseVirtualFocus\n ? undefined\n : (e: any) => {\n e.stopPropagation();\n manager.setFocused(false);\n if (e.detail?.clearFocusKey) {\n manager.setFocusedKey(null);\n }\n }\n );\n\n const autoFocusRef = useRef(autoFocus);\n const didAutoFocusRef = useRef(false);\n useEffect(() => {\n if (autoFocusRef.current) {\n let focusedKey: Key | null = null;\n\n // Check focus strategy to determine which item to focus\n if (autoFocus === 'first') {\n focusedKey = delegate.getFirstKey?.() ?? null;\n }\n if (autoFocus === 'last') {\n focusedKey = delegate.getLastKey?.() ?? null;\n }\n\n // If there are any selected keys, make the first one the new focus target\n let selectedKeys = manager.selectedKeys;\n if (selectedKeys.size) {\n for (let key of selectedKeys) {\n if (manager.canSelectItem(key)) {\n focusedKey = key;\n break;\n }\n }\n }\n\n manager.setFocused(true);\n manager.setFocusedKey(focusedKey);\n\n // If no default focus key is selected, focus the collection itself.\n if (focusedKey == null && !shouldUseVirtualFocus && ref.current) {\n focusSafely(ref.current);\n }\n\n // Wait until the collection has items to autofocus.\n if (manager.collection.size > 0) {\n autoFocusRef.current = false;\n didAutoFocusRef.current = true;\n }\n }\n });\n\n // Scroll the focused element into view when the focusedKey changes.\n let lastFocusedKey = useRef(manager.focusedKey);\n let raf = useRef<number | null>(null);\n useEffect(() => {\n if (\n manager.isFocused &&\n manager.focusedKey != null &&\n (manager.focusedKey !== lastFocusedKey.current || didAutoFocusRef.current) &&\n scrollRef.current &&\n ref.current\n ) {\n let modality = getInteractionModality();\n let element = getItemElement(ref, manager.focusedKey);\n if (!(element instanceof HTMLElement)) {\n // If item element wasn't found, return early (don't update autoFocusRef and lastFocusedKey).\n // The collection may initially be empty (e.g. virtualizer), so wait until the element exists.\n return;\n }\n\n if (modality === 'keyboard' || didAutoFocusRef.current) {\n if (raf.current) {\n cancelAnimationFrame(raf.current);\n }\n\n raf.current = requestAnimationFrame(() => {\n if (scrollRef.current) {\n scrollIntoView(scrollRef.current, element);\n // Avoid scroll in iOS VO, since it may cause overlay to close (i.e. RAC submenu)\n if (modality !== 'virtual') {\n scrollIntoViewport(element, {containingElement: ref.current});\n }\n }\n });\n }\n }\n\n // If the focused key becomes null (e.g. the last item is deleted), focus the whole collection.\n if (\n !shouldUseVirtualFocus &&\n manager.isFocused &&\n manager.focusedKey == null &&\n lastFocusedKey.current != null &&\n ref.current\n ) {\n focusSafely(ref.current);\n }\n\n lastFocusedKey.current = manager.focusedKey;\n didAutoFocusRef.current = false;\n });\n\n useEffect(() => {\n return () => {\n if (raf.current) {\n cancelAnimationFrame(raf.current);\n }\n };\n }, []);\n\n // Intercept FocusScope restoration since virtualized collections can reuse DOM nodes.\n useEvent(ref, 'react-aria-focus-scope-restore', e => {\n e.preventDefault();\n manager.setFocused(true);\n });\n\n let handlers = {\n ...mergeProps(keyboardProps, repeatKeyboardProps),\n onFocus,\n onBlur,\n onMouseDown(e) {\n // Ignore events that bubbled through portals.\n if (scrollRef.current === getEventTarget(e)) {\n // Prevent focus going to the collection when clicking on the scrollbar.\n e.preventDefault();\n }\n }\n };\n\n let {typeSelectProps} = useTypeSelect({\n keyboardDelegate: delegate,\n selectionManager: manager\n });\n\n if (!disallowTypeAhead) {\n // oxlint-disable-next-line react/react-compiler\n handlers = mergeProps(typeSelectProps, handlers);\n }\n\n // If nothing is focused within the collection, make the collection itself tabbable.\n // This will be marshalled to either the first or last item depending on where focus came from.\n let tabIndex: number | undefined = undefined;\n if (!shouldUseVirtualFocus) {\n tabIndex = manager.focusedKey == null ? 0 : -1;\n }\n\n let collectionId = useCollectionId(manager.collection);\n return {\n // oxlint-disable-next-line react/react-compiler\n collectionProps: mergeProps(handlers, {\n tabIndex,\n 'data-collection': collectionId\n })\n };\n}\n"],"names":[],"version":3,"file":"useSelectableCollection.cjs.map"}
1
+ {"mappings":"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","sources":["packages/react-aria/src/selection/useSelectableCollection.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 {CLEAR_FOCUS_EVENT, FOCUS_EVENT} from '../utils/constants';\n\nimport {dispatchVirtualFocus, moveVirtualFocus} from '../focus/virtualFocus';\nimport {\n DOMAttributes,\n FocusableElement,\n FocusStrategy,\n Key,\n KeyboardDelegate,\n KeyboardEvent,\n RefObject\n} from '@react-types/shared';\nimport {flushSync} from 'react-dom';\nimport {FocusEvent, useEffect, useRef} from 'react';\nimport {focusSafely} from '../interactions/focusSafely';\nimport {focusWithoutScrolling} from '../utils/focusWithoutScrolling';\nimport {\n getActiveElement,\n getEventTarget,\n isFocusWithin,\n nodeContains\n} from '../utils/shadowdom/DOMFunctions';\nimport {getFocusableTreeWalker} from '../focus/FocusScope';\nimport {getInteractionModality} from '../interactions/useFocusVisible';\nimport {getItemElement, isNonContiguousSelectionModifier, useCollectionId} from './utils';\nimport {isCtrlKeyPressed} from '../utils/keyboard';\nimport {isMac} from '../utils/platform';\nimport {isTabbable} from '../utils/isFocusable';\nimport {mergeProps} from '../utils/mergeProps';\nimport {MultipleSelectionManager} from 'react-stately/useMultipleSelectionState';\nimport {scrollIntoView, scrollIntoViewport} from '../utils/scrollIntoView';\nimport {useEvent} from '../utils/useEvent';\nimport {useKeyboard} from '../interactions/useKeyboard';\nimport {useLocale} from '../i18n/I18nProvider';\nimport {useRouter} from '../utils/openLink';\nimport {useTypeSelect} from './useTypeSelect';\nimport {useUpdateLayoutEffect} from '../utils/useUpdateLayoutEffect';\n\nexport interface AriaSelectableCollectionOptions {\n /**\n * An interface for reading and updating multiple selection state.\n */\n selectionManager: MultipleSelectionManager;\n /**\n * A delegate object that implements behavior for keyboard focus movement.\n */\n keyboardDelegate: KeyboardDelegate;\n /**\n * The ref attached to the element representing the collection.\n */\n ref: RefObject<HTMLElement | null>;\n /**\n * Whether the collection or one of its items should be automatically focused upon render.\n *\n * @default false\n */\n autoFocus?: boolean | FocusStrategy;\n /**\n * Whether focus should wrap around when the end/start is reached.\n *\n * @default false\n */\n shouldFocusWrap?: boolean;\n /**\n * Whether the collection allows empty selection.\n *\n * @default false\n */\n disallowEmptySelection?: boolean;\n /**\n * Whether the collection allows the user to select all items via keyboard shortcut.\n *\n * @default false\n */\n disallowSelectAll?: boolean;\n /**\n * Whether pressing the Escape should clear selection in the collection or not.\n *\n * @default 'clearSelection'\n */\n escapeKeyBehavior?: 'clearSelection' | 'none';\n /**\n * Whether selection should occur automatically on focus.\n *\n * @default false\n */\n selectOnFocus?: boolean;\n /**\n * Whether typeahead is disabled.\n *\n * @default false\n */\n disallowTypeAhead?: boolean;\n /**\n * Whether the collection items should use virtual focus instead of being focused directly.\n */\n shouldUseVirtualFocus?: boolean;\n /**\n * Whether navigation through tab key is enabled.\n */\n allowsTabNavigation?: boolean;\n /**\n * Whether the collection items are contained in a virtual scroller.\n */\n isVirtualized?: boolean;\n /**\n * The ref attached to the scrollable body. Used to provide automatic scrolling on item focus for\n * non-virtualized collections. If not provided, defaults to the collection ref.\n */\n scrollRef?: RefObject<HTMLElement | null>;\n /**\n * The behavior of links in the collection.\n * - 'action': link behaves like onAction.\n * - 'selection': link follows selection interactions (e.g. if URL drives selection).\n * - 'override': links override all other interactions (link items are not selectable).\n *\n * @default 'action'\n */\n linkBehavior?: 'action' | 'selection' | 'override';\n /**\n * Which item in the collection to focus when tabbing into the collection. Overrides default\n * roving tab index like behavior.\n *\n * @private\n */\n UNSTABLE_focusOnEntry?: 'first' | 'last';\n}\n\nexport interface SelectableCollectionAria {\n /** Props for the collection element. */\n collectionProps: DOMAttributes;\n}\n\n/**\n * Handles interactions with selectable collections.\n */\nexport function useSelectableCollection(\n options: AriaSelectableCollectionOptions\n): SelectableCollectionAria {\n let {\n selectionManager: manager,\n keyboardDelegate: delegate,\n ref,\n autoFocus = false,\n shouldFocusWrap = false,\n disallowEmptySelection = false,\n disallowSelectAll = false,\n escapeKeyBehavior = 'clearSelection',\n selectOnFocus = manager.selectionBehavior === 'replace',\n disallowTypeAhead = false,\n shouldUseVirtualFocus,\n allowsTabNavigation = false,\n // If no scrollRef is provided, assume the collection ref is the scrollable region\n scrollRef = ref,\n linkBehavior = 'action',\n UNSTABLE_focusOnEntry\n } = options;\n let {direction} = useLocale();\n let router = useRouter();\n\n const navigateToKey = (\n e: KeyboardEvent,\n key: Key | undefined,\n childFocus?: FocusStrategy\n ): boolean | void => {\n if (key != null) {\n if (\n manager.isLink(key) &&\n linkBehavior === 'selection' &&\n selectOnFocus &&\n !isNonContiguousSelectionModifier(e)\n ) {\n // Set focused key and re-render synchronously to bring item into view if needed.\n flushSync(() => {\n manager.setFocusedKey(key, childFocus);\n });\n\n let item = getItemElement(ref, key);\n let itemProps = manager.getItemProps(key);\n if (item) {\n router.open(item, e, itemProps.href, itemProps.routerOptions);\n return;\n }\n\n return false;\n }\n\n manager.setFocusedKey(key, childFocus);\n\n if (manager.isLink(key) && linkBehavior === 'override') {\n return false;\n }\n\n if (e.shiftKey && manager.selectionMode === 'multiple') {\n manager.extendSelection(key);\n return;\n } else if (selectOnFocus && !isNonContiguousSelectionModifier(e)) {\n manager.replaceSelection(key);\n return;\n }\n }\n return false;\n };\n\n let arrowDown = (e: KeyboardEvent) => {\n if (delegate.getKeyBelow) {\n let nextKey =\n manager.focusedKey != null\n ? delegate.getKeyBelow?.(manager.focusedKey)\n : delegate.getFirstKey?.();\n if (nextKey == null && shouldFocusWrap) {\n nextKey = delegate.getFirstKey?.(manager.focusedKey);\n }\n if (nextKey != null) {\n navigateToKey(e, nextKey);\n return;\n }\n }\n return false;\n };\n\n let arrowUp = (e: KeyboardEvent) => {\n if (delegate.getKeyAbove) {\n let nextKey =\n manager.focusedKey != null\n ? delegate.getKeyAbove?.(manager.focusedKey)\n : delegate.getLastKey?.();\n if (nextKey == null && shouldFocusWrap) {\n nextKey = delegate.getLastKey?.(manager.focusedKey);\n }\n if (nextKey != null) {\n navigateToKey(e, nextKey);\n return;\n }\n }\n return false;\n };\n\n let home = (e: KeyboardEvent) => {\n if (delegate.getFirstKey) {\n if (manager.focusedKey === null && e.shiftKey) {\n return false;\n }\n // TODO: should Home and End also be reversed in column reverse aka Home goes to top? Or should Home always to to the \"first\" (bottom)\n let firstKey: Key | null = delegate.getFirstKey(manager.focusedKey, isCtrlKeyPressed(e));\n manager.setFocusedKey(firstKey);\n if (firstKey != null) {\n if (isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {\n manager.extendSelection(firstKey);\n return;\n } else if (selectOnFocus) {\n manager.replaceSelection(firstKey);\n return;\n }\n }\n }\n return false;\n };\n\n let arrowLeft = (e: KeyboardEvent) => {\n if (delegate.getKeyLeftOf) {\n let nextKey: Key | undefined | null =\n manager.focusedKey != null\n ? delegate.getKeyLeftOf?.(manager.focusedKey)\n : delegate.getFirstKey?.();\n if (nextKey == null && shouldFocusWrap) {\n nextKey =\n direction === 'rtl'\n ? delegate.getFirstKey?.(manager.focusedKey)\n : delegate.getLastKey?.(manager.focusedKey);\n }\n if (nextKey != null) {\n navigateToKey(e, nextKey, direction === 'rtl' ? 'first' : 'last');\n return;\n }\n }\n return false;\n };\n\n let arrowRight = (e: KeyboardEvent) => {\n if (delegate.getKeyRightOf) {\n let nextKey: Key | undefined | null =\n manager.focusedKey != null\n ? delegate.getKeyRightOf?.(manager.focusedKey)\n : delegate.getFirstKey?.();\n if (nextKey == null && shouldFocusWrap) {\n nextKey =\n direction === 'rtl'\n ? delegate.getLastKey?.(manager.focusedKey)\n : delegate.getFirstKey?.(manager.focusedKey);\n }\n if (nextKey != null) {\n navigateToKey(e, nextKey, direction === 'rtl' ? 'last' : 'first');\n return;\n }\n }\n return false;\n };\n\n let end = (e: KeyboardEvent) => {\n if (delegate.getLastKey) {\n if (manager.focusedKey === null && e.shiftKey) {\n return false;\n }\n let lastKey = delegate.getLastKey(manager.focusedKey, isCtrlKeyPressed(e));\n manager.setFocusedKey(lastKey);\n if (lastKey != null) {\n if (isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {\n manager.extendSelection(lastKey);\n return;\n } else if (selectOnFocus) {\n manager.replaceSelection(lastKey);\n return;\n }\n }\n }\n return false;\n };\n\n let pageDown = (e: KeyboardEvent) => {\n if (delegate.getKeyPageBelow && manager.focusedKey != null) {\n let nextKey = delegate.getKeyPageBelow(manager.focusedKey);\n if (nextKey != null) {\n return navigateToKey(e, nextKey);\n }\n }\n return false;\n };\n\n let pageUp = (e: KeyboardEvent) => {\n if (delegate.getKeyPageAbove && manager.focusedKey != null) {\n let nextKey = delegate.getKeyPageAbove(manager.focusedKey);\n if (nextKey != null) {\n return navigateToKey(e, nextKey);\n }\n }\n return false;\n };\n\n let aHandler = () => {\n if (manager.selectionMode === 'multiple' && disallowSelectAll !== true) {\n manager.selectAll();\n return;\n }\n return false;\n };\n\n let escape = () => {\n if (\n escapeKeyBehavior === 'clearSelection' &&\n !disallowEmptySelection &&\n manager.selectedKeys.size !== 0\n ) {\n manager.clearSelection();\n return;\n }\n return false;\n };\n\n let tab = () => {\n if (!allowsTabNavigation && ref.current) {\n // There may be elements that are \"tabbable\" inside a collection (e.g. in a grid cell).\n // However, collections should be treated as a single tab stop, with arrow key navigation internally.\n // We don't control the rendering of these, so we can't override the tabIndex to prevent tabbing.\n // Instead, we handle the Tab key, and move focus manually to the first/last tabbable element\n // in the collection, so that the browser default behavior will apply starting from that element\n // rather than the currently focused one.\n\n let walker = getFocusableTreeWalker(ref.current, {tabbable: true});\n let next: FocusableElement | undefined = undefined;\n let last: FocusableElement;\n do {\n last = walker.lastChild() as FocusableElement;\n if (last) {\n next = last;\n }\n } while (last);\n\n // If the active element is NOT tabbable but is contained by an element that IS tabbable (aka the cell), the browser will actually move focus to\n // the containing element. We need to special case this so that tab will move focus out of the grid instead of looping between\n // focusing the containing cell and back to the non-tabbable child element\n let activeElement = getActiveElement();\n if (next && (!isFocusWithin(next) || (activeElement && !isTabbable(activeElement)))) {\n focusWithoutScrolling(next);\n }\n }\n return {shouldContinuePropagation: true, shouldPreventDefault: false};\n };\n\n let shiftTab = () => {\n if (!allowsTabNavigation && ref.current) {\n ref.current.focus();\n }\n return {shouldContinuePropagation: true, shouldPreventDefault: false};\n };\n\n let withShiftSel = (key, callback) => {\n return {\n [isMac() ? key + '+Shift+Alt' : key + '+Shift+Control']: callback,\n [key + '+Shift']: callback,\n [isMac() ? key + '+Alt' : key + '+Control']: callback,\n [key]: callback\n };\n };\n // oxlint-disable react/react-compiler\n let {keyboardProps: repeatKeyboardProps} = useKeyboard({\n shortcuts: {\n ...withShiftSel('ArrowDown', arrowDown),\n ...withShiftSel('ArrowUp', arrowUp),\n ...withShiftSel('ArrowLeft', arrowLeft),\n ...withShiftSel('ArrowRight', arrowRight),\n ...withShiftSel('PageDown', pageDown),\n ...withShiftSel('PageUp', pageUp)\n },\n allowRepeats: true\n });\n // oxlint-disable react/react-compiler\n let {keyboardProps} = useKeyboard({\n shortcuts: {\n ...withShiftSel('Home', home),\n ...withShiftSel('End', end),\n 'Mod+A': aHandler,\n Escape: escape,\n Tab: tab,\n 'Tab+Shift': shiftTab\n }\n });\n // oxlint-enable react/react-compiler\n\n // Store the scroll position so we can restore it later.\n /// TODO: should this happen all the time??\n let scrollPos = useRef({top: 0, left: 0});\n useEvent(scrollRef, 'scroll', () => {\n scrollPos.current = {\n top: scrollRef.current?.scrollTop ?? 0,\n left: scrollRef.current?.scrollLeft ?? 0\n };\n });\n\n let onFocus = (e: FocusEvent) => {\n if (manager.isFocused) {\n // If a focus event bubbled through a portal, reset focus state.\n if (!nodeContains(e.currentTarget, getEventTarget(e))) {\n manager.setFocused(false);\n }\n return;\n }\n\n // Focus events can bubble through portals. Ignore these events.\n if (!nodeContains(e.currentTarget, getEventTarget(e))) {\n return;\n }\n\n let modality = getInteractionModality();\n manager.setFocused(true);\n let navigateToKey = (key: Key | undefined | null) => {\n if (key != null) {\n manager.setFocusedKey(key);\n if (selectOnFocus && !manager.isSelected(key)) {\n manager.replaceSelection(key);\n }\n }\n };\n\n // we need the \"virtual\" modality case checks here because shift tabbing from the prompt field's attachment card back into the\n // thread is a virtual focus event (the tab handler in onKeyDown focuses the ref of the attachmentList aka TagGroup via a focus() call, hence the virtual modality)\n if (UNSTABLE_focusOnEntry && (modality === 'keyboard' || modality === 'virtual')) {\n // always go to the first item in the Thread when tabbing forwards/backwards into the collection\n // since it is probably more important to the user to see the new prompt reply rather than go to the last focused key\n navigateToKey(\n UNSTABLE_focusOnEntry === 'first' ? delegate.getFirstKey?.() : delegate.getLastKey?.()\n );\n } else if (manager.focusedKey == null) {\n // If the user hasn't yet interacted with the collection, there will be no focusedKey set.\n // Attempt to detect whether the user is tabbing forward or backward into the collection\n // and either focus the first or last item accordingly.\n let relatedTarget = e.relatedTarget as Element;\n if (\n relatedTarget &&\n e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING\n ) {\n navigateToKey(manager.lastSelectedKey ?? delegate.getLastKey?.());\n } else {\n navigateToKey(manager.firstSelectedKey ?? delegate.getFirstKey?.());\n }\n } else if (scrollRef.current) {\n // Restore the scroll position to what it was before.\n scrollRef.current.scrollTop = scrollPos.current.top;\n scrollRef.current.scrollLeft = scrollPos.current.left;\n }\n\n if (manager.focusedKey != null && scrollRef.current) {\n // Refocus and scroll the focused item into view if it exists within the scrollable region.\n let element = getItemElement(ref, manager.focusedKey);\n if (element instanceof HTMLElement) {\n // This prevents a flash of focus on the first/last element in the collection, or the collection itself.\n if (!isFocusWithin(element) && !shouldUseVirtualFocus) {\n focusWithoutScrolling(element);\n }\n\n if (modality === 'keyboard' || (UNSTABLE_focusOnEntry && modality === 'virtual')) {\n scrollIntoViewport(element, {containingElement: ref.current});\n }\n }\n }\n };\n\n let onBlur = e => {\n // Don't set blurred and then focused again if moving focus within the collection.\n if (!nodeContains(e.currentTarget, e.relatedTarget as HTMLElement)) {\n manager.setFocused(false);\n }\n };\n\n // Ref to track whether the first item in the collection should be automatically focused. Specifically used for autocomplete when user types\n // to focus the first key AFTER the collection updates.\n // TODO: potentially expand the usage of this\n let shouldVirtualFocusFirst = useRef(false);\n // Add event listeners for custom virtual events. These handle updating the focused key in response to various keyboard events\n // at the autocomplete level\n // TODO: fix type later\n useEvent(\n ref,\n FOCUS_EVENT,\n !shouldUseVirtualFocus\n ? undefined\n : (e: any) => {\n let {detail} = e;\n e.stopPropagation();\n manager.setFocused(true);\n // If the user is typing forwards, autofocus the first option in the list.\n if (detail?.focusStrategy === 'first') {\n shouldVirtualFocusFirst.current = true;\n }\n }\n );\n\n // update active descendant\n let firstKey = delegate.getFirstKey?.() ?? null;\n useUpdateLayoutEffect(() => {\n if (shouldVirtualFocusFirst.current) {\n // If no focusable items exist in the list, make sure to clear any activedescendant that may still exist and move focus back to\n // the original active element (e.g. the autocomplete input)\n if (firstKey == null) {\n let previousActiveElement = getActiveElement();\n moveVirtualFocus(ref.current);\n dispatchVirtualFocus(previousActiveElement!, null);\n\n // If there wasn't a focusable key but the collection had items, then that means we aren't in an intermediate load state and all keys are disabled.\n // Reset shouldVirtualFocusFirst so that we don't erronously autofocus an item when the collection is filtered again.\n if (manager.collection.size > 0) {\n shouldVirtualFocusFirst.current = false;\n }\n } else {\n manager.setFocusedKey(firstKey);\n // Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key\n // If there wasn't a key to focus, we might be in a temporary loading state so we'll want to still focus the first key\n // after the collection updates after load\n shouldVirtualFocusFirst.current = false;\n }\n }\n }, [firstKey, manager.collection.size]);\n\n // reset focus first flag\n useUpdateLayoutEffect(() => {\n // If user causes the focused key to change in any other way, clear shouldVirtualFocusFirst so we don't\n // accidentally move focus from under them. Skip this if the collection was empty because we might be in a load\n // state and will still want to focus the first item after load\n if (manager.collection.size > 0) {\n shouldVirtualFocusFirst.current = false;\n }\n }, [manager.focusedKey]);\n\n useEvent(\n ref,\n CLEAR_FOCUS_EVENT,\n !shouldUseVirtualFocus\n ? undefined\n : (e: any) => {\n e.stopPropagation();\n manager.setFocused(false);\n if (e.detail?.clearFocusKey) {\n manager.setFocusedKey(null);\n }\n }\n );\n\n const autoFocusRef = useRef(autoFocus);\n const didAutoFocusRef = useRef(false);\n useEffect(() => {\n if (autoFocusRef.current) {\n let focusedKey: Key | null = null;\n\n // Check focus strategy to determine which item to focus\n if (autoFocus === 'first') {\n focusedKey = delegate.getFirstKey?.() ?? null;\n }\n if (autoFocus === 'last') {\n focusedKey = delegate.getLastKey?.() ?? null;\n }\n\n // If there are any selected keys, make the first one the new focus target\n let selectedKeys = manager.selectedKeys;\n if (selectedKeys.size) {\n for (let key of selectedKeys) {\n if (manager.canSelectItem(key)) {\n focusedKey = key;\n break;\n }\n }\n }\n\n manager.setFocused(true);\n manager.setFocusedKey(focusedKey);\n\n if (\n focusedKey != null &&\n selectOnFocus &&\n !selectedKeys.size &&\n manager.canSelectItem(focusedKey)\n ) {\n manager.replaceSelection(focusedKey);\n }\n\n // If no default focus key is selected, focus the collection itself.\n if (focusedKey == null && !shouldUseVirtualFocus && ref.current) {\n focusSafely(ref.current);\n }\n\n // Wait until the collection has items to autofocus.\n if (manager.collection.size > 0) {\n autoFocusRef.current = false;\n didAutoFocusRef.current = true;\n }\n }\n });\n\n // Scroll the focused element into view when the focusedKey changes.\n let lastFocusedKey = useRef(manager.focusedKey);\n let raf = useRef<number | null>(null);\n useEffect(() => {\n if (\n manager.isFocused &&\n manager.focusedKey != null &&\n (manager.focusedKey !== lastFocusedKey.current || didAutoFocusRef.current) &&\n scrollRef.current &&\n ref.current\n ) {\n let modality = getInteractionModality();\n let element = getItemElement(ref, manager.focusedKey);\n if (!(element instanceof HTMLElement)) {\n // If item element wasn't found, return early (don't update autoFocusRef and lastFocusedKey).\n // The collection may initially be empty (e.g. virtualizer), so wait until the element exists.\n return;\n }\n\n if (modality === 'keyboard' || didAutoFocusRef.current) {\n if (raf.current) {\n cancelAnimationFrame(raf.current);\n }\n\n raf.current = requestAnimationFrame(() => {\n if (scrollRef.current) {\n scrollIntoView(scrollRef.current, element);\n // Avoid scroll in iOS VO, since it may cause overlay to close (i.e. RAC submenu)\n if (modality !== 'virtual') {\n scrollIntoViewport(element, {containingElement: ref.current});\n }\n }\n });\n }\n }\n\n // If the focused key becomes null (e.g. the last item is deleted), focus the whole collection.\n if (\n !shouldUseVirtualFocus &&\n manager.isFocused &&\n manager.focusedKey == null &&\n lastFocusedKey.current != null &&\n ref.current\n ) {\n focusSafely(ref.current);\n }\n\n lastFocusedKey.current = manager.focusedKey;\n didAutoFocusRef.current = false;\n });\n\n useEffect(() => {\n return () => {\n if (raf.current) {\n cancelAnimationFrame(raf.current);\n }\n };\n }, []);\n\n // Intercept FocusScope restoration since virtualized collections can reuse DOM nodes.\n useEvent(ref, 'react-aria-focus-scope-restore', e => {\n e.preventDefault();\n manager.setFocused(true);\n });\n\n let handlers = {\n ...mergeProps(keyboardProps, repeatKeyboardProps),\n onFocus,\n onBlur,\n onMouseDown(e) {\n // Ignore events that bubbled through portals.\n if (scrollRef.current === getEventTarget(e)) {\n // Prevent focus going to the collection when clicking on the scrollbar.\n e.preventDefault();\n }\n }\n };\n\n let {typeSelectProps} = useTypeSelect({\n keyboardDelegate: delegate,\n selectionManager: manager\n });\n\n if (!disallowTypeAhead) {\n // oxlint-disable-next-line react/react-compiler\n handlers = mergeProps(typeSelectProps, handlers);\n }\n\n // If nothing is focused within the collection, make the collection itself tabbable.\n // This will be marshalled to either the first or last item depending on where focus came from.\n let tabIndex: number | undefined = undefined;\n if (!shouldUseVirtualFocus) {\n tabIndex = manager.focusedKey == null ? 0 : -1;\n }\n\n let collectionId = useCollectionId(manager.collection);\n return {\n // oxlint-disable-next-line react/react-compiler\n collectionProps: mergeProps(handlers, {\n tabIndex,\n 'data-collection': collectionId\n })\n };\n}\n"],"names":[],"version":3,"file":"useSelectableCollection.cjs.map"}
@@ -404,6 +404,7 @@ function $80c8b4b5cf8e1f86$export$d6daf82dcd84e87c(options) {
404
404
  }
405
405
  manager.setFocused(true);
406
406
  manager.setFocusedKey(focusedKey);
407
+ if (focusedKey != null && selectOnFocus && !selectedKeys.size && manager.canSelectItem(focusedKey)) manager.replaceSelection(focusedKey);
407
408
  // If no default focus key is selected, focus the collection itself.
408
409
  if (focusedKey == null && !shouldUseVirtualFocus && ref.current) (0, $56c81cdebdc6a696$export$80f3e147d781571c)(ref.current);
409
410
  // Wait until the collection has items to autofocus.