fix: review round 1 — row press after a rename, related reset, dead items on removal, honest Prev/Next
- A press that begins while a field in the row is edited only ends the editing (rowOpen latches it at pointerdown); the card layout's row press is now tested. - A related video reset in the player forgets the session's stored position. - Removing the playing video passes over known-dead items and steps the way it went. - Prev/Next off only because of dead items stay focusable and say why (HU/EN). - The docked bar's scroller leaves room for focus rings. - A focus-opened About card is not closed by its own scroll into view. - EN "Clear watch progress" for the video reset, distinct from a page's "Reset view". - The signed-out title read goes to the page yt-dlp read; the retitle writes are conditional. - Tests: the cap of three errors, the bar's own Fullscreen, the group glyph, the backfill's reads.
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
//
|
||||
// The About cell's card opened the instant a pointer crossed the cell, so scrolling the table over
|
||||
// a column of them popped card after card. It waits for the pointer to rest on the cell now, and a
|
||||
// scroll puts an open one away.
|
||||
// scroll puts an open one away — unless the keyboard's focus opened it, whose own scroll into view
|
||||
// would put it away the moment it opened.
|
||||
import { describe, it, expect, vi, afterEach, beforeEach } from "vitest";
|
||||
import { render, screen, fireEvent, act, cleanup } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
@@ -66,4 +67,14 @@ describe("AboutCell — the hover card", () => {
|
||||
await wait(50);
|
||||
expect(card()).toBeNull();
|
||||
});
|
||||
|
||||
it("stays when the focus that opened it scrolls its cell into view", async () => {
|
||||
const cell = mount();
|
||||
act(() => cell.focus());
|
||||
await wait(10);
|
||||
expect(card()).not.toBeNull();
|
||||
act(() => void window.dispatchEvent(new Event("scroll")));
|
||||
await wait(50);
|
||||
expect(card()).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,17 +25,23 @@ const ABOUT_REST_MS = 500;
|
||||
export default function AboutCell({ text, channelId }: { text: string | null; channelId: string }) {
|
||||
const preview = (text ?? "").trim();
|
||||
const [open, setOpen] = useState(false);
|
||||
// Opened by the keyboard's focus: the scroll that brings a focused cell into view is that focus's
|
||||
// own, and would put the card away the moment it opened — so only a pointer's card goes on a scroll.
|
||||
const [byFocus, setByFocus] = useState(false);
|
||||
|
||||
const pop = useAnchoredPopover({
|
||||
open: open && !!preview,
|
||||
onOpenChange: setOpen,
|
||||
onOpenChange: (next, _event, reason) => {
|
||||
setByFocus(next && reason === "focus");
|
||||
setOpen(next);
|
||||
},
|
||||
mode: "hover",
|
||||
offset: 6,
|
||||
// Opens once the pointer rests on the cell, not as it crosses one: scrolling the table under a
|
||||
// still pointer, or moving down the column, used to pop card after card. The close grace lets
|
||||
// the cursor reach the card; a scroll puts an open one away.
|
||||
hoverDelay: { open: ABOUT_REST_MS, close: 160 },
|
||||
dismissOnScroll: true,
|
||||
dismissOnScroll: !byFocus,
|
||||
// Cap the panel to the space between the trigger and the viewport edge (publishes --fit-max-h) so a
|
||||
// long About never runs its top off-screen — at high browser zoom the short viewport made a fixed
|
||||
// max-height overflow above the top edge, where the scroll container can't reach.
|
||||
|
||||
Reference in New Issue
Block a user