🎉 Add design tokens to plugins API (#7602)

Co-authored-by: alonso.torres <alonso.torres@kaleidos.net>
This commit is contained in:
Andrés Moya
2025-11-14 11:14:56 +01:00
committed by GitHub
parent 2233f34a15
commit 3cc54fd988
18 changed files with 665 additions and 111 deletions

View File

@@ -9,7 +9,7 @@
[app.common.files.changes-builder :as pcb]
[app.common.types.tokens-lib :as ctob]))
(defn generate-update-active-sets
(defn- generate-update-active-sets
"Copy the active sets from the currently active themes and move them
to the hidden token theme and update the theme with
`update-theme-fn`.
@@ -28,12 +28,45 @@
(pcb/set-token-theme (ctob/get-id hidden-theme)
hidden-theme'))))
(defn generate-set-enabled-token-set
"Enable or disable a token set at `set-name` in `tokens-lib` without modifying a user theme."
[changes tokens-lib set-name enabled?]
(if enabled?
(generate-update-active-sets changes tokens-lib #(ctob/enable-set % set-name))
(generate-update-active-sets changes tokens-lib #(ctob/disable-set % set-name))))
(defn generate-toggle-token-set
"Toggle a token set at `set-name` in `tokens-lib` without modifying a
user theme."
"Toggle a token set at `set-name` in `tokens-lib` without modifying a user theme."
[changes tokens-lib set-name]
(generate-update-active-sets changes tokens-lib #(ctob/toggle-set % set-name)))
(defn- generate-update-active-token-theme
"Change the active state of a theme in `tokens-lib`. If after the change there is
any active theme other than the hidden one, deactivate the hidden theme."
[changes tokens-lib update-fn]
(let [active-token-themes (some-> tokens-lib
(update-fn)
(ctob/get-active-theme-paths))
active-token-themes' (if (= active-token-themes #{ctob/hidden-theme-path})
active-token-themes
(disj active-token-themes ctob/hidden-theme-path))]
(pcb/set-active-token-themes changes active-token-themes')))
(defn generate-set-active-token-theme
"Activate or deactivate a token theme in `tokens-lib`."
[changes tokens-lib id active?]
(if active?
(generate-update-active-token-theme changes tokens-lib
#(ctob/activate-theme % id))
(generate-update-active-token-theme changes tokens-lib
#(ctob/deactivate-theme % id))))
(defn generate-toggle-token-theme
"Toggle the active state of a token theme in `tokens-lib`."
[changes tokens-lib id]
(generate-update-active-token-theme changes tokens-lib
#(ctob/toggle-theme-active % id)))
(defn toggle-token-set-group
"Toggle a token set group at `group-path` in `tokens-lib` for a `tokens-lib-theme`."
[group-path tokens-lib tokens-lib-theme]

View File

@@ -310,6 +310,10 @@
schema:text-decoration
schema:dimensions])
(defn token-attr?
[attr]
(contains? all-keys attr))
(defn shape-attr->token-attrs
([shape-attr] (shape-attr->token-attrs shape-attr nil))
([shape-attr changed-sub-attr]
@@ -403,15 +407,15 @@
:text text-attributes
nil))
(defn appliable-attrs
(defn appliable-attrs-for-shape
"Returns intersection of shape `attributes` for `shape-type`."
[attributes shape-type is-layout]
(set/intersection attributes (shape-type->attributes shape-type is-layout)))
(defn any-appliable-attr?
(defn any-appliable-attr-for-shape?
"Checks if `token-type` supports given shape `attributes`."
[attributes token-type is-layout]
(seq (appliable-attrs attributes token-type is-layout)))
(d/not-empty? (appliable-attrs-for-shape attributes token-type is-layout)))
;; Token attrs that are set inside content blocks of text shapes, instead
;; at the shape level.

View File

@@ -758,7 +758,7 @@
(theme-active? [_ id] "predicate if token theme is active")
(activate-theme [_ id] "adds theme from the active-themes")
(deactivate-theme [_ id] "removes theme from the active-themes")
(toggle-theme-active? [_ id] "toggles theme in the active-themes")
(toggle-theme-active [_ id] "toggles theme in the active-themes")
(get-hidden-theme [_] "get the hidden temporary theme"))
(def schema:token-themes
@@ -901,6 +901,7 @@
(delete-token [_ set-id token-id] "delete a token from a set")
(toggle-set-in-theme [_ theme-id set-name] "toggle a set used / not used in a theme")
(get-active-themes-set-names [_] "set of set names that are active in the the active themes")
(token-set-active? [_ set-name] "if a set is active in any of the active themes")
(sets-at-path-all-active? [_ group-path] "compute active state for child sets at `group-path`.
Will return a value that matches this schema:
`:none` None of the nested sets are active
@@ -1206,7 +1207,7 @@ Will return a value that matches this schema:
(when-let [theme (get-theme this id)]
(contains? active-themes (get-theme-path theme))))
(toggle-theme-active? [this id]
(toggle-theme-active [this id]
(if (theme-active? this id)
(deactivate-theme this id)
(activate-theme this id)))
@@ -1270,6 +1271,10 @@ Will return a value that matches this schema:
(mapcat :sets)
(get-active-themes this)))
(token-set-active? [this set-name]
(let [set-names (get-active-themes-set-names this)]
(contains? set-names set-name)))
(sets-at-path-all-active? [this group-path]
(let [active-set-names (get-active-themes-set-names this)
prefixed-path-str (set-group-path->set-group-prefixed-path-str group-path)]

View File

@@ -1558,7 +1558,7 @@
:external-id "test-id-01"
:modified-at now
:sets #{"core"}))
(ctob/toggle-theme-active? (thi/id :theme-1)))
(ctob/toggle-theme-active (thi/id :theme-1)))
result (ctob/export-dtcg-json tokens-lib)
expected {"$themes" [{"description" ""
"group" "group-1"
@@ -1612,7 +1612,7 @@
:external-id "test-id-01"
:modified-at now
:sets #{"some/set"}))
(ctob/toggle-theme-active? (thi/id :theme-1)))
(ctob/toggle-theme-active (thi/id :theme-1)))
result (ctob/export-dtcg-multi-file tokens-lib)
expected {"$themes.json" [{"description" ""
"group" "group-1"

View File

@@ -39,6 +39,7 @@
(declare token-properties)
(declare update-layout-item-margin)
(declare all-attrs-appliable-for-token?)
;; Events to update the value of attributes with applied tokens ---------------------------------------------------------
@@ -519,7 +520,8 @@
(or
(and (ctsl/any-layout-immediate-child? objects shape)
(some ctt/spacing-margin-keys attributes))
(ctt/any-appliable-attr? attributes (:type shape) (:layout shape))))))
(and (ctt/any-appliable-attr-for-shape? attributes (:type shape) (:layout shape))
(all-attrs-appliable-for-token? attributes (:type token)))))))
shape-ids (d/nilv (keys shapes) [])
any-variant? (->> shapes vals (some ctk/is-variant?) boolean)
@@ -596,6 +598,7 @@
(watch [_ state _]
(let [objects (dsh/lookup-page-objects state)
shapes (into [] (keep (d/getf objects)) shape-ids)
shapes
(if expand-with-children
(into []
@@ -605,10 +608,15 @@
[shape])))
shapes)
shapes)
{:keys [attributes all-attributes on-update-shape]}
(get token-properties (:type token))
unapply-tokens?
(cft/shapes-token-applied? token shapes (or attrs all-attributes attributes))]
(cft/shapes-token-applied? token shapes (or attrs all-attributes attributes))
shape-ids (map :id shapes)]
(if unapply-tokens?
(rx/of
(unapply-token {:attributes (or attrs all-attributes attributes)
@@ -620,7 +628,7 @@
(apply-spacing-token {:token token
:attr attrs
:shapes shapes})
(apply-token {:attributes (or attrs attributes)
(apply-token {:attributes (if (empty? attrs) attributes attrs)
:token token
:shape-ids shape-ids
:on-update-shape on-update-shape}))))))))
@@ -808,3 +816,22 @@
(defn get-token-properties [token]
(get token-properties (:type token)))
(defn get-update-shape-fn
"Get the function that updates the attributes of a shape if this token is applied."
[token]
(when token
(-> (get-token-properties token)
:on-update-shape)))
(defn appliable-attributes-for-token
"Get the attributes to which this token type can be applied."
[token-type]
(let [props (get token-properties token-type)]
(or (:all-attributes props)
(:attributes props))))
(defn all-attrs-appliable-for-token?
"Check if any of the given attributes can be applied for the given token type."
[attributes token-type]
(set/subset? attributes (appliable-attributes-for-token token-type)))

View File

@@ -84,7 +84,8 @@
new-token-theme))]
(rx/of (dch/commit-changes changes)))))))))
(defn update-token-theme [id token-theme]
(defn update-token-theme
[id token-theme]
(ptk/reify ::update-token-theme
ptk/WatchEvent
(watch [it state _]
@@ -101,27 +102,38 @@
(pcb/set-token-theme (ctob/get-id token-theme) token-theme))]
(rx/of (dch/commit-changes changes))))))))
(defn toggle-token-theme-active? [id]
(ptk/reify ::toggle-token-theme-active?
(defn set-token-theme-active
[id active?]
(assert (uuid? id) "expected a uuid for `id`")
(assert (boolean? active?) "expected a boolean for `active?`")
(ptk/reify ::set-token-theme-active
ptk/WatchEvent
(watch [_ state _]
(let [data (dsh/lookup-file-data state)
tokens-lib (get-tokens-lib state)
changes (-> (pcb/empty-changes)
(pcb/with-library-data data)
(clt/generate-set-active-token-theme tokens-lib id active?))]
(rx/of (dch/commit-changes changes)
(dwtp/propagate-workspace-tokens))))))
(defn toggle-token-theme-active
[id]
(ptk/reify ::toggle-token-theme-active
ptk/WatchEvent
(watch [it state _]
(let [data (dsh/lookup-file-data state)
tokens-lib (get-tokens-lib state)
active-token-themes (some-> tokens-lib
(ctob/toggle-theme-active? id)
(ctob/get-active-theme-paths))
active-token-themes' (if (= active-token-themes #{ctob/hidden-theme-path})
active-token-themes
(disj active-token-themes ctob/hidden-theme-path))
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/set-active-token-themes active-token-themes'))]
(clt/generate-toggle-token-theme tokens-lib id))]
(rx/of
(dch/commit-changes changes)
(dwtp/propagate-workspace-tokens))))))
(defn delete-token-theme [id]
(defn delete-token-theme
[id]
(ptk/reify ::delete-token-theme
ptk/WatchEvent
(watch [it state _]
@@ -134,7 +146,7 @@
(dwtp/propagate-workspace-tokens))))))
(defn create-token-set
[set-name]
[token-set]
(ptk/reify ::create-token-set
ptk/UpdateEvent
(update [_ state]
@@ -145,20 +157,20 @@
(watch [it state _]
(let [data (dsh/lookup-file-data state)
tokens-lib (get data :tokens-lib)
set-name (ctob/normalize-set-name set-name)]
(if (and tokens-lib (ctob/get-set-by-name tokens-lib set-name))
token-set (ctob/rename token-set (ctob/normalize-set-name (ctob/get-name token-set)))]
(if (and tokens-lib (ctob/get-set-by-name tokens-lib (ctob/get-name token-set)))
(rx/of (ntf/show {:content (tr "errors.token-set-already-exists")
:type :toast
:level :error
:timeout 9000}))
(let [token-set (ctob/make-token-set :name set-name)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/set-token-set (ctob/get-id token-set) token-set))]
(let [changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/set-token-set (ctob/get-id token-set) token-set))]
(rx/of (set-selected-token-set-id (ctob/get-id token-set))
(dch/commit-changes changes))))))))
(defn rename-token-set-group [set-group-path set-group-fname]
(defn rename-token-set-group
[set-group-path set-group-fname]
(ptk/reify ::rename-token-set-group
ptk/WatchEvent
(watch [it _state _]
@@ -203,6 +215,22 @@
(rx/of (set-selected-token-set-id (ctob/get-id token-set))
(dch/commit-changes changes))))))))
(defn set-enabled-token-set
[name enabled?]
(assert (string? name) "expected a string for `name`")
(assert (boolean? enabled?) "expected a boolean for `enabled?`")
(ptk/reify ::set-enabled-token-set
ptk/WatchEvent
(watch [_ state _]
(let [data (dsh/lookup-file-data state)
tlib (get-tokens-lib state)
changes (-> (pcb/empty-changes)
(pcb/with-library-data data)
(clt/generate-set-enabled-token-set tlib name enabled?))]
(rx/of (dch/commit-changes changes)
(dwtp/propagate-workspace-tokens))))))
(defn toggle-token-set
[name]
(assert (string? name) "expected a string for `name`")
@@ -218,7 +246,8 @@
(rx/of (dch/commit-changes changes)
(dwtp/propagate-workspace-tokens))))))
(defn toggle-token-set-group [group-path]
(defn toggle-token-set-group
[group-path]
(ptk/reify ::toggle-token-set-group
ptk/WatchEvent
(watch [_ state _]
@@ -230,7 +259,8 @@
(dch/commit-changes changes)
(dwtp/propagate-workspace-tokens))))))
(defn import-tokens-lib [lib]
(defn import-tokens-lib
[lib]
(ptk/reify ::import-tokens-lib
ptk/WatchEvent
(watch [it state _]
@@ -265,7 +295,8 @@
(rx/of (dch/commit-changes changes)
(dwtp/propagate-workspace-tokens))))))
(defn drop-error [{:keys [error to-path]}]
(defn drop-error
[{:keys [error to-path]}]
(ptk/reify ::drop-error
ptk/WatchEvent
(watch [_ _ _]
@@ -282,7 +313,8 @@
;; FIXME: add schema for params
(defn drop-token-set-group [drop-opts]
(defn drop-token-set-group
[drop-opts]
(ptk/reify ::drop-token-set-group
ptk/WatchEvent
(watch [it state _]
@@ -344,47 +376,52 @@
(set-selected-token-set-id (ctob/get-id token-set)))))))
(defn create-token
[params]
(let [token (ctob/make-token params)]
(ptk/reify ::create-token
ptk/WatchEvent
(watch [it state _]
(if-let [token-set (lookup-token-set state)]
(let [data (dsh/lookup-file-data state)
token-type (:type token)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/set-token (ctob/get-id token-set)
(:id token)
token))]
([token] (create-token nil token))
([set-id token]
(ptk/reify ::create-token
ptk/WatchEvent
(watch [it state _]
(if-let [token-set (if set-id
(lookup-token-set state set-id)
(lookup-token-set state))]
(let [data (dsh/lookup-file-data state)
token-type (:type token)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/set-token (ctob/get-id token-set)
(:id token)
token))]
(rx/of (dch/commit-changes changes)
(ptk/data-event ::ev/event {::ev/name "create-token" :type token-type})))
(rx/of (dch/commit-changes changes)
(ptk/data-event ::ev/event {::ev/name "create-token" :type token-type})))
(rx/of (create-token-with-set token)))))))
(rx/of (create-token-with-set token)))))))
(defn update-token
[id params]
(assert (uuid? id) "expected uuid for `id`")
([id params] (update-token nil id params))
([set-id id params]
(assert (uuid? id) "expected uuid for `id`")
(ptk/reify ::update-token
ptk/WatchEvent
(watch [it state _]
(let [token-set (lookup-token-set state)
data (dsh/lookup-file-data state)
token (-> (get-tokens-lib state)
(ctob/get-token (ctob/get-id token-set) id))
token' (->> (merge token params)
(into {})
(ctob/make-token))
token-type (:type token)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/set-token (ctob/get-id token-set)
id
token'))]
(rx/of (dch/commit-changes changes)
(ptk/data-event ::ev/event {::ev/name "edit-token" :type token-type}))))))
(ptk/reify ::update-token
ptk/WatchEvent
(watch [it state _]
(let [token-set (if set-id
(lookup-token-set state set-id)
(lookup-token-set state))
data (dsh/lookup-file-data state)
token (-> (get-tokens-lib state)
(ctob/get-token (ctob/get-id token-set) id))
token' (->> (merge token params)
(into {})
(ctob/make-token))
token-type (:type token)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/set-token (ctob/get-id token-set)
id
token'))]
(rx/of (dch/commit-changes changes)
(ptk/data-event ::ev/event {::ev/name "edit-token" :type token-type})))))))
(defn delete-token
[set-id token-id]
@@ -413,10 +450,11 @@
(let [tokens (vals (ctob/get-tokens tokens-lib (ctob/get-id token-set)))
unames (map :name tokens)
suffix (tr "workspace.tokens.duplicate-suffix")
copy-name (cfh/generate-unique-name (:name token) unames :suffix suffix)]
(rx/of (create-token (assoc token
:id (uuid/next)
:name copy-name))))))))))
copy-name (cfh/generate-unique-name (:name token) unames :suffix suffix)
new-token (-> token
(ctob/reid (uuid/next))
(ctob/rename copy-name))]
(rx/of (create-token new-token)))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TOKEN UI OPS

