From be8d747772381ceda02b9480d619a5120b80ec60 Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez Date: Sat, 19 Oct 2024 07:17:01 -0700 Subject: [PATCH] Update scroll provider so that it only captures the scroll on div container and not the whole window --- .../desktop-client/src/components/App.tsx | 48 +++-- .../src/components/FinancesApp.tsx | 191 +++++++++--------- .../src/components/ScrollProvider.tsx | 57 ++++-- 3 files changed, 165 insertions(+), 131 deletions(-) diff --git a/packages/desktop-client/src/components/App.tsx b/packages/desktop-client/src/components/App.tsx index f7785d58df4..7fb79028f68 100644 --- a/packages/desktop-client/src/components/App.tsx +++ b/packages/desktop-client/src/components/App.tsx @@ -166,36 +166,34 @@ export function App() { - + - - - {process.env.REACT_APP_REVIEW_ID && - !Platform.isPlaywright && } - - - - - - + + {process.env.REACT_APP_REVIEW_ID && + !Platform.isPlaywright && } + + + + + - + diff --git a/packages/desktop-client/src/components/FinancesApp.tsx b/packages/desktop-client/src/components/FinancesApp.tsx index b585d5d30ee..400e7abba4c 100644 --- a/packages/desktop-client/src/components/FinancesApp.tsx +++ b/packages/desktop-client/src/components/FinancesApp.tsx @@ -1,5 +1,5 @@ // @ts-strict-ignore -import React, { type ReactElement, useEffect } from 'react'; +import React, { type ReactElement, useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { @@ -34,6 +34,7 @@ import { ManagePayeesPage } from './payees/ManagePayeesPage'; import { Reports } from './reports'; import { LoadingIndicator } from './reports/LoadingIndicator'; import { NarrowAlternate, WideComponent } from './responsive'; +import { ScrollProvider } from './ScrollProvider'; import { Settings } from './settings'; import { FloatableSidebar } from './sidebar'; import { Titlebar } from './Titlebar'; @@ -133,6 +134,8 @@ export function FinancesApp() { run(); }, [lastUsedVersion, setLastUsedVersion]); + const scrollableRef = useRef(null); + return ( @@ -156,113 +159,119 @@ export function FinancesApp() { width: '100%', }} > - - - - + > + + + - - 0 ? ( - + + 0 ? ( + + ) : ( + // If there are no accounts, we want to redirect the user to + // the All Accounts screen which will prompt them to add an account + + ) ) : ( - // If there are no accounts, we want to redirect the user to - // the All Accounts screen which will prompt them to add an account - + ) - ) : ( - - ) - } - /> + } + /> - } /> + } /> - } - /> + } + /> - - - - } - /> + + + + } + /> - } /> - } /> - } /> + } /> + } /> + } /> - - - - } - /> + + + + } + /> - } - /> + } + /> - } - /> + } + /> - - - - } - /> + + + + } + /> - - - - } - /> + + + + } + /> - {/* redirect all other traffic to the budget page */} - } /> - - + {/* redirect all other traffic to the budget page */} + } /> + + - - } /> - } /> - } /> - } /> - - + + } /> + } /> + } /> + } /> + + + diff --git a/packages/desktop-client/src/components/ScrollProvider.tsx b/packages/desktop-client/src/components/ScrollProvider.tsx index 21bb683b156..6c4f0951aee 100644 --- a/packages/desktop-client/src/components/ScrollProvider.tsx +++ b/packages/desktop-client/src/components/ScrollProvider.tsx @@ -1,6 +1,6 @@ -// @ts-strict-ignore import React, { type ReactNode, + type RefObject, createContext, useState, useContext, @@ -17,37 +17,60 @@ type IScrollContext = { const ScrollContext = createContext(undefined); -type ScrollProviderProps = { +type ScrollProviderProps = { + scrollableRef: RefObject; + isDisabled: boolean; children?: ReactNode; }; -export function ScrollProvider({ children }: ScrollProviderProps) { - const [scrollY, setScrollY] = useState(undefined); - const [scrollHeight, setScrollHeight] = useState(undefined); - const [clientHeight, setClientHeight] = useState(undefined); +export function ScrollProvider({ + scrollableRef, + isDisabled, + children, +}: ScrollProviderProps) { + const [scrollY, setScrollY] = useState(undefined); + const [scrollHeight, setScrollHeight] = useState( + undefined, + ); + const [clientHeight, setClientHeight] = useState( + undefined, + ); const hasScrolledToBottom = useCallback( - (tolerance = 1) => scrollHeight - scrollY <= clientHeight + tolerance, + (tolerance = 1) => { + if (scrollHeight && scrollY && clientHeight) { + return scrollHeight - scrollY <= clientHeight + tolerance; + } + return false; + }, [clientHeight, scrollHeight, scrollY], ); useEffect(() => { - const listenToScroll = debounce(e => { + if (isDisabled) { + return; + } + + const listenToScroll = debounce((e: Event) => { const target = e.target; - setScrollY(target?.scrollTop || 0); - setScrollHeight(target?.scrollHeight || 0); - setClientHeight(target?.clientHeight || 0); + if (target instanceof Element) { + setScrollY(target.scrollTop || 0); + setScrollHeight(target.scrollHeight || 0); + setClientHeight(target.clientHeight || 0); + } }, 10); - window.addEventListener('scroll', listenToScroll, { + const ref = scrollableRef.current; + + ref?.addEventListener('scroll', listenToScroll, { capture: true, passive: true, }); return () => - window.removeEventListener('scroll', listenToScroll, { + ref?.removeEventListener('scroll', listenToScroll, { capture: true, }); - }, []); + }, [isDisabled, scrollableRef]); return ( @@ -57,5 +80,9 @@ export function ScrollProvider({ children }: ScrollProviderProps) { } export function useScroll(): IScrollContext { - return useContext(ScrollContext); + const context = useContext(ScrollContext); + if (!context) { + throw new Error('useScroll must be used within a ScrollProvider'); + } + return context; }