unplugin-jade-garden
Version:
Build tool plugin for creating CSS with Jade Garden
348 lines (344 loc) • 10.8 kB
text/typescript
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 };