diff --git a/frontend/src/app/main/data/tokens.cljs b/frontend/src/app/main/data/tokens.cljs index 5f6c71e1e3..e0b827518f 100644 --- a/frontend/src/app/main/data/tokens.cljs +++ b/frontend/src/app/main/data/tokens.cljs @@ -6,6 +6,7 @@ (ns app.main.data.tokens (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] [app.common.geom.point :as gpt] @@ -57,6 +58,9 @@ (->> (map (fn [attr] [attr token-id]) 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)] (toggle-or-apply-token shape token))) 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 1b862b22d6..4a26f0f392 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 @@ -291,6 +291,16 @@ (on-switch-to-radius-4) (on-switch-to-radius-1)))) + on-border-radius-token-unapply + (mf/use-fn + (mf/deps ids change-radius border-radius-tokens) + (fn [token] + (let [token-value (some-> token wtc/resolve-token-value)] + (st/emit! + (change-radius (fn [shape] + (-> (dt/unapply-token-id shape (wtc/token-attributes :border-radius)) + (ctsr/set-radius-1 token-value)))))))) + on-radius-1-change (mf/use-fn (mf/deps ids change-radius border-radius-tokens) @@ -488,6 +498,7 @@ [:span {:class (stl/css :icon)} i/corner-radius] [:& editable-select {:placeholder (if (= :multiple (:rx values)) (tr "settings.multiple") "--") + :on-token-remove on-border-radius-token-unapply :class (stl/css :token-select) :type "number" :min 0 diff --git a/frontend/src/app/main/ui/workspace/tokens/core.cljs b/frontend/src/app/main/ui/workspace/tokens/core.cljs index 7865368931..9f0405a628 100644 --- a/frontend/src/app/main/ui/workspace/tokens/core.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/core.cljs @@ -13,7 +13,6 @@ [app.main.data.workspace :as udw] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.shape-layout :as dwsl] - [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.transforms :as dwt] [app.main.store :as st])) diff --git a/frontend/src/app/main/ui/workspace/tokens/editable_select.cljs b/frontend/src/app/main/ui/workspace/tokens/editable_select.cljs index 65264f7031..afbd5a2eeb 100644 --- a/frontend/src/app/main/ui/workspace/tokens/editable_select.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/editable_select.cljs @@ -17,6 +17,7 @@ [app.util.dom :as dom] [app.util.keyboard :as kbd] [app.util.timers :as timers] + [cuerdas.core :as str] [rumext.v2 :as mf])) (defn on-number-input-key-down [{:keys [event min-val max-val set-value!]}] @@ -59,22 +60,28 @@ [:span {:class (stl/css :check-icon)} i/tick]])))]]]) (mf/defc editable-select - [{:keys [value type options class on-change placeholder on-blur input-class] :as params}] + [{:keys [value type options class on-change placeholder on-blur input-class on-token-remove] :as params}] (let [state* (mf/use-state {:id (uuid/next) :is-open? false :current-value value + :token-value nil :current-item nil :top nil :left nil :bottom nil}) state (deref state*) is-open? (:is-open? state) + refocus? (:refocus? state) current-value (:current-value state) element-id (:id state) min-val (get params :min) max-val (get params :max) + multiple? (= :multiple value) + token (when-not multiple? + (-> (filter :selected? options) (first))) + emit-blur? (mf/use-ref nil) select-wrapper-ref (mf/use-ref) @@ -93,9 +100,15 @@ options) (into {})) + set-token-value! + (fn [value] + (swap! state* assoc :token-value value)) + set-value (fn [value] - (swap! state* assoc :current-value value) + (swap! state* assoc + :current-value value + :token-value value) (when on-change (on-change value))) select-item @@ -109,6 +122,7 @@ {:keys [value] :as item} (get labels-map label)] (swap! state* assoc :current-value value + :token-value nil :current-item item) (when on-change (on-change item)) (when on-blur (on-blur))))) @@ -119,32 +133,33 @@ value (or (d/parse-double value) value)] (set-value value))) - on-node-load - (fn [node] - ;; There is a problem when changing the state in this callback that - ;; produces the dropdown to close in the same event - (when node - (timers/schedule - #(when-let [bounds (when node (dom/get-bounding-rect node))] - (let [{window-height :height} (dom/get-window-size) - {:keys [left top height]} bounds - bottom (when (< (- window-height top) 300) (- window-height top)) - top (when (>= (- window-height top) 300) (+ top height))] - (swap! state* - assoc - :left left - :top top - :bottom bottom)))))) - handle-key-down (mf/use-fn - (mf/deps set-value is-open?) - (fn [event] + (mf/deps set-value is-open? token) + (fn [^js event] (cond + token (let [backspace? (kbd/backspace? event) + enter? (kbd/enter? event) + value (-> event dom/get-target dom/get-value) + caret-at-beginning? (nil? (.. event -target -selectionStart)) + no-text-selected? (str/empty? (.toString (js/document.getSelection))) + delete-token? (and backspace? caret-at-beginning? no-text-selected?) + replace-token-with-value? (and enter? (seq (str/trim value)))] + (cond + delete-token? (do + (dom/prevent-default event) + (on-token-remove token) + ;; Re-focus the input value of the newly rendered input element + (swap! state* assoc :refocus? true)) + replace-token-with-value? (do + (dom/prevent-default event) + (on-token-remove token) + (handle-change-input event) + (set-token-value! nil)) + :else (set-token-value! value))) is-open? (let [up? (kbd/up-arrow? event) down? (kbd/down-arrow? event)] - (dom/prevent-default event) - (js/console.log "up? down?" up? down?)) + (dom/prevent-default event)) (= type "number") (on-number-input-key-down {:event event :min-val min-val :max-val max-val @@ -152,13 +167,17 @@ handle-focus (mf/use-fn + (mf/deps refocus?) (fn [] + (when refocus? + (swap! state* dissoc :refocus?)) (mf/set-ref-val! emit-blur? false))) handle-blur (mf/use-fn (fn [] (mf/set-ref-val! emit-blur? true) + (swap! state* assoc :token-value nil) (timers/schedule 200 (fn [] @@ -167,7 +186,7 @@ (mf/use-effect (mf/deps value current-value) #(when (not= (str value) current-value) - (reset! state* {:current-value value}))) + (swap! state* assoc :current-value value))) (mf/with-effect [is-open?] (let [wrapper-node (mf/ref-val select-wrapper-ref) @@ -185,23 +204,34 @@ (mf/set-ref-val! emit-blur? (not is-open?))) - [:div {:class (dm/str class " " (stl/css :editable-select)) - :ref on-node-load} - (if (= type "number") - [:> numeric-input* {:value (or current-value "") - :className input-class - :on-change set-value - :on-focus handle-focus - :on-blur handle-blur - :placeholder placeholder}] - [:input {:value (or current-value "") - :class input-class - :on-change handle-change-input - :on-key-down handle-key-down - :on-focus handle-focus - :on-blur handle-blur - :placeholder placeholder - :type type}]) + [:div {:class (dm/str class " " (stl/css :editable-select))} + (when-let [{:keys [label value]} token] + [:div {:title (str label ": " value) + :class (stl/css :token-pill)} + value]) + (cond + token [:input {:value (or (:token-value state) "") + :class input-class + :on-change handle-change-input + :on-key-down handle-key-down + :on-focus handle-focus + :on-blur handle-blur + :type type}] + (= type "number") [:> numeric-input* {:autoFocus refocus? + :value (or current-value "") + :className input-class + :on-change set-value + :on-focus handle-focus + :on-blur handle-blur + :placeholder placeholder}] + :else [:input {:value (or current-value "") + :class input-class + :on-change handle-change-input + :on-key-down handle-key-down + :on-focus handle-focus + :on-blur handle-blur + :placeholder placeholder + :type type}]) (when (seq options) [:span {:class (stl/css :dropdown-button) diff --git a/frontend/src/app/main/ui/workspace/tokens/editable_select.scss b/frontend/src/app/main/ui/workspace/tokens/editable_select.scss index bfc2a0c9ef..7bb4e7f4ef 100644 --- a/frontend/src/app/main/ui/workspace/tokens/editable_select.scss +++ b/frontend/src/app/main/ui/workspace/tokens/editable_select.scss @@ -17,6 +17,17 @@ border-radius: $br-8; cursor: pointer; + background: transparent; + &:hover { + background: transparent; + } + &:focus-within { + .token-pill { + background-color: var(--button-primary-background-color-rest); + color: var(--button-primary-foreground-color-rest); + } + } + .dropdown-button { @include flexCenter; margin-right: -$s-8; @@ -38,6 +49,19 @@ margin-bottom: 0; } + .token-pill { + background-color: rgb(94 107 120 / 25%); + border-radius: $br-4; + padding: $s-2 $s-6; + text-overflow: ellipsis; + flex: 0 0 auto; + } + + .token-pill + input { + flex: 1 1 auto; + width: 0; + } + .custom-select-dropdown { @extend .dropdown-wrapper; max-height: $s-320;