From fe3a2902bb914aecff2d1971e1807705e08e9218 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Mon, 20 Jan 2025 15:44:36 +0100 Subject: [PATCH] :sparkles Add combobox to select group in token themes modal --- .../src/app/main/ui/ds/controls/combobox.cljs | 16 +- .../ds/controls/shared/options_dropdown.scss | 2 +- .../app/main/ui/workspace/tokens/common.cljs | 61 ---- .../app/main/ui/workspace/tokens/common.scss | 102 ------ .../ui/workspace/tokens/editable_select.cljs | 301 ------------------ .../ui/workspace/tokens/editable_select.scss | 155 --------- .../app/main/ui/workspace/tokens/form.scss | 6 - .../ui/workspace/tokens/modals/themes.cljs | 70 ++-- .../ui/workspace/tokens/modals/themes.scss | 30 +- .../app/main/ui/workspace/tokens/sidebar.scss | 1 - .../main/ui/workspace/tokens/token_pill.scss | 1 - frontend/translations/en.po | 6 + frontend/translations/es.po | 6 + 13 files changed, 64 insertions(+), 693 deletions(-) delete mode 100644 frontend/src/app/main/ui/workspace/tokens/common.scss delete mode 100644 frontend/src/app/main/ui/workspace/tokens/editable_select.cljs delete mode 100644 frontend/src/app/main/ui/workspace/tokens/editable_select.scss diff --git a/frontend/src/app/main/ui/ds/controls/combobox.cljs b/frontend/src/app/main/ui/ds/controls/combobox.cljs index 737dcb81e..b4f5b69da 100644 --- a/frontend/src/app/main/ui/ds/controls/combobox.cljs +++ b/frontend/src/app/main/ui/ds/controls/combobox.cljs @@ -56,7 +56,8 @@ (def ^:private schema:combobox [:map - [:options [:vector {:min 1} schema:combobox-option]] + [:id {:optional true} :string] + [:options [:vector schema:combobox-option]] [:class {:optional true} :string] [:disabled {:optional true} :boolean] [:default-selected {:optional true} :string] @@ -66,7 +67,7 @@ (mf/defc combobox* {::mf/props :obj ::mf/schema schema:combobox} - [{:keys [options class disabled has-error default-selected on-change] :rest props}] + [{:keys [id options class disabled has-error default-selected on-change] :rest props}] (let [open* (mf/use-state false) open (deref open*) @@ -177,7 +178,7 @@ (mod (+ index 1) len))] (handle-focus-change options focused* new-index options-nodes-refs)) - (or (kbd/space? event) (kbd/enter? event)) + (kbd/enter? event) (when (deref open*) (dom/prevent-default event) (handle-selection focused* selected* open*) @@ -191,7 +192,7 @@ on-input-change (mf/use-fn (fn [event] - (let [value (.-value (.-currentTarget event))] + (let [value (-> event dom/get-target dom/get-value)] (reset! selected* value) (reset! filter-value* value) (reset! focused* nil) @@ -226,8 +227,10 @@ [:> icon* {:icon-id icon :size "s" :aria-hidden true}]) - [:input {:type "text" + [:input {:id id + :type "text" :role "combobox" + :autoComplete "off" :aria-autocomplete "both" :aria-expanded open :aria-controls listbox-id @@ -239,7 +242,8 @@ :on-change on-input-change :on-key-down on-key-down}]] - [:> :button {:tab-index "-1" + [:> :button {:type "button" + :tab-index "-1" :aria-expanded open :aria-controls listbox-id :class (stl/css :button-toggle-list) diff --git a/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.scss b/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.scss index bdaf95f66..7ca4d5b36 100644 --- a/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.scss +++ b/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.scss @@ -20,7 +20,7 @@ width: 100%; background-color: var(--options-dropdown-bg-color); border-radius: $br-8; - border: $b-1 solid var(--options-dropdown-dropdown-border-color); + border: $b-1 solid var(--options-dropdown-border-color); padding-block: var(--sp-xs); margin-block-end: 0; max-height: $sz-400; diff --git a/frontend/src/app/main/ui/workspace/tokens/common.cljs b/frontend/src/app/main/ui/workspace/tokens/common.cljs index e81c93999..a3b5cc8bc 100644 --- a/frontend/src/app/main/ui/workspace/tokens/common.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/common.cljs @@ -5,14 +5,10 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.tokens.common - (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] - [app.common.data.macros :as dm] [app.main.data.shortcuts :as dsc] [app.main.store :as st] - [app.main.ui.components.dropdown :refer [dropdown]] - [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.globals :as globals] [app.util.keyboard :as kbd] @@ -72,60 +68,3 @@ (st/emit! (dsc/pop-shortcuts shortcuts-key))))) {:highlighted highlighted :on-dehighlight on-dehighlight})) - -(defn use-dropdown-open-state [] - (let [open? (mf/use-state false) - on-open (mf/use-fn #(reset! open? true)) - on-close (mf/use-fn #(reset! open? false)) - on-toggle (mf/use-fn #(swap! open? not))] - {:dropdown-open? @open? - :on-open-dropdown on-open - :on-close-dropdown on-close - :on-toggle-dropdown on-toggle})) - -;; Components ------------------------------------------------------------------ - -(mf/defc dropdown-select - [{:keys [id _shortcuts-key options on-close element-ref on-select] :as props}] - (let [{:keys [highlighted on-dehighlight]} (use-arrow-highlight props)] - [:& dropdown {:show true - :on-close on-close} - [:> :div {:class (stl/css :dropdown) - :on-mouse-enter on-dehighlight - :ref element-ref} - [:ul {:class (stl/css :dropdown-list)} - (for [[index item] (d/enumerate options)] - (cond - (= :separator item) - [:li {:class (stl/css :separator) - :key (dm/str id "-" index)}] - :else - (let [{:keys [label selected? disabled?]} item - highlighted? (= highlighted index)] - [:li - {:key (str id "-" index) - :class (stl/css-case :dropdown-element true - :is-selected selected? - :is-highlighted highlighted?) - :data-label label - :disabled disabled? - :on-click #(on-select item)} - [:span {:class (stl/css :label)} label] - [:span {:class (stl/css :check-icon)} i/tick]])))]]])) - -(mf/defc labeled-input - {::mf/wrap-props false} - [{:keys [label input-props auto-complete? error? render-right]}] - (let [input-props (cond-> input-props - :always camel-keys - ;; Disable auto-complete on form fields for proprietary password managers - ;; https://github.com/orgs/tokens-studio/projects/69/views/11?pane=issue&itemId=63724204 - (not auto-complete?) (assoc "data-1p-ignore" true - "data-lpignore" true - :auto-complete "off"))] - [:label {:class (stl/css-case :labeled-input true - :labeled-input-error error?)} - [:span {:class (stl/css :label)} label] - [:& :input input-props] - (when render-right - [:& render-right])])) diff --git a/frontend/src/app/main/ui/workspace/tokens/common.scss b/frontend/src/app/main/ui/workspace/tokens/common.scss deleted file mode 100644 index 34801d65c..000000000 --- a/frontend/src/app/main/ui/workspace/tokens/common.scss +++ /dev/null @@ -1,102 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. -// -// Copyright (c) KALEIDOS INC - -@import "refactor/common-refactor.scss"; - -.input { - @extend .input-element; -} - -.labeled-input { - @extend .input-element; - .label { - width: auto; - text-wrap: nowrap; - } -} - -.labeled-input-error { - border: $s-1 solid var(--status-color-error-500) !important; -} - -.dropdown { - @extend .dropdown-wrapper; - max-height: $s-320; - width: 100%; - margin-top: $s-4; - - ul { - margin: 0; - } - - .separator { - margin: 0; - height: $s-12; - } - - .dropdown-element { - @extend .dropdown-element-base; - color: var(--menu-foreground-color-rest); - display: flex; - - & > span { - display: flex; - justify-content: flex-start; - align-content: center; - } - - .label, - .value { - width: fit-content; - } - - .label { - text-transform: unset; - flex: 1; - } - - .value { - text-align: right; - justify-content: flex-end; - flex: 0.6; - } - - .check-icon { - @include flexCenter; - translate: -$s-4 0; - svg { - @extend .button-icon-small; - visibility: hidden; - stroke: var(--icon-foreground); - } - } - - &.is-selected { - color: var(--menu-foreground-color); - .check-icon svg { - stroke: var(--menu-foreground-color); - visibility: visible; - } - } - - &:hover { - background-color: var(--menu-background-color-hover); - color: var(--menu-foreground-color-hover); - .check-icon svg { - stroke: var(--menu-foreground-color-hover); - } - } - &.is-highlighted { - background-color: var(--button-primary-background-color-rest); - span { - color: var(--button-primary-foreground-color-rest); - } - .check-icon svg { - stroke: var(--button-primary-foreground-color-rest); - } - } - } -} diff --git a/frontend/src/app/main/ui/workspace/tokens/editable_select.cljs b/frontend/src/app/main/ui/workspace/tokens/editable_select.cljs deleted file mode 100644 index 7ec0f9051..000000000 --- a/frontend/src/app/main/ui/workspace/tokens/editable_select.cljs +++ /dev/null @@ -1,301 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) KALEIDOS INC - -(ns app.main.ui.workspace.tokens.editable-select - (:require-macros [app.main.style :as stl]) - (:require - [app.common.data :as d] - [app.common.data.macros :as dm] - [app.common.math :as mth] - [app.common.uuid :as uuid] - [app.main.data.shortcuts :as dsc] - [app.main.store :as st] - [app.main.ui.components.dropdown :refer [dropdown]] - [app.main.ui.components.numeric-input :refer [numeric-input*]] - [app.main.ui.icons :as i] - [app.main.ui.workspace.tokens.core :as wtc] - [app.util.dom :as dom] - [app.util.globals :as globals] - [app.util.keyboard :as kbd] - [app.util.timers :as timers] - [cuerdas.core :as str] - [goog.events :as events] - [rumext.v2 :as mf]) - (:import goog.events.EventType)) - -(defn on-number-input-key-down [{:keys [event min-val max-val set-value!]}] - (let [up? (kbd/up-arrow? event) - down? (kbd/down-arrow? event)] - (when (or up? down?) - (dom/prevent-default event) - (let [value (-> event dom/get-target dom/get-value) - value (or (d/parse-double value) value) - increment (cond - (kbd/shift? event) (if up? 10 -10) - (kbd/alt? event) (if up? 0.1 -0.1) - :else (if up? 1 -1)) - new-value (+ value increment) - new-value (cond - (and (d/num? min-val) (< new-value min-val)) min-val - (and (d/num? max-val) (> new-value max-val)) max-val - :else new-value)] - (set-value! new-value))))) - -(defn direction-select - "Returns next `n` in `direction` while wrapping around at the last item at the count of `coll`. - - `direction` accepts `:up` or `:down`." - [direction n coll] - (let [last-n (dec (count coll)) - next-n (case direction - :up (dec n) - :down (inc n)) - wrap-around-n (cond - (neg? next-n) last-n - (> next-n last-n) 0 - :else next-n)] - wrap-around-n)) - -(mf/defc dropdown-select [{:keys [position on-close element-id element-ref options on-select]}] - (let [highlighted* (mf/use-state nil) - highlighted (deref highlighted*) - on-keyup (fn [event] - (cond - (and (kbd/enter? event) highlighted) (on-select (nth options highlighted)) - (kbd/up-arrow? event) (do - (dom/prevent-default event) - (->> (direction-select :up (or highlighted 0) options) - (reset! highlighted*))) - (kbd/down-arrow? event) (do - (dom/prevent-default event) - (->> (direction-select :down (or highlighted -1) options) - (reset! highlighted*)))))] - (mf/with-effect [highlighted] - (let [keys [(events/listen globals/document EventType.KEYUP on-keyup) - (events/listen globals/document EventType.KEYDOWN dom/prevent-default)]] - (st/emit! (dsc/push-shortcuts :token {})) - (fn [] - (doseq [key keys] - (events/unlistenByKey key)) - (st/emit! (dsc/pop-shortcuts :token))))) - [:& dropdown {:show true - :on-close on-close} - [:> :div {:class (stl/css-case :custom-select-dropdown true - :custom-select-dropdown-right (= position :right) - :custom-select-dropdown-left (= position :left)) - :on-mouse-enter #(reset! highlighted* nil) - :ref element-ref} - [:ul {:class (stl/css :custom-select-dropdown-list)} - (for [[index item] (d/enumerate options)] - (cond - (= :separator item) [:li {:class (stl/css :separator) - :key (dm/str element-id "-" index)}] - ;; Remove items with missing references - (seq (:errors item)) nil - :else (let [{:keys [label selected? errors]} item - highlighted? (= highlighted index)] - [:li - {:key (str element-id "-" index) - :class (stl/css-case :dropdown-element true - :is-selected selected? - :is-highlighted highlighted?) - :data-label label - :disabled (seq errors) - :on-click #(on-select item)} - [:span {:class (stl/css :label)} label] - [:span {:class (stl/css :value)} (wtc/resolve-token-value item)] - [:span {:class (stl/css :check-icon)} i/tick]])))]]])) - -(mf/defc editable-select - [{:keys [value options disabled class on-change placeholder on-blur on-token-remove position input-props] :as params}] - (let [{:keys [type]} input-props - input-class (:class input-props) - 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) - - toggle-dropdown - (mf/use-fn - (mf/deps state) - #(swap! state* update :is-open? not)) - - close-dropdown - (fn [event] - (dom/stop-propagation event) - (swap! state* assoc :is-open? false)) - - labels-map (->> (map (fn [{:keys [label] :as item}] - [label item]) - options) - (into {})) - - set-token-value! - (fn [value] - (swap! state* assoc :token-value value)) - - set-value - (fn [value event] - (swap! state* assoc - :current-value value - :token-value value) - (when on-change (on-change value event))) - - select-item - (mf/use-fn - (mf/deps on-change on-blur labels-map) - (fn [{:keys [value] :as item}] - (swap! state* assoc - :current-value value - :token-value nil - :current-item item) - (when on-change (on-change item)) - (when on-blur (on-blur)))) - - handle-change-input - (fn [event] - (let [value (-> event dom/get-target dom/get-value) - value (or (d/parse-double value) value)] - (set-value value event))) - - handle-token-change-input - (fn [event] - (let [value (-> event dom/get-target dom/get-value) - value (or (d/parse-double value) value)] - (set-token-value! value))) - - handle-key-down - (mf/use-fn - (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? (zero? (.. 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))) - (= type "number") (on-number-input-key-down {:event event - :min-val min-val - :max-val max-val - :set-value! set-value})))) - - 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 [] - (when (and on-blur (mf/ref-val emit-blur?)) (on-blur))))))] - - (mf/use-effect - (mf/deps value current-value) - #(when (not= (str value) current-value) - (swap! state* assoc :current-value value))) - - (mf/with-effect [is-open?] - (let [wrapper-node (mf/ref-val select-wrapper-ref) - node (dom/get-element-by-class "checked-element is-selected" wrapper-node) - nodes (dom/get-elements-by-class "checked-element-value" wrapper-node) - closest (fn [a b] (first (sort-by #(mth/abs (- % b)) a))) - closest-value (str (closest options value))] - (when is-open? - (if (some? node) - (dom/scroll-into-view-if-needed! node) - (some->> nodes - (d/seek #(= closest-value (dom/get-inner-text %))) - (dom/scroll-into-view-if-needed!))))) - - (mf/set-ref-val! emit-blur? (not is-open?))) - - - [:div {:class (dm/str class " " (stl/css-case :editable-select true - :editable-select-disabled disabled))} - (when-let [{:keys [label value]} token] - [:div {:title (str label ": " value) - :class (stl/css :token-pill)} - (wtc/resolve-token-value token)]) - (cond - token [:& :input (merge input-props - {:value (or (:token-value state) "") - :type "text" - :class input-class - :onChange handle-token-change-input - :onKeyDown handle-key-down - :onFocus handle-focus - :onBlur handle-blur})] - (= type "number") [:& numeric-input* (merge input-props - {:autoFocus refocus? - :value (or current-value "") - :className input-class - :onChange set-value - :onFocus handle-focus - :onBlur handle-blur - :placeholder placeholder})] - :else [:& :input (merge input-props - {:value (or current-value "") - :class input-class - :onChange handle-change-input - :onKeyDown handle-key-down - :onFocus handle-focus - :onBlur handle-blur - :placeholder placeholder - :type type})]) - - (when (seq options) - [:div {:class (stl/css :dropdown-button) - :on-click toggle-dropdown} - i/arrow]) - - (when (and is-open? (seq options)) - [:& dropdown-select {:position position - :on-close close-dropdown - :element-id element-id - :element-ref select-wrapper-ref - :options options - :on-select select-item}])])) diff --git a/frontend/src/app/main/ui/workspace/tokens/editable_select.scss b/frontend/src/app/main/ui/workspace/tokens/editable_select.scss deleted file mode 100644 index c404919ec..000000000 --- a/frontend/src/app/main/ui/workspace/tokens/editable_select.scss +++ /dev/null @@ -1,155 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. -// -// Copyright (c) KALEIDOS INC - -@import "refactor/common-refactor.scss"; - -.editable-select { - @extend .asset-element; - margin: 0; - display: flex; - height: calc($s-32 - 2px); // Fixes border being clipped by the input field - width: 100%; - padding: $s-8; - border-radius: $br-8; - position: relative; - 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; - padding-right: $s-8; - padding-left: 0; - aspect-ratio: 0.8 / 1; - width: auto; - - svg { - @extend .button-icon-small; - transform: rotate(90deg); - stroke: var(--icon-foreground); - } - } - - .custom-select-dropdown-list { - min-width: 150px; - width: 100%; - max-width: 200px; - 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-left { - left: 0; - right: unset; - } - - .custom-select-dropdown-right { - right: 0; - left: unset; - } - - .custom-select-dropdown { - @extend .dropdown-wrapper; - max-height: $s-320; - width: auto; - margin-top: $s-4; - - .separator { - margin: 0; - height: $s-12; - } - - .dropdown-element { - @extend .dropdown-element-base; - color: var(--menu-foreground-color-rest); - padding: 0; - display: flex; - - & > span { - display: flex; - justify-content: flex-start; - align-content: center; - } - - .label, - .value { - width: fit-content; - } - - .label { - text-transform: unset; - flex: 1; - } - - .value { - text-align: right; - justify-content: flex-end; - flex: 0.6; - } - - .check-icon { - @include flexCenter; - translate: -$s-4 0; - svg { - @extend .button-icon-small; - visibility: hidden; - stroke: var(--icon-foreground); - } - } - - &.is-selected { - color: var(--menu-foreground-color); - .check-icon svg { - stroke: var(--menu-foreground-color); - visibility: visible; - } - } - - &:hover { - background-color: var(--menu-background-color-hover); - color: var(--menu-foreground-color-hover); - .check-icon svg { - stroke: var(--menu-foreground-color-hover); - } - } - &.is-highlighted { - background-color: var(--button-primary-background-color-rest); - span { - color: var(--button-primary-foreground-color-rest); - } - .check-icon svg { - stroke: var(--button-primary-foreground-color-rest); - } - } - } - } -} - -.editable-select-disabled { - pointer-events: none; -} diff --git a/frontend/src/app/main/ui/workspace/tokens/form.scss b/frontend/src/app/main/ui/workspace/tokens/form.scss index cac828b1e..171d8c1ac 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.scss +++ b/frontend/src/app/main/ui/workspace/tokens/form.scss @@ -5,7 +5,6 @@ // Copyright (c) KALEIDOS INC @import "refactor/common-refactor.scss"; -@import "./common.scss"; .form-wrapper { width: $s-384; @@ -39,11 +38,6 @@ gap: $s-4; } -.labeled-input-label { - color: var(--color-foreground-primary); - font-size: $fs-12; -} - .warning-name-change-notification-wrapper { margin-block-start: $s-16; } diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs index 2f54ad9ff..8e3b935a9 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs @@ -18,11 +18,12 @@ [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] + [app.main.ui.ds.controls.combobox :refer [combobox*]] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as ic] [app.main.ui.ds.foundations.typography.heading :refer [heading*]] [app.main.ui.ds.foundations.typography.text :refer [text*]] [app.main.ui.icons :as i] - [app.main.ui.workspace.tokens.common :refer [labeled-input] :as wtco] + [app.main.ui.workspace.tokens.components.controls.input-tokens :refer [input-tokens*]] [app.main.ui.workspace.tokens.sets :as wts] [app.main.ui.workspace.tokens.sets-context :as sets-context] [app.util.dom :as dom] @@ -158,40 +159,35 @@ (tr "workspace.token.create-theme-title")]]])) (mf/defc theme-inputs - [{:keys [theme dropdown-open? on-close-dropdown on-toggle-dropdown on-change-field]}] + [{:keys [theme on-change-field]}] (let [theme-groups (mf/deref refs/workspace-token-theme-groups) - group-input-ref (mf/use-ref) + theme-name-ref (mf/use-ref (:name theme)) + options (map (fn [group] + {:label group + :id group}) + theme-groups) on-update-group (partial on-change-field :group) - on-update-name (partial on-change-field :name)] + on-update-name + (mf/use-fn + (fn [event] + (let [value (-> event dom/get-target dom/get-value)] + (on-change-field :name value) + (mf/set-ref-val! theme-name-ref value))))] + [:div {:class (stl/css :edit-theme-inputs-wrapper)} [:div {:class (stl/css :group-input-wrapper)} - (when dropdown-open? - [:& wtco/dropdown-select {:id ::groups-dropdown - :shortcuts-key ::groups-dropdown - :options (map (fn [group] - {:label group - :value group}) - theme-groups) - :on-select (fn [{:keys [value]}] - (set! (.-value (mf/ref-val group-input-ref)) value) - (on-update-group value)) - :on-close on-close-dropdown}]) - [:& labeled-input {:label "Group" - :input-props {:ref group-input-ref - :default-value (:group theme) - :on-change (comp on-update-group dom/get-target-val)} - :render-right (when (seq theme-groups) - (mf/fnc drop-down-button [] - [:button {:class (stl/css :group-drop-down-button) - :type "button" - :on-click (fn [e] - (dom/stop-propagation e) - (on-toggle-dropdown))} - [:> icon* {:icon-id "arrow-down"}]]))}]] + [:label {:for "groups-dropdown" :class (stl/css :label)} (tr "workspace.token.label.group")] + [:> combobox* {:id (dm/str "groups-dropdown") + :default-selected (:group theme) + :options (clj->js options) + :on-change on-update-group}]] + [:div {:class (stl/css :group-input-wrapper)} - [:& labeled-input {:label "Theme" - :input-props {:default-value (:name theme) - :on-change (comp on-update-name dom/get-target-val)}}]]])) + [:> input-tokens* {:id "theme-input" + :label (tr "workspace.token.label.theme") + :type "text" + :on-change on-update-name + :value (mf/ref-val theme-name-ref)}]]])) (mf/defc theme-modal-buttons [{:keys [close-modal on-save-form disabled?] :as props}] @@ -208,8 +204,7 @@ (mf/defc create-theme [{:keys [set-state]}] - (let [{:keys [dropdown-open? _on-open-dropdown on-close-dropdown on-toggle-dropdown]} (wtco/use-dropdown-open-state) - theme (ctob/make-token-theme :name "") + (let [theme (ctob/make-token-theme :name "") on-back #(set-state (constantly {:type :themes-overview})) on-submit (mf/use-fn (fn [theme] @@ -242,10 +237,7 @@ (tr "workspace.token.create-theme-title")] [:form {:on-submit on-save-form} [:div {:class (stl/css :create-theme-wrapper)} - [:& theme-inputs {:dropdown-open? dropdown-open? - :on-close-dropdown on-close-dropdown - :on-toggle-dropdown on-toggle-dropdown - :theme theme + [:& theme-inputs {:theme theme :on-change-field on-change-field}] [:div {:class (stl/css :button-footer)} @@ -269,7 +261,6 @@ ;; Form / Modal handlers on-back #(set-state (constantly {:type :themes-overview})) on-submit #(st/emit! (wdt/update-token-theme [(:group theme) (:name theme)] %)) - {:keys [dropdown-open? _on-open-dropdown on-close-dropdown on-toggle-dropdown]} (wtco/use-dropdown-open-state) disabled? (-> (:name @theme-state) (str/trim) (str/empty?)) @@ -349,10 +340,7 @@ [:> icon* {:icon-id ic/arrow-left :aria-hidden true}] (tr "workspace.token.back-to-themes")] - [:& theme-inputs {:dropdown-open? dropdown-open? - :on-close-dropdown on-close-dropdown - :on-toggle-dropdown on-toggle-dropdown - :theme theme + [:& theme-inputs {:theme theme :on-change-field on-change-field}] [:> text* {:as "span" :typography "body-small" :class (stl/css :select-sets-message)} (tr "workspace.token.set-selection-theme")] diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss b/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss index 43793b951..8fdbfd4d9 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss +++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss @@ -4,6 +4,9 @@ // // Copyright (c) KALEIDOS INC +@use "../../../ds/typography.scss" as t; +@use "../../../ds/_sizes.scss" as *; + @import "refactor/common-refactor.scss"; .modal-overlay { @@ -13,11 +16,9 @@ .modal-dialog { @extend .modal-container-base; - display: flex; - flex-direction: column; width: 100%; max-width: $s-512; - max-height: $s-720; + max-height: unset; user-select: none; } @@ -31,15 +32,14 @@ } .themes-modal-wrapper { - display: flex; - flex-direction: column; + display: grid; + grid-template-rows: 0fr minmax(0, 1fr); gap: $s-24; - overflow: auto; + max-height: $s-688; } .edit-theme-form { display: flex; - overflow-y: auto; } .themes-modal-title { @@ -62,10 +62,6 @@ } } -.labeled-input-label { - color: var(--color-foreground-primary); -} - .button-footer { display: flex; justify-content: flex-end; @@ -172,6 +168,7 @@ display: flex; flex-direction: column; gap: $s-24; + inline-size: 100%; } .sets-list-wrapper { @@ -199,11 +196,8 @@ gap: $s-12; } -.group-drop-down-button { - @include buttonStyle; - color: var(--color-foreground-secondary); - width: $s-24; - height: 100%; - padding: 0; - margin: 0 $s-6; +.label { + @include t.use-typography("body-small"); + @include textEllipsis; + color: var(--color-foreground-primary); } diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.scss b/frontend/src/app/main/ui/workspace/tokens/sidebar.scss index ba6520e50..ed49eea66 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.scss +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.scss @@ -6,7 +6,6 @@ @use "../../ds/typography.scss" as *; @import "refactor/common-refactor.scss"; -@import "./common.scss"; .sidebar-wrapper { display: grid; diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.scss b/frontend/src/app/main/ui/workspace/tokens/token_pill.scss index e58271ca5..1b3d63769 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.scss +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.scss @@ -6,7 +6,6 @@ @use "../../ds/typography.scss" as *; @import "refactor/common-refactor.scss"; -@import "./common.scss"; .token-pill { @include use-typography("code-font"); diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 745a8b2fe..251953f93 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -6292,6 +6292,9 @@ msgstr "Edit themes" msgid "workspace.token.edit-token" msgstr "Edit token" +msgid "workspace.token.label.group" +msgstr "Group" + #: src/app/main/ui/workspace/tokens/sets.cljs:186 #, unused msgid "workspace.token.grouping-set-alert" @@ -6354,6 +6357,9 @@ msgstr "Select set." msgid "workspace.token.set-selection-theme" msgstr "Define what token sets should be used as part of this theme option:" +msgid "workspace.token.label.theme" +msgstr "Theme" + #: src/app/main/ui/workspace/tokens/modals/themes.cljs #, unused msgid "workspace.token.theme-name" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 26bae45fb..c4dc848ab 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -6318,6 +6318,9 @@ msgstr "Editar temas" msgid "workspace.token.edit-token" msgstr "Editar token" +msgid "workspace.token.label.group" +msgstr "Grupo" + #: src/app/main/ui/workspace/tokens/sets.cljs:186 msgid "workspace.token.grouping-set-alert" msgstr "La agrupación de sets aun no está soportada." @@ -6366,6 +6369,9 @@ msgstr "Selecciona set" msgid "workspace.token.set-selection-theme" msgstr "Define que sets de tokens deberian formar parte de este tema:" +msgid "workspace.token.label.theme" +msgstr "Tema" + #: src/app/main/ui/workspace/tokens/modals/themes.cljs #, unused msgid "workspace.token.theme-name"