fix(desktop): keep directive hover timers on owned boundaries

This commit is contained in:
Teknium
2026-09-07 01:03:17 -07:00
parent 45c7388213
commit d70fb4e6bd
3 changed files with 13 additions and 6 deletions

View File

@@ -150,6 +150,11 @@ describe('ComposerDirectiveActions', () => {
})
expect(pillValue()).toBe('https://example.com')
const button = screen.getByRole('button')
fireEvent.pointerOut(button, { relatedTarget: button.firstElementChild })
act(() => { vi.advanceTimersByTime(750) })
expect(pillValue()).toBe('https://example.com')
})
it('still hides shortly after the pointer leaves the pill for good', () => {
@@ -162,9 +167,9 @@ describe('ComposerDirectiveActions', () => {
fireEvent.pointerOut(chip, { relatedTarget: null })
fireEvent.mouseEnter(screen.getByRole('button').parentElement!)
fireEvent.mouseLeave(screen.getByRole('button').parentElement!)
act(() => {
vi.advanceTimersByTime(500)
})
act(() => { vi.advanceTimersByTime(300) })
fireEvent.pointerOut(document.body, { relatedTarget: document.documentElement })
act(() => { vi.advanceTimersByTime(200) })
expect(pillValue()).toBeNull()
})

View File

@@ -96,8 +96,10 @@ export function ComposerDirectiveActions({ editorRef }: { editorRef: RefObject<H
const editor = editorRef.current
const chip = editor && actionableChipAt(event.target, editor)
// A move within the same chip (its icon → its label) is not a leave.
if (chip && editor && chip === actionableChipAt(event.relatedTarget, editor)) {
// Only this editor's chip departures start the grace window. The pill
// owns its own boundary; internal pill or unrelated document transitions
// must neither dismiss a hovered action nor postpone an existing leave.
if (!chip || !editor || chip === actionableChipAt(event.relatedTarget, editor)) {
return
}

View File

@@ -47,7 +47,7 @@ The center of the app. You get:
- **The same conversation history** as every other Hermes surface — sessions started here resume in the CLI/TUI and vice versa.
- **Drag-and-drop files** anywhere in the chat area to attach them to your next message.
- **Independent background drafts** — hidden chat tabs can update their drafts without moving the caret or selection in the visible composer.
- **Directive chip actions** — hover an actionable reference (such as a URL) to reveal its action pill. A short grace period lets you move from the chip to the pill before it dismisses.
- **Directive chip actions** — hover an actionable reference (such as a URL) to reveal its action pill. A short grace period lets you move from the chip to the pill before it dismisses. The pill stays available while you move within it; after leaving, unrelated pointer movement does not delay dismissal. Clicking its action preserves the draft selection.
- **A right-hand preview rail** — render web pages, files, and tool outputs side by side while you keep chatting.
- **Comment mode in the in-app browser** — click **Annotate** in the preview browser bar, then click any element (or drag a box) on the live page and type a note; each saved comment stays as a numbered pin on the page. Saving a pin never sends a turn — when you're done, **Add N comments** attaches a cropped screenshot per pin and a short prompt naming each comment to the composer, and you still hit send yourself. Each element comment carries its CSS selector, its markup, and the computed styles that matter for layout, so the agent can find the element in your source instead of guessing from the picture. Password and hidden field values, and any attribute that looks like a key or token, are redacted on the page before the markup leaves it. Larger batches arrive grouped by which part of the page each comment sits in, so twenty-odd comments become a handful of pieces of work rather than one task each — and because the groups are separate DOM subtrees they usually touch separate files, which is what makes handing them to parallel workers safe. Pin numbers hold steady if you delete one, and switching chats clears the stack.
- **Composer history and queue editing** — press the up/down arrow keys in an empty composer to recall and reuse previous prompts, and edit messages you've queued up before they're sent. Pressing Stop (or Esc) while turns are queued pauses the queue and expands it above the composer; resume it from there, or send, edit, and delete individual entries.