one
Version:
One is a React framework for web, iOS, and Android apps.
121 lines (118 loc) • 3 kB
JavaScript
import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { VIEW_BASE, domStyle } from "../web/DomView.mjs";
import { jsx } from "react/jsx-runtime";
const hosts = /* @__PURE__ */ new Map();
const portals = [];
function refresh() {
for (let i = 0; i < portals.length; i++) {
const portal = portals[i];
const replaced = portal.name != null && portals.slice(i + 1).some((other) => other.name === portal.name);
if (replaced) {
portal.content.remove();
continue;
}
const host = portal.hostName == null ? null : hosts.get(portal.hostName);
const target = host ?? portal.source;
portal.content.removeAttribute("style");
Object.assign(portal.content.style, host ? {
...VIEW_BASE,
...portal.style,
position: "absolute",
inset: "0",
width: "100%",
height: "100%",
pointerEvents: "none"
} : { display: "contents" });
portal.source.style.position = host ? "absolute" : portal.style.position ?? "relative";
target.appendChild(portal.content);
}
}
function Portal({ hostName, name, children, style, testID, nativeID, accessibilityLabel }) {
const source = useRef(null);
const entry = useRef(null);
const [content, setContent] = useState(null);
useEffect(() => {
if (!source.current) return;
const node = document.createElement("div");
const value = {
hostName: hostName || void 0,
name: name || void 0,
source: source.current,
content: node,
style: domStyle(style)
};
entry.current = value;
portals.push(value);
setContent(node);
refresh();
return () => {
portals.splice(portals.indexOf(value), 1);
node.remove();
entry.current = null;
refresh();
};
}, []);
useEffect(() => {
const value = entry.current;
if (!value) return;
value.hostName = hostName || void 0;
value.name = name || void 0;
value.style = domStyle(style);
refresh();
}, [
hostName,
name,
style
]);
return /* @__PURE__ */ jsx("div", {
ref: source,
"data-testid": testID,
id: nativeID,
"aria-label": accessibilityLabel,
style: {
...VIEW_BASE,
...domStyle(style)
},
children: content ? createPortal(/* @__PURE__ */ jsx("div", {
style: {
display: "contents",
pointerEvents: "auto"
},
children
}), content) : null
});
}
function PortalHost({ name, children, style, testID, nativeID, accessibilityLabel }) {
const ref = useRef(null);
useEffect(() => {
const node = ref.current;
if (!node) return;
hosts.set(name, node);
refresh();
return () => {
if (hosts.get(name) === node) hosts.delete(name);
refresh();
};
}, [name]);
return /* @__PURE__ */ jsx("div", {
ref,
"data-testid": testID,
id: nativeID,
"aria-label": accessibilityLabel,
style: {
...VIEW_BASE,
...domStyle(style),
pointerEvents: "none"
},
children: /* @__PURE__ */ jsx("div", {
style: {
display: "contents",
pointerEvents: "auto"
},
children
})
});
}
export { Portal, PortalHost };
//# sourceMappingURL=Portal.mjs.map