feat(shared): add cn utility for tailwind-aware class merging #38
@@ -39,6 +39,7 @@ export {
|
||||
export {
|
||||
buildQueryString,
|
||||
clampNumber,
|
||||
cn,
|
||||
debounce,
|
||||
getDecimalPlaces,
|
||||
roundToStepPrecision,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import {
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
} from 'vitest';
|
||||
import { cn } from './cn';
|
||||
|
||||
describe('cn utility', () => {
|
||||
it('should merge classes with clsx', () => {
|
||||
expect(cn('class1', 'class2')).toBe('class1 class2');
|
||||
expect(cn('class1', { class2: true, class3: false })).toBe('class1 class2');
|
||||
});
|
||||
|
||||
it('should resolve tailwind specificity conflicts', () => {
|
||||
// text-neutral-400 vs text-brand (text-brand should win)
|
||||
expect(cn('text-neutral-400', 'text-brand')).toBe('text-brand');
|
||||
|
||||
// p-4 vs p-2
|
||||
expect(cn('p-4', 'p-2')).toBe('p-2');
|
||||
|
||||
// dark mode classes should be handled correctly too
|
||||
expect(cn('text-neutral-400 dark:text-neutral-400', 'text-brand dark:text-brand')).toBe(
|
||||
'text-brand dark:text-brand',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle undefined and null inputs', () => {
|
||||
expect(cn('class1', undefined, null, 'class2')).toBe('class1 class2');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import {
|
||||
type ClassValue,
|
||||
clsx,
|
||||
} from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
/**
|
||||
* Utility for merging Tailwind classes with clsx and tailwind-merge.
|
||||
* This resolves specificity conflicts between Tailwind classes.
|
||||
*/
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
@@ -15,6 +15,7 @@ export {
|
||||
type QueryParamValue,
|
||||
} from './buildQueryString/buildQueryString';
|
||||
export { clampNumber } from './clampNumber/clampNumber';
|
||||
export { cn } from './cn';
|
||||
export { debounce } from './debounce/debounce';
|
||||
export { getDecimalPlaces } from './getDecimalPlaces/getDecimalPlaces';
|
||||
export { getSkeletonWidth } from './getSkeletonWidth/getSkeletonWidth';
|
||||
|
||||
Reference in New Issue
Block a user