diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index c909f1924..0b3f3d28b 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -1049,13 +1049,10 @@ (defmethod process-change :mod-token-set [data {:keys [name token-set]}] (update data :tokens-lib (fn [lib] - (let [path-changed? (not= name (:name token-set)) - lib' (-> lib - (ctob/ensure-tokens-lib) - (ctob/update-set name (fn [prev-set] - (merge prev-set (dissoc token-set :tokens)))))] - (cond-> lib' - path-changed? (ctob/update-set-name name (:name token-set))))))) + (-> lib + (ctob/ensure-tokens-lib) + (ctob/update-set name (fn [prev-set] + (merge prev-set (dissoc token-set :tokens)))))))) (defmethod process-change :move-token-set-before [data {:keys [set-name before-set-name]}] diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index c79bf422e..827af70aa 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -59,7 +59,7 @@ (join-path separator)))) (defn get-path - "Get the groups part of the name as a vector. E.g. group.subgroup.name -> ['group' 'subrgoup']" + "Get the groups part of the name as a vector. E.g. group.subgroup.name -> ['group' 'subgroup']" [item separator] (dm/assert! "expected groupable item" @@ -67,7 +67,7 @@ (split-path (:name item) separator)) (defn get-groups-str - "Get the groups part of the name. E.g. group.subgroup.name -> group.subrgoup" + "Get the groups part of the name. E.g. group.subgroup.name -> group.subgroup" [item separator] (-> (get-path item separator) (butlast) @@ -177,16 +177,35 @@ ;; === Token Set +(def set-prefix "S-") + +(def set-group-prefix "G-") + (def set-separator "/") -(defn get-token-set-path [path] - (get-path path set-separator)) +(defn add-set-prefix [set-name] + (str set-prefix set-name)) -(defn get-token-set-group-str [path] - (get-groups-str path set-separator)) +(defn add-set-group-prefix [group-path] + (str set-group-prefix group-path)) -(defn split-token-set-path [path] - (split-path path set-separator)) +(defn add-token-set-paths-prefix + "Returns token-set paths with prefixes to differentiate between sets and set-groups. + + Sets will be prefixed with `set-prefix` (S-). + Set groups will be prefixed with `set-group-prefix` (G-)." + [paths] + (let [set-path (mapv add-set-group-prefix (butlast paths)) + set-name (add-set-prefix (last paths))] + (conj set-path set-name))) + +(defn split-token-set-name [token-set-name] + (-> (split-path token-set-name set-separator) + (add-token-set-paths-prefix))) + +(defn get-token-set-path [token-set] + (let [path (get-path token-set set-separator)] + (add-token-set-paths-prefix path))) (defn tokens-tree "Convert tokens into a nested tree with their `:name` as the path. @@ -299,20 +318,11 @@ token-set)) -;; === TokenSetGroup - -(defrecord TokenSetGroup [attr1 attr2]) - -;; TODO schema, validators, etc. - -(defn make-token-set-group - [] - (TokenSetGroup. "one" "two")) - ;; === TokenSets (collection) (defprotocol ITokenSets (add-set [_ token-set] "add a set to the library, at the end") + (add-sets [_ token-set] "add a collection of sets 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") (move-set-before [_ set-name before-set-name] "move a set with `set-name` before a set with `before-set-name` in the library. @@ -322,8 +332,7 @@ When `before-set-name` is nil, move set to bottom") (get-sets [_] "get an ordered sequence of all sets in the library") (get-ordered-set-names [_] "get an ordered sequence of all sets names in the library") (get-set [_ set-name] "get one set looking for name") - (get-neighbor-set-name [_ set-name index-offset] "get neighboring set name offset by `index-offset`") - (get-set-group [_ set-group-path] "get the attributes of a set group")) + (get-neighbor-set-name [_ set-name index-offset] "get neighboring set name offset by `index-offset`")) (def schema:token-set-node [:schema {:registry {::node [:or ::token-set @@ -518,6 +527,8 @@ When `before-set-name` is nil, move set to bottom") ;; === Tokens Lib +(declare make-tokens-lib) + (defprotocol ITokensLib "A library of tokens, sets and themes." (add-token-in-set [_ set-name token] "add token to a set") @@ -526,66 +537,62 @@ When `before-set-name` is nil, move set to bottom") (toggle-set-in-theme [_ group-name theme-name 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") (get-active-themes-set-tokens [_] "set of set names that are active in the the active themes") - (update-set-name [_ old-set-name new-set-name] "updates set name in themes") (encode-dtcg [_] "Encodes library to a dtcg compatible json string") (decode-dtcg-json [_ parsed-json] "Decodes parsed json containing tokens and converts to library") (get-all-tokens [_] "all tokens in the lib") (validate [_])) -(deftype TokensLib [sets set-groups themes active-themes] +(deftype TokensLib [sets themes active-themes] ;; NOTE: This is only for debug purposes, pending to properly ;; implement the toString and alternative printing. #?@(:clj [clojure.lang.IDeref (deref [_] {:sets sets - :set-groups set-groups :themes themes :active-themes active-themes})] :cljs [cljs.core/IDeref (-deref [_] {:sets sets - :set-groups set-groups :themes themes :active-themes active-themes})]) #?@(:cljs [cljs.core/IEncodeJS (-clj->js [_] (js-obj "sets" (clj->js sets) - "set-groups" (clj->js set-groups) "themes" (clj->js themes) "active-themes" (clj->js active-themes)))]) ITokenSets (add-set [_ token-set] (dm/assert! "expected valid token set" (check-token-set! token-set)) - (let [path (get-token-set-path token-set) - groups-str (get-token-set-group-str token-set)] + (let [path (get-token-set-path token-set)] (TokensLib. (d/oassoc-in sets path token-set) - (cond-> set-groups - (not (str/empty? groups-str)) - (assoc groups-str (make-token-set-group))) themes active-themes))) + (add-sets [this token-sets] + (reduce + (fn [lib set] + (add-set lib set)) + this token-sets)) + (update-set [this set-name f] - (let [path (split-token-set-path set-name) + (let [path (split-token-set-name set-name) set (get-in sets path)] (if set (let [set' (-> (make-token-set (f set)) (assoc :modified-at (dt/now))) - path' (get-path set' "/")] + path' (get-token-set-path set')] (check-token-set! set') (TokensLib. (if (= (:name set) (:name set')) (d/oassoc-in sets path set') (-> sets (d/oassoc-in-before path path' set') (d/dissoc-in path))) - set-groups ;; TODO update set-groups as needed themes active-themes)) this))) (delete-set [_ set-name] - (let [path (split-token-set-path set-name)] + (let [path (split-token-set-name set-name)] (TokensLib. (d/dissoc-in sets path) - set-groups ;; TODO remove set-group if needed (walk/postwalk (fn [form] (if (instance? TokenTheme form) @@ -596,19 +603,17 @@ When `before-set-name` is nil, move set to bottom") ;; TODO Handle groups and nesting (move-set-before [this set-name before-set-name] - (let [source-path (split-token-set-path set-name) + (let [source-path (split-token-set-name set-name) token-set (-> (get-set this set-name) (assoc :modified-at (dt/now))) - target-path (split-token-set-path before-set-name)] + target-path (split-token-set-name before-set-name)] (if before-set-name (TokensLib. (d/oassoc-in-before sets target-path source-path token-set) - set-groups ;; TODO remove set-group if needed themes active-themes) (TokensLib. (-> sets (d/dissoc-in source-path) (d/oassoc-in source-path token-set)) - set-groups ;; TODO remove set-group if needed themes active-themes)))) @@ -626,7 +631,7 @@ When `before-set-name` is nil, move set to bottom") (count (get-sets this))) (get-set [_ set-name] - (let [path (split-path set-name "/")] + (let [path (split-token-set-name set-name)] (get-in sets path))) (get-neighbor-set-name [this set-name index-offset] @@ -636,14 +641,10 @@ When `before-set-name` is nil, move set to bottom") (nth sets (+ index-offset index) nil))] neighbor-set-name)) - (get-set-group [_ set-group-path] - (get set-groups set-group-path)) - ITokenThemes (add-theme [_ token-theme] (dm/assert! "expected valid token theme" (check-token-theme! token-theme)) (TokensLib. sets - set-groups (update themes (:group token-theme) d/oassoc (:name token-theme) token-theme) active-themes)) @@ -659,7 +660,6 @@ When `before-set-name` is nil, move set to bottom") same-path? (and same-group? same-name?)] (check-token-theme! theme') (TokensLib. sets - set-groups (if same-path? (update themes group' assoc name' theme') (-> themes @@ -672,7 +672,6 @@ When `before-set-name` is nil, move set to bottom") (delete-theme [_ group name] (TokensLib. sets - set-groups (d/dissoc-in themes [group name]) (disj active-themes (token-theme-path group name)))) @@ -697,7 +696,6 @@ When `before-set-name` is nil, move set to bottom") (set-active-themes [_ active-themes] (TokensLib. sets - set-groups themes active-themes)) @@ -709,14 +707,12 @@ When `before-set-name` is nil, move set to bottom") active-themes' (-> (set/difference active-themes group-themes) (conj (theme-path theme)))] (TokensLib. sets - set-groups themes active-themes')) this)) (deactivate-theme [_ group name] (TokensLib. sets - set-groups themes (disj active-themes (token-theme-path group name)))) @@ -742,35 +738,17 @@ When `before-set-name` is nil, move set to bottom") 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) - set-groups - themes - active-themes) - this)) + (update-set this set-name #(add-token % token))) (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)) - set-groups - themes - active-themes) - this)) + (update-set this set-name #(update-token % token-name f))) (delete-token-from-set [this set-name token-name] - (if (contains? sets set-name) - (TokensLib. (update sets set-name - #(delete-token % token-name)) - set-groups - themes - active-themes) - this)) + (update-set this set-name #(delete-token % token-name))) (toggle-set-in-theme [this theme-group theme-name set-name] (if-let [_theme (get-in themes theme-group theme-name)] (TokensLib. sets - set-groups (d/oupdate-in themes [theme-group theme-name] #(toggle-set % set-name)) active-themes) @@ -794,38 +772,24 @@ When `before-set-name` is nil, move set to bottom") tokens (order-theme-set theme))) (d/ordered-map) active-themes))) - ;; TODO Move to `update-set` - (update-set-name [_ old-set-name new-set-name] - (TokensLib. sets - set-groups - (walk/postwalk - (fn [form] - (if (instance? TokenTheme form) - (-> form - (update :sets disj old-set-name) - (update :sets conj new-set-name)) - form)) - themes) - active-themes)) - (encode-dtcg [_] - (into {} (map (fn [[k v]] - [k (get-dtcg-tokens-tree v)]) - sets))) + (into {} (comp + (filter (partial instance? TokenSet)) + (map (fn [token-set] + [(:name token-set) (get-dtcg-tokens-tree token-set)]))) + (tree-seq d/ordered-map? vals sets))) (decode-dtcg-json [_ parsed-json] - (let [token-sets (into (d/ordered-map) - (map (fn [[set-name tokens]] - [set-name (make-token-set - :name set-name - :tokens (flatten-nested-tokens-json tokens ""))])) - (-> parsed-json - ;; tokens-studio/plugin will add these meta properties, remove them for now - (dissoc "$themes" "$metadata")))] - (TokensLib. token-sets - set-groups - themes - active-themes))) + (let [;; tokens-studio/plugin will add these meta properties, remove them for now + sets-data (dissoc parsed-json "$themes" "$metadata") + lib (make-tokens-lib) + lib' (reduce + (fn [lib [set-name tokens]] + (add-set lib (make-token-set + :name set-name + :tokens (flatten-nested-tokens-json tokens "")))) + lib sets-data)] + lib')) (get-all-tokens [this] (reduce @@ -834,7 +798,7 @@ When `before-set-name` is nil, move set to bottom") {} (get-sets this))) (validate [_] - (and (valid-token-sets? sets) ;; TODO: validate set-groups + (and (valid-token-sets? sets) (valid-token-themes? themes) (valid-active-token-themes? active-themes)))) @@ -858,12 +822,11 @@ When `before-set-name` is nil, move set to bottom") ;; structure the data and the order separately as we already do ;; with pages and pages-index. (make-tokens-lib :sets (d/ordered-map) - :set-groups {} :themes (d/ordered-map) :active-themes #{})) - ([& {:keys [sets set-groups themes active-themes]}] - (let [tokens-lib (TokensLib. sets set-groups themes (or active-themes #{}))] + ([& {:keys [sets themes active-themes]}] + (let [tokens-lib (TokensLib. sets themes (or active-themes #{}))] (dm/assert! "expected valid tokens lib" @@ -934,16 +897,29 @@ When `before-set-name` is nil, move set to bottom") (map->TokenTheme obj)))} {:name "penpot/tokens-lib/v1" + :rfn (fn [r] + (let [;; Migrate sets tree without prefix to new format + prev-sets (->> (fres/read-object! r) + (tree-seq d/ordered-map? vals) + (filter (partial instance? TokenSet))) + sets (-> (make-tokens-lib) + (add-sets prev-sets) + (deref) + :sets) + _set-groups (fres/read-object! r) + themes (fres/read-object! r) + active-themes (fres/read-object! r)] + (->TokensLib sets themes active-themes)))} + + {:name "penpot/tokens-lib/v1.1" :class TokensLib :wfn (fn [n w o] (fres/write-tag! w n 3) (fres/write-object! w (.-sets o)) - (fres/write-object! w (.-set-groups o)) (fres/write-object! w (.-themes o)) (fres/write-object! w (.-active-themes o))) :rfn (fn [r] (let [sets (fres/read-object! r) - set-groups (fres/read-object! r) themes (fres/read-object! r) active-themes (fres/read-object! r)] - (->TokensLib sets set-groups themes active-themes)))})) + (->TokensLib sets themes active-themes)))})) diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index e4e04dae2..52f010cb3 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -184,16 +184,6 @@ (t/is (= (first token-sets') token-set)) (t/is (= token-set' token-set)))) - (t/deftest add-token-set-with-group - (let [tokens-lib (ctob/make-tokens-lib) - token-set (ctob/make-token-set :name "test-group/test-token-set") - tokens-lib' (ctob/add-set tokens-lib token-set) - - set-group (ctob/get-set-group tokens-lib' "test-group")] - - (t/is (= (:attr1 set-group) "one")) - (t/is (= (:attr2 set-group) "two")))) - (t/deftest update-token-set (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :name "test-token-set"))) @@ -758,31 +748,31 @@ (t/is (= (:name (nth sets-list 3)) "group1/subgroup11/token-set-4")) (t/is (= (:name (nth sets-list 4)) "group2/token-set-5")) - (t/is (= (first node-set1) "token-set-1")) + (t/is (= (first node-set1) "S-token-set-1")) (t/is (= (ctob/group? (second node-set1)) false)) (t/is (= (:name (second node-set1)) "token-set-1")) - (t/is (= (first node-group1) "group1")) + (t/is (= (first node-group1) "G-group1")) (t/is (= (ctob/group? (second node-group1)) true)) (t/is (= (count (second node-group1)) 3)) - (t/is (= (first node-set2) "token-set-2")) + (t/is (= (first node-set2) "S-token-set-2")) (t/is (= (ctob/group? (second node-set2)) false)) (t/is (= (:name (second node-set2)) "group1/token-set-2")) - (t/is (= (first node-set3) "token-set-3")) + (t/is (= (first node-set3) "S-token-set-3")) (t/is (= (ctob/group? (second node-set3)) false)) (t/is (= (:name (second node-set3)) "group1/token-set-3")) - (t/is (= (first node-subgroup11) "subgroup11")) + (t/is (= (first node-subgroup11) "G-subgroup11")) (t/is (= (ctob/group? (second node-subgroup11)) true)) (t/is (= (count (second node-subgroup11)) 1)) - (t/is (= (first node-set4) "token-set-4")) + (t/is (= (first node-set4) "S-token-set-4")) (t/is (= (ctob/group? (second node-set4)) false)) (t/is (= (:name (second node-set4)) "group1/subgroup11/token-set-4")) - (t/is (= (first node-set5) "token-set-5")) + (t/is (= (first node-set5) "S-token-set-5")) (t/is (= (ctob/group? (second node-set5)) false)) (t/is (= (:name (second node-set5)) "group2/token-set-5")))) @@ -801,13 +791,13 @@ sets-tree (ctob/get-set-tree tokens-lib) sets-tree' (ctob/get-set-tree tokens-lib') - group1' (get sets-tree' "group1") - token-set (get-in sets-tree ["group1" "token-set-2"]) - token-set' (get-in sets-tree' ["group1" "token-set-2"])] + group1' (get sets-tree' "G-group1") + token-set (get-in sets-tree ["G-group1" "S-token-set-2"]) + token-set' (get-in sets-tree' ["G-group1" "S-token-set-2"])] (t/is (= (ctob/set-count tokens-lib') 5)) (t/is (= (count group1') 3)) - (t/is (= (d/index-of (keys group1') "token-set-2") 0)) + (t/is (= (d/index-of (keys group1') "S-token-set-2") 0)) (t/is (= (:name token-set') "group1/token-set-2")) (t/is (= (:description token-set') "some description")) (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) @@ -828,16 +818,18 @@ sets-tree (ctob/get-set-tree tokens-lib) sets-tree' (ctob/get-set-tree tokens-lib') - group1' (get sets-tree' "group1") - token-set (get-in sets-tree ["group1" "token-set-2"]) - token-set' (get-in sets-tree' ["group1" "updated-name"])] + group1' (get sets-tree' "G-group1") + token-set (get-in sets-tree ["G-group1" "S-token-set-2"]) + token-set' (get-in sets-tree' ["G-group1" "S-updated-name"])] (t/is (= (ctob/set-count tokens-lib') 5)) (t/is (= (count group1') 3)) - (t/is (= (d/index-of (keys group1') "updated-name") 0)) + (t/is (= (d/index-of (keys group1') "S-updated-name") 0)) (t/is (= (:name token-set') "group1/updated-name")) (t/is (= (:description token-set') nil)) - (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))) + sets-tree')) + (t/deftest move-set-of-group (let [tokens-lib (-> (ctob/make-tokens-lib) @@ -855,15 +847,15 @@ sets-tree (ctob/get-set-tree tokens-lib) sets-tree' (ctob/get-set-tree tokens-lib') - group1' (get sets-tree' "group1") - group2' (get sets-tree' "group2") - token-set (get-in sets-tree ["group1" "token-set-2"]) - token-set' (get-in sets-tree' ["group2" "updated-name"])] + group1' (get sets-tree' "G-group1") + group2' (get sets-tree' "G-group2") + token-set (get-in sets-tree ["G-group1" "S-token-set-2"]) + token-set' (get-in sets-tree' ["G-group2" "S-updated-name"])] (t/is (= (ctob/set-count tokens-lib') 4)) (t/is (= (count group1') 2)) (t/is (= (count group2') 1)) - (t/is (= (d/index-of (keys group2') "updated-name") 0)) + (t/is (nil? (get group1' "S-updated-name"))) (t/is (= (:name token-set') "group2/updated-name")) (t/is (= (:description token-set') nil)) (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) @@ -1139,4 +1131,3 @@ (t/is (= @with-prev-tokens-lib @tokens-lib))) (t/testing "fresh tokens library is also equal" (= @with-empty-tokens-lib @tokens-lib))))))) - diff --git a/frontend/src/app/main/ui/workspace/tokens/sets.cljs b/frontend/src/app/main/ui/workspace/tokens/sets.cljs index 37c4d6588..44666cb6d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sets.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sets.cljs @@ -200,13 +200,9 @@ context] :as _props}] (let [{:keys [editing? new? on-edit on-create on-reset] :as ctx} (or context (sets-context/use-context)) - avoid-token-set-grouping #(str/replace % "/" "-") submit-token #(do - ;; TODO: We don't support set grouping for now so we rename sets for now - (when (str/includes? (:name %) "/") - (warn-on-try-create-token-set-group!)) - (on-create-token-set (update % :name avoid-token-set-grouping)) + (on-create-token-set %) (on-reset))] [:ul {:class (stl/css :sets-list)} (if (and @@ -218,10 +214,7 @@ (when token-set (let [update-token #(do - ;; TODO: We don't support set grouping for now so we rename sets for now - (when (str/includes? (:name %) "/") - (warn-on-try-create-token-set-group!)) - (on-update-token-set (avoid-token-set-grouping (:name token-set)) (update % :name avoid-token-set-grouping)) + (on-update-token-set (:name token-set) %) (on-reset))] [:& sets-tree {:key (:name token-set) diff --git a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs index 72771c4fa..e2c77d007 100644 --- a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs @@ -182,8 +182,7 @@ (->> data-stream (rx/map (fn [data] (try - (-> (str/replace data "/" "-") ;; TODO Remove when token groups work - (t/decode-str)) + (t/decode-str data) (catch js/Error e (throw (wte/error-ex-info :error.import/json-parse-error data e)))))) (rx/map (fn [json-data]