0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-20 05:34:23 -05:00

Synchronize tokens in components

This commit is contained in:
Andrés Moya 2024-11-19 16:14:02 +01:00 committed by Andrés Moya
parent 2a766a7190
commit 6077ba6690
4 changed files with 92 additions and 23 deletions

View file

@ -1153,7 +1153,7 @@
; We need to trigger a sync if the shape has changed any
; attribute that participates in components synchronization.
(and (= (:type operation) :set)
(get ctk/sync-attrs (:attr operation))))
(ctk/component-attr? (:attr operation))))
any-sync? (some need-sync? operations)]
(when any-sync?
(if page-id

View file

@ -27,6 +27,7 @@
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.interactions :as ctsi]
[app.common.types.shape.layout :as ctl]
[app.common.types.token :as cto]
[app.common.types.typography :as cty]
[app.common.uuid :as uuid]
[clojure.set :as set]
@ -1479,6 +1480,44 @@
[{:type :set-remote-synced
:remote-synced (:remote-synced shape)}]}))))))
(defn- update-tokens
"Token synchronization algorithm. Copy the applied tokens that have changed
in the origin shape to the dest shape (applying or removing as necessary).
Only the given token attributes are synced."
[changes container dest-shape orig-shape token-attrs]
(let [orig-tokens (get orig-shape :applied-tokens {})
dest-tokens (get dest-shape :applied-tokens {})
dest-tokens' (reduce (fn [dest-tokens' token-attr]
(let [orig-token (get orig-tokens token-attr)
dest-token (get dest-tokens token-attr)]
(if (= orig-token dest-token)
dest-tokens'
(if (nil? orig-token)
(dissoc dest-tokens' token-attr)
(assoc dest-tokens' token-attr orig-token)))))
dest-tokens
token-attrs)]
(if (= dest-tokens dest-tokens')
changes
(-> changes
(update :redo-changes conj (make-change
container
{:type :mod-obj
:id (:id dest-shape)
:operations [{:type :set
:attr :applied-tokens
:val dest-tokens'
:ignore-touched true}]}))
(update :undo-changes conj (make-change
container
{:type :mod-obj
:id (:id dest-shape)
:operations [{:type :set
:attr :applied-tokens
:val dest-tokens
:ignore-touched true}]}))))))
(defn- update-attrs
"The main function that implements the attribute sync algorithm. Copy
attributes that have changed in the origin shape to the dest shape.
@ -1511,37 +1550,41 @@
(loop [attrs (->> (seq (keys ctk/sync-attrs))
;; We don't update the flex-child attrs
(remove ctk/swap-keep-attrs)
;; We don't do automatic update of the `layout-grid-cells` property.
(remove #(= :layout-grid-cells %)))
applied-tokens #{}
roperations []
uoperations '()]
(let [attr (first attrs)]
(if (nil? attr)
(if (empty? roperations)
(if (and (empty? roperations) (empty? applied-tokens))
changes
(let [all-parents (cfh/get-parent-ids (:objects container)
(:id dest-shape))]
(-> changes
(update :redo-changes conj (make-change
container
{:type :mod-obj
:id (:id dest-shape)
:operations roperations}))
(update :redo-changes conj (make-change
container
{:type :reg-objects
:shapes all-parents}))
(update :undo-changes conj (make-change
container
{:type :mod-obj
:id (:id dest-shape)
:operations (vec uoperations)}))
(update :undo-changes concat [(make-change
container
{:type :reg-objects
:shapes all-parents})]))))
(cond-> changes
(seq roperations)
(-> (update :redo-changes conj (make-change
container
{:type :mod-obj
:id (:id dest-shape)
:operations roperations}))
(update :redo-changes conj (make-change
container
{:type :reg-objects
:shapes all-parents}))
(update :undo-changes conj (make-change
container
{:type :mod-obj
:id (:id dest-shape)
:operations (vec uoperations)}))
(update :undo-changes concat [(make-change
container
{:type :reg-objects
:shapes all-parents})]))
(seq applied-tokens)
(update-tokens container dest-shape origin-shape applied-tokens))))
(let [;; position-data is a special case because can be affected by :geometry-group and :content-group
;; so, if the position-data changes but the geometry is touched we need to reset the position-data
;; so it's calculated again
@ -1564,14 +1607,21 @@
:val (get dest-shape attr)
:ignore-touched true}
attr-group (get ctk/sync-attrs attr)]
attr-group (get ctk/sync-attrs attr)
token-attrs (cto/shape-attr->token-attrs attr)
applied-tokens' (cond-> applied-tokens
(not (and (touched attr-group)
omit-touched?))
(into token-attrs))]
(if (or (= (get origin-shape attr) (get dest-shape attr))
(and (touched attr-group) omit-touched?))
(recur (next attrs)
applied-tokens'
roperations
uoperations)
(recur (next attrs)
applied-tokens'
(conj roperations roperation)
(conj uoperations uoperation)))))))))

View file

@ -140,6 +140,14 @@
:layout-item-z-index
:layout-item-align-self})
(defn component-attr?
"Check if some attribute is one that is involved in component syncrhonization.
Note that design tokens also are involved, although they go by an alternate
route and thus they are not part of :sync-attrs."
[attr]
(or (get sync-attrs attr)
(= :applied-tokens attr)))
(defn instance-root?
"Check if this shape is the head of a top instance."
[shape]

View file

@ -163,3 +163,14 @@
::spacing
::rotation
::dimensions])
(defn shape-attr->token-attrs
[shape-attr]
(cond
(= :fills shape-attr) #{:fill}
(= :strokes shape-attr) #{:stroke-color :stroke-width}
(border-radius-keys shape-attr) #{shape-attr}
(sizing-keys shape-attr) #{shape-attr}
(opacity-keys shape-attr) #{shape-attr}
(spacing-keys shape-attr) #{shape-attr}
(rotation-keys shape-attr) #{shape-attr}))