mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
fix(frontend): frontend UI keep flashing (#10352)
This commit is contained in:
parent
f8376a9702
commit
a1ffe5c936
@ -1,5 +1,5 @@
|
||||
import clsx from "clsx";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { NavTab } from "./nav-tab";
|
||||
import { ScrollLeftButton } from "./scroll-left-button";
|
||||
import { ScrollRightButton } from "./scroll-right-button";
|
||||
@ -25,18 +25,12 @@ export function Container({
|
||||
children,
|
||||
className,
|
||||
}: ContainerProps) {
|
||||
const [containerWidth, setContainerWidth] = useState(0);
|
||||
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
||||
const [canScrollRight, setCanScrollRight] = useState(false);
|
||||
const [showScrollButtons, setShowScrollButtons] = useState(false);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Track container width using ResizeObserver
|
||||
useTrackElementWidth({
|
||||
elementRef: containerRef,
|
||||
callback: setContainerWidth,
|
||||
});
|
||||
|
||||
// Check scroll position and update button states
|
||||
const updateScrollButtons = () => {
|
||||
if (scrollContainerRef.current) {
|
||||
@ -47,10 +41,19 @@ export function Container({
|
||||
}
|
||||
};
|
||||
|
||||
// Update scroll buttons when tabs change or container width changes
|
||||
useEffect(() => {
|
||||
updateScrollButtons();
|
||||
}, [labels, containerWidth]);
|
||||
// Track container width using ResizeObserver
|
||||
useTrackElementWidth({
|
||||
elementRef: containerRef,
|
||||
callback: (width: number) => {
|
||||
// Only update scroll button visibility when crossing the threshold
|
||||
const shouldShowScrollButtons =
|
||||
width < 598 && Boolean(labels) && labels!.length > 0;
|
||||
if (shouldShowScrollButtons) {
|
||||
setShowScrollButtons(shouldShowScrollButtons);
|
||||
}
|
||||
updateScrollButtons();
|
||||
},
|
||||
});
|
||||
|
||||
// Scroll functions
|
||||
const scrollLeft = () => {
|
||||
@ -65,8 +68,6 @@ export function Container({
|
||||
}
|
||||
};
|
||||
|
||||
const showScrollButtons = containerWidth < 598 && labels && labels.length > 0;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
|
||||
@ -1,18 +1,38 @@
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useCallback, useRef } from "react";
|
||||
|
||||
interface UseTrackElementWidthProps {
|
||||
elementRef: React.RefObject<HTMLElement | null>;
|
||||
callback: (width: number) => void;
|
||||
delay?: number; // Optional delay parameter with default
|
||||
}
|
||||
|
||||
export const useTrackElementWidth = ({
|
||||
elementRef,
|
||||
callback,
|
||||
delay = 100, // Default 100ms delay
|
||||
}: UseTrackElementWidthProps) => {
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// Create debounced callback that only fires after delay
|
||||
const debouncedCallback = useCallback(
|
||||
(width: number) => {
|
||||
// Clear existing timeout
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
// Set new timeout
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
callback(width);
|
||||
}, delay);
|
||||
},
|
||||
[callback, delay],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
callback(entry.contentRect.width);
|
||||
debouncedCallback(entry.contentRect.width);
|
||||
}
|
||||
});
|
||||
|
||||
@ -21,7 +41,11 @@ export const useTrackElementWidth = ({
|
||||
}
|
||||
|
||||
return () => {
|
||||
// Clean up timeout and observer
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, []);
|
||||
}, [debouncedCallback]);
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user