openpencil/packages/dom-css/tests/export/bundle/tokens.test.ts
Danila Poyarkov fb0cb9ee5f
feat: write variable-bound properties as tokens in exported code (#895)
* feat: write variable-bound properties as tokens in exported code

HTML and Tailwind JSX export reference the design tokens a layer is bound to, var(--color-primary) or bg-primary, instead of baking in their values. A binding becomes a reference only where the stylesheet resolves it as the canvas draws it: the layer still draws the value, the token's unit fits the property, and an attribute such as data-theme="dark" can put the element in the layer's mode. Standalone HTML includes the stylesheet for the tokens it uses, compiled into Tailwind's @theme for Tailwind pages.

* refactor: share the collection variable list and tighten token helpers

Read every variable in collection order through one collectionVariables helper built on es-toolkit's compact, used by the stylesheet and the token references, and map padding sides and color channels instead of repeating them.
2026-10-05 09:15:44 +00:00

39 lines
1.5 KiB
TypeScript

import { describe, expect, test } from 'bun:test'
import { exportHTMLBundle, sceneNodeToDesignDocument } from '#dom-css/export/index'
import { BLUE_500, card, designSystem } from '../token-fixtures'
async function standalone(style: 'inline' | 'tailwind') {
const graph = designSystem()
const frame = card(graph, graph.getPages()[0].id, BLUE_500)
const bundle = await exportHTMLBundle(sceneNodeToDesignDocument(graph, frame.id), {
html: 'standalone',
style
})
const page = bundle.files.find((file) => file.path === bundle.entrypoint)
if (typeof page?.content !== 'string') throw new Error('Expected an HTML page')
return page.content
}
describe('token stylesheet in standalone HTML', () => {
test('declares the tokens the page uses and the variables their aliases reach', async () => {
const html = await standalone('inline')
expect(html).toContain('--color-primary: var(--color-blue-500);')
expect(html).toContain('--spacing-gutter: 24px;')
// Dark points Primary at Blue/300, so its scope needs Blue/300 even though no layer is dark.
expect(html).toContain('--color-blue-300: #94C4FC;')
expect(html).toContain('[data-theme="dark"]')
expect(html).not.toContain('--count')
})
test('compiles token utilities into Tailwind pages', async () => {
const html = await standalone('tailwind')
expect(html).toMatch(/class="[^"]*\bbg-primary\b/)
expect(html).toMatch(/\.bg-primary\s*\{\s*background-color: var\(--color-primary\)/)
expect(html).toContain('--color-primary: var(--color-blue-500);')
})
})