Skip to content

ReAuthBannerBar overflows viewports narrower than 420px, and keeps flat CSS out of the Paper theme #2218

Closed

Description

@cliffhall

Two findings from the v2.5.0 milestone-merge review (#2215), both in clients/web/src/components/groups/ReAuthBanner/ReAuthBannerBar.tsx, which shipped on v2/main during the milestone. Filed here rather than fixed in the merge PR, whose tree is byte-identical to origin/v2/main.

1. The fixed 420px width overflows a narrow viewport (bug)

export const ReAuthBannerBar = Paper.withProps({
  pos: "fixed", top: "50%", left: "50%", w: 420,
  styles: { root: { transform: "translate(-50%, -50%)", zIndex: 200 } },
});

w: 420 is unconditional. Below a 420px viewport the banner is wider than the window, and because it is centred by left: 50% + translate(-50%, -50%) it overflows both edges equally — so it clips its close button on one side and the "Authorize again" action on the other. Those are the only two controls it has, and the component's own header comment explains that dismissing is not equivalent to ignoring it ("Authorize again" also clears the stale OAuth state, which a plain reconnect does not). Losing both controls is therefore a dead end, not a cosmetic clip.

It is reachable in a narrow desktop window, not only on a phone — the component is fixed-positioned against the viewport, so a user who has the browser docked to a third of a wide screen hits it.

Fix: cap rather than fix the width — a viewport-relative width with a 420px maximum, e.g. w="min(420px, calc(100vw - 2rem))" (or maw={420} with a relative w), keeping a gutter so the shadow and radius still read. Worth a story or a test at a narrow viewport, since nothing currently exercises this component below 420px.

2. transform / zIndex belong in a Paper theme variant (convention)

The same constant carries flat CSS in component-level styles. AGENTS.md is explicit that flat CSS properties belong in the theme layer, and clients/web/src/theme/Paper.ts already carries code, contained and panel root styles for exactly this.

The file's existing comment is correct that Mantine exposes neither transform nor zIndex as a style prop — but that argues for the theme variant, which is the next tier in the repo's preference order (props → theme variant → CSS class), not for inline styles.

Fix: add a reauth variant to theme/Paper.ts holding transform and zIndex, and select it here with variant: "reauth" in the .withProps() call.

The trade-off, recorded rather than hidden: this splits one component's positioning across two files, and these styles are genuinely local to this banner rather than a global Paper customization. That is an argument about where the convention's boundary should sit, not an exemption from it — the convention as written covers this, and the variant costs three lines.

Not actionable

The same review also flagged an unterminated inline-code span in clients/web/src/lib/authToken.ts:18. That is incorrect — the line reads // in the `x-mcp-remote-auth: Bearer …` header or the Hono backend returns 401. and carries exactly two backticks, balanced. Nothing to change.

Reported by Copilot on #2215.

Activity

  1. added this to the v2.6.0 milestone on Sep 1, 2026
  2. self-assigned this
    on Sep 1, 2026
  3. added
    bugSomething isn't working
    v2Issues and PRs for v2
    on Sep 1, 2026
  4. removed their assignment
    on Sep 2, 2026
  5. ump45nose commented on Sep 3, 2026

    @ump45nose

    I reproduced this locally and implemented both fixes. Per this repo's issues-only policy I'm not opening a PR — here is the prompt, the before/after, and how I verified it.

    One correction to finding 1 first

    The suggested w="min(420px, calc(100vw - 2rem))" does not work as written with Mantine. w is a spacing-style prop, and Mantine's spacingResolver splits string values on commas (it treats comma-separated values as a responsive list). The probe result: min(420px, calc(100vw - 2rem)) renders no width at all — the element gets neither a width nor a max-width inline style. The correct way to express "viewport-relative, capped at 420px" is to make the cap a separate prop:

    w="calc(100vw - 2rem)"
    maw={420}
    

    Prompt used

    In clients/web/src/components/groups/ReAuthBanner/ReAuthBannerBar.tsx, move the transform/zIndex flat CSS out of the component-level styles.root into a new reauth variant in clients/web/src/theme/Paper.ts, select it with variant: "reauth", and change the fixed w: 420 to a viewport-relative width capped at 420px so a narrow viewport never clips the two controls. Use w="calc(100vw - 2rem)" with maw={420} rather than a min() string, because Mantine's spacing resolver splits strings on commas. Keep the existing test assertions and add one that checks the capped width.

    Before / after

    Before:

    export const ReAuthBannerBar = Paper.withProps({
      pos: "fixed", top: "50%", left: "50%", w: 420,
      bg: "var(--mantine-color-body)", shadow: "xl", radius: "md",
      styles: { root: { transform: "translate(-50%, -50%)", zIndex: 200 } },
    });

    After:

    export const ReAuthBannerBar = Paper.withProps({
      pos: "fixed", top: "50%", left: "50%",
      w: "calc(100vw - 2rem)", maw: 420,
      bg: "var(--mantine-color-body)", shadow: "xl", radius: "md",
      variant: "reauth",
    });

    and in theme/Paper.ts:

    if (props.variant === "reauth") {
      return { root: { transform: "translate(-50%, -50%)", zIndex: 200 } };
    }

    Verification

    • Added reauth to the VARIANTS exercised in clients/web/src/theme/Paper.test.tsx (so the new theme branch is covered).
    • Added a test in ReAuthBannerBar.test.tsx asserting style.width === "calc(100vw - 2rem)" and style.maxWidth === "calc(26.25rem * var(--mantine-scale))" (Mantine renders maw={420} in rems × scale).
    • npx vitest run --project=unit src/components/groups/ReAuthBanner/ReAuthBannerBar.test.tsx src/theme/Paper.test.tsx → 8 tests passed.
    • eslint --max-warnings 0 and prettier --check pass on all four touched files.

    I confirmed the existing transform/zIndex assertions still pass via the reauth variant (the styled DOM is unchanged apart from the added width/max-width), and confirmed the min() bug by rendering w="min(420px, calc(100vw - 2rem))" directly against a Paper and observing no width style in the output.

    AI assistance disclosure: AI was used to discover this opportunity and draft the change or text. The submission was checked against the prepared artifact and recorded verification evidence.

  6. self-assigned this
    on Sep 6, 2026
  7. cliffhall commented on Sep 6, 2026

    @cliffhall
    MemberAuthor

    Fixed by #2266, merged to v2/main as 5402aea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingv2Issues and PRs for v2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions