mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
fix(link-actions): dismiss the link chooser when an outside click stops propagation (#33679)
* fix(link-actions): dismiss the link chooser when an outside click stops propagation * test(link-actions): wait for Radix to arm before the outside click
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useMemo, useRef } from 'react'
|
||||
import { useEffect, useEffectEvent, useMemo, useRef } from 'react'
|
||||
import { Check, Copy, ExternalLink, Globe, Settings } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import { ShortcutKeyCombo } from '@/components/ShortcutKeyCombo'
|
||||
@@ -64,6 +64,23 @@ export function LinkActionPopover<TRequest extends LinkActionRequest>({
|
||||
const copyableDestination = request?.kind === 'url' ? request.destination : ''
|
||||
const { copyText, status: copyStatus } = useClipboardTextCopyFeedback(copyableDestination)
|
||||
const copyInFlightRef = useRef(false)
|
||||
const contentRef = useRef<HTMLDivElement>(null)
|
||||
const dismissOnOutsidePointerDown = useEffectEvent((event: PointerEvent): void => {
|
||||
if (!request || (event.target instanceof Node && contentRef.current?.contains(event.target))) {
|
||||
return
|
||||
}
|
||||
onPointerDownOutside?.(event)
|
||||
onClose(request)
|
||||
})
|
||||
useEffect(() => {
|
||||
if (!request) {
|
||||
return
|
||||
}
|
||||
// Why: Radix defers outside dismissal to the click and skips it when the click's
|
||||
// propagation is stopped, which hover cards and sidebar cards both do.
|
||||
document.addEventListener('pointerdown', dismissOnOutsidePointerDown, true)
|
||||
return () => document.removeEventListener('pointerdown', dismissOnOutsidePointerDown, true)
|
||||
}, [request])
|
||||
const virtualRef = useMemo(
|
||||
() => ({
|
||||
current: {
|
||||
@@ -133,6 +150,7 @@ export function LinkActionPopover<TRequest extends LinkActionRequest>({
|
||||
<PopoverAnchor virtualRef={virtualRef} />
|
||||
{request ? (
|
||||
<PopoverContent
|
||||
ref={contentRef}
|
||||
align="start"
|
||||
side="top"
|
||||
sideOffset={6}
|
||||
@@ -143,7 +161,6 @@ export function LinkActionPopover<TRequest extends LinkActionRequest>({
|
||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||
onCloseAutoFocus={(event) => event.preventDefault()}
|
||||
onEscapeKeyDown={() => request.restoreFocus()}
|
||||
onPointerDownOutside={onPointerDownOutside}
|
||||
>
|
||||
<div className="mb-0.5 flex items-center gap-1 overflow-hidden border-b border-border px-1.5 py-0.5 font-mono text-xs text-muted-foreground">
|
||||
<span
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @vitest-environment happy-dom
|
||||
import type { ReactNode } from 'react'
|
||||
import { render, screen, fireEvent, cleanup } from '@testing-library/react'
|
||||
import { act, render, screen, fireEvent, cleanup } from '@testing-library/react'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { WorktreeCardDetailsHover } from './WorktreeCardMeta'
|
||||
import type { Worktree, WorkspaceAttachment } from '../../../../shared/worktree/types'
|
||||
@@ -192,6 +192,26 @@ describe('workspace linked references in hover details', () => {
|
||||
'true'
|
||||
)
|
||||
})
|
||||
it('dismisses the link chooser when an outside click stops propagation', async () => {
|
||||
Object.defineProperty(window, 'api', {
|
||||
configurable: true,
|
||||
value: { shell: { openUrl: vi.fn() } }
|
||||
})
|
||||
render(
|
||||
<>
|
||||
<Fixture onManage={vi.fn()} />
|
||||
<button onClick={(event) => event.stopPropagation()}>Other card</button>
|
||||
</>
|
||||
)
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Hover workspace' }))
|
||||
fireEvent.click(screen.getByRole('link', { name: 'Open MR !42' }))
|
||||
// Why: Radix arms its outside-pointerdown listener a tick after opening.
|
||||
await act(() => new Promise((resolve) => setTimeout(resolve, 0)))
|
||||
const otherCard = screen.getByRole('button', { name: 'Other card' })
|
||||
fireEvent.pointerDown(otherCard)
|
||||
fireEvent.click(otherCard)
|
||||
expect(screen.queryByRole('button', { name: /System Browser/ })).toBeNull()
|
||||
})
|
||||
it('opens link management from either section header and dismisses hover', () => {
|
||||
const onManage = vi.fn()
|
||||
const { container } = render(<Fixture onManage={onManage} />)
|
||||
|
||||
Reference in New Issue
Block a user