UNPKG

@use-pico/cls

Version:

Type-safe, composable styling system for React, Vue, Svelte, and vanilla JS

65 lines (58 loc) 1.92 kB
import type { Cls } from "../types/Cls"; import type { Contract } from "../types/Contract"; import type { Definition } from "../types/Definition"; import type { Slot } from "../types/Slot"; import type { Token } from "../types/Token"; import type { Tweak } from "../types/Tweak"; import type { Variant } from "../types/Variant"; // Standalone function to compute variants export function withVariants< const TToken extends Token.Type, const TSlot extends Slot.Type, const TVariant extends Variant.Type, const TContract extends Contract.Type<TToken, TSlot, TVariant, any>, >( tweak: Tweak.Type<TContract> | undefined, { contract, definition, }: Pick<Cls.Type<TContract>, "contract" | "definition">, ): Variant.VariantOf<TContract> { // Build inheritance chain (base -> child order) const layers: { contract: Contract.Type<Token.Type, Slot.Type, Variant.Type>; definition: Definition.Type<any>; }[] = []; let current: | Contract.Type<Token.Type, Slot.Type, Variant.Type> | undefined = contract; let currentDef: | Definition.Type<TContract> | Definition.Type<Contract.Type<Token.Type, Slot.Type, Variant.Type>> | undefined = definition; while (current && currentDef) { layers.unshift({ contract: current, definition: currentDef, }); current = current["~use"] as | Contract.Type<Token.Type, Slot.Type, Variant.Type> | undefined; currentDef = current?.["~definition"] as | Definition.Type< Contract.Type<Token.Type, Slot.Type, Variant.Type> > | undefined; } // Merge defaults from ALL layers in inheritance order const defaultVariant = {} as Variant.VariantOf<TContract>; // Process layers in inheritance order (base first, child last) for (const { definition } of layers) { // Merge defaults (child overrides base) Object.assign(defaultVariant, definition.defaults); } return { ...defaultVariant, ...tweak?.variant, } as const; }