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

fix(ux): invalid action for the block selection context menus

charlie 1 год назад
Родитель
Сommit
685b78e2a0

+ 50 - 47
deps/shui/src/logseq/shui/popup/core.cljs

@@ -70,7 +70,8 @@
           (.focus target))))))
 
 (defn show!
-  [^js event content & {:keys [id as-dropdown? as-content? align root-props content-props on-hide] :as opts}]
+  [^js event content & {:keys [id as-dropdown? as-content? align root-props content-props
+                               on-before-hide on-after-hide] :as opts}]
   (let [*target (volatile! nil)
         position (cond
                    (vector? event) event
@@ -78,7 +79,7 @@
                    (or (instance? js/MouseEvent (or (.-nativeEvent event) event))
                      (instance? js/goog.events.BrowserEvent event))
                    (do (vreset! *target (.-target (or (.-nativeEvent event) event)))
-                       [(.-clientX event) (.-clientY event)])
+                     [(.-clientX event) (.-clientY event)])
 
                    (instance? js/Element event)
                    (let [^js rect (.getBoundingClientRect event)
@@ -87,11 +88,11 @@
                          height (.-height rect)
                          bottom (.-bottom rect)]
                      (do (vreset! *target event)
-                         [(+ left (case (keyword align)
-                                    :start 0
-                                    :end width
-                                    (/ width 2)))
-                          (- bottom height) width height]))
+                       [(+ left (case (keyword align)
+                                  :start 0
+                                  :end width
+                                  (/ width 2)))
+                        (- bottom height) width height]))
                    :else [0 0])]
     (upsert-popup!
       (merge opts
@@ -100,7 +101,8 @@
          :as-dropdown? as-dropdown?
          :as-content? as-content?
          :root-props root-props
-         :on-hide on-hide
+         :on-before-hide on-before-hide
+         :on-after-hide on-after-hide
          :content-props (cond-> content-props
                           (not (nil? align))
                           (assoc :align (name align)))}))))
@@ -110,12 +112,16 @@
   ([id] (hide! id 0 {}))
   ([id delay] (hide! id delay {}))
   ([id delay {:keys [all?]}]
-   (let [f #(if all?
-              (reset! *popups [])
-              (detach-popup! id))]
-     (if (and (number? delay) (> delay 0))
-       (js/setTimeout f delay)
-       (f)))))
+   (when-let [popup (get-popup id)]
+     (let [config (last popup)
+           f #(if all?
+                (reset! *popups [])
+                (do (detach-popup! id)
+                  (some-> (:on-after-hide config) (apply []))))]
+       (some-> (:on-before-hide config) (apply []))
+       (if (and (number? delay) (> delay 0))
+         (js/setTimeout f delay)
+         (f))))))
 
 (defn hide-all!
   []
@@ -124,7 +130,8 @@
 
 (rum/defc x-popup
   [{:keys [id open? content position as-dropdown? as-content? force-popover?
-           auto-side? _auto-focus? _target root-props content-props on-hide]
+           auto-side? _auto-focus? _target root-props content-props
+           _on-before-hide _on-after-hide]
     :as _props}]
   ;; disableOutsidePointerEvents
   ;(rum/use-effect!
@@ -153,39 +160,35 @@
                                "top" "bottom"))))
           content-props (cond-> content-props
                           auto-side? (assoc :side (auto-side-fn)))