View File

@@ -55,10 +55,7 @@
(defn generic-attribute-actions [attributes title {:keys [token selected-shapes on-update-shape hint allowed-shape-attributes]}]
(let [allowed-attributes (set/intersection attributes allowed-shape-attributes)
on-update-shape-fn
(or on-update-shape
(-> (dwta/get-token-properties token)
(:on-update-shape)))
on-update-shape-fn (or on-update-shape (dwta/get-update-shape-fn token))
{:keys [selected-pred shape-ids]}
(attribute-actions token selected-shapes allowed-attributes)]

View File

@@ -69,6 +69,12 @@
[:fn {:error/fn #(tr "workspace.tokens.token-name-duplication-validation-error" (:value %))}
#(not (cft/token-name-path-exists? % tokens-tree))]])
(defn validate-token-name
[tokens-tree name]
(let [schema (make-token-name-schema tokens-tree)
explainer (sm/explainer schema)]
(-> name explainer sm/simplify not-empty)))
(def ^:private schema:token-description
[:string {:max 2048 :error/fn #(tr "errors.field-max-length" 2048)}])
@@ -363,27 +369,20 @@
;; Allow setting editing token to it's own path
(d/dissoc-in token-path)))
validate-token-name
(mf/with-memo [tokens-tree-in-selected-set]
(let [schema (make-token-name-schema tokens-tree-in-selected-set)
explainer (sm/explainer schema)]
(fn [name]
(-> name explainer sm/simplify not-empty))))
on-blur-name
(mf/use-fn
(mf/deps touched-name? validate-token-name)
(mf/deps touched-name?)
(fn [e]
(let [value (dom/get-target-val e)
errors (validate-token-name value)]
errors (validate-token-name tokens-tree-in-selected-set value)]
(when touched-name? (reset! warning-name-change* true))
(reset! name-errors* errors))))
on-update-name-debounced
(mf/with-memo [touched-name? validate-token-name]
(mf/with-memo [touched-name?]
(uf/debounce (fn [token-name]
(when touched-name?
(reset! name-errors* (validate-token-name token-name))))
(reset! name-errors* (validate-token-name tokens-tree-in-selected-set token-name))))
300))
on-update-name
@@ -487,7 +486,7 @@
on-submit
(mf/use-fn
(mf/deps is-create token active-theme-tokens validate-token validate-token-name validate-token-description)
(mf/deps is-create token active-theme-tokens validate-token validate-token-description)
(fn [e]
(dom/prevent-default e)
;; We have to re-validate the current form values before submitting
@@ -496,7 +495,7 @@
;; and press enter before the next validations could return.
(let [clean-name (clean-name (mf/ref-val token-name-ref))
valid-name? (empty? (validate-token-name clean-name))
valid-name? (empty? (validate-token-name tokens-tree-in-selected-set clean-name))
value (mf/ref-val value-ref)
clean-description (mf/ref-val description-ref)
@@ -512,10 +511,10 @@
(fn [valid-token]
(st/emit!
(if is-create
(dwtl/create-token {:name clean-name
:type token-type
:value (:value valid-token)
:description clean-description})
(dwtl/create-token (ctob/make-token {:name clean-name
:type token-type
:value (:value valid-token)
:description clean-description}))
(dwtl/update-token (:id token)
{:name clean-name

View File

@@ -166,7 +166,7 @@
;; Edge-case for allowing margin attribute on shapes inside layout parent
(and selected-inside-layout? (set/subset? ctt/spacing-margin-keys attrs))
(some (fn [shape]
(ctt/any-appliable-attr? attrs (:type shape) (:layout shape)))
(ctt/any-appliable-attr-for-shape? attrs (:type shape) (:layout shape)))
selected-shapes)))
(def token-types-with-status-icon

View File

@@ -33,15 +33,12 @@
can-edit?
(mf/use-ctx ctx/can-edit?)
active-token-sets-names
(mf/with-memo [tokens-lib]
(some-> tokens-lib (ctob/get-active-themes-set-names)))
token-set-active?
(mf/use-fn
(mf/deps active-token-sets-names)
(mf/deps tokens-lib)
(fn [name]
(contains? active-token-sets-names name)))
(when tokens-lib
(ctob/token-set-active? tokens-lib name))))
token-set-group-active?
(mf/use-fn

View File

@@ -28,7 +28,8 @@
(if-let [parent-path (ctob/get-set-path parent-set)]
(->> (concat parent-path (ctob/split-set-name name))
(ctob/join-set-path))
(ctob/normalize-set-name name))]
(ctob/normalize-set-name name))
token-set (ctob/make-token-set :name name)]
(st/emit! (ptk/data-event ::ev/event {::ev/name "create-token-set" :name name})
(dwtl/create-token-set name))))
(dwtl/create-token-set token-set))))

View File

@@ -51,7 +51,7 @@
true)) ;; if still no library exists, cannot be duplicate
:type-properties {:error/fn #(tr "workspace.tokens.theme-name-already-exists")}}))
(defn- validate-theme-name
(defn validate-theme-name
[tokens-lib group theme-id name]
(let [schema (theme-name-schema {:tokens-lib tokens-lib :theme-id theme-id :group group})
validation (m/explain schema (str/trim name))]
@@ -151,7 +151,7 @@
[:div {:on-click (fn [e]
(dom/prevent-default e)
(dom/stop-propagation e)
(st/emit! (dwtl/toggle-token-theme-active? id)))}
(st/emit! (dwtl/toggle-token-theme-active id)))}
[:& switch {:name (tr "workspace.tokens.theme-name" name)
:on-change (constantly nil)
:selected? selected?}]]]

View File

@@ -31,7 +31,7 @@
selected? (get active-theme-paths theme-id)
select-theme (fn [e]
(dom/stop-propagation e)
(st/emit! (dwtl/toggle-token-theme-active? id))
(st/emit! (dwtl/toggle-token-theme-active id))
(on-close))]]
[:li {:key theme-id
:role "option"

View File

@@ -28,6 +28,7 @@
[app.plugins.register :as r]
[app.plugins.shape :as shape]
[app.plugins.text :as text]
[app.plugins.tokens :as tokens]
[app.plugins.utils :as u]
[app.util.object :as obj]
[beicon.v2.core :as rx]
@@ -959,6 +960,12 @@
(map #(lib-component-proxy plugin-id file-id %)))]
(apply array components)))}
:tokens
{:this true
:get
(fn [_]
(tokens/tokens-catalog plugin-id file-id))}
:createColor
(fn []
(cond

View File

@@ -31,6 +31,7 @@
[app.common.types.shape.radius :as ctsr]
[app.common.types.shape.shadow :as ctss]
[app.common.types.text :as txt]
[app.common.types.token :as cto]
[app.common.uuid :as uuid]
[app.main.data.plugins :as dp]
[app.main.data.workspace :as dw]
@@ -42,6 +43,7 @@
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.texts :as dwt]
[app.main.data.workspace.tokens.application :as dwta]
[app.main.data.workspace.variants :as dwv]
[app.main.repo :as rp]
[app.main.store :as st]
@@ -765,6 +767,8 @@
;; Interactions
:interactions
{:this true
:get
@@ -1224,6 +1228,31 @@
(let [guide (u/proxy->ruler-guide value)]
(st/emit! (dwgu/remove-guide guide)))))
:tokens
{:this true
:get
(fn [_]
(let [tokens
(-> (u/locate-shape file-id page-id id)
(get :applied-tokens))]
(reduce
(fn [acc [prop name]]
(obj/set! acc (d/name prop) name))
#js {}
tokens)))}
:applyToken
(fn [token attrs]
(let [token (u/locate-token file-id (obj/get token "$set-id") (obj/get token "$id"))
kw-attrs (into #{} (map keyword attrs))]
(if (some #(not (cto/token-attr? %)) kw-attrs)
(u/display-not-valid :applyToken attrs)
(st/emit!
(dwta/toggle-token {:token token
:attrs kw-attrs
:shape-ids [id]
:expand-with-children false})))))
:isVariantHead
(fn []
(let [shape (u/locate-shape file-id page-id id)

View File

@@ -0,0 +1,396 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.plugins.tokens
(:require
[app.common.data.macros :as dm]
[app.common.types.token :as cto]
[app.common.types.tokens-lib :as ctob]
[app.common.uuid :as uuid]
[app.main.data.workspace.tokens.application :as dwta]
[app.main.data.workspace.tokens.library-edit :as dwtl]
[app.main.store :as st]
[app.main.ui.workspace.tokens.management.create.form :as token-form]
[app.main.ui.workspace.tokens.themes.create-modal :as theme-form]
[app.plugins.utils :as u]
[app.util.object :as obj]
[clojure.datafy :refer [datafy]]))
(defn- apply-token-to-shapes
[file-id set-id id shape-ids attrs]
(let [token (u/locate-token file-id set-id id)
kw-attrs (into #{} (map keyword attrs))]
(if (some #(not (cto/token-attr? %)) kw-attrs)
(u/display-not-valid :applyToSelected attrs)
(st/emit!
(dwta/toggle-token {:token token
:attrs kw-attrs
:shape-ids shape-ids
:expand-with-children false})))))
(defn token-proxy
[plugin-id file-id set-id id]
(obj/reify {:name "TokenSetProxy"}
:$plugin {:enumerable false :get (constantly plugin-id)}
:$file-id {:enumerable false :get (constantly file-id)}
:$set-id {:enumerable false :get (constantly set-id)}
:$id {:enumerable false :get (constantly id)}
:id
{:get #(dm/str id)}
:name
{:this true
:get
(fn [_]
(let [token (u/locate-token file-id set-id id)]
(ctob/get-name token)))
:set
(fn [_ value]
(let [tokens-lib (u/locate-tokens-lib file-id)
errors (token-form/validate-token-name
(ctob/get-tokens tokens-lib set-id)
value)]
(cond
(some? errors)
(u/display-not-valid :name (first errors))
:else
(st/emit! (dwtl/update-token set-id id {:name value})))))}
:type
{:this true
:get
(fn [_]
(let [token (u/locate-token file-id set-id id)]
(-> (:type token) (cto/token-type->dtcg-token-type))))}
:value
{:this true
:get
(fn [_]
(let [token (u/locate-token file-id set-id id)]
(:value token)))}
:description
{:this true
:get
(fn [_]
(let [token (u/locate-token file-id set-id id)]
(ctob/get-description token)))}
:duplicate
(fn []
(let [token (u/locate-token file-id set-id id)
token' (ctob/make-token (-> (datafy token)
(dissoc :id
:modified-at)))]
(st/emit! (dwtl/create-token set-id token'))
(token-proxy plugin-id file-id set-id (:id token'))))
:remove
(fn []
(st/emit! (dwtl/delete-token set-id id)))
:applyToShapes
(fn [shapes attrs]
(apply-token-to-shapes file-id set-id id (map :id shapes) attrs))
:applyToSelected
(fn [attrs]
(let [selected (get-in @st/state [:workspace-local :selected])]
(apply-token-to-shapes file-id set-id id selected attrs)))))
(defn token-set-proxy
[plugin-id file-id id]
(obj/reify {:name "TokenSetProxy"}
:$plugin {:enumerable false :get (constantly plugin-id)}
:$file-id {:enumerable false :get (constantly file-id)}
:$id {:enumerable false :get (constantly id)}
:id
{:get #(dm/str id)}
:name
{:this true
:get
(fn [_]
(let [set (u/locate-token-set file-id id)]
(ctob/get-name set)))
:set
(fn [_ value]
(let [set (u/locate-token-set file-id id)]
(cond
(not (string? value))
(u/display-not-valid :name value)
:else
(st/emit! (dwtl/update-token-set set value)))))}
:active
{:this true
:enumerable false
:get
(fn [_]
(let [tokens-lib (u/locate-tokens-lib file-id)
set (u/locate-token-set file-id id)]
(ctob/token-set-active? tokens-lib (ctob/get-name set))))
:set
(fn [_ value]
(let [set (u/locate-token-set file-id id)]
(st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) value))))}
:toggleActive
(fn [_]
(let [set (u/locate-token-set file-id id)]
(st/emit! (dwtl/toggle-token-set (ctob/get-name set)))))
:tokens
{:this true
:enumerable false
:get
(fn [_]
(let [file (u/locate-file file-id)
tokens-lib (->> file :data :tokens-lib)]
(->> (ctob/get-tokens tokens-lib id)
(vals)
(map #(token-proxy plugin-id file-id id (:id %)))
(apply array))))}
:tokensByType
{:this true
:enumerable false
:get
(fn [_]
(let [file (u/locate-file file-id)
tokens-lib (->> file :data :tokens-lib)
tokens (ctob/get-tokens tokens-lib id)]
(->> tokens
(vals)
(sort-by :name)
(group-by #(cto/token-type->dtcg-token-type (:type %)))
(into [])
(mapv (fn [[type tokens]]
#js [(name type)
(->> tokens
(map #(token-proxy plugin-id file-id id (:id %)))
(apply array))]))
(apply array))))}
:getTokenById
(fn [token-id]
(cond
(not (string? token-id))
(u/display-not-valid :getTokenById token-id)
:else
(let [token-id (uuid/parse token-id)
token (u/locate-token file-id id token-id)]
(when (some? token)
(token-proxy plugin-id file-id id token-id)))))
:addToken
(fn [type-str name value]
(let [type (cto/dtcg-token-type->token-type type-str)]
(cond
(nil? type)
(u/display-not-valid :addTokenType type-str)
(not (string? name))
(u/display-not-valid :addTokenName name)
:else
(let [token (ctob/make-token {:type type
:name name
:value value})]
(st/emit! (dwtl/create-token id token))
(token-proxy plugin-id file-id (:id set) (:id token))))))
:duplicate
(fn []
(let [set (u/locate-token-set file-id id)
set' (ctob/make-token-set (-> (datafy set)
(dissoc :id
:modified-at)))]
(st/emit! (dwtl/create-token-set set'))
(token-set-proxy plugin-id file-id (:id set'))))
:remove
(fn []
(st/emit! (dwtl/delete-token-set id)))))
(defn token-theme-proxy
[plugin-id file-id id]
(obj/reify {:name "TokenThemeProxy"}
:$plugin {:enumerable false :get (constantly plugin-id)}
:$file-id {:enumerable false :get (constantly file-id)}
:$id {:enumerable false :get (constantly id)}
:id
{:get #(dm/str id)}
:external-id
{:this true
:get
(fn [_]
(let [theme (u/locate-token-theme file-id id)]
(:external-id theme)))}
:group
{:this true
:get
(fn [_]
(let [theme (u/locate-token-theme file-id id)]
(:group theme)))
:set
(fn [_ value]
(let [theme (u/locate-token-theme file-id id)]
(cond
(not (string? value))
(u/display-not-valid :group value)
:else
(st/emit! (dwtl/update-token-theme id (assoc theme :group value))))))}
:name
{:this true
:get
(fn [_]
(let [theme (u/locate-token-theme file-id id)]
(:name theme)))
:set
(fn [_ value]
(let [theme (u/locate-token-theme file-id id)
errors (theme-form/validate-theme-name
(u/locate-tokens-lib file-id)
(:group theme)
id
value)]
(cond
(some? errors)
(u/display-not-valid :name (first errors))
:else
(st/emit! (dwtl/update-token-theme id (assoc theme :name value))))))}
:active
{:this true
:enumerable false
:get
(fn [_]
(let [tokens-lib (u/locate-tokens-lib file-id)]
(ctob/theme-active? tokens-lib id)))
:set
(fn [_ value]
(st/emit! (dwtl/set-token-theme-active id value)))}
:toggleActive
(fn [_]
(st/emit! (dwtl/toggle-token-theme-active id)))
:activeSets
{:this true :get (fn [_])}
:addSet
(fn [tokenSet]
(let [theme (u/locate-token-theme file-id id)]
(st/emit! (dwtl/update-token-theme id (ctob/enable-set theme (obj/get tokenSet :name))))))
:removeSet
(fn [tokenSet]
(let [theme (u/locate-token-theme file-id id)]
(st/emit! (dwtl/update-token-theme id (ctob/disable-set theme (obj/get tokenSet :name))))))
:duplicate
(fn []
(let [theme (u/locate-token-theme file-id id)
theme' (ctob/make-token-theme (-> (datafy theme)
(dissoc :id
:modified-at)))]
(st/emit! (dwtl/create-token-theme theme'))
(token-theme-proxy plugin-id file-id (:id theme'))))
:remove
(fn []
(st/emit! (dwtl/delete-token-theme id)))))
(defn tokens-catalog
[plugin-id file-id]
(obj/reify {:name "TokensCatalog"}
:$plugin {:enumerable false :get (constantly plugin-id)}
:$id {:enumerable false :get (constantly file-id)}
:themes
{:this true
:enumerable false
:get
(fn [_]
(let [file (u/locate-file file-id)
tokens-lib (->> file :data :tokens-lib)
themes (->> (ctob/get-themes tokens-lib)
(remove #(= (:id %) uuid/zero)))]
(apply array (map #(token-theme-proxy plugin-id file-id (ctob/get-id %)) themes))))}
:sets
{:this true
:enumerable false
:get
(fn [_]
(let [file (u/locate-file file-id)
tokens-lib (->> file :data :tokens-lib)
sets (ctob/get-sets tokens-lib)]
(apply array (map #(token-set-proxy plugin-id file-id (ctob/get-id %)) sets))))}
:addTheme
(fn [group name]
(cond
(not (string? group))
(u/display-not-valid :addThemeGroup group)
(not (string? name))
(u/display-not-valid :addThemeName name)
:else
(let [theme (ctob/make-token-theme {:group group
:name name})]
(st/emit! (dwtl/create-token-theme theme))
(token-theme-proxy plugin-id file-id (:id theme)))))
:addSet
(fn [name]
(cond
(not (string? name))
(u/display-not-valid :addSetName name)
:else
(let [set (ctob/make-token-set {:name name})]
(st/emit! (dwtl/create-token-set set))
(token-set-proxy plugin-id file-id (:id set)))))
:getThemeById
(fn [theme-id]
(cond
(not (string? theme-id))
(u/display-not-valid :getThemeById theme-id)
:else
(let [theme-id (uuid/parse theme-id)
theme (u/locate-token-theme file-id theme-id)]
(when (some? theme)
(token-theme-proxy plugin-id file-id theme-id)))))
:getSetById
(fn [set-id]
(cond
(not (string? set-id))
(u/display-not-valid :getSetById set-id)
:else
(let [set-id (uuid/parse set-id)
set (u/locate-token-set file-id set-id)]
(when (some? set)
(token-set-proxy plugin-id file-id set-id)))))))

View File

@@ -11,6 +11,7 @@
[app.common.data.macros :as dm]
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.common.types.tokens-lib :as ctob]
[app.main.data.helpers :as dsh]
[app.main.store :as st]
[app.util.object :as obj]))
@@ -52,6 +53,26 @@
(assert (uuid? id) "Component not valid uuid")
(dm/get-in (locate-file file-id) [:data :components id]))
(defn locate-tokens-lib
[file-id]
(let [file (locate-file file-id)]
(->> file :data :tokens-lib)))
(defn locate-token-theme
[file-id id]
(let [tokens-lib (locate-tokens-lib file-id)]
(ctob/get-theme tokens-lib id)))
(defn locate-token-set
[file-id set-id]
(let [tokens-lib (locate-tokens-lib file-id)]
(ctob/get-set tokens-lib set-id)))
(defn locate-token
[file-id set-id token-id]
(let [tokens-lib (locate-tokens-lib file-id)]
(ctob/get-token tokens-lib set-id token-id)))
(defn locate-presence
[session-id]
(dm/get-in @st/state [:workspace-presence session-id]))

View File

@@ -36,7 +36,7 @@
done
(let [file (setup-file-with-token-lib)
store (ths/setup-store file)
events [(dwtl/create-token-set "Set B")]]
events [(dwtl/create-token-set (ctob/make-token-set :name "Set B"))]]
(tohs/run-store-async
store done events