Skip to content

Commit 2ca63c2

Browse files
committed
fix(resource): hold breadcrumb nav latch across the route swap
scheduleClose fired on the pointer/focus exit that immediately follows a click-to-navigate and was clearing the reopen latch before the route swapped, letting the popover flash back open. The latch is now released by a short timer instead (addresses Cursor Bugbot).
1 parent 726eac6 commit 2ca63c2

1 file changed

Lines changed: 15 additions & 4 deletions

File tree

  • apps/sim/app/workspace/[workspaceId]/components/resource/components/resource-header

apps/sim/app/workspace/[workspaceId]/components/resource/components/resource-header/resource-header.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ interface BreadcrumbLocationPopoverProps {
371371
veilBoundaryRef: React.RefObject<HTMLDivElement | null>
372372
}
373373

374+
/** How long the reopen latch is held after a click-to-navigate, covering the route swap. */
375+
const NAVIGATE_LATCH_MS = 250
376+
374377
function BreadcrumbLocationPopover({
375378
icon: Icon,
376379
breadcrumbs,
@@ -386,11 +389,14 @@ function BreadcrumbLocationPopover({
386389
* veil and popover content would snap away instead of fading — a visible
387390
* flash. {@link navigateAndClose} closes the popover before running the
388391
* crumb's handler and latches this so the pointer still resting on the
389-
* trigger can't re-fire `openPopover` mid-navigation. It is cleared on the
390-
* next pointer/focus exit so the popover keeps working when the handler does
391-
* not actually navigate (e.g. an unsaved-changes guard that opens a modal).
392+
* trigger can't re-fire `openPopover` mid-navigation. The latch is held by a
393+
* short timer (not cleared on the next pointer exit, which fires immediately
394+
* and would let the popover flash back open before the route swaps); the
395+
* timer releases it so the popover keeps working when the handler does not
396+
* actually navigate (e.g. an unsaved-changes guard that opens a modal).
392397
*/
393398
const navigatingRef = useRef(false)
399+
const navigateLatchRef = useRef<ReturnType<typeof setTimeout> | null>(null)
394400
const rootBreadcrumb = breadcrumbs[0]
395401

396402
const clearCloseTimeout = () => {
@@ -407,7 +413,6 @@ function BreadcrumbLocationPopover({
407413
}
408414

409415
const scheduleClose = () => {
410-
navigatingRef.current = false
411416
clearCloseTimeout()
412417
closeTimeoutRef.current = setTimeout(() => {
413418
setOpen(false)
@@ -421,11 +426,17 @@ function BreadcrumbLocationPopover({
421426
clearCloseTimeout()
422427
setOpen(false)
423428
onClick()
429+
if (navigateLatchRef.current) clearTimeout(navigateLatchRef.current)
430+
navigateLatchRef.current = setTimeout(() => {
431+
navigatingRef.current = false
432+
navigateLatchRef.current = null
433+
}, NAVIGATE_LATCH_MS)
424434
}
425435

426436
useEffect(() => {
427437
return () => {
428438
if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current)
439+
if (navigateLatchRef.current) clearTimeout(navigateLatchRef.current)
429440
}
430441
}, [])
431442

0 commit comments

Comments
 (0)