diff --git a/frontend/src/app/main/data/workspace/tokens/remapping.cljs b/frontend/src/app/main/data/workspace/tokens/remapping.cljs index e36b9d1b1d..7ff4a8be4b 100644 --- a/frontend/src/app/main/data/workspace/tokens/remapping.cljs +++ b/frontend/src/app/main/data/workspace/tokens/remapping.cljs @@ -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))) diff --git a/frontend/test/frontend_tests/tokens/logic/token_remapping_test.cljs b/frontend/test/frontend_tests/tokens/logic/token_remapping_test.cljs index acad25311c..fc47db9132 100644 --- a/frontend/test/frontend_tests/tokens/logic/token_remapping_test.cljs +++ b/frontend/test/frontend_tests/tokens/logic/token_remapping_test.cljs @@ -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.