mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-30 15:18:50 +01:00
* feat: new dropdown * fix: maintain popover active when open * fix: update DeleteButton and ShareButton component to use useState for managing dialog state * BREAKING: style improvement of base Button component * style: update export button * a11y: ExportAndShareButton * add border * quick style fix * fix: flick issue on convo * fix: DropDown opens when renaming * chore: update radix-ui/react-dropdown-menu to latest * small fix * style: bookmarks update * reorder export modal * feat: imporved dropdowns * style: a lot of changes; header, bookmarks, export, nav, convo, convoOptions * fix: small style issues * fix: button * fix: bookmarks header menu * fix: dropdown close glitch * feat: Improve accessibility and keyboard navigation in ModelSpec component * fix: Nav related type issues * style: ConvoOptions theming and focus ring --------- Co-authored-by: Danny Avila <danny@librechat.ai>
65 lines
1.9 KiB
TypeScript
65 lines
1.9 KiB
TypeScript
import throttle from 'lodash/throttle';
|
|
import React, { useCallback, useEffect, useRef } from 'react';
|
|
import type { FetchNextPageOptions, InfiniteQueryObserverResult } from '@tanstack/react-query';
|
|
|
|
export default function useNavScrolling<TData>({
|
|
hasNextPage,
|
|
isFetchingNextPage,
|
|
setShowLoading,
|
|
fetchNextPage,
|
|
}: {
|
|
hasNextPage?: boolean;
|
|
isFetchingNextPage: boolean;
|
|
setShowLoading: React.Dispatch<React.SetStateAction<boolean>>;
|
|
fetchNextPage:
|
|
| ((
|
|
options?: FetchNextPageOptions | undefined,
|
|
) => Promise<InfiniteQueryObserverResult<TData, unknown>>)
|
|
| undefined;
|
|
}) {
|
|
const scrollPositionRef = useRef<number | null>(null);
|
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
const fetchNext = useCallback(
|
|
throttle(() => (fetchNextPage != null ? fetchNextPage() : () => ({})), 750, { leading: true }),
|
|
[fetchNextPage],
|
|
);
|
|
|
|
const handleScroll = useCallback(() => {
|
|
if (containerRef.current) {
|
|
const { scrollTop, clientHeight, scrollHeight } = containerRef.current;
|
|
const nearBottomOfList = scrollTop + clientHeight >= scrollHeight * 0.97;
|
|
|
|
if (nearBottomOfList && hasNextPage === true && !isFetchingNextPage) {
|
|
setShowLoading(true);
|
|
fetchNext();
|
|
} else {
|
|
setShowLoading(false);
|
|
}
|
|
}
|
|
}, [hasNextPage, isFetchingNextPage, fetchNext, setShowLoading]);
|
|
|
|
useEffect(() => {
|
|
const container = containerRef.current;
|
|
if (container) {
|
|
container.addEventListener('scroll', handleScroll);
|
|
}
|
|
|
|
return () => {
|
|
container?.removeEventListener('scroll', handleScroll);
|
|
};
|
|
}, [handleScroll, fetchNext]);
|
|
|
|
const moveToTop = useCallback(() => {
|
|
const container = containerRef.current;
|
|
if (container) {
|
|
scrollPositionRef.current = container.scrollTop;
|
|
}
|
|
}, [containerRef, scrollPositionRef]);
|
|
|
|
return {
|
|
containerRef,
|
|
moveToTop,
|
|
};
|
|
}
|