fix(fig): propagate nested icon swaps
This commit is contained in:
parent
4d758f26cb
commit
5e782b2850
|
|
@ -1,6 +1,6 @@
|
|||
import { guidToString } from '#core/kiwi/node-change/convert'
|
||||
|
||||
import { resolveOverrideTarget, repopulateInstance } from './resolve'
|
||||
import { getComponentRoot, resolveOverrideTarget, repopulateInstance } from './resolve'
|
||||
import type {
|
||||
OverrideContext,
|
||||
ComponentPropAssignment,
|
||||
|
|
@ -141,7 +141,7 @@ function applyComponentPropRef(
|
|||
if (!swapId) return
|
||||
const newCompId = ctx.guidToNodeId.get(swapId)
|
||||
if (!newCompId) return
|
||||
repopulateInstance(ctx, childId, newCompId)
|
||||
repopulateInstance(ctx, childId, getComponentRoot(ctx, newCompId))
|
||||
modified?.add(childId)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -340,6 +340,7 @@ export function repopulateInstance(ctx: OverrideContext, nodeId: string, compId:
|
|||
if (comp && comp.childIds.length > 0) {
|
||||
ctx.graph.populateInstanceChildren(nodeId, compId)
|
||||
}
|
||||
ctx.swappedInstances.add(nodeId)
|
||||
ctx.componentIdRoot.clear()
|
||||
candidateCache.delete(ctx)
|
||||
componentFindCache.delete(ctx)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@ const componentGuid = { sessionID: 1, localID: 1 }
|
|||
const componentTextGuid = { sessionID: 1, localID: 2 }
|
||||
const instanceGuid = { sessionID: 2, localID: 1 }
|
||||
const textPropGuid = { sessionID: 3, localID: 1 }
|
||||
const iconPropGuid = { sessionID: 3, localID: 2 }
|
||||
const mailIconGuid = { sessionID: 4, localID: 1 }
|
||||
const mailVectorGuid = { sessionID: 4, localID: 2 }
|
||||
const userIconGuid = { sessionID: 4, localID: 3 }
|
||||
const userVectorGuid = { sessionID: 4, localID: 4 }
|
||||
const componentIconGuid = { sessionID: 1, localID: 3 }
|
||||
const sourceInstanceGuid = { sessionID: 2, localID: 2 }
|
||||
const cloneInstanceGuid = { sessionID: 2, localID: 3 }
|
||||
|
||||
function baseTextChange(): NodeChange {
|
||||
return {
|
||||
|
|
@ -67,4 +75,106 @@ describe('Figma component property import', () => {
|
|||
const labels = Array.from(graph.getAllNodes()).filter((node) => node.type === 'TEXT')
|
||||
expect(labels.map((node) => node.text).sort()).toEqual(['Menu Item', 'Profile Item'])
|
||||
})
|
||||
|
||||
test('propagates nested instance swaps through clone chains', () => {
|
||||
const nodeChanges: NodeChange[] = [
|
||||
{ guid: documentGuid, phase: 'CREATED', type: 'DOCUMENT', name: 'Document' },
|
||||
{ guid: pageGuid, phase: 'CREATED', parentIndex: { guid: documentGuid, position: '!' }, type: 'CANVAS', name: 'Page' },
|
||||
{
|
||||
guid: mailIconGuid,
|
||||
phase: 'CREATED',
|
||||
parentIndex: { guid: pageGuid, position: '!' },
|
||||
type: 'SYMBOL',
|
||||
name: 'icon/mail',
|
||||
size: { x: 16, y: 16 },
|
||||
transform: { m00: 1, m01: 0, m02: 0, m10: 0, m11: 1, m12: 0 }
|
||||
},
|
||||
{
|
||||
guid: mailVectorGuid,
|
||||
phase: 'CREATED',
|
||||
parentIndex: { guid: mailIconGuid, position: '!' },
|
||||
type: 'VECTOR',
|
||||
name: 'mail-path',
|
||||
size: { x: 16, y: 16 },
|
||||
transform: { m00: 1, m01: 0, m02: 0, m10: 0, m11: 1, m12: 0 }
|
||||
},
|
||||
{
|
||||
guid: userIconGuid,
|
||||
phase: 'CREATED',
|
||||
parentIndex: { guid: pageGuid, position: '"' },
|
||||
type: 'SYMBOL',
|
||||
name: 'icon/user',
|
||||
size: { x: 16, y: 16 },
|
||||
transform: { m00: 1, m01: 0, m02: 40, m10: 0, m11: 1, m12: 0 }
|
||||
},
|
||||
{
|
||||
guid: userVectorGuid,
|
||||
phase: 'CREATED',
|
||||
parentIndex: { guid: userIconGuid, position: '!' },
|
||||
type: 'VECTOR',
|
||||
name: 'user-path',
|
||||
size: { x: 16, y: 16 },
|
||||
transform: { m00: 1, m01: 0, m02: 0, m10: 0, m11: 1, m12: 0 }
|
||||
},
|
||||
{
|
||||
guid: componentGuid,
|
||||
phase: 'CREATED',
|
||||
parentIndex: { guid: pageGuid, position: '#' },
|
||||
type: 'SYMBOL',
|
||||
name: 'Menu item',
|
||||
size: { x: 100, y: 20 },
|
||||
transform: { m00: 1, m01: 0, m02: 80, m10: 0, m11: 1, m12: 0 },
|
||||
componentPropDefs: [
|
||||
{ id: iconPropGuid, name: 'icon', initialValue: { guidValue: mailIconGuid } }
|
||||
]
|
||||
},
|
||||
{
|
||||
guid: componentIconGuid,
|
||||
phase: 'CREATED',
|
||||
parentIndex: { guid: componentGuid, position: '!' },
|
||||
type: 'INSTANCE',
|
||||
name: 'icon/mail',
|
||||
symbolData: { symbolID: mailIconGuid },
|
||||
size: { x: 16, y: 16 },
|
||||
transform: { m00: 1, m01: 0, m02: 0, m10: 0, m11: 1, m12: 0 },
|
||||
componentPropRefs: [
|
||||
{ defID: iconPropGuid, componentPropNodeField: 'OVERRIDDEN_SYMBOL_ID' }
|
||||
]
|
||||
},
|
||||
{
|
||||
guid: sourceInstanceGuid,
|
||||
phase: 'CREATED',
|
||||
parentIndex: { guid: pageGuid, position: '$' },
|
||||
type: 'INSTANCE',
|
||||
name: 'Menu item source',
|
||||
symbolData: { symbolID: componentGuid },
|
||||
size: { x: 100, y: 20 },
|
||||
transform: { m00: 1, m01: 0, m02: 120, m10: 0, m11: 1, m12: 0 },
|
||||
componentPropAssignments: [
|
||||
{
|
||||
defID: iconPropGuid,
|
||||
value: { guidValue: userIconGuid },
|
||||
varValue: { value: { symbolIdValue: { guid: userIconGuid } } }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
guid: cloneInstanceGuid,
|
||||
phase: 'CREATED',
|
||||
parentIndex: { guid: pageGuid, position: '%' },
|
||||
type: 'INSTANCE',
|
||||
name: 'Menu item clone',
|
||||
symbolData: { symbolID: sourceInstanceGuid },
|
||||
size: { x: 100, y: 20 },
|
||||
transform: { m00: 1, m01: 0, m02: 160, m10: 0, m11: 1, m12: 0 }
|
||||
}
|
||||
]
|
||||
|
||||
const graph = importNodeChanges(nodeChanges, [], undefined, { populate: 'all' })
|
||||
const clone = Array.from(graph.getAllNodes()).find((node) => node.name === 'Menu item clone')
|
||||
const icon = clone?.childIds.map((id) => graph.getNode(id)).find((node) => node?.type === 'INSTANCE')
|
||||
const iconChild = icon?.childIds.map((id) => graph.getNode(id)).find(Boolean)
|
||||
expect(icon?.name).toBe('icon/user')
|
||||
expect(iconChild?.name).toBe('user-path')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue