Skip to content

Commit 2174614

Browse files
authored
✨ Add letter spacing token (penpot#6814)
* 🐛 Fix merge schema not working with key generation * ✨ Add letter-spacing token * ♻️ Remove comments * ♻️ Inline line-height for now
1 parent 3165761 commit 2174614

8 files changed

Lines changed: 103 additions & 22 deletions

File tree

common/src/app/common/types/token.cljc

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
:color "color"
3535
:dimensions "dimension"
3636
:font-size "fontSizes"
37+
:letter-spacing "letterSpacing"
3738
:number "number"
3839
:opacity "opacity"
3940
:other "other"
@@ -107,11 +108,10 @@
107108
(def spacing-keys (schema-keys schema:spacing))
108109

109110
(def ^:private schema:dimensions
110-
[:merge
111-
schema:sizing
112-
schema:spacing
113-
schema:stroke-width
114-
schema:border-radius])
111+
(reduce mu/union [schema:sizing
112+
schema:spacing
113+
schema:stroke-width
114+
schema:border-radius]))
115115

116116
(def dimensions-keys (schema-keys schema:dimensions))
117117

@@ -127,12 +127,17 @@
127127

128128
(def font-size-keys (schema-keys schema:font-size))
129129

130-
(def typography-keys (set/union font-size-keys))
130+
(def ^:private schema:letter-spacing
131+
[:map
132+
[:letter-spacing {:optional true} token-name-ref]])
133+
134+
(def letter-spacing-keys (schema-keys schema:letter-spacing))
135+
136+
(def typography-keys (set/union font-size-keys letter-spacing-keys))
131137

132138
(def ^:private schema:number
133-
[:map
134-
[:rotation {:optional true} token-name-ref]
135-
[:line-height {:optional true} token-name-ref]])
139+
(reduce mu/union [[:map [:line-height {:optional true} token-name-ref]]
140+
schema:rotation]))
136141

137142
(def number-keys (schema-keys schema:number))
138143

@@ -159,6 +164,7 @@
159164
schema:rotation
160165
schema:number
161166
schema:font-size
167+
schema:letter-spacing
162168
schema:dimensions])
163169

164170
(defn shape-attr->token-attrs
@@ -187,6 +193,7 @@
187193
#{:m1 :m2 :m3 :m4})
188194

189195
(font-size-keys shape-attr) #{shape-attr}
196+
(letter-spacing-keys shape-attr) #{shape-attr}
190197
(border-radius-keys shape-attr) #{shape-attr}
191198
(sizing-keys shape-attr) #{shape-attr}
192199
(opacity-keys shape-attr) #{shape-attr}
@@ -280,4 +287,3 @@
280287

281288
(defn unapply-token-id [shape attributes]
282289
(update shape :applied-tokens d/without-keys attributes))
283-

common/test/common_tests/logic/token_apply_test.cljc

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@
5858
(ctob/add-token-in-set "test-token-set"
5959
(ctob/make-token :name "token-font-size"
6060
:type :font-size
61-
:value 24))))
61+
:value 24))
62+
(ctob/add-token-in-set "test-token-set"
63+
(ctob/make-token :name "token-letter-spacing"
64+
:type :letter-spacing
65+
:value 2))))
6266
(tho/add-frame :frame1)
6367
(tho/add-text :text1 "Hello World!")))
6468

@@ -72,7 +76,8 @@
7276
(tht/apply-token-to-shape :frame1 "token-color" [:stroke-color] [:stroke-color] "#00ff00")
7377
(tht/apply-token-to-shape :frame1 "token-color" [:fill] [:fill] "#00ff00")
7478
(tht/apply-token-to-shape :frame1 "token-dimensions" [:width :height] [:width :height] 100)
75-
(tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] 24)))
79+
(tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] 24)
80+
(tht/apply-token-to-shape :text1 "token-letter-spacing" [:letter-spacing] [:letter-spacing] 2)))
7681

