import { describe, it, expect } from 'vitest'; import { generate } from '../generate.js'; import type { ScaffoldUiPrimitivesInput } from '../types.js'; /** * Typographic-scale parity (client defect 2026-08-25 — "les cellules d'un * tableau sont plus grosses que ses en-têtes", extended to every typed * surface). The UI chrome — labels, dropdown options, buttons (`.btn` in the * package fixes 0.875rem), table headers — reads at text-sm; the theme sets * NO font-size on html/body, so anything without an explicit class inherits * the 16px browser default. Every data cell and every surface the user types * into must therefore carry text-sm explicitly, matching its own label and * its own suggestion list. (The iOS focus-zoom fallback for touch lives in * scaffold-theme: `@media (pointer: coarse)` bumps text-sm fields to 1rem.) */ function files() { const input: ScaffoldUiPrimitivesInput = { projectPath: '/tmp/web', appCode: 'crm', force: false }; return generate(input); } const contentOf = (name: string) => { const f = files().find((x) => x.path === `src/components/ui/${name}`); expect(f, `missing ${name}`).toBeDefined(); return f!.content; }; describe('scaffold-ui-primitives / font scale — DataTable header/cell parity', () => { it('column and BOTH emissions (data + skeleton) share text-sm', () => { const c = contentOf('DataTable.tsx'); // Header keeps its scale… expect(c).toMatch(/text-sm font-medium text-\[var\(--table-header-text\)\]/); // …and the two cell templates now carry the SAME scale (data + skeleton): const cellSites = c.match(/\$\{cellPadding\} text-sm/g) ?? []; expect(cellSites.length).toBeGreaterThanOrEqual(2); // No column template is left without a size (the historical defect: // cells inherited the 16px body default under 14px headers). expect(c).not.toMatch(/\$\{cellPadding\} \$\{getResponsiveHideClass/); expect(c).not.toMatch(/\$\{cellPadding\} text-\$\{getEffectiveAlign/); }); it('the built-in search box types at the chrome scale', () => { const c = contentOf('DataTable.tsx'); expect(c).toContain('className="input text-sm w-full pl-10 pr-10"'); }); }); describe('scaffold-ui-primitives / font scale — typed surfaces match their labels', () => { const cases: Array<[file: string, anchor: RegExp]> = [ // Each primitive's input/trigger carries text-sm — the same scale as its // own text-sm label above and its own text-sm option list below. ['EntityLookup.tsx', /pl-3 pr-16 py-2 text-sm rounded-\[var\(--radius-input/], ['DateInput.tsx', /pl-3 pr-16 py-2 text-sm rounded-\[var\(--radius-input/], ['EnumSelect.tsx', /pl-3 pr-9 py-2 text-sm text-left rounded-\[var\(--radius-input/], ['MultiSelect.tsx', /pl-2 pr-9 py-1\.5 text-sm cursor-pointer rounded-\[var\(--radius-input/], ['Textarea.tsx', /px-3 py-2 text-sm resize-none/], ]; for (const [file, anchor] of cases) { it(`${file} input/trigger carries text-sm`, () => { expect(contentOf(file)).toMatch(anchor); }); } });