Compare commits
1 Commits
dev
...
regression-safari
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a915eb71c |
@@ -28,7 +28,7 @@ import {
|
|||||||
import type {TrustedEvent, Filter, List} from "@welshman/util"
|
import type {TrustedEvent, Filter, List} from "@welshman/util"
|
||||||
import {load, request, mergeRepositoryUpdates} from "@welshman/net"
|
import {load, request, mergeRepositoryUpdates} from "@welshman/net"
|
||||||
import type {RepositoryUpdate} 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 {createScroller} from "@lib/html"
|
||||||
import {daysBetween} from "@lib/util"
|
import {daysBetween} from "@lib/util"
|
||||||
import {getEventsForUrl} from "@app/core/state"
|
import {getEventsForUrl} from "@app/core/state"
|
||||||
@@ -41,6 +41,7 @@ export const makeFeed = ({
|
|||||||
element,
|
element,
|
||||||
onBackwardExhausted,
|
onBackwardExhausted,
|
||||||
onForwardExhausted,
|
onForwardExhausted,
|
||||||
|
allowOptimisticSelfEvents = false,
|
||||||
at = now(),
|
at = now(),
|
||||||
}: {
|
}: {
|
||||||
url: string
|
url: string
|
||||||
@@ -48,6 +49,7 @@ export const makeFeed = ({
|
|||||||
element: HTMLElement
|
element: HTMLElement
|
||||||
onBackwardExhausted?: () => void
|
onBackwardExhausted?: () => void
|
||||||
onForwardExhausted?: () => void
|
onForwardExhausted?: () => void
|
||||||
|
allowOptimisticSelfEvents?: boolean
|
||||||
at?: number
|
at?: number
|
||||||
}) => {
|
}) => {
|
||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
@@ -113,7 +115,15 @@ export const makeFeed = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const matching = added.filter(
|
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) {
|
if (matching.length > 0) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
import InfoCircle from "@assets/icons/info-circle.svg?dataurl"
|
import InfoCircle from "@assets/icons/info-circle.svg?dataurl"
|
||||||
import Login2 from "@assets/icons/login-3.svg?dataurl"
|
import Login2 from "@assets/icons/login-3.svg?dataurl"
|
||||||
import cx from "classnames"
|
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 Button from "@lib/components/Button.svelte"
|
||||||
import Divider from "@lib/components/Divider.svelte"
|
import Divider from "@lib/components/Divider.svelte"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
@@ -246,6 +246,7 @@
|
|||||||
if (!isProgrammaticScroll) {
|
if (!isProgrammaticScroll) {
|
||||||
userHasScrolled = true
|
userHasScrolled = true
|
||||||
isUserScrolling = true
|
isUserScrolling = true
|
||||||
|
wasAtBottom = !element || Math.abs(element.scrollTop) < 100
|
||||||
clearIsUserScrolling()
|
clearIsUserScrolling()
|
||||||
manageScrollPosition()
|
manageScrollPosition()
|
||||||
}
|
}
|
||||||
@@ -281,6 +282,7 @@
|
|||||||
let events: Readable<TrustedEvent[]> = $state(readable([]))
|
let events: Readable<TrustedEvent[]> = $state(readable([]))
|
||||||
let compose: RoomCompose | undefined = $state()
|
let compose: RoomCompose | undefined = $state()
|
||||||
let eventToEdit: TrustedEvent | undefined = $state()
|
let eventToEdit: TrustedEvent | undefined = $state()
|
||||||
|
let wasAtBottom = true
|
||||||
|
|
||||||
const clearIsUserScrolling = debounce(150, () => {
|
const clearIsUserScrolling = debounce(150, () => {
|
||||||
isUserScrolling = false
|
isUserScrolling = false
|
||||||
@@ -359,8 +361,20 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (elements.length > 0 && !isUserScrolling) {
|
if (elements.length > 0) {
|
||||||
requestAnimationFrame(manageScrollPosition)
|
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,
|
url,
|
||||||
at: at || now(),
|
at: at || now(),
|
||||||
element: element!,
|
element: element!,
|
||||||
|
allowOptimisticSelfEvents: true,
|
||||||
filters: [{kinds: [MESSAGE, ROOM_ADD_MEMBER], "#h": [h]}],
|
filters: [{kinds: [MESSAGE, ROOM_ADD_MEMBER], "#h": [h]}],
|
||||||
onBackwardExhausted: () => {
|
onBackwardExhausted: () => {
|
||||||
loadingBackward = false
|
loadingBackward = false
|
||||||
@@ -404,7 +419,7 @@
|
|||||||
onMount(() => {
|
onMount(() => {
|
||||||
start()
|
start()
|
||||||
|
|
||||||
return cleanup
|
return () => cleanup?.()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -496,7 +511,7 @@
|
|||||||
{#if event.kind === ROOM_ADD_MEMBER}
|
{#if event.kind === ROOM_ADD_MEMBER}
|
||||||
<RoomItemAddMember {url} {event} />
|
<RoomItemAddMember {url} {event} />
|
||||||
{:else}
|
{:else}
|
||||||
<div in:slide class="cv">
|
<div>
|
||||||
<RoomItem
|
<RoomItem
|
||||||
{url}
|
{url}
|
||||||
{event}
|
{event}
|
||||||
|
|||||||
@@ -141,6 +141,7 @@
|
|||||||
if (!isProgrammaticScroll) {
|
if (!isProgrammaticScroll) {
|
||||||
userHasScrolled = true
|
userHasScrolled = true
|
||||||
isUserScrolling = true
|
isUserScrolling = true
|
||||||
|
wasAtBottom = !element || Math.abs(element.scrollTop) < 100
|
||||||
clearIsUserScrolling()
|
clearIsUserScrolling()
|
||||||
manageScrollPosition()
|
manageScrollPosition()
|
||||||
}
|
}
|
||||||
@@ -174,6 +175,7 @@
|
|||||||
let events: Readable<TrustedEvent[]> = $state(readable([]))
|
let events: Readable<TrustedEvent[]> = $state(readable([]))
|
||||||
let compose: RoomCompose | undefined = $state()
|
let compose: RoomCompose | undefined = $state()
|
||||||
let eventToEdit: TrustedEvent | undefined = $state()
|
let eventToEdit: TrustedEvent | undefined = $state()
|
||||||
|
let wasAtBottom = true
|
||||||
|
|
||||||
const clearIsUserScrolling = debounce(150, () => {
|
const clearIsUserScrolling = debounce(150, () => {
|
||||||
isUserScrolling = false
|
isUserScrolling = false
|
||||||
@@ -252,8 +254,20 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (elements.length > 0 && !isUserScrolling) {
|
if (elements.length > 0) {
|
||||||
requestAnimationFrame(manageScrollPosition)
|
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,
|
url,
|
||||||
at: at || now(),
|
at: at || now(),
|
||||||
element: element!,
|
element: element!,
|
||||||
|
allowOptimisticSelfEvents: true,
|
||||||
filters: [{kinds: [MESSAGE, RELAY_ADD_MEMBER]}],
|
filters: [{kinds: [MESSAGE, RELAY_ADD_MEMBER]}],
|
||||||
onBackwardExhausted: () => {
|
onBackwardExhausted: () => {
|
||||||
loadingBackward = false
|
loadingBackward = false
|
||||||
@@ -297,7 +312,7 @@
|
|||||||
onMount(() => {
|
onMount(() => {
|
||||||
start()
|
start()
|
||||||
|
|
||||||
return cleanup
|
return () => cleanup?.()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user