Skip to content

[Refactor] Replace hand-rolled overlay logic with useOverlay hook#198

Merged
samzong merged 3 commits intomainfrom
fix/bottom-sheet-primitive
Mar 27, 2026
Merged

[Refactor] Replace hand-rolled overlay logic with useOverlay hook#198
samzong merged 3 commits intomainfrom
fix/bottom-sheet-primitive

Conversation

@samzong
Copy link
Copy Markdown
Collaborator

@samzong samzong commented Mar 27, 2026

Summary

Replace duplicated overlay infrastructure (scroll lock, focus trap, escape handling, body overflow) across BottomSheet and DrawerLayout with a single useOverlay hook. All overlays now render through portals, fixing stacking context fragility and adding proper inert, reduced-motion support, and iOS-safe scroll lock.

Type of change

  • [Refactor] internal cleanup

Why is this needed?

The prior BottomSheet and DrawerLayout each hand-rolled identical overlay logic with known defects:

  1. No portalposition: fixed breaks under ancestor transform/will-change/filter
  2. Broken scroll lockdocument.body.style.overflow = "hidden" fails on iOS Safari and races when multiple overlays coexist
  3. Global keydown listener — two open dialogs both handle the same keypress; requestAnimationFrame never cancelled on unmount
  4. No inert — background content remains focusable and interactive to assistive technology
  5. No prefers-reduced-motion — spring animations run regardless of user preference
  6. Undefined CSS variable--text-tertiary used in GatewayDebugLog but never defined

What changed?

  • New hooks/useOverlay.ts: portal target, ref-counted scroll lock (iOS position:fixed + scrollY save/restore), inert on #root, scoped focus trap via onKeyDown on container, requestAnimationFrame cleanup, isConnected guard on focus restore, useReducedMotion from framer-motion
  • Rewritten BottomSheet.tsx: delegates overlay concerns to useOverlay, renders via createPortal
  • Refactored DrawerLayout.tsx: removed hand-written scroll lock effect (lines 40-49) and focus trap effect (lines 51-88), drawer now portals via useOverlay
  • Added --text-tertiary: #838b97 to both dark and light themes in index.css

Architecture impact

  • Owning layer: renderer (PWA)
  • Cross-layer impact: none
  • Invariants touched from docs/architecture-invariants.md: none
  • Why those invariants remain protected: changes are scoped to PWA renderer overlay infrastructure only

Linked issues

Closes #

Validation

  • pnpm lint
  • pnpm test
  • pnpm check:ui-contract
  • pnpm check (full gate: lint + architecture + ui-contract + renderer-copy + i18n + dead-code + format + typecheck + test)
  • Manual smoke test

Commands, screenshots, or notes:

pnpm check — all passed (157 tests, 0 failures)

Screenshots or recordings

No visual changes. Overlay behavior (animation, drag-to-dismiss, backdrop, escape) is identical. The only visible difference is --text-tertiary now resolves correctly in GatewayDebugLog (previously fell through to inherited color).

Release note

  • No user-facing change. Release note is NONE.
NONE

Checklist

  • The PR title uses at least one approved prefix: [Refactor]
  • The summary explains both what changed and why
  • Validation reflects the commands actually run for this PR
  • Architecture impact is described and references any touched invariants
  • Cross-layer changes are explicitly justified
  • The release note block is accurate

samzong added 2 commits March 27, 2026 08:56
- Extract portal, ref-counted scroll lock (iOS-safe), focus trap,
  inert, reduced-motion, and focus restore into useOverlay hook
- Rewrite BottomSheet to portal via createPortal, fixing stacking
  context fragility from inline fixed positioning
- Migrate DrawerLayout drawer to useOverlay + portal, removing
  duplicated scroll lock and focus trap effects
- Add --text-tertiary to both themes, fixing undefined CSS variable
  in GatewayDebugLog
@github-actions
Copy link
Copy Markdown
Contributor

Hi @samzong,
Thanks for your pull request!
If the PR is ready, use the /auto-cc command to assign Reviewer to Review.
We will review it shortly.

Details

Instructions for interacting with me using comments are available here.
If you have questions or suggestions related to my behavior, please file an issue against the gh-ci-bot repository.

…itive

# Conflicts:
#	packages/pwa/src/components/BottomSheet.tsx
#	packages/pwa/src/components/GatewayDebugLog.tsx
#	packages/pwa/src/components/SettingsSheet.tsx
#	packages/pwa/src/views/DrawerLayout.tsx
@samzong samzong merged commit 5ee9a83 into main Mar 27, 2026
7 checks passed
@samzong samzong deleted the fix/bottom-sheet-primitive branch March 29, 2026 14:10
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