fix: keep the issue popup open when the list moves the focus to the text #1397

This commit is contained in:
Linus Rath
2026-11-02 20:07:52 +01:00
parent e9c4fb095f
commit 43a18d2140
2 changed files with 9 additions and 4 deletions
@@ -116,9 +116,10 @@ export function IssuePopup({ state, issue, anchor, onApply, onDismiss, onClose }
style={{ width: WIDTH, maxWidth: "calc(100vw - 16px)", top: pos?.top ?? -9999, left: pos?.left ?? -9999 }}
onKeyDown={onKeyDown}
onBlur={(e) => {
// Tabbing out of it closes it; a click inside doesn't.
const next = e.relatedTarget as Node | null;
if (next && !ref.current?.contains(next)) onClose(false);
// Tabbing out of it closes it; a click inside, or going back to the
// text (where Escape closes it), doesn't.
const next = e.relatedTarget as Element | null;
if (next && !ref.current?.contains(next) && !next.closest?.(".tiptap")) onClose(false);
}}
>
<IssueActions issue={issue} onApply={apply} onDismiss={onDismiss} error={error} />
@@ -6,6 +6,7 @@
import { useCallback, useEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore, type RefObject } from "react";
import type { Editor } from "@tiptap/core";
import { TextSelection } from "@tiptap/pm/state";
import { ComposerProofreader, type DismissAction, type PlacedIssue, type ProofreaderStatus } from "@/lib/proofreading/composer-proofreader";
import { checkerAccess, type PolicyView } from "@/lib/proofreading/gate";
import { draftProtection, OPTIONS_SURFACE } from "@/lib/proofreading/protection";
@@ -271,7 +272,10 @@ export function useProofreading({ composerId, sessionKey, editor, textareaRef, p
if (!ed || plainRef.current) return;
const range = drawnIssues(ed.state).find((r) => r.key === issue.key);
if (!range) return;
ed.chain().focus().setTextSelection({ from: range.from, to: range.to }).scrollIntoView().run();
// Focus now, not later as TipTap's focus command does: a late focus
// would pull the keyboard out of the popup again.
ed.view.focus();
ed.view.dispatch(ed.state.tr.setSelection(TextSelection.create(ed.state.doc, range.from, range.to)).scrollIntoView());
openPopup(issue.key, issueRect(ed, issue.key), "keyboard");
}, [openPopup]);