instance.swapComponent(component) points an instance at another component, as in Figma, through the graph's shared swap that the editor's variant picker uses. It asserts editability, so an instance inside a read-only library definition cannot be swapped, and joins the instance surface check against @figma/plugin-typings.
103 lines
4.1 KiB
TypeScript
103 lines
4.1 KiB
TypeScript
import { describe, expect, test } from 'bun:test'
|
|
|
|
import {
|
|
assertNodeEditable,
|
|
getNodeEditCapability,
|
|
ReadOnlyLibraryDefinitionError
|
|
} from '@open-pencil/core/editor'
|
|
import { FigmaAPI } from '@open-pencil/core/figma-api'
|
|
import { updateNode } from '@open-pencil/core/tools/modify'
|
|
import { SceneGraph } from '@open-pencil/scene-graph'
|
|
|
|
describe('library definition capabilities', () => {
|
|
test('protects materialized definitions and descendants but not their instances', async () => {
|
|
const graph = new SceneGraph()
|
|
const page = graph.getPages()[0]
|
|
const component = graph.createNode('COMPONENT', page.id, {
|
|
name: 'Remote button',
|
|
librarySource: {
|
|
identity: { libraryId: 'design-system', assetKey: 'button', revisionId: 'r1' },
|
|
sourceNodeId: 'source',
|
|
readOnly: true
|
|
}
|
|
})
|
|
const child = graph.createNode('TEXT', component.id, { name: 'Label', text: 'Button' })
|
|
const instance = graph.createInstance(component.id, page.id)
|
|
if (!instance) throw new Error('Expected instance')
|
|
|
|
expect(getNodeEditCapability(graph, child.id)).toEqual({
|
|
editable: false,
|
|
reason: 'library-definition',
|
|
libraryId: 'design-system',
|
|
assetKey: 'button'
|
|
})
|
|
expect(getNodeEditCapability(graph, instance.id)).toEqual({ editable: true })
|
|
expect(() => assertNodeEditable(graph, child.id)).toThrow(ReadOnlyLibraryDefinitionError)
|
|
|
|
const figma = new FigmaAPI(graph)
|
|
const proxy = figma.getNodeById(component.id)
|
|
if (!proxy) throw new Error('Expected proxy')
|
|
expect(() => {
|
|
proxy.name = 'Changed'
|
|
}).toThrow(ReadOnlyLibraryDefinitionError)
|
|
expect(() => {
|
|
proxy.opacity = 0.5
|
|
}).toThrow(ReadOnlyLibraryDefinitionError)
|
|
expect(() => proxy.remove()).toThrow(ReadOnlyLibraryDefinitionError)
|
|
expect(graph.getNode(component.id)?.name).toBe('Remote button')
|
|
const instanceProxy = figma.getNodeById(instance.id)
|
|
if (!instanceProxy) throw new Error('Expected instance proxy')
|
|
instanceProxy.opacity = 0.5
|
|
expect(graph.getNode(instance.id)?.opacity).toBe(0.5)
|
|
expect(() => updateNode.execute(figma, { id: component.id, opacity: 0.5 })).toThrow(
|
|
ReadOnlyLibraryDefinitionError
|
|
)
|
|
})
|
|
|
|
test('does not detach an instance inside a read-only definition', () => {
|
|
const graph = new SceneGraph()
|
|
const page = graph.getPages()[0]
|
|
const icon = graph.createNode('COMPONENT', page.id, { name: 'Icon' })
|
|
const component = graph.createNode('COMPONENT', page.id, {
|
|
name: 'Remote button',
|
|
librarySource: {
|
|
identity: { libraryId: 'design-system', assetKey: 'button', revisionId: 'r1' },
|
|
sourceNodeId: 'source',
|
|
readOnly: true
|
|
}
|
|
})
|
|
const nested = graph.createInstance(icon.id, component.id)
|
|
if (!nested) throw new Error('Expected instance')
|
|
|
|
const figma = new FigmaAPI(graph)
|
|
const nestedProxy = figma.getNodeById(nested.id)
|
|
if (!nestedProxy) throw new Error('Expected proxy')
|
|
expect(() => nestedProxy.detachInstance()).toThrow(ReadOnlyLibraryDefinitionError)
|
|
expect(graph.getNode(nested.id)?.type).toBe('INSTANCE')
|
|
})
|
|
|
|
test('does not swap an instance inside a read-only definition', () => {
|
|
const graph = new SceneGraph()
|
|
const page = graph.getPages()[0]
|
|
const icon = graph.createNode('COMPONENT', page.id, { name: 'Icon' })
|
|
const otherIcon = graph.createNode('COMPONENT', page.id, { name: 'Other icon' })
|
|
const component = graph.createNode('COMPONENT', page.id, {
|
|
name: 'Remote button',
|
|
librarySource: {
|
|
identity: { libraryId: 'design-system', assetKey: 'button', revisionId: 'r1' },
|
|
sourceNodeId: 'source',
|
|
readOnly: true
|
|
}
|
|
})
|
|
const nested = graph.createInstance(icon.id, component.id)
|
|
if (!nested) throw new Error('Expected instance')
|
|
|
|
const figma = new FigmaAPI(graph)
|
|
const nestedProxy = figma.getNodeById(nested.id)
|
|
const otherIconProxy = figma.getNodeById(otherIcon.id)
|
|
if (!nestedProxy || !otherIconProxy) throw new Error('Expected proxies')
|
|
expect(() => nestedProxy.swapComponent(otherIconProxy)).toThrow(ReadOnlyLibraryDefinitionError)
|
|
expect(graph.getNode(nested.id)?.componentId).toBe(icon.id)
|
|
})
|
|
})
|