fix(site): keep mobile model picker effort row and last model visible (#27336)

This commit is contained in:
Danielle Maywood
2026-07-21 12:37:55 +01:00
committed by GitHub
parent 850c6a712d
commit 6014a44c85
2 changed files with 64 additions and 5 deletions
+12 -4
View File
@@ -83,13 +83,21 @@
calc(100vh - var(--mobile-dropdown-above-composer-bottom, 9rem) - 1rem)
) !important;
overflow: hidden !important;
display: flex !important;
flex-direction: column !important;
}
/* min-height: 0 on both flex children lets the list shrink below its
content and scroll inside the capped column instead of overflowing. */
.mobile-full-width-dropdown-above-composer > [cmdk-root],
.mobile-full-width-dropdown-above-composer > [cmdk-root] > [cmdk-list] {
flex: 1 1 0% !important;
min-height: 0 !important;
}
.mobile-full-width-dropdown-above-composer > [cmdk-root] > [cmdk-list] {
max-height: none !important;
}
.mobile-full-width-dropdown-above-composer
.mobile-full-width-dropdown-scroll-area {
max-height: calc(
var(--mobile-dropdown-above-composer-max-height, 18rem) -
0.5rem
) !important;
overflow-y: auto !important;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useState } from "react";
import { useEffect, useState } from "react";
import { expect, fn, screen, userEvent, waitFor, within } from "storybook/test";
import { ModelSelector, type ModelSelectorOption } from "./ModelSelector";
import { MockModelSelectorOption } from "./modelSelectorFixtures";
@@ -450,3 +450,54 @@ export const EffortRowClampedToMax: Story = {
});
},
};
// The pinned effort row must stay inside the mobile dropdown's capped
// height above the composer while the model list scrolls.
export const MobileEffortRow: Story = {
args: {
options: [
...Array.from({ length: 30 }, (_, index) => ({
...MockModelSelectorOption,
id: `openai/model-${index}`,
model: `model-${index}`,
displayName: `Model ${index}`,
})),
effortModel,
],
value: "openai/gpt-5",
reasoningEffort: "medium",
onReasoningEffortChange: fn(),
enableMobileFullWidthDropdown: true,
},
parameters: {
// The interaction runner defaults to a desktop width where the
// mobile dropdown CSS never applies, so pin a mobile viewport.
viewport: { defaultViewport: "mobile1" },
// Capture the visual snapshot at a mobile width so the pinned
// effort row and scrollable list render in the CI visual gate.
lostpixel: { breakpoints: [320] },
},
decorators: [
(Story) => {
useEffect(() => {
// Tight enough that the model list plus the pinned effort row
// overflow the dropdown, forcing the layout under test.
const root = document.documentElement.style;
root.setProperty(
"--mobile-dropdown-above-composer-max-height",
"260px",
);
return () => {
root.removeProperty("--mobile-dropdown-above-composer-max-height");
};
}, []);
return <Story />;
},
],
play: async ({ canvasElement }) => {
// Open the picker so the snapshot captures the dropdown, the pinned
// effort row, and the scrollable list.
await userEvent.click(within(canvasElement).getByRole("combobox"));
await within(document.body).findByRole("listbox");
},
};