From f57ed6a76373847ef76cbdac99025aa426d23e4e Mon Sep 17 00:00:00 2001 From: Aitor Date: Thu, 13 Jul 2023 10:21:45 +0200 Subject: [PATCH] :sparkles: Set smooth/instant autoscroll depending on distance --- CHANGES.md | 1 + .../main/ui/workspace/sidebar/layer_item.cljs | 22 ++++++++----- frontend/src/app/util/dom.cljs | 32 ++++++++++++++++++- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7ee9836bd..b4a585382 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,7 @@ - Add the ability to use the registration whitelist with OICD [Github #3348](https://github.com/penpot/penpot/issues/3348) - Add support for local caching of google fonts (this avoids exposing the final user IP to goolge and reduces the amount of request sent to google) +- Set smooth/instant autoscroll depending on distance [GitHub #3377](https://github.com/penpot/penpot/issues/3377) ### :bug: Bugs fixed diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index 985095337..fae77ac02 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -170,22 +170,28 @@ (mf/with-effect [selected? selected] (let [single? (= (count selected) 1) node (mf/ref-val ref) - parent-node (dom/get-parent (dom/get-parent node)) + ;; NOTE: Neither get-parent-at nor get-parent-with-selector + ;; work if the component template changes, so we need to + ;; seek for an alternate solution. Maybe use-context? + scroll-node (dom/get-parent-with-selector node ".tool-window-content") + parent-node (dom/get-parent-at node 2) subid (when (and single? selected?) (let [scroll-to @scroll-to-middle?] (ts/schedule 100 - #(if scroll-to - (dom/scroll-into-view! parent-node #js {:block "center" :behavior "smooth" :inline "start"}) - (do - (dom/scroll-into-view-if-needed! parent-node #js {:block "center" :behavior "smooth" :inline "start"}) - (reset! scroll-to-middle? true))))))] + #(let [scroll-distance-ratio (dom/get-scroll-distance-ratio node scroll-node) + scroll-behavior (if (> scroll-distance-ratio 1) "instant" "smooth")] + (if scroll-to + (dom/scroll-into-view! parent-node #js {:block "center" :behavior scroll-behavior :inline "start"}) + (do + (dom/scroll-into-view-if-needed! parent-node #js {:block "center" :behavior scroll-behavior :inline "start"}) + (reset! scroll-to-middle? true)))))))] #(when (some? subid) (rx/dispose! subid)))) - + (if new-css-system [:* [:div {:on-context-menu on-context-menu @@ -343,4 +349,4 @@ :index index :objects objects :key (:id item) - :sortable? sortable?}]))])]))) \ No newline at end of file + :sortable? sortable?}]))])]))) diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index 0e670e05d..535d7a0d0 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -143,9 +143,16 @@ (when (some? node) (.-parentElement ^js node))) +(defn get-parent-at + [^js node count] + (when (some? node) + (loop [current node current-count count] + (if (or (nil? current) (= current-count 0)) + current + (recur (.-parentElement current) (dec current-count)))))) + (defn get-parent-with-selector [^js node selector] - (loop [current node] (if (or (nil? current) (.matches current selector)) current @@ -180,6 +187,22 @@ :scroll-top (.-scrollTop event) :scroll-width (.-scrollWidth event)})) +(defn get-scroll-height-ratio + [^js node] + (when (some? node) + (/ (.-scrollHeight node) (.-clientHeight node)))) + +(defn get-scroll-distance + [^js node scroll-node] + (when (and (some? node) (some? scroll-node)) + (abs (- (.-scrollTop scroll-node) (.-offsetTop node))))) + +(defn get-scroll-distance-ratio + [^js node scroll-node] + (let [distance (get-scroll-distance node scroll-node) + height (.-clientHeight scroll-node)] + (/ distance height))) + (def get-target-val (comp get-value get-target)) (def get-target-scroll (comp get-scroll-position get-target)) @@ -550,6 +573,13 @@ (when (some? element) (.scrollIntoView element options)))) +;; NOTE: scrollIntoViewIfNeeded is not supported in Firefox +;; because it is not a standard API. BTW it only supports +;; centerIfNeeded as boolean option. +;; @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded +;; @see https://www.w3.org/Bugs/Public/show_bug.cgi?id=17152 +;; @see https://github.com/w3c/csswg-drafts/pull/1805 +;; @see https://github.com/w3c/csswg-drafts/pull/5677 (defn scroll-into-view-if-needed! ([^js element] (scroll-into-view-if-needed! element false))