Add style object support

This commit is contained in:
Alex
2024-07-02 21:09:10 -04:00
parent 835c5b7810
commit 398f2a7c69
17 changed files with 896 additions and 435 deletions

View File

@ -7,11 +7,15 @@ import { type ClassNameCollector, babelTailwind } from "./babel-tailwind";
import { esbuildPlugin } from "./esbuild-postcss";
import { vitePlugin } from "./vite-plugin";
import { type StyleMap, createPostCSS } from "./shared";
import { convertCssToJS } from "./css-to-js";
export { babelPlugin } from "./esbuild-babel";
export { createPostCSS } from "./shared";
type GetClassName = (className: string) => string;
export type BuildStyleFile = (
path: string
) => Promise<readonly ["css", string] | readonly ["js", string]>;
interface RecursiveStringObject {
[modifier: string]: string | RecursiveStringObject;
@ -20,7 +24,7 @@ interface RecursiveStringObject {
export type CSSAttributeValue = string | (string | RecursiveStringObject)[];
/**
* Tagged template macro function for Tailwind classes
* Tagged template macro function combining Tailwind classes
* @example "tw" => tw`p-2 text-center`
*/
export interface TailwindFunction {
@ -28,6 +32,15 @@ export interface TailwindFunction {
(...args: (string | RecursiveStringObject)[]): string;
}
/**
* Tagged template macro function compiling Tailwind styles
* @example "tws" => tws`p-2 text-center` // { padding: 2, textAlign: "center" }
*/
export interface TailwindStyleFunction<Output = React.CSSProperties> {
(strings: TemplateStringsArray): Output;
(...args: (string | RecursiveStringObject)[]): Output;
}
export interface TailwindPluginOptions {
/**
* Tailwind CSS configuration
@ -62,14 +75,21 @@ export interface TailwindPluginOptions {
jsxAttributeAction?: "delete" | "preserve" | ["rename", string];
/**
* Template macro function to use for Tailwind classes
* @default "tw"
* Template macro function to combine Tailwind classes
* @example
* declare const tw: TailwindFunction;
* "tw" => tw`p-2 text-center`
*/
macroFunction?: string | undefined;
/**
* Template macro function to compile Tailwind classes
* @example
* declare const tws: TailwindStyleFunction;
* "tws" => tws`p-2 text-center` // { padding: 2, textAlign: "center" }
*/
macroStyleFunction?: string | undefined;
/**
* The prefix to use for the generated class names.
* @default className => `tw-${hash(className)}`
@ -108,6 +128,7 @@ export type ResolveTailwindOptions = SetRequired<
| "styleMap"
| "tailwindConfig"
| "macroFunction"
| "macroStyleFunction"
>;
/**
@ -140,6 +161,7 @@ export function getTailwindPlugins(options: TailwindPluginOptions) {
postCSSPlugins: [],
styleMap: new Map(),
macroFunction: undefined,
macroStyleFunction: undefined,
tailwindConfig: {},
...options,
};
@ -149,12 +171,27 @@ export function getTailwindPlugins(options: TailwindPluginOptions) {
const { styleMap } = resolvedOptions;
const compile = options.compile ?? memoize(getCompiler());
const buildStyleFile: BuildStyleFile = async path => {
const styles = styleMap.get(path)!;
const compiled = await compile(
styles.map(({ className, key }) => `.${key} {\n @apply ${className}\n}`).join("\n")
);
if (path.endsWith(".css")) {
return ["css", compiled] as const;
} else if (path.endsWith(".js")) {
const js = convertCssToJS(compiled, x => x.slice(1));
return ["js", js] as const;
} else {
throw new Error("Unknown file extension");
}
};
return {
compile,
babel: (onCollect?: ClassNameCollector) => babelTailwind(resolvedOptions, onCollect),
esbuild: () => esbuildPlugin(styleMap, compile),
esbuild: () => esbuildPlugin({ styleMap, compile, buildStyleFile }),
/** Requires `options.vite` to be `true`. */
vite: () => vitePlugin(styleMap, compile),
vite: () => vitePlugin({ styleMap, compile, buildStyleFile }),
styleMap,
options,
getCompiler,