diff --git a/frontend/src/app/main/ui/ds/controls/select.cljs b/frontend/src/app/main/ui/ds/controls/select.cljs index 0d2730ebb..2a7b279de 100644 --- a/frontend/src/app/main/ui/ds/controls/select.cljs +++ b/frontend/src/app/main/ui/ds/controls/select.cljs @@ -17,6 +17,8 @@ [app.util.object :as obj] [rumext.v2 :as mf])) +(def listbox-id-index (atom 0)) + (def ^:private schema:select-option [:and [:map {:title "option"} @@ -71,14 +73,9 @@ ::mf/schema schema:select} [{:keys [options class disabled default-selected on-change] :rest props}] (let [open* (mf/use-state false) + listbox-id-ref (mf/use-ref (dm/str "select-listbox-" (swap! listbox-id-index inc))) + listbox-id (mf/ref-val listbox-id-ref) open (deref open*) - on-click - (mf/use-fn - (mf/deps disabled) - (fn [event] - (dom/stop-propagation event) - (when-not disabled - (swap! open* not)))) selected* (mf/use-state #(get-selected-option-id options default-selected)) selected (deref selected*) @@ -86,6 +83,18 @@ focused* (mf/use-state nil) focused (deref focused*) + has-focus* (mf/use-state false) + has-focus (deref has-focus*) + + on-click + (mf/use-fn + (mf/deps disabled) + (fn [event] + (dom/stop-propagation event) + (reset! has-focus* true) + (when-not disabled + (swap! open* not)))) + on-option-click (mf/use-fn (mf/deps on-change) @@ -116,7 +125,8 @@ (let [click-outside (nil? (.-relatedTarget event))] (when click-outside (reset! focused* nil) - (reset! open* false))))) + (reset! open* false) + (reset! has-focus* false))))) on-key-down (mf/use-fn @@ -146,12 +156,17 @@ (do (reset! open* false) (reset! focused* nil))))))) - class (dm/str class " " (stl/css :select)) + on-focus + (mf/use-fn + (fn [_] (reset! has-focus* true))) + + class (dm/str class " " (stl/css-case :select true + :focused has-focus)) props (mf/spread-props props {:class class :role "combobox" - :aria-controls "listbox" - :aria-haspopup "listbox" + :aria-controls listbox-id + :aria-haspopup listbox-id :aria-activedescendant focused :aria-expanded open :on-key-down on-key-down @@ -166,7 +181,10 @@ (mf/with-effect [options] (mf/set-ref-val! options-ref options)) - [:div {:class (stl/css :select-wrapper)} + [:div {:class (stl/css :select-wrapper) + :on-click on-click + :on-focus on-focus + :on-blur on-blur} [:> :button props [:span {:class (stl/css-case :select-header true :header-icon (some? icon))} diff --git a/frontend/src/app/main/ui/ds/controls/select.scss b/frontend/src/app/main/ui/ds/controls/select.scss index 072870cd4..db13d2c25 100644 --- a/frontend/src/app/main/ui/ds/controls/select.scss +++ b/frontend/src/app/main/ui/ds/controls/select.scss @@ -53,6 +53,10 @@ appearance: none; } +.focused { + --select-outline-color: var(--color-accent-primary); +} + .arrow { color: var(--select-icon-fg-color); transform: rotate(90deg); diff --git a/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.cljs b/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.cljs index 16ce0240a..66ecee2a1 100644 --- a/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.cljs +++ b/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.cljs @@ -16,34 +16,37 @@ {::mf/props :obj ::mf/private true} [{:keys [id label icon aria-label on-click selected set-ref focused] :rest props}] - [:> :li {:value id - :class (stl/css-case :option true - :option-with-icon (some? icon) - :option-current focused) - :aria-selected selected - :ref (fn [node] - (set-ref node id)) - :role "option" - :id id - :on-click on-click - :data-id id - :data-testid "dropdown-option"} - (when (some? icon) - [:> icon* - {:id icon - :size "s" - :class (stl/css :option-icon) - :aria-hidden (when label true) - :aria-label (when (not label) aria-label)}]) + (let [_ (prn selected)] + [:> :li {:value id + :class (stl/css-case :option true + :option-with-icon (some? icon) + :option-selected selected + :option-current focused) + :aria-selected selected + :ref (fn [node] + (set-ref node id)) + :role "option" + :id id + :on-click on-click + :data-id id + :data-testid "dropdown-option"} - [:span {:class (stl/css :option-text)} label] - (when selected - [:> icon* - {:id i/tick - :size "s" - :class (stl/css :option-check) - :aria-hidden (when label true)}])]) + (when (some? icon) + [:> icon* + {:id icon + :size "s" + :class (stl/css :option-icon) + :aria-hidden (when label true) + :aria-label (when (not label) aria-label)}]) + + [:span {:class (stl/css :option-text)} label] + (when selected + [:> icon* + {:id i/tick + :size "s" + :class (stl/css :option-check) + :aria-hidden (when label true)}])])) (mf/defc options-dropdown* {::mf/props :obj} 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 8b330e30b..bdaf95f66 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 @@ -44,6 +44,7 @@ outline: $b-1 solid var(--options-dropdown-outline-color); outline-offset: -1px; background-color: var(--options-dropdown-bg-color); + color: var(--options-dropdown-fg-color); &:hover, &[aria-selected="true"] { @@ -72,3 +73,8 @@ --options-dropdown-outline-color: var(--color-accent-primary); outline: $b-1 solid var(--options-dropdown-outline-color); } + +.option-selected { + --options-dropdown-fg-color: var(--color-accent-primary); + --options-dropdown-icon-fg-color: var(--color-accent-primary); +}