Toggle minimal shell on any scroll for web (#2499)

zio/stable
dan 2024-01-11 18:44:56 +00:00 committed by GitHub
parent 3662259c5b
commit b147f7ae8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 47 additions and 42 deletions

View File

@ -3,9 +3,11 @@ import {ScrollProvider} from '#/lib/ScrollContext'
import {NativeScrollEvent} from 'react-native'
import {useSetMinimalShellMode, useMinimalShellMode} from '#/state/shell'
import {useShellLayout} from '#/state/shell/shell-layout'
import {isWeb} from 'platform/detection'
import {isNative} from 'platform/detection'
import {useSharedValue, interpolate} from 'react-native-reanimated'
const WEB_HIDE_SHELL_THRESHOLD = 200
function clamp(num: number, min: number, max: number) {
'worklet'
return Math.min(Math.max(num, min), max)
@ -21,8 +23,10 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
const onBeginDrag = useCallback(
(e: NativeScrollEvent) => {
'worklet'
if (isNative) {
startDragOffset.value = e.contentOffset.y
startMode.value = mode.value
}
},
[mode, startDragOffset, startMode],
)
@ -30,6 +34,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
const onEndDrag = useCallback(
(e: NativeScrollEvent) => {
'worklet'
if (isNative) {
startDragOffset.value = null
startMode.value = null
if (e.contentOffset.y < headerHeight.value / 2) {
@ -39,6 +44,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
// Snap to whichever state is the closest.
setMode(Math.round(mode.value) === 1)
}
}
},
[startDragOffset, startMode, setMode, mode, headerHeight],
)
@ -46,18 +52,12 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
const onScroll = useCallback(
(e: NativeScrollEvent) => {
'worklet'
if (isNative) {
if (startDragOffset.value === null || startMode.value === null) {
if (mode.value !== 0 && e.contentOffset.y < headerHeight.value) {
// If we're close enough to the top, always show the shell.
// Even if we're not dragging.
setMode(false)
return
}
if (isWeb) {
// On the web, there is no concept of "starting" the drag.
// When we get the first scroll event, we consider that the start.
startDragOffset.value = e.contentOffset.y
startMode.value = mode.value
}
return
}
@ -75,12 +75,17 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
// Manually adjust the value. This won't be (and shouldn't be) animated.
mode.value = newValue
}
if (isWeb) {
// On the web, there is no concept of "starting" the drag,
// so we don't have any specific anchor point to calculate the distance.
// Instead, update it continuosly along the way and diff with the last event.
} else {
// On the web, we don't try to follow the drag because we don't know when it ends.
// Instead, show/hide immediately based on whether we're scrolling up or down.
const dy = e.contentOffset.y - (startDragOffset.value ?? 0)
startDragOffset.value = e.contentOffset.y
startMode.value = mode.value
if (dy < 0 || e.contentOffset.y < WEB_HIDE_SHELL_THRESHOLD) {
setMode(false)
} else if (dy > 0) {
setMode(true)
}
}
},
[headerHeight, mode, setMode, startDragOffset, startMode],