fix(chat): suppress programmatic scroll while user is scrolling (#132) (#216)

Co-authored-by: 1amKhush <khushvendras99@gmail.com>
Co-committed-by: 1amKhush <khushvendras99@gmail.com>
This commit was merged in pull request #216.
This commit is contained in:
2026-04-16 23:20:17 +00:00
committed by hodlbod
parent 59961cbdb5
commit 4a967de184
2 changed files with 18 additions and 2 deletions
+9 -1
View File
@@ -4,6 +4,7 @@
import {page} from "$app/stores" import {page} from "$app/stores"
import {goto} from "$app/navigation" import {goto} from "$app/navigation"
import type {Readable} from "svelte/store" import type {Readable} from "svelte/store"
import {debounce} from "throttle-debounce"
import {pubkey, publishThunk, waitForThunkError, joinRoom, leaveRoom} from "@welshman/app" import {pubkey, publishThunk, waitForThunkError, joinRoom, leaveRoom} from "@welshman/app"
import {now, ifLet, int, formatTimestampAsDate, ago, MINUTE} from "@welshman/lib" import {now, ifLet, int, formatTimestampAsDate, ago, MINUTE} from "@welshman/lib"
import type {MakeNonOptional} from "@welshman/lib" import type {MakeNonOptional} from "@welshman/lib"
@@ -244,6 +245,8 @@
const onScroll = () => { const onScroll = () => {
if (!isProgrammaticScroll) { if (!isProgrammaticScroll) {
userHasScrolled = true userHasScrolled = true
isUserScrolling = true
clearIsUserScrolling()
manageScrollPosition() manageScrollPosition()
} }
@@ -265,6 +268,7 @@
let leaving = $state(false) let leaving = $state(false)
let userHasScrolled = $state(false) let userHasScrolled = $state(false)
let isProgrammaticScroll = $state(false) let isProgrammaticScroll = $state(false)
let isUserScrolling = $state(false)
let loadingBackward = $state(true) let loadingBackward = $state(true)
let loadingForward = $state(true) let loadingForward = $state(true)
let share = $state(popKey<TrustedEvent | undefined>("share")) let share = $state(popKey<TrustedEvent | undefined>("share"))
@@ -278,6 +282,10 @@
let compose: RoomCompose | undefined = $state() let compose: RoomCompose | undefined = $state()
let eventToEdit: TrustedEvent | undefined = $state() let eventToEdit: TrustedEvent | undefined = $state()
const clearIsUserScrolling = debounce(150, () => {
isUserScrolling = false
})
const elements = $derived.by(() => { const elements = $derived.by(() => {
const elements = [] const elements = []
const seen = new Set() const seen = new Set()
@@ -351,7 +359,7 @@
}) })
$effect(() => { $effect(() => {
if (elements.length > 0) { if (elements.length > 0 && !isUserScrolling) {
requestAnimationFrame(manageScrollPosition) requestAnimationFrame(manageScrollPosition)
} }
}) })
+9 -1
View File
@@ -4,6 +4,7 @@
import {goto} from "$app/navigation" import {goto} from "$app/navigation"
import type {Readable} from "svelte/store" import type {Readable} from "svelte/store"
import {readable} from "svelte/store" import {readable} from "svelte/store"
import {debounce} from "throttle-debounce"
import {now, int, ifLet, formatTimestampAsDate, MINUTE, ago} from "@welshman/lib" import {now, int, ifLet, formatTimestampAsDate, MINUTE, ago} from "@welshman/lib"
import type {TrustedEvent, EventContent} from "@welshman/util" import type {TrustedEvent, EventContent} from "@welshman/util"
import {makeEvent, MESSAGE, RELAY_ADD_MEMBER} from "@welshman/util" import {makeEvent, MESSAGE, RELAY_ADD_MEMBER} from "@welshman/util"
@@ -139,6 +140,8 @@
const onScroll = () => { const onScroll = () => {
if (!isProgrammaticScroll) { if (!isProgrammaticScroll) {
userHasScrolled = true userHasScrolled = true
isUserScrolling = true
clearIsUserScrolling()
manageScrollPosition() manageScrollPosition()
} }
@@ -160,6 +163,7 @@
let loadingForward = $state(true) let loadingForward = $state(true)
let userHasScrolled = $state(false) let userHasScrolled = $state(false)
let isProgrammaticScroll = $state(false) let isProgrammaticScroll = $state(false)
let isUserScrolling = $state(false)
let share = $state(popKey<TrustedEvent | undefined>("share")) let share = $state(popKey<TrustedEvent | undefined>("share"))
let parent: TrustedEvent | undefined = $state() let parent: TrustedEvent | undefined = $state()
let element: HTMLElement | undefined = $state() let element: HTMLElement | undefined = $state()
@@ -171,6 +175,10 @@
let compose: RoomCompose | undefined = $state() let compose: RoomCompose | undefined = $state()
let eventToEdit: TrustedEvent | undefined = $state() let eventToEdit: TrustedEvent | undefined = $state()
const clearIsUserScrolling = debounce(150, () => {
isUserScrolling = false
})
const elements = $derived.by(() => { const elements = $derived.by(() => {
const elements = [] const elements = []
const seen = new Set() const seen = new Set()
@@ -244,7 +252,7 @@
}) })
$effect(() => { $effect(() => {
if (elements.length > 0) { if (elements.length > 0 && !isUserScrolling) {
requestAnimationFrame(manageScrollPosition) requestAnimationFrame(manageScrollPosition)
} }
}) })