fix(channels): a pick in the +N fold keeps the focus on its chip after the fold closes
The closing popover hands the focus back to "+N" in a microtask it queues as it unmounts, after the chip was focused (seen in Chrome; jsdom does not show it). A second focus, queued after it, wins.
This commit is contained in:
@@ -152,12 +152,14 @@ describe("TagFilterChips focus on a toggle that moves the chip", () => {
|
||||
// React gives the focus back to it after the commit. Only a remount (row ↔ fold) or a chip that
|
||||
// leaves the list loses it.
|
||||
|
||||
it("out of the fold: picked in the popover, it is focused on the row", () => {
|
||||
it("out of the fold: picked in the popover, it is focused on the row", async () => {
|
||||
fit.visible = 1;
|
||||
render(<Row start={[]} />);
|
||||
fireEvent.click(moreBtn()!);
|
||||
const inFold = named("beta");
|
||||
press(inFold);
|
||||
// The closing popover hands the focus back to "+N" a microtask later: past that too.
|
||||
await act(async () => {});
|
||||
const onRow = named("beta");
|
||||
expect(onRow).not.toBe(inFold);
|
||||
expect(document.activeElement).toBe(onRow);
|
||||
|
||||
@@ -136,13 +136,14 @@ export default function TagFilterChips({
|
||||
// closed fold, or onto the chip now in its old place when it is gone. A toggle in the open fold
|
||||
// closes it, so the focus never sits outside a popover left open. Held for the frame, since the fit
|
||||
// re-decides in layout effects after the toggle's render.
|
||||
const follow = useRef<{ key: string; at: number } | null>(null);
|
||||
const follow = useRef<{ key: string; at: number; closed: boolean } | null>(null);
|
||||
const foldRef = useRef<HTMLDivElement | null>(null);
|
||||
const moreRef = useRef<HTMLButtonElement | null>(null);
|
||||
const onToggled = (chipKey: string, from: HTMLElement) => {
|
||||
follow.current = { key: chipKey, at: chips.findIndex((c) => c.key === chipKey) };
|
||||
const closed = !!foldRef.current?.contains(from);
|
||||
follow.current = { key: chipKey, at: chips.findIndex((c) => c.key === chipKey), closed };
|
||||
requestAnimationFrame(() => (follow.current = null));
|
||||
if (foldRef.current?.contains(from)) setOpen(false);
|
||||
if (closed) setOpen(false);
|
||||
};
|
||||
useLayoutEffect(() => {
|
||||
const target = follow.current;
|
||||
@@ -158,6 +159,9 @@ export default function TagFilterChips({
|
||||
find(inBox(foldRef.current)) ??
|
||||
(gone ? (row[Math.min(target.at, row.length - 1)] ?? moreRef.current) : moreRef.current);
|
||||
if (el && document.activeElement !== el) el.focus();
|
||||
// The closing popover gives the focus back to "+N" in a microtask it queued as it unmounted
|
||||
// (seen in Chrome): this one, queued after it, has the last word.
|
||||
if (el && target.closed) queueMicrotask(() => el.isConnected && el.focus());
|
||||
});
|
||||
const setMore = (el: HTMLButtonElement | null) => {
|
||||
moreRef.current = el;
|
||||
|
||||
Reference in New Issue
Block a user