diff --git a/package.json b/package.json index 6cfa7ae..527f8ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lumyx/ui", - "version": "0.2.0", + "version": "0.3.0", "description": "The Lumyx design system: React components and Tailwind CSS v4 tokens.", "license": "MIT", "author": "Mathieu Chambaud", diff --git a/scripts/verify-ds.mjs b/scripts/verify-ds.mjs index 2d6d8fa..fdfb321 100644 --- a/scripts/verify-ds.mjs +++ b/scripts/verify-ds.mjs @@ -124,6 +124,39 @@ for (const size of uniqueScale) { } } +// 7-9. Les namespaces par defaut de Tailwind restent actifs (styles.css ne les remet pas a +// zero) : rien n'empeche a la compilation un `text-sm`, un `bg-white` ou un `duration-300`. +// Ces regles ferment la porte cote source. +const CODE_FILES = files.filter((f) => ['.ts', '.tsx', '.js'].includes(extname(f))); +function scanClasses(rule, pattern, accept = () => false) { + for (const f of CODE_FILES) { + readFileSync(f, 'utf8') + .split('\n') + .forEach((line, i) => { + for (const m of line.matchAll(pattern)) { + if (!accept(m)) fail(rule, `${rel(f)}:${i + 1} — ${m[0]}`); + } + }); + } +} + +// 7. Taille de texte sur l'echelle numerique (text-11 … text-44), jamais l'echelle Tailwind. +scanClasses('type-scale', /(? DURATIONS.has(m[1])); + if (failures.length) { console.error(`\n✗ ${failures.length} violation(s) des contraintes du design system\n`); failures.forEach((f) => console.error(' ' + f)); diff --git a/scripts/verify-ds.test.mjs b/scripts/verify-ds.test.mjs index 4949e9e..b38e9be 100644 --- a/scripts/verify-ds.test.mjs +++ b/scripts/verify-ds.test.mjs @@ -61,3 +61,47 @@ describe('verify-ds regle 2 — monospace par token', () => { expect(proc.exitCode).toBe(0); }); }); + +describe('verify-ds regle 7 — echelle typographique', () => { + test('accepte l echelle numerique', () => { + expect(runWith('export const A = () =>
;\n').code).toBe(0); + }); + + test('refuse l echelle Tailwind par defaut', () => { + const { code, output } = runWith('export const A = () => ;\n'); + expect(code).toBe(1); + expect(output).toContain('type-scale'); + }); +}); + +describe('verify-ds regle 8 — couleurs par token', () => { + test('accepte les utilitaires semantiques', () => { + expect(runWith('export const A = () => ;\n').code).toBe(0); + }); + + test('refuse black / white', () => { + const { code, output } = runWith('export const A = () => ;\n'); + expect(code).toBe(1); + expect(output).toContain('no-raw-palette'); + }); + + test('refuse la palette Tailwind par defaut', () => { + expect(runWith('export const A = () => ;\n').code).toBe(1); + }); +}); + +describe('verify-ds regle 9 — durees de motion', () => { + test('accepte 120 / 180 / 260', () => { + expect(runWith('export const A = () => ;\n').code).toBe(0); + }); + + test('refuse une duree hors systeme', () => { + const { code, output } = runWith('export const A = () => ;\n'); + expect(code).toBe(1); + expect(output).toContain('motion-duration'); + }); + + test('refuse une valeur arbitraire', () => { + expect(runWith('export const A = () => ;\n').code).toBe(1); + }); +}); diff --git a/src/components/lumyx/peer-card.tsx b/src/components/lumyx/peer-card.tsx index 816f1e3..714cc26 100644 --- a/src/components/lumyx/peer-card.tsx +++ b/src/components/lumyx/peer-card.tsx @@ -16,7 +16,7 @@ export type Peer = { /** Peers are indigo. Rooms and sessions are coral. They are never blended. */ export function PeerCard({ peer, className }: { peer: Peer; className?: string }) { return ( -