From 61bec3db2b7bf8d523f3c0474b0c0619461ac4cc Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Sun, 21 Jun 2026 00:08:54 +0800 Subject: [PATCH] fix(canvas): keep insert-above at the page root for nested selections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit insert_node_above_selection inserted into the selection's immediate parent, which broke a nested selection: a free-positioned icon/image dropped into a flex/auto-layout frame gets reflowed away from the cursor (and can detach the selected flow child), and into a clipped frame it can be hidden. Insert at the page root above the selection's top-level ancestor (descendant_contains) instead — correct for top-level selections, safe for nested ones. --- crates/op-editor-core/src/host_support.rs | 31 +++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/crates/op-editor-core/src/host_support.rs b/crates/op-editor-core/src/host_support.rs index f432b3617..d56b0eff8 100644 --- a/crates/op-editor-core/src/host_support.rs +++ b/crates/op-editor-core/src/host_support.rs @@ -184,24 +184,27 @@ impl EditorState { Some(id) } - /// Insert `node` directly above the current selection — one row up in the - /// LayerPanel, which is one step toward the front in z-order (the canvas - /// paints children back-to-front via `children.iter().rev()`, so a lower - /// index renders in front). Inserts as a sibling in the selection's parent; - /// falls back to appending at the page root (back) when nothing is selected. - /// Callers select the new node afterwards. + /// Insert `node` at the page root, directly above the selection's top-level + /// ancestor — one row up in the LayerPanel, which is one step toward the + /// front in z-order (the canvas paints children back-to-front via + /// `children.iter().rev()`, so a lower index renders in front). + /// + /// The new node is free-positioned (explicit `x`/`y` at the viewport + /// centre), so it is kept at the page root rather than nested into the + /// selection's parent: nesting it into a flex/auto-layout frame would + /// reflow it away from the cursor (and could detach the selected flow + /// child), and nesting into a clipped frame could hide it. Falls back to + /// appending at the page root (back) when nothing is selected. Callers + /// select the new node afterwards. fn insert_node_above_selection(&mut self, node: PenNode) { let sel = self.selection.anchor.clone(); if sel.is_real() { - if let Some((parent, idx)) = - crate::walkers::find_parent_and_index(self.active_children(), &sel) + if let Some(idx) = self + .active_children() + .iter() + .position(|n| crate::walkers::descendant_contains(n, &sel)) { - crate::walkers::insert_into_parent( - self.active_children_mut(), - parent.as_ref(), - Some(idx), - node, - ); + self.active_children_mut().insert(idx, node); return; } }