UNPKG

@gentleduck/variants

Version:

A package for creating variants of components, providing a simple and efficient way to create variants of components.

92 lines 4.89 kB
/** * Build a stable cache key by serializing props entries in sorted order. * * @template TVariants * The mapping of variant names to their allowed string/string[] classes. * * @param {CvaProps<TVariants>} props * The props object passed into the CVA function (variant selections + class/className). * * @returns {string} * A deterministic string key used for memoization. * * @example * ```ts * getCacheKey({ intent: 'primary', size: ['sm', 'md'], className: 'mt-4' }) * // => "className:mt-4|intent:primary|size:[sm,md]" * ``` */function e(e){let t=Object.entries(e),n=``;for(let e=0;e<t.length;e++){let[r,i]=t[e];Array.isArray(i)?n+=`${r}:[${i.map(String).join(`,`)}]`:n+=`${r}:${String(i)}`,e<t.length-1&&(n+=`|`)}return n} /** * Recursively flattens any supported `ClassValue` into individual CSS tokens. * * Supports: * - primitive strings/numbers/booleans (whitespace-split) * - nested arrays of `ClassValue` * - dictionaries `{ className: boolean }` for conditional classes * * @param {ClassValue | undefined} input * The value to flatten into tokens. * @param {string[]} tokens * The accumulator array receiving each CSS token. * * @example * ```ts * const out: string[] = [] * flattenClasses( * [ * 'px-4 py-2', * { 'text-bold': true, invisible: false }, * ['hover:bg-red-500', ['active:scale-95']], * ], * out * ) * // out => ['px-4','py-2','text-bold','hover:bg-red-500','active:scale-95'] * ``` */function t(e,n){if(e!=null){if(typeof e==`string`||typeof e==`number`||typeof e==`boolean`){let t=String(e).split(/\s+/);for(let e=0;e<t.length;e++){let r=t[e];r&&n.push(r)}return}if(Array.isArray(e)){for(let r=0;r<e.length;r++)t(e[r],n);return}for(let t in e)Object.prototype.hasOwnProperty.call(e,t)&&e[t]&&n.push(t)}} /** * Creates a Class Variance Authority (CVA) function for composing class names * based on a base string, variants, defaultVariants, and compoundVariants. * * Supports two call signatures: * - `cva(base: string, options: VariantsOptions<TVariants>)` * - `cva(options: VariantsOptions<TVariants> & { base: string })` * * @template TVariants * A record mapping variant keys to a record of allowed values and their classes. * * @param {string | (VariantsOptions<TVariants> & { base?: string })} baseOrOptions * Either the base class string, or an options object including `base`. * @param {VariantsOptions<TVariants>} [maybeOptions] * The options object when using the two-arg signature. * * @returns {(props?: CvaProps<TVariants>) => string} * A function that, given variant props and optional `class`/`className`, returns * the deduplicated, memoized className string. * * @example * ```ts * const button = cva('btn px-4 py-2', { * variants: { * intent: { primary: 'bg-blue-500 text-white', danger: 'bg-red-500' }, * size: { sm: 'text-sm', lg: 'text-lg' }, * }, * defaultVariants: { intent: 'primary', size: 'sm' }, * compoundVariants: [ * { * intent: ['primary','danger'], * size: 'lg', * className: 'uppercase', * }, * ], * }) * * // uses defaults + compound match * button() * // => 'btn px-4 py-2 bg-blue-500 text-white text-sm uppercase' * * // overrides size + adds custom classes * button({ size: 'lg', class: ['mt-4','shadow'] }) * // => 'btn px-4 py-2 bg-blue-500 text-white text-lg uppercase mt-4 shadow' * ``` */function n(n,r){let i=typeof n==`string`?{base:n,...r}:n,{base:a=``,variants:o,defaultVariants:s={},compoundVariants:c=[]}=i,l=new Map;return function(n={}){let r=e(n),i=l.get(r);if(i)return i;let u=[],d=new Set;t(a,u);let f={...s,...n};for(let e in o){let n=f[e];if(n==null||n===`unset`)continue;let r=o[e][String(n)];t(r,u)}for(let e=0;e<c.length;e++){let n=c[e],r=!0;for(let e in n){if(e===`class`||e===`className`)continue;let t=n[e],i=f[e];if(Array.isArray(t)&&i){if(!t.includes(i.toString())){r=!1;break}}else if(i!==t){r=!1;break}}r&&(t(n.class,u),t(n.className,u))}t(n.className,u),t(n.class,u);for(let e=0;e<u.length;e++)d.add(u[e]);let p=Array.from(d).join(` `);return l.set(r,p),p}}function r(e={sm:`p-2 h-2 m-2`,md:`p-4 h-4 m-4`,lg:`p-6 h-6 m-6`}){return Object.entries(e).map(([e,t])=>t.split(` `).map(t=>`${e}:${t}`).join(` `)).join(` `)}const i=n(`flex items-center`,{variants:{variant:{default:`bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm`,destructive:`bg-destructive/90 hover:bg-destructive/70 text-destructive-foreground shadow-xs`,nothing:``},size:{xs:`h-6 px-2 py-1 text-xs [&_svg]:size-[1.3em] rounded-sm`,sm:`h-8 px-3 py-1.5 text-sm [&_svg]:size-[1.3em] rounded-md`,default:`h-9 px-4 py-2 text-base [&_svg]:size-[1.3em] rounded-md`+r()},border:{default:``,primary:`border border-border/40 hover:border-border/80`}},defaultVariants:{variant:`default`,size:`default`,border:`default`}});console.log(i());export{i as buttonVariants,n as cva,r as generateResponsiveVariants}; //# sourceMappingURL=index.js.map