diff --git a/common/src/app/common/types/token.cljc b/common/src/app/common/types/token.cljc index 7e2a06e178..49ef41164a 100644 --- a/common/src/app/common/types/token.cljc +++ b/common/src/app/common/types/token.cljc @@ -34,6 +34,7 @@ :color "color" :dimensions "dimension" :font-size "fontSizes" + :letter-spacing "letterSpacing" :number "number" :opacity "opacity" :other "other" @@ -107,11 +108,10 @@ (def spacing-keys (schema-keys schema:spacing)) (def ^:private schema:dimensions - [:merge - schema:sizing - schema:spacing - schema:stroke-width - schema:border-radius]) + (reduce mu/union [schema:sizing + schema:spacing + schema:stroke-width + schema:border-radius])) (def dimensions-keys (schema-keys schema:dimensions)) @@ -127,12 +127,17 @@ (def font-size-keys (schema-keys schema:font-size)) -(def typography-keys (set/union font-size-keys)) +(def ^:private schema:letter-spacing + [:map + [:letter-spacing {:optional true} token-name-ref]]) + +(def letter-spacing-keys (schema-keys schema:letter-spacing)) + +(def typography-keys (set/union font-size-keys letter-spacing-keys)) (def ^:private schema:number - [:map - [:rotation {:optional true} token-name-ref] - [:line-height {:optional true} token-name-ref]]) + (reduce mu/union [[:map [:line-height {:optional true} token-name-ref]] + schema:rotation])) (def number-keys (schema-keys schema:number)) @@ -159,6 +164,7 @@ schema:rotation schema:number schema:font-size + schema:letter-spacing schema:dimensions]) (defn shape-attr->token-attrs @@ -187,6 +193,7 @@ #{:m1 :m2 :m3 :m4}) (font-size-keys shape-attr) #{shape-attr} + (letter-spacing-keys shape-attr) #{shape-attr} (border-radius-keys shape-attr) #{shape-attr} (sizing-keys shape-attr) #{shape-attr} (opacity-keys shape-attr) #{shape-attr} @@ -280,4 +287,3 @@ (defn unapply-token-id [shape attributes] (update shape :applied-tokens d/without-keys attributes)) - diff --git a/common/test/common_tests/logic/token_apply_test.cljc b/common/test/common_tests/logic/token_apply_test.cljc index c8d41f53af..384f534e8a 100644 --- a/common/test/common_tests/logic/token_apply_test.cljc +++ b/common/test/common_tests/logic/token_apply_test.cljc @@ -58,7 +58,11 @@ (ctob/add-token-in-set "test-token-set" (ctob/make-token :name "token-font-size" :type :font-size - :value 24)))) + :value 24)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "token-letter-spacing" + :type :letter-spacing + :value 2)))) (tho/add-frame :frame1) (tho/add-text :text1 "Hello World!"))) @@ -72,7 +76,8 @@ (tht/apply-token-to-shape :frame1 "token-color" [:stroke-color] [:stroke-color] "#00ff00") (tht/apply-token-to-shape :frame1 "token-color" [:fill] [:fill] "#00ff00") (tht/apply-token-to-shape :frame1 "token-dimensions" [:width :height] [:width :height] 100) - (tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] 24))) + (tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] 24) + (tht/apply-token-to-shape :text1 "token-letter-spacing" [:letter-spacing] [:letter-spacing] 2))) (t/deftest apply-tokens-to-shape (let [;; ==== Setup @@ -87,6 +92,7 @@ token-color (tht/get-token file "test-token-set" "token-color") token-dimensions (tht/get-token file "test-token-set" "token-dimensions") token-font-size (tht/get-token file "test-token-set" "token-font-size") + token-letter-spacing (tht/get-token file "test-token-set" "token-letter-spacing") ;; ==== Action changes (-> (-> (pcb/empty-changes nil) @@ -123,7 +129,10 @@ (as-> shape $ (cto/apply-token-to-shape {:token token-font-size :shape $ - :attributes [:font-size]}))) + :attributes [:font-size]}) + (cto/apply-token-to-shape {:token token-letter-spacing + :shape $ + :attributes [:letter-spacing]}))) (:objects page) {})) @@ -148,8 +157,9 @@ (t/is (= (:fill applied-tokens') "token-color")) (t/is (= (:width applied-tokens') "token-dimensions")) (t/is (= (:height applied-tokens') "token-dimensions")) - (t/is (= (count text1-applied-tokens) 1)) - (t/is (= (:font-size text1-applied-tokens) "token-font-size")))) + (t/is (= (count text1-applied-tokens) 2)) + (t/is (= (:font-size text1-applied-tokens) "token-font-size")) + (t/is (= (:letter-spacing text1-applied-tokens) "token-letter-spacing")))) (t/deftest unapply-tokens-from-shape (let [;; ==== Setup @@ -178,7 +188,8 @@ (cls/generate-update-shapes [(:id text1)] (fn [shape] (-> shape - (cto/unapply-token-id [:font-size]))) + (cto/unapply-token-id [:font-size]) + (cto/unapply-token-id [:letter-spacing]))) (:objects page) {})) @@ -228,7 +239,8 @@ txt/is-content-node? d/txt-merge {:fills (ths/sample-fills-color :fill-color "#fabada") - :font-size "1"})) + :font-size "1" + :letter-spacing "0"})) (:objects page) {})) diff --git a/frontend/src/app/main/data/workspace/tokens/application.cljs b/frontend/src/app/main/data/workspace/tokens/application.cljs index 778398fc11..69a93165ac 100644 --- a/frontend/src/app/main/data/workspace/tokens/application.cljs +++ b/frontend/src/app/main/data/workspace/tokens/application.cljs @@ -333,10 +333,7 @@ (defn update-line-height ([value shape-ids attributes] (update-line-height value shape-ids attributes nil)) - ([value shape-ids _attributes page-id] ; The attributes param is - ; needed to have the same - ; arity that other update - ; functions + ([value shape-ids _attributes page-id] (let [update-node? (fn [node] (or (txt/is-text-node? node) (txt/is-paragraph-node? node)))] @@ -346,6 +343,18 @@ {:ignore-touched true :page-id page-id}))))) +(defn update-letter-spacing + ([value shape-ids attributes] (update-letter-spacing value shape-ids attributes nil)) + ([value shape-ids _attributes page-id] + (let [update-node? (fn [node] + (or (txt/is-text-node? node) + (txt/is-paragraph-node? node)))] + (when (number? value) + (dwsh/update-shapes shape-ids + #(txt/update-text-content % update-node? d/txt-merge {:letter-spacing (str value)}) + {:ignore-touched true + :page-id page-id}))))) + (defn update-font-size ([value shape-ids attributes] (update-font-size value shape-ids attributes nil)) ([value shape-ids _attributes page-id] @@ -391,6 +400,14 @@ :fields [{:label "Font Size" :key :font-size}]}} + :letter-spacing + {:title "Letter Spacing" + :attributes ctt/letter-spacing-keys + :on-update-shape update-letter-spacing + :modal {:key :tokens/letter-spacing + :fields [{:label "Letter Spacing" + :key :letter-spacing}]}} + :stroke-width {:title "Stroke Width" :attributes ctt/stroke-width-keys diff --git a/frontend/src/app/main/data/workspace/tokens/propagation.cljs b/frontend/src/app/main/data/workspace/tokens/propagation.cljs index 237e8d2c69..30f403bfbf 100644 --- a/frontend/src/app/main/data/workspace/tokens/propagation.cljs +++ b/frontend/src/app/main/data/workspace/tokens/propagation.cljs @@ -34,6 +34,7 @@ ctt/opacity-keys dwta/update-opacity #{:line-height} dwta/update-line-height #{:font-size} dwta/update-font-size + #{:letter-spacing} dwta/update-letter-spacing #{:x :y} dwta/update-shape-position #{:p1 :p2 :p3 :p4} dwta/update-layout-padding #{:m1 :m2 :m3 :m4} dwta/update-layout-item-margin diff --git a/frontend/src/app/main/ui/workspace/tokens/management.cljs b/frontend/src/app/main/ui/workspace/tokens/management.cljs index 106c473f07..63ddb45c2a 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management.cljs @@ -2,6 +2,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.common.types.token :as ctt] [app.common.types.tokens-lib :as ctob] [app.config :as cf] [app.main.data.style-dictionary :as sd] @@ -21,6 +22,9 @@ (def ref:token-type-open-status (l/derived (l/key :open-status-by-type) refs/workspace-tokens)) +(defn- remove-keys [m ks] + (d/removem (comp ks key) m)) + (defn- get-sorted-token-groups "Separate token-types into groups of `empty` or `filled` depending if tokens exist for that type. Sort each group alphabetically (by their type). @@ -30,7 +34,7 @@ token-typography-types? (contains? cf/flags :token-typography-types) all-types (cond-> dwta/token-properties (not token-units?) (dissoc :number) - (not token-typography-types?) (dissoc :font-size)) + (not token-typography-types?) (remove-keys ctt/typography-keys)) all-types (-> all-types keys seq)] (loop [empty #js [] filled #js [] diff --git a/frontend/src/app/main/ui/workspace/tokens/management/create/modals.cljs b/frontend/src/app/main/ui/workspace/tokens/management/create/modals.cljs index 25eade8097..758b015e0e 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/create/modals.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/create/modals.cljs @@ -185,3 +185,9 @@ ::mf/register-as :tokens/font-size} [properties] [:& token-update-create-modal properties]) + +(mf/defc letter-spacing-modal + {::mf/register modal/components + ::mf/register-as :tokens/letter-spacing} + [properties] + [:& token-update-create-modal properties]) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/group.cljs b/frontend/src/app/main/ui/workspace/tokens/management/group.cljs index b78411c5e9..c96ed54cdf 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/group.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/group.cljs @@ -28,6 +28,7 @@ :color "drop" :boolean "boolean-difference" :font-size "text-font-size" + :letter-spacing "text-letterspacing" :opacity "percentage" :number "number" :rotation "rotation" diff --git a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs index 8c0ed6e59c..f55e05dca4 100644 --- a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs +++ b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs @@ -521,6 +521,40 @@ (t/is (= (:line-height (:applied-tokens text-1')) (:name token-target'))) (t/is (= (:line-height style-text-blocks) 1.5))))))))) +(t/deftest test-apply-letter-spacing + (t/testing "applies letter-spacing token and updates the text letter-spacing" + (t/async + done + (let [letter-spacing-token {:name "wide-spacing" + :value "2" + :type :letter-spacing} + file (-> (setup-file-with-tokens) + (update-in [:data :tokens-lib] + #(ctob/add-token-in-set % "Set A" (ctob/make-token letter-spacing-token)))) + store (ths/setup-store file) + text-1 (cths/get-shape file :text-1) + events [(dwta/apply-token {:shape-ids [(:id text-1)] + :attributes #{:letter-spacing} + :token (toht/get-token file "wide-spacing") + :on-update-shape dwta/update-letter-spacing})]] + (tohs/run-store-async + store done events + (fn [new-state] + (let [file' (ths/get-file-from-state new-state) + token-target' (toht/get-token file' "wide-spacing") + text-1' (cths/get-shape file' :text-1) + style-text-blocks (->> (:content text-1') + (txt/content->text+styles) + (remove (fn [[_ text]] (str/empty? (str/trim text)))) + (mapv (fn [[style text]] + {:styles (merge txt/default-text-attrs style) + :text-content text})) + (first) + (:styles))] + (t/is (some? (:applied-tokens text-1'))) + (t/is (= (:letter-spacing (:applied-tokens text-1')) (:name token-target'))) + (t/is (= (:letter-spacing style-text-blocks) "2"))))))))) + (t/deftest test-toggle-token-none (t/testing "should apply token to all selected items, where no item has the token applied" (t/async