fix: safari chat regressions

This commit is contained in:
2026-04-22 18:51:12 +05:45
parent 976ccdabd4
commit 7a915eb71c
3 changed files with 50 additions and 10 deletions
+12 -2
View File
@@ -28,7 +28,7 @@ import {
import type {TrustedEvent, Filter, List} from "@welshman/util"
import {load, request, mergeRepositoryUpdates} from "@welshman/net"
import type {RepositoryUpdate} from "@welshman/net"
import {repository, loadRelay, tracker} from "@welshman/app"
import {pubkey, repository, loadRelay, tracker} from "@welshman/app"
import {createScroller} from "@lib/html"
import {daysBetween} from "@lib/util"
import {getEventsForUrl} from "@app/core/state"
@@ -41,6 +41,7 @@ export const makeFeed = ({
element,
onBackwardExhausted,
onForwardExhausted,
allowOptimisticSelfEvents = false,
at = now(),
}: {
url: string
@@ -48,6 +49,7 @@ export const makeFeed = ({
element: HTMLElement
onBackwardExhausted?: () => void
onForwardExhausted?: () => void
allowOptimisticSelfEvents?: boolean
at?: number
}) => {
const controller = new AbortController()
@@ -113,7 +115,15 @@ export const makeFeed = ({
}
const matching = added.filter(
event => matchFilters(filters, event) && tracker.getRelays(event.id).has(url),
event =>
matchFilters(filters, event) &&
(tracker.getRelays(event.id).has(url) ||
// In Safari, relay confirmation can lag behind local repository updates.
// Only enable this for chat-like feeds that explicitly opt in.
(allowOptimisticSelfEvents &&
event.pubkey === pubkey.get() &&
tracker.getRelays(event.id).size === 0 &&
event.created_at >= now() - 60)),
)
if (matching.length > 0) {
+20 -5
View File
@@ -15,7 +15,7 @@
import InfoCircle from "@assets/icons/info-circle.svg?dataurl"
import Login2 from "@assets/icons/login-3.svg?dataurl"
import cx from "classnames"
import {slide, fade, fly} from "@lib/transition"
import {fade, fly} from "@lib/transition"
import Button from "@lib/components/Button.svelte"
import Divider from "@lib/components/Divider.svelte"
import Icon from "@lib/components/Icon.svelte"
@@ -246,6 +246,7 @@
if (!isProgrammaticScroll) {
userHasScrolled = true
isUserScrolling = true
wasAtBottom = !element || Math.abs(element.scrollTop) < 100
clearIsUserScrolling()
manageScrollPosition()
}
@@ -281,6 +282,7 @@
let events: Readable<TrustedEvent[]> = $state(readable([]))
let compose: RoomCompose | undefined = $state()
let eventToEdit: TrustedEvent | undefined = $state()
let wasAtBottom = true
const clearIsUserScrolling = debounce(150, () => {
isUserScrolling = false
@@ -359,8 +361,20 @@
})
$effect(() => {
if (elements.length > 0 && !isUserScrolling) {
requestAnimationFrame(manageScrollPosition)
if (elements.length > 0) {
requestAnimationFrame(() => {
// Safari does not implement CSS scroll anchoring for flex-col-reverse.
// When a new message is inserted, Safari shifts scrollTop upward to preserve
// visual position rather than keeping it pinned at 0 (visual bottom).
// Snap back to 0 whenever the user was at the bottom before the update.
if (element && isNaN(at) && wasAtBottom) {
isProgrammaticScroll = true
element.scrollTop = 0
}
if (!isUserScrolling) {
manageScrollPosition()
}
})
}
})
@@ -371,6 +385,7 @@
url,
at: at || now(),
element: element!,
allowOptimisticSelfEvents: true,
filters: [{kinds: [MESSAGE, ROOM_ADD_MEMBER], "#h": [h]}],
onBackwardExhausted: () => {
loadingBackward = false
@@ -404,7 +419,7 @@
onMount(() => {
start()
return cleanup
return () => cleanup?.()
})
</script>
@@ -496,7 +511,7 @@
{#if event.kind === ROOM_ADD_MEMBER}
<RoomItemAddMember {url} {event} />
{:else}
<div in:slide class="cv">
<div>
<RoomItem
{url}
{event}
+18 -3
View File
@@ -141,6 +141,7 @@
if (!isProgrammaticScroll) {
userHasScrolled = true
isUserScrolling = true
wasAtBottom = !element || Math.abs(element.scrollTop) < 100
clearIsUserScrolling()
manageScrollPosition()
}
@@ -174,6 +175,7 @@
let events: Readable<TrustedEvent[]> = $state(readable([]))
let compose: RoomCompose | undefined = $state()
let eventToEdit: TrustedEvent | undefined = $state()
let wasAtBottom = true
const clearIsUserScrolling = debounce(150, () => {
isUserScrolling = false
@@ -252,8 +254,20 @@
})
$effect(() => {
if (elements.length > 0 && !isUserScrolling) {
requestAnimationFrame(manageScrollPosition)
if (elements.length > 0) {
requestAnimationFrame(() => {
// Safari does not implement CSS scroll anchoring for flex-col-reverse.
// When a new message is inserted, Safari shifts scrollTop upward to preserve
// visual position rather than keeping it pinned at 0 (visual bottom).
// Snap back to 0 whenever the user was at the bottom before the update.
if (element && isNaN(at) && wasAtBottom) {
isProgrammaticScroll = true
element.scrollTop = 0
}
if (!isUserScrolling) {
manageScrollPosition()
}
})
}
})
@@ -264,6 +278,7 @@
url,
at: at || now(),
element: element!,
allowOptimisticSelfEvents: true,
filters: [{kinds: [MESSAGE, RELAY_ADD_MEMBER]}],
onBackwardExhausted: () => {
loadingBackward = false
@@ -297,7 +312,7 @@
onMount(() => {
start()
return cleanup
return () => cleanup?.()
})
</script>