mirror of
https://github.com/penpot/penpot.git
synced 2025-02-01 03:49:22 -05:00
✨ Synchronize tokens in components
This commit is contained in:
parent
2a766a7190
commit
6077ba6690
4 changed files with 92 additions and 23 deletions
|
@ -1153,7 +1153,7 @@
|
||||||
; We need to trigger a sync if the shape has changed any
|
; We need to trigger a sync if the shape has changed any
|
||||||
; attribute that participates in components synchronization.
|
; attribute that participates in components synchronization.
|
||||||
(and (= (:type operation) :set)
|
(and (= (:type operation) :set)
|
||||||
(get ctk/sync-attrs (:attr operation))))
|
(ctk/component-attr? (:attr operation))))
|
||||||
any-sync? (some need-sync? operations)]
|
any-sync? (some need-sync? operations)]
|
||||||
(when any-sync?
|
(when any-sync?
|
||||||
(if page-id
|
(if page-id
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.types.shape.interactions :as ctsi]
|
[app.common.types.shape.interactions :as ctsi]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
[app.common.types.token :as cto]
|
||||||
[app.common.types.typography :as cty]
|
[app.common.types.typography :as cty]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
|
@ -1479,6 +1480,44 @@
|
||||||
[{:type :set-remote-synced
|
[{:type :set-remote-synced
|
||||||
:remote-synced (:remote-synced shape)}]}))))))
|
: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
|
(defn- update-attrs
|
||||||
"The main function that implements the attribute sync algorithm. Copy
|
"The main function that implements the attribute sync algorithm. Copy
|
||||||
attributes that have changed in the origin shape to the dest shape.
|
attributes that have changed in the origin shape to the dest shape.
|
||||||
|
@ -1511,37 +1550,41 @@
|
||||||
(loop [attrs (->> (seq (keys ctk/sync-attrs))
|
(loop [attrs (->> (seq (keys ctk/sync-attrs))
|
||||||
;; We don't update the flex-child attrs
|
;; We don't update the flex-child attrs
|
||||||
(remove ctk/swap-keep-attrs)
|
(remove ctk/swap-keep-attrs)
|
||||||
|
|
||||||
;; We don't do automatic update of the `layout-grid-cells` property.
|
;; We don't do automatic update of the `layout-grid-cells` property.
|
||||||
(remove #(= :layout-grid-cells %)))
|
(remove #(= :layout-grid-cells %)))
|
||||||
|
applied-tokens #{}
|
||||||
roperations []
|
roperations []
|
||||||
uoperations '()]
|
uoperations '()]
|
||||||
|
|
||||||
(let [attr (first attrs)]
|
(let [attr (first attrs)]
|
||||||
(if (nil? attr)
|
(if (nil? attr)
|
||||||
(if (empty? roperations)
|
(if (and (empty? roperations) (empty? applied-tokens))
|
||||||
changes
|
changes
|
||||||
(let [all-parents (cfh/get-parent-ids (:objects container)
|
(let [all-parents (cfh/get-parent-ids (:objects container)
|
||||||
(:id dest-shape))]
|
(:id dest-shape))]
|
||||||
(-> changes
|
(cond-> changes
|
||||||
(update :redo-changes conj (make-change
|
(seq roperations)
|
||||||
container
|
(-> (update :redo-changes conj (make-change
|
||||||
{:type :mod-obj
|
container
|
||||||
:id (:id dest-shape)
|
{:type :mod-obj
|
||||||
:operations roperations}))
|
:id (:id dest-shape)
|
||||||
(update :redo-changes conj (make-change
|
:operations roperations}))
|
||||||
container
|
(update :redo-changes conj (make-change
|
||||||
{:type :reg-objects
|
container
|
||||||
:shapes all-parents}))
|
{:type :reg-objects
|
||||||
(update :undo-changes conj (make-change
|
:shapes all-parents}))
|
||||||
container
|
(update :undo-changes conj (make-change
|
||||||
{:type :mod-obj
|
container
|
||||||
:id (:id dest-shape)
|
{:type :mod-obj
|
||||||
:operations (vec uoperations)}))
|
:id (:id dest-shape)
|
||||||
(update :undo-changes concat [(make-change
|
:operations (vec uoperations)}))
|
||||||
container
|
(update :undo-changes concat [(make-change
|
||||||
{:type :reg-objects
|
container
|
||||||
:shapes all-parents})]))))
|
{: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
|
(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, if the position-data changes but the geometry is touched we need to reset the position-data
|
||||||
;; so it's calculated again
|
;; so it's calculated again
|
||||||
|
@ -1564,14 +1607,21 @@
|
||||||
:val (get dest-shape attr)
|
:val (get dest-shape attr)
|
||||||
:ignore-touched true}
|
: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))
|
(if (or (= (get origin-shape attr) (get dest-shape attr))
|
||||||
(and (touched attr-group) omit-touched?))
|
(and (touched attr-group) omit-touched?))
|
||||||
(recur (next attrs)
|
(recur (next attrs)
|
||||||
|
applied-tokens'
|
||||||
roperations
|
roperations
|
||||||
uoperations)
|
uoperations)
|
||||||
(recur (next attrs)
|
(recur (next attrs)
|
||||||
|
applied-tokens'
|
||||||
(conj roperations roperation)
|
(conj roperations roperation)
|
||||||
(conj uoperations uoperation)))))))))
|
(conj uoperations uoperation)))))))))
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,14 @@
|
||||||
:layout-item-z-index
|
:layout-item-z-index
|
||||||
:layout-item-align-self})
|
: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?
|
(defn instance-root?
|
||||||
"Check if this shape is the head of a top instance."
|
"Check if this shape is the head of a top instance."
|
||||||
[shape]
|
[shape]
|
||||||
|
|
|
@ -163,3 +163,14 @@
|
||||||
::spacing
|
::spacing
|
||||||
::rotation
|
::rotation
|
||||||
::dimensions])
|
::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}))
|
||||||
|
|
Loading…
Add table
Reference in a new issue