diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox.cljs index d006c49cc3..3f09683da7 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/combobox.cljs @@ -19,6 +19,8 @@ [app.main.ui.ds.controls.utilities.utils :as csu] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.forms :as fc] + [app.main.ui.workspace.tokens.management.forms.controls.floating :refer [use-floating-dropdown]] + [app.main.ui.workspace.tokens.management.forms.controls.navigation :refer [use-navigation]] [app.util.dom :as dom] [app.util.forms :as fm] [app.util.i18n :refer [tr]] @@ -173,36 +175,6 @@ raw-tokens-by-type (mf/use-ctx muc/active-tokens-by-type) - calculate-position - (mf/use-fn - (mf/deps dropdown-ref) - (fn [node] - (let [combobox-rect (dom/get-bounding-rect node) - dropdown-node (mf/ref-val dropdown-ref) - dropdown-height (if dropdown-node - (-> (dom/get-bounding-rect dropdown-node) - (:height)) - 0) - - windows-height (-> (dom/get-window-size) - (:height)) - - space-below (- windows-height (:bottom combobox-rect)) - space-above (:top combobox-rect) - - place-top? (< space-below dropdown-height) - - position (if place-top? - {:top (str (- space-above dropdown-height -14) "px") - :left (str (:left combobox-rect) "px") - :width (str (:width combobox-rect) "px") - :placement :top} - {:top (str (+ (:bottom combobox-rect) 4) "px") - :left (str (:left combobox-rect) "px") - :width (str (:width combobox-rect) "px") - :placement :bottom})] - (reset! dropdown-pos* position)))) - filtered-tokens-by-type (mf/with-memo [raw-tokens-by-type token-type] (csu/filter-tokens-for-input raw-tokens-by-type token-type)) @@ -438,28 +410,6 @@ (dom/scroll-into-view-if-needed! node {:block "nearest" :inline "nearest"}))))) - (mf/with-effect [is-open dropdown-ref wrapper-ref] - (when is-open - (let [handler (fn [event] - (let [dropdown-node (mf/ref-val dropdown-ref) - target (dom/get-target event)] - (when (or (nil? dropdown-node) - (not (instance? js/Node target)) - (not (.contains dropdown-node target))) - (js/requestAnimationFrame - (fn [] - (let [wrapper-node (mf/ref-val wrapper-ref)] - (reset! dropdown-ready* true) - (calculate-position wrapper-node)))))))] - (handler nil) - - (.addEventListener js/window "resize" handler) - (.addEventListener js/window "scroll" handler true) - - (fn [] - (.removeEventListener js/window "resize" handler) - (.removeEventListener js/window "scroll" handler true))))) - [:div {:ref wrapper-ref} [:> ds/input* props] (when ^boolean is-open @@ -468,10 +418,10 @@ (mf/html [:> options-dropdown* {:on-click on-option-click :class (stl/css :dropdown) - :style {:visibility (if dropdown-ready "visible" "hidden") - :left (:left dropdown-pos) - :top (:top dropdown-pos) - :width (:width dropdown-pos)} + :style {:visibility (if (:ready? floating) "visible" "hidden") + :left (get-in floating [:style :left]) + :top (get-in floating [:style :top]) + :width (get-in floating [:style :width])} :id listbox-id :options options :focused focused-id diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/floating.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/floating.cljs new file mode 100644 index 0000000000..0bd3aa1ebe --- /dev/null +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/floating.cljs @@ -0,0 +1,67 @@ +;; 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.management.forms.controls.floating + (:require + [app.util.dom :as dom] + [rumext.v2 :as mf])) + +(defn use-floating-dropdown [is-open wrapper-ref dropdown-ref] + (let [pos* (mf/use-state nil) + ready* (mf/use-state false) + calculate-position + (fn [node] + (let [combobox-rect (dom/get-bounding-rect node) + dropdown-node (mf/ref-val dropdown-ref) + dropdown-height (if dropdown-node + (-> (dom/get-bounding-rect dropdown-node) + (:height)) + 0) + + windows-height (-> (dom/get-window-size) + (:height)) + + space-below (- windows-height (:bottom combobox-rect)) + space-above (:top combobox-rect) + + place-top? (< space-below dropdown-height) + + position (if place-top? + {:top (str (- space-above dropdown-height -14) "px") + :left (str (:left combobox-rect) "px") + :width (str (:width combobox-rect) "px") + :placement :top} + {:top (str (+ (:bottom combobox-rect) 4) "px") + :left (str (:left combobox-rect) "px") + :width (str (:width combobox-rect) "px") + :placement :bottom})] + (reset! ready* true) + (reset! pos* position)))] + + (mf/with-effect [is-open dropdown-ref wrapper-ref] + (when is-open + (let [handler (fn [event] + (let [dropdown-node (mf/ref-val dropdown-ref) + target (dom/get-target event)] + (when (or (nil? dropdown-node) + (not (instance? js/Node target)) + (not (.contains dropdown-node target))) + (js/requestAnimationFrame + (fn [] + (let [wrapper-node (mf/ref-val wrapper-ref)] + (reset! ready* true) + (calculate-position wrapper-node)))))))] + (handler nil) + + (.addEventListener js/window "resize" handler) + (.addEventListener js/window "scroll" handler true) + + (fn [] + (.removeEventListener js/window "resize" handler) + (.removeEventListener js/window "scroll" handler true))))) + + {:style @pos* + :ready? @ready*})) \ No newline at end of file