openpencil/packages/dom-css/tests/import/jsx.test.tsx
Danila Poyarkov 00361313d1
refactor(dom-css): group sources into import, export, and runtime (#789)
* refactor(dom-css): group sources into import, export, and runtime

dom-css kept both conversion directions in one flat folder: HTML and CSS
import next to SceneGraph export, a JSX runtime next to the Tailwind JSX
printer, and CSS parsing and formatting in one file.

Sources now live in `import/`, `export/`, and `runtime/`, with the CSS
value helpers split by direction and `export/index.ts` as the `./export`
entry. Tests mirror the new folders. Public entry points are unchanged.

* docs(dom-css): add a package guide for the import, export, and runtime layout

dom-css had no AGENTS.md. The guide records the source layout, the
scene-graph-only dependency, the browser-safe `./export` entry, printed
code generation, and Base64 validation for imported documents, and the
root map links to it.
2026-09-30 09:44:52 +04:00

96 lines
2.9 KiB
TypeScript

/** @jsxImportSource @open-pencil/dom-css */
import { describe, expect, it } from 'bun:test'
import {
createHeadlessCSSRuntime,
jsxToDesignDocument,
jsxToSceneGraph,
serializeHTML,
tailwindJSXToSceneGraph
} from '#dom-css/index'
import { tailwindCardClasses } from '../helpers'
function CardTitle(props: { children?: string }) {
return <h1 class="title">{props.children}</h1>
}
describe('@open-pencil/dom-css JSX', () => {
it('converts JSX elements into DesignDOM documents', async () => {
const document = await jsxToDesignDocument(
<article class="card" data-id="card-1" style={{ width: '320px', backgroundColor: 'white' }}>
<CardTitle>OpenPencil</CardTitle>
<p style="font-size: 14px; line-height: 20px">Design with JSX-shaped DOM.</p>
</article>
)
const card = document.children[0]
expect(card?.type).toBe('element')
if (card?.type !== 'element') return
expect(card.tagName).toBe('article')
expect(card.attrs.class).toBe('card')
expect(card.attrs['data-id']).toBe('card-1')
expect(card.inlineStyle?.width).toBe('320px')
expect(card.inlineStyle?.['background-color']).toBe('white')
expect(serializeHTML(document)).toContain('Design with JSX-shaped DOM.')
})
it('runs JSX through CSS runtime styles before scene graph conversion', async () => {
const graph = await jsxToSceneGraph(
<article class="card">
<h1 class="title">OpenPencil</h1>
</article>,
{
runtime: createHeadlessCSSRuntime(),
cssText: `
.card {
display: flex;
flex-direction: column;
gap: 12px;
width: 320px;
height: 160px;
padding: 24px;
background: white;
}
.title {
font-size: 24px;
font-weight: 700;
line-height: 32px;
}
`
}
)
const page = graph.getPages()[0]
const card = page ? graph.getChildren(page.id)[0] : undefined
expect(card?.type).toBe('FRAME')
if (card?.type !== 'FRAME') return
expect(card.width).toBe(320)
expect(card.height).toBe(160)
expect(card.layoutMode).toBe('VERTICAL')
expect(card.paddingLeft).toBe(24)
const title = graph.getChildren(card.id)[0]
expect(title?.type).toBe('TEXT')
expect(title?.fontSize).toBe(24)
})
it('feeds JSX Tailwind classes through generated CSS', async () => {
const classes = [...tailwindCardClasses]
const graph = await tailwindJSXToSceneGraph(
<article class={classes.join(' ')}>
<h1>OpenPencil</h1>
</article>,
classes,
{ runtime: createHeadlessCSSRuntime() }
)
const page = graph.getPages()[0]
const card = page ? graph.getChildren(page.id)[0] : undefined
expect(card?.type).toBe('FRAME')
expect(card?.width).toBe(320)
expect(card?.height).toBe(176)
expect(card?.itemSpacing).toBe(12)
})
})