Browse Source

enhance(ui): WIP enhance the multi select component for shui

charlie 1 year ago
parent
commit
807ca2908a
2 changed files with 71 additions and 19 deletions
  1. 9 3
      deps/shui/src/logseq/shui/demo2.cljs
  2. 62 16
      deps/shui/src/logseq/shui/select/multi.cljs

+ 9 - 3
deps/shui/src/logseq/shui/demo2.cljs

@@ -1,5 +1,6 @@
 (ns logseq.shui.demo2
-  (:require [rum.core :as rum]
+  (:require [clojure.string :as string]
+            [rum.core :as rum]
             [logseq.shui.ui :as ui]
             [logseq.shui.popup.core :refer [install-popups update-popup! get-popup]]
             [logseq.shui.select.multi :refer [x-select]]
@@ -45,7 +46,8 @@
               (ui/button {:variant :link :size :sm} "+")])
            ;; content
            (x-select items selected-items
-             {:on-chosen on-chosen
+             {:close! #(set-open! false)
+              :on-chosen on-chosen
               :value-render (fn [v {:keys [selected?]}]
                               (if selected?
                                 [:b.text-red-800 v]
@@ -91,6 +93,8 @@
            ;; content
            (x-select items selected-items
              {;; test item render
+              :open? open?
+              :close! #(set-open! false)
               :search-enabled? true
               :item-render (fn [item {:keys [selected?]}]
                              (if item
@@ -106,7 +110,9 @@
               ;:head-render (fn [] [:b "header"])
               ;:foot-render (fn [] [:b "footer"])
               :content-props
-              {:onInteractOutside #(set-open! false)
+              {:align "start"
+               :onInteractOutside #(set-open! false)
+               :onEscapeKeyDown #(set-open! false)
                :class "w-48"}})
            ))))
 

+ 62 - 16
deps/shui/src/logseq/shui/select/multi.cljs

@@ -1,16 +1,22 @@
 (ns logseq.shui.select.multi
-  (:require [rum.core :as rum]
+  (:require [clojure.string :as string]
+            [rum.core :as rum]
             [logseq.shui.popup.core :as popup]
             [logseq.shui.form.core :as form]))
 
-(defn get-k [item]
+(defn- get-k [item]
   (when (map? item)
     (some->> ((juxt :id :key :label) item)
       (remove nil?)
       (first))))
 
+(defn- get-v
+  [item]
+  (if (string? item)
+    item (or (:title item) (:value item))))
+
 (rum/defc search-input
-  []
+  [input-props]
   (let [*el (rum/use-ref nil)
         [down set-down!] (rum/use-state 0)]
 
@@ -25,26 +31,67 @@
 
     [:div.search-input.p-2
      {:ref *el}
-     (form/input {:placeholder "search"
-                  :class "!h-8"
-                  :on-key-down #(when (= "ArrowDown" (.-key %))
-                                  (set-down! (inc down)))
-                  :auto-focus true})]))
+     (form/input
+       (merge {:placeholder "search"
+               :class "!h-8"
+               :on-key-up #(case (.-key %)
+                             "ArrowDown" (set-down! (inc down))
+                             "ArrowUp" nil
+                             :dune)
+               :auto-focus true}
+         input-props))]))
+
+(defn- simple-search-fn
+  [items q]
+  (let [q (some-> q (string/trim) (string/lower-case))]
+    (if (string/blank? q)
+      items
+      (filter #(some-> (get-v %)
+                 (string/lower-case)
+                 (string/starts-with? q)) items))))
 
 (rum/defc x-select
   [items selected-items & {:keys [on-chosen item-render value-render
-                                  head-render foot-render
-                                  search-enabled? search-key
+                                  head-render foot-render open? close!
+                                  search-enabled? search-key search-fn
                                   item-props content-props]}]
   (let [x-content popup/dropdown-menu-content
-        x-item popup/dropdown-menu-item]
+        x-item popup/dropdown-menu-item
+        [search-key1 set-search-key!] (rum/use-state search-key)
+        items (if search-enabled?
+                (if (fn? search-fn)
+                  (search-fn items search-key1)
+                  (simple-search-fn items search-key1))
+                items)
+        close1! #(when (fn? close!) (close!))]
+
+    (rum/use-effect!
+      (fn []
+        (when (and search-enabled? (false? open?))
+          (js/setTimeout #(set-search-key! "") 500)))
+      [open?])
+
     [:div.flex.flex-1.flex-col
      (x-content
-       (merge {} content-props)
+       (merge
+         {:onCloseAutoFocus false
+          :onInteractOutside close1!
+          :onEscapeKeyDown close1!}
+         content-props)
        ;; header
        (when (or search-enabled? (fn? head-render))
          [:div.head
-          (when search-enabled? (search-input))
+          (when search-enabled?
+            (search-input
+              {:value search-key1
+               :on-key-down (fn [^js e]
+                              (.stopPropagation e)
+                              (case (.-key e)
+                                "Escape" (if (string/blank? search-key1)
+                                           (some-> (.-target e) (.blur))
+                                           (set-search-key! ""))
+                                :dune))
+               :on-change #(set-search-key! (.-value (.-target %)))}))
           (when head-render (head-render))])
        ;; items
        (for [item items
@@ -57,9 +104,8 @@
                                selected-items)]]
          (if (fn? item-render)
            (item-render item {:x-item x-item :selected? selected?})
-           (let [{:keys [title value]} item
-                 k (get-k item)
-                 v (or title value)]
+           (let [k (get-k item)
+                 v (get-v item)]
              (when k
                (let [opts {:selected? selected?}
                      on-click' (:on-click item-props)