feat(shared/lib): add cn utility (clsx + tailwind-merge)
This commit is contained in:
@@ -52,5 +52,9 @@
|
|||||||
"@storybook/addon-docs": "^10.2.16",
|
"@storybook/addon-docs": "^10.2.16",
|
||||||
"playwright": "^1.58.2",
|
"playwright": "^1.58.2",
|
||||||
"@vitest/browser-playwright": "^4.0.18"
|
"@vitest/browser-playwright": "^4.0.18"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"tailwind-merge": "^3.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/shared/lib/cn.test.ts
Normal file
16
src/shared/lib/cn.test.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { cn } from './cn';
|
||||||
|
|
||||||
|
describe('cn', () => {
|
||||||
|
it('merges class strings', () => {
|
||||||
|
expect(cn('foo', 'bar')).toBe('foo bar');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('deduplicates conflicting Tailwind classes (last wins)', () => {
|
||||||
|
expect(cn('p-4', 'p-8')).toBe('p-8');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ignores falsy values', () => {
|
||||||
|
expect(cn('foo', false, undefined, null, 'bar')).toBe('foo bar');
|
||||||
|
});
|
||||||
|
});
|
||||||
7
src/shared/lib/cn.ts
Normal file
7
src/shared/lib/cn.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { clsx, type ClassValue } from 'clsx';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
/** Merge Tailwind classes without conflicts. Later classes win on collision. */
|
||||||
|
export function cn(...inputs: ClassValue[]): string {
|
||||||
|
return twMerge(clsx(inputs));
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
export * from './api';
|
export * from './api';
|
||||||
|
export { cn } from './cn';
|
||||||
|
|||||||
34
vitest.unit.config.ts
Normal file
34
vitest.unit.config.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||||
|
import { defineConfig } from "vitest/config";
|
||||||
|
|
||||||
|
const dirname =
|
||||||
|
typeof __dirname !== "undefined"
|
||||||
|
? __dirname
|
||||||
|
: path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
svelte({
|
||||||
|
hot: !process.env.VITEST,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: "jsdom",
|
||||||
|
setupFiles: ["./src/tests/setup.ts"],
|
||||||
|
include: ["src/**/*.{test,spec}.{js,ts}"],
|
||||||
|
exclude: ["src/tests/e2e/**/*.{test,spec}.{js,ts}"],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
$lib: path.resolve("./src/lib"),
|
||||||
|
$shared: path.resolve("./src/shared"),
|
||||||
|
$pages: path.resolve("./src/pages"),
|
||||||
|
$features: path.resolve("./src/features"),
|
||||||
|
$entities: path.resolve("./src/entities"),
|
||||||
|
$widgets: path.resolve("./src/widgets"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user