forked from
jollywhoppers.com/witchsky.app
fork
Configure Feed
Select the types of activity you want to include in your feed.
Bluesky app fork with some witchin' additions 馃挮
fork
Configure Feed
Select the types of activity you want to include in your feed.
1import {useEffect, useMemo, useState} from 'react'
2import {type EventArg, useNavigation} from '@react-navigation/core'
3
4if ('scrollRestoration' in history) {
5 // Tell the brower not to mess with the scroll.
6 // We're doing that manually below.
7 history.scrollRestoration = 'manual'
8}
9
10function createInitialScrollState() {
11 return {
12 scrollYs: new Map(),
13 focusedKey: null as string | null,
14 }
15}
16
17export function useWebScrollRestoration() {
18 const [state] = useState(createInitialScrollState)
19 const navigation = useNavigation()
20
21 useEffect(() => {
22 function onDispatch() {
23 if (state.focusedKey) {
24 // Remember where we were for later.
25 state.scrollYs.set(state.focusedKey, window.scrollY)
26 // TODO: Strictly speaking, this is a leak. We never clean up.
27 // This is because I'm not sure when it's appropriate to clean it up.
28 // It doesn't seem like popstate is enough because it can still Forward-Back again.
29 // Maybe we should use sessionStorage. Or check what Next.js is doing?
30 }
31 }
32 // We want to intercept any push/pop/replace *before* the re-render.
33 // There is no official way to do this yet, but this works okay for now.
34 // https://twitter.com/satya164/status/1737301243519725803
35 navigation.addListener('__unsafe_action__' as any, onDispatch)
36 return () => {
37 navigation.removeListener('__unsafe_action__' as any, onDispatch)
38 }
39 }, [state, navigation])
40
41 const screenListeners = useMemo(
42 () => ({
43 focus(e: EventArg<'focus', boolean | undefined, unknown>) {
44 const scrollY = state.scrollYs.get(e.target) ?? 0
45 window.scrollTo(0, scrollY)
46 state.focusedKey = e.target ?? null
47 },
48 }),
49 [state],
50 )
51 return screenListeners
52}