Просмотр исходного кода

enhance(ui): WIP playground for x popup

charlie 2 лет назад
Родитель
Сommit
6eb46ba77a
1 измененных файлов с 77 добавлено и 30 удалено
  1. 77 30
      deps/shui/src/logseq/shui/demo2.cljs

+ 77 - 30
deps/shui/src/logseq/shui/demo2.cljs

@@ -1,51 +1,98 @@
 (ns logseq.shui.demo2
   (:require [rum.core :as rum]
             [logseq.shui.ui :as ui]
-            [frontend.rum :refer [use-atom]]
+            [medley.core :as medley]
+            [logseq.shui.util :refer [use-atom]]
             [frontend.components.icon :refer [emojis-cp emojis]]))
 
 (defonce *x-popup-state
   (atom {:open? false :content nil :position [0 0]}))
 
+;; {:id "" :open? false :content nil :position [0 0] :root-props nil :content-props nil}
+(defonce ^:private *popups (atom []))
+(defonce ^:private *id (atom 0))
+(defonce ^:private gen-id #(reset! *id (inc @*id)))
+
+(defn get-popup
+  [id]
+  (when id
+    (some->> (medley/indexed @*popups)
+      (filter #(= id (:id (second %)))) (first))))
+
+(defn upsert-popup!
+  [config]
+  (when-let [_id (:id config)]
+    (swap! *popups conj config)))
+
+(defn update-popup!
+  [id ks val]
+  (when-let [[index config] (get-popup id)]
+    (let [ks (if (coll? ks) ks [ks])
+          config (if (nil? val)
+                   (medley/dissoc-in config ks)
+                   (assoc-in config ks val))]
+      (swap! *popups assoc index config))))
+
+(defn detach-popup!
+  [id]
+  (when-let [[index] (get-popup id)]
+    (swap! *popups #(->> % (medley/remove-nth index) (vec)))))
+
 (defn show-x-popup!
-  [^js event content & {:keys [as-menu? root-props content-props]}]
+  [^js event content & {:keys [id as-menu? root-props content-props]}]
   (let [x (.-clientX event)
         y (.-clientY event)]
-    (reset! *x-popup-state
-      {:open?    true :content content :position [x y]
+    (upsert-popup!
+      {:id (or id (gen-id)) :open? true :content content :position [x y]
        :as-menu? as-menu? :root-props root-props :content-props content-props})))
 
 (defn hide-x-popup!
+  [id]
+  (update-popup! id :open? false))
+
+(defn hide-x-popup-all!
+  []
+  (doseq [{:keys [id]} @*popups]
+    (hide-x-popup! id)))
+
+(rum/defc x-popup [{:keys [id open? content position as-menu? root-props content-props] :as _props}]
+  (rum/use-effect!
+    (fn []
+      (when (false? open?)
+        (js/setTimeout #(detach-popup! id) 128)))
+    [open?])
+
+  (when-let [[x y] position]
+    (let [popup-root (if as-menu? ui/dropdown-menu ui/popover)
+          popup-trigger (if as-menu? ui/dropdown-menu-trigger ui/popover-trigger)
+          popup-content (if as-menu? ui/dropdown-menu-content ui/popover-content)]
+      (popup-root
+        (merge root-props {:open open?})
+        (popup-trigger
+          {:as-child true}
+          (ui/button {:class "w-1 h-1 overflow-hidden fixed p-0 opacity-0"
+                      :style {:top y :left x}} ""))
+        (popup-content
+          (merge {:onEscapeKeyDown      #(hide-x-popup! id)
+                  :onPointerDownOutside #(hide-x-popup! id)} content-props)
+          (if (fn? content) (content {:id id}) content))))))
+
+(rum/defc install-popups
+  < rum/static
   []
-  (when (true? (:open? @*x-popup-state))
-    (swap! *x-popup-state assoc :open? false)
-    (js/setTimeout
-      #(reset! *x-popup-state
-         {:open? false :content nil :position [0 0] :as-menu? false}) 128)))
-
-(rum/defc x-popup []
-  (let [[{:keys [open? content position as-menu? root-props content-props]} _] (use-atom *x-popup-state)]
-    (when-let [[x y] position]
-      (let [popup-root (if as-menu? ui/dropdown-menu ui/popover)
-            popup-trigger (if as-menu? ui/dropdown-menu-trigger ui/popover-trigger)
-            popup-content (if as-menu? ui/dropdown-menu-content ui/popover-content)]
-        (popup-root
-          (merge root-props {:open open?})
-          (popup-trigger
-            {:as-child true}
-            (ui/button {:class "w-1 h-1 overflow-hidden fixed p-0 opacity-0"
-                        :style {:top y :left x}} ""))
-          (popup-content
-            (merge {:onEscapeKeyDown      #(hide-x-popup!)
-                    :onPointerDownOutside #(hide-x-popup!)} content-props)
-            (if (fn? content) (content) content))))
-      )))
+  (let [[popups _set-popups!] (use-atom *popups)]
+    [:<>
+     (for [config popups
+           :when (and (map? config) (:id config))]
+       (x-popup config))]))
 
 (rum/defc page []
   [:div.sm:p-10
    [:h1.text-3xl.font-bold.border-b.pb-4 "UI X Popup"]
 
-   (rum/portal (x-popup) js/document.body)
+   (rum/portal
+     (install-popups)
+     js/document.body)
 
    (let [[emoji set-emoji!] (rum/use-state nil)
          emoji-picker (fn [_nested?]
@@ -58,7 +105,7 @@
                                            {:on-chosen
                                             (fn [_ t]
                                               (set-emoji! t)
-                                              (hide-x-popup!))})]
+                                              (hide-x-popup-all!))})]
                                         {:content-props {:class "w-72 p-0"}
                                          :as-menu?      true})}
                           (if emoji [:strong.px-1.text-6xl [:em-emoji emoji]] "emoji :O")] "."])]
@@ -81,7 +128,7 @@
                                      (ui/dropdown-menu-item
                                        {:on-select (fn []
                                                      (ui/toast! it)
-                                                     (hide-x-popup!))}
+                                                     (hide-x-popup-all!))}
                                        [:strong it]))))
                             {:as-menu?      true
                              :content-props {:class "w-48"}})