diff --git a/.serena/memories/common/component-data-model.md b/.serena/memories/common/component-data-model.md index b8baf24fbd..326965701d 100644 --- a/.serena/memories/common/component-data-model.md +++ b/.serena/memories/common/component-data-model.md @@ -72,3 +72,9 @@ take find-content-ref-shape at every link. A swapped intermediate head follows its own main; collecting its replaced position's content overrides creates phantom groups in copies of that swap (F165). Position advancement still uses advance-shape-ref and find-ref-shape. + +A swapped head pushed into a main can become a plain nested copy of its own +component. If the old position supplied rotation or flips that differ from +that component's expected parent placement, the new nested copy needs a +geometry-group override. Otherwise a later sync discards the orientation +that update-main just pushed (F168). The source copy clears its overrides. diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index b6732279b7..870d71730b 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -734,6 +734,21 @@ {:type :reg-objects :shapes all-parents}) (map (comp del-obj-change :id) new-shapes)))) +(defn- rehead-pushed-swap + "A pushed swap becomes a plain nested copy. Its old position's + orientation becomes authored when it differs from its own main." + [shape main container] + (let [shape (-> shape + (assoc :shape-ref (:id main)) + (ctk/remove-swap-group)) + main-container (when main + (main-in-parent-orientation (:container (meta main)) main + container shape false)) + expected (get-in main-container [:objects (:id main)])] + (cond-> shape + (and expected (orient-like shape expected (gsh/shape->center shape))) + (update :touched ctk/set-touched-group :geometry-group)))) + (defn- add-shape-to-main "Add to the main shape `parent-main`, at `index`, a copy of `child-inst`, a child of the copy shape that pairs with it; `child-inst` then refers to @@ -752,14 +767,17 @@ (seq (ctn/get-parent-copy-heads (:objects main-container) parent-main))) replaced (when swap-in-copy? (ctn/get-shape main-container (:shape-ref child-inst))) + content-main (when (and (ctk/swapped? child-inst) (not swap-in-copy?)) + (ctf/find-content-ref-shape nil container libraries child-inst + :include-deleted? true + :with-context? true)) update-new-shape (fn [new-shape original-shape] (cond-> (reposition-shape new-shape root-inst root-main) (and (= (:id original-shape) (:id child-inst)) (ctk/swapped? child-inst) (not swap-in-copy?)) - (-> (assoc :shape-ref (swap-content-root-id libraries child-inst)) - (ctk/remove-swap-group)))) + (rehead-pushed-swap content-main main-container))) ;; the copy now follows the main, swap included update-original-shape (fn [original-shape new-shape] diff --git a/common/test/common_tests/logic/swap_group_test.cljc b/common/test/common_tests/logic/swap_group_test.cljc index 45cc06ed89..8682181ae0 100644 --- a/common/test/common_tests/logic/swap_group_test.cljc +++ b/common/test/common_tests/logic/swap_group_test.cljc @@ -899,3 +899,21 @@ (mapv :id chain))) (t/is (= #{:swap-group} (ctf/get-touched-from-ref-chain-until-target-ref page libraries child nil))))) + +(t/deftest update-main-authors-a-swaps-inherited-orientation-in-its-new-main + (doseq [angle [0 45]] + (let [initial (-> (tm/make-situation (setup-sized)) + (r/step (n/rotate :card-star angle)) r/settle) + swapped (-> initial (r/step (n/swap-shape :copy-star :heart)) r/settle) + updated (-> swapped (r/step (n/update-main :copy)) r/settle) + file (tm/file updated) + head (tm/resolve-shape updated :copy-star) + main (tm/shape-by-id updated (:shape-ref head)) + full (:file (r/sync-cascade file {} (keys (get-in file [:data :components]))))] + (t/is (= (if (zero? angle) #{} #{:geometry-group}) (set (:touched main)))) + (t/is (mth/close? angle (:rotation main) 0.001)) + (t/is (mth/close? angle (:rotation (ths/get-shape-by-id full (:id main))) 0.001)) + (t/is (gsh/close-attrs? :points (:points head) + (:points (ths/get-shape-by-id full (:id head))) 0.001)) + (t/is (= (thn/normalize-file (tm/file swapped)) + (thn/normalize-file (tm/file (r/step updated (n/undo)))))))))