mirror of
https://github.com/penpot/penpot.git
synced 2026-10-11 05:37:50 -04:00
🐛 Keep per-side token attributes when remapping a token (#12091)
Renaming a token with "Remap tokens" grouped the references by container and wrote the union of their attributes onto every shape in it. A shape with a stroke width token on one side got the token on all four sides when another shape in the same container had it on every side. Group the references by shape, so each shape is only renamed on the attributes it already had the token on. Closes #12075 AI-assisted-by: claude-opus-5-5
This commit is contained in:
1 parent
582f943228
commit
ff74c38bbf
2 files changed
+44
-7
No files matched your search
@@ -115,11 +115,14 @@
|
||||
shape-changes
|
||||
(reduce-kv
|
||||
(fn [changes container refs]
|
||||
(let [shape-ids (map :shape-id refs)
|
||||
(let [;; Each shape keeps only the attributes it already had the
|
||||
;; token on, so the rename never applies the token to new
|
||||
;; attributes (e.g. a stroke-width token on a single side).
|
||||
attributes-by-shape (update-vals (group-by :shape-id refs)
|
||||
#(into #{} (map :attribute) %))
|
||||
;; Find the correct token to apply (new or alias)
|
||||
token (or (some #(when (= (:name (:token %)) new-token-name) %) tokens-with-sets)
|
||||
(some #(when (= (:name (:token %)) old-token-name) %) tokens-with-sets))
|
||||
attributes (set (map :attribute refs))]
|
||||
token (or (some #(when (= (:name (:token %)) new-token-name) %) tokens-with-sets)
|
||||
(some #(when (= (:name (:token %)) old-token-name) %) tokens-with-sets))]
|
||||
(if token
|
||||
;; Create a new independent changes so we can call `with-file-data` after `with-container`
|
||||
;; otherwise it causes probelms looking up for objects
|
||||
@@ -127,10 +130,11 @@
|
||||
(-> (pcb/empty-changes)
|
||||
(pcb/with-container container)
|
||||
(pcb/with-file-data file-data)
|
||||
(pcb/update-shapes shape-ids
|
||||
(pcb/update-shapes (keys attributes-by-shape)
|
||||
(fn [shape]
|
||||
(update shape :applied-tokens
|
||||
#(merge % (cft/attributes-map attributes (:token token)))))
|
||||
(let [attributes (get attributes-by-shape (:id shape))]
|
||||
(update shape :applied-tokens
|
||||
#(merge % (cft/attributes-map attributes (:token token))))))
|
||||
{:ignore-touched true}))]
|
||||
(pcb/concat-changes changes container-changes))
|
||||
changes)))
|
||||
|
||||
@@ -120,6 +120,39 @@
|
||||
(let [result (dwtr/validate-token-remapping "color.primary" "brand.primary")]
|
||||
(t/is (true? (:valid? result)))))))
|
||||
|
||||
(t/deftest test-remap-keeps-applied-attributes-per-shape
|
||||
(t/testing "renaming a token only renames the attributes each shape already had"
|
||||
(let [stroke-token {:id (cthi/new-id! :sw-10)
|
||||
:name "sw-10"
|
||||
:value "10"
|
||||
:type :stroke-width}
|
||||
file (-> (ctht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "Set A"))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token stroke-token))))
|
||||
(ctho/add-rect :top-rect)
|
||||
(ctho/add-rect :all-rect)
|
||||
(ctht/apply-token-to-shape :top-rect "sw-10"
|
||||
[:stroke-width-top] [] nil)
|
||||
(ctht/apply-token-to-shape :all-rect "sw-10"
|
||||
cto/stroke-width-keys [] nil)
|
||||
;; The production flow renames the token first,
|
||||
;; then remaps the shapes that use it.
|
||||
(update-in [:data :tokens-lib]
|
||||
ctob/update-token (cthi/id :set-a) (cthi/id :sw-10)
|
||||
#(assoc % :name "sw-big")))
|
||||
changes (dwtr/build-remap-changes (:data file) "sw-10" "sw-big")
|
||||
file' (cthf/apply-changes file changes)
|
||||
top-rect' (cths/get-shape file' :top-rect)
|
||||
all-rect' (cths/get-shape file' :all-rect)]
|
||||
|
||||
(t/is (= {:stroke-width-top "sw-big"}
|
||||
(:applied-tokens top-rect')))
|
||||
(t/is (= (zipmap cto/stroke-width-keys (repeat "sw-big"))
|
||||
(:applied-tokens all-rect'))))))
|
||||
|
||||
(defn- setup-file-with-component-copy-and-token
|
||||
"Create a file containing a component, an instance copy of it, and a single
|
||||
`color.primary` token already applied to both the main and the copy shape.
|
||||
|
||||
Reference in new issue
Block a user