diff --git a/packages/pl-fe/src/components/scrollable-list.tsx b/packages/pl-fe/src/components/scrollable-list.tsx index 8e96493072..19fcd88e10 100644 --- a/packages/pl-fe/src/components/scrollable-list.tsx +++ b/packages/pl-fe/src/components/scrollable-list.tsx @@ -56,8 +56,10 @@ interface IScrollableList { style?: React.CSSProperties; /** Initial item index to scroll to. */ initialIndex?: number; - /** Estimated size for items */ + /** Estimated size for items. */ estimatedSize?: number; + /** Align the items to the bottom of the list. */ + alignToBottom?: boolean; } const ScrollableList = React.forwardRef, IScrollableList & IScrollableListWindowScroll>(({ @@ -81,6 +83,7 @@ const ScrollableList = React.forwardRef, IScrollableList & initialIndex = 0, style = {}, estimatedSize = 300, + alignToBottom, ...props }, ref) => { const { autoloadMore } = useSettings(); @@ -160,9 +163,9 @@ const ScrollableList = React.forwardRef, IScrollableList & const renderItem = (index: number): JSX.Element => { const PlaceholderComponent = Placeholder || Spinner; - if (index === data.length) return (isLoading) ? : loadMore ||
; + if (alignToBottom && hasMore ? index === 0 : index === data.length) return (isLoading) ? : loadMore ||
; if (showPlaceholder) return ; - return data[index]; + return data[alignToBottom && hasMore ? index - 1 : index]; }; const virtualItems = virtualizer.getVirtualItems(); diff --git a/packages/pl-fe/src/features/chats/components/chat-message-list.test.tsx b/packages/pl-fe/src/features/chats/components/chat-message-list.test.tsx index b83fef0ff0..f5ad0efe3a 100644 --- a/packages/pl-fe/src/features/chats/components/chat-message-list.test.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-message-list.test.tsx @@ -61,11 +61,9 @@ const store = rootState .set('instance', buildInstance({ version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)' })); const renderComponentWithChatContext = () => render( - // , - // , undefined, store, ); diff --git a/packages/pl-fe/src/features/chats/components/chat-message-list.tsx b/packages/pl-fe/src/features/chats/components/chat-message-list.tsx index ee47f00e22..6a258ed866 100644 --- a/packages/pl-fe/src/features/chats/components/chat-message-list.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-message-list.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'; +import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useIntl, defineMessages } from 'react-intl'; -import { Components, Virtuoso, VirtuosoHandle } from 'react-virtuoso'; -import { Avatar, Button, Divider, Spinner, Stack, Text } from 'pl-fe/components/ui'; +import ScrollableList from 'pl-fe/components/scrollable-list'; +import { Avatar, Button, Divider, Stack, Text } from 'pl-fe/components/ui'; import PlaceholderChatMessage from 'pl-fe/features/placeholder/components/placeholder-chat-message'; import { useAppSelector } from 'pl-fe/hooks'; import { useChatActions, useChatMessages } from 'pl-fe/queries/chats'; @@ -36,25 +36,25 @@ const timeChange = (prev: Pick, curr: Pick { - const { context, ...rest } = props; - return
; -}); +// const List: Components['List'] = React.forwardRef((props, ref) => { +// const { context, ...rest } = props; +// return
; +// }); -const Scroller: Components['Scroller'] = React.forwardRef((props, ref) => { - const { style, context, ...rest } = props; +// const Scroller: Components['Scroller'] = React.forwardRef((props, ref) => { +// const { style, context, ...rest } = props; - return ( -
- ); -}); +// return ( +//
+// ); +// }); interface IChatMessageList { /** Chat the messages are being rendered from. */ @@ -65,7 +65,7 @@ interface IChatMessageList { const ChatMessageList: React.FC = ({ chat }) => { const intl = useIntl(); - const node = useRef(null); + const parentRef = useRef(null); const [firstItemIndex, setFirstItemIndex] = useState(START_INDEX - 20); const { markChatAsRead } = useChatActions(chat.id); @@ -137,16 +137,16 @@ const ChatMessageList: React.FC = ({ chat }) => { }; const cachedChatMessages = buildCachedMessages(); - const initialScrollPositionProps = useMemo(() => { - if (process.env.NODE_ENV === 'test') { - return {}; - } + // const initialScrollPositionProps = useMemo(() => { + // if (process.env.NODE_ENV === 'test') { + // return {}; + // } - return { - initialTopMostItemIndex: cachedChatMessages.length - 1, - firstItemIndex: Math.max(0, firstItemIndex), - }; - }, [cachedChatMessages.length, firstItemIndex]); + // return { + // initialTopMostItemIndex: cachedChatMessages.length - 1, + // firstItemIndex: Math.max(0, firstItemIndex), + // }; + // }, [cachedChatMessages.length, firstItemIndex]); const handleStartReached = useCallback(() => { if (hasNextPage && !isFetching) { @@ -231,14 +231,30 @@ const ChatMessageList: React.FC = ({ chat }) => { } return ( -
-
- +
+ + {cachedChatMessages.map((chatMessage, index) => { + if (chatMessage.type === 'divider') { + return renderDivider(index, chatMessage.text); + } else { + return ; + } + })} + + {/* { if (chatMessage.type === 'divider') { @@ -258,7 +274,7 @@ const ChatMessageList: React.FC = ({ chat }) => { return null; }, }} - /> + /> */}
); diff --git a/packages/pl-fe/src/features/chats/components/chat-pane/chat-pane.test.tsx b/packages/pl-fe/src/features/chats/components/chat-pane/chat-pane.test.tsx index 6967eddb67..6be62485b6 100644 --- a/packages/pl-fe/src/features/chats/components/chat-pane/chat-pane.test.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-pane/chat-pane.test.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { VirtuosoMockContext } from 'react-virtuoso'; import { __stub } from 'pl-fe/api'; import { ChatContext } from 'pl-fe/contexts/chat-context'; @@ -10,13 +9,11 @@ import { render, screen, waitFor } from 'pl-fe/jest/test-helpers'; import ChatPane from './chat-pane'; const renderComponentWithChatContext = (store = {}) => render( - - - - - - - , + + + + + , undefined, store, ); diff --git a/packages/pl-fe/src/features/chats/components/chat-search/chat-search.test.tsx b/packages/pl-fe/src/features/chats/components/chat-search/chat-search.test.tsx index d549d441a2..8c4cacabc1 100644 --- a/packages/pl-fe/src/features/chats/components/chat-search/chat-search.test.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-search/chat-search.test.tsx @@ -1,6 +1,5 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; -import { VirtuosoMockContext } from 'react-virtuoso'; import { __stub } from 'pl-fe/api'; import { ChatProvider } from 'pl-fe/contexts/chat-context'; @@ -9,11 +8,9 @@ import { render, screen, waitFor } from 'pl-fe/jest/test-helpers'; import ChatSearch from './chat-search'; const renderComponent = () => render( - - - - , - , + + + , ); describe('', () => { diff --git a/packages/pl-fe/src/features/chats/components/chat-search/chat-search.tsx b/packages/pl-fe/src/features/chats/components/chat-search/chat-search.tsx index 546e3193c6..0dfcf241c2 100644 --- a/packages/pl-fe/src/features/chats/components/chat-search/chat-search.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-search/chat-search.tsx @@ -1,5 +1,5 @@ import { useMutation } from '@tanstack/react-query'; -import React, { useState } from 'react'; +import React, { useRef, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; @@ -25,9 +25,9 @@ interface IChatSearch { isMainPage?: boolean; } -const ChatSearch = (props: IChatSearch) => { +const ChatSearch: React.FC = ({ isMainPage = false }) => { + const parentRef = useRef(null); const intl = useIntl(); - const { isMainPage = false } = props; const debounce = useDebounce; const history = useHistory(); @@ -70,6 +70,7 @@ const ChatSearch = (props: IChatSearch) => { handleClickOnSearchResult.mutate(id); clearValue(); }} + parentRef={parentRef} /> ); } else if (hasSearchValue && !hasSearchResults && !isFetching) { @@ -109,7 +110,7 @@ const ChatSearch = (props: IChatSearch) => { />
- + {renderBody()} diff --git a/packages/pl-fe/src/features/chats/components/chat-search/results.tsx b/packages/pl-fe/src/features/chats/components/chat-search/results.tsx index f4b6fc9a88..f78dd890c7 100644 --- a/packages/pl-fe/src/features/chats/components/chat-search/results.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-search/results.tsx @@ -11,9 +11,10 @@ import type { Account } from 'pl-api'; interface IResults { accountSearchResult: ReturnType; onSelect(id: string): void; + parentRef: React.RefObject; } -const Results = ({ accountSearchResult, onSelect }: IResults) => { +const Results = ({ accountSearchResult, onSelect, parentRef }: IResults) => { const { data: accounts, isFetching, hasNextPage, fetchNextPage } = accountSearchResult; const [isNearBottom, setNearBottom] = useState(false); @@ -47,8 +48,9 @@ const Results = ({ accountSearchResult, onSelect }: IResults) => { ), []); + //
return ( -
+ <> { isLoading={isFetching} hasMore={hasNextPage} onLoadMore={handleLoadMore} + useWindowScroll={false} + parentRef={parentRef} > {(accounts || []).map((chat) => renderAccount(chat))} - <> -
-
- -
+
+
+ ); }; diff --git a/packages/pl-fe/src/features/chats/components/chat.tsx b/packages/pl-fe/src/features/chats/components/chat.tsx index 9853198071..5815b6d4a8 100644 --- a/packages/pl-fe/src/features/chats/components/chat.tsx +++ b/packages/pl-fe/src/features/chats/components/chat.tsx @@ -161,7 +161,7 @@ const Chat: React.FC = ({ chat, inputRef, className }) => { return (
- +
=> { // localForage error in FireFox private browsing mode (which doesn't support IndexedDB). // We only use IndexedDB as a cache, so we can safely ignore the error. 'No available storage method found', - // Virtuoso throws these errors, but it is a false-positive. - // https://github.com/petyosi/react-virtuoso/issues/254 - 'ResizeObserver loop completed with undelivered notifications.', - 'ResizeObserver loop limit exceeded', ], denyUrls: [ // Browser extensions. diff --git a/packages/pl-fe/src/styles/basics.scss b/packages/pl-fe/src/styles/basics.scss index 446cc185f4..22144ed283 100644 --- a/packages/pl-fe/src/styles/basics.scss +++ b/packages/pl-fe/src/styles/basics.scss @@ -21,12 +21,6 @@ noscript { @apply w-4 h-4 -mt-[0.2ex] mb-[0.2ex] inline-block align-middle object-contain; } -// Virtuoso empty placeholder fix. -// https://gitlab.com/petyosi/soapbox-fe/-/commit/1e22c39934b60e5e186de804060ecfdf1955b506 -div[data-viewport-type='window'] { - @apply static #{!important}; -} - body.system-font, body.system-font .font-sans { font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;