import { describe, expect, test } from 'bun:test' import { makeGraph, pageId, tw } from './helpers' describe('Tailwind JSX layout classes', () => { test('spacing uses v4 multiplier (px / 4)', () => { const graph = makeGraph() const node = graph.createNode('RECTANGLE', pageId(graph), { width: 16, height: 2 }) const jsx = tw(graph, node.id) expect(jsx).toContain('w-4') expect(jsx).toContain('h-[2px]') }) test('non-standard spacing falls back to arbitrary value', () => { const graph = makeGraph() const node = graph.createNode('RECTANGLE', pageId(graph), { width: 37, height: 100 }) const jsx = tw(graph, node.id) expect(jsx).toContain('w-[37px]') expect(jsx).toContain('h-25') }) test('1px uses w-px', () => { const graph = makeGraph() const node = graph.createNode('RECTANGLE', pageId(graph), { width: 1, height: 1 }) const jsx = tw(graph, node.id) expect(jsx).toContain('w-px') expect(jsx).toContain('h-px') }) test('auto-layout frame → flex classes', () => { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { name: 'Row', width: 400, height: 100, layoutMode: 'HORIZONTAL', itemSpacing: 16, paddingTop: 12, paddingRight: 12, paddingBottom: 12, paddingLeft: 12, primaryAxisSizing: 'FIXED', counterAxisSizing: 'HUG' }) const jsx = tw(graph, frame.id) expect(jsx).toContain(' { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { width: 320, height: 200, layoutMode: 'VERTICAL', itemSpacing: 8, primaryAxisSizing: 'HUG', counterAxisSizing: 'FIXED' }) const jsx = tw(graph, frame.id) expect(jsx).toContain('flex ') expect(jsx).toContain('flex-col') expect(jsx).toContain('gap-2') expect(jsx).toContain('w-80') }) test('asymmetric padding', () => { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { width: 100, height: 100, layoutMode: 'HORIZONTAL', paddingTop: 8, paddingRight: 16, paddingBottom: 8, paddingLeft: 16, primaryAxisSizing: 'FIXED', counterAxisSizing: 'FIXED' }) const jsx = tw(graph, frame.id) expect(jsx).toContain('py-2') expect(jsx).toContain('px-4') expect(jsx).not.toContain('pt-') expect(jsx).not.toContain('pb-') }) test('justify and items alignment', () => { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { width: 100, height: 100, layoutMode: 'HORIZONTAL', primaryAxisAlign: 'CENTER', counterAxisAlign: 'CENTER', primaryAxisSizing: 'FIXED', counterAxisSizing: 'FIXED' }) const jsx = tw(graph, frame.id) expect(jsx).toContain('justify-center') expect(jsx).toContain('items-center') }) test('grow emits grow class', () => { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { width: 400, height: 100, layoutMode: 'HORIZONTAL', primaryAxisSizing: 'FIXED', counterAxisSizing: 'FIXED' }) const child = graph.createNode('RECTANGLE', frame.id, { width: 100, height: 50, layoutGrow: 1 }) const jsx = tw(graph, child.id) expect(jsx).toContain('grow') }) test('wrap emits flex-wrap', () => { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { width: 400, height: 400, layoutMode: 'HORIZONTAL', layoutWrap: 'WRAP', counterAxisSpacing: 12, primaryAxisSizing: 'FIXED', counterAxisSizing: 'FIXED' }) const jsx = tw(graph, frame.id) expect(jsx).toContain('flex-wrap') expect(jsx).toContain('gap-y-3') }) test('grid layout → grid + grid-cols + grid-rows', () => { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { name: 'Grid', width: 400, height: 300, layoutMode: 'GRID', gridTemplateColumns: [ { sizing: 'FR', value: 1 }, { sizing: 'FR', value: 1 }, { sizing: 'FR', value: 1 } ], gridTemplateRows: [ { sizing: 'FR', value: 1 }, { sizing: 'FR', value: 1 } ], gridColumnGap: 16, gridRowGap: 8, paddingTop: 12, paddingRight: 12, paddingBottom: 12, paddingLeft: 12 }) const jsx = tw(graph, frame.id) expect(jsx).toContain('grid ') expect(jsx).toContain('grid-cols-3') expect(jsx).toContain('grid-rows-2') expect(jsx).toContain('gap-x-4') expect(jsx).toContain('gap-y-2') expect(jsx).toContain('p-3') expect(jsx).not.toContain('flex') }) test('grid with mixed tracks uses arbitrary value', () => { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { width: 600, height: 400, layoutMode: 'GRID', gridTemplateColumns: [ { sizing: 'FIXED', value: 200 }, { sizing: 'FR', value: 1 }, { sizing: 'AUTO', value: 0 } ], gridTemplateRows: [], gridColumnGap: 0, gridRowGap: 0 }) const jsx = tw(graph, frame.id) expect(jsx).toContain('grid-cols-[200px_1fr_auto]') expect(jsx).not.toContain('grid-rows') }) test('grid child placement → col-start/row-start/col-span', () => { const graph = makeGraph() const frame = graph.createNode('FRAME', pageId(graph), { width: 400, height: 300, layoutMode: 'GRID', gridTemplateColumns: [ { sizing: 'FR', value: 1 }, { sizing: 'FR', value: 1 } ], gridTemplateRows: [ { sizing: 'FR', value: 1 }, { sizing: 'FR', value: 1 } ], gridColumnGap: 0, gridRowGap: 0 }) const child = graph.createNode('RECTANGLE', frame.id, { name: 'Span', width: 100, height: 50, gridPosition: { column: 1, row: 2, columnSpan: 2, rowSpan: 1 } }) const jsx = tw(graph, child.id) expect(jsx).toContain('col-start-1') expect(jsx).toContain('row-start-2') expect(jsx).toContain('col-span-2') expect(jsx).not.toContain('row-span') }) })