"use strict"; "use client"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { Branch: () => Branch, DismissableLayer: () => DismissableLayer, DismissableLayerBranch: () => DismissableLayerBranch, Root: () => Root, useDismissableLayerSurface: () => useDismissableLayerSurface }); module.exports = __toCommonJS(index_exports); // src/dismissable-layer.tsx var React = __toESM(require("react")); var import_primitive = require("@radix-ui/primitive"); var import_react_primitive = require("@radix-ui/react-primitive"); var import_react_compose_refs = require("@radix-ui/react-compose-refs"); var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref"); var import_react_use_escape_keydown = require("@radix-ui/react-use-escape-keydown"); var import_jsx_runtime = require("react/jsx-runtime"); var DISMISSABLE_LAYER_NAME = "DismissableLayer"; var CONTEXT_UPDATE = "dismissableLayer.update"; var POINTER_DOWN_OUTSIDE = "dismissableLayer.pointerDownOutside"; var FOCUS_OUTSIDE = "dismissableLayer.focusOutside"; var originalBodyPointerEvents; var DismissableLayerContext = React.createContext({ layers: /* @__PURE__ */ new Set(), layersWithOutsidePointerEventsDisabled: /* @__PURE__ */ new Set(), branches: /* @__PURE__ */ new Set(), // Outside elements that belong to a layer's own dismiss affordance (eg, a // dialog overlay). Pressing them should dismiss the layer regardless of // whether or not they stop propagation. // // See https://github.com/radix-ui/primitives/issues/3346 dismissableSurfaces: /* @__PURE__ */ new Set() }); var DismissableLayer = React.forwardRef( (props, forwardedRef) => { const { disableOutsidePointerEvents = false, deferPointerDownOutside = false, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, onDismiss, ...layerProps } = props; const context = React.useContext(DismissableLayerContext); const [node, setNode] = React.useState(null); const ownerDocument = node?.ownerDocument ?? globalThis?.document; const [, force] = React.useState({}); const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node2) => setNode(node2)); const layers = Array.from(context.layers); const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1); const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); const index = node ? layers.indexOf(node) : -1; const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0; const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex; const isDeferredPointerDownOutsideRef = React.useRef(false); const pointerDownOutside = usePointerDownOutside( (event) => { const target = event.target; if (!(target instanceof Node)) { return; } const isPointerDownOnBranch = [...context.branches].some( (branch) => branch.contains(target) ); if (!isPointerEventsEnabled || isPointerDownOnBranch) return; onPointerDownOutside?.(event); onInteractOutside?.(event); if (!event.defaultPrevented) onDismiss?.(); }, { ownerDocument, deferPointerDownOutside, isDeferredPointerDownOutsideRef, dismissableSurfaces: context.dismissableSurfaces } ); const focusOutside = useFocusOutside((event) => { if (deferPointerDownOutside && isDeferredPointerDownOutsideRef.current) { return; } const target = event.target; const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target)); if (isFocusInBranch) return; onFocusOutside?.(event); onInteractOutside?.(event); if (!event.defaultPrevented) onDismiss?.(); }, ownerDocument); (0, import_react_use_escape_keydown.useEscapeKeydown)((event) => { const isHighestLayer = index === context.layers.size - 1; if (!isHighestLayer) return; onEscapeKeyDown?.(event); if (!event.defaultPrevented && onDismiss) { event.preventDefault(); onDismiss(); } }, ownerDocument); React.useEffect(() => { if (!node) return; if (disableOutsidePointerEvents) { if (context.layersWithOutsidePointerEventsDisabled.size === 0) { originalBodyPointerEvents = ownerDocument.body.style.pointerEvents; ownerDocument.body.style.pointerEvents = "none"; } context.layersWithOutsidePointerEventsDisabled.add(node); } context.layers.add(node); dispatchUpdate(); return () => { if (disableOutsidePointerEvents) { context.layersWithOutsidePointerEventsDisabled.delete(node); if (context.layersWithOutsidePointerEventsDisabled.size === 0) { ownerDocument.body.style.pointerEvents = originalBodyPointerEvents; } } }; }, [node, ownerDocument, disableOutsidePointerEvents, context]); React.useEffect(() => { return () => { if (!node) return; context.layers.delete(node); context.layersWithOutsidePointerEventsDisabled.delete(node); dispatchUpdate(); }; }, [node, context]); React.useEffect(() => { const handleUpdate = () => force({}); document.addEventListener(CONTEXT_UPDATE, handleUpdate); return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate); }, []); return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_react_primitive.Primitive.div, { ...layerProps, ref: composedRefs, style: { pointerEvents: isBodyPointerEventsDisabled ? isPointerEventsEnabled ? "auto" : "none" : void 0, ...props.style }, onFocusCapture: (0, import_primitive.composeEventHandlers)(props.onFocusCapture, focusOutside.onFocusCapture), onBlurCapture: (0, import_primitive.composeEventHandlers)(props.onBlurCapture, focusOutside.onBlurCapture), onPointerDownCapture: (0, import_primitive.composeEventHandlers)( props.onPointerDownCapture, pointerDownOutside.onPointerDownCapture ) } ); } ); DismissableLayer.displayName = DISMISSABLE_LAYER_NAME; var BRANCH_NAME = "DismissableLayerBranch"; var DismissableLayerBranch = React.forwardRef((props, forwardedRef) => { const context = React.useContext(DismissableLayerContext); const ref = React.useRef(null); const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref); React.useEffect(() => { const node = ref.current; if (node) { context.branches.add(node); return () => { context.branches.delete(node); }; } }, [context.branches]); return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...props, ref: composedRefs }); }); DismissableLayerBranch.displayName = BRANCH_NAME; function useDismissableLayerSurface() { const context = React.useContext(DismissableLayerContext); const [node, setNode] = React.useState(null); React.useEffect(() => { if (!node) { return; } context.dismissableSurfaces.add(node); return () => { context.dismissableSurfaces.delete(node); }; }, [node, context.dismissableSurfaces]); return setNode; } function usePointerDownOutside(onPointerDownOutside, args) { const { ownerDocument = globalThis?.document, deferPointerDownOutside = false, isDeferredPointerDownOutsideRef, dismissableSurfaces } = args; const handlePointerDownOutside = (0, import_react_use_callback_ref.useCallbackRef)(onPointerDownOutside); const isPointerInsideReactTreeRef = React.useRef(false); const isPointerDownOutsideRef = React.useRef(false); const interceptedOutsideInteractionEventsRef = React.useRef(/* @__PURE__ */ new Map()); const handleClickRef = React.useRef(() => { }); React.useEffect(() => { function resetOutsideInteraction() { isPointerDownOutsideRef.current = false; isDeferredPointerDownOutsideRef.current = false; interceptedOutsideInteractionEventsRef.current.clear(); } function isOutsideInteractionIntercepted() { return Array.from(interceptedOutsideInteractionEventsRef.current.values()).some(Boolean); } function handleInteractionCapture(event) { if (!isPointerDownOutsideRef.current) { return; } const target = event.target; const isDismissableSurface = target instanceof Node && [...dismissableSurfaces].some((surface) => surface.contains(target)); if (!isDismissableSurface) { interceptedOutsideInteractionEventsRef.current.set(event.type, true); } if (event.type === "click") { window.setTimeout(() => { if (isPointerDownOutsideRef.current) { handleClickRef.current(); } }, 0); } } function handleInteractionBubble(event) { if (isPointerDownOutsideRef.current) { interceptedOutsideInteractionEventsRef.current.set(event.type, false); } } const handlePointerDown = (event) => { if (event.target && !isPointerInsideReactTreeRef.current) { let handleAndDispatchPointerDownOutsideEvent2 = function() { ownerDocument.removeEventListener("click", handleClickRef.current); const wasOutsideInteractionIntercepted = isOutsideInteractionIntercepted(); resetOutsideInteraction(); if (!wasOutsideInteractionIntercepted) { handleAndDispatchCustomEvent( POINTER_DOWN_OUTSIDE, handlePointerDownOutside, eventDetail, { discrete: true } ); } }; var handleAndDispatchPointerDownOutsideEvent = handleAndDispatchPointerDownOutsideEvent2; const eventDetail = { originalEvent: event }; isPointerDownOutsideRef.current = true; isDeferredPointerDownOutsideRef.current = deferPointerDownOutside && event.button === 0; interceptedOutsideInteractionEventsRef.current.clear(); if (!deferPointerDownOutside || event.button !== 0) { handleAndDispatchPointerDownOutsideEvent2(); } else { ownerDocument.removeEventListener("click", handleClickRef.current); handleClickRef.current = handleAndDispatchPointerDownOutsideEvent2; ownerDocument.addEventListener("click", handleClickRef.current, { once: true }); } } else { ownerDocument.removeEventListener("click", handleClickRef.current); resetOutsideInteraction(); } isPointerInsideReactTreeRef.current = false; }; const outsideInteractionEvents = [ "pointerup", "mousedown", "mouseup", "touchstart", "touchend", "click" ]; for (const eventName of outsideInteractionEvents) { ownerDocument.addEventListener(eventName, handleInteractionCapture, true); ownerDocument.addEventListener(eventName, handleInteractionBubble); } const timerId = window.setTimeout(() => { ownerDocument.addEventListener("pointerdown", handlePointerDown); }, 0); return () => { window.clearTimeout(timerId); ownerDocument.removeEventListener("pointerdown", handlePointerDown); ownerDocument.removeEventListener("click", handleClickRef.current); for (const eventName of outsideInteractionEvents) { ownerDocument.removeEventListener(eventName, handleInteractionCapture, true); ownerDocument.removeEventListener(eventName, handleInteractionBubble); } }; }, [ ownerDocument, handlePointerDownOutside, deferPointerDownOutside, isDeferredPointerDownOutsideRef, dismissableSurfaces ]); return { // ensures we check React component tree (not just DOM tree) onPointerDownCapture: () => isPointerInsideReactTreeRef.current = true }; } function useFocusOutside(onFocusOutside, ownerDocument = globalThis?.document) { const handleFocusOutside = (0, import_react_use_callback_ref.useCallbackRef)(onFocusOutside); const isFocusInsideReactTreeRef = React.useRef(false); React.useEffect(() => { const handleFocus = (event) => { if (event.target && !isFocusInsideReactTreeRef.current) { const eventDetail = { originalEvent: event }; handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, { discrete: false }); } }; ownerDocument.addEventListener("focusin", handleFocus); return () => ownerDocument.removeEventListener("focusin", handleFocus); }, [ownerDocument, handleFocusOutside]); return { onFocusCapture: () => isFocusInsideReactTreeRef.current = true, onBlurCapture: () => isFocusInsideReactTreeRef.current = false }; } function dispatchUpdate() { const event = new CustomEvent(CONTEXT_UPDATE); document.dispatchEvent(event); } function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) { const target = detail.originalEvent.target; const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail }); if (handler) target.addEventListener(name, handler, { once: true }); if (discrete) { (0, import_react_primitive.dispatchDiscreteCustomEvent)(target, event); } else { target.dispatchEvent(event); } } var Root = DismissableLayer; var Branch = DismissableLayerBranch; //# sourceMappingURL=index.js.map