openpencil/tests/engine/layout/auto-layout/nested/basic.test.ts

157 lines
4.5 KiB
TypeScript

import { describe, expect, test } from 'bun:test'
import { computeAllLayouts, computeLayout, SceneGraph } from '@open-pencil/core'
import { getNodeOrThrow } from '#tests/helpers/assert'
import { autoFrame, pageId, rect } from '#tests/helpers/layout'
describe('nested auto layout', () => {
test('nested horizontal frames', () => {
const graph = new SceneGraph()
const outer = autoFrame(graph, pageId(graph), {
width: 500,
height: 200,
itemSpacing: 10
})
const inner = autoFrame(graph, outer.id, {
primaryAxisSizing: 'HUG',
counterAxisSizing: 'FIXED',
width: 999,
height: 100,
itemSpacing: 5
})
rect(graph, inner.id, 40, 40)
rect(graph, inner.id, 60, 40)
rect(graph, outer.id, 80, 80)
computeLayout(graph, outer.id)
const innerNode = getNodeOrThrow(graph, inner.id)
expect(innerNode.width).toBe(105)
expect(innerNode.x).toBe(0)
const outerChildren = graph.getChildren(outer.id)
expect(outerChildren[1].x).toBe(115)
})
test('nested vertical inside horizontal', () => {
const graph = new SceneGraph()
const outer = autoFrame(graph, pageId(graph), {
width: 500,
height: 300,
itemSpacing: 20
})
const inner = autoFrame(graph, outer.id, {
layoutMode: 'VERTICAL',
primaryAxisSizing: 'HUG',
counterAxisSizing: 'FIXED',
width: 100,
height: 999,
itemSpacing: 10
})
rect(graph, inner.id, 80, 50)
rect(graph, inner.id, 80, 70)
rect(graph, outer.id, 60, 60)
computeLayout(graph, outer.id)
const innerNode = getNodeOrThrow(graph, inner.id)
expect(innerNode.height).toBe(130)
const outerChildren = graph.getChildren(outer.id)
expect(outerChildren[0].x).toBe(0)
expect(outerChildren[1].x).toBe(120)
})
test('computeAllLayouts handles deeply nested frames', () => {
const graph = new SceneGraph()
const page = pageId(graph)
const outer = autoFrame(graph, page, {
layoutMode: 'VERTICAL',
width: 300,
height: 500,
itemSpacing: 10
})
const middle = autoFrame(graph, outer.id, {
layoutMode: 'HORIZONTAL',
primaryAxisSizing: 'HUG',
counterAxisSizing: 'HUG',
width: 999,
height: 999,
itemSpacing: 5
})
rect(graph, middle.id, 40, 30)
rect(graph, middle.id, 60, 30)
rect(graph, outer.id, 100, 50)
computeAllLayouts(graph)
const middleNode = getNodeOrThrow(graph, middle.id)
expect(middleNode.width).toBe(105)
expect(middleNode.height).toBe(30)
const outerChildren = graph.getChildren(outer.id)
expect(outerChildren[0].y).toBe(0)
expect(outerChildren[1].y).toBe(40)
})
test('computeAllLayouts preserves fixed children inside instances', () => {
const graph = new SceneGraph()
const page = pageId(graph)
const outer = autoFrame(graph, page, {
width: 500,
height: 300,
paddingTop: 20,
paddingBottom: 20
})
const instance = graph.createNode('INSTANCE', outer.id, {
width: 120,
height: 120,
layoutMode: 'HORIZONTAL',
primaryAxisSizing: 'FIXED',
counterAxisSizing: 'FIXED',
paddingTop: 20,
paddingBottom: 20
})
graph.updateNode(instance.id, { source: { ...instance.source, format: 'fig' } })
const fixedChild = autoFrame(graph, instance.id, {
width: 80,
height: 80,
paddingTop: 1665,
paddingBottom: 1665
})
computeAllLayouts(graph, page)
const childNode = getNodeOrThrow(graph, fixedChild.id)
expect(childNode.height).toBe(80)
expect(childNode.y).toBe(0)
})
test('computeAllLayouts relayouts user-created instance children', () => {
const graph = new SceneGraph()
const page = pageId(graph)
const component = graph.createNode('COMPONENT', page, {
layoutMode: 'VERTICAL',
primaryAxisSizing: 'FIXED',
counterAxisSizing: 'FIXED',
width: 100,
height: 100,
counterAxisAlign: 'STRETCH',
paddingLeft: 10,
paddingRight: 10
})
rect(graph, component.id, 80, 20, { layoutAlignSelf: 'STRETCH' })
const outer = autoFrame(graph, page, { width: 300, height: 150 })
const instance = graph.createInstance(component.id, outer.id, { width: 200, height: 100 })
if (!instance) throw new Error('Expected instance creation to succeed')
const instanceChild = graph.getChildren(instance.id)[0]
computeAllLayouts(graph, page)
const childNode = getNodeOrThrow(graph, instanceChild.id)
expect(childNode.x).toBe(10)
expect(childNode.width).toBe(180)
})
})