diff --git a/.serena/memories/common/component-sync-contract.md b/.serena/memories/common/component-sync-contract.md index 10dafa2b85..fed4207439 100644 --- a/.serena/memories/common/component-sync-contract.md +++ b/.serena/memories/common/component-sync-contract.md @@ -72,3 +72,9 @@ change builder (F182). Its content and position reference can have different sizes, so rotating the content rigidly can leave its untransformed anchor different from full sync. Keep the swapped head/children untouched and put the derived correction in the same undo group. Authored geometry stays. + +Reset drops the root's geometry override from the whole sync context +(F185), including the branch that clones replacement children. Clearing it +only while updating existing shapes can turn a newly added child by the +old override after its parent has already reset. The reset and replacement +children share one undo group and stay stable through later sync. diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index 264d7644cd..70bab2ae62 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -321,7 +321,8 @@ :main-container main-container :component component :library library - :root-inst shape-inst + ;; Reset also places new children in the main's frame. + :root-inst (cond-> shape-inst reset? (dissoc :touched)) :root-main shape-main :reset? reset?} shape-inst @@ -366,10 +367,7 @@ as it follows its near main." [changes {:keys [container main-container root-inst root-main reset?]} shape-inst shape-main] - (let [omit-touched? (not reset?) - ;; Reset takes the main's orientation too. Its old geometry override - ;; must not turn the main into the copy's frame before overwriting it. - root-inst (cond-> root-inst reset? (dissoc :touched))] + (let [omit-touched? (not reset?)] (cond-> (update-attrs changes shape-inst shape-main root-inst root-main container omit-touched?) ;; the children refer to the children of `shape-main`, in the ;; container of the walk's main shapes diff --git a/common/test/common_tests/logic/comp_expected_geometry_test.cljc b/common/test/common_tests/logic/comp_expected_geometry_test.cljc index 2b5dddc511..97b4e269f8 100644 --- a/common/test/common_tests/logic/comp_expected_geometry_test.cljc +++ b/common/test/common_tests/logic/comp_expected_geometry_test.cljc @@ -36,6 +36,40 @@ (t/use-fixtures :each thi/test-fixture) +(t/deftest resetting-a-turned-copy-places-replacement-children-in-the-main-frame + (doseq [angle [45 90]] + (let [file (-> (thf/sample-file :file) + (tho/add-simple-component :a :main-a :rect-a + :root-params {:width 100 :height 100} + :child-params {:width 20 :height 20 :x 10 :y 10}) + (tho/add-simple-component :other :main-other :rect-other + :root-params {:width 100 :height 100} + :child-params {:width 20 :height 20 :x 10 :y 10}) + (tho/add-frame :main-b {:width 200 :height 200}) + (thc/instantiate-component :a :b-a :parent-label :main-b) + (thc/make-component :b :main-b) + (thc/instantiate-component :b :copy-b :children-labels [:copy-a])) + turned (-> (tm/make-situation file) + (r/step (n/swap-shape :copy-a :other)) r/settle + (r/step (n/rotate :copy-b angle)) r/settle) + reset (-> turned (r/step (n/reset :copy-b)) r/settle) + head (tm/resolve-shape reset :copy-a) + child (tm/shape-by-id reset (first (:shapes head))) + expected (gsh/move (ths/get-shape file :rect-a) + (gpt/subtract (gsh/shape->center head) + (gsh/shape->center (ths/get-shape file :main-a)))) + file (tm/file reset) + full (:file (r/sync-cascade file {} (keys (get-in file [:data :components]))))] + (t/is (mth/close? 0 (:rotation head) 0.001)) + (t/is (mth/close? 0 (:rotation child) 0.001)) + (t/is (empty? (:touched head))) + (t/is (empty? (:touched child))) + (t/is (gsh/close-attrs? :points (:points expected) (:points child) 0.001)) + (t/is (gsh/close-attrs? :points (:points child) + (:points (ths/get-shape-by-id full (:id child))) 0.001)) + (t/is (= (thn/normalize-file (tm/file turned)) + (thn/normalize-file (tm/file (r/step reset (n/undo))))))))) + (t/deftest turning-a-parent-settles-a-swapped-head-with-a-different-position-size (doseq [angle [45 90]] (let [file (-> (thf/sample-file :file)