Adam 1 месяц назад
Родитель
Сommit
5053822bd6
1 измененных файлов с 62 добавлено и 11 удалено
  1. 62 11
      packages/ui/src/hooks/create-auto-scroll.tsx

+ 62 - 11
packages/ui/src/hooks/create-auto-scroll.tsx

@@ -11,6 +11,8 @@ export function createAutoScroll(options: AutoScrollOptions) {
   let scroll: HTMLElement | undefined
   let settling = false
   let settleTimer: ReturnType<typeof setTimeout> | undefined
+  let down = false
+  let cleanup: (() => void) | undefined
 
   const [store, setStore] = createStore({
     contentRef: undefined as HTMLElement | undefined,
@@ -45,8 +47,43 @@ export function createAutoScroll(options: AutoScrollOptions) {
     scrollToBottomNow(behavior)
   }
 
+  const stop = () => {
+    if (!active()) return
+    if (store.userScrolled) return
+
+    setStore("userScrolled", true)
+    options.onUserInteracted?.()
+  }
+
+  const handleWheel = (e: WheelEvent) => {
+    if (e.deltaY >= 0) return
+    stop()
+  }
+
+  const handlePointerUp = () => {
+    down = false
+    window.removeEventListener("pointerup", handlePointerUp)
+  }
+
+  const handlePointerDown = () => {
+    if (down) return
+    down = true
+    window.addEventListener("pointerup", handlePointerUp)
+  }
+
+  const handleTouchEnd = () => {
+    down = false
+    window.removeEventListener("touchend", handleTouchEnd)
+  }
+
+  const handleTouchStart = () => {
+    if (down) return
+    down = true
+    window.addEventListener("touchend", handleTouchEnd)
+  }
+
   const handleScroll = () => {
-    if (!options.working()) return
+    if (!active()) return
     if (!scroll) return
 
     if (distanceFromBottom() < 10) {
@@ -54,18 +91,11 @@ export function createAutoScroll(options: AutoScrollOptions) {
       return
     }
 
-    if (store.userScrolled) return
-
-    setStore("userScrolled", true)
-    options.onUserInteracted?.()
+    if (down) stop()
   }
 
   const handleInteraction = () => {
-    if (!options.working()) return
-    if (store.userScrolled) return
-
-    setStore("userScrolled", true)
-    options.onUserInteracted?.()
+    stop()
   }
 
   createResizeObserver(
@@ -99,12 +129,33 @@ export function createAutoScroll(options: AutoScrollOptions) {
 
   onCleanup(() => {
     if (settleTimer) clearTimeout(settleTimer)
+    if (cleanup) cleanup()
   })
 
   return {
     scrollRef: (el: HTMLElement | undefined) => {
+      if (cleanup) {
+        cleanup()
+        cleanup = undefined
+      }
+
       scroll = el
-      if (el) el.style.overflowAnchor = "none"
+      down = false
+
+      if (!el) return
+
+      el.style.overflowAnchor = "none"
+      el.addEventListener("wheel", handleWheel, { passive: true })
+      el.addEventListener("pointerdown", handlePointerDown)
+      el.addEventListener("touchstart", handleTouchStart, { passive: true })
+
+      cleanup = () => {
+        el.removeEventListener("wheel", handleWheel)
+        el.removeEventListener("pointerdown", handlePointerDown)
+        el.removeEventListener("touchstart", handleTouchStart)
+        window.removeEventListener("pointerup", handlePointerUp)
+        window.removeEventListener("touchend", handleTouchEnd)
+      }
     },
     contentRef: (el: HTMLElement | undefined) => setStore("contentRef", el),
     handleScroll,