Skip to content

Review 5343

Cindy Zhang edited this page Aug 23, 2026 · 1 revision

Review 5343 — AlertDialog, narrow surfaces

#5343 · rubyycheung · internal Head reviewed 24d843d04a115b09342cca1d14d560bfd931aedf Verdict request-changes · posted 2026-08-23 A/B vibe test, both arms drafted; A won — see Calibration.

Problem

An AlertDialog with a complete destructive label is unreadable on a phone. At 375px the surface is 337.5px (Dialog's maxWidth: 90vw) while the footer row wants 396px, so Button's whiteSpace: nowrap pushes the cancel button out through the left edge — "Keep this workspace" renders as "workspace", clipped mid-word. Measured on main: the button escapes the surface by 74px.

Solution

useMediaQuery('(max-width: 640px)') drives three things below the breakpoint: width is replaced with calc(100dvw - spacing-4 - spacing-4), the footer switches HStackStack direction="vertical" hAlign="stretch" with the destructive action first in DOM, and both buttons get width:100%; height:auto; whiteSpace:normal. Keying on width instead of pointer is the right call.

Impact

Everyone on the next release, no opt-in. @astryxdesign/core is public and published (0.4.7). Reaches past phones: any viewport 445–640px, including a half-width browser window on a laptop.

API

~ AlertDialog.width?: number | string = 400   (public, core barrel — SIGNATURE UNCHANGED,
                                               MEANING CHANGED: replaced, not clamped, at <=640px)

No props added or removed. No new exports.

Theme targets

None new. astryx-alert-dialog untouched. One existing target changes value: the footer Stack emits themeProps('stack', {direction}), so astryx-stack--direction-horizontal flips to vertical below 640px.

Ossification

Nothing new to freeze. The thing that quietly becomes a contract is the literal 640, a second copy of BREAKPOINT_VALUES.sm in AppShell — module-private, so neither can see the other and nothing fails when one moves.

Breaking

  • API — no. Every call site compiles; only width's meaning shifts.

  • Visual — yes, and it is the finding.

    viewport main this PR
    320 288px 288px
    375 337.5px 343px
    445 400px 413px
    640 400px 608px
    641 400px 400px

    640 → 641 snaps 608px ↔ 400px on one pixel of window drag. Buttons grow 32 → 36px. The isInline docs preview overflows its column: 468px inside a 458px column at 500px, 5px past the page edge.

  • Theme — yes, small. A theme selecting the footer's horizontal stack stops matching below 640px. Drove --spacing-4 to both far sides (0, 48px): sane.

Performance

No effects added. One useMediaQuery per AlertDialog, taken before the isOpen branch, so a mounted-but-closed dialog holds it too. One matchMedia listener, removed on unmount. No forced reflow, no new dependency. No perf test warranted.

Judgement

request changes — and the ask is a deletion, which makes the PR smaller.

  1. width is replaced rather than clamped, and 100dvw is viewport-relative → the isInline docs preview renders 468px inside a 458px column at 500px and runs off the page; on main it fits at 400px. · AlertDialog.tsx:210
  2. The same line makes geometry a step function at the breakpoint → dragging a desktop window across 640px snaps the dialog between 608px and 400px, buttons flipping from full-width stacked to a small right-aligned row. · AlertDialog.tsx:210
  3. The fix is keyed to viewport width, but what breaks is the dialog's own width → at 1440px cancelLabel="Keep this workspace" is still cut by the surface edge, by 11.5px, identically to main. The PR's own NarrowFinePointer story renders that state on any normal monitor. · AlertDialog.tsx:237 (pre-existing; not charged to the author, but it is why the shape is wrong)

Theme axis, deliberately not raised: the footer stack's data-direction flip is the intended consequence of stacking, and no shipped theme targets that stack.

On the shape. Root cause is that the footer action row cannot reflow — HStack with no wrap, Button with whiteSpace: nowrap and an ellipsizing label. True in every narrow container, not just AlertDialog. The unevadable fix is a dialog whose width clamps to its container and an action row that wraps — and #5352, open from the same author, is already adding exactly that to Dialog: max-width: min(100%, calc(100dvw - var(--spacing-4) - var(--spacing-4))), no breakpoint, plus HStack wrap="wrap" in its footers. Verified flex-wrap: wrap on this footer in Chromium at 1440px: the cancel button stops escaping. So delete the width half here, keep the stacking, add wrap.

Not an R3e hand-back — nothing permanent gets frozen either way, and the right mechanism is already in flight from the same person.

Evidence

31 frames, real Chromium, deviceScaleFactor 2, bare story iframe. Before (main) / after (head) / proposed at 320 · 375 · 445 · 500 · 640 · 641 · 800 · 1440 · RTL, plus the docs-column overflow pair and the in-browser wrap fix check.

Clone this wiki locally