🐛 Preserve untouched parent grid cells during component swaps

Restore the original cell metadata after replacing a child in place, and
ignore touched while assigning the new instance. Later main cell moves
can then reach the swapped copy. Fix F128.

The regression failed before the fix. Swap suite: 37 tests, 137 assertions.
Benchmark ratios against Phase 1e: main 10/100/1000 0.46/0.52/0.53;
three levels 0.47; chain 0.51; library 0.51; many shapes 0.49;
variant switch 0.61. No regression flag.

AI-assisted-by: GPT-6
This commit is contained in:
alonso.torres 2026-10-23 14:51:12 +02:00
parent e4e02a4753
commit 4e7cca7ff4
3 changed files with 26 additions and 2 deletions

View File

@ -99,7 +99,7 @@
(cond-> (and (some? row) (some? column))
(-> (ctsl/push-into-cell [(:id first-shape)] row column)
(ctsl/assign-cells objects)))))
{:with-objects? true})
{:with-objects? true :ignore-touched true})
(pcb/reorder-grid-children [(:parent-id first-shape)])))
changes)

View File

@ -428,7 +428,15 @@
[changes parents-of-swapped]
(if keep-touched?
(generate-keep-touched changes new-shape shape orig-shapes page libraries ldata)
[changes []])]
[changes []])
;; Replacement keeps the head id and its cell. Cleanup during the
;; temporary deletion must not change the parent's placement data.
changes (cond-> changes
(ctsl/grid-layout? parent)
(pcb/update-shapes [(:id parent)]
#(assoc % :layout-grid-cells (:layout-grid-cells parent))
{:ignore-touched true}))]
[new-shape changes (concat all-parents parents-of-swapped)]))
(defn find-switch-target

View File

@ -22,6 +22,10 @@
[app.common.logic.variants :as clv]
[app.common.math :as mth]
[app.common.test-helpers.components :as thc]
[app.common.test-helpers.composable.comp.nodes :as n]
[app.common.test-helpers.composable.comp.runner :as r]
[app.common.test-helpers.composable.comp.setups :as setups]
[app.common.test-helpers.composable.core :as tm]
[app.common.test-helpers.compositions :as tho]
[app.common.test-helpers.files :as thf]
[app.common.test-helpers.ids-map :as thi]
@ -34,6 +38,18 @@
(t/use-fixtures :each thi/test-fixture)
(t/deftest swapping-a-grid-child-keeps-the-parent-cells-untouched
(let [initial (setups/grid-component-with-copy)
swapped (-> initial (r/step (n/swap-shape :copy-child1 :other)) r/settle)
parent (tm/resolve-shape swapped :grid-copy)
moved (-> swapped (r/step (n/move-to-cell :grid-root :child1 1 3)) r/settle)
final-parent (tm/resolve-shape moved :grid-copy)
child-id (:id (tm/resolve-shape moved :copy-child1))
cell (first (filter #(some #{child-id} (:shapes %)) (vals (:layout-grid-cells final-parent))))]
(t/is (nil? (:touched parent)))
(t/is (= (:layout-grid-cells (tm/resolve-shape initial :grid-copy)) (:layout-grid-cells parent)))
(t/is (= 3 (:column cell)))))
(defn- setup
[]
;; {:star-main} [:name Frame1] # [Component :star]