tiwi
Version:
React library to create components with Tailwind styles baked in.
253 lines (252 loc) • 4.51 kB
JavaScript
import { forwardRef, useMemo } from "react";
import { twMerge } from "tailwind-merge";
//#region src/elements.ts
const allIntrinsicElements = [
"a",
"abbr",
"address",
"area",
"article",
"aside",
"audio",
"b",
"base",
"bdi",
"bdo",
"big",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"center",
"cite",
"code",
"col",
"colgroup",
"data",
"datalist",
"dd",
"del",
"details",
"dfn",
"dialog",
"div",
"dl",
"dt",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"iframe",
"img",
"input",
"ins",
"kbd",
"keygen",
"label",
"legend",
"li",
"link",
"main",
"map",
"mark",
"menu",
"menuitem",
"meta",
"meter",
"nav",
"noindex",
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"picture",
"pre",
"progress",
"q",
"rp",
"rt",
"ruby",
"s",
"samp",
"search",
"slot",
"script",
"section",
"select",
"small",
"source",
"span",
"strong",
"style",
"sub",
"summary",
"sup",
"table",
"template",
"tbody",
"td",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"u",
"ul",
"var",
"video",
"wbr",
"webview",
"svg",
"animate",
"animateMotion",
"animateTransform",
"circle",
"clipPath",
"defs",
"desc",
"ellipse",
"feBlend",
"feColorMatrix",
"feComponentTransfer",
"feComposite",
"feConvolveMatrix",
"feDiffuseLighting",
"feDisplacementMap",
"feDistantLight",
"feDropShadow",
"feFlood",
"feFuncA",
"feFuncB",
"feFuncG",
"feFuncR",
"feGaussianBlur",
"feImage",
"feMerge",
"feMergeNode",
"feMorphology",
"feOffset",
"fePointLight",
"feSpecularLighting",
"feSpotLight",
"feTile",
"feTurbulence",
"filter",
"foreignObject",
"g",
"image",
"line",
"linearGradient",
"marker",
"mask",
"metadata",
"mpath",
"path",
"pattern",
"polygon",
"polyline",
"radialGradient",
"rect",
"set",
"stop",
"switch",
"symbol",
"text",
"textPath",
"tspan",
"use",
"view"
];
//#endregion
//#region src/types.ts
const tiwiComponentSymbol = Symbol("TiwiComponent");
//#endregion
//#region src/tiwi.ts
function variantsToArray(variants) {
if (!variants) return [];
if (typeof variants === "string") return [variants];
if (Array.isArray(variants)) return variants.filter(isString);
return Object.keys(variants).filter((k) => variants[k] === true);
}
function isTiwiComponent(Element) {
return Element && Element[tiwiComponentSymbol] === true;
}
function isString(value) {
return typeof value === "string";
}
function buildTiwiBase(createElement) {
return (Element) => {
return (classNames, ...variantDefinitions) => {
const AnyElement = Element;
const isTiwi = isTiwiComponent(Element);
const component = forwardRef((props, ref) => {
const { className, variants, ...otherProps } = props;
const flatVariants = variantsToArray(variants);
const mergedClassName = useMemo(() => {
return twMerge([...classNames.reduce((list, current, index) => {
const variantDefinition = variantDefinitions[index - 1];
if (variantDefinition) Object.keys(variantDefinition).filter((v) => flatVariants.includes(v)).forEach((v) => {
const variantValue = variantDefinition[v];
if (!variantValue) return;
list.push(variantValue);
});
list.push(current);
return list;
}, []), className]) || void 0;
}, [className, flatVariants]);
if (isTiwi) return createElement(AnyElement, {
...otherProps,
ref,
className: mergedClassName,
variants
});
return createElement(AnyElement, {
...otherProps,
ref,
className: mergedClassName
});
});
component[tiwiComponentSymbol] = true;
component.displayName = (() => {
if (typeof Element === "string") return component.displayName = `tiwi.${Element}`;
return component.displayName = `tiwi(${Element.displayName || Element.name || ""})`;
})();
return component;
};
};
}
function buildTiwi(createElement) {
const tiwiBase = buildTiwiBase(createElement);
if (typeof navigator === "object" && navigator.product === "ReactNative") return tiwiBase;
const intrinsicElementsFunctions = allIntrinsicElements.reduce((result, DomElement) => {
result[DomElement] = tiwiBase(DomElement);
return result;
}, {});
return Object.assign(tiwiBase, intrinsicElementsFunctions);
}
//#endregion
export { buildTiwiBase as n, tiwiComponentSymbol as r, buildTiwi as t };