docs: the folding channel header in its e2e, and three comments brought up to date
The e2e asserted the channel chrome never moves; it folds once now. The ui catalog lists scrollFold and progressiveRows, Tabs names the per-tab memory its callers use, and the welcome note says a removed language orphans its stored copies too.
This commit is contained in:
@@ -106,28 +106,34 @@ test.describe("channel view", () => {
|
||||
await expectContentType(page, "includeLive", false);
|
||||
});
|
||||
|
||||
// Platform S4b: the whole channel chrome (banner, identity, tabs, toolbar) is fixed — it stays
|
||||
// put while only the video grid scrolls.
|
||||
test("the channel chrome stays fixed while the video grid scrolls", async ({ page }) => {
|
||||
// Platform S4b + E31 S4c: the channel chrome sits outside the scroller. Scrolling into the videos
|
||||
// folds the banner and identity once (the name moves into the tab row); from then on the folded
|
||||
// chrome stays put while only the video grid scrolls.
|
||||
test("the channel chrome folds once, then stays fixed while the grid scrolls", async ({
|
||||
page,
|
||||
}) => {
|
||||
await openApp(page);
|
||||
await page.getByTestId("video-card-channel").first().click();
|
||||
const count = page.getByTestId("item-count");
|
||||
const title = page.getByTestId("channel-title");
|
||||
await expect(count).toBeVisible();
|
||||
await expect(page.getByTestId("video-card").first()).toBeVisible();
|
||||
const titleTop = await title.evaluate((el) => el.getBoundingClientRect().top);
|
||||
const countTop = await count.evaluate((el) => el.getBoundingClientRect().top);
|
||||
await expect(page.getByTestId("channel-folded")).toHaveCount(0);
|
||||
|
||||
// Keep nudging until the grid is tall enough to actually scroll (it may still be filling in).
|
||||
await expect
|
||||
.poll(async () => {
|
||||
await page.getByRole("main").evaluate((el) => el.scrollBy(0, 1500));
|
||||
await page.getByRole("main").evaluate((el) => el.scrollBy(0, 600));
|
||||
return page.getByRole("main").evaluate((el) => el.scrollTop);
|
||||
})
|
||||
.toBeGreaterThan(400);
|
||||
const folded = page.getByTestId("channel-folded");
|
||||
await expect(folded).toBeVisible();
|
||||
await expect(folded.getByTestId("channel-title")).toBeVisible();
|
||||
const titleTop = await folded.evaluate((el) => el.getBoundingClientRect().top);
|
||||
const countTop = await count.evaluate((el) => el.getBoundingClientRect().top);
|
||||
|
||||
// The chrome didn't move — banner title and toolbar are in exactly the same place.
|
||||
expect(await title.evaluate((el) => el.getBoundingClientRect().top)).toBe(titleTop);
|
||||
await page.getByRole("main").evaluate((el) => el.scrollBy(0, 400));
|
||||
expect(await folded.evaluate((el) => el.getBoundingClientRect().top)).toBe(titleTop);
|
||||
expect(await count.evaluate((el) => el.getBoundingClientRect().top)).toBe(countTop);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,8 +40,8 @@ domain-free.
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| overlays & anchoring | `AnchoredPopover` + `anchoredPopoverHooks` (the popover engine: arrows, typeahead, Escape, anchor-flip), `ActionMenu`, `ContextMenu` + `useContextMenu` (the SAME menu, opened by right-click / long-press / Shift+F10 / a row's `MoreButton` "…" via `buttonProps`; `anchor` for a panel a row opens; `PageMenu` for a page's background menu), `Modal` (+ `ModalFooter`; `initialFocus` by purpose, C4), `Overlay`, `SidePanel`, `Tooltip`, `Toaster` (+ `toastLevels`, `overlayOrder`; `lib/toastDock` docks one control under the stack, in every host), `CommandPalette`, `KeyboardHelp` |
|
||||
| actions & inputs | `Button`, `IconButton`, `Pressable` (`selectable` when its text is a title or a name), `Chip` + `chipStyles`, `DragHandle` + `OrderButtons` / `useOrderItems` (the non-drag reorder, WCAG 2.5.7) (one per button family, docs/DESIGN.md; a raw `<button>` or a bare `FocusSafeButton` outside the control primitives — eslint `BUTTON_PRIMITIVES` — is a lint error), `Input` + `fieldStyles`, `NativeControls`, `MenuCheck` (the drawn check of a menu row or a whole-row checkbox button), `SelectTrigger` (the field family; a raw `<input>` is a lint error), `useReturnFocus`, `surfaces` (the B5 glass roles; a bare glass class is a lint error), `Badge` (a static label), `LinkButton` / `IconLink` (a link wearing the button face) over `buttonStyles`, `Skeleton` (B8 first loads, through `LoadingState shape`), `NavRail` (B7; `NavRailGroup` folds a set of rare pages into one row with a panel), `form`, `DraftSaveBar`, `Combobox`, `FilterSelect`, `SegmentedToggle`, `SortControl`, `ColumnSortControl`, `PriorityStepper`, `UndoToolbar` |
|
||||
| data display | `DataTable`, `tableHeader` + `tableAlign`, `HiddenFilterCue` (names a filter whose column is off screen), `Pager` + `pagerContent`, `VirtualGrid` + `gridColumns` (the column/width maths, incl. the ultrawide `maxCols` cap), `readAhead`, `Carousel`, `MediaCard` + `mediaCardStyles` (the one media card, docs/DESIGN.md "Media card") + `MediaPreview` / `useMediaPreview` (its mouse-rest preview), `NavGrid` (a plain grid, list or table body the keyboard walks — `DataTable`, `VirtualGrid` and `Carousel` take `keyboardNav`), `Avatar`, `CountBadge`, `ItemCount`, `FilterChipGroup`, `RelativeTime` ("3d ago" with the exact minute on hover, docs/DESIGN.md "Copy"), `ClampedText` (a long text clamped to a few lines; More / Less only when it is cut), `StatTiles` + `StatTile` / `StatBars` (number tiles, a breakdown as horizontal bars) |
|
||||
| page & panel structure | `PageShell` + `pageToolbarSlot` + `pageHeading`, `PageScroller`, `Headings` (`PageHeading`, `SectionLabel`), `SkipLink` + `landmarks`, `FilterFold` (B4), `PanelGroup`, `PanelGroups`, `Tabs`, `BackToTop` |
|
||||
| data display | `DataTable` (+ `progressiveRows`: a long page mounts in steps), `tableHeader` + `tableAlign`, `HiddenFilterCue` (names a filter whose column is off screen), `Pager` + `pagerContent`, `VirtualGrid` + `gridColumns` (the column/width maths, incl. the ultrawide `maxCols` cap), `readAhead`, `Carousel`, `MediaCard` + `mediaCardStyles` (the one media card, docs/DESIGN.md "Media card") + `MediaPreview` / `useMediaPreview` (its mouse-rest preview), `NavGrid` (a plain grid, list or table body the keyboard walks — `DataTable`, `VirtualGrid` and `Carousel` take `keyboardNav`), `Avatar`, `CountBadge`, `ItemCount`, `FilterChipGroup`, `RelativeTime` ("3d ago" with the exact minute on hover, docs/DESIGN.md "Copy"), `ClampedText` (a long text clamped to a few lines; More / Less only when it is cut), `StatTiles` + `StatTile` / `StatBars` (number tiles, a breakdown as horizontal bars) |
|
||||
| page & panel structure | `PageShell` + `pageToolbarSlot` + `pageHeading`, `PageScroller`, `Headings` (`PageHeading`, `SectionLabel`), `SkipLink` + `landmarks`, `FilterFold` (B4), `scrollFold` (`useScrollFold`: a fixed header that folds once its content scrolls), `PanelGroup`, `PanelGroups`, `Tabs`, `BackToTop` |
|
||||
| state & messaging | `QueryState`, `Banner`, `InlineNotice` |
|
||||
|
||||
## The size contract (E10 S1c)
|
||||
|
||||
@@ -9,7 +9,8 @@ import CountBadge from "./CountBadge";
|
||||
// Below it a side rail leaves a phone too little width for the content beside it (measured at 390 px:
|
||||
// the rail clipped its own labels and Settings → Account pushed its buttons over their text), so there
|
||||
// it is a horizontal row that scrolls. Callers persist the active tab with lib/storage's
|
||||
// useAccountPersistedState (account-scoped), so a reload keeps the user where they were.
|
||||
// useTabPersistedState (per browser tab, E31 S4b): a reload keeps the user where they were, and a
|
||||
// fresh tab opens on the first sub-tab rather than wherever the last visit ended.
|
||||
//
|
||||
// An ARIA tab list (E28 review F3), not a row of toggle buttons: `tablist` / `tab` / `aria-selected`,
|
||||
// ONE Tab stop (the selected tab; roving tabindex), the arrows move and select (either axis, since the
|
||||
|
||||
Reference in New Issue
Block a user