@stratakit/foundations
Version:
Foundational pieces of StrataKit
202 lines (201 loc) • 6.35 kB
JavaScript
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { PortalContext } from "@ariakit/react/portal";
import { Role } from "@ariakit/react/role";
import cx from "classnames";
import componentsCss from "./~components.css.js";
import { useLayoutEffect, useMergedRefs } from "./~hooks.js";
import foundationsCss from "./~styles.css.js";
import {
forwardRef,
getOwnerDocument,
getWindow,
identity,
isDocument
} from "./~utils.js";
import {
HtmlSanitizerContext,
RootNodeContext,
spriteSheetId,
useRootNode
} from "./Root.internal.js";
import { loadStyles } from "./styles.internal.js";
const css = foundationsCss + componentsCss;
const stack = new Error()?.stack?.split("Error")?.at(-1)?.trim() || "";
const Root = forwardRef((props, forwardedRef) => {
throwIfNotSingleton();
const {
children,
synchronizeColorScheme = false,
unstable_htmlSanitizer = identity,
...rest
} = props;
const [portalContainer, setPortalContainer] = React.useState(null);
return /* @__PURE__ */ jsxs(RootInternal, { ...rest, ref: forwardedRef, children: [
/* @__PURE__ */ jsx(Styles, {}),
/* @__PURE__ */ jsx(Fonts, {}),
/* @__PURE__ */ jsx(InlineSpriteSheet, {}),
synchronizeColorScheme ? /* @__PURE__ */ jsx(SynchronizeColorScheme, { colorScheme: props.colorScheme }) : null,
/* @__PURE__ */ jsx(
PortalContainer,
{
colorScheme: props.colorScheme,
density: props.density,
ref: setPortalContainer
}
),
/* @__PURE__ */ jsx(PortalContext.Provider, { value: portalContainer, children: /* @__PURE__ */ jsx(HtmlSanitizerContext.Provider, { value: unstable_htmlSanitizer, children }) })
] });
});
DEV: Root.displayName = "Root";
const RootInternal = forwardRef(
(props, forwardedRef) => {
const { children, colorScheme, density, ...rest } = props;
const [rootNode, setRootNode] = React.useState(null);
const findRootNodeFromRef = React.useCallback((element) => {
if (!element) return;
const rootNode2 = element.getRootNode();
if (!isDocument(rootNode2) && !isShadow(rootNode2)) return;
setRootNode(rootNode2);
}, []);
return /* @__PURE__ */ jsx(
Role,
{
...rest,
className: cx("\u{1F95D}-root", props.className),
"data-kiwi-theme": colorScheme,
"data-kiwi-density": density,
ref: useMergedRefs(forwardedRef, findRootNodeFromRef),
children: /* @__PURE__ */ jsx(RootNodeContext.Provider, { value: rootNode, children })
}
);
}
);
function SynchronizeColorScheme({
colorScheme
}) {
const rootNode = useRootNode();
useLayoutEffect(() => {
if (!rootNode) return;
if (isDocument(rootNode)) {
rootNode.documentElement.dataset.colorScheme = colorScheme;
const meta = rootNode.querySelector("meta[name='color-scheme']");
if (meta) meta.content = colorScheme;
} else if (isShadow(rootNode)) {
rootNode.host.dataset.colorScheme = colorScheme;
}
}, [rootNode, colorScheme]);
return null;
}
const PortalContainer = forwardRef((props, forwardedRef) => {
const rootNode = useRootNode();
if (!rootNode) return null;
const destination = isDocument(rootNode) ? rootNode.body : rootNode;
if (!destination) return null;
return ReactDOM.createPortal(
/* @__PURE__ */ jsx(
"div",
{
className: "\u{1F95D}-root",
"data-kiwi-theme": props.colorScheme,
"data-kiwi-density": props.density,
style: { display: "contents" },
ref: forwardedRef
}
),
destination
);
});
function Styles() {
const rootNode = useRootNode();
useLayoutEffect(() => {
if (!rootNode) return;
const { cleanup } = loadStyles(rootNode, { css });
return cleanup;
}, [rootNode]);
return null;
}
function Fonts() {
const rootNode = useRootNode();
useLayoutEffect(() => {
if (!rootNode) return;
loadFonts(rootNode);
}, [rootNode]);
return null;
}
function InlineSpriteSheet() {
const rootNode = useRootNode();
React.useEffect(
function maybeCreateSpriteSheet() {
const ownerDocument = getOwnerDocument(rootNode);
if (!ownerDocument) return;
const spriteSheet = ownerDocument?.getElementById(spriteSheetId);
if (spriteSheet) return;
const svg = ownerDocument.createElementNS(
"http://www.w3.org/2000/svg",
"svg"
);
svg.id = spriteSheetId;
svg.style.display = "none";
Object.defineProperty(svg, Symbol.for("\u{1F95D}"), {
value: { icons: /* @__PURE__ */ new Map() }
// Map of icon URLs that have already been inlined.
});
ownerDocument.body.appendChild(svg);
return () => {
if (svg.isConnected) {
ownerDocument.body.removeChild(svg);
}
};
},
[rootNode]
);
return null;
}
function loadFonts(rootNode) {
const ownerWindow = getWindow(rootNode);
if (!ownerWindow?.document?.fonts || Array.from(ownerWindow.document.fonts).some(
(font) => font.family === "InterVariable"
)) {
return;
}
const interStyles = {
normal: "https://rsms.me/inter/font-files/InterVariable.woff2?v=4.1",
italic: "https://rsms.me/inter/font-files/InterVariable-Italic.woff2?v=4.1"
};
for (const [style, url] of Object.entries(interStyles)) {
const font = new ownerWindow.FontFace(
"InterVariable",
`url(${url}) format("woff2")`,
{
display: "swap",
weight: "100 900",
style
}
);
ownerWindow.document.fonts.add(font);
}
}
function throwIfNotSingleton() {
const symbol = Symbol.for("@stratakit/foundations");
const _globalThis = globalThis;
_globalThis[symbol] ??= { versions: /* @__PURE__ */ new Set() };
if (stack) _globalThis[symbol].versions?.add(stack);
if ((_globalThis[symbol].versions?.size || 0) > 1) {
console.table(
Array.from(_globalThis[symbol].versions || []).map((stack2) => ({
"@stratakit/foundations location": stack2
}))
);
throw new Error(
`Multiple instances of @stratakit/foundations detected. This can lead to unexpected behavior.`
);
}
}
function isShadow(node) {
return node instanceof ShadowRoot || node?.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !!node?.host;
}
export {
Root
};