;; 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.components.dropdown (:require [app.config :as cfg] [app.util.dom :as dom] [app.util.globals :as globals] [app.util.keyboard :as kbd] [app.util.timers :as tm] [goog.events :as events] [goog.object :as gobj] [rumext.v2 :as mf]) (:import goog.events.EventType)) (mf/defc dropdown' {::mf/wrap-props false} [props] (let [children (gobj/get props "children") on-close (gobj/get props "on-close") container-ref (gobj/get props "container") listening-ref (mf/use-ref nil) on-click (fn [event] (when (mf/ref-val listening-ref) (let [target (dom/get-target event) ;; MacOS ctrl+click sends two events: context-menu and click. ;; In order to not have two handlings we ignore ctrl+click for this platform mac-ctrl-click? (and (cfg/check-platform? :macos) (kbd/ctrl? event))] (when (and (not mac-ctrl-click?) (not (.-data-no-close ^js target))) (if container-ref (let [parent (mf/ref-val container-ref)] (when-not (or (not parent) (.contains parent target)) (on-close))) (on-close)))))) on-keyup (fn [event] (when (kbd/esc? event) (on-close))) on-mount (fn [] (let [keys [(events/listen globals/document EventType.CLICK on-click) (events/listen globals/document EventType.CONTEXTMENU on-click) (events/listen globals/document EventType.KEYUP on-keyup)]] (tm/schedule #(mf/set-ref-val! listening-ref true)) #(run! events/unlistenByKey keys)))] (mf/use-effect on-mount) children)) (mf/defc dropdown {::mf/wrap-props false} [props] (assert (fn? (gobj/get props "on-close")) "missing `on-close` prop") (assert (boolean? (gobj/get props "show")) "missing `show` prop") (when (gobj/get props "show") (mf/element dropdown' props)))