Files
Housekeeping-web-admin/node_modules/@radix-ui/react-dismissable-layer/dist/index.mjs
T
2026-06-24 09:48:54 +02:00

333 lines
13 KiB
JavaScript

"use client";
// src/dismissable-layer.tsx
import * as React from "react";
import { composeEventHandlers } from "@radix-ui/primitive";
import { Primitive, dispatchDiscreteCustomEvent } from "@radix-ui/react-primitive";
import { useComposedRefs } from "@radix-ui/react-compose-refs";
import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
import { useEscapeKeydown } from "@radix-ui/react-use-escape-keydown";
import { jsx } from "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 = 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);
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__ */ jsx(
Primitive.div,
{
...layerProps,
ref: composedRefs,
style: {
pointerEvents: isBodyPointerEventsDisabled ? isPointerEventsEnabled ? "auto" : "none" : void 0,
...props.style
},
onFocusCapture: composeEventHandlers(props.onFocusCapture, focusOutside.onFocusCapture),
onBlurCapture: composeEventHandlers(props.onBlurCapture, focusOutside.onBlurCapture),
onPointerDownCapture: 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 = useComposedRefs(forwardedRef, ref);
React.useEffect(() => {
const node = ref.current;
if (node) {
context.branches.add(node);
return () => {
context.branches.delete(node);
};
}
}, [context.branches]);
return /* @__PURE__ */ jsx(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 = 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 = 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) {
dispatchDiscreteCustomEvent(target, event);
} else {
target.dispatchEvent(event);
}
}
var Root = DismissableLayer;
var Branch = DismissableLayerBranch;
export {
Branch,
DismissableLayer,
DismissableLayerBranch,
Root,
useDismissableLayerSurface
};
//# sourceMappingURL=index.mjs.map