fix(nav): Back's focus keeps its place among items of the same name

Restoring by name picked the first item of that name, so Back on the log console (repeated
http.request lines) or two same-titled downloads landed on the wrong one. The saved place wins while
it still holds the name; otherwise the nearest item of that name.
This commit is contained in:
2026-09-19 05:47:16 +02:00
parent 1fa6a0bea8
commit 49fe56b6e7
2 changed files with 45 additions and 3 deletions
@@ -194,6 +194,37 @@ describe("rememberNavPosition · the list it comes back to (deep-review E11 roun
await waitFor(() => expect(focused()).toBe("I Am Mother"));
});
// Names repeat — a log console's `http.request GET /api/feed 200` lines. The first of them is not
// the one left: the saved place still holding the name wins, and when the list moved, the nearest.
it("among items of one name, takes the saved place or the nearest", async () => {
const Lines = ({ names }: { names: string[] }) => {
const ref = useRef<HTMLDivElement>(null);
useListNav(ref, { enabled: true });
return (
<div ref={ref} aria-label="Lines">
{names.map((name, i) => (
<div key={i} data-testid={`l${i}`} data-nav-name={name} {...navItemAttrs(i)}>
{name}
</div>
))}
</div>
);
};
const names = ["GET 200", "POST 200", "POST 200", "GET 200", "POST 200"];
const first = render(<Lines names={names} />);
const stamped = leaveFrom("l3", 4);
first.unmount();
landOn(stamped);
const back = render(<Lines names={names} />);
await waitFor(() => expect(focused()).toBe("l3"));
back.unmount();
(document.activeElement as HTMLElement | null)?.blur?.();
landOn(stamped);
// A line arrived above: the left one is l4 now, a GET two places up is l1.
render(<Lines names={["new", ...names]} />);
await waitFor(() => expect(focused()).toBe("l4"));
});
it("gives up on an unnamed list when the page came back with another number of lists", async () => {
const { unmount } = render(<Page />);
const stamped = leaveFrom("a1", 2);