UNPKG

unplugin-jade-garden

Version:

Build tool plugin for creating CSS with Jade Garden

348 lines (344 loc) 10.8 kB
import { ClassValue as ClassValue$1 } from 'clsx'; /** * Represents the `class` and `className` props for `cva` and `sva`. * Ensures that only one of `class` or `className` is present. */ type ClassProp = { class?: ClassValue; className?: never; } | { class?: never; className?: ClassValue; }; /** * **This is the `ClassValue` type from [clsx](https://github.com/lukeed/clsx/tree/master)**. * - Represents a value that can be used as a class name. * - It can be a `string`, `number`, `bigint`, `null`, `boolean`, `undefined`, an array of ClassValue, or a Record with values of `any`. */ type ClassValue = ClassValue$1; /** * Represents a function that merges class names. * * @param {...ClassValue[]} classes - An array of class names to merge. * @returns {string} The merged class name string. */ type MergeClassFn = (...classes: ClassValue[]) => string; /** * Represents a dictionary where keys are strings and values are ClassValue. */ type RecordClassValue = Record<string, ClassValue>; /** * Converts "true" or "false" string literals to boolean types. * Otherwise, returns the original type. * * @template T - The type to convert. * @returns {T extends "true" | "false" ? boolean : T} The converted type. */ type StringToBoolean<T> = T extends "true" | "false" ? boolean : T; /** * Represents the variant configurations for `cva`. * Each variant is a record of class names, keyed by variant values. * * @example * ```ts * { * size: { * small: "text-sm py-1 px-2", * medium: "text-base py-2 px-4", * }, * intent: { * primary: "bg-blue-500 text-white", * secondary: "bg-gray-200 text-gray-800", * } * } * ``` */ type Variant = Record<string, RecordClassValue>; /** * Represents the schema for variant props in `cva`. * Each variant prop is typed as a StringToBoolean of the corresponding variant value keys. * * @template V - The type of variants. * @example * ```ts * type ButtonVariants = CVAVariants<{ * size: { small: string; medium: string }; * intent: { primary: string; secondary: string }; * }>; * // ButtonVariants = { size?: "small" | "medium"; intent?: "primary" | "secondary" }; * ``` */ type CVAVariants<V extends Variant> = { [K in keyof V]?: StringToBoolean<keyof V[K]>; }; /** * Represents the configuration object for the `cva` function. * * @template V - The type of variants. * @property {string=} name - Optional component name. * @property {ClassValue=} base - The base class name for the component. * @property {V=} variants - Variants allow you to create multiple versions of the same component. * @property {(V extends Variant ? (CVAVariants<V> | { [K in keyof V]?: StringToBoolean<keyof V[K]> | StringToBoolean<keyof V[K]>[]; }) & ClassProp : ClassProp)[]=} compoundVariants - Compound variants allow you to apply classes to multiple variants at once. * @property {CVAVariants<V>=} defaultVariants - Default variants allow you to set default variants for a component. * * @example * ```ts * const buttonConfig: CVAConfig<{ * size: { small: string; medium: string }; * intent: { primary: string; secondary: string }; * }> = { * base: "rounded-md", * variants: { * size: { * small: "text-sm", * medium: "text-base" * }, * intent: { * primary: "bg-blue-500", * secondary: "bg-gray-200" * } * }, * compoundVariants: [ * { * size: "small", * intent: "primary", * class: "font-bold" * } * ], * defaultVariants: { * size: "medium", * intent: "primary" * } * }; * ``` */ type CVAConfig<V extends Variant> = { /** * The name of the cva component. */ name?: string; /** * The base class name for the component. */ base?: ClassValue; /** * Variants allow you to create multiple versions of the same component. */ variants?: V; /** * Compound variants allow you to apply classes to multiple variants at once. */ compoundVariants?: (V extends Variant ? (CVAVariants<V> | { [K in keyof V]?: StringToBoolean<keyof V[K]> | StringToBoolean<keyof V[K]>[]; }) & ClassProp : ClassProp)[]; /** * Default variants allow you to set default variants for a component. */ defaultVariants?: CVAVariants<V>; }; /** * Represents the class values for slots, where keys are slot names and values are class names. * * @template RCV - The type of record class values. * @example * ```ts * type ButtonSlots = SlotsClassValue<{ root: string; item: string }>; * // ButtonSlots = { root?: ClassValue; item?: ClassValue }; * ``` */ type SlotsClassValue<RCV extends RecordClassValue> = { [K in keyof RCV]?: ClassValue; }; /** * Represents the default variants for a component. * * @template RCV - The type of record class values. * @example * ```ts * { * size: { * small: { * root: "text-sm" * }, * medium: { * root: "text-base" * } * } * } * ``` */ type DefaultVariants<RCV extends RecordClassValue> = { [key: string]: { [key: string]: SlotsClassValue<RCV>; }; }; /** * Represents the variants for a component. * * @template RCV - The type of record class values. * @template V - The type of variants. * @example * ```ts * type ButtonVariants = Variants< * { * root: string; * item: string; * }, * { * size: { * small: { * root: string; * }; * medium: { * root: string; * }; * }; * } * >; * // type ButtonVariants = * // | { size?: { small?: { root?: ClassValue }; medium?: { root?: ClassValue } } } * // | { size: { small: { root: ClassValue }; medium: { root: ClassValue } } }; * ``` */ type Variants<RCV extends RecordClassValue, V extends DefaultVariants<RCV> = DefaultVariants<RCV>> = { [K in keyof V]?: { [K2 in keyof V[K]]?: SlotsClassValue<RCV>; }; } | DefaultVariants<RCV>; /** * Reusable type for compound styles that apply based on multiple variant combinations. * * @template RCV - The type of record class values. * @template V - The type of variants. * @example * ```ts * type ButtonCompound = CompoundBase< * { root: string; item: string }, * { size: { small: { root: string }; medium: { root: string } } } * >; * // ButtonCompound = { size?: "small" | "medium" | ("small" | "medium")[] }; * ``` */ type CompoundBase<RCV extends RecordClassValue, V extends Variants<RCV>> = { [K in keyof V]?: StringToBoolean<keyof V[K]> | StringToBoolean<keyof V[K]>[]; }; /** * Represents the props for a component with variants and slots. * * @template RCV - The type of record class values. * @template V - The type of variants. * @example * ```ts * type ButtonProps = SVAVariants< * { root: string; item: string }, * { size: { small: { root: string }; medium: { root: string } } } * >; * // ButtonProps = { size?: "small" | "medium" }; * ``` */ type SVAVariants<RCV extends RecordClassValue, V extends Variants<RCV>> = { [K in keyof V]?: StringToBoolean<keyof V[K]>; }; /** * Represents the configuration object for the `sva` function. * * @template RCV - The type of record class values. * @template V - The type of variants. * @property {string=} name - Optional component name. * @property {S=} slots - Slots allow you to separate a component into multiple parts. * @property {V=} variants - Variants allow you to create multiple versions of the same component. * @property {Array<CompoundBase<RCV, V> & ( { class?: SlotsClassValue<RCV>; className?: never; } | { class?: never; className?: SlotsClassValue<RCV>; } )>=} compoundVariants - Compound variants allow you to apply classes to multiple variants at once. * @property {Array<{ slots: Array<keyof S> } & CompoundBase<RCV, V> & ClassProp>=} compoundSlots - Compound slots allow you to apply classes to multiple slots at once. * @property {SVAVariants<RCV, V>=} defaultVariants - Default variants allow you to set default variants for a component. * * @example * ```ts * const buttonConfig: SVAConfig< * { root: string; item: string }, * { size: { small: { root: string }; medium: { root: string } } } * > = { * slots: { * root: "flex", * item: "px-2 py-1" * }, * variants: { * size: { * small: { * root: "text-sm" * }, * medium: { * root: "text-base" * } * } * }, * compoundVariants: [{ size: "small", class: { root: "font-bold" } }], * compoundSlots: [{ slots: ["root", "item"], class: "rounded" }], * defaultVariants: { * size: "medium" * } * }; * ``` */ type SVAConfig<RCV extends RecordClassValue, V extends Variants<RCV>> = { /** * The name of the sva component. */ name?: string; /** * Slots allow you to separate a component into multiple parts. */ slots?: RCV; /** * Variants allow you to create multiple versions of the same component. */ variants?: V; /** * Compound variants allow you to apply classes to multiple variants at once. */ compoundVariants?: Array<CompoundBase<RCV, V> & ({ class?: SlotsClassValue<RCV>; className?: never; } | { class?: never; className?: SlotsClassValue<RCV>; })>; /** * Compound slots allow you to apply classes to multiple slots at once. */ compoundSlots?: Array<{ slots: Array<keyof RCV>; } & CompoundBase<RCV, V> & ClassProp>; /** * Default variants allow you to set default variants for a component. */ defaultVariants?: SVAVariants<RCV, V>; }; type CVA = CVAConfig<any>; type Options = { /** * The relative path to the main CSS/Tailwind file where the generated `@apply` * directives will be written. This file should typically reside in a * dedicated styling directory (e.g., `css`, `styles`). * * Example: `./styles/components.css` */ entry?: string; /** * An object containing arrays of your `jade-garden` CVA and SVA configurations. * The plugin will process these configurations to generate the corresponding CSS. */ components?: { cva?: CVA[]; sva?: SVA[]; }; /** * An optional custom class merging function. If not provided, the plugin * will use `jade-garden`'s default `cx` utility for merging generated class names. * You might provide this if you are using `tailwind-merge` or a similar utility * to handle class conflicts. */ mergeFn?: MergeClassFn; }; type PluginInstance<T> = (options?: Options | undefined) => T; type SVA = SVAConfig<any, any>; export type { PluginInstance as P };