From 7f99638e6505cefdcdff26548035c5b3f54ad744 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Tue, 30 Jun 2026 21:50:05 +0300 Subject: [PATCH] perf(vue): patch layer tree node updates --- .../primitives/LayerTree/LayerTreeRoot.vue | 61 ++++++++++++++++--- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/packages/vue/src/primitives/LayerTree/LayerTreeRoot.vue b/packages/vue/src/primitives/LayerTree/LayerTreeRoot.vue index 1cc62ee70..2ba21d2e5 100644 --- a/packages/vue/src/primitives/LayerTree/LayerTreeRoot.vue +++ b/packages/vue/src/primitives/LayerTree/LayerTreeRoot.vue @@ -7,6 +7,7 @@ import { provideLayerTree } from '#vue/primitives/LayerTree/context' import { useLayerDrag } from '#vue/primitives/LayerTree/useLayerDrag' import type { LayerNode } from '#vue/primitives/LayerTree/context' +import type { SceneNode } from '@open-pencil/scene-graph' const { indentPerLevel = 16 } = defineProps<{ indentPerLevel?: number @@ -32,6 +33,17 @@ const { draggingId, instruction, instructionTargetId, setupItem } = useLayerDrag expandNode ) +function nodeToLayerNode(node: SceneNode): LayerNode { + return { + id: node.id, + name: node.name, + type: node.type, + layoutMode: node.layoutMode, + visible: node.visible, + locked: node.locked + } +} + function buildTree(parentId: string): LayerNode[] { const parent = editor.graph.getNode(parentId) if (!parent) return [] @@ -39,12 +51,7 @@ function buildTree(parentId: string): LayerNode[] { .map((cid) => editor.graph.getNode(cid)) .filter((n): n is NonNullable => !!n) .map((node) => ({ - id: node.id, - name: node.name, - type: node.type, - layoutMode: node.layoutMode, - visible: node.visible, - locked: node.locked, + ...nodeToLayerNode(node), children: node.childIds.length > 0 ? buildTree(node.id) : undefined })) } @@ -59,6 +66,46 @@ function rebuildTree() { treeVersion.value++ } +function replaceLayerNode(nodes: LayerNode[], replacement: LayerNode): LayerNode[] | null { + let changed = false + const next = nodes.map((node) => { + if (node.id === replacement.id) { + changed = true + return { ...replacement, children: node.children } + } + if (!node.children) return node + const children = replaceLayerNode(node.children, replacement) + if (!children) return node + changed = true + return { ...node, children } + }) + return changed ? next : null +} + +function patchLayerNode(id: string, changes: Partial) { + if ('childIds' in changes || 'parentId' in changes) { + rebuildTree() + return + } + + if ( + !( + 'name' in changes || + 'type' in changes || + 'layoutMode' in changes || + 'visible' in changes || + 'locked' in changes + ) + ) { + return + } + + const node = editor.graph.getNode(id) + if (!node) return + const next = replaceLayerNode(items.value, nodeToLayerNode(node)) + if (next) items.value = next +} + const unsubscribe = [ editor.onEditorEvent('graph:replaced', rebuildTree), editor.onEditorEvent('page:changed', rebuildTree), @@ -66,7 +113,7 @@ const unsubscribe = [ editor.onEditorEvent('node:deleted', rebuildTree), editor.onEditorEvent('node:reparented', rebuildTree), editor.onEditorEvent('node:reordered', rebuildTree), - editor.onEditorEvent('node:updated', rebuildTree) + editor.onEditorEvent('node:updated', patchLayerNode) ] onScopeDispose(() => {