mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
修复 添加供应商页面 搜索预设后无法点击选中搜索结果 (#4315)
* fix(provider-preset-selector): after searching presets, it is impossible to select search results. feat(provider-preset-selector): add keyboard shortcut for search input and improve focus handling. * fix(provider-list): prevent keydown event from triggering when default is prevented * fix(provider-preset): keep preset clickable after search and restore keyboard UX - ProviderList: scope the typing guard to the Ctrl/Cmd+F branch so Escape still closes the search panel (the top-level early return swallowed it); reuse isTextEditableTarget instead of re-implementing the check. - ProviderPresetSelector: drop the rAF select() that raced with typing and ate the first character (gateway -> ateway), and restore the input autoFocus for the open-by-click path; refocus via rAF when Ctrl/Cmd+F is pressed while the box is already open so focus returns to the input. - Add a regression test for the re-focus-on-shortcut behavior. --------- Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { TFunction } from "i18next";
|
||||
@@ -421,18 +421,80 @@ describe("ProviderPresetSelector", () => {
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("点击搜索区域外自动收起并清空", async () => {
|
||||
it("按 Ctrl+F 快捷键打开搜索输入框", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderSelector();
|
||||
|
||||
// 初始没有搜索输入框
|
||||
expect(
|
||||
screen.queryByRole("textbox", {
|
||||
name: /providerPreset\.(searchInput|searchPlaceholder)|搜索预设|search/i,
|
||||
}),
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
// 按 Ctrl+F 展开输入框
|
||||
await user.keyboard("{Control>}f{/Control}");
|
||||
expect(getSearchInput()).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("搜索后点击预设按钮可选中预设且不清空搜索关键词", async () => {
|
||||
const user = userEvent.setup();
|
||||
const onPresetChange = vi.fn();
|
||||
renderSelector({ onPresetChange });
|
||||
|
||||
await user.click(getSearchButton());
|
||||
await user.type(getSearchInput(), "gateway");
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Beta Gateway" }));
|
||||
|
||||
expect(onPresetChange).toHaveBeenCalledWith("beta");
|
||||
// 搜索框仍展开、关键词保留
|
||||
expect(getSearchInput()).toBeInTheDocument();
|
||||
expect(getSearchInput()).toHaveValue("gateway");
|
||||
});
|
||||
|
||||
it("搜索已打开、焦点在别处时再次 Ctrl+F 把焦点移回搜索框且保留关键词", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderSelector();
|
||||
|
||||
await user.click(getSearchButton());
|
||||
await user.type(getSearchInput(), "gateway");
|
||||
|
||||
// 选中 preset 后焦点离开搜索框(搜索框仍展开、关键词保留)
|
||||
await user.click(screen.getByRole("button", { name: "Beta Gateway" }));
|
||||
expect(getSearchInput()).not.toHaveFocus();
|
||||
|
||||
// 再次 Ctrl+F:setSearchOpen(true) 同值不重渲染、autoFocus 不重触发,
|
||||
// 需靠快捷键命中时的命令式聚焦把焦点移回搜索框,且不清空关键词
|
||||
await user.keyboard("{Control>}f{/Control}");
|
||||
await waitFor(() => expect(getSearchInput()).toHaveFocus());
|
||||
expect(getSearchInput()).toHaveValue("gateway");
|
||||
});
|
||||
|
||||
it("点击组件外区域自动收起并清空", async () => {
|
||||
const user = userEvent.setup();
|
||||
const Wrapper = () => {
|
||||
const form = useForm();
|
||||
return (
|
||||
<Form {...form}>
|
||||
<ProviderPresetSelector
|
||||
selectedPresetId="custom"
|
||||
presetEntries={presetEntries}
|
||||
presetCategoryLabels={presetCategoryLabels}
|
||||
onPresetChange={vi.fn()}
|
||||
/>
|
||||
<div data-testid="outside">Outside</div>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
render(<Wrapper />);
|
||||
|
||||
await user.click(getSearchButton());
|
||||
await user.type(getSearchInput(), "gateway");
|
||||
expect(getSearchInput()).toBeInTheDocument();
|
||||
|
||||
// 点击搜索区域外的元素(custom 按钮)应收起搜索框
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "providerPreset.custom" }),
|
||||
);
|
||||
// 点击组件外的元素应收起搜索框
|
||||
await user.click(screen.getByTestId("outside"));
|
||||
|
||||
expect(
|
||||
screen.queryByRole("textbox", {
|
||||
|
||||
Reference in New Issue
Block a user