diff --git a/library/components/legends/SemanticTreeLegend.vue b/library/components/legends/SemanticTreeLegend.vue index 174e2d0d1..6f82578f9 100644 --- a/library/components/legends/SemanticTreeLegend.vue +++ b/library/components/legends/SemanticTreeLegend.vue @@ -288,6 +288,27 @@ watch(() => props.open, (v) => { }) watch(() => safeNodes.value, () => { + // ★ A DATA REFRESH IS NOT A DESELECTION (rega, WAGF Regions on Simple Research, 2026-09-28). The + // polygon highlight landed 51-85 ms after the click and was wiped 433-667 ms later, leaving no row + // marked and every region at full colour — which reads exactly like the Driver's "the legend isn't + // connecting with the map", and is worse, because it connected and then undid itself. + // + // This watcher fires on the IDENTITY of the nodes array, and every tree here is a computed that + // returns a NEW array on each evaluation. So any late async that touches a dependency — pins still + // arriving, a lazily loaded layer, a refresh — rebuilt the array with IDENTICAL CONTENT and this + // reset cancelled the user's selection. The reset itself is right for genuinely new data; what was + // wrong is that it could not tell one case from the other. + // + // So ask whether the selected row still EXISTS. If it does, re-point at the new object and leave the + // tab and the expansion alone: nothing about the reader's state has become invalid. If it is gone, + // the reset below is correct and the deselect is honest. + const keepId = selectedNode.value?.id || null + if (keepId) { + const survivor = findNodeById(safeNodes.value, keepId) + // Re-pointed, not kept: the old object belongs to the discarded array, and holding it would make + // the highlight compare against a node the tree no longer contains. + if (survivor) { selectedNode.value = survivor; return } + } // Falls back to defaultTab, not a hardcoded 0 — otherwise a profile that opens on // a deeper generation silently reverts to the top the first time its nodes change. // ⚠ AND THE STORE ONLY COUNTS ONCE IT HAS BEEN TOUCHED. This read `instance?.activeTab.value`