♻️ Design review for numeric inputs (#8630)

* ♻️ Update tooltip position on icon buttons

* ♻️ Sort token groups by priority not alphabetically

* ♻️ Add proper padding on text-icon-inputs

* ♻️ Hide detach button when dropdown is open

* 🐛 Fix detach stroke width

* 🐛 Fix strokes applied on all rows

* 🐛 Fix nillable inputs

* 🐛 Fix comments on PR
This commit is contained in:
Eva Marco 2026-03-19 16:46:18 +01:00 committed by GitHub
parent b876417d5b
commit 8e7e6ffc2f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 131 additions and 200 deletions

View File

@ -522,31 +522,31 @@
(def tokens-by-input (def tokens-by-input
"A map from input name to applicable token for that input." "A map from input name to applicable token for that input."
{:width #{:sizing :dimensions} {:width [:sizing :dimensions]
:height #{:sizing :dimensions} :height [:sizing :dimensions]
:max-width #{:sizing :dimensions} :max-width [:sizing :dimensions]
:max-height #{:sizing :dimensions} :max-height [:sizing :dimensions]
:min-width #{:sizing :dimensions} :min-width [:sizing :dimensions]
:min-height #{:sizing :dimensions} :min-height [:sizing :dimensions]
:x #{:dimensions} :x [:dimensions]
:y #{:dimensions} :y [:dimensions]
:rotation #{:number :rotation} :rotation [:rotation :number]
:border-radius #{:border-radius :dimensions} :border-radius [:border-radius :dimensions]
:row-gap #{:spacing :dimensions} :row-gap [:spacing :dimensions]
:column-gap #{:spacing :dimensions} :column-gap [:spacing :dimensions]
:horizontal-padding #{:spacing :dimensions} :horizontal-padding [:spacing :dimensions]
:vertical-padding #{:spacing :dimensions} :vertical-padding [:spacing :dimensions]
:sided-paddings #{:spacing :dimensions} :sided-paddings [:spacing :dimensions]
:horizontal-margin #{:spacing :dimensions} :horizontal-margin [:spacing :dimensions]
:vertical-margin #{:spacing :dimensions} :vertical-margin [:spacing :dimensions]
:sided-margins #{:spacing :dimensions} :sided-margins [:spacing :dimensions]
:line-height #{:line-height :number} :line-height [:line-height :number]
:opacity #{:opacity} :opacity [:opacity]
:stroke-width #{:stroke-width :dimensions} :stroke-width [:stroke-width :dimensions]
:font-size #{:font-size} :font-size [:font-size]
:letter-spacing #{:letter-spacing} :letter-spacing [:letter-spacing]
:fill #{:color} :fill [:color]
:stroke-color #{:color}}) :stroke-color [:color]})
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; HELPERS for tokens application ;; HELPERS for tokens application

View File

@ -19,6 +19,7 @@
[app.main.ui.ds.controls.utilities.token-field :refer [token-field*]] [app.main.ui.ds.controls.utilities.token-field :refer [token-field*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list] :as i] [app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list] :as i]
[app.main.ui.formats :as fmt] [app.main.ui.formats :as fmt]
[app.main.ui.workspace.tokens.management.forms.controls.utils :as csu]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :refer [tr]] [app.util.i18n :refer [tr]]
[app.util.keyboard :as kbd] [app.util.keyboard :as kbd]
@ -83,48 +84,6 @@
(str/replace #"^\{" "") (str/replace #"^\{" "")
(str/replace #"\}$" ""))) (str/replace #"\}$" "")))
(defn- token->dropdown-option
[token]
{:id (str (get token :id))
:type :token
:resolved-value (get token :resolved-value)
:name (get token :name)})
(defn- generate-dropdown-options
[tokens no-sets]
(if (empty? tokens)
[{:type :empty
:label (if no-sets
(tr "ds.inputs.numeric-input.no-applicable-tokens")
(tr "ds.inputs.numeric-input.no-matches"))}]
(->> tokens
(map (fn [[type items]]
(cons {:group true
:type :group
:id (dm/str "group-" (name type))
:name (name type)}
(map token->dropdown-option items))))
(interpose [{:separator true
:id "separator"
:type :separator}])
(apply concat)
(vec)
(not-empty))))
(defn- extract-partial-brace-text
[s]
(when-let [start (str/last-index-of s "{")]
(subs s (inc start))))
(defn- filter-token-groups-by-name
[tokens filter-text]
(let [lc-filter (str/lower filter-text)]
(into {}
(keep (fn [[group tokens]]
(let [filtered (filter #(str/includes? (str/lower (:name %)) lc-filter) tokens)]
(when (seq filtered)
[group filtered]))))
tokens)))
(defn- focusable-option? (defn- focusable-option?
[option] [option]
@ -149,31 +108,6 @@
j))) j)))
indices))) indices)))
(defn- sort-groups-and-tokens
"Sorts both the groups and the tokens inside them alphabetically.
Input:
A map where:
- keys are groups (keywords or strings, e.g. :dimensions, :colors)
- values are vectors of token maps, each containing at least a :name key
Example input:
{:dimensions [{:name \"tres\"} {:name \"quini\"}]
:colors [{:name \"azul\"} {:name \"rojo\"}]}
Output:
A sorted map where:
- groups are ordered alphabetically by key
- tokens inside each group are sorted alphabetically by :name
Example output:
{:colors [{:name \"azul\"} {:name \"rojo\"}]
:dimensions [{:name \"quini\"} {:name \"tres\"}]}"
[groups->tokens]
(into (sorted-map) ;; ensure groups are ordered alphabetically by their key
(for [[group tokens] groups->tokens]
[group (sort-by :name tokens)])))
(def ^:private schema:icon (def ^:private schema:icon
[:and :string [:fn #(contains? icon-list %)]]) [:and :string [:fn #(contains? icon-list %)]])
@ -288,16 +222,7 @@
dropdown-options dropdown-options
(mf/with-memo [tokens filter-id] (mf/with-memo [tokens filter-id]
(delay (csu/get-token-dropdown-options tokens filter-id))
(let [tokens (if (delay? tokens) @tokens tokens)
sorted-tokens (sort-groups-and-tokens tokens)
partial (extract-partial-brace-text filter-id)
options (if (seq partial)
(filter-token-groups-by-name sorted-tokens partial)
sorted-tokens)
no-sets? (nil? sorted-tokens)]
(generate-dropdown-options options no-sets?))))
selected-id* selected-id*
(mf/use-state (fn [] (mf/use-state (fn []
@ -649,6 +574,7 @@
:icon i/tokens :icon i/tokens
:tooltip-class (stl/css :button-tooltip) :tooltip-class (stl/css :button-tooltip)
:class (stl/css :invisible-button) :class (stl/css :invisible-button)
:tooltip-placement "top-left"
:aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown") :aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown")
:ref open-dropdown-ref :ref open-dropdown-ref
:on-click open-dropdown}]))) :on-click open-dropdown}])))
@ -676,6 +602,7 @@
:on-blur on-blur :on-blur on-blur
:class inner-class :class inner-class
:property property :property property
:is-open is-open
:slot-start (when (or icon text-icon) :slot-start (when (or icon text-icon)
(mf/html (mf/html
(cond (cond
@ -714,6 +641,11 @@
(when-let [node (mf/ref-val ref)] (when-let [node (mf/ref-val ref)]
(dom/set-value! node value')))) (dom/set-value! node value'))))
(mf/with-effect [applied-token]
(when (nil? applied-token)
(reset! token-applied* nil)
(reset! selected-id* nil)))
(mf/with-layout-effect [on-mouse-wheel] (mf/with-layout-effect [on-mouse-wheel]
(when-let [node (mf/ref-val ref)] (when-let [node (mf/ref-val ref)]
(let [key (events/listen node "wheel" on-mouse-wheel #js {:passive false})] (let [key (events/listen node "wheel" on-mouse-wheel #js {:passive false})]

View File

@ -35,9 +35,10 @@
.text-icon { .text-icon {
color: var(--color-foreground-secondary); color: var(--color-foreground-secondary);
@include t.use-typography("code-font"); @include t.use-typography("body-small");
inline-size: fit-content; inline-size: fit-content;
min-inline-size: px2rem(40); min-inline-size: px2rem(46);
padding-inline-start: var(--sp-xs);
} }
.invisible-button { .invisible-button {

View File

@ -25,6 +25,7 @@
[:property {:optional true} [:maybe :string]] [:property {:optional true} [:maybe :string]]
[:value :any] [:value :any]
[:disabled {:optional true} :boolean] [:disabled {:optional true} :boolean]
[:is-open {:optional true} :boolean]
[:slot-start {:optional true} [:maybe some?]] [:slot-start {:optional true} [:maybe some?]]
[:on-click {:optional true} fn?] [:on-click {:optional true} fn?]
[:on-token-key-down fn?] [:on-token-key-down fn?]
@ -36,7 +37,7 @@
{::mf/schema schema:token-field} {::mf/schema schema:token-field}
[{:keys [id label value slot-start disabled class [{:keys [id label value slot-start disabled class
on-click on-token-key-down on-blur detach-token on-click on-token-key-down on-blur detach-token
token-wrapper-ref token-detach-btn-ref on-focus property]}] token-wrapper-ref token-detach-btn-ref on-focus property is-open]}]
(let [set-active? (some? id) (let [set-active? (some? id)
content (if set-active? content (if set-active?
label label
@ -88,9 +89,11 @@
(when-not ^boolean disabled (when-not ^boolean disabled
[:> icon-button* {:variant "ghost" [:> icon-button* {:variant "ghost"
:class (stl/css :invisible-button) :class (stl/css-case :invisible-button true
:invisible-btn-dropdown-open is-open)
:tooltip-class (stl/css :button-tooltip) :tooltip-class (stl/css :button-tooltip)
:icon i/broken-link :icon i/broken-link
:ref token-detach-btn-ref :ref token-detach-btn-ref
:tooltip-placement "top-left"
:aria-label (tr "ds.inputs.token-field.detach-token") :aria-label (tr "ds.inputs.token-field.detach-token")
:on-click detach-token}])]])) :on-click detach-token}])]]))

View File

@ -136,6 +136,9 @@
--opacity-button: 1; --opacity-button: 1;
} }
} }
.invisible-btn-dropdown-open {
--opacity-button: 0;
}
.content-wrapper { .content-wrapper {
inline-size: 100%; inline-size: 100%;

View File

@ -172,7 +172,7 @@
(deref placement*) (deref placement*)
delay delay
(d/nilv delay 300) (d/nilv delay 700)
schedule-ref schedule-ref
(mf/use-ref nil) (mf/use-ref nil)
@ -188,7 +188,7 @@
(when-not (.-hidden js/document) (when-not (.-hidden js/document)
(let [trigger-el (mf/ref-val trigger-ref)] (let [trigger-el (mf/ref-val trigger-ref)]
(clear-schedule schedule-ref) (clear-schedule schedule-ref)
(add-schedule schedule-ref (d/nilv delay 300) (add-schedule schedule-ref delay
(fn [] (fn []
(when-let [active @active-tooltip] (when-let [active @active-tooltip]
(when (not= (:id active) tooltip-id) (when (not= (:id active) tooltip-id)

View File

@ -7,6 +7,8 @@
(ns app.main.ui.workspace.sidebar.options.common (ns app.main.ui.workspace.sidebar.options.common
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.main.data.workspace.tokens.application :as dwta]
[app.main.store :as st]
[app.util.dom :as dom] [app.util.dom :as dom]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -24,3 +26,17 @@
:ref ref} :ref ref}
children]))) children])))
(defn emit-value-or-token [value emit-value-fn ids attrs]
(cond
(nil? value)
(emit-value-fn nil)
(or (string? value) (number? value))
(emit-value-fn value)
:else
(st/emit!
(dwta/toggle-token {:token (first value)
:attrs attrs
:shape-ids ids}))))

View File

@ -11,6 +11,7 @@
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.hooks :as hooks] [app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.common :as soc]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]] [app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
@ -130,26 +131,21 @@
(mf/use-fn (mf/use-fn
(mf/deps change-radius ids) (mf/deps change-radius ids)
(fn [value] (fn [value]
(if (or (string? value) (number? value)) (soc/emit-value-or-token
(st/emit! value
(change-radius (fn [shape] #(st/emit! (change-radius (fn [shape] (ctsr/set-radius-to-all-corners shape %))))
(ctsr/set-radius-to-all-corners shape value)))) ids
(st/emit! #{:r1 :r2 :r3 :r4})))
(dwta/toggle-token {:token (first value)
:attrs #{:r1 :r2 :r3 :r4}
:shape-ids ids})))))
on-single-radius-change on-single-radius-change
(mf/use-fn (mf/use-fn
(mf/deps change-one-radius ids) (mf/deps change-one-radius ids)
(fn [value attr] (fn [value attr]
(if (or (string? value) (number? value)) (soc/emit-value-or-token
(st/emit! (change-one-radius #(ctsr/set-radius-to-single-corner % attr value) attr)) value
(st/emit! (st/emit! #(st/emit! (change-one-radius (fn [shape] (ctsr/set-radius-to-single-corner shape attr %)) attr))
(dwta/toggle-token {:token (first value) ids
:attrs #{attr} #{attr})))
:shape-ids ids}))))))
on-radius-r1-change #(on-single-radius-change % :r1) on-radius-r1-change #(on-single-radius-change % :r1)
on-radius-r2-change #(on-single-radius-change % :r2) on-radius-r2-change #(on-single-radius-change % :r2)

View File

@ -1,9 +1,9 @@
(ns app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens (ns app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.types.token :as tk]
[app.main.ui.context :as muc] [app.main.ui.context :as muc]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]] [app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.main.ui.workspace.tokens.management.forms.controls.utils :as csu]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -11,11 +11,8 @@
[{:keys [value attr applied-token align on-detach placeholder input-type class] :rest props}] [{:keys [value attr applied-token align on-detach placeholder input-type class] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type) (let [tokens (mf/use-ctx muc/active-tokens-by-type)
tokens (mf/with-memo [tokens input-type] tokens (mf/with-memo [tokens input-type attr]
(delay (csu/filter-tokens-for-input tokens (or input-type attr)))
(-> (deref tokens)
(select-keys (get tk/tokens-by-input (or input-type attr)))
(not-empty))))
on-detach-attr on-detach-attr
(mf/use-fn (mf/use-fn

View File

@ -30,6 +30,7 @@
[app.main.ui.formats :as fmt] [app.main.ui.formats :as fmt]
[app.main.ui.hooks :as h] [app.main.ui.hooks :as h]
[app.main.ui.icons :as deprecated-icon] [app.main.ui.icons :as deprecated-icon]
[app.main.ui.workspace.sidebar.options.common :as soc]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]] [app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
@ -335,15 +336,8 @@
(mf/use-fn (mf/use-fn
(mf/deps on-change ids) (mf/deps on-change ids)
(fn [value attr event] (fn [value attr event]
(if (or (string? value) (number? value)) (let [on-change-fn #(on-change :simple attr % event)]
(on-change :simple attr value event) (soc/emit-value-or-token value on-change-fn ids #{attr}))))
(do
(st/emit!
(dwta/toggle-token {:token (first value)
:attrs (if (= :p1 attr)
#{:p1 :p3}
#{:p2 :p4})
:shape-ids ids}))))))
on-detach-token on-detach-token
(mf/use-fn (mf/use-fn
@ -719,15 +713,8 @@
(mf/use-fn (mf/use-fn
(mf/deps on-change wrap-type ids) (mf/deps on-change wrap-type ids)
(fn [value event attr] (fn [value event attr]
(if (or (string? value) (number? value)) (let [on-change-fn #((on-change (= "nowrap" wrap-type) attr % event))]
(on-change (= "nowrap" wrap-type) attr value event) (soc/emit-value-or-token value on-change-fn ids #{attr}))))
(do
(st/emit!
(dwta/toggle-token {:token (first value)
:attrs (if (= "nowrap" wrap-type)
#{:row-gap :colum-gap}
#{attr})
:shape-ids ids}))))))
on-detach-token on-detach-token
(mf/use-fn (mf/use-fn

View File

@ -21,6 +21,7 @@
[app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.components.title-bar :refer [title-bar*]]
[app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.icons :as deprecated-icon] [app.main.ui.icons :as deprecated-icon]
[app.main.ui.workspace.sidebar.options.common :as soc]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]] [app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon]] [app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon]]
[app.util.dom :as dom] [app.util.dom :as dom]
@ -117,15 +118,11 @@
(mf/use-fn (mf/use-fn
(mf/deps on-change ids) (mf/deps on-change ids)
(fn [value attr] (fn [value attr]
(if (or (string? value) (number? value)) (soc/emit-value-or-token
(on-change :simple attr value) value
(do #(on-change :simple attr %)
(st/emit! ids
(dwta/toggle-token {:token (first value) (if (= :m1 attr) #{:m1 :m3} #{:m2 :m4}))))
:attrs (if (= :m1 attr)
#{:m1 :m3}
#{:m2 :m4})
:shape-ids ids}))))))
on-focus-m1 on-focus-m1
(mf/use-fn (mf/deps on-focus) #(on-focus :m1)) (mf/use-fn (mf/deps on-focus) #(on-focus :m1))
@ -247,14 +244,11 @@
(mf/use-fn (mf/use-fn
(mf/deps on-change ids) (mf/deps on-change ids)
(fn [value attr] (fn [value attr]
(if (or (string? value) (number? value)) (soc/emit-value-or-token
(on-change :multiple attr value) value
(do #(on-change :multiple attr %)
(st/emit! ids
(dwta/toggle-token {:token (first value) #{attr})))
:attrs #{attr}
:shape-ids ids}))))))
on-m1-change on-m1-change
(mf/use-fn (mf/deps on-change') #(on-change' % :m1)) (mf/use-fn (mf/deps on-change') #(on-change' % :m1))
@ -577,13 +571,11 @@
(mf/use-fn (mf/use-fn
(mf/deps ids) (mf/deps ids)
(fn [value attr] (fn [value attr]
(if (or (string? value) (number? value)) (soc/emit-value-or-token
(st/emit! (dwsl/update-layout-child ids {attr value})) value
(do #(st/emit! (dwsl/update-layout-child ids {attr %}))
(st/emit! ids
(dwta/toggle-token {:token (first value) #{attr})))
:attrs #{attr}
:shape-ids ids}))))))
on-layout-item-min-w-change on-layout-item-min-w-change
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :layout-item-min-w)) (mf/use-fn (mf/deps on-size-change) #(on-size-change % :layout-item-min-w))

View File

@ -168,6 +168,7 @@
on-blur (fn [_] on-blur (fn [_]
(reset! disable-drag false)) (reset! disable-drag false))
on-detach-token on-detach-token
(mf/use-fn (mf/use-fn
(mf/deps ids) (mf/deps ids)
@ -205,7 +206,7 @@
(seq strokes) (seq strokes)
[:> h/sortable-container* {} [:> h/sortable-container* {}
(for [[index value] (d/enumerate (:strokes values []))] (for [[index value] (d/enumerate (:strokes values []))]
[:> stroke-row* {:key (dm/str "stroke-" index) [:> stroke-row* {:key (dm/str "stroke-" index "-" (hash applied-tokens))
:stroke value :stroke value
:title (tr "workspace.options.stroke-color") :title (tr "workspace.options.stroke-color")
:index index :index index
@ -222,7 +223,7 @@
:on-stroke-cap-start-change on-stroke-cap-start-change :on-stroke-cap-start-change on-stroke-cap-start-change
:on-stroke-cap-end-change on-stroke-cap-end-change :on-stroke-cap-end-change on-stroke-cap-end-change
:on-stroke-cap-switch on-stroke-cap-switch :on-stroke-cap-switch on-stroke-cap-switch
:applied-tokens applied-tokens :applied-tokens (when (= 0 index) applied-tokens)
:on-detach-token on-detach-token :on-detach-token on-detach-token
:on-remove on-remove :on-remove on-remove
:on-reorder handle-reorder :on-reorder handle-reorder

View File

@ -11,7 +11,6 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.types.color :as clr] [app.common.types.color :as clr]
[app.common.types.shape.attrs :refer [default-color]] [app.common.types.shape.attrs :refer [default-color]]
[app.common.types.token :as tk]
[app.config :as cfg] [app.config :as cfg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.workspace.colors :as dwc] [app.main.data.workspace.colors :as dwc]
@ -27,6 +26,7 @@
[app.main.ui.ds.utilities.swatch :refer [swatch*]] [app.main.ui.ds.utilities.swatch :refer [swatch*]]
[app.main.ui.formats :as fmt] [app.main.ui.formats :as fmt]
[app.main.ui.hooks :as h] [app.main.ui.hooks :as h]
[app.main.ui.workspace.tokens.management.forms.controls.utils :as csu]
[app.util.color :as uc] [app.util.color :as uc]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
@ -176,12 +176,9 @@
active-tokens* (mf/use-ctx ctx/active-tokens-by-type) active-tokens* (mf/use-ctx ctx/active-tokens-by-type)
tokens (mf/with-memo [active-tokens* origin] tokens (mf/with-memo [active-tokens* origin]
(let [origin (if (= :color-selection origin) :fill origin)] (csu/filter-tokens-for-input active-tokens* origin))
(delay
(-> (deref active-tokens*)
(select-keys (get tk/tokens-by-input origin))
(not-empty)))))
on-focus' on-focus'
(mf/use-fn (mf/use-fn
(mf/deps on-focus) (mf/deps on-focus)

View File

@ -18,6 +18,7 @@
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.hooks :as h] [app.main.ui.hooks :as h]
[app.main.ui.workspace.sidebar.options.common :as soc]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]] [app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
@ -92,14 +93,13 @@
on-width-change on-width-change
(mf/use-fn (mf/use-fn
(mf/deps index on-stroke-width-change) (mf/deps index on-stroke-width-change ids)
(fn [value] (fn [value]
(if (or (string? value) (number? value)) (soc/emit-value-or-token
(on-stroke-width-change index value) value
#(on-stroke-width-change index %)
(st/emit! (dwta/toggle-token {:token (first value) ids
:attrs #{:stroke-width} #{:stroke-width})))
:shape-ids ids})))))
stroke-alignment (or (:stroke-alignment stroke) :center) stroke-alignment (or (:stroke-alignment stroke) :center)
@ -164,7 +164,7 @@
(mf/use-fn (mf/use-fn
(mf/deps on-detach-token) (mf/deps on-detach-token)
(fn [token] (fn [token]
(on-detach-token (first token) #{:stroke-width}))) (on-detach-token token #{:stroke-width})))
stroke-caps-options stroke-caps-options
[{:value nil :label (tr "workspace.options.stroke-cap.none")} [{:value nil :label (tr "workspace.options.stroke-cap.none")}

View File

@ -9,7 +9,7 @@
[token] [token]
{:id (str (get token :id)) {:id (str (get token :id))
:type :token :type :token
:resolved-value (get token :value) :resolved-value (get token :resolved-value)
:name (get token :name)}) :name (get token :name)})
(defn- generate-dropdown-options (defn- generate-dropdown-options
@ -53,7 +53,7 @@
tokens))) tokens)))
(defn- sort-groups-and-tokens (defn- sort-groups-and-tokens
"Sorts both the groups and the tokens inside them alphabetically. "Sorts the tokens inside the groups alphabetically.
Input: Input:
A map where: A map where:
@ -65,18 +65,18 @@
:colors [{:name \"azul\"} {:name \"rojo\"}]} :colors [{:name \"azul\"} {:name \"rojo\"}]}
Output: Output:
A sorted map where: A map which:
- groups are ordered alphabetically by key
- tokens inside each group are sorted alphabetically by :name - tokens inside each group are sorted alphabetically by :name
Example output: Example output:
{:colors [{:name \"azul\"} {:name \"rojo\"}] {:dimensions [{:name \"quini\"} {:name \"tres\"}]
:dimensions [{:name \"quini\"} {:name \"tres\"}]}" :colors [{:name \"azul\"} {:name \"rojo\"}]}"
[groups->tokens] [groups->tokens]
(into (sorted-map) ;; ensure groups are ordered alphabetically by their key (reduce (fn [acc [group tokens]]
(for [[group tokens] groups->tokens] (assoc acc group (sort-by :name tokens)))
[group (sort-by :name tokens)]))) {}
groups->tokens))
(defn get-token-dropdown-options (defn get-token-dropdown-options
[tokens filter-term] [tokens filter-term]
@ -94,9 +94,15 @@
(defn filter-tokens-for-input (defn filter-tokens-for-input
[raw-tokens input-type] [raw-tokens input-type]
(delay (delay
(-> (deref raw-tokens) (let [raw-tokens (deref raw-tokens)
(select-keys (get cto/tokens-by-input input-type)) key-order (get cto/tokens-by-input input-type)]
(not-empty)))) (-> (reduce (fn [acc k]
(if (contains? raw-tokens k)
(assoc acc k (get raw-tokens k))
acc))
(array-map)
key-order)
(not-empty)))))
(defn focusable-options [options] (defn focusable-options [options]
(filter #(= (:type %) :token) options)) (filter #(= (:type %) :token) options))