-          hide (fn []
-                 (when (fn? on-hide)
-                   (on-hide))
-                 ;; Async so that popup closing will be in another run
-                 (js/setTimeout #(hide! id) 0))]
+          hide (fn [] (hide! id 1))]
       (popup-root
-       (merge root-props {:open open?})
-       (popup-trigger
-        {:as-child true}
-        (button {:class "overflow-hidden fixed p-0 opacity-0"
-                 :style {:height (if (and (number? height)
-                                          (> height 0))
-                                   height 1)
-                         :width 1
-                         :top y
-                         :left x}} ""))
-       (let [content-props (cond-> (merge {:onEscapeKeyDown hide
-                                           :disableOutsideScroll false
-                                           :onPointerDownOutside hide}
-                                          content-props)
-                             (and (not force-popover?)
-                                  (not as-dropdown?))
-                             (assoc :on-key-down (fn [^js e]
-                                                   (some-> content-props :on-key-down (apply [e]))
-                                                   (set! (. e -defaultPrevented) true))
-                                    :on-pointer-move #(set! (. % -defaultPrevented) true)))
-             content (if (fn? content)
-                       (content (cond-> {:id id}
-                                  as-content?
-                                  (assoc :content-props content-props))) content)]
-         (if as-content?
-           content
-           (popup-content content-props content)))))))
+        (merge root-props {:open open?})
+        (popup-trigger
+          {:as-child true}
+          (button {:class "overflow-hidden fixed p-0 opacity-0"
+                   :style {:height (if (and (number? height)
+                                         (> height 0))
+                                     height 1)
+                           :width 1
+                           :top y
+                           :left x}} ""))
+        (let [content-props (cond-> (merge {:onEscapeKeyDown hide
+                                            :disableOutsideScroll false
+                                            :onPointerDownOutside hide}
+                                      content-props)
+                              (and (not force-popover?)
+                                (not as-dropdown?))
+                              (assoc :on-key-down (fn [^js e]
+                                                    (some-> content-props :on-key-down (apply [e]))
+                                                    (set! (. e -defaultPrevented) true))
+                                :on-pointer-move #(set! (. % -defaultPrevented) true)))
+              content (if (fn? content)
+                        (content (cond-> {:id id}
+                                   as-content?
+                                   (assoc :content-props content-props))) content)]
+          (if as-content?
+            content
+            (popup-content content-props content)))))))
 
 (rum/defc install-popups
   < rum/static

+ 11 - 10
src/main/frontend/components/container.cljs

@@ -700,14 +700,12 @@
 (defn- hide-context-menu-and-clear-selection
   [e]
   (state/hide-custom-context-menu!)
-  (let [block (.closest (.-target e) ".ls-block")]
-    (when-not (or (gobj/get e "shiftKey")
-                  (util/meta-key? e)
-                  (state/get-edit-input-id)
-                  (and block
-                       (or (= block (.-target e))
-                           (.contains block (.-target e)))))
-      (editor-handler/clear-selection!))))
+  (when-not (or (gobj/get e "shiftKey")
+              (util/meta-key? e)
+              (state/get-edit-input-id)
+              (some-> (.-target e) (.closest ".ls-block"))
+              (some-> (.-target e) (.closest "[data-keep-selection]")))
+    (editor-handler/clear-selection!)))
 
 (rum/defc render-custom-context-menu
   [links position]
@@ -837,8 +835,11 @@
                     (fn [content]
                       (shui/popup-show! e
                         (fn [{:keys [id]}]
-                          [:div {:on-click #(shui/popup-hide! id)} content])
-                        {:on-hide state/clear-selection!
+                          [:div {:on-click #(shui/popup-hide! id)
+                                 :data-keep-selection true}
+                           content])
+                        {:on-before-hide state/dom-clear-selection!
+                         :on-after-hide state/state-clear-selection!
                          :content-props {:class "w-[280px] ls-context-menu-content"}
                          :as-dropdown? true}))
 

+ 7 - 3
src/main/frontend/state.cljs

@@ -1151,7 +1151,7 @@ Similar to re-frame subscriptions"
   []
   (get-selected-block-ids (get-selection-blocks)))
 
-(defn- dom-clear-selection!
+(defn dom-clear-selection!
   []
   (doseq [node (dom/by-class "ls-block selected")]
     (dom/remove-class! node "selected")))
@@ -1190,15 +1190,19 @@ Similar to re-frame subscriptions"
   []
   (set-state! :selection/mode true))
 
-(defn clear-selection!
+(defn state-clear-selection!
   []
-  (dom-clear-selection!)
   (set-state! :selection/mode false)
   (set-state! :selection/blocks nil)
   (set-state! :selection/direction :down)
   (set-state! :selection/start-block nil)
   (set-state! :selection/selected-all? false))
 
+(defn clear-selection!
+  []
+  (dom-clear-selection!)
+  (state-clear-selection!))
+
 (defn get-selection-start-block-or-first
   []
   (or (get-selection-start-block)