mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 14:00:37 +00:00
🐛 Keep library color and typography syncs from touching copies
A library color sync wrote a copy's fills through update-shapes, and a library typography sync wrote a copy text's content with a plain :set, so both marked the copy as overridden (:fill-group, or :content-group with :text-content-attribute). A later edit of that fill or text style in the main then never reached the copy. Both syncs are derived writes: they now write with ignore-touched. The typography sync also merged the whole typography into each text node that uses it, so its :modified-at (and :path) ended in the content of the main and of every copy. It now writes only the text styles of the typography. Benchmark (lower quantile, ms; baseline / now / ratio): deepest-edit-through-three-levels 35.2 / 34.7 / 0.98 edit-through-a-chain-of-dependents 68.9 / 67.6 / 0.98 library-update-into-copies 83.1 / 76.0 / 0.91 main-edit-into-10-copies 1.8 / 1.5 / 0.86 main-edit-into-100-copies 15.4 / 15.2 / 0.99 main-edit-into-1000-copies 153.1 / 157.1 / 1.03 variant-switch-into-copies 32.1 / 27.0 / 0.84 AI-assisted-by: claude-opus-5-5
This commit is contained in:
parent
51e9cdbad7
commit
c66928d555
@ -641,22 +641,25 @@
|
||||
(shape-log :debug (:id shape) nil :msg "Sync colors of shape" :shape (:name shape))
|
||||
|
||||
;; Synchronize a shape that uses some colors of the library. The value of the
|
||||
;; color in the library is copied to the shape.
|
||||
;; color in the library is copied to the shape. It is a derived write, so it
|
||||
;; touches no override of a copy.
|
||||
(let [library-colors (get-in libraries [library-id :data :colors])]
|
||||
(pcb/update-shapes changes
|
||||
[(:id shape)]
|
||||
#(ctl/sync-colors % library-id library-colors))))
|
||||
#(ctl/sync-colors % library-id library-colors)
|
||||
{:ignore-touched true})))
|
||||
|
||||
(defmethod generate-sync-shape :typographies
|
||||
[_ changes library-id container shape libraries _]
|
||||
(shape-log :debug (:id shape) nil :msg "Sync typographies of shape" :shape (:name shape))
|
||||
|
||||
;; Synchronize a shape that uses some typographies of the library. The attributes
|
||||
;; of the typography are copied to the shape."
|
||||
;; Synchronize a shape that uses some typographies of the library. The text
|
||||
;; styles of the typography are copied to the shape. It is a derived write,
|
||||
;; so it touches no override of a copy.
|
||||
(let [typographies (get-in libraries [library-id :data :typographies])
|
||||
update-node (fn [node]
|
||||
(if-let [typography (get typographies (:typography-ref-id node))]
|
||||
(merge node (dissoc typography :name :id))
|
||||
(merge node (select-keys typography txt/typography-fields))
|
||||
(dissoc node :typography-ref-id
|
||||
:typography-ref-file)))]
|
||||
(generate-sync-text-shape changes shape container update-node)))
|
||||
@ -673,7 +676,8 @@
|
||||
:id (:id shape)
|
||||
:operations [{:type :set
|
||||
:attr :content
|
||||
:val new-content}
|
||||
:val new-content
|
||||
:ignore-touched true}
|
||||
{:type :set
|
||||
:attr :position-data
|
||||
:val nil}]})
|
||||
@ -685,7 +689,8 @@
|
||||
:id (:id shape)
|
||||
:operations [{:type :set
|
||||
:attr :content
|
||||
:val old-content}
|
||||
:val old-content
|
||||
:ignore-touched true}
|
||||
{:type :set
|
||||
:attr :position-data
|
||||
:val nil}]})
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
[app.common.logic.libraries :as cll]
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.test-helpers.components :as thc]
|
||||
[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]
|
||||
@ -80,8 +79,8 @@
|
||||
(let [file' (change-library-color (component-using-color) "#222222")
|
||||
copy (ths/get-shape file' :copy-child)]
|
||||
(t/is (= "#222222" (-> copy :fills first :fill-color)))
|
||||
;; the sync writes the fill without ignore-touched
|
||||
(tm/known-failure "F3" nil #{:fill-group} (:touched copy))))
|
||||
;; a library sync is a derived write
|
||||
(t/is (nil? (:touched copy)))))
|
||||
|
||||
(t/deftest main-fill-edit-reaches-the-copy-after-a-library-color-sync
|
||||
(let [file' (-> (component-using-color)
|
||||
@ -89,8 +88,7 @@
|
||||
(sync-file :components (thi/id :component1))
|
||||
(update-shape :main-child #(assoc % :fills (ths/sample-fills-color :fill-color "#333333")))
|
||||
(sync-file :components (thi/id :component1)))]
|
||||
;; the touched fill blocks it
|
||||
(tm/known-failure "F3" "#333333" "#222222" (-> (ths/get-shape file' :copy-child) :fills first :fill-color))))
|
||||
(t/is (= "#333333" (-> (ths/get-shape file' :copy-child) :fills first :fill-color)))))
|
||||
|
||||
;; ---- Typographies
|
||||
|
||||
@ -131,8 +129,8 @@
|
||||
(let [file' (change-library-typography (component-using-typography) "24")
|
||||
copy (ths/get-shape file' :copy-child)]
|
||||
(t/is (= "24" (font-size-of copy)))
|
||||
;; the sync writes the content with a raw :set, which touches it
|
||||
(tm/known-failure "F3" nil #{:content-group :text-content-attribute} (:touched copy))))
|
||||
;; a library sync is a derived write
|
||||
(t/is (nil? (:touched copy)))))
|
||||
|
||||
(t/deftest main-font-edit-reaches-the-copy-after-a-library-typography-sync
|
||||
(let [file' (-> (component-using-typography)
|
||||
@ -143,12 +141,9 @@
|
||||
(update shape :content
|
||||
#(txt/transform-nodes txt/is-content-node? (fn [node] (assoc node :font-size "40")) %))))
|
||||
(sync-file :components (thi/id :component1)))]
|
||||
;; the touched text attributes block it
|
||||
(tm/known-failure "F3" "40" "24" (font-size-of (ths/get-shape file' :copy-child)))))
|
||||
(t/is (= "40" (font-size-of (ths/get-shape file' :copy-child))))))
|
||||
|
||||
(t/deftest library-typography-sync-writes-only-text-styles
|
||||
;; the sync merges the whole typography into each node, its own
|
||||
;; :modified-at included
|
||||
(let [file' (change-library-typography (component-using-typography) "24")
|
||||
node (get-in (ths/get-shape file' :main-child) [:content :children 0 :children 0 :children 0])]
|
||||
(tm/known-failure "F80" false true (contains? node :modified-at))))
|
||||
(t/is (not (contains? node :modified-at)))))
|
||||
|
||||
@ -403,10 +403,8 @@
|
||||
(sync :colors (thi/id :brand))
|
||||
(thtx/set-text :main-child [[["New arrivals" {:weight 600 :size 18 :fills (brand "#7B3FD1")}]]])
|
||||
(sync :components (thi/id :component1)))]
|
||||
(tm/known-failure "F3"
|
||||
[[["New arrivals" {:weight 600 :size 18 :fills (brand "#7B3FD1")}]]]
|
||||
[[["New arrivals" {:weight 600 :fills (brand "#7B3FD1")}]]]
|
||||
(thtx/text-of file' :copy-child))))
|
||||
(t/is (= [[["New arrivals" {:weight 600 :size 18 :fills (brand "#7B3FD1")}]]]
|
||||
(thtx/text-of file' :copy-child)))))
|
||||
|
||||
;; ---- The worked example: a copy that bolds "Hello" and adds "!!!"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user