Skip to content

Instantly share code, notes, and snippets.

@dburles
Last active April 27, 2020 02:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dburles/b0ab180decb880c5381ea75ceb8221d0 to your computer and use it in GitHub Desktop.
Save dburles/b0ab180decb880c5381ea75ceb8221d0 to your computer and use it in GitHub Desktop.
import React, { useState, useRef, forwardRef, useEffect } from 'react';
import { createPortal } from 'react-dom';
const useEnsuredForwardedRef = forwardedRef => {
const ensuredRef = useRef(forwardedRef && forwardedRef.current);
useEffect(() => {
if (!forwardedRef) {
return;
}
forwardedRef.current = ensuredRef.current;
}, [forwardedRef]);
return ensuredRef;
};
const ShadowContent = ({ shadow, children }) => {
return createPortal(children, shadow);
};
const MysticalCSSProp = forwardRef(function MysticalCSSProp(
{ css, children },
ref,
) {
const changed = JSON.stringify(css);
const node = useEnsuredForwardedRef(ref);
const [shadow, setShadow] = useState(null);
useEffect(() => {
if (node.current) {
const shadow =
node.current.shadowRoot || node.current.attachShadow({ mode: 'open' });
setShadow(shadow);
const sheet = new CSSStyleSheet();
sheet.replaceSync(`${children.type} {}`);
Object.keys(css).forEach(key => {
sheet.cssRules.item(0).style[key] = css[key];
});
shadow.adoptedStyleSheets = [sheet];
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [changed, node, ref]);
return (
<div ref={node}>
{shadow && <ShadowContent shadow={shadow}>{children}</ShadowContent>}
</div>
);
});
const jsx = (type, props, ...children) => {
if (typeof type === 'string') {
const { css, ...rest } = props || {};
const element = React.createElement(type, rest, ...children);
return css
? React.createElement(MysticalCSSProp, { css }, element)
: element;
}
return React.createElement(type, props, ...children);
};
export default jsx;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment