@use-pico/cls
Version:
Type-safe, composable styling system for React, Vue, Svelte, and vanilla JS
139 lines (126 loc) • 2.97 kB
text/typescript
import type { Contract } from "../types/Contract";
import type { ContractBuilder } from "../types/ContractBuilder";
import type { Slot } from "../types/Slot";
import type { Token } from "../types/Token";
import type { Variant } from "../types/Variant";
import { dedupeConcat } from "../utils/dedupe";
import { mergeVariants } from "../utils/mergeVariants";
import { definition } from "./definition";
/**
* Creates a contract builder with the given state
*/
function builder<
const TToken extends Token.Type,
const TSlot extends Slot.Type,
const TVariant extends Variant.Type,
const TUse extends Contract.Any | unknown = unknown,
>(
state: ContractBuilder.State<TToken, TSlot, TVariant, TUse>,
): ContractBuilder.Builder<TToken, TSlot, TVariant, TUse> {
return {
tokens(tokens) {
return builder({
...state,
tokens: dedupeConcat(state.tokens, tokens),
});
},
token(token) {
return builder({
...state,
tokens: dedupeConcat(state.tokens, [
token,
] as const),
});
},
slots(slots) {
return builder({
...state,
slot: dedupeConcat(state.slot, slots),
});
},
slot(slot) {
return builder({
...state,
slot: dedupeConcat(state.slot, [
slot,
] as const),
});
},
variants(variants) {
return builder({
...state,
variant: mergeVariants(state.variant, variants),
});
},
variant(name, values) {
return builder({
...state,
variant: mergeVariants(state.variant, {
[name]: values,
} as Record<typeof name, typeof values>),
});
},
bool(name) {
return builder({
...state,
variant: mergeVariants(state.variant, {
[name]: [
"bool",
],
} as Record<
typeof name,
[
"bool",
]
>),
});
},
build() {
const { use, ...contract } = state;
return {
...contract,
/**
* Important piece - this will enable inheritance.
*/
"~use": use,
/**
* Definition - not yet
*/
"~definition": undefined,
} satisfies Contract.Type<TToken, TSlot, TVariant, TUse>;
},
def() {
return definition(this.build(), state.use);
},
};
}
/**
* Creates a new contract builder instance.
* Provides a fluent API for building contracts with proper type accumulation.
*
* @example
* ```typescript
* const myContract = contract()
* .tokens(["color.primary", "color.secondary"])
* .slots(["root", "label"])
* .variant("size", ["sm", "md", "lg"])
* .build();
* ```
*/
export function contract(): Omit<
ContractBuilder.Builder<readonly [], readonly [], {}, unknown>,
"build"
>;
export function contract<const TUse extends Contract.Any>(
use: TUse,
): ContractBuilder.Builder<readonly [], readonly [], {}, TUse>;
export function contract<const TUse extends Contract.Any | unknown = unknown>(
use?: TUse,
): ContractBuilder.Builder<readonly [], readonly [], {}, TUse> {
return builder({
tokens: [],
slot: [],
variant: {},
use,
});
}