mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
fix(app): keep the chat scroller pinned to the end while it resizes (#1860)
This commit is contained in:
1 parent
a2099fb0e2
commit
2af0405317
36 files changed
+171
-191
No files matched your search
@@ -392,7 +392,7 @@ export const MobileSectionNav: React.FC<MobileSectionNavProps> = observer(
|
||||
const scrollerRef = useRef<ScrollerHandle | null>(null);
|
||||
useEffect(() => {
|
||||
if (!activeSectionId) return;
|
||||
const node = scrollerRef.current?.getScrollerNode();
|
||||
const node = scrollerRef.current?.getViewportElement();
|
||||
if (!node) return;
|
||||
const activeButton = node.querySelector(`[data-section-id="${activeSectionId}"]`);
|
||||
if (activeButton instanceof HTMLElement) {
|
||||
|
||||
@@ -125,7 +125,7 @@ export const SettingsModalDesktopScroll: React.FC<SettingsModalDesktopScrollProp
|
||||
if (!scrollerRef) {
|
||||
return;
|
||||
}
|
||||
const node = internalRef.current?.getScrollerNode() ?? null;
|
||||
const node = internalRef.current?.getViewportElement() ?? null;
|
||||
if (typeof scrollerRef === 'function') {
|
||||
scrollerRef(node);
|
||||
} else {
|
||||
|
||||
@@ -734,7 +734,7 @@ export const UnreadChannelsContent = observer(function UnreadChannelsContent() {
|
||||
const target = event.target as Element | null;
|
||||
if (target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement) return;
|
||||
if (target instanceof HTMLElement && target.isContentEditable) return;
|
||||
const scrollerNode = scrollerRef.current?.getScrollerNode() ?? null;
|
||||
const scrollerNode = scrollerRef.current?.getViewportElement() ?? null;
|
||||
if (!scrollerNode) return;
|
||||
if (target && !scrollerNode.contains(target) && document.activeElement !== document.body) return;
|
||||
const sections = Array.from(scrollerNode.querySelectorAll<HTMLElement>('[data-inbox-channel-section]'));
|
||||
|
||||
@@ -69,7 +69,7 @@ const AuthLayoutContent = observer(function AuthLayoutContent({children}: {child
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
scrollerRef.current?.scrollToTop();
|
||||
scrollerRef.current?.jumpToStartEdge();
|
||||
}, [location.pathname]);
|
||||
const splashScale = useMemo(() => {
|
||||
if (!splashDimensions) return null;
|
||||
|
||||
@@ -242,7 +242,7 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr
|
||||
() => [channels.length, ReadStates.version, userGuildSettings, hideMutedChannels, showFadedUnreadOnMutedChannels],
|
||||
[channels.length, ReadStates.version, userGuildSettings, hideMutedChannels, showFadedUnreadOnMutedChannels],
|
||||
);
|
||||
const getChannelScrollContainer = useCallback(() => scrollerRef.current?.getScrollerNode() ?? null, [scrollerRef]);
|
||||
const getChannelScrollContainer = useCallback(() => scrollerRef.current?.getViewportElement() ?? null, [scrollerRef]);
|
||||
useDragAutoScroll({active: isDraggingAnything, getScrollElement: getChannelScrollContainer});
|
||||
const handleChannelDrop = useCallback(
|
||||
(item: DragItem, result: DropResult) => {
|
||||
@@ -306,15 +306,15 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr
|
||||
}, [guild.id]);
|
||||
const handleResize = useCallback((_entry: ResizeObserverEntry, _type: 'container' | 'content') => {
|
||||
if (stickToBottomRef.current && scrollerRef.current) {
|
||||
scrollerRef.current.scrollToBottom({animate: false});
|
||||
scrollerRef.current.jumpToEndEdge({animate: false});
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
const guildDimensions = Dimension.getGuildDimensions(guild.id);
|
||||
const guildDimensions = Dimension.guildDimensionsFor(guild.id);
|
||||
if (guildDimensions.scrollTo) {
|
||||
const element = document.querySelector(`[data-channel-id="${guildDimensions.scrollTo}"]`);
|
||||
if (element && scrollerRef.current) {
|
||||
scrollerRef.current.scrollIntoViewNode({node: element as HTMLElement, shouldScrollToStart: false});
|
||||
scrollerRef.current.revealElement({node: element as HTMLElement, preferStartEdge: false});
|
||||
}
|
||||
DimensionCommands.clearChannelListScrollTo(guild.id);
|
||||
} else if (guildDimensions.scrollTop && guildDimensions.scrollTop > 0 && scrollerRef.current) {
|
||||
@@ -337,7 +337,8 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr
|
||||
const unreadCount = ReadStates.getUnreadCount(channelId);
|
||||
const mentionCount = ReadStates.getMentionCount(channelId);
|
||||
const isMuted =
|
||||
UserGuildSettings.isParentCategoryMuted(guild.id, channelId) || UserGuildSettings.isChannelDirectlyMuted(guild.id, channelId);
|
||||
UserGuildSettings.isParentCategoryMuted(guild.id, channelId) ||
|
||||
UserGuildSettings.isChannelDirectlyMuted(guild.id, channelId);
|
||||
const channel = Channels.getChannel(channelId);
|
||||
const unreadBadgesLevel = channel
|
||||
? UserGuildSettings.resolvedUnreadBadgesLevel({
|
||||
@@ -360,7 +361,9 @@ export const ChannelListContent = observer(({guild, scrollY}: {guild: Guild; scr
|
||||
for (const group of channelGroups) {
|
||||
const isCollapsed = group.category ? (collapsedCategories?.has(group.category.id) ?? false) : false;
|
||||
const isNullSpace = !group.category;
|
||||
const isCategoryMuted = group.category ? UserGuildSettings.isChannelDirectlyMuted(guild.id, group.category.id) : false;
|
||||
const isCategoryMuted = group.category
|
||||
? UserGuildSettings.isChannelDirectlyMuted(guild.id, group.category.id)
|
||||
: false;
|
||||
let filteredTextChannels: Array<Channel>;
|
||||
let filteredVoiceChannels: Array<Channel>;
|
||||
if (hideMutedChannels) {
|
||||
|
||||
@@ -651,7 +651,7 @@ export const FavoritesChannelListContent = observer(() => {
|
||||
const getScrollElement = useCallback(() => {
|
||||
const scroller = scrollerRef.current;
|
||||
if (scroller == null) return null;
|
||||
return scroller.getScrollerNode();
|
||||
return scroller.getViewportElement();
|
||||
}, []);
|
||||
useDragAutoScroll({active: isDraggingFavorite, getScrollElement});
|
||||
const favorites = Favorites.sortedChannels;
|
||||
|
||||
@@ -164,7 +164,7 @@ function resolveScrollerNode(scroller: ScrollerHandle | null): HTMLElement | nul
|
||||
if (scroller == null) {
|
||||
return null;
|
||||
}
|
||||
return scroller.getScrollerNode();
|
||||
return scroller.getViewportElement();
|
||||
}
|
||||
|
||||
function resolveOwnerWindow(container: HTMLElement): Window & typeof globalThis {
|
||||
@@ -221,7 +221,7 @@ function cancelOwnedSettleTimer(timer: OwnedSettleTimer | null): void {
|
||||
}
|
||||
|
||||
function alignMountedTarget({animate, direction, scroller, targetNode}: AlignMountedTargetRequest): boolean {
|
||||
const container = scroller.getScrollerNode();
|
||||
const container = scroller.getViewportElement();
|
||||
if (container == null) return false;
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const targetRect = targetNode.getBoundingClientRect();
|
||||
@@ -451,7 +451,7 @@ export const FloatingUnreadIndicators = observer(
|
||||
if (scrollTarget(edge.id, direction)) {
|
||||
scheduleRefresh(FloatingUnreadRefreshScope.GEOMETRY);
|
||||
if (scroller == null) return;
|
||||
const scrollNode = scroller.getScrollerNode();
|
||||
const scrollNode = scroller.getViewportElement();
|
||||
if (scrollNode == null) return;
|
||||
const ownerWindow = resolveOwnerWindow(scrollNode);
|
||||
cancelOwnedAnimationFrame(targetAlignmentFrameRef.current);
|
||||
@@ -467,7 +467,7 @@ export const FloatingUnreadIndicators = observer(
|
||||
}
|
||||
scheduleRefresh(FloatingUnreadRefreshScope.SCROLL);
|
||||
if (scroller == null) return;
|
||||
const scrollNode = scroller.getScrollerNode();
|
||||
const scrollNode = scroller.getViewportElement();
|
||||
if (scrollNode == null) return;
|
||||
const ownerWindow = resolveOwnerWindow(scrollNode);
|
||||
cancelOwnedSettleTimer(settleTimerRef.current);
|
||||
|
||||
@@ -184,7 +184,7 @@ function resolveGuildFolderId(folderId: number | null): number {
|
||||
|
||||
function resolveGuildListScrollerNode(scroller: ScrollerHandle | null): HTMLElement | null {
|
||||
if (scroller == null) return null;
|
||||
return scroller.getScrollerNode();
|
||||
return scroller.getViewportElement();
|
||||
}
|
||||
|
||||
type GuildNavigationRow =
|
||||
@@ -1583,7 +1583,7 @@ const GuildList = observer(() => {
|
||||
const visibleDMListRows = useFrameBatchedDMListRows(targetDMListRows);
|
||||
const shouldRenderGuildListItems = hasUnavailableGuilds || organizedItems.length > 0;
|
||||
const initialGuildListScrollTop = useMemo(() => {
|
||||
const liveScrollTop = untracked(() => Dimension.getGuildListDimensions().scrollTop);
|
||||
const liveScrollTop = untracked(() => Dimension.currentGuildListDimensions().scrollTop);
|
||||
if (liveScrollTop > 0) {
|
||||
return liveScrollTop;
|
||||
}
|
||||
@@ -1859,7 +1859,7 @@ const GuildList = observer(() => {
|
||||
const node = scrollTargetRegistry.getTargetNode(targetId);
|
||||
const scroller = scrollRef.current;
|
||||
if (node == null || scroller == null) return false;
|
||||
scroller.scrollIntoViewNode({
|
||||
scroller.revealElement({
|
||||
node,
|
||||
alignment,
|
||||
animate: Accessibility.useSmoothScrolling,
|
||||
|
||||
@@ -467,7 +467,7 @@ export const GuildRailSkeleton: React.FC<GuildRailSkeletonProps> = ({
|
||||
const [mountState] = useState(() => {
|
||||
const rememberedLayout = getRememberedSkeletonGuildRailLayout();
|
||||
const remScale = getRemScaleForDocument(document);
|
||||
const liveScrollTop = Math.max(0, Dimension.getGuildListDimensions().scrollTop);
|
||||
const liveScrollTop = Math.max(0, Dimension.currentGuildListDimensions().scrollTop);
|
||||
let scrollTop = liveScrollTop;
|
||||
if (liveScrollTop === 0 && rememberedLayout != null) {
|
||||
scrollTop = rememberedLayout.scrollTopPx * remScale;
|
||||
|
||||
@@ -72,7 +72,7 @@ export function WhatsNewModal({entry}: WhatsNewModalProps) {
|
||||
ModalCommands.pop();
|
||||
}, [entry.id]);
|
||||
const updateScrollHintVisibility = useCallback(() => {
|
||||
const scrollerNode = scrollerRef.current?.getScrollerNode();
|
||||
const scrollerNode = scrollerRef.current?.getViewportElement();
|
||||
if (!scrollerNode) {
|
||||
setIsScrollHintVisible(false);
|
||||
return;
|
||||
@@ -89,7 +89,7 @@ export function WhatsNewModal({entry}: WhatsNewModalProps) {
|
||||
updateScrollHintVisibility();
|
||||
}, [updateScrollHintVisibility]);
|
||||
const handleScrollToBottom = useCallback(() => {
|
||||
scrollerRef.current?.scrollToBottom({animate: true});
|
||||
scrollerRef.current?.jumpToEndEdge({animate: true});
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
updateScrollHintVisibility();
|
||||
|
||||
@@ -265,7 +265,7 @@ function resolveScrollNode(scrollerRef: React.RefObject<ScrollerHandle | null>):
|
||||
if (scroller == null) {
|
||||
return null;
|
||||
}
|
||||
return scroller.getScrollerNode();
|
||||
return scroller.getViewportElement();
|
||||
}
|
||||
|
||||
interface ResolveNavigationRowNodeQuery {
|
||||
@@ -311,7 +311,7 @@ function scrollNavigationRowIntoView({
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
scroller.scrollIntoViewNode({node, alignment: resolveNavigationScrollerAlignment(align)});
|
||||
scroller.revealElement({node, alignment: resolveNavigationScrollerAlignment(align)});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user