154 lines
4 KiB
TypeScript
154 lines
4 KiB
TypeScript
import { describe, expect, test } from 'bun:test'
|
|
|
|
import { computeAllLayouts } from '@open-pencil/core/layout'
|
|
import { parsePenFile, parseSize, type PenDocument, type PenNode } from '@open-pencil/pen'
|
|
|
|
function parseLayoutDocument(children: PenNode[]) {
|
|
const document: PenDocument = { version: '2.17', children }
|
|
const graph = parsePenFile(JSON.stringify(document))
|
|
computeAllLayouts(graph)
|
|
return graph
|
|
}
|
|
|
|
function fixedChild(id: string): PenNode {
|
|
return { id, type: 'frame', width: 620, height: 420 }
|
|
}
|
|
|
|
describe('parsePenFile — Pen layout defaults (#564)', () => {
|
|
test('treats an omitted frame layout as horizontal', () => {
|
|
const graph = parseLayoutDocument([
|
|
{
|
|
id: 'screen',
|
|
type: 'frame',
|
|
width: 1440,
|
|
layout: 'vertical',
|
|
children: [
|
|
{
|
|
id: 'section',
|
|
type: 'frame',
|
|
width: 'fill_container',
|
|
gap: 56,
|
|
padding: [72, 80],
|
|
alignItems: 'center',
|
|
children: [
|
|
fixedChild('fixed'),
|
|
{
|
|
id: 'fill',
|
|
type: 'frame',
|
|
width: 'fill_container',
|
|
height: 420
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
])
|
|
|
|
expect(graph.getNode('section')).toMatchObject({
|
|
layoutMode: 'HORIZONTAL',
|
|
width: 1440,
|
|
height: 564,
|
|
paddingTop: 72,
|
|
paddingRight: 80,
|
|
paddingBottom: 72,
|
|
paddingLeft: 80
|
|
})
|
|
expect(graph.getNode('fixed')).toMatchObject({ x: 80, y: 72, width: 620, height: 420 })
|
|
expect(graph.getNode('fill')).toMatchObject({ x: 756, y: 72, width: 604, height: 420 })
|
|
})
|
|
|
|
test.each(['fit_content', 'fit_content(100)'])('maps %s to HUG sizing', (height) => {
|
|
const graph = parseLayoutDocument([
|
|
{
|
|
id: 'section',
|
|
type: 'frame',
|
|
width: 1440,
|
|
height,
|
|
layout: 'horizontal',
|
|
padding: [72, 80],
|
|
children: [fixedChild('fixed')]
|
|
}
|
|
])
|
|
|
|
expect(graph.getNode('section')).toMatchObject({
|
|
counterAxisSizing: 'HUG',
|
|
height: 564
|
|
})
|
|
})
|
|
|
|
test('uses the parameterized fit-content value when a frame has no content', () => {
|
|
const graph = parseLayoutDocument([
|
|
{
|
|
id: 'empty',
|
|
type: 'frame',
|
|
width: 'fit_content(240)',
|
|
height: 'fit_content(120)'
|
|
}
|
|
])
|
|
|
|
expect(graph.getNode('empty')).toMatchObject({
|
|
layoutMode: 'HORIZONTAL',
|
|
primaryAxisSizing: 'HUG',
|
|
counterAxisSizing: 'HUG',
|
|
width: 240,
|
|
height: 120,
|
|
minWidth: 240,
|
|
minHeight: 120
|
|
})
|
|
})
|
|
|
|
test('ignores the parameterized fallback when content determines the size', () => {
|
|
const graph = parseLayoutDocument([
|
|
{
|
|
id: 'content-frame',
|
|
type: 'frame',
|
|
width: 'fit_content(240)',
|
|
height: 'fit_content(120)',
|
|
padding: 10,
|
|
children: [{ id: 'content', type: 'frame', width: 20, height: 30 }]
|
|
}
|
|
])
|
|
|
|
expect(graph.getNode('content-frame')).toMatchObject({
|
|
width: 40,
|
|
height: 50,
|
|
minWidth: null,
|
|
minHeight: null
|
|
})
|
|
})
|
|
|
|
test('keeps explicit freeform frames out of auto-layout', () => {
|
|
const graph = parseLayoutDocument([
|
|
{
|
|
id: 'freeform',
|
|
type: 'frame',
|
|
layout: 'none',
|
|
children: [fixedChild('fixed')]
|
|
}
|
|
])
|
|
|
|
expect(graph.getNode('freeform')?.layoutMode).toBe('NONE')
|
|
})
|
|
})
|
|
|
|
describe('parseSize — Pen sizing fallbacks (#564)', () => {
|
|
test('preserves parameterized fill-container fallback values', () => {
|
|
expect(parseSize('fill_container(900)', 100)).toEqual({ value: 900, sizing: 'FILL' })
|
|
})
|
|
|
|
test('preserves parameterized fit-content fallback metadata', () => {
|
|
expect(parseSize('fit_content(900)', 100)).toEqual({
|
|
value: 900,
|
|
sizing: 'HUG',
|
|
fitContentFallback: 900
|
|
})
|
|
})
|
|
|
|
test.each(['fit_content()', 'fit_content(nope)', 'fit_content(100)garbage'])(
|
|
'rejects malformed sizing behavior %s',
|
|
(value) => {
|
|
expect(parseSize(value, 100)).toEqual({ value: 100, sizing: 'FIXED' })
|
|
}
|
|
)
|
|
})
|