7782
(t/deftest apply-tokens-to-shape
7883
(let [;; ==== Setup
@@ -87,6 +92,7 @@
8792
token-color (tht/get-token file "test-token-set" "token-color")
8893
token-dimensions (tht/get-token file "test-token-set" "token-dimensions")
8994
token-font-size (tht/get-token file "test-token-set" "token-font-size")
95+
token-letter-spacing (tht/get-token file "test-token-set" "token-letter-spacing")
9096

9197
;; ==== Action
9298
changes (-> (-> (pcb/empty-changes nil)
@@ -123,7 +129,10 @@
123129
(as-> shape $
124130
(cto/apply-token-to-shape {:token token-font-size
125131
:shape $
126-
:attributes [:font-size]})))
132+
:attributes [:font-size]})
133+
(cto/apply-token-to-shape {:token token-letter-spacing
134+
:shape $
135+
:attributes [:letter-spacing]})))
127136
(:objects page)
128137
{}))
129138

@@ -148,8 +157,9 @@
148157
(t/is (= (:fill applied-tokens') "token-color"))
149158
(t/is (= (:width applied-tokens') "token-dimensions"))
150159
(t/is (= (:height applied-tokens') "token-dimensions"))
151-
(t/is (= (count text1-applied-tokens) 1))
152-
(t/is (= (:font-size text1-applied-tokens) "token-font-size"))))
160+
(t/is (= (count text1-applied-tokens) 2))
161+
(t/is (= (:font-size text1-applied-tokens) "token-font-size"))
162+
(t/is (= (:letter-spacing text1-applied-tokens) "token-letter-spacing"))))
153163

154164
(t/deftest unapply-tokens-from-shape
155165
(let [;; ==== Setup
@@ -178,7 +188,8 @@
178188
(cls/generate-update-shapes [(:id text1)]
179189
(fn [shape]
180190
(-> shape
181-
(cto/unapply-token-id [:font-size])))
191+
(cto/unapply-token-id [:font-size])
192+
(cto/unapply-token-id [:letter-spacing])))
182193
(:objects page)
183194
{}))
184195

@@ -228,7 +239,8 @@
228239
txt/is-content-node?
229240
d/txt-merge
230241
{:fills (ths/sample-fills-color :fill-color "#fabada")
231-
:font-size "1"}))
242+
:font-size "1"
243+
:letter-spacing "0"}))
232244
(:objects page)
233245
{}))
234246

frontend/src/app/main/data/workspace/tokens/application.cljs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,7 @@
333333

334334
(defn update-line-height
335335
([value shape-ids attributes] (update-line-height value shape-ids attributes nil))
336-
([value shape-ids _attributes page-id] ; The attributes param is
337-
; needed to have the same
338-
; arity that other update
339-
; functions
336+
([value shape-ids _attributes page-id]
340337
(let [update-node? (fn [node]
341338
(or (txt/is-text-node? node)
342339
(txt/is-paragraph-node? node)))]
@@ -346,6 +343,18 @@
346343
{:ignore-touched true
347344
:page-id page-id})))))
348345

346+
(defn update-letter-spacing
347+
([value shape-ids attributes] (update-letter-spacing value shape-ids attributes nil))
348+
([value shape-ids _attributes page-id]
349+
(let [update-node? (fn [node]
350+
(or (txt/is-text-node? node)
351+
(txt/is-paragraph-node? node)))]
352+
(when (number? value)
353+
(dwsh/update-shapes shape-ids
354+
#(txt/update-text-content % update-node? d/txt-merge {:letter-spacing (str value)})
355+
{:ignore-touched true
356+
:page-id page-id})))))
357+
349358
(defn update-font-size
350359
([value shape-ids attributes] (update-font-size value shape-ids attributes nil))
351360
([value shape-ids _attributes page-id]
@@ -391,6 +400,14 @@
391400
:fields [{:label "Font Size"
392401
:key :font-size}]}}
393402

