mirror of
https://github.com/penpot/penpot.git
synced 2025-01-21 06:02:32 -05:00
Merge pull request #262 from tokens-studio/refactor-types-1
🔧 Add tokens-lib custom type
This commit is contained in:
commit
6f37a43be1
20 changed files with 937 additions and 173 deletions
|
@ -6,6 +6,8 @@
|
|||
|
||||
(ns user
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.fressian :as fres]
|
||||
[app.common.pprint :as pp]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.desc-js-like :as smdj]
|
||||
|
|
|
@ -44,8 +44,8 @@
|
|||
|
||||
(defn ordered-map
|
||||
([] lkm/empty-linked-map)
|
||||
([a] (conj lkm/empty-linked-map a))
|
||||
([a & xs] (apply conj lkm/empty-linked-map a xs)))
|
||||
([k a] (assoc lkm/empty-linked-map k a))
|
||||
([k a & xs] (apply assoc lkm/empty-linked-map k a xs)))
|
||||
|
||||
(defn ordered-set?
|
||||
[o]
|
||||
|
@ -564,6 +564,41 @@
|
|||
new-elems
|
||||
(remove p? after))))
|
||||
|
||||
(defn addm-at-index
|
||||
"Insert an element in an ordered map at an arbitrary index"
|
||||
[coll index key element]
|
||||
(assert (ordered-map? coll))
|
||||
(-> (ordered-map)
|
||||
(into (take index coll))
|
||||
(assoc key element)
|
||||
(into (drop index coll))))
|
||||
|
||||
(defn insertm-at-index
|
||||
"Insert a map {k v} of elements in an ordered map at an arbitrary index"
|
||||
[coll index new-elems]
|
||||
(assert (ordered-map? coll))
|
||||
(-> (ordered-map)
|
||||
(into (take index coll))
|
||||
(into new-elems)
|
||||
(into (drop index coll))))
|
||||
|
||||
(defn adds-at-index
|
||||
"Insert an element in an ordered set at an arbitrary index"
|
||||
[coll index element]
|
||||
(assert (ordered-set? coll))
|
||||
(-> (ordered-set)
|
||||
(into (take index coll))
|
||||
(conj element)
|
||||
(into (drop index coll))))
|
||||
|
||||
(defn inserts-at-index
|
||||
"Insert a list of elements in an ordered set at an arbitrary index"
|
||||
[coll index new-elems]
|
||||
(assert (ordered-set? coll))
|
||||
(-> (ordered-set)
|
||||
(into (take index coll))
|
||||
(into new-elems)
|
||||
(into (drop index coll))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Data Parsing / Conversion
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.token-theme :as ctot]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-list :as ctol]
|
||||
[app.common.types.tokens-theme-list :as ctotl]
|
||||
[app.common.types.typographies-list :as ctyl]
|
||||
|
@ -289,28 +290,37 @@
|
|||
[:map {:title "ModTokenSetChange"}
|
||||
[:type [:= :mod-token-set]]
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]
|
||||
[:token-set ::ctot/token-set]]]
|
||||
|
||||
[:del-token-set
|
||||
[:map {:title "DelTokenSetChange"}
|
||||
[:type [:= :del-token-set]]
|
||||
[:id ::sm/uuid]]]
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]]]
|
||||
|
||||
[:add-token
|
||||
[:map {:title "AddTokenChange"}
|
||||
[:type [:= :add-token]]
|
||||
[:set-id ::sm/uuid]
|
||||
[:set-name :string]
|
||||
[:token ::cto/token]]]
|
||||
|
||||
[:mod-token
|
||||
[:map {:title "ModTokenChange"}
|
||||
[:type [:= :mod-token]]
|
||||
[:set-id ::sm/uuid]
|
||||
[:set-name :string]
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]
|
||||
[:token ::cto/token]]]
|
||||
|
||||
[:del-token
|
||||
[:map {:title "DelTokenChange"}
|
||||
[:type [:= :del-token]]
|
||||
[:id ::sm/uuid]]]]])
|
||||
[:set-name :string]
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]]]]])
|
||||
|
||||
(sm/register! ::changes
|
||||
[:sequential {:gen/max 2} ::change])
|
||||
|
@ -780,16 +790,37 @@
|
|||
;; -- Tokens
|
||||
|
||||
(defmethod process-change :add-token
|
||||
[data {:keys [token]}]
|
||||
(ctol/add-token data token))
|
||||
[data {:keys [set-id set-name token]}]
|
||||
(-> data
|
||||
(ctol/add-token set-id token)
|
||||
(update :tokens-lib
|
||||
#(-> %
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/add-token-in-set set-name (ctob/make-token token))))))
|
||||
|
||||
(defmethod process-change :mod-token
|
||||
[data {:keys [id token]}]
|
||||
(ctol/update-token data id merge token))
|
||||
[data {:keys [set-name id name token]}]
|
||||
(-> data
|
||||
(ctol/update-token id merge token)
|
||||
(update :tokens-lib
|
||||
#(-> %
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/update-token-in-set
|
||||
set-name
|
||||
name
|
||||
(fn [old-token]
|
||||
(ctob/make-token (merge old-token token))))))))
|
||||
|
||||
(defmethod process-change :del-token
|
||||
[data {:keys [id]}]
|
||||
(ctol/delete-token data id))
|
||||
[data {:keys [set-name id name]}]
|
||||
(-> data
|
||||
(ctol/delete-token id)
|
||||
(update :tokens-lib
|
||||
#(-> %
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/delete-token-from-set
|
||||
set-name
|
||||
name)))))
|
||||
|
||||
(defmethod process-change :add-temporary-token-theme
|
||||
[data {:keys [token-theme]}]
|
||||
|
@ -817,15 +848,32 @@
|
|||
|
||||
(defmethod process-change :add-token-set
|
||||
[data {:keys [token-set]}]
|
||||
(ctotl/add-token-set data token-set))
|
||||
(-> data
|
||||
(ctotl/add-token-set token-set)
|
||||
(update :tokens-lib
|
||||
#(-> %
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set token-set))))))
|
||||
|
||||
(defmethod process-change :mod-token-set
|
||||
[data {:keys [id token-set]}]
|
||||
(ctotl/update-token-set data id merge token-set))
|
||||
[data {:keys [id name token-set]}]
|
||||
(-> data
|
||||
(ctotl/update-token-set id merge token-set)
|
||||
(update :tokens-lib
|
||||
#(-> %
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/update-set name (fn [prev-set]
|
||||
(merge prev-set
|
||||
(dissoc token-set :tokens))))))))
|
||||
|
||||
(defmethod process-change :del-token-set
|
||||
[data {:keys [id]}]
|
||||
(ctotl/delete-token-set data id))
|
||||
[data {:keys [id name]}]
|
||||
(-> data
|
||||
(ctotl/delete-token-set id)
|
||||
(update :tokens-lib
|
||||
#(-> %
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/delete-set name)))))
|
||||
|
||||
;; === Operations
|
||||
(defmethod process-operation :set
|
||||
|
@ -980,5 +1028,3 @@
|
|||
(defmethod frames-changed :default
|
||||
[_ _]
|
||||
nil)
|
||||
|
||||
|
||||
|
|
|
@ -737,48 +737,48 @@
|
|||
[changes token-set]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :add-token-set :token-set token-set})
|
||||
(update :undo-changes conj {:type :del-token-set :id (:id token-set)})
|
||||
(update :undo-changes conj {:type :del-token-set :id (:id token-set) :name (:name token-set)})
|
||||
(apply-changes-local)))
|
||||
|
||||
(defn update-token-set
|
||||
[changes token-set prev-token-set]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :mod-token-set :id (:id token-set) :token-set token-set})
|
||||
(update :undo-changes conj {:type :mod-token-set :id (:id token-set) :token-set (or prev-token-set token-set)})
|
||||
(update :redo-changes conj {:type :mod-token-set :id (:id token-set) :name (:name prev-token-set) :token-set token-set})
|
||||
(update :undo-changes conj {:type :mod-token-set :id (:id token-set) :name (:name prev-token-set) :token-set (or prev-token-set token-set)})
|
||||
(apply-changes-local)))
|
||||
|
||||
(defn delete-token-set
|
||||
[changes token-set-id]
|
||||
[changes token-set-id token-set-name]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
prev-token-set (get-in library-data [:token-sets-index token-set-id])]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :del-token-set :id token-set-id})
|
||||
(update :redo-changes conj {:type :del-token-set :id token-set-id :name token-set-name})
|
||||
(update :undo-changes conj {:type :add-token-set :token-set prev-token-set})
|
||||
(apply-changes-local))))
|
||||
|
||||
(defn add-token
|
||||
[changes token]
|
||||
[changes set-id set-name token]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :add-token :token token})
|
||||
(update :undo-changes conj {:type :del-token :id (:id token)})
|
||||
(update :redo-changes conj {:type :add-token :set-id set-id :set-name set-name :token token})
|
||||
(update :undo-changes conj {:type :del-token :set-name set-name :id (:id token) :name (:name token)})
|
||||
(apply-changes-local)))
|
||||
|
||||
(defn update-token
|
||||
[changes {:keys [id] :as token} prev-token]
|
||||
[changes set-id set-name {:keys [id name] :as token} {prev-name :name :as prev-token}]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :mod-token :id id :token token})
|
||||
(update :undo-changes conj {:type :mod-token :id id :token (or prev-token token)})
|
||||
(update :redo-changes conj {:type :mod-token :set-id set-id :set-name set-name :id id :name prev-name :token token})
|
||||
(update :undo-changes conj {:type :mod-token :set-id set-id :set-name set-name :id id :name name :token (or prev-token token)})
|
||||
(apply-changes-local)))
|
||||
|
||||
(defn delete-token
|
||||
[changes token-id]
|
||||
[changes set-name token-id token-name]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
prev-token (get-in library-data [:tokens token-id])]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :del-token :id token-id})
|
||||
(update :undo-changes conj {:type :add-token :token prev-token})
|
||||
(update :redo-changes conj {:type :del-token :set-name set-name :id token-id :name token-name})
|
||||
(update :undo-changes conj {:type :add-token :set-id uuid/zero :set-name set-name :token prev-token})
|
||||
(apply-changes-local))))
|
||||
|
||||
(defn add-component
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
java.time.Instant
|
||||
java.time.OffsetDateTime
|
||||
java.util.List
|
||||
linked.map.LinkedMap
|
||||
org.fressian.Reader
|
||||
org.fressian.StreamingWriter
|
||||
org.fressian.Writer
|
||||
|
@ -109,6 +110,13 @@
|
|||
(clojure.lang.PersistentArrayMap. (.toArray kvs))
|
||||
(clojure.lang.PersistentHashMap/create (seq kvs)))))
|
||||
|
||||
(defn read-ordered-map
|
||||
[^Reader rdr]
|
||||
(let [kvs ^java.util.List (read-object! rdr)]
|
||||
(reduce #(assoc %1 (first %2) (second %2))
|
||||
(d/ordered-map)
|
||||
(partition-all 2 (seq kvs)))))
|
||||
|
||||
(def ^:dynamic *write-handler-lookup* nil)
|
||||
(def ^:dynamic *read-handler-lookup* nil)
|
||||
|
||||
|
@ -225,6 +233,11 @@
|
|||
:wfn write-map-like
|
||||
:rfn read-map-like}
|
||||
|
||||
{:name "linked/map"
|
||||
:class LinkedMap
|
||||
:wfn write-map-like
|
||||
:rfn read-ordered-map}
|
||||
|
||||
{:name "clj/keyword"
|
||||
:class clojure.lang.Keyword
|
||||
:wfn write-named
|
||||
|
|
|
@ -308,7 +308,6 @@
|
|||
::explain explain}))))
|
||||
true)))
|
||||
|
||||
|
||||
(defn fast-validate!
|
||||
"A fast path for validation process, assumes the ILazySchema protocol
|
||||
implemented on the provided `s` schema. Sould not be used directly."
|
||||
|
|
|
@ -26,11 +26,18 @@
|
|||
#?(:clj (Instant/now)
|
||||
:cljs (.local ^js DateTime)))
|
||||
|
||||
#?(:clj
|
||||
(defn is-after?
|
||||
[one other]
|
||||
(.isAfter one other)))
|
||||
|
||||
(defn instant
|
||||
[s]
|
||||
#?(:clj (Instant/ofEpochMilli s)
|
||||
:cljs (.fromMillis ^js DateTime s #js {:zone "local" :setZone false})))
|
||||
|
||||
;; To check for valid date time we can just use the core inst? function
|
||||
|
||||
#?(:cljs
|
||||
(extend-protocol IComparable
|
||||
DateTime
|
||||
|
@ -45,7 +52,6 @@
|
|||
0
|
||||
(if (< (inst-ms it) (inst-ms other)) -1 1)))))
|
||||
|
||||
|
||||
#?(:cljs
|
||||
(extend-type DateTime
|
||||
cljs.core/IEquiv
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[app.common.uri :as uri]
|
||||
[cognitect.transit :as t]
|
||||
[lambdaisland.uri :as luri]
|
||||
[linked.core :as lk]
|
||||
[linked.map :as lkm]
|
||||
[linked.set :as lks])
|
||||
#?(:clj
|
||||
(:import
|
||||
|
@ -24,6 +24,7 @@
|
|||
java.time.Instant
|
||||
java.time.OffsetDateTime
|
||||
lambdaisland.uri.URI
|
||||
linked.map.LinkedMap
|
||||
linked.set.LinkedSet)))
|
||||
|
||||
(def write-handlers (atom nil))
|
||||
|
@ -118,10 +119,15 @@
|
|||
{:id "u"
|
||||
:rfn parse-uuid})
|
||||
|
||||
{:id "ordered-map"
|
||||
:class #?(:clj LinkedMap :cljs lkm/LinkedMap)
|
||||
:wfn vec
|
||||
:rfn #(into lkm/empty-linked-map %)}
|
||||
|
||||
{:id "ordered-set"
|
||||
:class #?(:clj LinkedSet :cljs lks/LinkedSet)
|
||||
:wfn vec
|
||||
:rfn #(into (lk/set) %)}
|
||||
:rfn #(into lks/empty-linked-set %)}
|
||||
|
||||
{:id "duration"
|
||||
:class #?(:clj Duration :cljs lxn/Duration)
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.token-theme :as ctt]
|
||||
[app.common.types.tokens-lib :as ctl]
|
||||
[app.common.types.typographies-list :as ctyl]
|
||||
[app.common.types.typography :as cty]
|
||||
[app.common.uuid :as uuid]
|
||||
|
@ -78,7 +79,8 @@
|
|||
[:token-sets-index {:optional true}
|
||||
[:map-of {:gen/max 10} ::sm/uuid ::ctt/token-set]]
|
||||
[:tokens {:optional true}
|
||||
[:map-of {:gen/max 100} ::sm/uuid ::cto/token]]])
|
||||
[:map-of {:gen/max 100} ::sm/uuid ::cto/token]]
|
||||
[:tokens-lib {:optional true} ::ctl/tokens-lib]])
|
||||
|
||||
(def check-file-data!
|
||||
(sm/check-fn ::data))
|
||||
|
|
|
@ -47,8 +47,16 @@
|
|||
:string
|
||||
:typography})
|
||||
|
||||
(defn valid-token-type?
|
||||
[t]
|
||||
(token-types t))
|
||||
|
||||
(def token-name-ref :string)
|
||||
|
||||
(defn valid-token-name-ref?
|
||||
[n]
|
||||
(string? n))
|
||||
|
||||
(sm/register! ::token
|
||||
[:map {:title "Token"}
|
||||
[:id ::sm/uuid]
|
||||
|
|
319
common/src/app/common/types/tokens_lib.cljc
Normal file
319
common/src/app/common/types/tokens_lib.cljc
Normal file
|
@ -0,0 +1,319 @@
|
|||
;; 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.common.types.tokens-lib
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.time :as dt]
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.token :as cto]
|
||||
#?(:clj [app.common.fressian :as fres])))
|
||||
|
||||
;; #?(:clj (set! *warn-on-reflection* true))
|
||||
|
||||
;; === Token
|
||||
|
||||
(defrecord Token [name type value description modified-at])
|
||||
|
||||
(def schema:token
|
||||
[:and
|
||||
[:map {:title "Token"}
|
||||
[:name cto/token-name-ref] ;; not necessary to have uuid
|
||||
[:type [::sm/one-of cto/token-types]]
|
||||
[:value :any]
|
||||
[:description [:maybe :string]] ;; defrecord always have the attributes, even with nil value
|
||||
[:modified-at ::sm/inst]]
|
||||
[:fn (partial instance? Token)]])
|
||||
|
||||
(sm/register! ::token schema:token)
|
||||
|
||||
(def valid-token?
|
||||
(sm/validator schema:token))
|
||||
|
||||
(def check-token!
|
||||
(sm/check-fn ::token))
|
||||
|
||||
(defn make-token
|
||||
[& {:keys [] :as params}]
|
||||
(let [params (-> params
|
||||
(dissoc :id) ;; we will remove this when old data structures are removed
|
||||
(update :modified-at #(or % (dt/now))))
|
||||
token (map->Token params)]
|
||||
|
||||
(dm/assert!
|
||||
"expected valid token"
|
||||
(check-token! token))
|
||||
|
||||
token))
|
||||
|
||||
;; === Token Set
|
||||
|
||||
(defprotocol ITokenSet
|
||||
(add-token [_ token] "add a token at the end of the list")
|
||||
(update-token [_ token-name f] "update a token in the list")
|
||||
(delete-token [_ token-name] "delete a token from the list"))
|
||||
|
||||
(defrecord TokenSet [name description modified-at tokens]
|
||||
ITokenSet
|
||||
(add-token [_ token]
|
||||
(dm/assert! "expected valid token" (check-token! token))
|
||||
(TokenSet. name
|
||||
description
|
||||
(dt/now)
|
||||
(assoc tokens (:name token) token)))
|
||||
|
||||
(update-token [this token-name f]
|
||||
(if-let [token (get tokens token-name)]
|
||||
(let [token' (-> (make-token (f token))
|
||||
(assoc :modified-at (dt/now)))]
|
||||
(check-token! token')
|
||||
(TokenSet. name
|
||||
description
|
||||
(dt/now)
|
||||
(if (= (:name token) (:name token'))
|
||||
(assoc tokens (:name token') token')
|
||||
(let [index (d/index-of (keys tokens) (:name token))]
|
||||
(-> tokens
|
||||
(dissoc (:name token))
|
||||
(d/addm-at-index index (:name token') token'))))))
|
||||
this))
|
||||
|
||||
(delete-token [_ token-name]
|
||||
(TokenSet. name
|
||||
description
|
||||
(dt/now)
|
||||
(dissoc tokens token-name))))
|
||||
|
||||
(def schema:token-set
|
||||
[:and [:map {:title "TokenSet"}
|
||||
[:name :string]
|
||||
[:description [:maybe :string]]
|
||||
[:modified-at ::sm/inst]
|
||||
[:tokens [:map-of {:gen/max 5} :string ::token]]]
|
||||
[:fn (partial instance? TokenSet)]])
|
||||
|
||||
(sm/register! ::token-set schema:token-set)
|
||||
|
||||
(def valid-token-set?
|
||||
(sm/validator schema:token-set))
|
||||
|
||||
(def check-token-set!
|
||||
(sm/check-fn ::token-set))
|
||||
|
||||
(defn make-token-set
|
||||
[& {:keys [] :as params}]
|
||||
(let [params (-> params
|
||||
(dissoc :id)
|
||||
(update :modified-at #(or % (dt/now)))
|
||||
(update :tokens #(into (d/ordered-map) %)))
|
||||
token-set (map->TokenSet params)]
|
||||
|
||||
(dm/assert!
|
||||
"expected valid token set"
|
||||
(check-token-set! token-set))
|
||||
|
||||
token-set))
|
||||
|
||||
;; === TokenSets (collection)
|
||||
|
||||
(defprotocol ITokenSets
|
||||
(add-set [_ token-set] "add a set to the library, at the end")
|
||||
(update-set [_ set-name f] "modify a set in the ilbrary")
|
||||
(delete-set [_ set-name] "delete a set in the library")
|
||||
(set-count [_] "get the total number if sets in the library")
|
||||
(get-sets [_] "get an ordered sequence of all sets in the library")
|
||||
(get-set [_ set-name] "get one set looking for name")
|
||||
(validate [_]))
|
||||
|
||||
(def schema:token-sets
|
||||
[:and
|
||||
[:map-of {:title "TokenSets"}
|
||||
:string ::token-set]
|
||||
[:fn d/ordered-map?]])
|
||||
|
||||
(sm/register! ::token-sets schema:token-sets)
|
||||
|
||||
(def valid-token-sets?
|
||||
(sm/validator schema:token-sets))
|
||||
|
||||
(def check-token-sets!
|
||||
(sm/check-fn ::token-sets))
|
||||
|
||||
;; === TokenThemes (collection)
|
||||
|
||||
(def valid-token-themes?
|
||||
(constantly true))
|
||||
|
||||
;; === Tokens Lib
|
||||
|
||||
(defprotocol ITokensLib
|
||||
"A library of tokens, sets and themes."
|
||||
(add-token-in-set [_ set-name token] "add token to a set")
|
||||
(update-token-in-set [_ set-name token-name f] "update a token in a set")
|
||||
(delete-token-from-set [_ set-name token-name] "delete a token from a set"))
|
||||
|
||||
(deftype TokensLib [sets themes]
|
||||
;; NOTE: This is only for debug purposes, pending to properly
|
||||
;; implement the toString and alternative printing.
|
||||
#?@(:clj [clojure.lang.IDeref
|
||||
(deref [_] {:sets sets :themes themes})]
|
||||
:cljs [cljs.core/IDeref
|
||||
(-deref [_] {:sets sets :themes themes})])
|
||||
|
||||
#?@(:cljs [cljs.core/IEncodeJS
|
||||
(-clj->js [_] (js-obj "sets" (clj->js sets)
|
||||
"themes" (clj->js themes)))])
|
||||
|
||||
ITokenSets
|
||||
(add-set [_ token-set]
|
||||
(dm/assert! "expected valid token set" (check-token-set! token-set))
|
||||
(TokensLib. (assoc sets (:name token-set) token-set)
|
||||
themes))
|
||||
|
||||
(update-set [this set-name f]
|
||||
(if-let [set (get sets set-name)]
|
||||
(let [set' (-> (make-token-set (f set))
|
||||
(assoc :modified-at (dt/now)))]
|
||||
(check-token-set! set')
|
||||
(TokensLib. (if (= (:name set) (:name set'))
|
||||
(assoc sets (:name set') set')
|
||||
(let [index (d/index-of (keys sets) (:name set))]
|
||||
(-> sets
|
||||
(dissoc (:name set))
|
||||
(d/addm-at-index index (:name set') set'))))
|
||||
themes))
|
||||
this))
|
||||
|
||||
(delete-set [_ set-name]
|
||||
(TokensLib. (dissoc sets set-name)
|
||||
themes))
|
||||
|
||||
(validate [_]
|
||||
(and (valid-token-sets? sets)
|
||||
(valid-token-themes? themes)))
|
||||
|
||||
(set-count [_]
|
||||
(count sets))
|
||||
|
||||
(get-sets [_]
|
||||
(vals sets))
|
||||
|
||||
(get-set [_ set-name]
|
||||
(get sets set-name))
|
||||
|
||||
ITokensLib
|
||||
(add-token-in-set [this set-name token]
|
||||
(dm/assert! "expected valid token instance" (check-token! token))
|
||||
(if (contains? sets set-name)
|
||||
(TokensLib. (update sets set-name add-token token)
|
||||
themes)
|
||||
this))
|
||||
|
||||
(update-token-in-set [this set-name token-name f]
|
||||
(if (contains? sets set-name)
|
||||
(TokensLib. (update sets set-name
|
||||
#(update-token % token-name f))
|
||||
themes)
|
||||
this))
|
||||
|
||||
(delete-token-from-set [this set-name token-name]
|
||||
(if (contains? sets set-name)
|
||||
(TokensLib. (update sets set-name
|
||||
#(delete-token % token-name))
|
||||
themes)
|
||||
this)))
|
||||
|
||||
(defn valid-tokens-lib?
|
||||
[o]
|
||||
(and (instance? TokensLib o)
|
||||
(validate o)))
|
||||
|
||||
(defn check-tokens-lib!
|
||||
[lib]
|
||||
(dm/assert!
|
||||
"expected valid tokens lib"
|
||||
(valid-tokens-lib? lib)))
|
||||
|
||||
(defn make-tokens-lib
|
||||
"Create an empty or prepopulated tokens library."
|
||||
([]
|
||||
;; NOTE: is possible that ordered map is not the most apropriate
|
||||
;; data structure and maybe we need a specific that allows us an
|
||||
;; easy way to reorder it, or just store inside Tokens data
|
||||
;; structure the data and the order separately as we already do
|
||||
;; with pages and pages-index.
|
||||
(make-tokens-lib :sets (d/ordered-map)
|
||||
:themes (d/ordered-map)))
|
||||
|
||||
([& {:keys [sets themes]}]
|
||||
(let [tokens-lib (TokensLib. sets themes)]
|
||||
|
||||
(dm/assert!
|
||||
"expected valid tokens lib"
|
||||
(valid-tokens-lib? tokens-lib))
|
||||
|
||||
tokens-lib)))
|
||||
|
||||
(defn ensure-tokens-lib
|
||||
[tokens-lib]
|
||||
(or tokens-lib (make-tokens-lib)))
|
||||
|
||||
(def type:tokens-lib
|
||||
{:type ::tokens-lib
|
||||
:pred valid-tokens-lib?})
|
||||
|
||||
(sm/register! ::tokens-lib type:tokens-lib)
|
||||
|
||||
;; === Serialization handlers for RPC API and database
|
||||
|
||||
(t/add-handlers!
|
||||
{:id "penpot/tokens-lib"
|
||||
:class TokensLib
|
||||
:wfn deref
|
||||
:rfn #(make-tokens-lib %)}
|
||||
|
||||
{:id "penpot/token-set"
|
||||
:class TokenSet
|
||||
:wfn #(into {} %)
|
||||
:rfn #(make-token-set %)}
|
||||
|
||||
{:id "penpot/token"
|
||||
:class Token
|
||||
:wfn #(into {} %)
|
||||
:rfn #(make-token %)})
|
||||
|
||||
#?(:clj
|
||||
(fres/add-handlers!
|
||||
{:name "penpot/token/v1"
|
||||
:class Token
|
||||
:wfn (fn [n w o]
|
||||
(fres/write-tag! w n 1)
|
||||
(fres/write-object! w (into {} o)))
|
||||
:rfn (fn [r]
|
||||
(let [obj (fres/read-object! r)]
|
||||
(map->Token obj)))}
|
||||
|
||||
{:name "penpot/token-set/v1"
|
||||
:class TokenSet
|
||||
:wfn (fn [n w o]
|
||||
(fres/write-tag! w n 1)
|
||||
(fres/write-object! w (into {} o)))
|
||||
:rfn (fn [r]
|
||||
(let [obj (fres/read-object! r)]
|
||||
(map->TokenSet obj)))}
|
||||
|
||||
{:name "penpot/tokens-lib/v1"
|
||||
:class TokensLib
|
||||
:wfn (fn [n w o]
|
||||
(fres/write-tag! w n 2)
|
||||
(fres/write-object! w (.-sets o))
|
||||
(fres/write-object! w (.-themes o)))
|
||||
:rfn (fn [r]
|
||||
(let [sets (fres/read-object! r)
|
||||
themes (fres/read-object! r)]
|
||||
(->TokensLib sets themes)))}))
|
|
@ -21,8 +21,12 @@
|
|||
|
||||
(defn add-token
|
||||
"Adds a new token to the file data, setting its `modified-at` timestamp."
|
||||
[file-data token]
|
||||
(update file-data :tokens assoc (:id token) (touch token)))
|
||||
[file-data token-set-id token]
|
||||
(-> file-data
|
||||
(update :tokens assoc (:id token) (touch token))
|
||||
(d/update-in-when [:token-sets-index token-set-id] #(->
|
||||
(update % :tokens conj (:id token))
|
||||
(touch)))))
|
||||
|
||||
(defn get-token
|
||||
"Retrieves a token by its ID from the file data."
|
||||
|
|
259
common/test/common_tests/types/tokens_lib_test.cljc
Normal file
259
common/test/common_tests/types/tokens_lib_test.cljc
Normal file
|
@ -0,0 +1,259 @@
|
|||
;; 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 common-tests.types.tokens-lib-test
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.fressian :as fres]
|
||||
[app.common.time :as dt]
|
||||
[app.common.transit :as tr]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(t/deftest make-token
|
||||
(let [now (dt/now)
|
||||
token1 (ctob/make-token :name "test-token-1"
|
||||
:type :boolean
|
||||
:value true)
|
||||
token2 (ctob/make-token :name "test-token-2"
|
||||
:type :numeric
|
||||
:value 66
|
||||
:description "test description"
|
||||
:modified-at now)]
|
||||
|
||||
(t/is (= (:name token1) "test-token-1"))
|
||||
(t/is (= (:type token1) :boolean))
|
||||
(t/is (= (:value token1) true))
|
||||
(t/is (nil? (:description token1)))
|
||||
(t/is (some? (:modified-at token1)))
|
||||
(t/is (ctob/valid-token? token1))
|
||||
|
||||
(t/is (= (:name token2) "test-token-2"))
|
||||
(t/is (= (:type token2) :numeric))
|
||||
(t/is (= (:value token2) 66))
|
||||
(t/is (= (:description token2) "test description"))
|
||||
(t/is (= (:modified-at token2) now))
|
||||
(t/is (ctob/valid-token? token2))))
|
||||
|
||||
(t/deftest invalid-tokens
|
||||
(let [args {:name 777
|
||||
:type :invalid}]
|
||||
(t/is (thrown-with-msg? Exception #"expected valid token"
|
||||
(apply ctob/make-token args)))
|
||||
(t/is (false? (ctob/valid-token? {})))))
|
||||
|
||||
(t/deftest make-token-set
|
||||
(let [now (dt/now)
|
||||
token-set1 (ctob/make-token-set :name "test-token-set-1")
|
||||
token-set2 (ctob/make-token-set :name "test-token-set-2"
|
||||
:description "test description"
|
||||
:modified-at now
|
||||
:tokens [])]
|
||||
|
||||
(t/is (= (:name token-set1) "test-token-set-1"))
|
||||
(t/is (nil? (:description token-set1)))
|
||||
(t/is (some? (:modified-at token-set1)))
|
||||
(t/is (empty? (:tokens token-set1)))
|
||||
|
||||
(t/is (= (:name token-set2) "test-token-set-2"))
|
||||
(t/is (= (:description token-set2) "test description"))
|
||||
(t/is (= (:modified-at token-set2) now))
|
||||
(t/is (empty? (:tokens token-set2)))))
|
||||
|
||||
(t/deftest invalid-token-set
|
||||
(let [args {:name 777
|
||||
:description 999}]
|
||||
(t/is (thrown-with-msg? Exception #"expected valid token set"
|
||||
(apply ctob/make-token-set args)))))
|
||||
|
||||
(t/deftest make-tokens-lib
|
||||
(let [tokens-lib (ctob/make-tokens-lib)]
|
||||
(t/is (= (ctob/set-count tokens-lib) 0))))
|
||||
|
||||
(t/deftest add-token-set
|
||||
(let [tokens-lib (ctob/make-tokens-lib)
|
||||
token-set (ctob/make-token-set :name "test-token-set")
|
||||
tokens-lib' (ctob/add-set tokens-lib token-set)
|
||||
|
||||
token-sets' (ctob/get-sets tokens-lib')
|
||||
token-set' (ctob/get-set tokens-lib' "test-token-set")]
|
||||
|
||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||
(t/is (= (first token-sets') token-set))
|
||||
(t/is (= token-set' token-set))))
|
||||
|
||||
(t/deftest update-token-set
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set")))
|
||||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-set "test-token-set"
|
||||
(fn [token-set]
|
||||
(assoc token-set
|
||||
:name "updated-name"
|
||||
:description "some description")))
|
||||
(ctob/update-set "not-existing-set"
|
||||
(fn [token-set]
|
||||
(assoc token-set
|
||||
:name "no-effect"))))
|
||||
|
||||
token-set (ctob/get-set tokens-lib "test-token-set")
|
||||
token-set' (ctob/get-set tokens-lib' "updated-name")]
|
||||
|
||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||
(t/is (= (:name token-set') "updated-name"))
|
||||
(t/is (= (:description token-set') "some description"))
|
||||
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))))
|
||||
|
||||
(t/deftest delete-token-set
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set")))
|
||||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/delete-set "test-token-set")
|
||||
(ctob/delete-set "not-existing-set"))
|
||||
|
||||
token-set' (ctob/get-set tokens-lib' "updated-name")]
|
||||
|
||||
(t/is (= (ctob/set-count tokens-lib') 0))
|
||||
(t/is (nil? token-set'))))
|
||||
|
||||
(t/deftest add-token
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set")))
|
||||
token (ctob/make-token :name "test-token"
|
||||
:type :boolean
|
||||
:value true)
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/add-token-in-set "test-token-set" token)
|
||||
(ctob/add-token-in-set "not-existing-set" token))
|
||||
|
||||
token-set (ctob/get-set tokens-lib "test-token-set")
|
||||
token-set' (ctob/get-set tokens-lib' "test-token-set")
|
||||
token' (get-in token-set' [:tokens "test-token"])]
|
||||
|
||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||
(t/is (= (count (:tokens token-set')) 1))
|
||||
(t/is (= (:name token') "test-token"))
|
||||
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))))
|
||||
|
||||
(t/deftest update-token
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "test-token-1"
|
||||
:type :boolean
|
||||
:value true))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "test-token-2"
|
||||
:type :boolean
|
||||
:value true)))
|
||||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-token-in-set "test-token-set" "test-token-1"
|
||||
(fn [token]
|
||||
(assoc token
|
||||
:description "some description"
|
||||
:value false)))
|
||||
(ctob/update-token-in-set "not-existing-set" "test-token-1"
|
||||
(fn [token]
|
||||
(assoc token
|
||||
:name "no-effect")))
|
||||
(ctob/update-token-in-set "test-token-set" "not-existing-token"
|
||||
(fn [token]
|
||||
(assoc token
|
||||
:name "no-effect"))))
|
||||
|
||||
token-set (ctob/get-set tokens-lib "test-token-set")
|
||||
token-set' (ctob/get-set tokens-lib' "test-token-set")
|
||||
token (get-in token-set [:tokens "test-token-1"])
|
||||
token' (get-in token-set' [:tokens "test-token-1"])]
|
||||
|
||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||
(t/is (= (count (:tokens token-set')) 2))
|
||||
(t/is (= (d/index-of (keys (:tokens token-set')) "test-token-1") 0))
|
||||
(t/is (= (:name token') "test-token-1"))
|
||||
(t/is (= (:description token') "some description"))
|
||||
(t/is (= (:value token') false))
|
||||
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))
|
||||
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
|
||||
|
||||
(t/deftest rename-token
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "test-token-1"
|
||||
:type :boolean
|
||||
:value true))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "test-token-2"
|
||||
:type :boolean
|
||||
:value true)))
|
||||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-token-in-set "test-token-set" "test-token-1"
|
||||
(fn [token]
|
||||
(assoc token
|
||||
:name "updated-name"))))
|
||||
|
||||
token-set (ctob/get-set tokens-lib "test-token-set")
|
||||
token-set' (ctob/get-set tokens-lib' "test-token-set")
|
||||
token (get-in token-set [:tokens "test-token-1"])
|
||||
token' (get-in token-set' [:tokens "updated-name"])]
|
||||
|
||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||
(t/is (= (count (:tokens token-set')) 2))
|
||||
(t/is (= (d/index-of (keys (:tokens token-set')) "updated-name") 0))
|
||||
(t/is (= (:name token') "updated-name"))
|
||||
(t/is (= (:description token') nil))
|
||||
(t/is (= (:value token') true))
|
||||
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))
|
||||
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
|
||||
|
||||
(t/deftest delete-token
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "test-token"
|
||||
:type :boolean
|
||||
:value true)))
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/delete-token-from-set "test-token-set" "test-token")
|
||||
(ctob/delete-token-from-set "not-existing-set" "test-token")
|
||||
(ctob/delete-token-from-set "test-set" "not-existing-token"))
|
||||
|
||||
token-set (ctob/get-set tokens-lib "test-token-set")
|
||||
token-set' (ctob/get-set tokens-lib' "test-token-set")
|
||||
token' (get-in token-set' [:tokens "test-token"])]
|
||||
|
||||
(t/is (= (ctob/set-count tokens-lib') 1))
|
||||
(t/is (= (count (:tokens token-set')) 0))
|
||||
(t/is (nil? token'))
|
||||
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))))
|
||||
|
||||
(t/deftest transit-serialization
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
|
||||
(ctob/add-token-in-set "test-token-set" (ctob/make-token :name "test-token"
|
||||
:type :boolean
|
||||
:value true)))
|
||||
encoded-str (tr/encode-str tokens-lib)
|
||||
tokens-lib' (tr/decode-str encoded-str)]
|
||||
|
||||
(t/is (ctob/valid-tokens-lib? tokens-lib'))
|
||||
(t/is (= (ctob/set-count tokens-lib') 1))))
|
||||
|
||||
(t/deftest fressian-serialization
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
|
||||
(ctob/add-token-in-set "test-token-set" (ctob/make-token :name "test-token"
|
||||
:type :boolean
|
||||
:value true)))
|
||||
encoded-blob (fres/encode tokens-lib)
|
||||
tokens-lib' (fres/decode encoded-blob)]
|
||||
|
||||
(t/is (ctob/valid-tokens-lib? tokens-lib'))
|
||||
(t/is (= (ctob/set-count tokens-lib') 1))))
|
|
@ -96,6 +96,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@tokens-studio/sd-transforms": "^0.16.1",
|
||||
"bun": "^1.1.25",
|
||||
"compression": "^1.7.4",
|
||||
"date-fns": "^3.6.0",
|
||||
"eventsource-parser": "^1.1.2",
|
||||
|
|
|
@ -81,6 +81,11 @@
|
|||
(let [workspace-data (deref refs/workspace-data)]
|
||||
(get (:tokens workspace-data) id)))
|
||||
|
||||
(defn get-token-set-data-from-token-set-id
|
||||
[id]
|
||||
(let [workspace-data (deref refs/workspace-data)]
|
||||
(get (:token-sets-index workspace-data) id)))
|
||||
|
||||
(defn set-selected-token-set-id
|
||||
[id]
|
||||
(ptk/reify ::set-selected-token-set-id
|
||||
|
@ -88,6 +93,10 @@
|
|||
(update [_ state]
|
||||
(wtts/assoc-selected-token-set-id state id))))
|
||||
|
||||
(defn get-token-set-tokens
|
||||
[token-set file]
|
||||
(map #(get-in file [:tokens %]) (:tokens token-set)))
|
||||
|
||||
(defn create-token-theme [token-theme]
|
||||
(let [new-token-theme (merge
|
||||
{:id (uuid/next)
|
||||
|
@ -120,7 +129,7 @@
|
|||
(not theme-id) (-> changes
|
||||
(pcb/add-temporary-token-theme
|
||||
{:id (uuid/next)
|
||||
:name ""
|
||||
:name "Test theme"
|
||||
:sets #{id}}))
|
||||
new-set? (-> changes
|
||||
(pcb/update-token-theme
|
||||
|
@ -196,14 +205,14 @@
|
|||
(dch/commit-changes changes)
|
||||
(wtu/update-workspace-tokens))))))
|
||||
|
||||
(defn delete-token-set [token-set-id]
|
||||
(defn delete-token-set [token-set-id token-set-name]
|
||||
(ptk/reify ::delete-token-set
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (get state :workspace-data)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/delete-token-set token-set-id))]
|
||||
(pcb/delete-token-set token-set-id token-set-name))]
|
||||
(rx/of
|
||||
(dch/commit-changes changes)
|
||||
(wtu/update-workspace-tokens))))))
|
||||
|
@ -214,46 +223,44 @@
|
|||
(ptk/reify ::update-create-token
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [prev-token (get-token-data-from-token-id (:id token))
|
||||
(let [token-set (wtts/get-selected-token-set state)
|
||||
create-set? (not token-set)
|
||||
token-set (or token-set
|
||||
{:id (uuid/next)
|
||||
:name "Global"
|
||||
:tokens []})
|
||||
|
||||
changes (cond-> (pcb/empty-changes it)
|
||||
create-set?
|
||||
(pcb/add-token-set token-set))
|
||||
|
||||
prev-token-id (d/seek #(= % (:id token)) (:tokens token-set))
|
||||
prev-token (get-token-data-from-token-id prev-token-id)
|
||||
create-token? (not prev-token)
|
||||
token-changes (if create-token?
|
||||
(-> (pcb/empty-changes it)
|
||||
(pcb/add-token token))
|
||||
(-> (pcb/empty-changes it)
|
||||
(pcb/update-token token prev-token)))
|
||||
token-set (wtts/get-selected-token-set state)
|
||||
create-set? (not token-set)
|
||||
new-token-set {:id (uuid/next)
|
||||
:name "Global"
|
||||
:tokens [(:id token)]}
|
||||
selected-token-set-id (if create-set?
|
||||
(:id new-token-set)
|
||||
(:id token-set))
|
||||
set-changes (cond
|
||||
create-set? (-> token-changes
|
||||
(pcb/add-token-set new-token-set))
|
||||
:else (let [updated-token-set (if (contains? token-set (:id token))
|
||||
token-set
|
||||
(update token-set :tokens conj (:id token)))]
|
||||
(-> token-changes
|
||||
(pcb/update-token-set updated-token-set token-set))))
|
||||
theme-changes (-> set-changes
|
||||
|
||||
changes (if create-token?
|
||||
(pcb/add-token changes (:id token-set) (:name token-set) token)
|
||||
(pcb/update-token changes (:id token-set) (:name token-set) token prev-token))
|
||||
|
||||
changes (-> changes
|
||||
(ensure-token-theme-changes state {:new-set? create-set?
|
||||
:id selected-token-set-id}))]
|
||||
:id (:id token-set)}))]
|
||||
(rx/of
|
||||
(set-selected-token-set-id selected-token-set-id)
|
||||
(dch/commit-changes theme-changes)))))))
|
||||
(set-selected-token-set-id (:id token-set))
|
||||
(dch/commit-changes changes)))))))
|
||||
|
||||
(defn delete-token
|
||||
[id]
|
||||
[set-name id name]
|
||||
(dm/assert! (string? set-name))
|
||||
(dm/assert! (uuid? id))
|
||||
(dm/assert! (string? name))
|
||||
(ptk/reify ::delete-token
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (get state :workspace-data)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/delete-token id))]
|
||||
(pcb/delete-token set-name id name))]
|
||||
(rx/of (dch/commit-changes changes))))))
|
||||
|
||||
(defn duplicate-token
|
||||
|
|
|
@ -201,10 +201,11 @@
|
|||
(generic-attribute-actions #{:x} "X" (assoc context-data :on-update-shape wtch/update-shape-position))
|
||||
(generic-attribute-actions #{:y} "Y" (assoc context-data :on-update-shape wtch/update-shape-position))))}))
|
||||
|
||||
(defn default-actions [{:keys [token]}]
|
||||
(let [{:keys [modal]} (wtty/get-token-properties token)]
|
||||
(defn default-actions [{:keys [token selected-token-set-id]}]
|
||||
(let [{:keys [modal]} (wtty/get-token-properties token)
|
||||
selected-token-set (dt/get-token-set-data-from-token-set-id selected-token-set-id)]
|
||||
[{:title "Delete Token"
|
||||
:action #(st/emit! (dt/delete-token (:id token)))}
|
||||
:action #(st/emit! (dt/delete-token (:name selected-token-set) (:id token) (:name token)))}
|
||||
{:title "Duplicate Token"
|
||||
:action #(st/emit! (dt/duplicate-token (:id token)))}
|
||||
{:title "Edit Token"
|
||||
|
@ -311,7 +312,8 @@
|
|||
selected (mf/deref refs/selected-shapes)
|
||||
selected-shapes (into [] (keep (d/getf objects)) selected)
|
||||
token-id (:token-id mdata)
|
||||
token (get (mf/deref refs/workspace-selected-token-set-tokens) token-id)]
|
||||
token (get (mf/deref refs/workspace-selected-token-set-tokens) token-id)
|
||||
selected-token-set-id (mf/deref refs/workspace-selected-token-set-id)]
|
||||
(mf/use-effect
|
||||
(mf/deps mdata)
|
||||
(fn []
|
||||
|
@ -327,4 +329,5 @@
|
|||
[:ul {:class (stl/css :context-list)}
|
||||
[:& menu-tree {:submenu-offset @width
|
||||
:token token
|
||||
:selected-token-set-id selected-token-set-id
|
||||
:selected-shapes selected-shapes}]])]]))
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
(defn on-select-token-set-click [id]
|
||||
(st/emit! (wdt/set-selected-token-set-id id)))
|
||||
|
||||
(defn on-delete-token-set-click [id event]
|
||||
(defn on-delete-token-set-click [id name event]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (wdt/delete-token-set id)))
|
||||
(st/emit! (wdt/delete-token-set id name)))
|
||||
|
||||
(defn on-update-token-set [token-set]
|
||||
(st/emit! (wdt/update-token-set token-set)))
|
||||
|
@ -115,7 +115,7 @@
|
|||
[:*
|
||||
[:div {:class (stl/css :set-name)} name]
|
||||
[:div {:class (stl/css :delete-set)}
|
||||
[:button {:on-click #(on-delete-token-set-click id %)
|
||||
[:button {:on-click #(on-delete-token-set-click id name %)
|
||||
:type "button"}
|
||||
i/delete]]
|
||||
(if set?
|
||||
|
|
|
@ -13,106 +13,65 @@
|
|||
|
||||
(def token-types
|
||||
(ordered-map
|
||||
[:border-radius
|
||||
{:title "Border Radius"
|
||||
:attributes ctt/border-radius-keys
|
||||
:on-update-shape wtch/update-shape-radius-all
|
||||
:modal {:key :tokens/border-radius
|
||||
:fields [{:label "Border Radius"
|
||||
:key :border-radius}]}}]
|
||||
[:stroke-width
|
||||
{:title "Stroke Width"
|
||||
:attributes ctt/stroke-width-keys
|
||||
:on-update-shape wtch/update-stroke-width
|
||||
:modal {:key :tokens/stroke-width
|
||||
:fields [{:label "Stroke Width"
|
||||
:key :stroke-width}]}}]
|
||||
:border-radius
|
||||
{:title "Border Radius"
|
||||
:attributes ctt/border-radius-keys
|
||||
:on-update-shape wtch/update-shape-radius-all
|
||||
:modal {:key :tokens/border-radius
|
||||
:fields [{:label "Border Radius"
|
||||
:key :border-radius}]}}
|
||||
:stroke-width
|
||||
{:title "Stroke Width"
|
||||
:attributes ctt/stroke-width-keys
|
||||
:on-update-shape wtch/update-stroke-width
|
||||
:modal {:key :tokens/stroke-width
|
||||
:fields [{:label "Stroke Width"
|
||||
:key :stroke-width}]}}
|
||||
|
||||
[:sizing
|
||||
{:title "Sizing"
|
||||
:attributes #{:width :height}
|
||||
:all-attributes ctt/sizing-keys
|
||||
:on-update-shape wtch/update-shape-dimensions
|
||||
:modal {:key :tokens/sizing
|
||||
:fields [{:label "Sizing"
|
||||
:key :sizing}]}}]
|
||||
[:dimensions
|
||||
{:title "Dimensions"
|
||||
:attributes #{:width :height}
|
||||
:all-attributes (set/union
|
||||
ctt/spacing-keys
|
||||
ctt/sizing-keys
|
||||
ctt/border-radius-keys
|
||||
ctt/stroke-width-keys)
|
||||
:on-update-shape wtch/update-shape-dimensions
|
||||
:modal {:key :tokens/dimensions
|
||||
:fields [{:label "Dimensions"
|
||||
:key :dimensions}]}}]
|
||||
:sizing
|
||||
{:title "Sizing"
|
||||
:attributes #{:width :height}
|
||||
:all-attributes ctt/sizing-keys
|
||||
:on-update-shape wtch/update-shape-dimensions
|
||||
:modal {:key :tokens/sizing
|
||||
:fields [{:label "Sizing"
|
||||
:key :sizing}]}}
|
||||
:dimensions
|
||||
{:title "Dimensions"
|
||||
:attributes #{:width :height}
|
||||
:all-attributes (set/union
|
||||
ctt/spacing-keys
|
||||
ctt/sizing-keys
|
||||
ctt/border-radius-keys
|
||||
ctt/stroke-width-keys)
|
||||
:on-update-shape wtch/update-shape-dimensions
|
||||
:modal {:key :tokens/dimensions
|
||||
:fields [{:label "Dimensions"
|
||||
:key :dimensions}]}}
|
||||
|
||||
[:opacity
|
||||
{:title "Opacity"
|
||||
:attributes ctt/opacity-keys
|
||||
:on-update-shape wtch/update-opacity
|
||||
:modal {:key :tokens/opacity
|
||||
:fields [{:label "Opacity"
|
||||
:key :opacity}]}}]
|
||||
:opacity
|
||||
{:title "Opacity"
|
||||
:attributes ctt/opacity-keys
|
||||
:on-update-shape wtch/update-opacity
|
||||
:modal {:key :tokens/opacity
|
||||
:fields [{:label "Opacity"
|
||||
:key :opacity}]}}
|
||||
|
||||
[:rotation
|
||||
{:title "Rotation"
|
||||
:attributes ctt/rotation-keys
|
||||
:on-update-shape wtch/update-rotation
|
||||
:modal {:key :tokens/rotation
|
||||
:fields [{:label "Rotation"
|
||||
:key :rotation}]}}]
|
||||
[:spacing
|
||||
{:title "Spacing"
|
||||
:attributes #{:column-gap :row-gap}
|
||||
:all-attributes ctt/spacing-keys
|
||||
:on-update-shape wtch/update-layout-spacing
|
||||
:modal {:key :tokens/spacing
|
||||
:fields [{:label "Spacing"
|
||||
:key :spacing}]}}]
|
||||
(comment
|
||||
[:boolean
|
||||
{:title "Boolean"
|
||||
:modal {:key :tokens/boolean
|
||||
:fields [{:label "Boolean"}]}}]
|
||||
|
||||
[:box-shadow
|
||||
{:title "Box Shadow"
|
||||
:modal {:key :tokens/box-shadow
|
||||
:fields [{:label "Box shadows"
|
||||
:key :box-shadow
|
||||
:type :box-shadow}]}}]
|
||||
|
||||
[:numeric
|
||||
{:title "Numeric"
|
||||
:modal {:key :tokens/numeric
|
||||
:fields [{:label "Numeric"
|
||||
:key :numeric}]}}]
|
||||
|
||||
[:other
|
||||
{:title "Other"
|
||||
:modal {:key :tokens/other
|
||||
:fields [{:label "Other"
|
||||
:key :other}]}}]
|
||||
[:string
|
||||
{:title "String"
|
||||
:modal {:key :tokens/string
|
||||
:fields [{:label "String"
|
||||
:key :string}]}}]
|
||||
[:typography
|
||||
{:title "Typography"
|
||||
:modal {:key :tokens/typography
|
||||
:fields [{:label "Font" :key :font-family}
|
||||
{:label "Weight" :key :weight}
|
||||
{:label "Font Size" :key :font-size}
|
||||
{:label "Line Height" :key :line-height}
|
||||
{:label "Letter Spacing" :key :letter-spacing}
|
||||
{:label "Paragraph Spacing" :key :paragraph-spacing}
|
||||
{:label "Paragraph Indent" :key :paragraph-indent}
|
||||
{:label "Text Decoration" :key :text-decoration}
|
||||
{:label "Text Case" :key :text-case}]}}])))
|
||||
:rotation
|
||||
{:title "Rotation"
|
||||
:attributes ctt/rotation-keys
|
||||
:on-update-shape wtch/update-rotation
|
||||
:modal {:key :tokens/rotation
|
||||
:fields [{:label "Rotation"
|
||||
:key :rotation}]}}
|
||||
:spacing
|
||||
{:title "Spacing"
|
||||
:attributes #{:column-gap :row-gap}
|
||||
:all-attributes ctt/spacing-keys
|
||||
:on-update-shape wtch/update-layout-spacing
|
||||
:modal {:key :tokens/spacing
|
||||
:fields [{:label "Spacing"
|
||||
:key :spacing}]}}))
|
||||
|
||||
(defn get-token-properties [token]
|
||||
(get token-types (:type token)))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns token-tests.logic.token-actions-test
|
||||
(:require
|
||||
[app.common.pprint :refer [pprint]]
|
||||
[app.common.logging :as log]
|
||||
[app.common.test-helpers.compositions :as ctho]
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
|
|
|
@ -2427,6 +2427,62 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@oven/bun-darwin-aarch64@npm:1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "@oven/bun-darwin-aarch64@npm:1.1.25"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@oven/bun-darwin-x64-baseline@npm:1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "@oven/bun-darwin-x64-baseline@npm:1.1.25"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@oven/bun-darwin-x64@npm:1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "@oven/bun-darwin-x64@npm:1.1.25"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@oven/bun-linux-aarch64@npm:1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "@oven/bun-linux-aarch64@npm:1.1.25"
|
||||
conditions: os=linux & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@oven/bun-linux-x64-baseline@npm:1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "@oven/bun-linux-x64-baseline@npm:1.1.25"
|
||||
conditions: os=linux & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@oven/bun-linux-x64@npm:1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "@oven/bun-linux-x64@npm:1.1.25"
|
||||
conditions: os=linux & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@oven/bun-windows-x64-baseline@npm:1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "@oven/bun-windows-x64-baseline@npm:1.1.25"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@oven/bun-windows-x64@npm:1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "@oven/bun-windows-x64@npm:1.1.25"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@pkgjs/parseargs@npm:^0.11.0":
|
||||
version: 0.11.0
|
||||
resolution: "@pkgjs/parseargs@npm:0.11.0"
|
||||
|
@ -4379,6 +4435,43 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bun@npm:^1.1.25":
|
||||
version: 1.1.25
|
||||
resolution: "bun@npm:1.1.25"
|
||||
dependencies:
|
||||
"@oven/bun-darwin-aarch64": "npm:1.1.25"
|
||||
"@oven/bun-darwin-x64": "npm:1.1.25"
|
||||
"@oven/bun-darwin-x64-baseline": "npm:1.1.25"
|
||||
"@oven/bun-linux-aarch64": "npm:1.1.25"
|
||||
"@oven/bun-linux-x64": "npm:1.1.25"
|
||||
"@oven/bun-linux-x64-baseline": "npm:1.1.25"
|
||||
"@oven/bun-windows-x64": "npm:1.1.25"
|
||||
"@oven/bun-windows-x64-baseline": "npm:1.1.25"
|
||||
dependenciesMeta:
|
||||
"@oven/bun-darwin-aarch64":
|
||||
optional: true
|
||||
"@oven/bun-darwin-x64":
|
||||
optional: true
|
||||
"@oven/bun-darwin-x64-baseline":
|
||||
optional: true
|
||||
"@oven/bun-linux-aarch64":
|
||||
optional: true
|
||||
"@oven/bun-linux-x64":
|
||||
optional: true
|
||||
"@oven/bun-linux-x64-baseline":
|
||||
optional: true
|
||||
"@oven/bun-windows-x64":
|
||||
optional: true
|
||||
"@oven/bun-windows-x64-baseline":
|
||||
optional: true
|
||||
bin:
|
||||
bun: bin/bun.exe
|
||||
bunx: bin/bun.exe
|
||||
checksum: 10c0/ac0cec14aaaaae8b5b3818c6868dd417a60fb5d9c4230f5265c19c0367fd588ae9175ce0feac04db5b5684d624187c639fae1854ee2b52cdd2e2ae0a75a7dd9c
|
||||
conditions: (os=darwin | os=linux | os=win32) & (cpu=arm64 | cpu=x64)
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bytes@npm:3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "bytes@npm:3.0.0"
|
||||
|
@ -6819,6 +6912,7 @@ __metadata:
|
|||
"@tokens-studio/sd-transforms": "npm:^0.16.1"
|
||||
"@types/node": "npm:^20.11.20"
|
||||
autoprefixer: "npm:^10.4.19"
|
||||
bun: "npm:^1.1.25"
|
||||
compression: "npm:^1.7.4"
|
||||
concurrently: "npm:^8.2.2"
|
||||
date-fns: "npm:^3.6.0"
|
||||
|
|
Loading…
Add table
Reference in a new issue