fix(fig): restore instance constraint propagation

This commit is contained in:
Danila Poyarkov 2026-08-31 23:18:00 +03:00
parent f1ae826412
commit 29aba9e953
5 changed files with 17 additions and 21 deletions

View file

@ -18,6 +18,7 @@ import { isEqual } from 'es-toolkit/predicate'
import { guidToString, resolvedNumericBindingUpdate } from '@open-pencil/fig/node-change'
import type { SceneGraph, SceneNode } from '@open-pencil/scene-graph'
import { hasInstanceOverride } from '@open-pencil/scene-graph'
import {
INSTANCE_SYNC_PROPS,
INSTANCE_SYNC_TEXT_PROPS,

View file

@ -1,16 +0,0 @@
import { findInstanceAncestor } from '@open-pencil/scene-graph'
import type { SceneGraph } from '@open-pencil/scene-graph'
/**
* True when `nodeId`'s `field` was recorded as a live instance override
* (via recordInstanceOverride) — i.e. the field was edited after the file
* was last imported/saved. Lazy-population resync (re-cloning instance
* children, reapplying the stored symbol overrides) must not clobber these,
* since the stored data predates the edit.
*/
export function hasLiveOverride(graph: SceneGraph, nodeId: string, field: string): boolean {
const instance = findInstanceAncestor(graph, nodeId)
if (!instance) return false
const key = nodeId === instance.id ? field : `${nodeId}:${field}`
return key in instance.overrides
}

View file

@ -1,4 +1,5 @@
import { hasLiveOverride } from '../live-overrides'
import { hasInstanceOverride } from '@open-pencil/scene-graph'
import { applyOverridePatch } from '../patches'
import { resolveOverrideTarget } from '../resolve'
import type { OverrideContext } from '../types'
@ -16,7 +17,9 @@ function dropLiveOverriddenFields(
): void {
if (!patch?.props) return
const kept = Object.fromEntries(
Object.entries(patch.props).filter(([field]) => !hasLiveOverride(ctx.graph, targetId, field))
Object.entries(patch.props).filter(
([field]) => !hasInstanceOverride(ctx.graph, targetId, field)
)
)
patch.props = Object.keys(kept).length > 0 ? (kept as typeof patch.props) : undefined
}

View file

@ -5,8 +5,7 @@ export * from './copy'
export {
copyInstanceComponentProps,
hasInstanceOverride,
INSTANCE_SYNC_FIELDS,
INSTANCE_SYNC_TEXT_PROPS,
INSTANCE_SYNC_PROPS,
recordInstanceOverride
} from './instances'
export * from './snap'

View file

@ -294,7 +294,16 @@ export function findInstanceAncestor(graph: SceneGraph, nodeId: string): SceneNo
}
/**
* Marks `nodeId`'s `fields` as instance overrides so resync (swapInstanceComponent,
* True when a node field is protected from instance synchronization.
*/
export function hasInstanceOverride(graph: SceneGraph, nodeId: string, field: string): boolean {
const instance = findInstanceAncestor(graph, nodeId)
if (!instance) return false
const key = nodeId === instance.id ? field : `${nodeId}:${field}`
return key in instance.overrides
}
/*
* syncInstances) won't clobber them, and — if `nodeId` sits inside an INSTANCE —
* so the .fig exporter knows to write the diff out as a symbol override. A no-op
* for fields outside INSTANCE_SYNC_PROPS or nodes with no INSTANCE ancestor.