diff --git a/src/hooks/useStyleSheet.ts b/src/hooks/useStyleSheet.ts index 9a8088c9..8d966f35 100644 --- a/src/hooks/useStyleSheet.ts +++ b/src/hooks/useStyleSheet.ts @@ -1,30 +1,38 @@ +/* eslint-disable no-extra-boolean-cast */ import { RefObject } from "react"; - import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect"; +import { getOwnerDocument } from "../utils/ownerDocument"; import { getNonce } from "../utils/nonce"; // Bundler is configured to load this as a processed minified CSS-string import styles from "../css/styles.css"; -const styleElementMap: Map = new Map(); +const styleElementMap: Map = new Map(); /** * Injects CSS code into the document's */ export const useStyleSheet = (nodeRef: RefObject): void => { useIsomorphicLayoutEffect(() => { - const parentDocument = nodeRef.current ? nodeRef.current.ownerDocument : document; - - if (typeof parentDocument !== "undefined" && !styleElementMap.has(parentDocument)) { - const styleElement = parentDocument.createElement("style"); + const ownerDocument = getOwnerDocument(nodeRef.current); + const parentDocument = ownerDocument || document; + if ( + parentDocument && + typeof parentDocument !== "undefined" && + !styleElementMap.has(parentDocument) + ) { + const styleElement = document.createElement("style"); styleElement.innerHTML = styles; styleElementMap.set(parentDocument, styleElement); // Conform to CSP rules by setting `nonce` attribute to the inline styles const nonce = getNonce(); if (nonce) styleElement.setAttribute("nonce", nonce); - - parentDocument.head.appendChild(styleElement); + if (parentDocument instanceof ShadowRoot) { + parentDocument.appendChild(styleElement); + } else { + parentDocument.head.appendChild(styleElement); + } } }, []); }; diff --git a/src/utils/ownerDocument.ts b/src/utils/ownerDocument.ts new file mode 100644 index 00000000..a5339812 --- /dev/null +++ b/src/utils/ownerDocument.ts @@ -0,0 +1,11 @@ +export const getOwnerDocument = (node: HTMLElement | null): ShadowRoot | Document | null => { + let parent = node && node.parentNode; + const ownerDocument = node && node.ownerDocument; + while (parent) { + if (parent instanceof ShadowRoot) { + return parent; + } + parent = parent.parentNode; + } + return ownerDocument; +};