@kobalte/core
Version:
Unstyled components and primitives for building accessible web apps and design systems with SolidJS.
161 lines (156 loc) • 4.19 kB
JSX
import {
createInteractOutside
} from "./MGQGUY64.jsx";
import {
createEscapeKeyDown
} from "./IGYOA2ZZ.jsx";
import {
layerStack
} from "./3NI6FTA2.jsx";
import {
Polymorphic
} from "./FLVHQV4A.jsx";
// src/dismissable-layer/dismissable-layer.tsx
import { contains, getDocument, mergeRefs } from "@kobalte/utils";
import {
createEffect,
on,
onCleanup,
onMount,
splitProps
} from "solid-js";
// src/dismissable-layer/dismissable-layer-context.tsx
import { createContext, useContext } from "solid-js";
var DismissableLayerContext = createContext();
function useOptionalDismissableLayerContext() {
return useContext(DismissableLayerContext);
}
// src/dismissable-layer/dismissable-layer.tsx
function DismissableLayer(props) {
let ref;
const parentContext = useOptionalDismissableLayerContext();
const [local, others] = splitProps(props, [
"ref",
"disableOutsidePointerEvents",
"excludedElements",
"onEscapeKeyDown",
"onPointerDownOutside",
"onFocusOutside",
"onInteractOutside",
"onDismiss",
"bypassTopMostLayerCheck"
]);
const nestedLayers = /* @__PURE__ */ new Set([]);
const registerNestedLayer = (element) => {
nestedLayers.add(element);
const parentUnregister = parentContext?.registerNestedLayer(element);
return () => {
nestedLayers.delete(element);
parentUnregister?.();
};
};
const shouldExcludeElement = (element) => {
if (!ref) {
return false;
}
return local.excludedElements?.some((node) => contains(node(), element)) || [...nestedLayers].some((layer) => contains(layer, element));
};
const onPointerDownOutside = (e) => {
if (!ref || layerStack.isBelowPointerBlockingLayer(ref)) {
return;
}
if (!local.bypassTopMostLayerCheck && !layerStack.isTopMostLayer(ref)) {
return;
}
local.onPointerDownOutside?.(e);
local.onInteractOutside?.(e);
if (!e.defaultPrevented) {
local.onDismiss?.();
}
};
const onFocusOutside = (e) => {
local.onFocusOutside?.(e);
local.onInteractOutside?.(e);
if (!e.defaultPrevented) {
local.onDismiss?.();
}
};
createInteractOutside(
{
shouldExcludeElement,
onPointerDownOutside,
onFocusOutside
},
() => ref
);
createEscapeKeyDown({
ownerDocument: () => getDocument(ref),
onEscapeKeyDown: (e) => {
if (!ref || !layerStack.isTopMostLayer(ref)) {
return;
}
local.onEscapeKeyDown?.(e);
if (!e.defaultPrevented && local.onDismiss) {
e.preventDefault();
local.onDismiss();
}
}
});
onMount(() => {
if (!ref) {
return;
}
layerStack.addLayer({
node: ref,
isPointerBlocking: local.disableOutsidePointerEvents,
dismiss: local.onDismiss
});
const unregisterFromParentLayer = parentContext?.registerNestedLayer(ref);
layerStack.assignPointerEventToLayers();
layerStack.disableBodyPointerEvents(ref);
onCleanup(() => {
if (!ref) {
return;
}
layerStack.removeLayer(ref);
unregisterFromParentLayer?.();
layerStack.assignPointerEventToLayers();
layerStack.restoreBodyPointerEvents(ref);
});
});
createEffect(
on(
[() => ref, () => local.disableOutsidePointerEvents],
([ref2, disableOutsidePointerEvents]) => {
if (!ref2) {
return;
}
const layer = layerStack.find(ref2);
if (layer && layer.isPointerBlocking !== disableOutsidePointerEvents) {
layer.isPointerBlocking = disableOutsidePointerEvents;
layerStack.assignPointerEventToLayers();
}
if (disableOutsidePointerEvents) {
layerStack.disableBodyPointerEvents(ref2);
}
onCleanup(() => {
layerStack.restoreBodyPointerEvents(ref2);
});
},
{
defer: true
}
)
);
const context = {
registerNestedLayer
};
return <DismissableLayerContext.Provider value={context}><Polymorphic
as="div"
ref={mergeRefs((el) => ref = el, local.ref)}
{...others}
/></DismissableLayerContext.Provider>;
}
export {
DismissableLayer
};