From 252797183c6737399170ea020bc70b216611a9bd Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Wed, 7 Aug 2024 15:14:32 +0200 Subject: [PATCH 01/16] Use :name as the token identifier [*] [*] Using uuid as the token identiefier for :applied-tokens is not correct as we want to merge all sets together by their name, to get the final values. --- common/src/app/common/types/token.cljc | 50 +++++++------ .../app/main/ui/workspace/tokens/changes.cljs | 4 +- .../ui/workspace/tokens/style_dictionary.cljs | 8 +- .../app/main/ui/workspace/tokens/token.cljs | 15 ++-- frontend/test/token_tests/helpers/tokens.cljs | 4 +- frontend/test/token_tests/token_test.cljs | 74 ++++++++++--------- 6 files changed, 82 insertions(+), 73 deletions(-) diff --git a/common/src/app/common/types/token.cljc b/common/src/app/common/types/token.cljc index 2e8a4e2cce..104948105c 100644 --- a/common/src/app/common/types/token.cljc +++ b/common/src/app/common/types/token.cljc @@ -47,10 +47,12 @@ :string :typography}) +(def token-name-ref :string) + (sm/register! ::token [:map {:title "Token"} [:id ::sm/uuid] - [:name :string] + [:name token-name-ref] [:type [::sm/one-of token-types]] [:value :any] [:description {:optional true} :string] @@ -58,48 +60,48 @@ (sm/register! ::border-radius [:map - [:rx {:optional true} ::sm/uuid] - [:ry {:optional true} ::sm/uuid] - [:r1 {:optional true} ::sm/uuid] - [:r2 {:optional true} ::sm/uuid] - [:r3 {:optional true} ::sm/uuid] - [:r4 {:optional true} ::sm/uuid]]) + [:rx {:optional true} token-name-ref] + [:ry {:optional true} token-name-ref] + [:r1 {:optional true} token-name-ref] + [:r2 {:optional true} token-name-ref] + [:r3 {:optional true} token-name-ref] + [:r4 {:optional true} token-name-ref]]) (def border-radius-keys (schema-keys ::border-radius)) (sm/register! ::stroke-width [:map - [:stroke-width {:optional true} ::sm/uuid]]) + [:stroke-width {:optional true} token-name-ref]]) (def stroke-width-keys (schema-keys ::stroke-width)) (sm/register! ::sizing [:map - [:width {:optional true} ::sm/uuid] - [:height {:optional true} ::sm/uuid] - [:layout-item-min-w {:optional true} ::sm/uuid] - [:layout-item-max-w {:optional true} ::sm/uuid] - [:layout-item-min-h {:optional true} ::sm/uuid] - [:layout-item-max-h {:optional true} ::sm/uuid]]) + [:width {:optional true} token-name-ref] + [:height {:optional true} token-name-ref] + [:layout-item-min-w {:optional true} token-name-ref] + [:layout-item-max-w {:optional true} token-name-ref] + [:layout-item-min-h {:optional true} token-name-ref] + [:layout-item-max-h {:optional true} token-name-ref]]) (def sizing-keys (schema-keys ::sizing)) (sm/register! ::opacity [:map - [:opacity {:optional true} ::sm/uuid]]) + [:opacity {:optional true} token-name-ref]]) (def opacity-keys (schema-keys ::opacity)) (sm/register! ::spacing [:map - [:row-gap {:optional true} ::sm/uuid] - [:column-gap {:optional true} ::sm/uuid] - [:p1 {:optional true} ::sm/uuid] - [:p2 {:optional true} ::sm/uuid] - [:p3 {:optional true} ::sm/uuid] - [:p4 {:optional true} ::sm/uuid] - [:x {:optional true} ::sm/uuid] - [:y {:optional true} ::sm/uuid]]) + [:row-gap {:optional true} token-name-ref] + [:column-gap {:optional true} token-name-ref] + [:p1 {:optional true} token-name-ref] + [:p2 {:optional true} token-name-ref] + [:p3 {:optional true} token-name-ref] + [:p4 {:optional true} token-name-ref] + [:x {:optional true} token-name-ref] + [:y {:optional true} token-name-ref]]) (def spacing-keys (schema-keys ::spacing)) @@ -113,7 +115,7 @@ (sm/register! ::rotation [:map - [:rotation {:optional true} ::sm/uuid]]) + [:rotation {:optional true} token-name-ref]]) (def rotation-keys (schema-keys ::rotation)) diff --git a/frontend/src/app/main/ui/workspace/tokens/changes.cljs b/frontend/src/app/main/ui/workspace/tokens/changes.cljs index af53ee46c1..e6e311ad00 100644 --- a/frontend/src/app/main/ui/workspace/tokens/changes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/changes.cljs @@ -38,7 +38,7 @@ (let [undo-id (js/Symbol) resolved-value (-> (get sd-tokens (:id token)) (wtt/resolve-token-value)) - tokenized-attributes (wtt/attributes-map attributes (:id token))] + tokenized-attributes (wtt/attributes-map attributes token)] (rx/of (dwu/start-undo-transaction undo-id) (dwsh/update-shapes shape-ids (fn [shape] @@ -58,7 +58,7 @@ ptk/WatchEvent (watch [_ _ _] (rx/of - (let [remove-token #(when % (wtt/remove-attributes-for-token-id attributes (:id token) %))] + (let [remove-token #(when % (wtt/remove-attributes-for-token attributes token %))] (dwsh/update-shapes shape-ids (fn [shape] 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 738cdbc1e7..7d16ffd0e8 100644 --- a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs @@ -86,18 +86,19 @@ [tokens & {:keys [debug?] :as config}] (p/let [sd-tokens (-> (wtt/token-names-tree tokens) (resolve-sd-tokens+ config))] - (let [resolved-tokens (reduce + (let [tokens-by-name (wtt/token-names-map tokens) + resolved-tokens (reduce (fn [acc ^js cur] (let [value (.-value cur) resolved-value (d/parse-double (.-value cur)) original-value (-> cur .-original .-value) - id (uuid (.-uuid (.-id cur))) + id (.-name cur) missing-reference? (and (not resolved-value) (re-find #"\{" value) (= value original-value))] (cond-> (assoc-in acc [id :resolved-value] resolved-value) missing-reference? (update-in [id :errors] (fnil conj #{}) :style-dictionary/missing-reference)))) - tokens sd-tokens)] + tokens-by-name sd-tokens)] (when debug? (js/console.log "Resolved tokens" resolved-tokens)) resolved-tokens))) @@ -157,6 +158,7 @@ (-> (clj->js {"a" {:name "a" :value "5"} "b" {:name "b" :value "{a} * 2"}}) + (#(resolve-sd-tokens+ % {:debug? true}))) (let [example (-> (shadow.resource/inline "./data/example-tokens-set.json") diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index b0d12d2205..647dab7366 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -4,6 +4,9 @@ [clojure.set :as set] [cuerdas.core :as str])) +(defn token-identifier [{:keys [name] :as _token}] + name) + (defn resolve-token-value [{:keys [value resolved-value] :as _token}] (or resolved-value @@ -11,17 +14,17 @@ (defn attributes-map "Creats an attributes map using collection of `attributes` for `id`." - [attributes id] - (->> (map (fn [attr] {attr id}) attributes) + [attributes token] + (->> (map (fn [attr] [attr (token-identifier token)]) attributes) (into {}))) -(defn remove-attributes-for-token-id +(defn remove-attributes-for-token "Removes applied tokens with `token-id` for the given `attributes` set from `applied-tokens`." - [attributes token-id applied-tokens] + [attributes token applied-tokens] (let [attr? (set attributes)] (->> (remove (fn [[k v]] (and (attr? k) - (= v token-id))) + (= v (token-identifier token)))) applied-tokens) (into {})))) @@ -29,7 +32,7 @@ "Test if `token` is applied to a `shape` on single `token-attribute`." [token shape token-attribute] (when-let [id (get-in shape [:applied-tokens token-attribute])] - (= (:id token) id))) + (= (token-identifier token) id))) (defn token-applied? "Test if `token` is applied to a `shape` with at least one of the one of the given `token-attributes`." diff --git a/frontend/test/token_tests/helpers/tokens.cljs b/frontend/test/token_tests/helpers/tokens.cljs index 716dd07558..87db316fb9 100644 --- a/frontend/test/token_tests/helpers/tokens.cljs +++ b/frontend/test/token_tests/helpers/tokens.cljs @@ -15,8 +15,8 @@ (defn apply-token-to-shape [file shape-label token-label attributes] (let [first-page-id (get-in file [:data :pages 0]) shape-id (thi/id shape-label) - token-id (thi/id token-label) - applied-attributes (wtt/attributes-map attributes token-id)] + token (get-token file token-label) + applied-attributes (wtt/attributes-map attributes token)] (update-in file [:data :pages-index first-page-id :objects shape-id diff --git a/frontend/test/token_tests/token_test.cljs b/frontend/test/token_tests/token_test.cljs index bcf86fcc99..4ad17cf5b2 100644 --- a/frontend/test/token_tests/token_test.cljs +++ b/frontend/test/token_tests/token_test.cljs @@ -10,66 +10,68 @@ [cljs.test :as t :include-macros true])) (t/deftest remove-attributes-for-token-id - (t/testing "removes attributes matching the `token-id`, keeps other attributes" - (t/is (= {:ry :b} - (wtt/remove-attributes-for-token-id - #{:rx :ry} :a {:rx :a :ry :b}))))) + (t/testing "removes attributes matching the `token`, keeps other attributes" + (t/is (= {:ry "b"} + (wtt/remove-attributes-for-token #{:rx :ry} {:name "a"} {:rx "a" :ry "b"}))))) (t/deftest token-applied-test (t/testing "matches passed token with `:token-attributes`" - (t/is (true? (wtt/token-applied? {:id :a} {:applied-tokens {:x :a}} #{:x})))) + (t/is (true? (wtt/token-applied? {:name "a"} {:applied-tokens {:x "a"}} #{:x})))) (t/testing "doesn't match empty token" - (t/is (nil? (wtt/token-applied? {} {:applied-tokens {:x :a}} #{:x})))) + (t/is (nil? (wtt/token-applied? {} {:applied-tokens {:x "a"}} #{:x})))) (t/testing "does't match passed token `:id`" - (t/is (nil? (wtt/token-applied? {:id :b} {:applied-tokens {:x :a}} #{:x})))) + (t/is (nil? (wtt/token-applied? {:name "b"} {:applied-tokens {:x "a"}} #{:x})))) (t/testing "doesn't match passed `:token-attributes`" - (t/is (nil? (wtt/token-applied? {:id :a} {:applied-tokens {:x :a}} #{:y}))))) + (t/is (nil? (wtt/token-applied? {:name "a"} {:applied-tokens {:x "a"}} #{:y}))))) (t/deftest token-applied-attributes - (t/is (= #{:x} (wtt/token-applied-attributes {:id :a} - {:applied-tokens {:x :a :y :b}} + (t/is (= #{:x} (wtt/token-applied-attributes {:name "a"} + {:applied-tokens {:x "a" :y "b"}} #{:x :missing})))) (t/deftest shapes-ids-by-applied-attributes (t/testing "Returns set of matched attributes that fit the applied token" (let [attributes #{:x :y :z} - shape-applied-x {:id :shape-applied-x - :applied-tokens {:x 1}} - shape-applied-y {:id :shape-applied-y - :applied-tokens {:y 1}} - shape-applied-x-y {:id :shape-applied-x-y - :applied-tokens {:x 1 :y 1}} - shape-applied-none {:id :shape-applied-none + shape-applied-x {:id "shape-applied-x" + :applied-tokens {:x "1"}} + shape-applied-y {:id "shape-applied-y" + :applied-tokens {:y "1"}} + shape-applied-x-y {:id "shape-applied-x-y" + :applied-tokens {:x "1" :y "1"}} + shape-applied-none {:id "shape-applied-none" :applied-tokens {}} - shape-applied-all {:id :shape-applied-all - :applied-tokens {:x 1 :y 1 :z 1}} - ids-set (fn [& xs] (into #{} (map :id xs))) + shape-applied-all {:id "shape-applied-all" + :applied-tokens {:x "1" :y "1" :z "1"}} + shape-ids (fn [& xs] (into #{} (map :id xs))) shapes [shape-applied-x shape-applied-y shape-applied-x-y shape-applied-all shape-applied-none] - expected (wtt/shapes-ids-by-applied-attributes {:id 1} shapes attributes)] - (t/is (= (:x expected) (ids-set shape-applied-x - shape-applied-x-y - shape-applied-all))) - (t/is (= (:y expected) (ids-set shape-applied-y - shape-applied-x-y - shape-applied-all))) - (t/is (= (:z expected) (ids-set shape-applied-all))) - (t/is (true? (wtt/shapes-applied-all? expected (ids-set shape-applied-all) attributes))) - (t/is (false? (wtt/shapes-applied-all? expected (apply ids-set shapes) attributes)))))) + expected (wtt/shapes-ids-by-applied-attributes {:name "1"} shapes attributes)] + (t/is (= (:x expected) (shape-ids shape-applied-x + shape-applied-x-y + shape-applied-all))) + (t/is (= (:y expected) (shape-ids shape-applied-y + shape-applied-x-y + shape-applied-all))) + (t/is (= (:z expected) (shape-ids shape-applied-all))) + (t/is (true? (wtt/shapes-applied-all? expected (shape-ids shape-applied-all) attributes))) + (t/is (false? (wtt/shapes-applied-all? expected (apply shape-ids shapes) attributes))) + (shape-ids shape-applied-x + shape-applied-x-y + shape-applied-all)))) (t/deftest tokens-applied-test (t/testing "is true when single shape matches the token and attributes" - (t/is (true? (wtt/shapes-token-applied? {:id :a} [{:applied-tokens {:x :a}} - {:applied-tokens {:x :b}}] + (t/is (true? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "a"}} + {:applied-tokens {:x "b"}}] #{:x})))) (t/testing "is false when no shape matches the token or attributes" - (t/is (nil? (wtt/shapes-token-applied? {:id :a} [{:applied-tokens {:x :b}} - {:applied-tokens {:x :b}}] + (t/is (nil? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "b"}} + {:applied-tokens {:x "b"}}] #{:x}))) - (t/is (nil? (wtt/shapes-token-applied? {:id :a} [{:applied-tokens {:x :a}} - {:applied-tokens {:x :a}}] + (t/is (nil? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "a"}} + {:applied-tokens {:x "a"}}] #{:y}))))) (t/deftest name->path-test From 980238e27b34d4690ac9c2e149093606d16ea6eb Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 09:22:32 +0200 Subject: [PATCH 02/16] Move find-token-references to token namespace --- .../app/main/ui/workspace/tokens/form.cljs | 2 +- .../ui/workspace/tokens/style_dictionary.cljs | 7 ------- .../app/main/ui/workspace/tokens/token.cljs | 7 +++++++ .../token_tests/style_dictionary_test.cljs | 20 ------------------- frontend/test/token_tests/token_test.cljs | 10 ++++++++++ 5 files changed, 18 insertions(+), 28 deletions(-) delete mode 100644 frontend/test/token_tests/style_dictionary_test.cljs diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index 5094f29eff..400e2b6ccb 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -92,7 +92,7 @@ Token names should only contain letters and digits separated by . characters.")} ;; When creating a new token we dont have a token name yet, ;; so we use a temporary token name that hopefully doesn't clash with any of the users token names. token-name (if (str/empty? name-value) "__TOKEN_STUDIO_SYSTEM.TEMP" name-value) - token-references (sd/find-token-references input) + token-references (wtt/find-token-references input) direct-self-reference? (get token-references token-name)] (cond empty-input? (p/rejected nil) 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 7d16ffd0e8..83231fc30c 100644 --- a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs @@ -23,13 +23,6 @@ ;; Functions ------------------------------------------------------------------- -(defn find-token-references - "Finds token reference values in `value-string` and returns a set with all contained namespaces." - [value-string] - (some->> (re-seq #"\{([^}]*)\}" value-string) - (map second) - (into #{}))) - (defn tokens->style-dictionary+ "Resolves references and math expressions using StyleDictionary. Returns a promise with the resolved dictionary." diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index 647dab7366..557d3dad03 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -4,6 +4,13 @@ [clojure.set :as set] [cuerdas.core :as str])) +(defn find-token-references + "Finds token reference values in `value-string` and returns a set with all contained namespaces." + [value-string] + (some->> (re-seq #"\{([^}]*)\}" value-string) + (map second) + (into #{}))) + (defn token-identifier [{:keys [name] :as _token}] name) diff --git a/frontend/test/token_tests/style_dictionary_test.cljs b/frontend/test/token_tests/style_dictionary_test.cljs deleted file mode 100644 index ff03ba16c8..0000000000 --- a/frontend/test/token_tests/style_dictionary_test.cljs +++ /dev/null @@ -1,20 +0,0 @@ -;; 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 token-tests.style-dictionary-test - (:require - [app.main.ui.workspace.tokens.style-dictionary :as wtsd] - [cljs.test :as t :include-macros true])) - -(t/deftest test-find-token-references - ;; Return references - (t/is (= #{"foo" "bar"} (wtsd/find-token-references "{foo} + {bar}"))) - ;; Ignore non reference text - (t/is (= #{"foo.bar.baz"} (wtsd/find-token-references "{foo.bar.baz} + something"))) - ;; No references found - (t/is (nil? (wtsd/find-token-references "1 + 2"))) - ;; Edge-case: Ignore unmatched closing parens - (t/is (= #{"foo" "bar"} (wtsd/find-token-references "{foo}} + {bar}")))) diff --git a/frontend/test/token_tests/token_test.cljs b/frontend/test/token_tests/token_test.cljs index 4ad17cf5b2..d9f2732b9a 100644 --- a/frontend/test/token_tests/token_test.cljs +++ b/frontend/test/token_tests/token_test.cljs @@ -9,6 +9,16 @@ [app.main.ui.workspace.tokens.token :as wtt] [cljs.test :as t :include-macros true])) +(t/deftest find-token-references + ;; Return references + (t/is (= #{"foo" "bar"} (wtt/find-token-references "{foo} + {bar}"))) + ;; Ignore non reference text + (t/is (= #{"foo.bar.baz"} (wtt/find-token-references "{foo.bar.baz} + something"))) + ;; No references found + (t/is (nil? (wtt/find-token-references "1 + 2"))) + ;; Edge-case: Ignore unmatched closing parens + (t/is (= #{"foo" "bar"} (wtt/find-token-references "{foo}} + {bar}")))) + (t/deftest remove-attributes-for-token-id (t/testing "removes attributes matching the `token`, keeps other attributes" (t/is (= {:ry "b"} From 2e8e33d7019696733faba8c02138ceed86cc4b57 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 09:40:26 +0200 Subject: [PATCH 03/16] Add token value parsing function --- .../app/main/ui/workspace/tokens/token.cljs | 8 ++++++ frontend/test/token_tests/token_test.cljs | 27 +++++++++++++------ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index 557d3dad03..92591f14a2 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -4,6 +4,14 @@ [clojure.set :as set] [cuerdas.core :as str])) +(def parseable-token-value-regexp + #"^\s*(-?[0-9]+\.?[0-9]*)\s*$") + +(defn parse-token-value [value] + (when-let [double-str (-> (re-find parseable-token-value-regexp value) + (last))] + (d/parse-double double-str))) + (defn find-token-references "Finds token reference values in `value-string` and returns a set with all contained namespaces." [value-string] diff --git a/frontend/test/token_tests/token_test.cljs b/frontend/test/token_tests/token_test.cljs index d9f2732b9a..77cb674ae2 100644 --- a/frontend/test/token_tests/token_test.cljs +++ b/frontend/test/token_tests/token_test.cljs @@ -9,15 +9,26 @@ [app.main.ui.workspace.tokens.token :as wtt] [cljs.test :as t :include-macros true])) +(t/deftest test-parse-token-value + (t/testing "parses double from a token value" + (t/is (= 100.1 (wtt/parse-token-value "100.1"))) + (t/is (= -9 (wtt/parse-token-value "-9"))) + (t/testing "trims white-space" + (t/is (= -1.3 (wtt/parse-token-value " -1.3 ")))) + (t/testing "returns nil for any invalid characters" + (t/is (nil? (wtt/parse-token-value " -1.3a ")))) + (t/testing "doesnt accept invalid double" + (t/is (nil? (wtt/parse-token-value ".3")))))) + (t/deftest find-token-references - ;; Return references - (t/is (= #{"foo" "bar"} (wtt/find-token-references "{foo} + {bar}"))) - ;; Ignore non reference text - (t/is (= #{"foo.bar.baz"} (wtt/find-token-references "{foo.bar.baz} + something"))) - ;; No references found - (t/is (nil? (wtt/find-token-references "1 + 2"))) - ;; Edge-case: Ignore unmatched closing parens - (t/is (= #{"foo" "bar"} (wtt/find-token-references "{foo}} + {bar}")))) + (t/testing "finds references inside curly braces in a string" + (t/is (= #{"foo" "bar"} (wtt/find-token-references "{foo} + {bar}"))) + (t/testing "ignores extra text" + (t/is (= #{"foo.bar.baz"} (wtt/find-token-references "{foo.bar.baz} + something")))) + (t/testing "ignores string without references" + (t/is (nil? (wtt/find-token-references "1 + 2")))) + (t/testing "handles edge-case for extra curly braces" + (t/is (= #{"foo" "bar"} (wtt/find-token-references "{foo}} + {bar}")))))) (t/deftest remove-attributes-for-token-id (t/testing "removes attributes matching the `token`, keeps other attributes" From 37f23855e873f30ad1f404254f14d73eec876ca3 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 09:52:51 +0200 Subject: [PATCH 04/16] Fix re-find only accepting string values throw --- frontend/src/app/main/ui/workspace/tokens/token.cljs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index 92591f14a2..8d967151b3 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -8,9 +8,10 @@ #"^\s*(-?[0-9]+\.?[0-9]*)\s*$") (defn parse-token-value [value] - (when-let [double-str (-> (re-find parseable-token-value-regexp value) - (last))] - (d/parse-double double-str))) + (when (string? value) + (when-let [double-str (-> (re-find parseable-token-value-regexp value) + (last))] + (d/parse-double double-str)))) (defn find-token-references "Finds token reference values in `value-string` and returns a set with all contained namespaces." From 0684d893e06561e0c1ef754a61595b493a1af662 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 11:06:49 +0200 Subject: [PATCH 05/16] Return resolved & parsed token names map --- .../app/main/ui/workspace/tokens/changes.cljs | 5 ++-- .../ui/workspace/tokens/style_dictionary.cljs | 30 +++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/changes.cljs b/frontend/src/app/main/ui/workspace/tokens/changes.cljs index e6e311ad00..45ff044df4 100644 --- a/frontend/src/app/main/ui/workspace/tokens/changes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/changes.cljs @@ -34,10 +34,9 @@ (watch [_ state _] (->> (rx/from (sd/resolve-tokens+ (get-in state [:workspace-data :tokens]))) (rx/mapcat - (fn [sd-tokens] + (fn [resolved-tokens] (let [undo-id (js/Symbol) - resolved-value (-> (get sd-tokens (:id token)) - (wtt/resolve-token-value)) + resolved-value (get-in resolved-tokens [(wtt/token-identifier token) :resolved-value]) tokenized-attributes (wtt/attributes-map attributes token)] (rx/of (dwu/start-undo-transaction undo-id) 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 83231fc30c..1ab85db960 100644 --- a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs @@ -79,19 +79,16 @@ [tokens & {:keys [debug?] :as config}] (p/let [sd-tokens (-> (wtt/token-names-tree tokens) (resolve-sd-tokens+ config))] - (let [tokens-by-name (wtt/token-names-map tokens) - resolved-tokens (reduce + (let [resolved-tokens (reduce (fn [acc ^js cur] - (let [value (.-value cur) - resolved-value (d/parse-double (.-value cur)) - original-value (-> cur .-original .-value) - id (.-name cur) - missing-reference? (and (not resolved-value) - (re-find #"\{" value) - (= value original-value))] - (cond-> (assoc-in acc [id :resolved-value] resolved-value) - missing-reference? (update-in [id :errors] (fnil conj #{}) :style-dictionary/missing-reference)))) - tokens-by-name sd-tokens)] + (let [id (uuid (.-uuid (.-id cur))) + origin-token (get tokens id) + resolved-value (wtt/parse-token-value (.-value cur)) + resolved-token (if (not resolved-value) + (assoc origin-token :errors [:style-dictionary/missing-reference]) + (assoc origin-token :resolved-value resolved-value))] + (assoc acc (wtt/token-identifier resolved-token) resolved-token))) + {} sd-tokens)] (when debug? (js/console.log "Resolved tokens" resolved-tokens)) resolved-tokens))) @@ -142,11 +139,18 @@ (comment (defonce !output (atom nil)) + (-> @refs/workspace-tokens + (resolve-tokens+ {:debug? false}) + (.then js/console.log)) + (-> (resolve-workspace-tokens+ {:debug? true}) (p/then #(reset! !output %))) + @!output + (->> @refs/workspace-tokens - (resolve-tokens+)) + (resolve-tokens+) + (#(doto % js/console.log))) (-> (clj->js {"a" {:name "a" :value "5"} From 31674db11df16dd2a496d0e25817ffca6d4b42eb Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 11:07:24 +0200 Subject: [PATCH 06/16] Skip parsing on numbers --- frontend/src/app/main/ui/workspace/tokens/token.cljs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index 8d967151b3..a641295379 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -8,10 +8,11 @@ #"^\s*(-?[0-9]+\.?[0-9]*)\s*$") (defn parse-token-value [value] - (when (string? value) - (when-let [double-str (-> (re-find parseable-token-value-regexp value) - (last))] - (d/parse-double double-str)))) + (cond + (number? value) value + (string? value) (when-let [double-str (-> (re-find parseable-token-value-regexp value) + (last))] + (d/parse-double double-str)))) (defn find-token-references "Finds token reference values in `value-string` and returns a set with all contained namespaces." From d98e9826649e91c1e57c473f72d800f2d6642fad Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 11:07:32 +0200 Subject: [PATCH 07/16] Cleanup --- frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs | 1 - 1 file changed, 1 deletion(-) 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 1ab85db960..fd0fe6d36a 100644 --- a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs @@ -2,7 +2,6 @@ (:require ["@tokens-studio/sd-transforms" :as sd-transforms] ["style-dictionary$default" :as sd] - [app.common.data :as d] [app.main.refs :as refs] [app.main.ui.workspace.tokens.token :as wtt] [cuerdas.core :as str] From e27e2d357ceb68c18c5122120da3e14e5fa43e5a Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 11:09:12 +0200 Subject: [PATCH 08/16] Add simple applying test --- .../token_tests/logic/token_actions_test.cljs | 58 ++++--------------- 1 file changed, 12 insertions(+), 46 deletions(-) diff --git a/frontend/test/token_tests/logic/token_actions_test.cljs b/frontend/test/token_tests/logic/token_actions_test.cljs index beef098473..7e0f87e7c7 100644 --- a/frontend/test/token_tests/logic/token_actions_test.cljs +++ b/frontend/test/token_tests/logic/token_actions_test.cljs @@ -5,6 +5,8 @@ [app.common.test-helpers.files :as cthf] [app.common.test-helpers.shapes :as cths] [app.main.ui.workspace.tokens.changes :as wtch] + [app.main.ui.workspace.tokens.token :as wtt] + [cljs.pprint :as pprint] [cljs.test :as t :include-macros true] [frontend-tests.helpers.pages :as thp] [frontend-tests.helpers.state :as ths] @@ -31,65 +33,29 @@ :type :border-radius}))) (t/deftest test-apply-token - (t/testing "applying a token twice with the same attributes will override the previous applied token" - (t/async - done - (let [file (setup-file) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:rx :ry} - :token (toht/get-token file :token-1) - :on-update-shape wtch/update-shape-radius-all}) - (wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:rx :ry} - :token (toht/get-token file :token-2) - :on-update-shape wtch/update-shape-radius-all})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-2' (toht/get-token file' :token-2) - rect-1' (cths/get-shape file' :rect-1)] - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:rx (:applied-tokens rect-1')) (:id token-2'))) - (t/is (= (:ry (:applied-tokens rect-1')) (:id token-2'))) - (t/is (= (:rx rect-1') 24)) - (t/is (= (:ry rect-1') 24))))))))) - -(t/deftest test-apply-token-overwrite - (t/testing "removes old token attributes and applies only single attribute" + (t/testing "applies token to shape and updates shape attributes to resolved value" (t/async done (let [file (setup-file) store (ths/setup-store file) rect-1 (cths/get-shape file :rect-1) - events [;; Apply `:token-1` to all border radius attributes - (wtch/apply-token {:attributes #{:rx :ry :r1 :r2 :r3 :r4} - :token (toht/get-token file :token-1) - :shape-ids [(:id rect-1)] - :on-update-shape wtch/update-shape-radius-all}) - ;; Apply single `:r1` attribute to same shape - ;; while removing other attributes from the border-radius set - ;; but keep `:r4` for testing purposes - (wtch/apply-token {:attributes #{:r1} - :attributes-to-remove #{:rx :ry :r1 :r2 :r3} + events [(wtch/apply-token {:shape-ids [(:id rect-1)] + :attributes #{:rx :ry} :token (toht/get-token file :token-2) - :shape-ids [(:id rect-1)] :on-update-shape wtch/update-shape-radius-all})]] (tohs/run-store-async store done events (fn [new-state] (let [file' (ths/get-file-from-store new-state) - token-1' (toht/get-token file' :token-1) token-2' (toht/get-token file' :token-2) rect-1' (cths/get-shape file' :rect-1)] - (t/testing "other border-radius attributes got removed" - (t/is (nil? (:rx (:applied-tokens rect-1'))))) - (t/testing "r1 got applied with :token-2" - (t/is (= (:r1 (:applied-tokens rect-1')) (:id token-2')))) - (t/testing "while :r4 was kept" - (t/is (= (:r4 (:applied-tokens rect-1')) (:id token-1')))))))))));))))))))))) + (t/testing "shape `:applied-tokens` got updated" + (t/is (some? (:applied-tokens rect-1'))) + (t/is (= (:rx (:applied-tokens rect-1')) (wtt/token-identifier token-2'))) + (t/is (= (:ry (:applied-tokens rect-1')) (wtt/token-identifier token-2')))) + (t/testing "shape radius got update to the resolved token value." + (t/is (= (:rx rect-1') 24)) + (t/is (= (:ry rect-1') 24)))))))))) (t/deftest test-apply-border-radius (t/testing "applies radius token and updates the shapes radius" From a073520d0e7ee5d75ccf5904ac5de902c8916eba Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 11:22:40 +0200 Subject: [PATCH 09/16] Restore tests to work with new identifier --- .../token_tests/logic/token_actions_test.cljs | 185 +++++++++++------- 1 file changed, 114 insertions(+), 71 deletions(-) diff --git a/frontend/test/token_tests/logic/token_actions_test.cljs b/frontend/test/token_tests/logic/token_actions_test.cljs index 7e0f87e7c7..17c16bece7 100644 --- a/frontend/test/token_tests/logic/token_actions_test.cljs +++ b/frontend/test/token_tests/logic/token_actions_test.cljs @@ -6,7 +6,6 @@ [app.common.test-helpers.shapes :as cths] [app.main.ui.workspace.tokens.changes :as wtch] [app.main.ui.workspace.tokens.token :as wtt] - [cljs.pprint :as pprint] [cljs.test :as t :include-macros true] [frontend-tests.helpers.pages :as thp] [frontend-tests.helpers.state :as ths] @@ -57,63 +56,77 @@ (t/is (= (:rx rect-1') 24)) (t/is (= (:ry rect-1') 24)))))))))) -(t/deftest test-apply-border-radius - (t/testing "applies radius token and updates the shapes radius" +(t/deftest test-apply-multiple-tokens + (t/testing "applying a token twice with the same attributes will override the previously applied tokens values" (t/async - done - (let [file (setup-file) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:rx :ry} - :token (toht/get-token file :token-2) - :on-update-shape wtch/update-shape-radius-all})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-2' (toht/get-token file' :token-2) - rect-1' (cths/get-shape file' :rect-1)] - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:rx (:applied-tokens rect-1')) (:id token-2'))) - (t/is (= (:ry (:applied-tokens rect-1')) (:id token-2'))) - (t/is (= (:rx rect-1') 24)) - (t/is (= (:ry rect-1') 24))))))))) + done + (let [file (setup-file) + store (ths/setup-store file) + rect-1 (cths/get-shape file :rect-1) + events [(wtch/apply-token {:shape-ids [(:id rect-1)] + :attributes #{:rx :ry} + :token (toht/get-token file :token-1) + :on-update-shape wtch/update-shape-radius-all}) + (wtch/apply-token {:shape-ids [(:id rect-1)] + :attributes #{:rx :ry} + :token (toht/get-token file :token-2) + :on-update-shape wtch/update-shape-radius-all})]] + (tohs/run-store-async + store done events + (fn [new-state] + (let [file' (ths/get-file-from-store new-state) + token-2' (toht/get-token file' :token-2) + rect-1' (cths/get-shape file' :rect-1)] + (t/testing "shape `:applied-tokens` got updated" + (t/is (some? (:applied-tokens rect-1'))) + (t/is (= (:rx (:applied-tokens rect-1')) (wtt/token-identifier token-2'))) + (t/is (= (:ry (:applied-tokens rect-1')) (wtt/token-identifier token-2')))) + (t/testing "shape radius got update to the resolved token value." + (t/is (= (:rx rect-1') 24)) + (t/is (= (:ry rect-1') 24)))))))))) + +(t/deftest test-apply-token-overwrite + (t/testing "removes old token attributes and applies only single attribute" + (t/async + done + (let [file (setup-file) + store (ths/setup-store file) + rect-1 (cths/get-shape file :rect-1) + events [;; Apply `:token-1` to all border radius attributes + (wtch/apply-token {:attributes #{:rx :ry :r1 :r2 :r3 :r4} + :token (toht/get-token file :token-1) + :shape-ids [(:id rect-1)] + :on-update-shape wtch/update-shape-radius-all}) + ;; Apply single `:r1` attribute to same shape + ;; while removing other attributes from the border-radius set + ;; but keep `:r4` for testing purposes + (wtch/apply-token {:attributes #{:r1} + :attributes-to-remove #{:rx :ry :r1 :r2 :r3} + :token (toht/get-token file :token-2) + :shape-ids [(:id rect-1)] + :on-update-shape wtch/update-shape-radius-all})]] + (tohs/run-store-async + store done events + (fn [new-state] + (let [file' (ths/get-file-from-store new-state) + token-1' (toht/get-token file' :token-1) + token-2' (toht/get-token file' :token-2) + rect-1' (cths/get-shape file' :rect-1)] + (t/testing "other border-radius attributes got removed" + (t/is (nil? (:rx (:applied-tokens rect-1'))))) + (t/testing "r1 got applied with :token-2" + (t/is (= (:r1 (:applied-tokens rect-1')) (wtt/token-identifier token-2')))) + (t/testing "while :r4 was kept" + (t/is (= (:r4 (:applied-tokens rect-1')) (wtt/token-identifier token-1')))))))))));))))))))))) (t/deftest test-apply-dimensions (t/testing "applies dimensions token and updates the shapes width and height" - (t/async - done - (let [file (-> (setup-file) - (toht/add-token :token-target {:value "100" - :name "dimensions.sm" - :type :dimensions})) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:width :height} - :token (toht/get-token file :token-target) - :on-update-shape wtch/update-shape-dimensions})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-target' (toht/get-token file' :token-target) - rect-1' (cths/get-shape file' :rect-1)] - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:width (:applied-tokens rect-1')) (:id token-target'))) - (t/is (= (:height (:applied-tokens rect-1')) (:id token-target'))) - (t/is (= (:width rect-1') 100)) - (t/is (= (:height rect-1') 100))))))))) - -(t/deftest test-apply-sizing - (t/testing "applies sizing token and updates the shapes width and height" (t/async done (let [file (-> (setup-file) (toht/add-token :token-target {:value "100" - :name "sizing.sm" - :type :sizing})) + :name "dimensions.sm" + :type :dimensions})) store (ths/setup-store file) rect-1 (cths/get-shape file :rect-1) events [(wtch/apply-token {:shape-ids [(:id rect-1)] @@ -126,11 +139,41 @@ (let [file' (ths/get-file-from-store new-state) token-target' (toht/get-token file' :token-target) rect-1' (cths/get-shape file' :rect-1)] - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:width (:applied-tokens rect-1')) (:id token-target'))) - (t/is (= (:height (:applied-tokens rect-1')) (:id token-target'))) - (t/is (= (:width rect-1') 100)) - (t/is (= (:height rect-1') 100))))))))) + (t/testing "shape `:applied-tokens` got updated" + (t/is (some? (:applied-tokens rect-1'))) + (t/is (= (:width (:applied-tokens rect-1')) (wtt/token-identifier token-target'))) + (t/is (= (:height (:applied-tokens rect-1')) (wtt/token-identifier token-target')))) + (t/testing "shapes width and height got updated" + (t/is (= (:width rect-1') 100)) + (t/is (= (:height rect-1') 100)))))))))) + +;; (t/deftest test-apply-sizing +;; (t/testing "applies sizing token and updates the shapes width and height" +;; (t/async +;; done +;; (let [file (-> (setup-file) +;; (toht/add-token :token-target {:value "100" +;; :name "sizing.sm" +;; :type :sizing})) +;; store (ths/setup-store file) +;; rect-1 (cths/get-shape file :rect-1) +;; events [(wtch/apply-token {:shape-ids [(:id rect-1)] +;; :attributes #{:width :height} +;; :token (toht/get-token file :token-target) +;; :on-update-shape wtch/update-shape-dimensions})]] +;; (tohs/run-store-async +;; store done events +;; (fn [new-state] +;; (let [file' (ths/get-file-from-store new-state) +;; token-target' (toht/get-token file' :token-target) +;; rect-1' (cths/get-shape file' :rect-1)] +;; (t/testing "shape `:applied-tokens` got updated" +;; (t/is (some? (:applied-tokens rect-1'))) +;; (t/is (= (:width (:applied-tokens rect-1')) (wtt/token-identifier token-target'))) +;; (t/is (= (:height (:applied-tokens rect-1')) (wtt/token-identifier token-target')))) +;; (t/testing "shapes width and height got updated" +;; (t/is (= (:width rect-1') 100)) +;; (t/is (= (:height rect-1') 100)))))))))) (t/deftest test-apply-opacity (t/testing "applies opacity token and updates the shapes opacity" @@ -173,13 +216,13 @@ token-opacity-percent (toht/get-token file' :opacity-percent) token-opacity-invalid (toht/get-token file' :opacity-invalid)] (t/testing "float value got translated to float and applied to opacity" - (t/is (= (:opacity (:applied-tokens rect-1')) (:id token-opacity-float))) + (t/is (= (:opacity (:applied-tokens rect-1')) (wtt/token-identifier token-opacity-float))) (t/is (= (:opacity rect-1') 0.3))) (t/testing "percentage value got translated to float and applied to opacity" - (t/is (= (:opacity (:applied-tokens rect-2')) (:id token-opacity-percent))) + (t/is (= (:opacity (:applied-tokens rect-2')) (wtt/token-identifier token-opacity-percent))) (t/is (= (:opacity rect-2') 0.4))) (t/testing "invalid opacity value got applied but did not change shape" - (t/is (= (:opacity (:applied-tokens rect-3')) (:id token-opacity-invalid))) + (t/is (= (:opacity (:applied-tokens rect-3')) (wtt/token-identifier token-opacity-invalid))) (t/is (nil? (:opacity rect-3'))))))))))) (t/deftest test-apply-rotation @@ -203,7 +246,7 @@ token-target' (toht/get-token file' :token-target) rect-1' (cths/get-shape file' :rect-1)] (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:rotation (:applied-tokens rect-1')) (:id token-target'))) + (t/is (= (:rotation (:applied-tokens rect-1')) (wtt/token-identifier token-target'))) (t/is (= (:rotation rect-1') 120))))))))) (t/deftest test-apply-stroke-width @@ -233,10 +276,10 @@ rect-with-stroke' (cths/get-shape file' :rect-1) rect-without-stroke' (cths/get-shape file' :rect-2)] (t/testing "token got applied to rect with stroke and shape stroke got updated" - (t/is (= (:stroke-width (:applied-tokens rect-with-stroke')) (:id token-target'))) + (t/is (= (:stroke-width (:applied-tokens rect-with-stroke')) (wtt/token-identifier token-target'))) (t/is (= (get-in rect-with-stroke' [:strokes 0 :stroke-width]) 10))) (t/testing "token got applied to rect without stroke but shape didnt get updated" - (t/is (= (:stroke-width (:applied-tokens rect-without-stroke')) (:id token-target'))) + (t/is (= (:stroke-width (:applied-tokens rect-without-stroke')) (wtt/token-identifier token-target'))) (t/is (empty? (:strokes rect-without-stroke'))))))))))) (t/deftest test-toggle-token-none @@ -260,10 +303,10 @@ rect-2' (cths/get-shape file' :rect-2)] (t/is (some? (:applied-tokens rect-1'))) (t/is (some? (:applied-tokens rect-2'))) - (t/is (= (:rx (:applied-tokens rect-1')) (:id token-2'))) - (t/is (= (:rx (:applied-tokens rect-2')) (:id token-2'))) - (t/is (= (:ry (:applied-tokens rect-1')) (:id token-2'))) - (t/is (= (:ry (:applied-tokens rect-2')) (:id token-2'))) + (t/is (= (:rx (:applied-tokens rect-1')) (wtt/token-identifier token-2'))) + (t/is (= (:rx (:applied-tokens rect-2')) (wtt/token-identifier token-2'))) + (t/is (= (:ry (:applied-tokens rect-1')) (wtt/token-identifier token-2'))) + (t/is (= (:ry (:applied-tokens rect-2')) (wtt/token-identifier token-2'))) (t/is (= (:rx rect-1') 24)) (t/is (= (:rx rect-2') 24))))))))) @@ -327,10 +370,10 @@ rect-with-other-token-2' (cths/get-shape file' :rect-3)] (t/testing "token got applied to all shapes" - (t/is (= (:rx (:applied-tokens rect-with-other-token-1')) (:id target-token))) - (t/is (= (:rx (:applied-tokens rect-without-token')) (:id target-token))) - (t/is (= (:rx (:applied-tokens rect-with-other-token-2')) (:id target-token))) + (t/is (= (:rx (:applied-tokens rect-with-other-token-1')) (wtt/token-identifier target-token))) + (t/is (= (:rx (:applied-tokens rect-without-token')) (wtt/token-identifier target-token))) + (t/is (= (:rx (:applied-tokens rect-with-other-token-2')) (wtt/token-identifier target-token))) - (t/is (= (:ry (:applied-tokens rect-with-other-token-1')) (:id target-token))) - (t/is (= (:ry (:applied-tokens rect-without-token')) (:id target-token))) - (t/is (= (:ry (:applied-tokens rect-with-other-token-2')) (:id target-token))))))))))) + (t/is (= (:ry (:applied-tokens rect-with-other-token-1')) (wtt/token-identifier target-token))) + (t/is (= (:ry (:applied-tokens rect-without-token')) (wtt/token-identifier target-token))) + (t/is (= (:ry (:applied-tokens rect-with-other-token-2')) (wtt/token-identifier target-token))))))))))) From 2d67a92d6485b9f003e05a43e2bd47bc8afd1184 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 11:39:58 +0200 Subject: [PATCH 10/16] Fix getter --- frontend/src/app/main/ui/workspace/tokens/form.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index 400e2b6ccb..4521906289 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -104,7 +104,7 @@ Token names should only contain letters and digits separated by . characters.")} (-> (sd/resolve-tokens+ new-tokens #_ {:debug? true}) (p/then (fn [resolved-tokens] - (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens token-id)] + (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens token-name)] (cond resolved-value (p/resolved resolved-token) (sd/missing-reference-error? errors) (p/rejected :error/token-missing-reference) From 8b8b909fb7255bc2ecee445a5e6dbf94293c16f9 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 15:12:28 +0200 Subject: [PATCH 11/16] Parse values with unit --- .../ui/workspace/tokens/style_dictionary.cljs | 16 ++++++++------ .../app/main/ui/workspace/tokens/token.cljs | 11 +++++----- frontend/test/token_tests/token_test.cljs | 21 ++++++++++++------- 3 files changed, 29 insertions(+), 19 deletions(-) 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 fd0fe6d36a..81881d8109 100644 --- a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs @@ -6,8 +6,7 @@ [app.main.ui.workspace.tokens.token :as wtt] [cuerdas.core :as str] [promesa.core :as p] - [rumext.v2 :as mf] - [shadow.resource])) + [rumext.v2 :as mf])) (def StyleDictionary "The global StyleDictionary instance used as an external library for now, @@ -82,10 +81,12 @@ (fn [acc ^js cur] (let [id (uuid (.-uuid (.-id cur))) origin-token (get tokens id) - resolved-value (wtt/parse-token-value (.-value cur)) - resolved-token (if (not resolved-value) + parsed-value (wtt/parse-token-value (.-value cur)) + resolved-token (if (not parsed-value) (assoc origin-token :errors [:style-dictionary/missing-reference]) - (assoc origin-token :resolved-value resolved-value))] + (assoc origin-token + :resolved-value (:value parsed-value) + :resolved-unit (:unit parsed-value)))] (assoc acc (wtt/token-identifier resolved-token) resolved-token))) {} sd-tokens)] (when debug? @@ -157,9 +158,12 @@ (#(resolve-sd-tokens+ % {:debug? true}))) + (defonce output (atom nil)) + (require '[shadow.resource]) (let [example (-> (shadow.resource/inline "./data/example-tokens-set.json") (js/JSON.parse) .-core)] - (resolve-sd-tokens+ example {:debug? true})) + (.then (resolve-sd-tokens+ example {:debug? true}) + #(reset! output %))) nil) diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index a641295379..aabfdf412a 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -5,14 +5,15 @@ [cuerdas.core :as str])) (def parseable-token-value-regexp - #"^\s*(-?[0-9]+\.?[0-9]*)\s*$") + #"^\s*(-?[0-9]+\.?[0-9]*)(px|%)?\s*$") (defn parse-token-value [value] (cond - (number? value) value - (string? value) (when-let [double-str (-> (re-find parseable-token-value-regexp value) - (last))] - (d/parse-double double-str)))) + (number? value) {:value value} + (string? value) (when-let [[_ value unit] (re-find parseable-token-value-regexp value)] + (when-let [parsed-value (d/parse-double value)] + {:value parsed-value + :unit unit})))) (defn find-token-references "Finds token reference values in `value-string` and returns a set with all contained namespaces." diff --git a/frontend/test/token_tests/token_test.cljs b/frontend/test/token_tests/token_test.cljs index 77cb674ae2..4b38c889cc 100644 --- a/frontend/test/token_tests/token_test.cljs +++ b/frontend/test/token_tests/token_test.cljs @@ -11,14 +11,19 @@ (t/deftest test-parse-token-value (t/testing "parses double from a token value" - (t/is (= 100.1 (wtt/parse-token-value "100.1"))) - (t/is (= -9 (wtt/parse-token-value "-9"))) - (t/testing "trims white-space" - (t/is (= -1.3 (wtt/parse-token-value " -1.3 ")))) - (t/testing "returns nil for any invalid characters" - (t/is (nil? (wtt/parse-token-value " -1.3a ")))) - (t/testing "doesnt accept invalid double" - (t/is (nil? (wtt/parse-token-value ".3")))))) + (t/is (= {:value 100.1 :unit nil} (wtt/parse-token-value "100.1"))) + (t/is (= {:value -9 :unit nil} (wtt/parse-token-value "-9")))) + (t/testing "trims white-space" + (t/is (= {:value -1.3 :unit nil} (wtt/parse-token-value " -1.3 ")))) + (t/testing "parses unit: px" + (t/is (= {:value 70.3 :unit "px"} (wtt/parse-token-value " 70.3px ")))) + (t/testing "parses unit: %" + (t/is (= {:value -10 :unit "%"} (wtt/parse-token-value "-10%")))) + (t/testing "parses unit: px") + (t/testing "returns nil for any invalid characters" + (t/is (nil? (wtt/parse-token-value " -1.3a ")))) + (t/testing "doesnt accept invalid double" + (t/is (nil? (wtt/parse-token-value ".3"))))) (t/deftest find-token-references (t/testing "finds references inside curly braces in a string" From e992bf0aa6bf4f61ac30b7f8e4d6cd9f99e5f29d Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 8 Aug 2024 15:13:04 +0200 Subject: [PATCH 12/16] Fix sizing test --- .../token_tests/logic/token_actions_test.cljs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/frontend/test/token_tests/logic/token_actions_test.cljs b/frontend/test/token_tests/logic/token_actions_test.cljs index 17c16bece7..e0d3fac38d 100644 --- a/frontend/test/token_tests/logic/token_actions_test.cljs +++ b/frontend/test/token_tests/logic/token_actions_test.cljs @@ -147,33 +147,33 @@ (t/is (= (:width rect-1') 100)) (t/is (= (:height rect-1') 100)))))))))) -;; (t/deftest test-apply-sizing -;; (t/testing "applies sizing token and updates the shapes width and height" -;; (t/async -;; done -;; (let [file (-> (setup-file) -;; (toht/add-token :token-target {:value "100" -;; :name "sizing.sm" -;; :type :sizing})) -;; store (ths/setup-store file) -;; rect-1 (cths/get-shape file :rect-1) -;; events [(wtch/apply-token {:shape-ids [(:id rect-1)] -;; :attributes #{:width :height} -;; :token (toht/get-token file :token-target) -;; :on-update-shape wtch/update-shape-dimensions})]] -;; (tohs/run-store-async -;; store done events -;; (fn [new-state] -;; (let [file' (ths/get-file-from-store new-state) -;; token-target' (toht/get-token file' :token-target) -;; rect-1' (cths/get-shape file' :rect-1)] -;; (t/testing "shape `:applied-tokens` got updated" -;; (t/is (some? (:applied-tokens rect-1'))) -;; (t/is (= (:width (:applied-tokens rect-1')) (wtt/token-identifier token-target'))) -;; (t/is (= (:height (:applied-tokens rect-1')) (wtt/token-identifier token-target')))) -;; (t/testing "shapes width and height got updated" -;; (t/is (= (:width rect-1') 100)) -;; (t/is (= (:height rect-1') 100)))))))))) +(t/deftest test-apply-sizing + (t/testing "applies sizing token and updates the shapes width and height" + (t/async + done + (let [file (-> (setup-file) + (toht/add-token :token-target {:value "100" + :name "sizing.sm" + :type :sizing})) + store (ths/setup-store file) + rect-1 (cths/get-shape file :rect-1) + events [(wtch/apply-token {:shape-ids [(:id rect-1)] + :attributes #{:width :height} + :token (toht/get-token file :token-target) + :on-update-shape wtch/update-shape-dimensions})]] + (tohs/run-store-async + store done events + (fn [new-state] + (let [file' (ths/get-file-from-store new-state) + token-target' (toht/get-token file' :token-target) + rect-1' (cths/get-shape file' :rect-1)] + (t/testing "shape `:applied-tokens` got updated" + (t/is (some? (:applied-tokens rect-1'))) + (t/is (= (:width (:applied-tokens rect-1')) (wtt/token-identifier token-target'))) + (t/is (= (:height (:applied-tokens rect-1')) (wtt/token-identifier token-target')))) + (t/testing "shapes width and height got updated" + (t/is (= (:width rect-1') 100)) + (t/is (= (:height rect-1') 100)))))))))) (t/deftest test-apply-opacity (t/testing "applies opacity token and updates the shapes opacity" From 5552295d61fe43ed59f5f0f79ef9b8e2db13fb85 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Fri, 9 Aug 2024 17:37:36 +0200 Subject: [PATCH 13/16] Add docstring --- frontend/src/app/main/ui/workspace/tokens/token.cljs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index aabfdf412a..9c0efd356d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -5,9 +5,14 @@ [cuerdas.core :as str])) (def parseable-token-value-regexp + "Regexp that can be used to parse a number value out of resolved token value. + This regexp also trims whitespace around the value." #"^\s*(-?[0-9]+\.?[0-9]*)(px|%)?\s*$") -(defn parse-token-value [value] +(defn parse-token-value + "Parses a resolved value and separates the unit from the value. + Returns a map of {:value `number` :unit `string`}." + [value] (cond (number? value) {:value value} (string? value) (when-let [[_ value unit] (re-find parseable-token-value-regexp value)] From 9ff4567955766a9fcf34ac993c78f65823f3f882 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Fri, 9 Aug 2024 18:03:20 +0200 Subject: [PATCH 14/16] Remove unused function --- frontend/src/app/main/data/tokens.cljs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/frontend/src/app/main/data/tokens.cljs b/frontend/src/app/main/data/tokens.cljs index 84c83ef0ac..3cce3bbc8b 100644 --- a/frontend/src/app/main/data/tokens.cljs +++ b/frontend/src/app/main/data/tokens.cljs @@ -80,17 +80,6 @@ (apply-token-to-shape props) shape)) -(defn update-token-from-attributes - [{:keys [token-id shape-id attributes]}] - (ptk/reify ::update-token-from-attributes - ptk/WatchEvent - (watch [_ state _] - (let [shape (get-shape-from-state shape-id state) - applied-tokens (apply-token-id-to-attributes {:shape shape - :token-id token-id - :attributes attributes})] - (rx/of (update-shape shape-id {:applied-tokens applied-tokens})))))) - (defn get-token-data-from-token-id [id] (let [workspace-data (deref refs/workspace-data)] From 51a27c07ec28d4f244a2ee66c95af37e4e217bb8 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Fri, 9 Aug 2024 18:03:47 +0200 Subject: [PATCH 15/16] Use token identifier --- frontend/src/app/main/data/tokens.cljs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/main/data/tokens.cljs b/frontend/src/app/main/data/tokens.cljs index 3cce3bbc8b..a27c7f30cb 100644 --- a/frontend/src/app/main/data/tokens.cljs +++ b/frontend/src/app/main/data/tokens.cljs @@ -16,6 +16,7 @@ [app.main.data.workspace.shapes :as dwsh] [app.main.refs :as refs] [app.main.ui.workspace.tokens.common :refer [workspace-shapes]] + [app.main.ui.workspace.tokens.token :as wtt] [beicon.v2.core :as rx] [clojure.data :as data] [cuerdas.core :as str] @@ -55,22 +56,22 @@ (first))] shape)) -(defn token-from-attributes [token-id attributes] - (->> (map (fn [attr] [attr token-id]) attributes) +(defn token-from-attributes [token attributes] + (->> (map (fn [attr] [attr (wtt/token-identifier token)]) attributes) (into {}))) (defn unapply-token-id [shape attributes] (update shape :applied-tokens d/without-keys attributes)) -(defn apply-token-id-to-attributes [{:keys [shape token-id attributes]}] - (let [token (token-from-attributes token-id attributes)] +(defn apply-token-to-attributes [{:keys [shape token attributes]}] + (let [token (token-from-attributes token attributes)] (toggle-or-apply-token shape token))) (defn apply-token-to-shape [{:keys [shape token attributes] :as _props}] - (let [applied-tokens (apply-token-id-to-attributes {:shape shape - :token-id (:id token) - :attributes attributes})] + (let [applied-tokens (apply-token-to-attributes {:shape shape + :token token + :attributes attributes})] (update shape :applied-tokens #(merge % applied-tokens)))) (defn maybe-apply-token-to-shape From 726b0a26713d5200592df78ce6d10907f44afd31 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Fri, 9 Aug 2024 18:04:33 +0200 Subject: [PATCH 16/16] Fix :applied-tokens not being updated --- .../app/main/ui/workspace/sidebar/options/menus/measures.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 05efc28a48..e786b1141f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -300,7 +300,7 @@ (update-fn shape) shape)) {:reg-objects? true - :attrs [:rx :ry :r1 :r2 :r3 :r4]}))) + :attrs [:rx :ry :r1 :r2 :r3 :r4 :applied-tokens]}))) on-switch-to-radius-1 (mf/use-fn