Skip to content

refactor(chrome): Drawer primitive — unify the 3 edge overlays - #253

Closed
catomean wants to merge 1 commit into
refactor/chrome-ssotfrom
refactor/chrome-drawer
Closed

refactor(chrome): Drawer primitive — unify the 3 edge overlays#253
catomean wants to merge 1 commit into
refactor/chrome-ssotfrom
refactor/chrome-drawer

Conversation

@catomean

Copy link
Copy Markdown
Collaborator

Stacked on #251 (base refactor/chrome-ssot). This is the deferred follow-up: the shared <Drawer> overlay primitive.

What

components/ui/Drawer.tsx — the edge-anchored sibling of <Modal>. One SSOT for right-side sheets and bottom sheets. It owns the parts that were hand-rolled (and drifting) in three places: the portal, useFocusTrap (Escape / initial focus / Tab cycle / focus restore), body scroll-lock, and the bg-black/40 backdrop-blur-xs click-to-close scrim.

API: isOpen / onClose / side='right'|'bottom' / ariaLabel, className (panel size), rootClassName (viewport gating like xl:hidden).

Migrated

Overlay Before After
MobileMenu portal + focus-trap + scroll-lock (the good reference) <Drawer side="right" rootClassName="xl:hidden"> — scaffolding extracted verbatim
MessageSidebar no portal / focus-trap / scroll-lock; backdrop didn't close; bg-opacity-50 <Drawer side="right">gains all of it; deprecated bg-opacity-50 gone
DashboardMobileNav sheet its own createPortal + useFocusTrap + scroll-lock <Drawer side="bottom" rootClassName="lg:hidden"> — duplication removed (also drops a setState-in-effect lint warning)

Verification

  • typecheck clean · lint 0 errors.
  • Browser-verified (screenshots in chat): the mobile menu opens through the Drawer (right panel + backdrop + full content — banner, collapsible nav, language pills, auth buttons), Escape closes it, body scroll-lock applies then releases on close, no console errors. MessageSidebar + dashboard sheet use the identical primitive, so they inherit the same behavior.

Docs

CLAUDE.md chrome decision-table gains Drawer + Modal rows; the "deferred drawer" note is replaced with the Drawer rule.

🤖 Generated with Claude Code

The edge-overlay sibling of <Modal>. SSOT for right-side sheets and bottom
sheets: owns the portal, useFocusTrap (Escape / initial focus / Tab cycle /
focus restore), body scroll-lock, and the bg-black/40 backdrop-blur-xs scrim.

- components/ui/Drawer.tsx — new. side='right'|'bottom'; isOpen/onClose/
  ariaLabel; className (panel size) + rootClassName (viewport gating).
- MobileMenu -> Drawer side=right rootClassName=xl:hidden (scaffolding
  extracted verbatim from the reference impl).
- MessageSidebar -> Drawer side=right. GAINS focus-trap, scroll-lock, Escape,
  click-to-close; drops deprecated bg-opacity-50.
- DashboardMobileNav sheet -> Drawer side=bottom rootClassName=lg:hidden;
  removes its duplicated createPortal + useFocusTrap + scroll-lock.

Docs: CLAUDE.md chrome table gains Drawer/Modal rows; deferred note replaced.

verify green (typecheck, lint 0 err). Browser-verified: mobile menu opens via
Drawer, Escape closes, scroll-lock applies then releases, no console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@catomean

Copy link
Copy Markdown
Collaborator Author

Shipped to main via fast-forward (rebased onto the current main atop #252). Live + prod-verified.

@catomean catomean closed this Jul 28, 2026
@catomean
catomean deleted the refactor/chrome-drawer branch July 28, 2026 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant