mirror of
https://github.com/penpot/penpot.git
synced 2025-08-07 14:38:33 +02:00
✨ Add letter spacing token (#6814)
* 🐛 Fix merge schema not working with key generation * ✨ Add letter-spacing token * ♻️ Remove comments * ♻️ Inline line-height for now
This commit is contained in:
parent
3165761bac
commit
21746144b7
8 changed files with 103 additions and 22 deletions
|
@ -34,6 +34,7 @@
|
||||||
:color "color"
|
:color "color"
|
||||||
:dimensions "dimension"
|
:dimensions "dimension"
|
||||||
:font-size "fontSizes"
|
:font-size "fontSizes"
|
||||||
|
:letter-spacing "letterSpacing"
|
||||||
:number "number"
|
:number "number"
|
||||||
:opacity "opacity"
|
:opacity "opacity"
|
||||||
:other "other"
|
:other "other"
|
||||||
|
@ -107,11 +108,10 @@
|
||||||
(def spacing-keys (schema-keys schema:spacing))
|
(def spacing-keys (schema-keys schema:spacing))
|
||||||
|
|
||||||
(def ^:private schema:dimensions
|
(def ^:private schema:dimensions
|
||||||
[:merge
|
(reduce mu/union [schema:sizing
|
||||||
schema:sizing
|
|
||||||
schema:spacing
|
schema:spacing
|
||||||
schema:stroke-width
|
schema:stroke-width
|
||||||
schema:border-radius])
|
schema:border-radius]))
|
||||||
|
|
||||||
(def dimensions-keys (schema-keys schema:dimensions))
|
(def dimensions-keys (schema-keys schema:dimensions))
|
||||||
|
|
||||||
|
@ -127,12 +127,17 @@
|
||||||
|
|
||||||
(def font-size-keys (schema-keys schema:font-size))
|
(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
|
(def ^:private schema:number
|
||||||
[:map
|
(reduce mu/union [[:map [:line-height {:optional true} token-name-ref]]
|
||||||
[:rotation {:optional true} token-name-ref]
|
schema:rotation]))
|
||||||
[:line-height {:optional true} token-name-ref]])
|
|
||||||
|
|
||||||
(def number-keys (schema-keys schema:number))
|
(def number-keys (schema-keys schema:number))
|
||||||
|
|
||||||
|
@ -159,6 +164,7 @@
|
||||||
schema:rotation
|
schema:rotation
|
||||||
schema:number
|
schema:number
|
||||||
schema:font-size
|
schema:font-size
|
||||||
|
schema:letter-spacing
|
||||||
schema:dimensions])
|
schema:dimensions])
|
||||||
|
|
||||||
(defn shape-attr->token-attrs
|
(defn shape-attr->token-attrs
|
||||||
|
@ -187,6 +193,7 @@
|
||||||
#{:m1 :m2 :m3 :m4})
|
#{:m1 :m2 :m3 :m4})
|
||||||
|
|
||||||
(font-size-keys shape-attr) #{shape-attr}
|
(font-size-keys shape-attr) #{shape-attr}
|
||||||
|
(letter-spacing-keys shape-attr) #{shape-attr}
|
||||||
(border-radius-keys shape-attr) #{shape-attr}
|
(border-radius-keys shape-attr) #{shape-attr}
|
||||||
(sizing-keys shape-attr) #{shape-attr}
|
(sizing-keys shape-attr) #{shape-attr}
|
||||||
(opacity-keys shape-attr) #{shape-attr}
|
(opacity-keys shape-attr) #{shape-attr}
|
||||||
|
@ -280,4 +287,3 @@
|
||||||
|
|
||||||
(defn unapply-token-id [shape attributes]
|
(defn unapply-token-id [shape attributes]
|
||||||
(update shape :applied-tokens d/without-keys attributes))
|
(update shape :applied-tokens d/without-keys attributes))
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,11 @@
|
||||||
(ctob/add-token-in-set "test-token-set"
|
(ctob/add-token-in-set "test-token-set"
|
||||||
(ctob/make-token :name "token-font-size"
|
(ctob/make-token :name "token-font-size"
|
||||||
:type :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-frame :frame1)
|
||||||
(tho/add-text :text1 "Hello World!")))
|
(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" [:stroke-color] [:stroke-color] "#00ff00")
|
||||||
(tht/apply-token-to-shape :frame1 "token-color" [:fill] [:fill] "#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 :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
|
(t/deftest apply-tokens-to-shape
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
|
@ -87,6 +92,7 @@
|
||||||
token-color (tht/get-token file "test-token-set" "token-color")
|
token-color (tht/get-token file "test-token-set" "token-color")
|
||||||
token-dimensions (tht/get-token file "test-token-set" "token-dimensions")
|
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-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
|
;; ==== Action
|
||||||
changes (-> (-> (pcb/empty-changes nil)
|
changes (-> (-> (pcb/empty-changes nil)
|
||||||
|
@ -123,7 +129,10 @@
|
||||||
(as-> shape $
|
(as-> shape $
|
||||||
(cto/apply-token-to-shape {:token token-font-size
|
(cto/apply-token-to-shape {:token token-font-size
|
||||||
:shape $
|
:shape $
|
||||||
:attributes [:font-size]})))
|
:attributes [:font-size]})
|
||||||
|
(cto/apply-token-to-shape {:token token-letter-spacing
|
||||||
|
:shape $
|
||||||
|
:attributes [:letter-spacing]})))
|
||||||
(:objects page)
|
(:objects page)
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
|
@ -148,8 +157,9 @@
|
||||||
(t/is (= (:fill applied-tokens') "token-color"))
|
(t/is (= (:fill applied-tokens') "token-color"))
|
||||||
(t/is (= (:width applied-tokens') "token-dimensions"))
|
(t/is (= (:width applied-tokens') "token-dimensions"))
|
||||||
(t/is (= (:height applied-tokens') "token-dimensions"))
|
(t/is (= (:height applied-tokens') "token-dimensions"))
|
||||||
(t/is (= (count text1-applied-tokens) 1))
|
(t/is (= (count text1-applied-tokens) 2))
|
||||||
(t/is (= (:font-size text1-applied-tokens) "token-font-size"))))
|
(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
|
(t/deftest unapply-tokens-from-shape
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
|
@ -178,7 +188,8 @@
|
||||||
(cls/generate-update-shapes [(:id text1)]
|
(cls/generate-update-shapes [(:id text1)]
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(-> shape
|
(-> shape
|
||||||
(cto/unapply-token-id [:font-size])))
|
(cto/unapply-token-id [:font-size])
|
||||||
|
(cto/unapply-token-id [:letter-spacing])))
|
||||||
(:objects page)
|
(:objects page)
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
|
@ -228,7 +239,8 @@
|
||||||
txt/is-content-node?
|
txt/is-content-node?
|
||||||
d/txt-merge
|
d/txt-merge
|
||||||
{:fills (ths/sample-fills-color :fill-color "#fabada")
|
{:fills (ths/sample-fills-color :fill-color "#fabada")
|
||||||
:font-size "1"}))
|
:font-size "1"
|
||||||
|
:letter-spacing "0"}))
|
||||||
(:objects page)
|
(:objects page)
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
|
|
|
@ -333,10 +333,7 @@
|
||||||
|
|
||||||
(defn update-line-height
|
(defn update-line-height
|
||||||
([value shape-ids attributes] (update-line-height value shape-ids attributes nil))
|
([value shape-ids attributes] (update-line-height value shape-ids attributes nil))
|
||||||
([value shape-ids _attributes page-id] ; The attributes param is
|
([value shape-ids _attributes page-id]
|
||||||
; needed to have the same
|
|
||||||
; arity that other update
|
|
||||||
; functions
|
|
||||||
(let [update-node? (fn [node]
|
(let [update-node? (fn [node]
|
||||||
(or (txt/is-text-node? node)
|
(or (txt/is-text-node? node)
|
||||||
(txt/is-paragraph-node? node)))]
|
(txt/is-paragraph-node? node)))]
|
||||||
|
@ -346,6 +343,18 @@
|
||||||
{:ignore-touched true
|
{:ignore-touched true
|
||||||
:page-id page-id})))))
|
: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
|
(defn update-font-size
|
||||||
([value shape-ids attributes] (update-font-size value shape-ids attributes nil))
|
([value shape-ids attributes] (update-font-size value shape-ids attributes nil))
|
||||||
([value shape-ids _attributes page-id]
|
([value shape-ids _attributes page-id]
|
||||||
|
@ -391,6 +400,14 @@
|
||||||
:fields [{:label "Font Size"
|
:fields [{:label "Font Size"
|
||||||
:key :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
|
:stroke-width
|
||||||
{:title "Stroke Width"
|
{:title "Stroke Width"
|
||||||
:attributes ctt/stroke-width-keys
|
:attributes ctt/stroke-width-keys
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
ctt/opacity-keys dwta/update-opacity
|
ctt/opacity-keys dwta/update-opacity
|
||||||
#{:line-height} dwta/update-line-height
|
#{:line-height} dwta/update-line-height
|
||||||
#{:font-size} dwta/update-font-size
|
#{:font-size} dwta/update-font-size
|
||||||
|
#{:letter-spacing} dwta/update-letter-spacing
|
||||||
#{:x :y} dwta/update-shape-position
|
#{:x :y} dwta/update-shape-position
|
||||||
#{:p1 :p2 :p3 :p4} dwta/update-layout-padding
|
#{:p1 :p2 :p3 :p4} dwta/update-layout-padding
|
||||||
#{:m1 :m2 :m3 :m4} dwta/update-layout-item-margin
|
#{:m1 :m2 :m3 :m4} dwta/update-layout-item-margin
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.types.token :as ctt]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.main.data.style-dictionary :as sd]
|
[app.main.data.style-dictionary :as sd]
|
||||||
|
@ -21,6 +22,9 @@
|
||||||
(def ref:token-type-open-status
|
(def ref:token-type-open-status
|
||||||
(l/derived (l/key :open-status-by-type) refs/workspace-tokens))
|
(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
|
(defn- get-sorted-token-groups
|
||||||
"Separate token-types into groups of `empty` or `filled` depending if
|
"Separate token-types into groups of `empty` or `filled` depending if
|
||||||
tokens exist for that type. Sort each group alphabetically (by their type).
|
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)
|
token-typography-types? (contains? cf/flags :token-typography-types)
|
||||||
all-types (cond-> dwta/token-properties
|
all-types (cond-> dwta/token-properties
|
||||||
(not token-units?) (dissoc :number)
|
(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)]
|
all-types (-> all-types keys seq)]
|
||||||
(loop [empty #js []
|
(loop [empty #js []
|
||||||
filled #js []
|
filled #js []
|
||||||
|
|
|
@ -185,3 +185,9 @@
|
||||||
::mf/register-as :tokens/font-size}
|
::mf/register-as :tokens/font-size}
|
||||||
[properties]
|
[properties]
|
||||||
[:& token-update-create-modal 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])
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
:color "drop"
|
:color "drop"
|
||||||
:boolean "boolean-difference"
|
:boolean "boolean-difference"
|
||||||
:font-size "text-font-size"
|
:font-size "text-font-size"
|
||||||
|
:letter-spacing "text-letterspacing"
|
||||||
:opacity "percentage"
|
:opacity "percentage"
|
||||||
:number "number"
|
:number "number"
|
||||||
:rotation "rotation"
|
:rotation "rotation"
|
||||||
|
|
|
@ -521,6 +521,40 @@
|
||||||
(t/is (= (:line-height (:applied-tokens text-1')) (:name token-target')))
|
(t/is (= (:line-height (:applied-tokens text-1')) (:name token-target')))
|
||||||
(t/is (= (:line-height style-text-blocks) 1.5)))))))))
|
(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/deftest test-toggle-token-none
|
||||||
(t/testing "should apply token to all selected items, where no item has the token applied"
|
(t/testing "should apply token to all selected items, where no item has the token applied"
|
||||||
(t/async
|
(t/async
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue