From 29aba9e95328e2b5d0fd3d099ceb84516c2d0f11 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Mon, 31 Aug 2026 23:18:00 +0300 Subject: [PATCH] fix(fig): restore instance constraint propagation --- packages/fig/src/instance-overrides/index.ts | 1 + .../fig/src/instance-overrides/live-overrides.ts | 16 ---------------- .../src/instance-overrides/symbol/overrides.ts | 7 +++++-- packages/scene-graph/src/index.ts | 3 +-- packages/scene-graph/src/instances.ts | 11 ++++++++++- 5 files changed, 17 insertions(+), 21 deletions(-) delete mode 100644 packages/fig/src/instance-overrides/live-overrides.ts diff --git a/packages/fig/src/instance-overrides/index.ts b/packages/fig/src/instance-overrides/index.ts index 1b17531cc..eb264976b 100644 --- a/packages/fig/src/instance-overrides/index.ts +++ b/packages/fig/src/instance-overrides/index.ts @@ -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, diff --git a/packages/fig/src/instance-overrides/live-overrides.ts b/packages/fig/src/instance-overrides/live-overrides.ts deleted file mode 100644 index a048922a8..000000000 --- a/packages/fig/src/instance-overrides/live-overrides.ts +++ /dev/null @@ -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 -} diff --git a/packages/fig/src/instance-overrides/symbol/overrides.ts b/packages/fig/src/instance-overrides/symbol/overrides.ts index cb9f6d56a..6226ff4ed 100644 --- a/packages/fig/src/instance-overrides/symbol/overrides.ts +++ b/packages/fig/src/instance-overrides/symbol/overrides.ts @@ -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 } diff --git a/packages/scene-graph/src/index.ts b/packages/scene-graph/src/index.ts index 42aea1d09..162618df8 100644 --- a/packages/scene-graph/src/index.ts +++ b/packages/scene-graph/src/index.ts @@ -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' diff --git a/packages/scene-graph/src/instances.ts b/packages/scene-graph/src/instances.ts index b50a31386..6aadc86f5 100644 --- a/packages/scene-graph/src/instances.ts +++ b/packages/scene-graph/src/instances.ts @@ -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.