403+
:letter-spacing
404+
{:title "Letter Spacing"
405+
:attributes ctt/letter-spacing-keys
406+
:on-update-shape update-letter-spacing
407+
:modal {:key :tokens/letter-spacing
408+
:fields [{:label "Letter Spacing"
409+
:key :letter-spacing}]}}
410+
394411
:stroke-width
395412
{:title "Stroke Width"
396413
:attributes ctt/stroke-width-keys

frontend/src/app/main/data/workspace/tokens/propagation.cljs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
ctt/opacity-keys dwta/update-opacity
3535
#{:line-height} dwta/update-line-height
3636
#{:font-size} dwta/update-font-size
37+
#{:letter-spacing} dwta/update-letter-spacing
3738
#{:x :y} dwta/update-shape-position
3839
#{:p1 :p2 :p3 :p4} dwta/update-layout-padding
3940
#{:m1 :m2 :m3 :m4} dwta/update-layout-item-margin

frontend/src/app/main/ui/workspace/tokens/management.cljs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
(:require-macros [app.main.style :as stl])
33
(:require
44
[app.common.data :as d]
5+
[app.common.types.token :as ctt]
56
[app.common.types.tokens-lib :as ctob]
67
[app.config :as cf]
78
[app.main.data.style-dictionary :as sd]
@@ -21,6 +22,9 @@
2122
(def ref:token-type-open-status
2223
(l/derived (l/key :open-status-by-type) refs/workspace-tokens))
2324

25+
(defn- remove-keys [m ks]
26+
(d/removem (comp ks key) m))
27+
2428
(defn- get-sorted-token-groups
2529
"Separate token-types into groups of `empty` or `filled` depending if
2630
tokens exist for that type. Sort each group alphabetically (by their type).
@@ -30,7 +34,7 @@
3034
token-typography-types? (contains? cf/flags :token-typography-types)
3135
all-types (cond-> dwta/token-properties
3236
(not token-units?) (dissoc :number)
33-
(not token-typography-types?) (dissoc :font-size))
37+
(not token-typography-types?) (remove-keys ctt/typography-keys))
3438
all-types (-> all-types keys seq)]
3539
(loop [empty #js []
3640
filled #js []

frontend/src/app/main/ui/workspace/tokens/management/create/modals.cljs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,9 @@
185185
::mf/register-as :tokens/font-size}
186186
[properties]
187187
[:& token-update-create-modal properties])
188+
189+
(mf/defc letter-spacing-modal
190+
{::mf/register modal/components
191+
::mf/register-as :tokens/letter-spacing}
192+
[properties]
193+
[:& token-update-create-modal properties])

frontend/src/app/main/ui/workspace/tokens/management/group.cljs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
:color "drop"
2929
:boolean "boolean-difference"
3030
:font-size "text-font-size"
31+
:letter-spacing "text-letterspacing"
3132
:opacity "percentage"
3233
:number "number"
3334
:rotation "rotation"

frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,40 @@
521521
(t/is (= (:line-height (:applied-tokens text-1')) (:name token-target')))
522522
(t/is (= (:line-height style-text-blocks) 1.5)))))))))
523523

524+
(t/deftest test-apply-letter-spacing
525+
(t/testing "applies letter-spacing token and updates the text letter-spacing"
526+
(t/async
527+
done
528+
(let [letter-spacing-token {:name "wide-spacing"
529+
:value "2"
530+
:type :letter-spacing}
531+
file (-> (setup-file-with-tokens)
532+
(update-in [:data :tokens-lib]
533+
#(ctob/add-token-in-set % "Set A" (ctob/make-token letter-spacing-token))))
534+
store (ths/setup-store file)
535+
text-1 (cths/get-shape file :text-1)
536+
events [(dwta/apply-token {:shape-ids [(:id text-1)]
537+
:attributes #{:letter-spacing}
538+
:token (toht/get-token file "wide-spacing")
539+
:on-update-shape dwta/update-letter-spacing})]]
540+
(tohs/run-store-async
541+
store done events
542+
(fn [new-state]
543+
(let [file' (ths/get-file-from-state new-state)
544+
token-target' (toht/get-token file' "wide-spacing")
545+
text-1' (cths/get-shape file' :text-1)
546+
style-text-blocks (->> (:content text-1')
547+
(txt/content->text+styles)
548+
(remove (fn [[_ text]] (str/empty? (str/trim text))))
549+
(mapv (fn [[style text]]
550+
{:styles (merge txt/default-text-attrs style)
551+
:text-content text}))
552+
(first)
553+
(:styles))]
554+
(t/is (some? (:applied-tokens text-1')))
555+
(t/is (= (:letter-spacing (:applied-tokens text-1')) (:name token-target')))
556+
(t/is (= (:letter-spacing style-text-blocks) "2")))))))))
557+
524558
(t/deftest test-toggle-token-none
525559
(t/testing "should apply token to all selected items, where no item has the token applied"
526560
(t/async

0 commit comments

Comments
 (0)