From ba42f290b3c07184dee0df265185b6f512a296d0 Mon Sep 17 00:00:00 2001 From: Hailey Date: Sun, 5 May 2024 05:05:43 -0700 Subject: [PATCH] foolproof the logic --- src/view/com/util/List.web.tsx | 116 ++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 46 deletions(-) diff --git a/src/view/com/util/List.web.tsx b/src/view/com/util/List.web.tsx index e481ee4f66..ba2547f642 100644 --- a/src/view/com/util/List.web.tsx +++ b/src/view/com/util/List.web.tsx @@ -1,5 +1,6 @@ import React, {isValidElement, memo, startTransition, useRef} from 'react' import {FlatListProps, StyleSheet, View, ViewProps} from 'react-native' +import {ReanimatedScrollEvent} from 'react-native-reanimated/lib/typescript/reanimated2/hook/commonTypes' import {batchedUpdates} from '#/lib/batchedUpdates' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' @@ -87,9 +88,48 @@ function ListImpl( const getScrollableNode = React.useCallback(() => { if (containWeb) { - return nativeRef.current as HTMLDivElement | null + if (!nativeRef.current) return null + return { + scrollWidth: nativeRef.current?.scrollWidth, + scrollHeight: nativeRef.current?.scrollHeight, + clientWidth: nativeRef.current?.clientWidth, + clientHeight: nativeRef.current?.clientHeight, + scrollY: nativeRef.current?.scrollTop, + scrollX: nativeRef.current?.scrollLeft, + scrollTo(options?: ScrollToOptions) { + nativeRef.current?.scrollTo(options) + }, + scrollBy(options: ScrollToOptions) { + nativeRef.current?.scrollBy(options) + }, + addEventListener(event: string, handler: any) { + nativeRef.current?.addEventListener(event, handler) + }, + removeEventListener(event: string, handler: any) { + nativeRef.current?.removeEventListener(event, handler) + }, + } } else { - return window + return { + scrollWidth: document.documentElement.scrollWidth, + scrollHeight: document.documentElement.scrollHeight, + clientWidth: window.innerWidth, + clientHeight: window.innerHeight, + scrollY: window.scrollY, + scrollX: window.scrollX, + scrollTo(options: ScrollToOptions) { + window.scrollTo(options) + }, + scrollBy(options: ScrollToOptions) { + window.scrollBy(options) + }, + addEventListener(event: string, handler: any) { + window.addEventListener(event, handler) + }, + removeEventListener(event: string, handler: any) { + window.removeEventListener(event, handler) + }, + } } }, [containWeb]) @@ -118,14 +158,12 @@ function ListImpl( const element = getScrollableNode() element?.scrollTo({ left: 0, - top: containWeb - ? element?.scrollHeight - : document.documentElement.scrollHeight, + top: element.scrollHeight, behavior: animated ? 'smooth' : 'instant', }) }, } as any), // TODO: Better types. - [containWeb, getScrollableNode], + [getScrollableNode], ) // --- onContentSizeChange, maintainVisibleContentPosition --- @@ -137,46 +175,31 @@ function ListImpl( const handleScroll = useNonReactiveCallback(() => { if (!isInsideVisibleTree) return - // If we are in "contain" mode, scroll events come from the container div rather than the window. We can use the - // `nativeRef` to get the needed values. - if (containWeb) { - const element = getScrollableNode() - contextScrollHandlers.onScroll?.( - { - contentOffset: { - x: Math.max(0, element?.scrollLeft ?? 0), - y: Math.max(0, element?.scrollTop ?? 0), - }, - layoutMeasurement: { - width: element?.clientWidth, - height: element?.clientHeight, - }, - contentSize: { - width: element?.scrollWidth, - height: element?.scrollHeight, - }, - } as any, // TODO: Better types. - null as any, - ) - } else { - contextScrollHandlers.onScroll?.( - { - contentOffset: { - x: Math.max(0, window.scrollX), - y: Math.max(0, window.scrollY), - }, - layoutMeasurement: { - width: window.innerWidth, - height: window.innerHeight, - }, - contentSize: { - width: document.documentElement.scrollWidth, - height: document.documentElement.scrollHeight, - }, - } as any, // TODO: Better types. - null as any, - ) - } + const element = getScrollableNode() + contextScrollHandlers.onScroll?.( + { + contentOffset: { + x: Math.max(0, element?.scrollX ?? 0), + y: Math.max(0, element?.scrollY ?? 0), + }, + layoutMeasurement: { + width: element?.clientWidth, + height: element?.clientHeight, + }, + contentSize: { + width: element?.scrollWidth, + height: element?.scrollHeight, + }, + } as Exclude< + ReanimatedScrollEvent, + | 'velocity' + | 'eventName' + | 'zoomScale' + | 'targetContentOffset' + | 'contentInset' + >, + null as any, + ) }) React.useEffect(() => { @@ -187,6 +210,7 @@ function ListImpl( } const element = getScrollableNode() + element?.addEventListener('scroll', handleScroll) return () => { element?.removeEventListener('scroll', handleScroll)