mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
🐛 Keep inherited orientation when pushing a swapped child
When update-main turns a swap into a plain nested copy, retain its orientation as a geometry override if it differs from its own component's expected parent placement. Otherwise a later full sync discards the rotation inherited from the replaced position (F168). The portable regression fails three assertions before the fix. Both 0-degree and 45-degree cases now pass, including exact undo. Fresh swap, variant and flex suites pass 125 tests and 596 assertions. The pure golden master matches all 1149 assertions without recording. Benchmark ratios against Phase 1e: main 10/100/1000 copies 0.52/0.62/0.56, three levels 0.48, chain 0.56, library 0.51, many shapes 0.43, variant switch 0.60. No regression flags. AI-assisted-by: GPT-6
This commit is contained in:
parent
357e8a7ff7
commit
5ad0744d0e
@ -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.
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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)))))))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user