From f4c95d5ea6443eb3e89c0b61133d1920307ac482 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Sat, 18 Apr 2026 15:49:24 +0300 Subject: [PATCH] feat: add cn utility to shared/lib --- src/shared/lib/cn.test.ts | 34 ++++++++++++++++++++++++++++++++++ src/shared/lib/cn.ts | 9 +++++++++ src/shared/lib/index.ts | 1 + 3 files changed, 44 insertions(+) create mode 100644 src/shared/lib/cn.test.ts create mode 100644 src/shared/lib/cn.ts create mode 100644 src/shared/lib/index.ts diff --git a/src/shared/lib/cn.test.ts b/src/shared/lib/cn.test.ts new file mode 100644 index 0000000..dc8d082 --- /dev/null +++ b/src/shared/lib/cn.test.ts @@ -0,0 +1,34 @@ +import { describe, it, expect } from 'vitest' +import { cn } from './cn' + +describe('cn', () => { + describe('basic merging', () => { + it('returns single class unchanged', () => { + expect(cn('foo')).toBe('foo') + }) + + it('joins multiple classes', () => { + expect(cn('foo', 'bar')).toBe('foo bar') + }) + }) + + describe('conditional classes', () => { + it('includes truthy conditional', () => { + expect(cn('foo', true && 'bar')).toBe('foo bar') + }) + + it('excludes falsy conditional', () => { + expect(cn('foo', false && 'bar')).toBe('foo') + }) + }) + + describe('tailwind conflict resolution', () => { + it('last padding wins', () => { + expect(cn('px-2', 'px-4')).toBe('px-4') + }) + + it('last text color wins', () => { + expect(cn('text-red-500', 'text-blue-500')).toBe('text-blue-500') + }) + }) +}) diff --git a/src/shared/lib/cn.ts b/src/shared/lib/cn.ts new file mode 100644 index 0000000..bcf5736 --- /dev/null +++ b/src/shared/lib/cn.ts @@ -0,0 +1,9 @@ +import { clsx, type ClassValue } from 'clsx' +import { twMerge } from 'tailwind-merge' + +/** + * Merges Tailwind classes, resolving conflicts in favor of the last value. + */ +export function cn(...inputs: ClassValue[]): string { + return twMerge(clsx(inputs)) +} diff --git a/src/shared/lib/index.ts b/src/shared/lib/index.ts new file mode 100644 index 0000000..28b7438 --- /dev/null +++ b/src/shared/lib/index.ts @@ -0,0 +1 @@ +export { cn } from './cn'