* feat(demo): rebuild the first page as a component library with staged loading The demo generated its document behind an empty canvas with no progress, and the first page still carried a legacy library in a dark section that matched neither the current showcase nor the rest of the demo. Drive the existing editor preparation from demo generation so the canvas overlay and tab indicator report the real phases and progress, and rebuild the first page around a component library authored in the current style: a Button component set with two variants, linked instances, text and boolean component properties, and the variable collections. The deleted effects, typography, and app-preview examples are already covered by pages 02 and 03. * fix(demo): record demo generation failures as preparation failures Demo generation reported a thrown error as a cancellation, because the catch only warned and the trailing finally always cancelled the handle. Report the failure through the preparation handle so diagnostics distinguish a broken demo build from an abandoned one. The finally needs no failure guard: failing clears the handle, so the following cancel already returns early, as the preparation controller test asserts. * fix(demo): roll back an abandoned demo build A preparation that superseded the demo's handle — a page switch, a font retry, or a closed tab — left the document half-built: the first page stayed renamed, the extra pages and sections remained, and the one-page precondition then blocked any later attempt in that session. Track what the build creates and remove it whenever the build does not finish, restoring the original page name and clearing the variables it added. The cleanup is guarded by graph identity because node and page IDs are only unique within one graph, so a document that replaced the demo is never touched. Splitting the build into its own function keeps the entry point to orchestration and stays within the complexity budget.
42 lines
1.5 KiB
TypeScript
42 lines
1.5 KiB
TypeScript
import { describe, expect, test } from 'bun:test'
|
|
|
|
import { createTypographySection } from '@/app/demo/typography/section'
|
|
import { createEditorStore } from '@/app/editor/session'
|
|
|
|
describe('demo document', () => {
|
|
test('showcases OpenType features and native text decorations', async () => {
|
|
const store = createEditorStore()
|
|
const page = store.graph.addPage('Typography')
|
|
|
|
await createTypographySection(store.graph, page.id)
|
|
|
|
const nodes = [...store.graph.getAllNodes()]
|
|
const sample = (name: string) =>
|
|
nodes.find((node) => node.name === name && node.type === 'TEXT')
|
|
|
|
expect(sample('Discretionary ligatures / DLIG ON')?.fontFeatures).toEqual([
|
|
{ tag: 'DLIG', enabled: true }
|
|
])
|
|
expect(sample('Discretionary ligatures / DLIG OFF')?.fontFeatures).toEqual([
|
|
{ tag: 'DLIG', enabled: false }
|
|
])
|
|
expect(sample('Tabular and proportional figures / TNUM ON · PNUM OFF')?.fontFeatures).toEqual([
|
|
{ tag: 'TNUM', enabled: true },
|
|
{ tag: 'PNUM', enabled: false }
|
|
])
|
|
|
|
expect(sample('Wavy underline')).toMatchObject({
|
|
textDecoration: 'UNDERLINE',
|
|
textDecorationStyle: 'WAVY',
|
|
textDecorationThickness: 1.6
|
|
})
|
|
expect(sample('Wavy underline')?.textDecorationFills[0]?.type).toBe('SOLID')
|
|
expect(sample('Dotted underline')).toMatchObject({
|
|
textDecoration: 'UNDERLINE',
|
|
textDecorationStyle: 'DOTTED',
|
|
textDecorationThickness: 2
|
|
})
|
|
expect(sample('Dotted underline')?.textDecorationFills[0]?.type).toBe('SOLID')
|
|
})
|
|
})
|