New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@gentleduck/variants

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@gentleduck/variants - npm Package Compare versions

Comparing version
0.1.12
to
0.1.13
+13
-3
dist/index.d.ts

@@ -90,2 +90,14 @@ //#region src/variants.types.d.ts

/**
* Removes an array type from a union type.
* Used to exclude `class` and `className` from `VariantProps`.
* @template T - A union type.
* @example
* ```ts
* type Props = { class?: string; className?: string }
* type PropsWithoutArray = RemoveArray<Props>
* // => { class?: string; className?: string }
* ```
*/
type RemoveArray<T> = T extends any[] ? never : T;
/**
* Extracts only the variant-related props from a CVA function’s signature,

@@ -108,3 +120,3 @@ * omitting `class` and `className`.

*/
type VariantProps<T> = T extends ((props?: infer P) => string) ? { [K in keyof P as K extends 'class' | 'className' ? never : K]: P[K] } : never;
type VariantProps<T> = T extends ((props?: infer P) => string) ? { [K in keyof P as K extends 'class' | 'className' ? never : K]: RemoveArray<P[K]> } : never;
/**

@@ -134,3 +146,2 @@ * A dictionary mapping CSS class names to boolean flags.

type ClassValue = string | number | boolean | ClassDictionary | ClassArray;
//#endregion

@@ -187,5 +198,4 @@ //#region src/variants.d.ts

}), maybeOptions?: VariantsOptions<TVariants>): (props?: CvaProps<TVariants>) => string;
//#endregion
export { ClassArray, ClassDictionary, ClassValue, CvaProps, VariantParams, VariantProps, VariantsOptions, cva };
//# sourceMappingURL=index.d.ts.map
+1
-91

@@ -1,92 +0,2 @@

/**
* 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.hasOwn(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(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}}export{n as cva};
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}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.hasOwn(e,t)&&e[t]&&n.push(t)}}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(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}}export{n as cva};
//# sourceMappingURL=index.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","names":["props: CvaProps<TVariants>","input: ClassValue | undefined","tokens: string[]","baseOrOptions: string | (VariantsOptions<TVariants> & { base?: string })","maybeOptions?: VariantsOptions<TVariants>"],"sources":["../src/variants.ts"],"sourcesContent":["import type { ClassValue, CvaProps, VariantsOptions } from './variants.types'\n\n/**\n * Build a stable cache key by serializing props entries in sorted order.\n *\n * @template TVariants\n * The mapping of variant names to their allowed string/string[] classes.\n *\n * @param {CvaProps<TVariants>} props\n * The props object passed into the CVA function (variant selections + class/className).\n *\n * @returns {string}\n * A deterministic string key used for memoization.\n *\n * @example\n * ```ts\n * getCacheKey({ intent: 'primary', size: ['sm', 'md'], className: 'mt-4' })\n * // => \"className:mt-4|intent:primary|size:[sm,md]\"\n * ```\n */\nfunction getCacheKey<TVariants extends Record<string, Record<string, string | string[]>>>(\n props: CvaProps<TVariants>,\n): string {\n const entries = Object.entries(props) as [string, ClassValue][]\n\n let key = ''\n for (let i = 0; i < entries.length; i++) {\n const [k, v] = entries[i]\n if (Array.isArray(v)) {\n key += `${k}:[${v.map(String).join(',')}]`\n } else {\n key += `${k}:${String(v)}`\n }\n if (i < entries.length - 1) key += '|'\n }\n return key\n}\n\n/**\n * Recursively flattens any supported `ClassValue` into individual CSS tokens.\n *\n * Supports:\n * - primitive strings/numbers/booleans (whitespace-split)\n * - nested arrays of `ClassValue`\n * - dictionaries `{ className: boolean }` for conditional classes\n *\n * @param {ClassValue | undefined} input\n * The value to flatten into tokens.\n * @param {string[]} tokens\n * The accumulator array receiving each CSS token.\n *\n * @example\n * ```ts\n * const out: string[] = []\n * flattenClasses(\n * [\n * 'px-4 py-2',\n * { 'text-bold': true, invisible: false },\n * ['hover:bg-red-500', ['active:scale-95']],\n * ],\n * out\n * )\n * // out => ['px-4','py-2','text-bold','hover:bg-red-500','active:scale-95']\n * ```\n */\nfunction flattenClasses(input: ClassValue | undefined, tokens: string[]): void {\n if (input === undefined || input === null) return\n\n // primitive values\n if (typeof input === 'string' || typeof input === 'number' || typeof input === 'boolean') {\n const parts = String(input).split(/\\s+/)\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n if (part) tokens.push(part)\n }\n return\n }\n\n // arrays of ClassValue\n if (Array.isArray(input)) {\n for (let i = 0; i < input.length; i++) {\n flattenClasses(input[i], tokens)\n }\n return\n }\n\n // object dictionary `{ className: true }`\n for (const key in input) {\n if (Object.hasOwn(input, key) && input[key]) {\n tokens.push(key)\n }\n }\n}\n\n/**\n * Creates a Class Variance Authority (CVA) function for composing class names\n * based on a base string, variants, defaultVariants, and compoundVariants.\n *\n * Supports two call signatures:\n * - `cva(base: string, options: VariantsOptions<TVariants>)`\n * - `cva(options: VariantsOptions<TVariants> & { base: string })`\n *\n * @template TVariants\n * A record mapping variant keys to a record of allowed values and their classes.\n *\n * @param {string | (VariantsOptions<TVariants> & { base?: string })} baseOrOptions\n * Either the base class string, or an options object including `base`.\n * @param {VariantsOptions<TVariants>} [maybeOptions]\n * The options object when using the two-arg signature.\n *\n * @returns {(props?: CvaProps<TVariants>) => string}\n * A function that, given variant props and optional `class`/`className`, returns\n * the deduplicated, memoized className string.\n *\n * @example\n * ```ts\n * const button = cva('btn px-4 py-2', {\n * variants: {\n * intent: { primary: 'bg-blue-500 text-white', danger: 'bg-red-500' },\n * size: { sm: 'text-sm', lg: 'text-lg' },\n * },\n * defaultVariants: { intent: 'primary', size: 'sm' },\n * compoundVariants: [\n * {\n * intent: ['primary','danger'],\n * size: 'lg',\n * className: 'uppercase',\n * },\n * ],\n * })\n *\n * // uses defaults + compound match\n * button()\n * // => 'btn px-4 py-2 bg-blue-500 text-white text-sm uppercase'\n *\n * // overrides size + adds custom classes\n * button({ size: 'lg', class: ['mt-4','shadow'] })\n * // => 'btn px-4 py-2 bg-blue-500 text-white text-lg uppercase mt-4 shadow'\n * ```\n */\nexport function cva<TVariants extends Record<string, Record<string, string | string[]>>>(\n baseOrOptions: string | (VariantsOptions<TVariants> & { base?: string }),\n maybeOptions?: VariantsOptions<TVariants>,\n): (props?: CvaProps<TVariants>) => string {\n // Normalize the two possible call signatures\n const config = typeof baseOrOptions === 'string' ? { base: baseOrOptions, ...maybeOptions } : baseOrOptions\n\n const { base = '', variants, defaultVariants = {}, compoundVariants = [] } = config\n\n // Memoization cache keyed by serialized props\n const cache = new Map<string, string>()\n\n return (props: CvaProps<TVariants> = {} as CvaProps<TVariants>): string => {\n // 1) Memo lookup\n const cacheKey = getCacheKey(props)\n const memo = cache.get(cacheKey)\n if (memo) return memo\n\n const tokens: string[] = []\n const seen = new Set<string>()\n\n // 2) Base classes\n flattenClasses(base, tokens)\n\n // 3) Merge defaults + incoming props\n const merged = { ...defaultVariants, ...props } as Record<keyof TVariants, ClassValue>\n\n // 4) Apply variant-specific classes\n for (const variantName in variants) {\n const v = merged[variantName]\n if (v == null || v === 'unset') continue\n const cls = variants[variantName][String(v)]\n flattenClasses(cls, tokens)\n }\n\n // 5) Apply compoundVariants when all conditions match\n for (let i = 0; i < compoundVariants.length; i++) {\n const cv = compoundVariants[i as number]\n let match = true\n\n for (const key in cv) {\n if (key === 'class' || key === 'className') continue\n\n const cond = cv[key as keyof typeof cv]\n const actual = merged[key as keyof typeof merged]\n\n // array- or single-value condition\n if (Array.isArray(cond) && actual) {\n if (!cond.includes(actual.toString())) {\n match = false\n break\n }\n } else if (actual !== cond) {\n match = false\n break\n }\n }\n if (!match) continue\n\n flattenClasses(cv.class, tokens)\n flattenClasses(cv.className, tokens)\n }\n\n // 6) Finally append any `className` or `class` from props\n flattenClasses(props.className, tokens)\n flattenClasses(props.class, tokens)\n\n // 7) Deduplicate & join\n for (let i = 0; i < tokens.length; i++) {\n seen.add(tokens[i as number])\n }\n const result = Array.from(seen).join(' ')\n\n cache.set(cacheKey, result)\n return result\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;EAoBA,SAAS,EACPA,EAAAA,CAIA,IAFM,EAAU,OAAO,QAAQ,EAAA,CAE3B,EAAM,GACV,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAAK,CACvC,GAAM,CAAC,EAAG,EAAE,CAAG,EAAQ,GAMvB,AALI,MAAM,QAAQ,EAAA,CAChB,IAAA,EAAU,EAAE,IAAI,EAAE,IAAI,OAAA,CAAQ,KAAK,IAAA,CAAK,GAExC,IAAA,EAAU,EAAE,GAAG,OAAO,EAAA,CAAA,EAEpB,EAAI,EAAQ,OAAS,IAAG,GAAO,IACpC,CACD,OAAO,CACR;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BD,SAAS,EAAeC,EAA+BC,EAAAA,CACjD,MAAiC,KAGrC,WAAW,GAAU,iBAAmB,GAAU,iBAAmB,GAAU,UAAW,CACxF,IAAM,EAAQ,OAAO,EAAA,CAAO,MAAM,MAAA,CAClC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,IAAM,EAAO,EAAM,GACnB,AAAI,GAAM,EAAO,KAAK,EAAA,AACvB,CACD,MACD,CAGD,GAAI,MAAM,QAAQ,EAAA,CAAQ,CACxB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAChC,EAAe,EAAM,GAAI,EAAA,CAE3B,MACD,CAGD,IAAK,IAAM,KAAO,EAChB,AAAI,OAAO,OAAO,EAAO,EAAA,EAAQ,EAAM,IACrC,EAAO,KAAK,EAAA,AAbf,CAgBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgDD,SAAgB,EACdC,EACAC,EAAAA,CAQA,IALM,SAAgB,GAAkB,SAAW,CAAE,KAAM,EAAe,GAAG,CAAc,EAAG,EAExF,CAAE,OAAO,GAAI,WAAU,kBAAkB,CAAE,EAAE,mBAAmB,CAAE,EAAE,CAAG,EAGvE,EAAQ,IAAI,IAElB,MAAO,CAACJ,EAA6B,CAAE,IAAA,CAGrC,IADM,EAAW,EAAY,EAAA,CACvB,EAAO,EAAM,IAAI,EAAA,CACvB,GAAI,EAAM,OAAO,EAGjB,IADME,EAAmB,CAAE,EACrB,EAAO,IAAI,IAGjB,EAAe,EAAM,EAAA,CAGrB,IAAM,EAAS,CAAE,GAAG,EAAiB,GAAG,CAAO,EAG/C,IAAK,IAAM,KAAe,EAAU,CAClC,IAAM,EAAI,EAAO,GACjB,GAAI,GAAK,MAAQ,IAAM,QAAS,SAChC,IAAM,EAAM,EAAS,GAAa,OAAO,EAAA,EACzC,EAAe,EAAK,EAAA,AACrB,CAGD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAiB,OAAQ,IAAK,CAEhD,IADM,EAAK,EAAiB,GACxB,GAAQ,EAEZ,IAAK,IAAM,KAAO,EAAI,CACpB,GAAI,IAAQ,SAAW,IAAQ,YAAa,SAG5C,IADM,EAAO,EAAG,GACV,EAAS,EAAO,GAGtB,GAAI,MAAM,QAAQ,EAAA,EAAS,OACpB,EAAK,SAAS,EAAO,UAAA,CAAA,CAAa,CACrC,GAAQ,EACR,KACD,UACQ,IAAW,EAAM,CAC1B,GAAQ,EACR,KACD,CACF,CACI,IAEL,EAAe,EAAG,MAAO,EAAA,CACzB,EAAe,EAAG,UAAW,EAAA,CAC9B,CAID,AADA,EAAe,EAAM,UAAW,EAAA,CAChC,EAAe,EAAM,MAAO,EAAA,CAG5B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,IACjC,EAAK,IAAI,EAAO,GAAA,CAElB,IAAM,EAAS,MAAM,KAAK,EAAA,CAAM,KAAK,IAAA,CAGrC,MADA,GAAM,IAAI,EAAU,EAAA,CACb,CACR,CACF"}
{"version":3,"file":"index.js","names":["getCacheKey","props","entries","Object","key","i","length","k","v","Array","isArray","map","String","join","flattenClasses","input","tokens","undefined","parts","split","part","push","hasOwn","cva","baseOrOptions","maybeOptions","config","base","variants","defaultVariants","compoundVariants","cache","Map","cacheKey","memo","get","seen","Set","merged","variantName","cls","cv","match","cond","actual","includes","toString","class","className","add","result","from","set"],"sources":["../src/variants.ts"],"sourcesContent":["import type { ClassValue, CvaProps, VariantsOptions } from './variants.types'\n\n/**\n * Build a stable cache key by serializing props entries in sorted order.\n *\n * @template TVariants\n * The mapping of variant names to their allowed string/string[] classes.\n *\n * @param {CvaProps<TVariants>} props\n * The props object passed into the CVA function (variant selections + class/className).\n *\n * @returns {string}\n * A deterministic string key used for memoization.\n *\n * @example\n * ```ts\n * getCacheKey({ intent: 'primary', size: ['sm', 'md'], className: 'mt-4' })\n * // => \"className:mt-4|intent:primary|size:[sm,md]\"\n * ```\n */\nfunction getCacheKey<TVariants extends Record<string, Record<string, string | string[]>>>(\n props: CvaProps<TVariants>,\n): string {\n const entries = Object.entries(props) as [string, ClassValue][]\n\n let key = ''\n for (let i = 0; i < entries.length; i++) {\n const [k, v] = entries[i]\n if (Array.isArray(v)) {\n key += `${k}:[${v.map(String).join(',')}]`\n } else {\n key += `${k}:${String(v)}`\n }\n if (i < entries.length - 1) key += '|'\n }\n return key\n}\n\n/**\n * Recursively flattens any supported `ClassValue` into individual CSS tokens.\n *\n * Supports:\n * - primitive strings/numbers/booleans (whitespace-split)\n * - nested arrays of `ClassValue`\n * - dictionaries `{ className: boolean }` for conditional classes\n *\n * @param {ClassValue | undefined} input\n * The value to flatten into tokens.\n * @param {string[]} tokens\n * The accumulator array receiving each CSS token.\n *\n * @example\n * ```ts\n * const out: string[] = []\n * flattenClasses(\n * [\n * 'px-4 py-2',\n * { 'text-bold': true, invisible: false },\n * ['hover:bg-red-500', ['active:scale-95']],\n * ],\n * out\n * )\n * // out => ['px-4','py-2','text-bold','hover:bg-red-500','active:scale-95']\n * ```\n */\nfunction flattenClasses(input: ClassValue | undefined, tokens: string[]): void {\n if (input === undefined || input === null) return\n\n // primitive values\n if (typeof input === 'string' || typeof input === 'number' || typeof input === 'boolean') {\n const parts = String(input).split(/\\s+/)\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n if (part) tokens.push(part)\n }\n return\n }\n\n // arrays of ClassValue\n if (Array.isArray(input)) {\n for (let i = 0; i < input.length; i++) {\n flattenClasses(input[i], tokens)\n }\n return\n }\n\n // object dictionary `{ className: true }`\n for (const key in input) {\n if (Object.hasOwn(input, key) && input[key]) {\n tokens.push(key)\n }\n }\n}\n\n/**\n * Creates a Class Variance Authority (CVA) function for composing class names\n * based on a base string, variants, defaultVariants, and compoundVariants.\n *\n * Supports two call signatures:\n * - `cva(base: string, options: VariantsOptions<TVariants>)`\n * - `cva(options: VariantsOptions<TVariants> & { base: string })`\n *\n * @template TVariants\n * A record mapping variant keys to a record of allowed values and their classes.\n *\n * @param {string | (VariantsOptions<TVariants> & { base?: string })} baseOrOptions\n * Either the base class string, or an options object including `base`.\n * @param {VariantsOptions<TVariants>} [maybeOptions]\n * The options object when using the two-arg signature.\n *\n * @returns {(props?: CvaProps<TVariants>) => string}\n * A function that, given variant props and optional `class`/`className`, returns\n * the deduplicated, memoized className string.\n *\n * @example\n * ```ts\n * const button = cva('btn px-4 py-2', {\n * variants: {\n * intent: { primary: 'bg-blue-500 text-white', danger: 'bg-red-500' },\n * size: { sm: 'text-sm', lg: 'text-lg' },\n * },\n * defaultVariants: { intent: 'primary', size: 'sm' },\n * compoundVariants: [\n * {\n * intent: ['primary','danger'],\n * size: 'lg',\n * className: 'uppercase',\n * },\n * ],\n * })\n *\n * // uses defaults + compound match\n * button()\n * // => 'btn px-4 py-2 bg-blue-500 text-white text-sm uppercase'\n *\n * // overrides size + adds custom classes\n * button({ size: 'lg', class: ['mt-4','shadow'] })\n * // => 'btn px-4 py-2 bg-blue-500 text-white text-lg uppercase mt-4 shadow'\n * ```\n */\nexport function cva<TVariants extends Record<string, Record<string, string | string[]>>>(\n baseOrOptions: string | (VariantsOptions<TVariants> & { base?: string }),\n maybeOptions?: VariantsOptions<TVariants>,\n): (props?: CvaProps<TVariants>) => string {\n // Normalize the two possible call signatures\n const config = typeof baseOrOptions === 'string' ? { base: baseOrOptions, ...maybeOptions } : baseOrOptions\n\n const { base = '', variants, defaultVariants = {}, compoundVariants = [] } = config\n\n // Memoization cache keyed by serialized props\n const cache = new Map<string, string>()\n\n return (props: CvaProps<TVariants> = {} as CvaProps<TVariants>): string => {\n // 1) Memo lookup\n const cacheKey = getCacheKey(props)\n const memo = cache.get(cacheKey)\n if (memo) return memo\n\n const tokens: string[] = []\n const seen = new Set<string>()\n\n // 2) Base classes\n flattenClasses(base, tokens)\n\n // 3) Merge defaults + incoming props\n const merged = { ...defaultVariants, ...props } as Record<keyof TVariants, ClassValue>\n\n // 4) Apply variant-specific classes\n for (const variantName in variants) {\n const v = merged[variantName]\n if (v == null || v === 'unset') continue\n const cls = variants[variantName][String(v)]\n flattenClasses(cls, tokens)\n }\n\n // 5) Apply compoundVariants when all conditions match\n for (let i = 0; i < compoundVariants.length; i++) {\n const cv = compoundVariants[i as number]\n let match = true\n\n for (const key in cv) {\n if (key === 'class' || key === 'className') continue\n\n const cond = cv[key as keyof typeof cv]\n const actual = merged[key as keyof typeof merged]\n\n // array- or single-value condition\n if (Array.isArray(cond) && actual) {\n if (!cond.includes(actual.toString())) {\n match = false\n break\n }\n } else if (actual !== cond) {\n match = false\n break\n }\n }\n if (!match) continue\n\n flattenClasses(cv.class, tokens)\n flattenClasses(cv.className, tokens)\n }\n\n // 6) Finally append any `className` or `class` from props\n flattenClasses(props.className, tokens)\n flattenClasses(props.class, tokens)\n\n // 7) Deduplicate & join\n for (let i = 0; i < tokens.length; i++) {\n seen.add(tokens[i as number])\n }\n const result = Array.from(seen).join(' ')\n\n cache.set(cacheKey, result)\n return result\n }\n}\n"],"mappings":"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"}
{
"name": "@gentleduck/variants",
"author": "wilddcuk",
"bugs": {
"url": "https://github.com/gentleduck/ui/issues"
},
"description": "A package for creating variants of components, providing a simple and efficient way to create variants of components.",
"types": "./dist/index.d.ts",
"main": "./dist/index.js",
"private": false,
"version": "0.1.12",
"type": "module",
"devDependencies": {
"@changesets/cli": "^2.27.7",
"clsx": "^1.2.1",
"cva": "1.0.0-beta.3",
"husky": "^9.1.7",
"tsdown": "^0.11",
"@gentleduck/tsdown-config": "0.0.1",
"@gentleduck/typescript-config": "0.1.0"
},
"engines": {
"node": ">=22.0.0"
},
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"exports": {
".": "./dist/index.js"
},
"homepage": "https://github.com/gentleduck/ui/tree/master/packages/duck-variants#readme",
"keywords": [

@@ -33,4 +44,9 @@ "class-variants",

],
"author": "wilddcuk",
"license": "MIT",
"main": "./dist/index.js",
"name": "@gentleduck/variants",
"peerDependencies": {
"typescript": "^5.8.3"
},
"private": false,
"repository": {

@@ -40,27 +56,11 @@ "type": "git",

},
"bugs": {
"url": "https://github.com/gentleduck/ui/issues"
},
"homepage": "https://github.com/gentleduck/ui/tree/master/packages/duck-variants#readme",
"devDependencies": {
"@changesets/cli": "^2.27.7",
"clsx": "^1.2.1",
"cva": "1.0.0-beta.3",
"husky": "^9.1.7",
"tsdown": "^0.11",
"@gentleduck/typescript-config": "0.1.0",
"@gentleduck/tsdown-config": "0.0.1"
},
"peerDependencies": {
"typescript": "^5.8.3"
},
"engines": {
"node": ">=22.0.0"
},
"type": "module",
"types": "./dist/index.d.ts",
"version": "0.1.13",
"scripts": {
"build": "tsdown",
"ci": "pnpm run lint && pnpm run format && pnpm run build",
"clean": "git clean -xdf .cache .turbo node_modules dist",
"build": "tsdown",
"format": "biome format --write ./",
"lint": "biome lint --write ./",
"format": "biome format --write ./",
"ci": "pnpm run lint && pnpm run format && pnpm run build",
"release": "changeset version",

@@ -67,0 +67,0 @@ "test": "vitest"