@@ -212,64 +212,24 @@ export function Sidebar() {
212212 // Combined loading state
213213 const isLoading = workflowsLoading || sessionLoading
214214
215- // Ref to track active timeout IDs for cleanup
216- const scrollTimeoutRef = useRef < number | null > ( null )
217-
218215 /**
219- * Scrolls an element into view if it's not already visible in the scroll container.
220- * Uses a retry mechanism with cleanup to wait for the element to be rendered in the DOM.
221- *
222- * @param elementId - The ID of the element to scroll to
223- * @param maxRetries - Maximum number of retry attempts (default: 10)
216+ * Scrolls a newly created element into view if completely off-screen.
217+ * Uses requestAnimationFrame to sync with render, then scrolls.
224218 */
225- const scrollToElement = useCallback (
226- ( elementId : string , maxRetries = 10 ) => {
227- // Clear any existing timeout
228- if ( scrollTimeoutRef . current !== null ) {
229- clearTimeout ( scrollTimeoutRef . current )
230- scrollTimeoutRef . current = null
231- }
232-
233- let attempts = 0
234-
235- const tryScroll = ( ) => {
236- attempts ++
237- const element = document . querySelector ( `[data-item-id="${ elementId } "]` )
238- const container = scrollContainerRef . current
239-
240- if ( element && container ) {
241- const elementRect = element . getBoundingClientRect ( )
242- const containerRect = container . getBoundingClientRect ( )
243-
244- // Check if element is not fully visible in the container
245- const isAboveView = elementRect . top < containerRect . top
246- const isBelowView = elementRect . bottom > containerRect . bottom
247-
248- if ( isAboveView || isBelowView ) {
249- element . scrollIntoView ( { behavior : 'smooth' , block : 'nearest' } )
250- }
251- scrollTimeoutRef . current = null
252- } else if ( attempts < maxRetries ) {
253- // Element not in DOM yet, retry after a short delay
254- scrollTimeoutRef . current = window . setTimeout ( tryScroll , 50 )
255- } else {
256- scrollTimeoutRef . current = null
257- }
258- }
259-
260- // Start the scroll attempt after a small delay to ensure rendering.
261- scrollTimeoutRef . current = window . setTimeout ( tryScroll , 50 )
262- } ,
263- [ scrollContainerRef ]
264- )
265-
266- // Cleanup timeouts on unmount
267- useEffect ( ( ) => {
268- return ( ) => {
269- if ( scrollTimeoutRef . current !== null ) {
270- clearTimeout ( scrollTimeoutRef . current )
219+ const scrollToElement = useCallback ( ( elementId : string ) => {
220+ requestAnimationFrame ( ( ) => {
221+ const element = document . querySelector ( `[data-item-id="${ elementId } "]` )
222+ const container = scrollContainerRef . current
223+ if ( ! element || ! container ) return
224+
225+ const { top : elTop , bottom : elBottom } = element . getBoundingClientRect ( )
226+ const { top : ctTop , bottom : ctBottom } = container . getBoundingClientRect ( )
227+
228+ // Only scroll if element is completely off-screen
229+ if ( elBottom <= ctTop || elTop >= ctBottom ) {
230+ element . scrollIntoView ( { behavior : 'smooth' , block : 'center' } )
271231 }
272- }
232+ } )
273233 } , [ ] )
274234
275235 /**
0 commit comments