Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 63 additions & 10 deletions src/components/AssetFilter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -331,23 +331,76 @@ describe("AssetFilter", () => {

it("clamps focusedIndex when list shrinks (#754)", () => {
const onSelect = vi.fn();
renderComponent({ onAssetSelect: onSelect });
const { rerender } = renderComponent({ onAssetSelect: onSelect });
const input = screen.getByPlaceholderText(/search/i);
// Move focus to index 3 (last item in mockAssets)

// Move focus to index 3 (last item in mockAssets: RANDOM)
fireEvent.keyDown(input, { key: "ArrowDown" });
fireEvent.keyDown(input, { key: "ArrowDown" });
fireEvent.keyDown(input, { key: "ArrowDown" });

// Now filter so there are only 2 items (e.g. search for "xlm" matches XLM and yXLM)
fireEvent.change(input, { target: { value: "xlm" } });


// List shrinks to 2 items without typing
rerender(
<AssetFilter
assets={mockAssets.slice(0, 2)}
onAssetSelect={onSelect}
/>,
);

// Press Enter to select focused item
fireEvent.keyDown(input, { key: "Enter" });
// It should have clamped to index 1 (yXLM)

// It should have clamped to index 1 (USDC)
expect(onSelect).toHaveBeenCalledWith(
expect.objectContaining({ asset: "yXLM" })
expect.objectContaining({ asset: "USDC" }),
);
});

it("resets keyboard focus to index 0 on filter change (#853)", () => {
const onSelect = vi.fn();
renderComponent({ onAssetSelect: onSelect });
const input = screen.getByPlaceholderText(/search/i);

// Move focus down first (to index 2)
fireEvent.keyDown(input, { key: "ArrowDown" });
fireEvent.keyDown(input, { key: "ArrowDown" });

// Type in the filter — focus must reset to index 0
fireEvent.change(input, { target: { value: "xlm" } });

const rows = screen.getByRole("listbox").querySelectorAll("[data-asset-row]");
expect(rows[0]).toHaveClass("bg-surface-2");

// Press Enter to select focused item at index 0
fireEvent.keyDown(input, { key: "Enter" });
expect(onSelect).toHaveBeenCalledWith(
expect.objectContaining({ asset: "XLM" }),
);
});

it("allows arrow-key navigation after typing in filter (#853)", () => {
const onSelect = vi.fn();
renderComponent({ onAssetSelect: onSelect });
const input = screen.getByPlaceholderText(/search/i);

// Type in the filter matching multiple assets
fireEvent.change(input, { target: { value: "xlm" } });

const rows = screen.getByRole("listbox").querySelectorAll("[data-asset-row]");
expect(rows[0]).toHaveClass("bg-surface-2");

// Move down with ArrowDown
fireEvent.keyDown(input, { key: "ArrowDown" });
expect(rows[1]).toHaveClass("bg-surface-2");

// Move back up with ArrowUp
fireEvent.keyDown(input, { key: "ArrowUp" });
expect(rows[0]).toHaveClass("bg-surface-2");

// Press Enter to select focused item at index 0
fireEvent.keyDown(input, { key: "Enter" });
expect(onSelect).toHaveBeenCalledWith(
expect.objectContaining({ asset: "XLM" }),
);
});
});
Expand Down
11 changes: 9 additions & 2 deletions src/components/AssetFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,7 @@ function AssetFilter({
value={search}
onChange={(e) => {
setSearch(e.target.value);
setFocusedIndex(0);
onPageReset?.();
}}
onKeyDown={handleKeyDown}
Expand All @@ -641,7 +642,10 @@ function AssetFilter({
{search && (
<button
type="button"
onClick={() => setSearch("")}
onClick={() => {
setSearch("");
setFocusedIndex(0);
}}
className="absolute right-3 top-1/2 -translate-y-1/2 text-ink-4 hover:text-ink-2"
aria-label="Clear search"
>
Expand Down Expand Up @@ -810,7 +814,10 @@ function AssetFilter({
{search && (
<button
type="button"
onClick={() => setSearch("")}
onClick={() => {
setSearch("");
setFocusedIndex(0);
}}
className="mt-1 text-[12px] text-ink-4 underline hover:text-ink-2"
>
Clear search
Expand Down
Loading