diff --git a/CHANGES.md b/CHANGES.md index c70c72bdd..abc3e4222 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -31,6 +31,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 aea655edc..9fd49134f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -185,19 +185,25 @@ (mf/with-effect [selected? selected] (let [single? (= (count selected) 1) - node (mf/ref-val ref) - parent (dom/get-parent (dom/get-parent node)) + node (mf/ref-val ref) + ;; 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 {:block "center" :behavior "smooth" :inline "start"}) - (do - (dom/scroll-into-view-if-needed! parent {: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)))) diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index c9babc26d..73fc9bfeb 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -158,9 +158,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 @@ -195,6 +202,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)) @@ -573,6 +596,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))