UNPKG

@pandabox/define-recipe

Version:

End-to-end type-safe theming for PandaCSS

69 lines (63 loc) 4.73 kB
import { RecipeVariantRecord, RecipeConfig, Pretty, RecipeCompoundVariant, RecipeCompoundSelection, RecipeSelection, DistributiveOmit, SlotRecipeVariantRecord, SlotRecipeConfig } from '@pandacss/types'; export { RecipeCompoundSelection, RecipeCompoundVariant, RecipeConfig, RecipeSelection, RecipeVariantRecord, SlotRecipeConfig, SlotRecipeVariantRecord } from '@pandacss/types'; type Pick_<T, K> = Pick<T, Extract<keyof T, K>>; type DistributivePick<T, K> = T extends unknown ? keyof Pick_<T, K> extends never ? never : { [P in keyof Pick_<T, K>]: Pick_<T, K>[P]; } : never; interface RecipeBuilder<T extends RecipeVariantRecord> extends RecipeConfig<T> { extend: <TVariants extends RecipeVariantRecord>(variants: TVariants) => RecipeBuilder<Pretty<T & TVariants>>; merge: <TVariants extends RecipeVariantRecord, MergedVariants extends Pretty<TVariants & T> = Pretty<TVariants & T>>(extension: Partial<Omit<RecipeConfig<any>, 'variants' | 'compoundVariants' | 'defaultVariants'>> & { variants?: TVariants; compoundVariants?: Array<Pretty<RecipeCompoundVariant<RecipeCompoundSelection<MergedVariants>>>>; defaultVariants?: RecipeSelection<MergedVariants>; }) => RecipeBuilder<MergedVariants>; pick: <TKeys extends keyof T>(...keys: TKeys[]) => RecipeBuilder<DistributivePick<T, TKeys>>; omit: <TKeys extends keyof T>(...keys: TKeys[]) => RecipeBuilder<DistributiveOmit<T, TKeys>>; cast: () => RecipeConfig<RecipeVariantRecord>; } type PickSlots<S extends string, T extends SlotRecipeVariantRecord<S>, TKeys extends S> = Pretty<{ [VName in keyof T]: { [VKey in keyof T[VName]]: { [VSlot in Extract<keyof T[VName][VKey], TKeys>]: T[VName][VKey][VSlot]; }; }; }>; type OmitSlots<S extends string, T extends SlotRecipeVariantRecord<S>, TKeys extends S> = Pretty<{ [VName in keyof T]: { [VKey in keyof T[VName]]: { [VSlot in Exclude<keyof T[VName][VKey], TKeys>]: T[VName][VKey][VSlot]; }; }; }>; interface SlotExtensionFns<S extends string, T extends SlotRecipeVariantRecord<S>> { add: <TSlots extends string>(...slots: TSlots[]) => SlotRecipeBuilder<S | TSlots, T extends SlotRecipeVariantRecord<S | TSlots> ? T : never>; pick: <TKeys extends S>(...keys: TKeys[]) => SlotRecipeBuilder<Extract<S, TKeys>, PickSlots<S, T, TKeys>>; omit: <TKeys extends S>(...keys: TKeys[]) => SlotRecipeBuilder<Exclude<S, TKeys>, OmitSlots<S, T, TKeys>>; /** Assign simple recipe to slot */ assignTo: <TSlot extends S, TRecipe extends RecipeConfig, TVariants extends NonNullable<TRecipe['variants']> = NonNullable<TRecipe['variants']>>(slot: TSlot, recipe: TRecipe) => SlotRecipeBuilder<S, { [VName in keyof T]: { [VKey in keyof T[VName]]: { [VSlot in keyof T[VName][VKey]]: VSlot extends TSlot ? { [VRecipeVariant in keyof TVariants]: VRecipeVariant extends VName ? VKey extends keyof TVariants[VRecipeVariant] ? TVariants[VRecipeVariant][VKey] : T[VName][VKey][VSlot] : T[VName][VKey][VSlot]; }[keyof TVariants] : T[VName][VKey][VSlot]; }; }; }>; } interface SlotRecipeBuilder<S extends string, T extends SlotRecipeVariantRecord<S>> extends SlotRecipeConfig<S, T> { extend: <TVariants extends SlotRecipeVariantRecord<S>>(variants: TVariants) => SlotRecipeBuilder<S, Pretty<T & TVariants>>; merge: <TVariants extends SlotRecipeVariantRecord<S>, MergedVariants extends Pretty<TVariants & T> = Pretty<TVariants & T>>(extension: Partial<Omit<SlotRecipeConfig<any>, 'slots' | 'variants' | 'compoundVariants' | 'defaultVariants'>> & { slots?: S[]; variants?: TVariants extends unknown ? SlotRecipeVariantRecord<S> : TVariants; compoundVariants?: Array<Pretty<RecipeCompoundVariant<RecipeCompoundSelection<MergedVariants>>>>; defaultVariants?: RecipeSelection<MergedVariants>; }) => SlotRecipeBuilder<S, MergedVariants>; pick: <TKeys extends keyof T>(...keys: TKeys[]) => SlotRecipeBuilder<S, DistributivePick<T, TKeys>>; omit: <TKeys extends keyof T>(...keys: TKeys[]) => SlotRecipeBuilder<S, DistributiveOmit<T, TKeys>>; cast: () => SlotRecipeConfig<S, SlotRecipeVariantRecord<S>>; /** Add slots, pick or omit some or assign a config recipe to a slot */ slot: SlotExtensionFns<S, T>; } declare function defineRecipe<T extends RecipeVariantRecord>(config: RecipeConfig<T>): RecipeBuilder<T>; declare function defineSlotRecipe<S extends string, T extends SlotRecipeVariantRecord<S>>(config: SlotRecipeConfig<S, T>): SlotRecipeBuilder<S, T>; export { type RecipeBuilder, type SlotExtensionFns, type SlotRecipeBuilder, defineRecipe, defineSlotRecipe };