web: pin Connection Info modal header while body scrolls (#1754) (#1755)

Same fix as #1698, applied to the Connection Info modal, which had the same
pattern: a custom header Group (title + close) inside a Stack in the modal body,
using the default `<Modal>` with no `scrollAreaComponent`. With a long server
`instructions` section (e.g. the everything server) the details overflow the
viewport and the whole modal scrolled, taking the header out of view.

Switch to the compound `Modal.Root`/`Content`/`Header`/`Body` API, move the
header into `Modal.Header` (sticky by design) and set
`scrollAreaComponent={ScrollArea.Autosize}` so only the body scrolls. The
fade-down transition is supplied app-wide by `ThemeModalRoot` (added in #1753),
so no `transitionProps` literal is needed here.

Closes #1754


Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cliff Hall 2026-07-23 22:08:04 -04:00 • committed by GitHub
commit e788bcbaca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 53 additions and 21 deletions

View file

@ -1,4 +1,4 @@
import { CloseButton, Group, Modal, Stack } from "@mantine/core"; import { CloseButton, Group, Modal, ScrollArea } from "@mantine/core";
import type { import type {
ClientCapabilities, ClientCapabilities,
DiscoverResult, DiscoverResult,
@ -35,30 +35,40 @@ export function ConnectionInfoModal({
onClearOAuth, onClearOAuth,
}: ConnectionInfoModalProps) { }: ConnectionInfoModalProps) {
return ( return (
<Modal // Compound Modal so the header lives in `Modal.Header` (sticky by design)
// while `scrollAreaComponent` confines overflow to `Modal.Body` — otherwise
// a long connection-info payload grows the whole modal past the viewport and
// scrolls the header out of view (#1754, same fix as the settings modals in
// #1698). The fade-down transition is supplied app-wide by `ThemeModalRoot`.
<Modal.Root
opened={opened} opened={opened}
onClose={onClose} onClose={onClose}
withCloseButton={false}
size="lg" size="lg"
centered centered
scrollAreaComponent={ScrollArea.Autosize}
> >
<Stack gap="md"> <Modal.Overlay />
<Group justify="space-between" wrap="nowrap"> <Modal.Content>
{/* `Modal.Title` (not a bare `Title`) registers the modal's <Modal.Header>
accessible name — it wires the dialog's `aria-labelledby`. */} <Group justify="space-between" wrap="nowrap" w="100%">
<Modal.Title flex={1}>Connection Info</Modal.Title> {/* `Modal.Title` (not a bare `Title`) registers the modal's
<CloseButton aria-label="Close" onClick={onClose} /> accessible name — it wires the dialog's `aria-labelledby`. */}
</Group> <Modal.Title flex={1}>Connection Info</Modal.Title>
<ConnectionInfoContent <CloseButton aria-label="Close" onClick={onClose} />
initializeResult={initializeResult} </Group>
clientCapabilities={clientCapabilities} </Modal.Header>
transport={transport} <Modal.Body>
protocolEra={protocolEra} <ConnectionInfoContent
discoverResult={discoverResult} initializeResult={initializeResult}
oauth={oauth} clientCapabilities={clientCapabilities}
onClearOAuth={onClearOAuth} transport={transport}
/> protocolEra={protocolEra}
</Stack> discoverResult={discoverResult}
</Modal> oauth={oauth}
onClearOAuth={onClearOAuth}
/>
</Modal.Body>
</Modal.Content>
</Modal.Root>
); );
} }

View file

@ -1,3 +1,25 @@
# Connection Info modal: sticky header while body scrolls (#1754) — proof screenshots
Same fix as #1698, applied to the **Connection Info** modal. With a real server
whose `instructions` are long (e.g. the everything server in a typical config),
the connection details overflow the viewport; before the fix the whole modal
scrolled and the header left the view. Captured from the `ConnectionInfoModal`
Storybook story (`WithOAuth`, ~620px viewport) via Playwright.
![Connection Info scrolled to the top — header pinned, Server Implementation visible](ci-1754-header-pinned-top.png)
Top of scroll: the **Connection Info** header (title + close) sits above the
first section.
![Connection Info scrolled down — same header still pinned while the body shows Server Instructions / OAuth Details](ci-1754-header-pinned-scrolled.png)
Scrolled down (now showing Server Instructions → OAuth Details): the **same
header stays pinned**. Measured in-page: the body scroll container is
`scrollHeight` 1172 × `clientHeight` 558 (scrolls internally), header
`position: sticky` flush to the dialog top.
---
# Server/Client Settings modal: sticky header while body scrolls (#1698) — proof screenshots # Server/Client Settings modal: sticky header while body scrolls (#1698) — proof screenshots
Expanding enough accordion sections grew the Server Settings modal past the Expanding enough accordion sections grew the Server Settings modal past the

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB