Skip to content

Commit 480294a

Browse files
committed
fix(workflow): make connection picker scrolling seamless
1 parent dc131b6 commit 480294a

1 file changed

Lines changed: 42 additions & 10 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/connection-block-selector/connection-block-selector.tsx

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
'use client'
22

3-
import { useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from 'react'
3+
import {
4+
startTransition,
5+
useCallback,
6+
useDeferredValue,
7+
useEffect,
8+
useMemo,
9+
useRef,
10+
useState,
11+
} from 'react'
412
import { Button, cn } from '@sim/emcn'
513
import { X } from '@sim/emcn/icons'
614
import { WorkflowBlockBorder, type WorkflowBorderPort } from '@sim/workflow-renderer'
@@ -47,6 +55,7 @@ const SELECTOR_ACTION_MENU_RIGHT_INSET = 24
4755
const SELECTOR_ACTION_MENU_AMPLITUDE = 7
4856
const RECENT_SELECTION_LIMIT = 3
4957
const RECENT_SELECTION_STORAGE_PREFIX = 'sim:connection-block-selector:recent'
58+
const BROWSE_PREFETCH_MARGIN_PX = 640
5059
const POPULAR_BLOCK_TYPES = [
5160
'agent',
5261
'function',
@@ -138,6 +147,7 @@ export function ConnectionBlockSelector({ id, data }: NodeProps<ConnectionBlockS
138147
const posthog = usePostHog()
139148
const inputRef = useRef<HTMLInputElement>(null)
140149
const listRef = useRef<HTMLDivElement>(null)
150+
const browseSentinelRef = useRef<HTMLDivElement>(null)
141151
const [search, setSearch] = useState('')
142152
const [selectedValue, setSelectedValue] = useState('')
143153
const [recentSelections, setRecentSelections] = useState<RecentSelection[]>([])
@@ -269,6 +279,36 @@ export function ConnectionBlockSelector({ id, data }: NodeProps<ConnectionBlockS
269279
)
270280
const hasMoreBrowseResults = browseLimit < browseBlocks.length + browseTools.length
271281

282+
/**
283+
* Keep the initial commit bounded, then extend the catalog before the user
284+
* reaches its end. Rendering every cmdk item up front caused the original
285+
* frame spike, while a manual pagination control exposed that constraint in
286+
* the UI. Prefetching near the viewport preserves continuous scrolling and
287+
* cmdk's native keyboard navigation without mounting the whole catalog.
288+
*/
289+
useEffect(() => {
290+
const list = listRef.current
291+
const sentinel = browseSentinelRef.current
292+
if (isSearching || !hasMoreBrowseResults || !list || !sentinel) return
293+
294+
const browseResultCount = browseBlocks.length + browseTools.length
295+
const observer = new IntersectionObserver(
296+
([entry]) => {
297+
if (!entry.isIntersecting) return
298+
startTransition(() => {
299+
setBrowseLimit((current) => Math.min(current + MAX_RESULTS_PER_GROUP, browseResultCount))
300+
})
301+
},
302+
{
303+
root: list,
304+
rootMargin: `0px 0px ${BROWSE_PREFETCH_MARGIN_PX}px 0px`,
305+
}
306+
)
307+
308+
observer.observe(sentinel)
309+
return () => observer.disconnect()
310+
}, [browseBlocks.length, browseTools.length, hasMoreBrowseResults, isSearching])
311+
272312
const dispatchSelection = useCallback(
273313
(type: string, resultType: 'block' | 'tool' | 'tool_operation', presetOperation?: string) => {
274314
window.dispatchEvent(
@@ -494,15 +534,7 @@ export function ConnectionBlockSelector({ id, data }: NodeProps<ConnectionBlockS
494534
/>
495535
<ToolsGroup items={visibleBrowseTools} onSelect={handleToolSelect} />
496536
{hasMoreBrowseResults && (
497-
<div className='px-2 py-1.5'>
498-
<Button
499-
variant='ghost'
500-
className='nodrag nopan h-8 w-full text-[var(--text-secondary)]'
501-
onClick={() => setBrowseLimit((current) => current + MAX_RESULTS_PER_GROUP)}
502-
>
503-
Show more
504-
</Button>
505-
</div>
537+
<div ref={browseSentinelRef} aria-hidden='true' className='h-px' />
506538
)}
507539
</>
508540
)}

0 commit comments

Comments
 (0)