@stratakit/foundations
Version:
Foundational pieces of StrataKit
251 lines (250 loc) • 7.85 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 css from "./~styles.css.js";
import {
forwardRef,
getOwnerDocument,
getWindow,
identity,
isBrowser,
isDocument
} from "./~utils.js";
import {
HtmlSanitizerContext,
RootContext,
RootNodeContext,
spriteSheetId,
useRootNode
} from "./Root.internal.js";
import { loadStyles } from "./styles.internal.js";
const packageName = "@stratakit/foundations";
const key = `${packageName}@${"0.4.9"}`;
const stack = new Error()?.stack?.split("Error")?.at(-1)?.trim() || "";
const versions = /* @__PURE__ */ new Map([[packageName, "0.4.9"]]);
const Root = forwardRef((props, forwardedRef) => {
throwIfNotSingleton();
const {
children,
synchronizeColorScheme = true,
unstable_htmlSanitizer = identity,
portalContainer: portalContainerProp,
...rest
} = props;
return /* @__PURE__ */ jsx(RootInternal, { ...rest, ref: forwardedRef, children: /* @__PURE__ */ jsxs(RootProvider, { children: [
/* @__PURE__ */ jsx(Styles, {}),
/* @__PURE__ */ jsx(Fonts, {}),
/* @__PURE__ */ jsx(InlineSpriteSheet, {}),
synchronizeColorScheme ? /* @__PURE__ */ jsx(SynchronizeColorScheme, { colorScheme: props.colorScheme }) : null,
/* @__PURE__ */ jsx(SynchronizeAccentColor, { accentColor: props.unstable_accentColor }),
/* @__PURE__ */ jsx(HtmlSanitizerContext.Provider, { value: unstable_htmlSanitizer, children: /* @__PURE__ */ jsx(
PortalProvider,
{
colorScheme: props.colorScheme,
unstable_accentColor: props.unstable_accentColor,
density: props.density,
portalContainerProp,
children
}
) })
] }) });
});
const RootProvider = (props) => {
const rootNode = useRootNode();
return /* @__PURE__ */ jsx(RootContext.Provider, { value: { versions, rootNode, loadStyles }, children: props.children });
};
const RootInternal = forwardRef(
(props, forwardedRef) => {
const {
children,
colorScheme,
unstable_accentColor,
density,
rootNode = isBrowser ? document : void 0,
...rest
} = props;
return /* @__PURE__ */ jsx(
Role,
{
...rest,
className: cx("\u{1F95D}Root", props.className),
"data-_sk-color-scheme": colorScheme,
"data-_sk-accent-color": unstable_accentColor,
"data-_sk-density": density,
ref: forwardedRef,
children: /* @__PURE__ */ jsx(RootNodeContext.Provider, { value: rootNode, children })
}
);
}
);
function SynchronizeColorScheme({
colorScheme
}) {
const rootNode = useRootNode();
React.useInsertionEffect(() => {
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;
}
function SynchronizeAccentColor({
accentColor
}) {
const rootNode = useRootNode();
React.useInsertionEffect(() => {
if (!rootNode || !isDocument(rootNode)) return;
if (!accentColor) return;
rootNode.documentElement.dataset._skAccentColor = accentColor;
}, [rootNode, accentColor]);
return null;
}
function PortalProvider(props) {
const [portalContainer, setPortalContainer] = React.useState(null);
return /* @__PURE__ */ jsxs(PortalContext.Provider, { value: portalContainer, children: [
props.children,
/* @__PURE__ */ jsx(
PortalContainer,
{
colorScheme: props.colorScheme,
unstable_accentColor: props.unstable_accentColor,
density: props.density,
ref: setPortalContainer,
render: props.portalContainerProp
}
)
] });
}
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(
Role,
{
render: props.render,
className: "\u{1F95D}Root",
"data-_sk-color-scheme": props.colorScheme,
"data-_sk-accent-color": props.unstable_accentColor,
"data-_sk-density": props.density,
style: { display: "contents" },
ref: forwardedRef
}
),
destination
);
}
);
function Styles() {
const rootNode = useRootNode();
React.useInsertionEffect(
/** Adds `@layer reset` _before_ all other styles to ensure correct layer order. */
function addResetLayer() {
if (!rootNode) return;
const styleElement = document.createElement("style");
(rootNode.head || rootNode).prepend(styleElement);
styleElement.textContent = "@layer reset;";
},
[rootNode]
);
React.useInsertionEffect(() => {
if (!rootNode) return;
const { cleanup } = loadStyles(rootNode, { css, key });
return cleanup;
}, [rootNode]);
return null;
}
function Fonts() {
const rootNode = useRootNode();
React.useInsertionEffect(() => {
if (!rootNode) return;
loadFonts(rootNode);
}, [rootNode]);
return null;
}
function InlineSpriteSheet() {
const rootNode = useRootNode();
React.useInsertionEffect(
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, /* @__PURE__ */ 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 = /* @__PURE__ */ 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
};