Pickers: anchor the desktop dropdown to its chip, never clipped
"The model selection in teach it back is kinda broken at least on desktop": the desktop panels were position:absolute children of whatever container held their chip. In chat that is the composer at the bottom of the column, which works, but Teach it back keeps its chips inside a scrolling form card — so the panel opened upward out of the card and its top rows (including the selected model) were cut off. The probe measured top: -66px and no way to reach the first rows by scrolling the list. - New components/chat/PickerPopover.tsx: the desktop surface for both pickers, portalled to <body> and position:fixed, anchored to the opening chip ([data-picker-trigger][aria-expanded="true"]), opening on the side with room and capped to the viewport so the panel scrolls as a whole with its heading and note attached. It closes on an outside press, Escape, resize or a page scroll — but not on scrolling its own list. - ContextPicker and ModelPicker use it on desktop; the phone sheets and their inner list caps are unchanged (the list max-height became a parameter: the sheet caps it, the desktop panel scrolls instead). - teach-test pins it: the panel's rect is fully inside the viewport, elementFromPoint over it lands on the panel, it is not a descendant of the scrolling card, and picking a model updates the chip + freezmo.chat.model.v1 (46 checks). Chat and the phone sheets re-verified unchanged (110 + 128). Version 0.8.3, SW v105.
This commit is contained in:
parent
d72b335965
commit
705808d45a
7 changed files with 215 additions and 82 deletions
|
|
@ -224,6 +224,42 @@ try {
|
|||
(await page.getByRole("button", { name: "Skeptical student" }).getAttribute("aria-pressed")) === "true",
|
||||
);
|
||||
|
||||
/* The model dropdown lives in a fixed, portalled panel: inside the
|
||||
scrolling card it used to open off the top of the viewport and lose its
|
||||
first rows. */
|
||||
await page.locator("[data-picker-trigger]").last().click();
|
||||
const modelDialog = page.getByRole("dialog", { name: "Chat model" });
|
||||
await modelDialog.waitFor({ timeout: 5000 });
|
||||
const panelFit = await modelDialog.evaluate((node) => {
|
||||
const rect = node.getBoundingClientRect();
|
||||
const centre = document.elementFromPoint(rect.left + rect.width / 2, rect.top + 12);
|
||||
return {
|
||||
inside:
|
||||
rect.top >= 0 &&
|
||||
rect.left >= 0 &&
|
||||
rect.bottom <= window.innerHeight + 1 &&
|
||||
rect.right <= window.innerWidth + 1,
|
||||
onTop: Boolean(centre && node.contains(centre)),
|
||||
portalled: node.closest(".chat-scroll") === null,
|
||||
};
|
||||
});
|
||||
check(
|
||||
"ui: the model dropdown fits the viewport and is not clipped by the card",
|
||||
panelFit.inside && panelFit.onTop && panelFit.portalled,
|
||||
JSON.stringify(panelFit),
|
||||
);
|
||||
await modelDialog.getByRole("button", { name: /stub-vision/i }).first().click();
|
||||
await page.waitForTimeout(300);
|
||||
check(
|
||||
"ui: picking a model updates the chip and is remembered",
|
||||
(await page.getByRole("button", { name: /Stub Vision/ }).count()) > 0 &&
|
||||
(await page.evaluate(() => window.localStorage.getItem("freezmo.chat.model.v1"))) === "stub-vision",
|
||||
);
|
||||
/* Back to the first model so the session checks below stay on stub-text. */
|
||||
await page.locator("[data-picker-trigger]").last().click();
|
||||
await page.getByRole("dialog", { name: "Chat model" }).getByRole("button", { name: /stub-text/i }).first().click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
/* 6. UI: a session ----------------------------------------------- */
|
||||
turns = 0;
|
||||
await page.getByTestId("teach-start").click();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue