index.mjs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. import $kqwpH$babelruntimehelpersesmextends from "@babel/runtime/helpers/esm/extends";
  2. import {createContext as $kqwpH$createContext, forwardRef as $kqwpH$forwardRef, useContext as $kqwpH$useContext, useState as $kqwpH$useState, useEffect as $kqwpH$useEffect, createElement as $kqwpH$createElement, useRef as $kqwpH$useRef} from "react";
  3. import {composeEventHandlers as $kqwpH$composeEventHandlers} from "@radix-ui/primitive";
  4. import {Primitive as $kqwpH$Primitive, dispatchDiscreteCustomEvent as $kqwpH$dispatchDiscreteCustomEvent} from "@radix-ui/react-primitive";
  5. import {useComposedRefs as $kqwpH$useComposedRefs} from "@radix-ui/react-compose-refs";
  6. import {useCallbackRef as $kqwpH$useCallbackRef} from "@radix-ui/react-use-callback-ref";
  7. import {useEscapeKeydown as $kqwpH$useEscapeKeydown} from "@radix-ui/react-use-escape-keydown";
  8. /* -------------------------------------------------------------------------------------------------
  9. * DismissableLayer
  10. * -----------------------------------------------------------------------------------------------*/ const $5cb92bef7577960e$var$DISMISSABLE_LAYER_NAME = 'DismissableLayer';
  11. const $5cb92bef7577960e$var$CONTEXT_UPDATE = 'dismissableLayer.update';
  12. const $5cb92bef7577960e$var$POINTER_DOWN_OUTSIDE = 'dismissableLayer.pointerDownOutside';
  13. const $5cb92bef7577960e$var$FOCUS_OUTSIDE = 'dismissableLayer.focusOutside';
  14. let $5cb92bef7577960e$var$originalBodyPointerEvents;
  15. const $5cb92bef7577960e$var$DismissableLayerContext = /*#__PURE__*/ $kqwpH$createContext({
  16. layers: new Set(),
  17. layersWithOutsidePointerEventsDisabled: new Set(),
  18. branches: new Set()
  19. });
  20. const $5cb92bef7577960e$export$177fb62ff3ec1f22 = /*#__PURE__*/ $kqwpH$forwardRef((props, forwardedRef)=>{
  21. var _node$ownerDocument;
  22. const { disableOutsidePointerEvents: disableOutsidePointerEvents = false , onEscapeKeyDown: onEscapeKeyDown , onPointerDownOutside: onPointerDownOutside , onFocusOutside: onFocusOutside , onInteractOutside: onInteractOutside , onDismiss: onDismiss , ...layerProps } = props;
  23. const context = $kqwpH$useContext($5cb92bef7577960e$var$DismissableLayerContext);
  24. const [node1, setNode] = $kqwpH$useState(null);
  25. const ownerDocument = (_node$ownerDocument = node1 === null || node1 === void 0 ? void 0 : node1.ownerDocument) !== null && _node$ownerDocument !== void 0 ? _node$ownerDocument : globalThis === null || globalThis === void 0 ? void 0 : globalThis.document;
  26. const [, force] = $kqwpH$useState({});
  27. const composedRefs = $kqwpH$useComposedRefs(forwardedRef, (node)=>setNode(node)
  28. );
  29. const layers = Array.from(context.layers);
  30. const [highestLayerWithOutsidePointerEventsDisabled] = [
  31. ...context.layersWithOutsidePointerEventsDisabled
  32. ].slice(-1); // prettier-ignore
  33. const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); // prettier-ignore
  34. const index = node1 ? layers.indexOf(node1) : -1;
  35. const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0;
  36. const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex;
  37. const pointerDownOutside = $5cb92bef7577960e$var$usePointerDownOutside((event)=>{
  38. const target = event.target;
  39. const isPointerDownOnBranch = [
  40. ...context.branches
  41. ].some((branch)=>branch.contains(target)
  42. );
  43. if (!isPointerEventsEnabled || isPointerDownOnBranch) return;
  44. onPointerDownOutside === null || onPointerDownOutside === void 0 || onPointerDownOutside(event);
  45. onInteractOutside === null || onInteractOutside === void 0 || onInteractOutside(event);
  46. if (!event.defaultPrevented) onDismiss === null || onDismiss === void 0 || onDismiss();
  47. }, ownerDocument);
  48. const focusOutside = $5cb92bef7577960e$var$useFocusOutside((event)=>{
  49. const target = event.target;
  50. const isFocusInBranch = [
  51. ...context.branches
  52. ].some((branch)=>branch.contains(target)
  53. );
  54. if (isFocusInBranch) return;
  55. onFocusOutside === null || onFocusOutside === void 0 || onFocusOutside(event);
  56. onInteractOutside === null || onInteractOutside === void 0 || onInteractOutside(event);
  57. if (!event.defaultPrevented) onDismiss === null || onDismiss === void 0 || onDismiss();
  58. }, ownerDocument);
  59. $kqwpH$useEscapeKeydown((event)=>{
  60. const isHighestLayer = index === context.layers.size - 1;
  61. if (!isHighestLayer) return;
  62. onEscapeKeyDown === null || onEscapeKeyDown === void 0 || onEscapeKeyDown(event);
  63. if (!event.defaultPrevented && onDismiss) {
  64. event.preventDefault();
  65. onDismiss();
  66. }
  67. }, ownerDocument);
  68. $kqwpH$useEffect(()=>{
  69. if (!node1) return;
  70. if (disableOutsidePointerEvents) {
  71. if (context.layersWithOutsidePointerEventsDisabled.size === 0) {
  72. $5cb92bef7577960e$var$originalBodyPointerEvents = ownerDocument.body.style.pointerEvents;
  73. ownerDocument.body.style.pointerEvents = 'none';
  74. }
  75. context.layersWithOutsidePointerEventsDisabled.add(node1);
  76. }
  77. context.layers.add(node1);
  78. $5cb92bef7577960e$var$dispatchUpdate();
  79. return ()=>{
  80. if (disableOutsidePointerEvents && context.layersWithOutsidePointerEventsDisabled.size === 1) ownerDocument.body.style.pointerEvents = $5cb92bef7577960e$var$originalBodyPointerEvents;
  81. };
  82. }, [
  83. node1,
  84. ownerDocument,
  85. disableOutsidePointerEvents,
  86. context
  87. ]);
  88. /**
  89. * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect
  90. * because a change to `disableOutsidePointerEvents` would remove this layer from the stack
  91. * and add it to the end again so the layering order wouldn't be _creation order_.
  92. * We only want them to be removed from context stacks when unmounted.
  93. */ $kqwpH$useEffect(()=>{
  94. return ()=>{
  95. if (!node1) return;
  96. context.layers.delete(node1);
  97. context.layersWithOutsidePointerEventsDisabled.delete(node1);
  98. $5cb92bef7577960e$var$dispatchUpdate();
  99. };
  100. }, [
  101. node1,
  102. context
  103. ]);
  104. $kqwpH$useEffect(()=>{
  105. const handleUpdate = ()=>force({})
  106. ;
  107. document.addEventListener($5cb92bef7577960e$var$CONTEXT_UPDATE, handleUpdate);
  108. return ()=>document.removeEventListener($5cb92bef7577960e$var$CONTEXT_UPDATE, handleUpdate)
  109. ;
  110. }, []);
  111. return /*#__PURE__*/ $kqwpH$createElement($kqwpH$Primitive.div, $kqwpH$babelruntimehelpersesmextends({}, layerProps, {
  112. ref: composedRefs,
  113. style: {
  114. pointerEvents: isBodyPointerEventsDisabled ? isPointerEventsEnabled ? 'auto' : 'none' : undefined,
  115. ...props.style
  116. },
  117. onFocusCapture: $kqwpH$composeEventHandlers(props.onFocusCapture, focusOutside.onFocusCapture),
  118. onBlurCapture: $kqwpH$composeEventHandlers(props.onBlurCapture, focusOutside.onBlurCapture),
  119. onPointerDownCapture: $kqwpH$composeEventHandlers(props.onPointerDownCapture, pointerDownOutside.onPointerDownCapture)
  120. }));
  121. });
  122. /*#__PURE__*/ Object.assign($5cb92bef7577960e$export$177fb62ff3ec1f22, {
  123. displayName: $5cb92bef7577960e$var$DISMISSABLE_LAYER_NAME
  124. });
  125. /* -------------------------------------------------------------------------------------------------
  126. * DismissableLayerBranch
  127. * -----------------------------------------------------------------------------------------------*/ const $5cb92bef7577960e$var$BRANCH_NAME = 'DismissableLayerBranch';
  128. const $5cb92bef7577960e$export$4d5eb2109db14228 = /*#__PURE__*/ $kqwpH$forwardRef((props, forwardedRef)=>{
  129. const context = $kqwpH$useContext($5cb92bef7577960e$var$DismissableLayerContext);
  130. const ref = $kqwpH$useRef(null);
  131. const composedRefs = $kqwpH$useComposedRefs(forwardedRef, ref);
  132. $kqwpH$useEffect(()=>{
  133. const node = ref.current;
  134. if (node) {
  135. context.branches.add(node);
  136. return ()=>{
  137. context.branches.delete(node);
  138. };
  139. }
  140. }, [
  141. context.branches
  142. ]);
  143. return /*#__PURE__*/ $kqwpH$createElement($kqwpH$Primitive.div, $kqwpH$babelruntimehelpersesmextends({}, props, {
  144. ref: composedRefs
  145. }));
  146. });
  147. /*#__PURE__*/ Object.assign($5cb92bef7577960e$export$4d5eb2109db14228, {
  148. displayName: $5cb92bef7577960e$var$BRANCH_NAME
  149. });
  150. /* -----------------------------------------------------------------------------------------------*/ /**
  151. * Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`
  152. * to mimic layer dismissing behaviour present in OS.
  153. * Returns props to pass to the node we want to check for outside events.
  154. */ function $5cb92bef7577960e$var$usePointerDownOutside(onPointerDownOutside, ownerDocument = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) {
  155. const handlePointerDownOutside = $kqwpH$useCallbackRef(onPointerDownOutside);
  156. const isPointerInsideReactTreeRef = $kqwpH$useRef(false);
  157. const handleClickRef = $kqwpH$useRef(()=>{});
  158. $kqwpH$useEffect(()=>{
  159. const handlePointerDown = (event)=>{
  160. if (event.target && !isPointerInsideReactTreeRef.current) {
  161. const eventDetail = {
  162. originalEvent: event
  163. };
  164. function handleAndDispatchPointerDownOutsideEvent() {
  165. $5cb92bef7577960e$var$handleAndDispatchCustomEvent($5cb92bef7577960e$var$POINTER_DOWN_OUTSIDE, handlePointerDownOutside, eventDetail, {
  166. discrete: true
  167. });
  168. }
  169. /**
  170. * On touch devices, we need to wait for a click event because browsers implement
  171. * a ~350ms delay between the time the user stops touching the display and when the
  172. * browser executres events. We need to ensure we don't reactivate pointer-events within
  173. * this timeframe otherwise the browser may execute events that should have been prevented.
  174. *
  175. * Additionally, this also lets us deal automatically with cancellations when a click event
  176. * isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.
  177. *
  178. * This is why we also continuously remove the previous listener, because we cannot be
  179. * certain that it was raised, and therefore cleaned-up.
  180. */ if (event.pointerType === 'touch') {
  181. ownerDocument.removeEventListener('click', handleClickRef.current);
  182. handleClickRef.current = handleAndDispatchPointerDownOutsideEvent;
  183. ownerDocument.addEventListener('click', handleClickRef.current, {
  184. once: true
  185. });
  186. } else handleAndDispatchPointerDownOutsideEvent();
  187. } else // We need to remove the event listener in case the outside click has been canceled.
  188. // See: https://github.com/radix-ui/primitives/issues/2171
  189. ownerDocument.removeEventListener('click', handleClickRef.current);
  190. isPointerInsideReactTreeRef.current = false;
  191. };
  192. /**
  193. * if this hook executes in a component that mounts via a `pointerdown` event, the event
  194. * would bubble up to the document and trigger a `pointerDownOutside` event. We avoid
  195. * this by delaying the event listener registration on the document.
  196. * This is not React specific, but rather how the DOM works, ie:
  197. * ```
  198. * button.addEventListener('pointerdown', () => {
  199. * console.log('I will log');
  200. * document.addEventListener('pointerdown', () => {
  201. * console.log('I will also log');
  202. * })
  203. * });
  204. */ const timerId = window.setTimeout(()=>{
  205. ownerDocument.addEventListener('pointerdown', handlePointerDown);
  206. }, 0);
  207. return ()=>{
  208. window.clearTimeout(timerId);
  209. ownerDocument.removeEventListener('pointerdown', handlePointerDown);
  210. ownerDocument.removeEventListener('click', handleClickRef.current);
  211. };
  212. }, [
  213. ownerDocument,
  214. handlePointerDownOutside
  215. ]);
  216. return {
  217. // ensures we check React component tree (not just DOM tree)
  218. onPointerDownCapture: ()=>isPointerInsideReactTreeRef.current = true
  219. };
  220. }
  221. /**
  222. * Listens for when focus happens outside a react subtree.
  223. * Returns props to pass to the root (node) of the subtree we want to check.
  224. */ function $5cb92bef7577960e$var$useFocusOutside(onFocusOutside, ownerDocument = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) {
  225. const handleFocusOutside = $kqwpH$useCallbackRef(onFocusOutside);
  226. const isFocusInsideReactTreeRef = $kqwpH$useRef(false);
  227. $kqwpH$useEffect(()=>{
  228. const handleFocus = (event)=>{
  229. if (event.target && !isFocusInsideReactTreeRef.current) {
  230. const eventDetail = {
  231. originalEvent: event
  232. };
  233. $5cb92bef7577960e$var$handleAndDispatchCustomEvent($5cb92bef7577960e$var$FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {
  234. discrete: false
  235. });
  236. }
  237. };
  238. ownerDocument.addEventListener('focusin', handleFocus);
  239. return ()=>ownerDocument.removeEventListener('focusin', handleFocus)
  240. ;
  241. }, [
  242. ownerDocument,
  243. handleFocusOutside
  244. ]);
  245. return {
  246. onFocusCapture: ()=>isFocusInsideReactTreeRef.current = true
  247. ,
  248. onBlurCapture: ()=>isFocusInsideReactTreeRef.current = false
  249. };
  250. }
  251. function $5cb92bef7577960e$var$dispatchUpdate() {
  252. const event = new CustomEvent($5cb92bef7577960e$var$CONTEXT_UPDATE);
  253. document.dispatchEvent(event);
  254. }
  255. function $5cb92bef7577960e$var$handleAndDispatchCustomEvent(name, handler, detail, { discrete: discrete }) {
  256. const target = detail.originalEvent.target;
  257. const event = new CustomEvent(name, {
  258. bubbles: false,
  259. cancelable: true,
  260. detail: detail
  261. });
  262. if (handler) target.addEventListener(name, handler, {
  263. once: true
  264. });
  265. if (discrete) $kqwpH$dispatchDiscreteCustomEvent(target, event);
  266. else target.dispatchEvent(event);
  267. }
  268. const $5cb92bef7577960e$export$be92b6f5f03c0fe9 = $5cb92bef7577960e$export$177fb62ff3ec1f22;
  269. const $5cb92bef7577960e$export$aecb2ddcb55c95be = $5cb92bef7577960e$export$4d5eb2109db14228;
  270. export {$5cb92bef7577960e$export$177fb62ff3ec1f22 as DismissableLayer, $5cb92bef7577960e$export$4d5eb2109db14228 as DismissableLayerBranch, $5cb92bef7577960e$export$be92b6f5f03c0fe9 as Root, $5cb92bef7577960e$export$aecb2ddcb55c95be as Branch};
  271. //# sourceMappingURL=index.mjs.map