Skip to content

Instantly share code, notes, and snippets.

@g4rcez
Created October 21, 2020 12:50
Show Gist options
  • Save g4rcez/3a6cee259569b101e9838e82686381ed to your computer and use it in GitHub Desktop.
Save g4rcez/3a6cee259569b101e9838e82686381ed to your computer and use it in GitHub Desktop.
import React, { useLayoutEffect, useMemo, useState } from "react";
import { useClassNames } from "styleguide";
type Html = React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
type StyledArgs<E, T> = ((args: E & T) => string | number) | string | number;
function Styled<ExtraProps = unknown, Element = Html>(tag: string) {
return ([first, ...placeholders]: TemplateStringsArray, ...a: StyledArgs<Element, ExtraProps>[]) => {
return ({ children, ...props }: Html & ExtraProps) => {
/* eslint-disable */
const className = useMemo(() => `${tag}-${Date.now()}`, []);
const str = useMemo(() => {
const final = placeholders.reduce((acc, el, i) => {
const curr = a[i];
if (typeof curr === "function") {
return acc + curr(props as never) + el;
}
return acc + a[i] + el;
}, first);
return final.trim();
}, [props]);
useLayoutEffect(() => {
const sheet = document.createElement("style");
sheet.innerHTML = `.${className} { ${str} }`;
sheet.id = className;
const el = document.getElementById(className);
if (!el) {
document.head.insertBefore(sheet, document.head.firstElementChild);
return;
}
el?.replaceWith(sheet);
}, [str]);
const classNames = useClassNames([props.className, str], props.className, className);
const computedProps = useMemo(() => {
const div = document.createElement(tag);
const newProps = {};
for (const prop in div) {
if (prop in props) {
newProps[prop] = props[prop];
}
}
div.remove();
return newProps;
}, [props, str]);
return React.createElement(tag, { ...computedProps, className: classNames }, children);
};
};
}
type DIV = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
Styled.div = <T,>(
[first, ...placeholders]: TemplateStringsArray,
...a: StyledArgs<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, T>[]
) => Styled<T, DIV>("div")([first, ...placeholders] as any, ...(a as any));
type GridProps = { gap: number; rows: number };
const GridRow = Styled.div<GridProps>`
display: grid;
grid-template-rows: repeat(${(props) => props.rows}, minmax(0, 1fr));
grid-auto-flow: column dense;
grid-gap: ${(props) => props.gap}rem;
gap: ${(props) => props.gap}rem;
`;
const App = () => {
const [zero, setZero] = useState(0);
return (
<GridRow gap={zero} rows={4}>
<button onClick={() => setZero((p) => p + 1)}>Add + {zero}</button>
<button onClick={() => setZero((p) => p + 1)}>Add + {zero}</button>
<button onClick={() => setZero((p) => p + 1)}>Add + {zero}</button>
<button onClick={() => setZero((p) => p + 1)}>Add + {zero}</button>
<button onClick={() => setZero((p) => p + 1)}>Add + {zero}</button>
{/* <button onClick={() => setZero((p) => p + 1)}>Add + {zero}</button> */}
</GridRow>
);
};
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment