Skip to content

Instantly share code, notes, and snippets.

@g4rcez
Last active October 21, 2020 03:41
Show Gist options
  • Save g4rcez/160005a0d392d25b3150f95b51e926b7 to your computer and use it in GitHub Desktop.
Save g4rcez/160005a0d392d25b3150f95b51e926b7 to your computer and use it in GitHub Desktop.
Emulate zoaded-components.tsx for div component
import React, { useLayoutEffect, useMemo } from "react";
import { useClassNames } from "styleguide";
const AD_REPLACER_R = /(a)(d)/gi;
const charsLength = 52;
const getAlphabeticChar = (code: number) => String.fromCharCode(code + (code > 25 ? 39 : 97));
function generateAlphabeticName(code: number) {
let name = "";
let x;
/* get a char and divide by alphabet-length */
for (x = Math.abs(code); x > charsLength; x = (x / charsLength) | 0) {
name = getAlphabeticChar(x % charsLength) + name;
}
return (getAlphabeticChar(x % charsLength) + name).replace(AD_REPLACER_R, "$1-$2");
}
type Div = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
type StyledArgs<T> = ((arg: Div & T) => string | number) | string | number;
function StyledDiv<T = unknown>([first, ...placeholders]: TemplateStringsArray, ...a: StyledArgs<T>[]) {
return ({ children, ...props }: Div & T) => {
/* eslint-disable */
const className = useMemo(() => generateAlphabeticName(placeholders.length ** 100 * first.length), []);
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} }`;
document.head.insertBefore(sheet, document.head.firstElementChild);
}, [str]);
const classNames = useClassNames([props.className], props.className, className);
const computedProps = useMemo(() => {
const div = document.createElement("div");
const newProps = {};
for (const prop in div) {
if (prop in props) {
newProps[prop] = props[prop];
}
}
return newProps;
}, [props]);
return React.createElement("div", { ...computedProps, className: classNames }, children);
};
}
const opacity = 1;
const Div = StyledDiv<{ bg: string; padding: number }>`
color: green;
background-color: ${(props) => props.bg};
padding: ${(props) => props.padding}rem;
opacity: ${opacity};
width: 500px;
`;
const App = () => {
return (
<Div bg="red" padding={5}>
OK
</Div>
);
};
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment