diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index 501fd24f49..9e8d9cb7d9 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -458,24 +458,12 @@ [:type [:= :set-tokens-lib]] [:tokens-lib :any]]] - [:add-token - [:map {:title "AddTokenChange"} - [:type [:= :add-token]] + [:set-token + [:map {:title "SetTokenChange"} + [:type [:= :set-token]] [:set-name :string] - [:token ::cto/token]]] - - [:mod-token - [:map {:title "ModTokenChange"} - [:type [:= :mod-token]] - [:set-name :string] - [:name :string] - [:token ::cto/token]]] - - [:del-token - [:map {:title "DelTokenChange"} - [:type [:= :del-token]] - [:set-name :string] - [:name :string]]]]]) + [:token-name :string] + [:token [:maybe ::cto/token]]]]]]) (def schema:changes [:sequential {:gen/max 5 :gen/min 1} schema:change]) @@ -1036,29 +1024,21 @@ [data {:keys [tokens-lib]}] (assoc data :tokens-lib tokens-lib)) -(defmethod process-change :add-token - [data {:keys [set-name token]}] - (update data :tokens-lib #(-> % - (ctob/ensure-tokens-lib) - (ctob/add-token-in-set set-name (ctob/make-token token))))) +(defmethod process-change :set-token + [data {:keys [set-name token-name token]}] + (update data :tokens-lib + (fn [lib] + (let [lib' (ctob/ensure-tokens-lib lib)] + (cond + (not token) + (ctob/delete-token-from-set lib' set-name token-name) -(defmethod process-change :mod-token - [data {:keys [set-name name token]}] - (update data :tokens-lib #(-> % - (ctob/ensure-tokens-lib) - (ctob/update-token-in-set - set-name - name - (fn [old-token] - (ctob/make-token (merge old-token token))))))) + (not (ctob/get-token-in-set lib' set-name token-name)) + (ctob/add-token-in-set lib' set-name (ctob/make-token token)) -(defmethod process-change :del-token - [data {:keys [set-name name]}] - (update data :tokens-lib #(-> % - (ctob/ensure-tokens-lib) - (ctob/delete-token-from-set - set-name - name)))) + :else + (ctob/update-token-in-set lib' set-name token-name (fn [prev-token] + (ctob/make-token (merge prev-token token))))))))) (defmethod process-change :add-temporary-token-theme [data {:keys [token-theme]}] diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index fe27e4c81d..2fb307e92b 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -884,30 +884,31 @@ (update :undo-changes conj {:type :set-tokens-lib :tokens-lib prev-tokens-lib}) (apply-changes-local)))) -(defn add-token - [changes set-name token] - (-> changes - (update :redo-changes conj {:type :add-token :set-name set-name :token token}) - (update :undo-changes conj {:type :del-token :set-name set-name :name (:name token)}) - (apply-changes-local))) - -(defn update-token - [changes set-name token prev-token] - (-> changes - (update :redo-changes conj {:type :mod-token :set-name set-name :name (:name prev-token) :token token}) - (update :undo-changes conj {:type :mod-token :set-name set-name :name (:name token) :token (or prev-token token)}) - (apply-changes-local))) - -(defn delete-token - [changes set-name token-name] +(defn set-token [changes set-name token-name token] (assert-library! changes) (let [library-data (::library-data (meta changes)) prev-token (some-> (get library-data :tokens-lib) (ctob/get-set set-name) (ctob/get-token token-name))] (-> changes - (update :redo-changes conj {:type :del-token :set-name set-name :name token-name}) - (update :undo-changes conj {:type :add-token :set-name set-name :token prev-token}) + (update :redo-changes conj {:type :set-token + :set-name set-name + :token-name token-name + :token token}) + (update :undo-changes conj (if prev-token + {:type :set-token + :set-name set-name + :token-name (or + ;; Undo of edit + (:name token) + ;; Undo of delete + token-name) + :token prev-token} + ;; Undo of create token + {:type :set-token + :set-name set-name + :token-name token-name + :token nil})) (apply-changes-local)))) (defn add-component diff --git a/common/src/app/common/test_helpers/tokens.cljc b/common/src/app/common/test_helpers/tokens.cljc index c344f32b7b..2c62b1ce7e 100644 --- a/common/src/app/common/test_helpers/tokens.cljc +++ b/common/src/app/common/test_helpers/tokens.cljc @@ -35,6 +35,11 @@ (ctob/get-set set-name) (ctob/get-token token-name))))) +(defn token-data-eq? + "Compare token data without comparing modified timestamp" + [t1 t2] + (= (dissoc t1 :modified-at) (dissoc t2 :modified-at))) + (defn- set-stroke-width [shape stroke-width] (let [strokes (if (seq (:strokes shape)) diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index 2e52588800..88834e12df 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -801,6 +801,7 @@ used for managing active sets without a user created theme.") (set-path-exists? [_ path] "if a set at `path` exists") (set-group-path-exists? [_ path] "if a set group at `path` exists") (add-token-in-set [_ set-name token] "add token to a set") + (get-token-in-set [_ set-name token-name] "get token in 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") (toggle-set-in-theme [_ group-name theme-name set-name] "toggle a set used / not used in a theme") @@ -1134,6 +1135,11 @@ Will return a value that matches this schema: (dm/assert! "expected valid token instance" (check-token! token)) (update-set this set-name #(add-token % token))) + (get-token-in-set [this set-name token-name] + (some-> this + (get-set set-name) + (get-token token-name))) + (update-token-in-set [this set-name token-name f] (update-set this set-name #(update-token % token-name f))) diff --git a/common/test/common_tests/logic/token_test.cljc b/common/test/common_tests/logic/token_test.cljc index 9a06beb998..aa84adf82c 100644 --- a/common/test/common_tests/logic/token_test.cljc +++ b/common/test/common_tests/logic/token_test.cljc @@ -73,6 +73,70 @@ ;; Undo (t/is (some? (ctob/get-hidden-theme undo-lib)))))) +(t/deftest set-token-test + (t/testing "delete token" + (let [set-name "foo" + token-name "to.delete.color.red" + file (setup-file #(-> % + (ctob/add-set (ctob/make-token-set :name set-name)) + (ctob/add-token-in-set set-name (ctob/make-token {:name token-name + :value "red" + :type :color})))) + changes (-> (pcb/empty-changes) + (pcb/with-library-data (:data file)) + (pcb/set-token set-name token-name nil)) + + redo (thf/apply-changes file changes) + redo-lib (tht/get-tokens-lib redo) + undo (thf/apply-undo-changes redo changes) + undo-lib (tht/get-tokens-lib undo)] + (t/is (nil? (ctob/get-token-in-set redo-lib set-name token-name))) + ;; Undo + (t/is (some? (ctob/get-token-in-set undo-lib set-name token-name))))) + + (t/testing "add token" + (let [set-name "foo" + token (ctob/make-token {:name "to.add.color.red" + :value "red" + :type :color}) + file (setup-file #(-> % (ctob/add-set (ctob/make-token-set :name set-name)))) + changes (-> (pcb/empty-changes) + (pcb/with-library-data (:data file)) + (pcb/set-token set-name (:name token) token)) + + redo (thf/apply-changes file changes) + redo-lib (tht/get-tokens-lib redo) + undo (thf/apply-undo-changes redo changes) + undo-lib (tht/get-tokens-lib undo)] + (t/is (= token (ctob/get-token-in-set redo-lib set-name (:name token)))) + ;; Undo + (t/is (nil? (ctob/get-token-in-set undo-lib set-name (:name token)))))) + + (t/testing "update token" + (let [set-name "foo" + prev-token (ctob/make-token {:name "to.update.color.red" + :value "red" + :type :color}) + token (-> prev-token + (assoc :name "color.red.changed") + (assoc :value "blue")) + file (setup-file #(-> % + (ctob/add-set (ctob/make-token-set :name set-name)) + (ctob/add-token-in-set set-name prev-token))) + changes (-> (pcb/empty-changes) + (pcb/with-library-data (:data file)) + (pcb/set-token set-name (:name prev-token) token)) + + redo (thf/apply-changes file changes) + redo-lib (tht/get-tokens-lib redo) + undo (thf/apply-undo-changes redo changes) + undo-lib (tht/get-tokens-lib undo)] + (t/is (tht/token-data-eq? token (ctob/get-token-in-set redo-lib set-name (:name token)))) + (t/is (nil? (ctob/get-token-in-set redo-lib set-name (:name prev-token)))) + ;; Undo + (t/is (tht/token-data-eq? prev-token (ctob/get-token-in-set undo-lib set-name (:name prev-token)))) + (t/is (nil? (ctob/get-token-in-set undo-lib set-name (:name token))))))) + (t/deftest generate-toggle-token-set-group-test (t/testing "toggling set group with no active sets inside will activate all child sets" (let [file (setup-file #(-> % diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index ada669d7a6..a7ba89d47a 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -7,8 +7,8 @@ (ns common-tests.types.tokens-lib-test (:require #?(:clj [app.common.fressian :as fres]) - #?(:clj [clojure.data.json :as json]) [app.common.data :as d] + [app.common.test-helpers.tokens :as tht] [app.common.time :as dt] [app.common.transit :as tr] [app.common.types.tokens-lib :as ctob] @@ -1188,8 +1188,7 @@ lib (ctob/decode-dtcg-json (ctob/ensure-tokens-lib nil) json) get-set-token (fn [set-name token-name] (some-> (ctob/get-set lib set-name) - (ctob/get-token token-name) - (dissoc :modified-at))) + (ctob/get-token token-name))) token-theme (ctob/get-theme lib "group-1" "theme-1")] (t/is (= '("core" "light" "dark" "theme") (ctob/get-ordered-set-names lib))) (t/testing "set exists in theme" @@ -1197,21 +1196,21 @@ (t/is (= (:name token-theme) "theme-1")) (t/is (= (:sets token-theme) #{"light"}))) (t/testing "tokens exist in core set" - (t/is (= (get-set-token "core" "colors.red.600") - {:name "colors.red.600" - :type :color - :value "#e53e3e" - :description nil})) - (t/is (= (get-set-token "core" "spacing.multi-value") - {:name "spacing.multi-value" - :type :spacing - :value "{dimension.sm} {dimension.xl}" - :description "You can have multiple values in a single spacing token"})) - (t/is (= (get-set-token "theme" "button.primary.background") - {:name "button.primary.background" - :type :color - :value "{accent.default}" - :description nil}))) + (t/is (tht/token-data-eq? (get-set-token "core" "colors.red.600") + {:name "colors.red.600" + :type :color + :value "#e53e3e" + :description nil})) + (t/is (tht/token-data-eq? (get-set-token "core" "spacing.multi-value") + {:name "spacing.multi-value" + :type :spacing + :value "{dimension.sm} {dimension.xl}" + :description "You can have multiple values in a single spacing token"})) + (t/is (tht/token-data-eq? (get-set-token "theme" "button.primary.background") + {:name "button.primary.background" + :type :color + :value "{accent.default}" + :description nil}))) (t/testing "invalid tokens got discarded" (t/is (nil? (get-set-token "typography" "H1.Bold")))))) diff --git a/frontend/src/app/main/data/tokens.cljs b/frontend/src/app/main/data/tokens.cljs index add65ed08a..af5b103aed 100644 --- a/frontend/src/app/main/data/tokens.cljs +++ b/frontend/src/app/main/data/tokens.cljs @@ -20,7 +20,6 @@ [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.tokens.selected-set :as dwts] [app.main.data.workspace.undo :as dwu] - [app.main.store :as st] [app.main.ui.workspace.tokens.update :as wtu] [app.util.i18n :refer [tr]] [beicon.v2.core :as rx] @@ -241,14 +240,15 @@ [{:keys [token prev-token-name]}] (ptk/reify ::update-create-token ptk/WatchEvent - (watch [_ state _] - (let [token-set (dwts/get-selected-token-set state) - token-set-name (or (:name token-set) "Global") + (watch [it state _] + (let [data (dsh/lookup-file-data state) + token-set (dwts/get-selected-token-set state) + set-name (or (:name token-set) "Global") changes (if (not token-set) ;; No set created add a global set (let [tokens-lib (get-tokens-lib state) - token-set (ctob/make-token-set :name token-set-name :tokens {(:name token) token}) - hidden-theme (ctob/make-hidden-token-theme :sets [token-set-name]) + token-set (ctob/make-token-set :name set-name :tokens {(:name token) token}) + hidden-theme (ctob/make-hidden-token-theme :sets [set-name]) active-theme-paths (some-> tokens-lib ctob/get-active-theme-paths) add-to-hidden-theme? (= active-theme-paths #{ctob/hidden-token-theme-path}) base-changes (pcb/add-token-set (pcb/empty-changes) token-set)] @@ -262,14 +262,14 @@ (pcb/update-token-theme (ctob/toggle-set prev-hidden-theme ctob/hidden-token-theme-path) prev-hidden-theme))) :else base-changes)) - ;; Either update or add token to existing set - (if-let [prev-token (ctob/get-token token-set (or prev-token-name (:name token)))] - (pcb/update-token (pcb/empty-changes) (:name token-set) token prev-token) - (do - (st/emit! (ptk/event ::ev/event {::ev/name "create-tokens"})) - (pcb/add-token (pcb/empty-changes) (:name token-set) token))))] + (-> (pcb/empty-changes it) + (pcb/with-library-data data) + (pcb/set-token set-name (or prev-token-name (:name token)) token)))] + (rx/of - (dwts/set-selected-token-set-name token-set-name) + (dwts/set-selected-token-set-name set-name) + (when-not prev-token-name + (ptk/event ::ev/event {::ev/name "create-tokens"})) (dch/commit-changes changes)))))) (defn delete-token @@ -282,7 +282,7 @@ (let [data (dsh/lookup-file-data state) changes (-> (pcb/empty-changes it) (pcb/with-library-data data) - (pcb/delete-token set-name token-name))] + (pcb/set-token set-name token-name nil))] (rx/of (dch/commit-changes changes)))))) (defn duplicate-token