@kobalte/core
Version:
Unstyled components and primitives for building accessible web apps and design systems with SolidJS.
130 lines (126 loc) • 4.09 kB
JavaScript
import { createInteractOutside } from './KKN23NY7.js';
import { createEscapeKeyDown } from './QEMPLYZX.js';
import { layerStack } from './ZKYDDHM6.js';
import { Polymorphic } from './6Y7B2NEO.js';
import { createComponent, mergeProps } from 'solid-js/web';
import { getDocument, mergeRefs, contains } from '@kobalte/utils';
import { createContext, splitProps, onMount, createEffect, on, onCleanup, 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 createComponent(DismissableLayerContext.Provider, {
value: context,
get children() {
return createComponent(Polymorphic, mergeProps({
as: "div",
ref(r$) {
const _ref$ = mergeRefs((el) => ref = el, local.ref);
typeof _ref$ === "function" && _ref$(r$);
}
}, others));
}
});
}
export { DismissableLayer };