diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index ac1e96b1b9..520113644b 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -2162,8 +2162,7 @@ (if collapsed? (editor-handler/expand-block! uuid) (editor-handler/collapse-block! uuid))) - (when (util/mobile?) - (haptics/haptics :light))) + (haptics/haptics)) ;; debug config context (when (and (state/developer-mode?) (.-metaKey event)) (js/console.debug "[block config]==" config)))} @@ -3007,22 +3006,6 @@ (swap! *hide-block-refs? not)))} [:span.text-sm block-refs-count'])])) -(rum/defc block-left-menu < rum/reactive - [_config {:block/keys [uuid] :as _block}] - [:div.block-left-menu.flex.bg-base-2.rounded-r-md.mr-1 - [:div.commands-button.w-0.rounded-r-md - {:id (str "block-left-menu-" uuid) - :style {:max-width 40}} - [:div.indent (ui/icon "indent-increase" {:size 18})]]]) - -(rum/defc block-right-menu < rum/reactive - [_config {:block/keys [uuid] :as _block}] - [:div.block-right-menu.flex.bg-base-2.rounded-md.ml-1 - [:div.commands-button.w-0.rounded-md - {:id (str "block-right-menu-" uuid) - :style {:max-width 40}} - [:div.outdent (ui/icon "indent-decrease" {:size 18})]]]) - (rum/defc block-content-with-error [config block edit-input-id block-id *show-query? editor-box] (let [[editing? set-editing!] (hooks/use-state false) @@ -3482,6 +3465,12 @@ ::hide-block-refs? (atom default-hide?) ::show-query? (atom false) ::refs-count *refs-count)))} + (mixins/event-mixin + (fn [state] + (let [*ref (::ref state)] + ;; React doesn't let us directly control passive via onTouchMove + ;; So here we listen `touchmove` on the block node + (mixins/listen state @*ref "touchmove" block-handler/on-touch-move)))) [state container-state repo config* block {:keys [navigating-block navigated? editing? selected?] :as opts}] (let [*ref (::ref state) *hide-block-refs? (get state ::hide-block-refs?) @@ -3524,8 +3513,6 @@ db-collapsed?) config (assoc config :collapsed? collapsed?) breadcrumb-show? (:breadcrumb-show? config) - *show-left-menu? (::show-block-left-menu? container-state) - *show-right-menu? (::show-block-right-menu? container-state) doc-mode? (:document/mode? config) embed? (:embed? config) page-embed? (:page-embed? config) @@ -3567,7 +3554,7 @@ :icon-props {:style {:width "1lh" :height "1lh" :font-size (if (:page-title? config) 38 18)}}})])))] - [:div.ls-block + [:div.ls-block.swipe-item (cond-> {:id (str "ls-block-" ;; container-id "-" @@ -3582,7 +3569,12 @@ (when order-list? " is-order-list") (when (string/blank? title) " is-blank") (when original-block " embed-block")) - :haschild (str (boolean has-child?))} + :haschild (str (boolean has-child?)) + :on-touch-start (fn [event uuid] (block-handler/on-touch-start event uuid)) + :on-touch-end (fn [event] + (block-handler/on-touch-end event)) + :on-touch-cancel (fn [e] + (block-handler/on-touch-cancel e))} (:property-default-value? config) (assoc :data-is-property-default-value (:property-default-value? config)) @@ -3619,13 +3611,6 @@ {:style (when (and db-based? (:page-title? config)) {:margin-left (if page-icon -36 -30)}) :data-has-heading (some-> block (pu/lookup :logseq.property/heading)) - :on-touch-start (fn [event uuid] (block-handler/on-touch-start event uuid)) - :on-touch-move (fn [event] - (block-handler/on-touch-move event block uuid editing? *show-left-menu? *show-right-menu?)) - :on-touch-end (fn [event] - (block-handler/on-touch-end event block uuid *show-left-menu? *show-right-menu?)) - :on-touch-cancel (fn [_e] - (block-handler/on-touch-cancel *show-left-menu? *show-right-menu?)) :on-mouse-enter (fn [e] (block-mouse-over e block *control-show? block-id doc-mode?)) :on-mouse-move (fn [e] @@ -3645,9 +3630,6 @@ :*control-show? *control-show? :edit? edit?})))) - (when (and @*show-left-menu? (not in-whiteboard?) (not (or table? property?))) - (block-left-menu config block)) - [:div.flex.flex-col.w-full [:div.block-main-content.flex.flex-row.gap-2 (when page-icon @@ -3672,10 +3654,7 @@ :*show-query? *show-query?}))])] (when (and db-based? (not collapsed?) (not (or table? property? (:page-title? config)))) - (block-positioned-properties config block :block-below))] - - (when (and @*show-right-menu? (not in-whiteboard?) (not (or table? property?))) - (block-right-menu config block))]) + (block-positioned-properties config block :block-below))]]) (when (and db-based? (not collapsed?) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index 78689eac4b..8feb4e3f7b 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -540,6 +540,11 @@ .ls-block { @apply flex-1 relative py-0.5 transition-[background-color] mx-auto; + width: 100%; + transform: translateX(0); + transition: transform 0.3s ease; + will-change: transform; + container-type: inline-size; container-name: ls-block; @@ -1141,3 +1146,7 @@ html.is-mac { @apply mb-2; } } + +.swipe-item { + touch-action: pan-y; /* disables horizontal scrolling on touch */ +} diff --git a/src/main/frontend/handler/block.cljs b/src/main/frontend/handler/block.cljs index af43ab1ba4..29148c8575 100644 --- a/src/main/frontend/handler/block.cljs +++ b/src/main/frontend/handler/block.cljs @@ -15,7 +15,6 @@ [frontend.state :as state] [frontend.util :as util] [frontend.util.file-based.drawer :as drawer] - [goog.dom :as gdom] [goog.object :as gobj] [logseq.db :as ldb] [logseq.db.sqlite.util :as sqlite-util] @@ -294,140 +293,92 @@ (defn on-touch-start [event uuid] - (let [target (.-target event) - input (state/get-input) + (util/stop-propagation event) + (let [input (state/get-input) input-id (state/get-edit-input-id) selection-type (.-type (.getSelection js/document))] (reset! *touch-start (js/Date.now)) (when-not (and input (string/ends-with? input-id (str uuid))) (state/clear-edit!)) - (when-not (target-disable-swipe? target) - (when (not= selection-type "Range") - (when-let [touches (.-targetTouches event)] - (when (= (.-length touches) 1) - (let [touch (aget touches 0) - x (.-clientX touch) - y (.-clientY touch)] - (reset! *swipe {:x0 x :y0 y :xi x :yi y :tx x :ty y :direction nil})))))))) + (when (not= selection-type "Range") + (when-let [touches (.-targetTouches event)] + (when (= (.-length touches) 1) + (let [touch (aget touches 0) + x (.-clientX touch) + y (.-clientY touch)] + (reset! *swipe {:x0 x :y0 y :xi x :yi y :tx x :ty y :direction nil}))))))) ;; FIXME: disable scroll (defn on-touch-move - [event block uuid edit? *show-left-menu? *show-right-menu?] - (when-let [touches (.-targetTouches event)] - (let [selection-type (.-type (.getSelection js/document))] - (when-not (= selection-type "Range") - (when (or (not (state/editing?)) - (< (- (js/Date.now) @*touch-start) 600)) - (when (and (= (.-length touches) 1) @*swipe) - (let [{:keys [x0 xi direction]} @*swipe - touch (aget touches 0) - tx (.-clientX touch) - ty (.-clientY touch) - direction (if (nil? direction) - (if (> tx x0) - :right - :left) - direction)] - (swap! *swipe #(-> % - (assoc :tx tx) - (assoc :ty ty) - (assoc :xi tx) - (assoc :yi ty) - (assoc :direction direction))) - (when (< (* (- xi x0) (- tx xi)) 0) + [^js goog-event] + (let [event (.-event_ goog-event)] + (when-let [touches (.-targetTouches event)] + (let [selection-type (.-type (.getSelection js/document)) + target (.-target event) + block-container (util/rec-get-node target "ls-block")] + (when-not (= selection-type "Range") + (when (or (not (state/editing?)) + (< (- (js/Date.now) @*touch-start) 600)) + (when (and (= (.-length touches) 1) @*swipe) + (let [{:keys [x0 xi direction]} @*swipe + touch (aget touches 0) + tx (.-clientX touch) + ty (.-clientY touch) + direction (if (nil? direction) + (if (> tx x0) + :right + :left) + direction)] (swap! *swipe #(-> % - (assoc :x0 tx) - (assoc :y0 ty)))) - (let [{:keys [x0 y0]} @*swipe - dx (- tx x0) - dy (- ty y0)] - (when (and (< (. js/Math abs dy) 30) - (> (. js/Math abs dx) 30)) - (let [left (gdom/getElement (str "block-left-menu-" uuid)) - right (gdom/getElement (str "block-right-menu-" uuid))] - - (cond - (= direction :right) - (do - (reset! *show-left-menu? true) - (when left - (when (>= dx 0) - (set! (.. left -style -width) (str dx "px"))) - (when (< dx 0) - (set! (.. left -style -width) (str (max (+ 40 dx) 0) "px"))) - - (let [indent (gdom/getFirstElementChild left)] - (when (indentable? block) - (if (>= (.-clientWidth left) 40) - (set! (.. indent -style -opacity) "100%") - (set! (.. indent -style -opacity) "30%")))))) - - (= direction :left) - (do - (reset! *show-right-menu? true) - (when right - (when (<= dx 0) - (set! (.. right -style -width) (str (- dx) "px"))) - (when (> dx 0) - (set! (.. right -style -width) (str (max (- 80 dx) 0) "px"))) - - (let [outdent (gdom/getFirstElementChild right) - more (when-not edit? - (gdom/getLastElementChild right))] - (when (and outdent (outdentable? block)) - (if (and (>= (.-clientWidth right) 40) - (< (.-clientWidth right) 80)) - (set! (.. outdent -style -opacity) "100%") - (set! (.. outdent -style -opacity) "30%"))) - - (when more - (if (>= (.-clientWidth right) 80) - (set! (.. more -style -opacity) "100%") - (set! (.. more -style -opacity) "30%")))))) - :else - nil))))))))))) + (assoc :tx tx) + (assoc :ty ty) + (assoc :xi tx) + (assoc :yi ty) + (assoc :direction direction))) + (when (< (* (- xi x0) (- tx xi)) 0) + (swap! *swipe #(-> % + (assoc :x0 tx) + (assoc :y0 ty)))) + (let [{:keys [x0 y0]} @*swipe + dx (- tx x0) + dy (- ty y0)] + (when (and (< (. js/Math abs dy) 30) + (> (. js/Math abs dx) 10) + direction) + (.preventDefault goog-event) + (let [left (if (= direction :right) + (if (>= dx 0) (min dx 60) (max dx 0)) + (if (<= dx 0) (- (min (js/Math.abs dx) 60)) (min dx 60)))] + (dom/set-style! block-container :transform (util/format "translateX(%dpx)" left))))))))))))) (defn on-touch-end - [_event block uuid *show-left-menu? *show-right-menu?] + [event] + (util/stop-propagation event) (when @*swipe - (let [left-menu (gdom/getElement (str "block-left-menu-" uuid)) - right-menu (gdom/getElement (str "block-right-menu-" uuid)) - {:keys [x0 tx]} @*swipe - dx (- tx x0)] + (let [target (.-target event) + {:keys [x0 y0 tx ty]} @*swipe + dy (- ty y0) + dx (- tx x0) + block-container (util/rec-get-node target "ls-block")] (try - (when (> (. js/Math abs dx) 10) - (cond - left-menu - (when (indentable? block) - (haptics/with-haptics-impact - (indent-outdent-blocks! [block] true nil) - :light)) + (when (and (> (. js/Math abs dx) (. js/Math abs dy)) + (> (. js/Math abs dx) 10)) + (dom/set-style! block-container :transform "translateX(0)") + (state/exit-editing-and-set-selected-blocks! [block-container]) + (haptics/haptics) - right-menu - (when (outdentable? block) - (haptics/with-haptics-impact - (indent-outdent-blocks! [block] false nil) - :light)) - -;; TODO: long press to select ;; (haptics/with-haptics-impact ;; (do (state/set-state! :mobile/show-action-bar? true) ;; (state/set-state! :mobile/actioned-block block) ;; (select-block! uuid)) ;; :light) - - :else - nil)) + ) (catch :default e (js/console.error e)) (finally - (reset! *show-left-menu? false) - (reset! *show-right-menu? false) (reset! *swipe nil)))))) (defn on-touch-cancel - [*show-left-menu? *show-right-menu?] - (reset! *show-left-menu? false) - (reset! *show-right-menu? false) + [_e] (reset! *swipe nil)) diff --git a/src/main/frontend/mobile/haptics.cljs b/src/main/frontend/mobile/haptics.cljs index ac5f74fd85..0dfecfe433 100644 --- a/src/main/frontend/mobile/haptics.cljs +++ b/src/main/frontend/mobile/haptics.cljs @@ -1,20 +1,17 @@ (ns frontend.mobile.haptics (:require ["@capacitor/haptics" :refer [Haptics ImpactStyle]] - [promesa.core :as p])) + [frontend.util :as util])) (defn haptics - [impact-style] - (let [style (cond - (= impact-style :light) - {:style (.-Light ImpactStyle)} + ([] + (haptics :light)) + ([impact-style] + (when util/capacitor-new? + (let [style (cond + (= impact-style :light) + {:style (.-Light ImpactStyle)} - (= impact-style :medium) - {:style (.-Medium ImpactStyle)})] - (.impact Haptics (clj->js style)))) - -(defn with-haptics-impact - [result impact-style] - (p/do! - (haptics impact-style) - result)) + (= impact-style :medium) + {:style (.-Medium ImpactStyle)})] + (.impact Haptics (clj->js style))))))