UNPKG

@clayui/shared

Version:
191 lines (190 loc) 6.88 kB
"use strict"; 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); var Overlay_exports = {}; __export(Overlay_exports, { Overlay: () => Overlay }); module.exports = __toCommonJS(Overlay_exports); var import_aria_hidden = require("aria-hidden"); var import_react = __toESM(require("react")); var import_Keys = require("./Keys"); var import_Portal = require("./Portal"); var import_useInteractOutside = require("./useInteractOutside"); const overlayStack = []; function Overlay({ children, inert, isCloseOnInteractOutside = false, isKeyboardDismiss = false, isModal = false, isOpen = false, menuClassName, menuRef, onClose, portalRef, suppress, triggerRef }) { const unsuppressCallbackRef = (0, import_react.useRef)(null); const isInert = (isModal || inert) && (0, import_aria_hidden.supportsInert)(); const onHide = (0, import_react.useCallback)( (action) => { if (overlayStack[overlayStack.length - 1]?.menu === menuRef) { onClose(action); } }, [onClose] ); useEvent( "focus", (0, import_react.useCallback)( (event) => { if (portalRef && !portalRef.current?.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) { onHide("blur"); } }, [onHide] ), isOpen, true, [isOpen, onHide] ); useEvent( "keydown", (0, import_react.useCallback)( (event) => { if (event.key === import_Keys.Keys.Esc && overlayStack[overlayStack.length - 1]?.menu === menuRef) { event.stopImmediatePropagation(); event.preventDefault(); if (triggerRef.current) { if (unsuppressCallbackRef.current) { unsuppressCallbackRef.current(); unsuppressCallbackRef.current = null; } triggerRef.current.focus(); } onClose("escape"); } }, [onClose] ), isOpen && isKeyboardDismiss, true, [isOpen, onClose] ); (0, import_useInteractOutside.useInteractOutside)({ isDisabled: isOpen ? !isCloseOnInteractOutside : true, onInteract: (event) => { if (event.button === 0) { onHide("blur"); } }, onInteractStart: (event) => { if (overlayStack[overlayStack.length - 1]?.menu === menuRef) { if (unsuppressCallbackRef.current) { unsuppressCallbackRef.current(); unsuppressCallbackRef.current = null; } if (isModal) { event.stopPropagation(); event.preventDefault(); } } }, ref: portalRef ?? menuRef, triggerRef }); (0, import_react.useEffect)(() => { if (isOpen) { overlayStack.push({ inert: isInert, menu: menuRef }); } return () => { const index = overlayStack.findIndex( (object) => object.menu === menuRef ); if (index >= 0) { overlayStack.splice(index, 1); } }; }, [isOpen, menuRef]); (0, import_react.useEffect)(() => { const currentMenuRef = menuRef?.current; const previousOverlayStacks = overlayStack.slice(0, -1); const previouslyHidden = previousOverlayStacks.findIndex( (object) => object.inert === void 0 ) >= 0; const previouslyInert = previousOverlayStacks.findIndex( (object) => object.inert === true ) >= 0; if (currentMenuRef && isOpen) { const parentMenuElements = previousOverlayStacks.map(({ menu }) => menu.current).filter((element) => Boolean(element)).filter((element) => element !== currentMenuRef); const primaryElements = suppress ? suppress.map((ref) => ref.current) : [currentMenuRef]; const elements = primaryElements.concat(parentMenuElements); const hiddenElement = currentMenuRef.closest("[aria-hidden]") || currentMenuRef.closest("[inert]"); hiddenElement?.removeAttribute("data-suppressed"); hiddenElement?.removeAttribute("data-aria-hidden"); hiddenElement?.removeAttribute("aria-hidden"); hiddenElement?.removeAttribute("inert"); if (isInert) { unsuppressCallbackRef.current = (0, import_aria_hidden.suppressOthers)(elements); } else { unsuppressCallbackRef.current = (0, import_aria_hidden.hideOthers)(elements); } return () => { if (unsuppressCallbackRef.current) { unsuppressCallbackRef.current(); } if (isInert && !previouslyInert) { document.querySelectorAll("[inert]").forEach((element) => { element.removeAttribute("inert"); }); } else if (!isInert && !previouslyHidden) { document.querySelectorAll("[aria-hidden]").forEach((element) => { element.removeAttribute("aria-hidden"); }); } unsuppressCallbackRef.current = null; }; } }, [isModal, inert, isOpen]); return /* @__PURE__ */ import_react.default.createElement(import_Portal.ClayPortal, { className: menuClassName, subPortalRef: portalRef }, isModal && /* @__PURE__ */ import_react.default.createElement("span", { "data-focus-scope-start": "true" }), children, isModal && /* @__PURE__ */ import_react.default.createElement("span", { "data-focus-scope-end": "true" })); } function useEvent(name, onEvent, conditional, capture, deps = []) { (0, import_react.useEffect)(() => { if (conditional) { document.addEventListener(name, onEvent, capture); return () => { document.removeEventListener(name, onEvent, capture); }; } }, deps); }