mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
🐛 Author pushed content against its new nested reference
When a pushed swap takes a position with the same component, preserve content differences as overrides on the promoted head and descendants. The source copy clears its overrides and follows the promoted subtree. Portable regression: three failures before the fix; now passes, including full sync and exact undo. Focused JVM suites: 121 tests, 638 assertions. Component benchmark ratios: mains 0.61/0.78/0.69; levels 0.53; chain 0.50; library 0.56; many shapes 0.75; variant switch 0.61. All worlds pass the baseline performance gate. AI-assisted-by: GPT-6
This commit is contained in:
parent
c36d15db20
commit
337b1230b6
@ -755,6 +755,30 @@
|
||||
(and expected (orient-like shape expected (gsh/shape->center shape)))
|
||||
(update :touched ctk/set-touched-group :geometry-group))))
|
||||
|
||||
(defn- author-pushed-content
|
||||
"Taking a new content reference makes the pushed differences authored.
|
||||
Placement still follows the position, and existing overrides survive."
|
||||
[shape reference]
|
||||
(if (or (nil? reference) (ctk/swapped? shape))
|
||||
shape
|
||||
(let [text? (cfh/text-shape? shape)
|
||||
groups (into #{}
|
||||
(keep (fn [attr]
|
||||
(let [group (ctk/resolve-sync-group (:type shape) attr)]
|
||||
(when (and group
|
||||
(not (contains? placement-groups group))
|
||||
(not= attr :position-data)
|
||||
(not (and text? (= attr :content)))
|
||||
(not= (get shape attr) (get reference attr)))
|
||||
group))))
|
||||
updatable-attrs)
|
||||
text-groups (when text?
|
||||
(txt/override-groups (:content reference) (:content shape)))
|
||||
groups (cond-> (into groups text-groups)
|
||||
(seq text-groups) (conj :content-group))]
|
||||
(cond-> shape
|
||||
(seq groups) (update :touched (fnil into #{}) groups)))))
|
||||
|
||||
(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
|
||||
@ -817,11 +841,15 @@
|
||||
|
||||
new-shapes
|
||||
(if swap-in-copy?
|
||||
(let [objects (d/index-by :id new-shapes)
|
||||
position (ctf/find-ref-shape nil main-container libraries replaced
|
||||
:include-deleted? true
|
||||
:with-context? true)]
|
||||
(mapv (ctf/take-position nil libraries objects new-head (:shape-ref replaced) position)
|
||||
(let [objects (d/index-by :id new-shapes)
|
||||
position (ctf/find-ref-shape nil main-container libraries replaced
|
||||
:include-deleted? true
|
||||
:with-context? true)
|
||||
take-position (ctf/take-position nil libraries objects new-head (:shape-ref replaced) position)
|
||||
position-objects (get-in (meta position) [:container :objects])]
|
||||
(mapv (fn [shape]
|
||||
(let [shape (take-position shape)]
|
||||
(author-pushed-content shape (get position-objects (:shape-ref shape)))))
|
||||
new-shapes))
|
||||
new-shapes)
|
||||
|
||||
|
||||
@ -933,3 +933,36 @@
|
||||
(: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))))))))
|
||||
|
||||
(t/deftest pushing-a-swap-authors-content-that-differs-from-its-new-position
|
||||
(let [file (-> (setup)
|
||||
(tho/add-frame :page-main)
|
||||
(thc/instantiate-component :card :inner-copy
|
||||
:parent-label :page-main
|
||||
:children-labels [:inner-star])
|
||||
(thc/make-component :page :page-main)
|
||||
(thc/instantiate-component :page :outer-copy
|
||||
:children-labels [:outer-inner :outer-star]))
|
||||
swapped (-> (tm/make-situation file)
|
||||
(r/step (n/swap-shape :outer-star :heart)) r/settle
|
||||
(r/step (n/swap-shape :card-star :heart)) r/settle)
|
||||
child-id (first (:shapes (tm/resolve-shape swapped :card-star)))
|
||||
edited (-> swapped
|
||||
(r/step (n/change-property :card-star :fills "#333333")) r/settle
|
||||
(r/step (n/change-property (constantly child-id) :fills "#444444")) r/settle)
|
||||
updated (-> edited (r/step (n/update-main :outer-copy)) r/settle)
|
||||
head (tm/resolve-shape updated :outer-star)
|
||||
main (tm/shape-by-id updated (:shape-ref head))
|
||||
main-child (tm/shape-by-id updated (first (:shapes main)))
|
||||
file (tm/file updated)
|
||||
full (:file (r/sync-cascade file {} (keys (get-in file [:data :components]))))]
|
||||
(t/is (ctk/swapped? (tm/resolve-shape edited :outer-star)))
|
||||
(t/is (= (thi/id :card-star) (:shape-ref main)))
|
||||
(t/is (= #{:fill-group} (:touched main) (:touched main-child)))
|
||||
(t/is (= (:fills (tm/resolve-shape edited :outer-star)) (:fills main)))
|
||||
(t/is (= "#222222" (get-in main-child [:fills 0 :fill-color])))
|
||||
(t/is (empty? (:touched head)))
|
||||
(t/is (= (:fills main) (:fills (ths/get-shape-by-id full (:id main)))))
|
||||
(t/is (= (:fills main-child) (:fills (ths/get-shape-by-id full (:id main-child)))))
|
||||
(t/is (= (thn/normalize-file (tm/file edited))
|
||||
(thn/normalize-file (tm/file (r/step updated (n/undo))))))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user