UNPKG

@stratakit/foundations

Version:

Foundational pieces of StrataKit

251 lines (250 loc) 7.85 kB
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 };