@ariakit/react
Version:
Toolkit for building accessible web apps with React
260 lines (235 loc) • 9.7 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true});
var _MOTSR5FYcjs = require('./MOTSR5FY.cjs');
var _LZ6L3ECGcjs = require('./LZ6L3ECG.cjs');
// ../ariakit-react-components/dist/portal/portal-context.js
var _react = require('react');
var PortalContext = _react.createContext.call(void 0, null);
// ../ariakit-react-components/dist/portal/portal.js
var _jsxruntime = require('react/jsx-runtime');
var _reactdom = require('react-dom');
var TagName = "div";
function getRootElement(element) {
var _a;
const doc = _LZ6L3ECGcjs.getDocument.call(void 0, element);
const { fullscreenElement } = doc;
const HTMLElementClass = (_a = doc.defaultView) == null ? void 0 : _a.HTMLElement;
if (HTMLElementClass && fullscreenElement instanceof HTMLElementClass) return fullscreenElement;
return doc.body;
}
function getPortalElement(element, portalElement) {
if (!portalElement) return _LZ6L3ECGcjs.getDocument.call(void 0, element).createElement("div");
if (typeof portalElement === "function") return portalElement(element);
return portalElement;
}
function getRandomId(prefix = "id") {
return `${prefix ? `${prefix}-` : ""}${Math.random().toString(36).slice(2, 8)}`;
}
function queueFocus(element) {
queueMicrotask(() => {
element == null ? void 0 : element.focus();
});
}
function attachPortalRef(ref, node) {
return {
ref,
node,
cleanup: _LZ6L3ECGcjs.setRef.call(void 0, ref, node)
};
}
function detachPortalRef(attached) {
if (typeof attached.cleanup === "function") attached.cleanup();
else _LZ6L3ECGcjs.setRef.call(void 0, attached.ref, null);
}
var usePortal = _LZ6L3ECGcjs.createHook.call(void 0, function usePortal2({ preserveTabOrder, preserveTabOrderAnchor, portalElement, portalRef, portal = true, ...props }) {
const ref = _react.useRef.call(void 0, null);
const refProp = _LZ6L3ECGcjs.useMergeRefs.call(void 0, ref, props.ref);
const context = _react.useContext.call(void 0, PortalContext);
const [portalNode, setPortalNode] = _react.useState.call(void 0, null);
const [anchorPortalNode, setAnchorPortalNode] = _react.useState.call(void 0, null);
const outerBeforeRef = _react.useRef.call(void 0, null);
const innerBeforeRef = _react.useRef.call(void 0, null);
const innerAfterRef = _react.useRef.call(void 0, null);
const outerAfterRef = _react.useRef.call(void 0, null);
const portalRefProp = _LZ6L3ECGcjs.useLiveRef.call(void 0, portalRef);
const attachedPortalRefRef = _react.useRef.call(void 0, null);
_LZ6L3ECGcjs.useSafeLayoutEffect.call(void 0, () => {
const element = ref.current;
if (!element || !portal) {
setPortalNode(null);
return;
}
const portalEl = getPortalElement(element, portalElement);
if (!portalEl) {
setPortalNode(null);
return;
}
const isPortalInDocument = portalEl.isConnected;
if (!isPortalInDocument) (context || getRootElement(element)).appendChild(portalEl);
if (!portalEl.id) portalEl.id = element.id ? `portal/${element.id}` : getRandomId();
setPortalNode(portalEl);
attachedPortalRefRef.current = attachPortalRef(portalRefProp.current, portalEl);
return () => {
const attached = attachedPortalRefRef.current;
if (attached) {
attachedPortalRefRef.current = null;
detachPortalRef(attached);
}
if (!isPortalInDocument) portalEl.remove();
};
}, [
portal,
portalElement,
context
]);
_LZ6L3ECGcjs.useSafeLayoutEffect.call(void 0, () => {
const attached = attachedPortalRefRef.current;
if (!attached) return;
if (attached.ref === portalRef) return;
detachPortalRef(attached);
attachedPortalRefRef.current = attachPortalRef(portalRef, attached.node);
}, [portalRef]);
_react.useEffect.call(void 0, () => {
if (!portalNode) return;
if (context) return;
if (portalElement) return;
const doc = _LZ6L3ECGcjs.getDocument.call(void 0, portalNode);
const onFullscreenChange = () => {
const rootElement = getRootElement(portalNode);
if (portalNode.parentElement !== rootElement) rootElement.appendChild(portalNode);
};
if (portalNode.isConnected) onFullscreenChange();
doc.addEventListener("fullscreenchange", onFullscreenChange);
return () => {
doc.removeEventListener("fullscreenchange", onFullscreenChange);
};
}, [
portalNode,
context,
portalElement
]);
_LZ6L3ECGcjs.useSafeLayoutEffect.call(void 0, () => {
if (!portal) return;
if (!preserveTabOrder) return;
if (!preserveTabOrderAnchor) return;
const element = _LZ6L3ECGcjs.getDocument.call(void 0, preserveTabOrderAnchor).createElement("span");
element.style.position = "fixed";
preserveTabOrderAnchor.insertAdjacentElement("afterend", element);
setAnchorPortalNode(element);
return () => {
element.remove();
setAnchorPortalNode(null);
};
}, [
portal,
preserveTabOrder,
preserveTabOrderAnchor
]);
_react.useEffect.call(void 0, () => {
if (!portalNode) return;
if (!preserveTabOrder) return;
let raf = 0;
const onFocus = (event) => {
if (!_LZ6L3ECGcjs.isFocusEventOutside.call(void 0, event)) return;
const focusing = event.type === "focusin";
cancelAnimationFrame(raf);
if (focusing) return _LZ6L3ECGcjs.restoreFocusIn.call(void 0, portalNode);
raf = requestAnimationFrame(() => {
_LZ6L3ECGcjs.disableFocusIn.call(void 0, portalNode, true);
});
};
portalNode.addEventListener("focusin", onFocus, true);
portalNode.addEventListener("focusout", onFocus, true);
return () => {
cancelAnimationFrame(raf);
portalNode.removeEventListener("focusin", onFocus, true);
portalNode.removeEventListener("focusout", onFocus, true);
};
}, [portalNode, preserveTabOrder]);
props = _LZ6L3ECGcjs.useWrapElement.call(void 0, props, (element) => {
element = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PortalContext.Provider, {
value: portalNode || context,
children: element
});
if (!portal) return element;
if (!portalNode) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", {
ref: refProp,
id: props.id,
style: { position: "fixed" },
hidden: true
});
element = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
preserveTabOrder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _MOTSR5FYcjs.FocusTrap, {
ref: innerBeforeRef,
"data-focus-trap": props.id,
className: "__focus-trap-inner-before",
onFocus: (event) => {
if (_LZ6L3ECGcjs.isFocusEventOutside.call(void 0, event, portalNode)) queueFocus(_LZ6L3ECGcjs.getNextTabbable.call(void 0, ));
else queueFocus(outerBeforeRef.current);
}
}),
element,
preserveTabOrder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _MOTSR5FYcjs.FocusTrap, {
ref: innerAfterRef,
"data-focus-trap": props.id,
className: "__focus-trap-inner-after",
onFocus: (event) => {
if (_LZ6L3ECGcjs.isFocusEventOutside.call(void 0, event, portalNode)) queueFocus(_LZ6L3ECGcjs.getPreviousTabbable.call(void 0, ));
else queueFocus(outerAfterRef.current);
}
})
] });
element = _reactdom.createPortal.call(void 0, element, portalNode);
let preserveTabOrderElement = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
preserveTabOrder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _MOTSR5FYcjs.FocusTrap, {
ref: outerBeforeRef,
"data-focus-trap": props.id,
className: "__focus-trap-outer-before",
onFocus: (event) => {
if (!(event.relatedTarget === outerAfterRef.current) && _LZ6L3ECGcjs.isFocusEventOutside.call(void 0, event, portalNode)) queueFocus(innerBeforeRef.current);
else queueFocus(_LZ6L3ECGcjs.getPreviousTabbable.call(void 0, ));
}
}),
preserveTabOrder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", {
"aria-owns": portalNode.id,
style: { position: "fixed" }
}),
preserveTabOrder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _MOTSR5FYcjs.FocusTrap, {
ref: outerAfterRef,
"data-focus-trap": props.id,
className: "__focus-trap-outer-after",
onFocus: (event) => {
if (_LZ6L3ECGcjs.isFocusEventOutside.call(void 0, event, portalNode)) queueFocus(innerAfterRef.current);
else {
const nextTabbable = _LZ6L3ECGcjs.getNextTabbable.call(void 0, );
if (nextTabbable === innerBeforeRef.current) {
requestAnimationFrame(() => {
var _a;
return (_a = _LZ6L3ECGcjs.getNextTabbable.call(void 0, )) == null ? void 0 : _a.focus();
});
return;
}
queueFocus(nextTabbable);
}
}
})
] });
if (anchorPortalNode && preserveTabOrder) preserveTabOrderElement = _reactdom.createPortal.call(void 0, preserveTabOrderElement, anchorPortalNode);
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [preserveTabOrderElement, element] });
}, [
portalNode,
context,
portal,
props.id,
preserveTabOrder,
anchorPortalNode
]);
props = {
...props,
ref: refProp
};
return props;
});
var Portal = _LZ6L3ECGcjs.forwardRef.call(void 0, function Portal2(props) {
return _LZ6L3ECGcjs.createElement.call(void 0, TagName, usePortal(props));
});
exports.PortalContext = PortalContext; exports.usePortal = usePortal; exports.Portal = Portal;