From 0a071e94222e760e29aaf958468da839c56d2bdb Mon Sep 17 00:00:00 2001
From: Mayank <9084735+mayank99@users.noreply.github.com>
Date: Tue, 26 Mar 2024 15:33:42 -0400
Subject: [PATCH] add `adoptedStyleSheets` fallback for older safari (#1954)
Slight refactor of ShadowRoot, with the main change being that when adoptedStyleSheets is not supported, an inline : null;
+
+ return shadowRoot ? (
+ ReactDOM.createPortal(
+ <>
+ {fallbackCss}
+ {children}
+ >,
+ shadowRoot,
+ )
+ ) : (
+
);
};
// ----------------------------------------------------------------------------
+/**
+ * Given a ref, this hook will return a shadowRoot attached to its parent element.
+ *
+ * The css will be added to the shadowRoot using `adoptedStyleSheets` (if supported).
+ */
+function useShadowRoot(
+ templateRef: React.RefObject,
+ { css = '' },
+) {
+ const [shadowRoot, setShadowRoot] = React.useState(null);
+ const styleSheet = React.useRef();
+ const latestCss = useLatestRef(css);
+
+ useLayoutEffect(() => {
+ const parent = templateRef.current?.parentElement;
+ if (!parent) {
+ return;
+ }
+
+ if (parent.shadowRoot) {
+ parent.shadowRoot.replaceChildren(); // Remove previous shadowroot content
+ }
+
+ const shadow = parent.shadowRoot || parent.attachShadow({ mode: 'open' });
+
+ if (supportsAdoptedStylesheets) {
+ // create an empty stylesheet and add it to the shadowRoot
+ const currentWindow = shadow.ownerDocument.defaultView || globalThis;
+ styleSheet.current = new currentWindow.CSSStyleSheet();
+ shadow.adoptedStyleSheets = [styleSheet.current];
+
+ // add the CSS immediately to avoid FOUC (one-time)
+ if (latestCss.current) {
+ styleSheet.current.replaceSync(latestCss.current);
+ }
+ }
+
+ queueMicrotask(() => {
+ // Flush the state immediately to ensure layout measurements in parent component are correct
+ ReactDOM.flushSync(() => setShadowRoot(shadow));
+ });
+
+ return () => void setShadowRoot(null);
+ }, [templateRef, latestCss]);
+
+ // Synchronize `css` with contents of the existing stylesheet
+ useLayoutEffect(() => {
+ if (css && supportsAdoptedStylesheets) {
+ styleSheet.current?.replaceSync(css);
+ }
+ }, [css]);
+
+ return shadowRoot;
+}
+
+// ----------------------------------------------------------------------------
+
function useIsFirstRender() {
const [isFirstRender, setIsFirstRender] = React.useState(true);
React.useEffect(() => setIsFirstRender(false), []);