From fd3ceac4510a126542277b7d0a09101b734c6dbe Mon Sep 17 00:00:00 2001 From: Arnold Loubriat Date: Tue, 3 Nov 2026 19:59:07 +0100 Subject: [PATCH] fix: Keep subtree root grafted on updates without tree info --- accesskit_consumer/src/tree.rs | 66 +++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/accesskit_consumer/src/tree.rs b/accesskit_consumer/src/tree.rs index 2f508a0a4..327108109 100644 --- a/accesskit_consumer/src/tree.rs +++ b/accesskit_consumer/src/tree.rs @@ -260,7 +260,10 @@ impl TreeState { if let Some(node_state) = self.nodes.get_mut(&node_id) { if local_node_id == root { - node_state.parent_and_index = None; + node_state.parent_and_index = self + .graft_parents + .get(&tree_id) + .map(|&graft_id| ParentAndIndex(graft_id, 0)); } for child_id in node_state.data.children().iter() { let mapped_existing_child_id = map_id(*child_id); @@ -3023,6 +3026,67 @@ mod tests { assert!(!handler.updated_nodes.contains(&subtree_node_id(0)),); } + #[test] + fn subtree_root_update_without_tree_keeps_graft_parent() { + let update = TreeUpdate { + nodes: vec![ + (NodeId(0), { + let mut node = Node::new(Role::Window); + node.set_children(vec![NodeId(1)]); + node + }), + (NodeId(1), { + let mut node = Node::new(Role::GenericContainer); + node.set_tree_id(subtree_id()); + node + }), + ], + tree: Some(TreeInfo::new(NodeId(0))), + tree_id: TreeId::ROOT, + focus: NodeId(0), + }; + let mut tree = super::Tree::new(update, false); + + let subtree_root = |label: &str| { + let mut node = Node::new(Role::Document); + node.set_label(label); + node + }; + tree.update_and_process_changes( + TreeUpdate { + nodes: vec![(NodeId(0), subtree_root("original"))], + tree: Some(TreeInfo::new(NodeId(0))), + tree_id: subtree_id(), + focus: NodeId(0), + }, + &mut NoOpHandler, + ); + assert_eq!( + tree.state() + .node_by_id(subtree_node_id(0)) + .unwrap() + .parent_id(), + Some(node_id(1)) + ); + + tree.update_and_process_changes( + TreeUpdate { + nodes: vec![(NodeId(0), subtree_root("modified"))], + tree: None, + tree_id: subtree_id(), + focus: NodeId(0), + }, + &mut NoOpHandler, + ); + + let subtree_root = tree.state().node_by_id(subtree_node_id(0)).unwrap(); + assert_eq!(subtree_root.label().as_deref(), Some("modified")); + assert_eq!(subtree_root.parent_id(), Some(node_id(1))); + + let graft_node = tree.state().node_by_id(node_id(1)).unwrap(); + assert_eq!(graft_node.child_ids().next(), Some(subtree_node_id(0))); + } + #[test] fn host_focus_change_keeps_focus_in_subtree() { let root_update = |focus| TreeUpdate {