From bb34c73069f32862d4e09f7978e864b0b8bd4ca5 Mon Sep 17 00:00:00 2001 From: Hampus Date: Mon, 24 Aug 2026 12:42:09 +0200 Subject: [PATCH] perf(app): load sheet and popout media against their own scrollers (#1900) --- .../components/shared/ChannelPinsContent.tsx | 183 +++++++++--------- .../bottomsheets/ChannelSearchBottomSheet.tsx | 168 ++++++++-------- .../modals/BookmarksBottomSheet.tsx | 66 ++++--- 3 files changed, 217 insertions(+), 200 deletions(-) diff --git a/fluxer_app/src/features/app/components/shared/ChannelPinsContent.tsx b/fluxer_app/src/features/app/components/shared/ChannelPinsContent.tsx index a71adcf3c..98af3d60a 100644 --- a/fluxer_app/src/features/app/components/shared/ChannelPinsContent.tsx +++ b/fluxer_app/src/features/app/components/shared/ChannelPinsContent.tsx @@ -13,6 +13,7 @@ import {isKeyboardActivationKey} from '@app/features/input/utils/KeyboardUtils'; import {ensureMembersForMessages} from '@app/features/messaging/commands/MessageCommands'; import {useMessageListKeyboardNavigation} from '@app/features/messaging/hooks/useMessageListKeyboardNavigation'; import {useMessageSelectionCopyForMessages} from '@app/features/messaging/hooks/useMessageSelectionCopy'; +import {NearViewportSurfaceContext} from '@app/features/messaging/hooks/useNearViewport'; import type {Message} from '@app/features/messaging/models/MessagingMessage'; import {focusChannelTextareaAfterNavigation} from '@app/features/messaging/utils/ChannelTextareaFocusUtils'; import {goToMessage} from '@app/features/messaging/utils/MessageNavigator'; @@ -79,6 +80,7 @@ export const ChannelPinsContent = observer(({channel, onJump}: ChannelPinsConten const canUnpin = isDMChannel || Permission.can(Permissions.MANAGE_MESSAGES, channel); const mobileLayout = MobileLayout; const scrollerRef = useRef(null); + const resolvePinnedScrollSurface = useMemo(() => () => scrollerRef.current?.getViewportElement() ?? null, []); const [menuOpen, setMenuOpen] = useState(false); const [selectedMessage, setSelectedMessage] = useState(null); const pinMessagesPermissionLabel = formatPermissionLabel(i18n, Permissions.PIN_MESSAGES); @@ -187,107 +189,114 @@ export const ChannelPinsContent = observer(({channel, onJump}: ChannelPinsConten } return ( <> - - {mobileLayout.enabled &&
} - {pinnedPins.slice().map(({message}) => { - const cardClasses = clsx(previewStyles.previewCard, mobileLayout.enabled && previewStyles.previewCardMobile); - const messageChannel = - Channels.getChannel(message.channelId) ?? (message.channelId === channel.id ? channel : null); - if (!messageChannel) return null; - if (mobileLayout.enabled) { + + + {mobileLayout.enabled && ( +
+ )} + {pinnedPins.slice().map(({message}) => { + const cardClasses = clsx( + previewStyles.previewCard, + mobileLayout.enabled && previewStyles.previewCardMobile, + ); + const messageChannel = + Channels.getChannel(message.channelId) ?? (message.channelId === channel.id ? channel : null); + if (!messageChannel) return null; + if (mobileLayout.enabled) { + return ( + handleTap(message)} + onKeyDown={(e) => { + if (isKeyboardActivationKey(e.key)) { + e.preventDefault(); + handleTap(message); + } + }} + onLongPress={() => { + if (!canUnpin) return; + setSelectedMessage(message); + setMenuOpen(true); + }} + data-flx="app.channel-pins-content.button.tap" + > + + + ); + } return ( - handleTap(message)} - onKeyDown={(e) => { - if (isKeyboardActivationKey(e.key)) { - e.preventDefault(); - handleTap(message); - } - }} - onLongPress={() => { - if (!canUnpin) return; - setSelectedMessage(message); - setMenuOpen(true); - }} - data-flx="app.channel-pins-content.button.tap" + data-flx="app.channel-pins-content.div--6" > - +
+ + + + {renderUnpinButton(message)} +
+
); - } - return ( -
- -
- - - - {renderUnpinButton(message)} + })} + {isLoading && ( +
+ +
+ )} + {!hasMore && ( +
+
+ +
+

+ {i18n._(YOU_VE_REACHED_THE_END_DESCRIPTOR)} +

+

+ {endStateDescription} +

+
- ); - })} - {isLoading && ( -
- -
- )} - {!hasMore && ( -
-
- -
-

- {i18n._(YOU_VE_REACHED_THE_END_DESCRIPTOR)} -

-

- {endStateDescription} -

-
-
-
- )} - + )} + + {mobileLayout.enabled && selectedMessage && ( = const [selectedMessage, setSelectedMessage] = useState(null); const [selectedMessageChannel, setSelectedMessageChannel] = useState(null); const scrollerRef = useRef(null); + const resolveSearchSheetScrollSurface = useMemo(() => () => scrollerRef.current?.getViewportElement() ?? null, []); const inputRef = useRef(null); const [hasFilters, setHasFilters] = useState>([]); const [fromUserIds, setFromUserIds] = useState>([]); @@ -605,89 +607,91 @@ export const ChannelSearchBottomSheet: React.FC = value={collapsedMessageVisibility} data-flx="channel.channel-search-bottom-sheet.render-content.collapsed-message-visibility-provider" > - - {resultGroups.map((resultGroup) => { - const messageChannel = - searchChannelsById.get(resultGroup.channelId) ?? Channels.getChannel(resultGroup.channelId); - if (!messageChannel) { - return null; - } - const renderMessageWrapper = ({ - message, - index, - isGroupStart, - children, - }: MessageGroupRenderWrapperProps) => ( - handleTap(message)} - onKeyDown={(e) => { - if (isKeyboardActivationKey(e.key)) { - e.preventDefault(); - handleTap(message); - } - }} - onLongPress={() => { - setSelectedMessage(message); - setMenuOpen(true); - }} - data-flx="channel.channel-search-bottom-sheet.render-message-wrapper.search-result-item.tap" - > - {children} - - ); - return ( - - {hasMultipleChannels && ( -
- {ChannelUtils.getIcon(messageChannel, { - className: styles.channelIcon, - })} - + + {resultGroups.map((resultGroup) => { + const messageChannel = + searchChannelsById.get(resultGroup.channelId) ?? Channels.getChannel(resultGroup.channelId); + if (!messageChannel) { + return null; + } + const renderMessageWrapper = ({ + message, + index, + isGroupStart, + children, + }: MessageGroupRenderWrapperProps) => ( + handleTap(message)} + onKeyDown={(e) => { + if (isKeyboardActivationKey(e.key)) { + e.preventDefault(); + handleTap(message); + } + }} + onLongPress={() => { + setSelectedMessage(message); + setMenuOpen(true); + }} + data-flx="channel.channel-search-bottom-sheet.render-message-wrapper.search-result-item.tap" + > + {children} + + ); + return ( + + {hasMultipleChannels && ( +
- {messageChannel.name || 'Unnamed Channel'} - -
- )} - ( - + {ChannelUtils.getIcon(messageChannel, { + className: styles.channelIcon, + })} + + {messageChannel.name || 'Unnamed Channel'} + +
)} - data-flx="channel.channel-search-bottom-sheet.render-content.search-result-message-list" - /> -
- ); - })} -
+ ( + + )} + data-flx="channel.channel-search-bottom-sheet.render-content.search-result-message-list" + /> + + ); + })} + + {totalPages > 1 && (
0 || missingSavedMessages.length > 0; const scrollerRef = useRef(null); + const resolveBookmarksScrollSurface = useMemo(() => () => scrollerRef.current?.getViewportElement() ?? null, []); const [selectedMessage, setSelectedMessage] = useState(null); const [menuOpen, setMenuOpen] = useState(false); const onCopySelectedMessages = useMessageSelectionCopyForMessages(savedMessages); @@ -122,39 +124,41 @@ export const BookmarksBottomSheet = observer(({isOpen, onClose}: BookmarksBottom data-flx="channel.bookmarks-bottom-sheet.bottom-sheet" > {hasBookmarks ? ( - - {missingSavedMessages.length > 0 && ( -
- {missingSavedMessages.map((entry) => ( - SavedMessageCommands.remove(i18n, entry.id)} - data-flx="channel.bookmarks-bottom-sheet.saved-message-missing-card" + + + {missingSavedMessages.length > 0 && ( +
+ {missingSavedMessages.map((entry) => ( + SavedMessageCommands.remove(i18n, entry.id)} + data-flx="channel.bookmarks-bottom-sheet.saved-message-missing-card" + /> + ))} +
+ )} +
+
+ {savedMessages.map((message) => ( + ))}
- )} -
-
- {savedMessages.map((message) => ( - - ))} -
- + + ) : (