fix(ai): keep assistant open for portaled controls (#236)

This commit is contained in:
tianma-if committed 2026-08-21 12:25:02 +08:00
1 parent 9c4d6eea54
commit ee00a98be7
2 files changed
+19 -8

No files matched your search

@@ -49,6 +49,13 @@ import { cn } from "@/lib/utils";
const FREEFORM_VALUE = "custom";
const PROMPT_VALUE_PREFIX = "prompt:";
const AI_ASSISTANT_LAYER_SELECTOR = '[data-edgeever-ai-assistant-layer="true"]';
export const isAiAssistantPointerTarget = (target: EventTarget | null, panel: HTMLElement | null) => {
if (!(target instanceof Node)) return false;
if (panel?.contains(target)) return true;
return target instanceof Element && Boolean(target.closest(AI_ASSISTANT_LAYER_SELECTOR));
};
const promptSelectValue = (id: string) => `${PROMPT_VALUE_PREFIX}${id}`;
@@ -182,9 +189,7 @@ export const AiAssistantDialog = ({
if (!open) return;
const frame = window.requestAnimationFrame(() => instructionRef.current?.focus());
const handlePointerDown = (event: PointerEvent) => {
const target = event.target;
if (!(target instanceof Node) || panelRef.current?.contains(target)) return;
if (target instanceof Element && target.closest('[data-radix-popper-content-wrapper], [role="dialog"]')) return;
if (isAiAssistantPointerTarget(event.target, panelRef.current)) return;
onOpenChange(false);
};
window.addEventListener("pointerdown", handlePointerDown);
@@ -432,7 +437,7 @@ export const AiAssistantDialog = ({
<SelectTrigger aria-label={t("aiAssistant.actionLabel")} className="h-10 w-full min-w-0 sm:col-span-2">
<SelectValue placeholder={t("aiAssistant.actionLabel")} />
</SelectTrigger>
<SelectContent>
<SelectContent data-edgeever-ai-assistant-layer="true">
{prompts.length ? (
<SelectGroup>
<SelectLabel>{t("aiAssistant.myPrompts")}</SelectLabel>
@@ -480,7 +485,7 @@ export const AiAssistantDialog = ({
<SelectTrigger aria-label={t("aiAssistant.targetLanguage")} className="h-10">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectContent data-edgeever-ai-assistant-layer="true">
{targetLanguages.map((language) => (
<SelectItem key={language} value={language}>{t(`aiAssistant.targetLanguages.${language}`)}</SelectItem>
))}
@@ -496,7 +501,7 @@ export const AiAssistantDialog = ({
clearResult();
}}>
<SelectTrigger aria-label={t("aiAssistant.tone")} className="h-10"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectContent data-edgeever-ai-assistant-layer="true">
{aiTones.map((item) => <SelectItem key={item} value={item}>{t(`aiAssistant.tones.${item}`)}</SelectItem>)}
</SelectContent>
</Select>
@@ -659,7 +664,7 @@ export const AiAssistantDialog = ({
createPromptMutation.reset();
}
}}>
<DialogContent className="sm:max-w-md">
<DialogContent className="sm:max-w-md" data-edgeever-ai-assistant-layer="true">
<form
className="grid gap-4"
onSubmit={(event: FormEvent) => {
+7 -1
View File
@@ -174,7 +174,13 @@ test.describe("AI custom prompts", () => {
await slashMenu.getByText("用 AI 处理", { exact: true }).click();
await expect(slashMenu).toBeHidden();
await expect(editor).not.toContainText("/");
await expect(page.getByRole("dialog", { name: "AI 笔记助手" })).toBeVisible();
const assistant = page.getByRole("dialog", { name: "AI 笔记助手" });
await expect(assistant).toBeVisible();
await assistant.getByRole("combobox", { name: "处理方式" }).click();
await expect(assistant).toBeVisible();
await expect(page.getByRole("option", { name: "自定义指令", exact: true })).toBeVisible();
await page.getByRole("option", { name: "自定义指令", exact: true }).click();
await expect(assistant).toBeVisible();
});
test("sends temporary files with one AI request", async ({ page }) => {