mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-22 22:30:52 +01:00
Update InfiniteScroll, fix chat history scroll
This commit is contained in:
parent
16e583594a
commit
558067c531
@ -1,30 +1,37 @@
|
|||||||
import { useVirtual } from '@tanstack/react-virtual';
|
import { useVirtual } from '@tanstack/react-virtual';
|
||||||
import { FC, Fragment, ReactElement, useRef } from 'react';
|
import { FC, Fragment, ReactElement, useEffect, useRef, useState } from 'react';
|
||||||
import { Base } from './Base';
|
import { Base } from './Base';
|
||||||
|
|
||||||
interface InfiniteScrollProps<T = any>
|
interface InfiniteScrollProps<T = any>
|
||||||
{
|
{
|
||||||
rows: T[];
|
rows: T[];
|
||||||
estimateSize: number;
|
|
||||||
overscan?: number;
|
overscan?: number;
|
||||||
|
scrollToBottom?: boolean;
|
||||||
rowRender: (row: T) => ReactElement;
|
rowRender: (row: T) => ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InfiniteScroll: FC<InfiniteScrollProps> = props =>
|
export const InfiniteScroll: FC<InfiniteScrollProps> = props =>
|
||||||
{
|
{
|
||||||
const { rows = [], estimateSize = 0, overscan = 5, rowRender = null } = props;
|
const { rows = [], overscan = 5, scrollToBottom = false, rowRender = null } = props;
|
||||||
|
const [ scrollIndex, setScrollIndex ] = useState<number>(rows.length - 1);
|
||||||
const elementRef = useRef<HTMLDivElement>(null);
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const rowVirtualizer = useVirtual({
|
const { virtualItems = [], totalSize = 0, scrollToIndex = null } = useVirtual({
|
||||||
parentRef: elementRef,
|
parentRef: elementRef,
|
||||||
size: rows.length,
|
size: rows.length,
|
||||||
overscan: 5
|
overscan
|
||||||
});
|
});
|
||||||
|
|
||||||
const { virtualItems, totalSize, } = rowVirtualizer;
|
|
||||||
const paddingTop = (virtualItems.length > 0) ? (virtualItems?.[0]?.start || 0) : 0
|
const paddingTop = (virtualItems.length > 0) ? (virtualItems?.[0]?.start || 0) : 0
|
||||||
const paddingBottom = (virtualItems.length > 0) ? (totalSize - (virtualItems?.[virtualItems.length - 1]?.end || 0)) : 0;
|
const paddingBottom = (virtualItems.length > 0) ? (totalSize - (virtualItems?.[virtualItems.length - 1]?.end || 0)) : 0;
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!scrollToBottom) return;
|
||||||
|
|
||||||
|
scrollToIndex(scrollIndex);
|
||||||
|
}, [ scrollToBottom, scrollIndex, scrollToIndex ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Base fit innerRef={ elementRef } position="relative" overflow="auto">
|
<Base fit innerRef={ elementRef } position="relative" overflow="auto">
|
||||||
{ (paddingTop > 0) &&
|
{ (paddingTop > 0) &&
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ILinkEventTracker } from '@nitrots/nitro-renderer';
|
import { ILinkEventTracker } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { AddEventLinkTracker, ChatEntryType, LocalizeText, RemoveLinkEventTracker } from '../../api';
|
import { AddEventLinkTracker, ChatEntryType, LocalizeText, RemoveLinkEventTracker } from '../../api';
|
||||||
import { Flex, InfiniteScroll, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
|
import { Flex, InfiniteScroll, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
|
||||||
import { useChatHistory } from '../../hooks';
|
import { useChatHistory } from '../../hooks';
|
||||||
@ -9,6 +9,7 @@ export const ChatHistoryView: FC<{}> = props =>
|
|||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const [ searchText, setSearchText ] = useState<string>('');
|
const [ searchText, setSearchText ] = useState<string>('');
|
||||||
const { chatHistory = [] } = useChatHistory();
|
const { chatHistory = [] } = useChatHistory();
|
||||||
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const filteredChatHistory = useMemo(() =>
|
const filteredChatHistory = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -19,10 +20,10 @@ export const ChatHistoryView: FC<{}> = props =>
|
|||||||
return chatHistory.filter(entry => ((entry.message && entry.message.toLowerCase().includes(text))) || (entry.name && entry.name.toLowerCase().includes(text)));
|
return chatHistory.filter(entry => ((entry.message && entry.message.toLowerCase().includes(text))) || (entry.name && entry.name.toLowerCase().includes(text)));
|
||||||
}, [ chatHistory, searchText ]);
|
}, [ chatHistory, searchText ]);
|
||||||
|
|
||||||
/* useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(elementRef && elementRef.current && isVisible) elementRef.current.scrollTop = elementRef.current.scrollHeight;
|
if(elementRef && elementRef.current && isVisible) elementRef.current.scrollTop = elementRef.current.scrollHeight;
|
||||||
}, [ isVisible ]); */
|
}, [ isVisible ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -59,9 +60,9 @@ export const ChatHistoryView: FC<{}> = props =>
|
|||||||
return (
|
return (
|
||||||
<NitroCardView uniqueKey="chat-history" className="nitro-chat-history" theme="primary-slim">
|
<NitroCardView uniqueKey="chat-history" className="nitro-chat-history" theme="primary-slim">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('room.chathistory.button.text') } onCloseClick={ event => setIsVisible(false) }/>
|
<NitroCardHeaderView headerText={ LocalizeText('room.chathistory.button.text') } onCloseClick={ event => setIsVisible(false) }/>
|
||||||
<NitroCardContentView overflow="hidden" gap={ 2 }>
|
<NitroCardContentView innerRef={ elementRef } overflow="hidden" gap={ 2 }>
|
||||||
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={ searchText } onChange={ event => setSearchText(event.target.value) } />
|
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={ searchText } onChange={ event => setSearchText(event.target.value) } />
|
||||||
<InfiniteScroll rows={ filteredChatHistory } estimateSize={ 35 } rowRender={ row =>
|
<InfiniteScroll rows={ filteredChatHistory } scrollToBottom={ true } rowRender={ row =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Flex alignItems="center" className="p-1" gap={ 2 }>
|
<Flex alignItems="center" className="p-1" gap={ 2 }>
|
||||||
|
@ -70,7 +70,7 @@ export const ChatlogView: FC<ChatlogViewProps> = props =>
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Column>
|
</Column>
|
||||||
{ (records && (records.length > 0)) &&
|
{ (records && (records.length > 0)) &&
|
||||||
<InfiniteScroll rows={ allRecords } estimateSize={ 25 } rowRender={ (row: ChatlogRecord) =>
|
<InfiniteScroll rows={ allRecords } rowRender={ (row: ChatlogRecord) =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -43,7 +43,7 @@ export const ModToolsUserRoomVisitsView: FC<ModToolsUserRoomVisitsViewProps> = p
|
|||||||
<Base className="g-col-3">Visit</Base>
|
<Base className="g-col-3">Visit</Base>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Column>
|
</Column>
|
||||||
<InfiniteScroll rows={ roomVisitData?.rooms ?? [] } estimateSize={ 25 } rowRender={ row =>
|
<InfiniteScroll rows={ roomVisitData?.rooms ?? [] } rowRender={ row =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Grid fullHeight={ false } gap={ 1 } alignItems="center" className="text-black py-1 border-bottom">
|
<Grid fullHeight={ false } gap={ 1 } alignItems="center" className="text-black py-1 border-bottom">
|
||||||
|
@ -36,7 +36,7 @@ export const ChooserWidgetView: FC<ChooserWidgetViewProps> = props =>
|
|||||||
<NitroCardHeaderView headerText={ title } onCloseClick={ onClose } />
|
<NitroCardHeaderView headerText={ title } onCloseClick={ onClose } />
|
||||||
<NitroCardContentView overflow="hidden" gap={ 2 }>
|
<NitroCardContentView overflow="hidden" gap={ 2 }>
|
||||||
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={ searchValue } onChange={ event => setSearchValue(event.target.value) } />
|
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={ searchValue } onChange={ event => setSearchValue(event.target.value) } />
|
||||||
<InfiniteScroll rows={ filteredItems } estimateSize={ 25 } rowRender={ row =>
|
<InfiniteScroll rows={ filteredItems } rowRender={ row =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Flex alignItems="center" className={ classNames('rounded p-1', (selectedItem === row) && 'bg-muted') } pointer onClick={ event => setSelectedItem(row) }>
|
<Flex alignItems="center" className={ classNames('rounded p-1', (selectedItem === row) && 'bg-muted') } pointer onClick={ event => setSelectedItem(row) }>
|
||||||
|
Loading…
Reference in New Issue
Block a user