Comparing version 0.4.0 to 1.0.0
@@ -1,4 +0,14 @@ | ||
import clsx, { type ClassValue } from 'clsx'; | ||
/** | ||
* @module | ||
* This module contains functions for configuring and | ||
* creating class variant utility functions. | ||
* | ||
* It also includes types for extracting variant props | ||
* from a class variant utility function. | ||
* | ||
* For more information see the {@link https://github.com/erictaylor/cvu/blob/main/README.md|GitHub README} | ||
*/ | ||
import { type ClassValue, clsx } from 'clsx'; | ||
type ConfigWrapperProps = { | ||
cx: (...inputs: Parameters<typeof clsx>) => ReturnType<typeof clsx>; | ||
clsx: (...inputs: ClassValue[]) => string; | ||
}; | ||
@@ -33,8 +43,151 @@ type StringToBoolean<T> = T extends 'true' | 'false' ? boolean : T; | ||
}; | ||
/** | ||
* A helper type to extract the variant props from | ||
* a class variant utility function. | ||
* | ||
* @example | ||
* ```ts | ||
* import { cvu, type VariantProps } from 'cvu'; | ||
* | ||
* const buttonClassnames = cvu('font-semibold', { | ||
* variants: { | ||
* size: { | ||
* sm: 'text-sm', | ||
* }, | ||
* }, | ||
* }); | ||
* type ButtonClassnameProps = VariantProps<typeof buttonClassnames>; | ||
* ``` | ||
*/ | ||
export type VariantProps<T extends VariantClassNameFn<ConfigSchema>> = NonNullVariantPropsValues<Exclude<Parameters<T>[0], undefined>>; | ||
/** | ||
* A helper type to extract the variant props from | ||
* a class variant utility function and marking | ||
* the specified keys as required. | ||
* | ||
* @example | ||
* ```ts | ||
* import { cvu, type VariantPropsWithRequired } from "cvu"; | ||
* | ||
* type ButtonClassnamesProps = VariantPropsWithRequired< | ||
* typeof buttonClassnames, | ||
* "intent" | ||
* >; | ||
* const buttonClassnames = cvu("…", { | ||
* variants: { | ||
* intent: { | ||
* primary: "…", | ||
* secondary: "…", | ||
* }, | ||
* size: { | ||
* sm: "…", | ||
* md: "…", | ||
* }, | ||
* }, | ||
* }); | ||
* | ||
* const wrapper = (props: ButtonClassnamesProps) => { | ||
* return buttonClassnames(props); | ||
* }; | ||
* | ||
* // ❌ TypeScript Error: | ||
* // Argument of type "{}": is not assignable to parameter of type "ButtonClassnamesProps". | ||
* // Property "intent" is missing in type "{}" but required in type | ||
* // "ButtonClassnamesProps". | ||
* wrapper({}); | ||
* | ||
* // ✅ | ||
* wrapper({ intent: "primary" }); | ||
* ``` | ||
*/ | ||
export type VariantPropsWithRequired<T extends VariantClassNameFn<ConfigSchema>, K extends keyof VariantProps<T>> = VariantProps<T> & Required<Pick<VariantProps<T>, K>>; | ||
/** | ||
* The class variant utility function. | ||
*/ | ||
export type ClassVariantUtility = <T>(base?: ClassValue, variantsConfig?: VariantsConfig<T>) => VariantClassNameFn<T>; | ||
export declare const config: ({ cx }: ConfigWrapperProps) => ClassVariantUtility; | ||
export declare const cx: typeof clsx; | ||
/** | ||
* A function to create a custom class variant utility. | ||
* | ||
* Allows you to provide your own underlying `clsx` | ||
* implementation or wrapping logic. | ||
* | ||
* @param config Object of configuration options. Pass a custom `clsx` function to be used for generating class strings. | ||
* @returns A class variant utility function. | ||
* | ||
* @example | ||
* ```ts | ||
* import { config, clsx } from 'cvu'; | ||
* import { twMerge } from 'tailwind-merge'; | ||
* | ||
* export const customCvu = config({ | ||
* clsx: (...inputs) => twMerge(clsx(inputs)), | ||
* }); | ||
* ``` | ||
*/ | ||
export declare const config: ({ clsx: cx }: ConfigWrapperProps) => ClassVariantUtility; | ||
/** | ||
* The default `clsx` function used for generating class strings. | ||
* | ||
* Provided by the `clsx` NPM package. | ||
*/ | ||
export { clsx }; | ||
/** | ||
* Class variant utility function. | ||
* | ||
* Creates a function that generates a class string based on the provided variant props. | ||
* | ||
* @param base The base class name (`string`, `string[]`, or other `clsx` compatible values). | ||
* @param variantsConfig Object of configuration options for the class variants. | ||
* @param variantsConfig.variants Object variants schema. | ||
* @param variantsConfig.componentVariants Array of Objects describing class names to be applied when variant combinations are active. | ||
* @param variantsConfig.defaultVariants Object of default values for the variants. | ||
* @returns A function that generates a class string based on the provided variant props. | ||
* | ||
* @example | ||
* ```ts | ||
* import { cvu } from "cvu"; | ||
* | ||
* const buttonClassnames = cvu( | ||
* ["font-semibold", "border", "rounded"], | ||
* // --or-- | ||
* // 'font-semibold border rounded' | ||
* { | ||
* variants: { | ||
* intent: { | ||
* primary: [ | ||
* "bg-blue-500", | ||
* "text-white", | ||
* "border-transparent", | ||
* "hover:bg-blue-600", | ||
* ], | ||
* secondary: "bg-white text-gray-800 border-gray-400 hover:bg-gray-100", | ||
* }, | ||
* size: { | ||
* sm: "text-sm py-1 px-2", | ||
* md: ["text-base", "py-2", "px-4"], | ||
* }, | ||
* }, | ||
* compoundVariants: [ | ||
* { | ||
* intent: "primary", | ||
* size: "md", | ||
* className: "uppercase", | ||
* }, | ||
* ], | ||
* defaultVariants: { | ||
* intent: "primary", | ||
* size: "md", | ||
* }, | ||
* } | ||
* ); | ||
* | ||
* buttonClassnames(); | ||
* // => 'font-semibold border rounded bg-blue-500 text-white border-transparent hover:bg-blue-600 text-base py-2 px-4 uppercase' | ||
* | ||
* buttonClassnames({ intent: "secondary", size: "sm" }); | ||
* // => 'font-semibold border rounded bg-white text-gray-800 border-gray-400 hover:bg-gray-100 text-sm py-1 px-2' | ||
* ``` | ||
*/ | ||
export declare const cvu: ClassVariantUtility; | ||
export default cvu; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,2 +0,134 @@ | ||
"use strict";var h=Object.create;var u=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var b=Object.getPrototypeOf,K=Object.prototype.hasOwnProperty;var j=(e,n)=>{for(var t in n)u(e,t,{get:n[t],enumerable:!0})},C=(e,n,t,s)=>{if(n&&typeof n=="object"||typeof n=="function")for(let a of R(n))!K.call(e,a)&&a!==t&&u(e,a,{get:()=>n[a],enumerable:!(s=k(n,a))||s.enumerable});return e};var B=(e,n,t)=>(t=e!=null?h(b(e)):{},C(n||!e||!e.__esModule?u(t,"default",{value:e,enumerable:!0}):t,e)),F=e=>C(u({},"__esModule",{value:!0}),e);var E={};j(E,{config:()=>y,cvu:()=>x,cx:()=>m,default:()=>W});module.exports=F(E);var g=B(require("clsx")),V=e=>(e==null?void 0:e.toString())||"",y=({cx:e})=>(n,t)=>{let{variants:s,defaultVariants:a,compoundVariants:T}=t||{};return(i,d)=>{if(!s)return e(n,d);let S=Object.entries(s).map(([r,o])=>{let f=i==null?void 0:i[r],p=a==null?void 0:a[r];if(f===null)return null;let l=V(f)||V(p);return o==null?void 0:o[l]}),N=i&&Object.fromEntries(Object.entries(i).filter(([,r])=>r!==void 0)),P=T==null?void 0:T.reduce((r,{className:o,...f})=>(Object.entries(f).every(([p,l])=>{let c={...a,...N}[p];return Array.isArray(l)&&c!=null?l.includes(c):c===l})&&r.push(o),r),[]);return e(n,S,P,d)}},m=g.default,x=y({cx:m}),W=x; | ||
//# sourceMappingURL=index.js.map | ||
/** | ||
* @module | ||
* This module contains functions for configuring and | ||
* creating class variant utility functions. | ||
* | ||
* It also includes types for extracting variant props | ||
* from a class variant utility function. | ||
* | ||
* For more information see the {@link https://github.com/erictaylor/cvu/blob/main/README.md|GitHub README} | ||
*/ | ||
import { clsx } from 'clsx'; | ||
const valueToString = (value) => { | ||
return (value === null || value === void 0 ? void 0 : value.toString()) || ''; | ||
}; | ||
/** | ||
* A function to create a custom class variant utility. | ||
* | ||
* Allows you to provide your own underlying `clsx` | ||
* implementation or wrapping logic. | ||
* | ||
* @param config Object of configuration options. Pass a custom `clsx` function to be used for generating class strings. | ||
* @returns A class variant utility function. | ||
* | ||
* @example | ||
* ```ts | ||
* import { config, clsx } from 'cvu'; | ||
* import { twMerge } from 'tailwind-merge'; | ||
* | ||
* export const customCvu = config({ | ||
* clsx: (...inputs) => twMerge(clsx(inputs)), | ||
* }); | ||
* ``` | ||
*/ | ||
export const config = ({ clsx: cx }) => (base, variantsConfig) => { | ||
const { variants, defaultVariants, compoundVariants } = variantsConfig || {}; | ||
return (variantProps, className) => { | ||
if (!variants) { | ||
return cx(base, className); | ||
} | ||
const variantClassNames = Object.entries(variants).map(([variant, variantOptions]) => { | ||
const variantProp = variantProps === null || variantProps === void 0 ? void 0 : variantProps[variant]; | ||
const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant]; | ||
if (variantProp === null) { | ||
return null; | ||
} | ||
const variantKey = valueToString(variantProp) || valueToString(defaultVariantProp); | ||
return variantOptions === null || variantOptions === void 0 ? void 0 : variantOptions[variantKey]; | ||
}); | ||
const variantPropsWithoutUndefined = variantProps && | ||
Object.fromEntries(Object.entries(variantProps).filter(([, value]) => value !== undefined)); | ||
const compoundVariantClassNames = compoundVariants === null || compoundVariants === void 0 ? void 0 : compoundVariants.reduce((acc, { className: compoundClassName, ...compoundVariantOptions }) => { | ||
if (Object.entries(compoundVariantOptions).every(([key, value]) => { | ||
const o = { | ||
...defaultVariants, | ||
...variantPropsWithoutUndefined, | ||
}; | ||
const v = o[key]; | ||
return Array.isArray(value) && v != null | ||
? value.includes(v) | ||
: v === value; | ||
})) { | ||
acc.push(compoundClassName); | ||
return acc; | ||
} | ||
return acc; | ||
}, []); | ||
return cx(base, variantClassNames, compoundVariantClassNames, className); | ||
}; | ||
}; | ||
/** | ||
* The default `clsx` function used for generating class strings. | ||
* | ||
* Provided by the `clsx` NPM package. | ||
*/ | ||
export { clsx }; | ||
/** | ||
* Class variant utility function. | ||
* | ||
* Creates a function that generates a class string based on the provided variant props. | ||
* | ||
* @param base The base class name (`string`, `string[]`, or other `clsx` compatible values). | ||
* @param variantsConfig Object of configuration options for the class variants. | ||
* @param variantsConfig.variants Object variants schema. | ||
* @param variantsConfig.componentVariants Array of Objects describing class names to be applied when variant combinations are active. | ||
* @param variantsConfig.defaultVariants Object of default values for the variants. | ||
* @returns A function that generates a class string based on the provided variant props. | ||
* | ||
* @example | ||
* ```ts | ||
* import { cvu } from "cvu"; | ||
* | ||
* const buttonClassnames = cvu( | ||
* ["font-semibold", "border", "rounded"], | ||
* // --or-- | ||
* // 'font-semibold border rounded' | ||
* { | ||
* variants: { | ||
* intent: { | ||
* primary: [ | ||
* "bg-blue-500", | ||
* "text-white", | ||
* "border-transparent", | ||
* "hover:bg-blue-600", | ||
* ], | ||
* secondary: "bg-white text-gray-800 border-gray-400 hover:bg-gray-100", | ||
* }, | ||
* size: { | ||
* sm: "text-sm py-1 px-2", | ||
* md: ["text-base", "py-2", "px-4"], | ||
* }, | ||
* }, | ||
* compoundVariants: [ | ||
* { | ||
* intent: "primary", | ||
* size: "md", | ||
* className: "uppercase", | ||
* }, | ||
* ], | ||
* defaultVariants: { | ||
* intent: "primary", | ||
* size: "md", | ||
* }, | ||
* } | ||
* ); | ||
* | ||
* buttonClassnames(); | ||
* // => 'font-semibold border rounded bg-blue-500 text-white border-transparent hover:bg-blue-600 text-base py-2 px-4 uppercase' | ||
* | ||
* buttonClassnames({ intent: "secondary", size: "sm" }); | ||
* // => 'font-semibold border rounded bg-white text-gray-800 border-gray-400 hover:bg-gray-100 text-sm py-1 px-2' | ||
* ``` | ||
*/ | ||
export const cvu = config({ clsx }); | ||
export default cvu; |
MIT License | ||
Copyright (c) 2023 Eric Taylor | ||
Copyright (c) 2024 Eric Taylor | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
{ | ||
"name": "cvu", | ||
"description": "A tiny, performant, utility for constructing variant based CSS class strings.", | ||
"version": "0.4.0", | ||
"version": "1.0.0", | ||
"license": "MIT", | ||
@@ -9,3 +9,3 @@ "publishConfig": { | ||
}, | ||
"packageManager": "pnpm@8.5.1", | ||
"packageManager": "pnpm@8.15.5", | ||
"author": "Eric Taylor <eric@daxos.com> (https://github.com/erictaylor)", | ||
@@ -28,7 +28,7 @@ "repository": { | ||
], | ||
"type": "module", | ||
"exports": { | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.js", | ||
"import": "./dist/index.js", | ||
"default": "./dist/index.js" | ||
@@ -38,22 +38,20 @@ } | ||
"main": "dist/index.js", | ||
"module": "dist/index.mjs", | ||
"module": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
"dist/*.mjs", | ||
"dist/*.mjs.map", | ||
"dist/*.js", | ||
"dist/*.js.map", | ||
"dist/*.d.ts" | ||
"dist" | ||
], | ||
"dependencies": { | ||
"clsx": "^2.0.0" | ||
"clsx": "^2.1.0" | ||
}, | ||
"devDependencies": { | ||
"@biomejs/biome": "^1.3.1", | ||
"@size-limit/preset-small-lib": "^8.2.4", | ||
"cspell": "^7.3.8", | ||
"esbuild": "^0.19.2", | ||
"size-limit": "^8.2.4", | ||
"typescript": "^5.0.4", | ||
"vitest": "^0.34.1" | ||
"@biomejs/biome": "^1.6.3", | ||
"@commitlint/cli": "^19.2.1", | ||
"@commitlint/config-conventional": "^19.1.0", | ||
"@size-limit/preset-small-lib": "^11.1.2", | ||
"cspell": "^8.6.1", | ||
"lefthook": "^1.6.7", | ||
"size-limit": "^11.1.2", | ||
"typescript": "^5.4.3", | ||
"vitest": "^1.4.0" | ||
}, | ||
@@ -63,6 +61,2 @@ "size-limit": [ | ||
"path": "dist/index.js", | ||
"limit": "1 kB" | ||
}, | ||
{ | ||
"path": "dist/index.mjs", | ||
"limit": "600 B" | ||
@@ -73,13 +67,10 @@ } | ||
"scripts": { | ||
"build": "pnpm run build:lib && pnpm run build:dts", | ||
"build:dts": "tsc --project tsconfig.dts.json", | ||
"build:lib": "node bin/build.mjs", | ||
"build": "tsc --project tsconfig.build.json", | ||
"check": "biome check ./", | ||
"check:ci": "biome ci ./", | ||
"format": "biome format --write ./", | ||
"lint": "biome check ./", | ||
"size": "size-limit", | ||
"size:why": "size-limit --why", | ||
"test": "pnpm run test:biome && pnpm run test:vitest run", | ||
"test:biome": "biome ci ./src", | ||
"test:vitest": "vitest" | ||
"test": "vitest" | ||
} | ||
} |
@@ -7,2 +7,11 @@ <h1 align="center">cvu</h1> | ||
<p align="center"> | ||
<a href="https://jsr.io/@erictaylor/cvu"> | ||
<img src="https://jsr.io/badges/@erictaylor/cvu" alt="" /> | ||
</a> | ||
<a href="https://jsr.io/@erictaylor/cvu"> | ||
<img src="https://jsr.io/badges/@erictaylor/cvu/score" alt="" /> | ||
</a> | ||
</p> | ||
<br /> | ||
@@ -16,2 +25,4 @@ | ||
npm i cvu | ||
# or | ||
npx jsr add @erictaylor/cvu | ||
``` | ||
@@ -23,2 +34,4 @@ | ||
yarn add cvu | ||
# or | ||
yarn dlx jsr add @erictaylor/cvu | ||
``` | ||
@@ -29,5 +42,25 @@ | ||
```sh | ||
pnpm i cvu | ||
pnpm add cvu | ||
# or | ||
pnp dlx jsr add @erictaylor/cvu | ||
``` | ||
Bun: | ||
```sh | ||
bun add cvu | ||
# or | ||
bux jsr add @erictaylor/cvu | ||
``` | ||
Deno: | ||
```sh | ||
deno add @erictaylor/cvu | ||
``` | ||
> [!NOTE] | ||
> | ||
> This library is an ESM _only_ package as of version 1.0.0. | ||
### Tailwind CSS | ||
@@ -95,7 +128,7 @@ | ||
```tsx | ||
import { type ClassVariantUtility, config, cx } from "cvu"; | ||
import { type ClassVariantUtility, config, clsx } from "cvu"; | ||
import { twMerge } from "tailwind-merge"; | ||
export const cvu: ClassVariantUtility = config({ | ||
cx: (...inputs) => twMerge(cx(inputs)), | ||
clsx: (...inputs) => twMerge(clsx(inputs)), | ||
}); | ||
@@ -300,3 +333,3 @@ ``` | ||
```ts | ||
import { cvu, cx, type VariantProps } from "cvu"; | ||
import { cvu, clsx, type VariantProps } from "cvu"; | ||
@@ -320,3 +353,3 @@ /** | ||
({}: /* destructured props */ CardClassnamesProps = {}) => | ||
cx( | ||
clsx( | ||
boxClassnames({ | ||
@@ -356,9 +389,9 @@ /* … */ | ||
Allows you to provide your own underlying `cx` implementation or wrapping logic. | ||
Allows you to provide your own underlying `clsx` implementation or wrapping logic. | ||
```ts | ||
import { config, cx } from "cvu"; | ||
import { config, clsx } from "cvu"; | ||
export const customCvu = config({ | ||
cx: (...inputs) => twMerge(cx(inputs)), | ||
clsx: (...inputs) => twMerge(clsx(inputs)), | ||
}); | ||
@@ -365,0 +398,0 @@ ``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
325
0
409
Yes
25134
9
6
1
Updatedclsx@^2.1.0