feat(prevent-scroll): lock modal overlay body scroll via usePreventScroll#1640
feat(prevent-scroll): lock modal overlay body scroll via usePreventScroll#1640te6-in wants to merge 10 commits into
Conversation
…move-scroll Wrap modal Dialog/Drawer content in RemoveScroll (enabled when modal && open), routed through a Primitive.div + asChild Slot (ScrollLockSlot) so the scroll lock merges onto the existing dialog element instead of inserting a wrapper node, which would break flex-child layouts like BottomSheet content. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…g for backdrop-only model Remove the `blockPointerEvents` feature from useDismissibleLayer/layer-stack and the vaul-era body pointer-events resets from useDrawer. Both Drawer and Dialog now rely solely on the backdrop to absorb background interaction, matching Dialog's existing model and avoiding mutation of the shared document.body — fragile under stackflow where every activity shares one body and a body-none freezes sibling AppScreens pushed on top. - useDismissibleLayer: remove body-block effect, per-layer pointer-events style, and the originalBodyPointerEvents module state - layer-stack: remove Layer.blockPointerEvents, isBelowPointerBlockingLayer, getPointerEventsEnabled - use-pointer-down-outside: drop the isBelowPointerBlockingLayer guard, which was already redundant with the isTopMost guard above it - Drawer: stop passing blockPointerEvents; drop vaul body "auto" resets - positioner pointer-events (closed full-screen positioner) kept intact Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…locking page scroll The inline StackflowPreview rendered stackflow activities (e.g. a defaultOpen AlertDialog) directly in the docs document. With the modal scroll lock (react-remove-scroll), an open inline dialog locked the shared document.body and froze the whole docs page. Restrict StackflowExample to the isolated iframe preview so those global effects stay scoped to the iframe's own document. - StackflowExample: drop the names/StackflowPreview inline path; require path - migrate 11 inline stackflow examples to standalone stackflow-spa activities (app-screen x4, alert-dialog, result-section, article x2, pull-to-refresh x3), register routes, and point docs at them via path= + doc-gen:file - remove the chip-tabs and inline-banner stackflow examples - delete the now-orphaned StackflowPreview and inline Stackflow runtime Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eventScroll New @seed-design/react-prevent-scroll (internal, 0.0.0). Vendors react-aria's usePreventScroll (standard + mobile Safari paths) with the react-stately/shadow-DOM coupling removed. Locks the root element via scrollbar-gutter (or paddingRight) + overflow:hidden, so position:fixed/sticky elements don't shift the way react-remove-scroll's removeScrollBar body margin-right does. No pointer-events handling — that stays owned by DismissibleLayer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace react-remove-scroll with @seed-design/react-prevent-scroll. The RemoveScroll
wrapper and ScrollLockSlot are removed; DialogContent/DrawerContent now call
usePreventScroll({ isDisabled: !(modal && open) }). This fixes the fixed/sticky-element
layout shift caused by removeScrollBar's body margin-right, and drops the
react-remove-scroll dependency from both packages. The Drawer scroll-lock test now
asserts on the root element's overflow instead of the react-remove-scroll-only
data-scroll-locked attribute.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… iOS 16.4 Constructable CSSStyleSheet / document.adoptedStyleSheets is Safari/iOS 16.4+ only, so the overscroll-behavior rule stays a <style> injection for now. Leaves a TODO to migrate (and drop getNonce) once the support floor reaches Safari/iOS 16.4+. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The global reset locked body scrolling, making the document root non-scrollable. usePreventScroll locks the root scroller, so a faithful manual test of the modal scroll lock needs the root to actually scroll. Removing overflow:hidden lets a non-AppScreen activity drive root scroll. Verified no regression across activity types: AppScreen activities keep content in an out-of-flow absolute layer (body scrollHeight 0), and non-AppScreen activities either constrain their own height or render minimal bases, so none of the existing activities gain an unintended root scroll. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Alpha Preview (Stackflow SPA)
|
Alpha Preview (Storybook)
|
Alpha Preview (Docs)
|
Scroll lock is handled solely by usePreventScroll since 2fcfe06. usePositionFixed was already a no-op under the default noBodyStyles=true and no internal caller passed noBodyStyles=false, so removing the hook and the noBodyStyles/preventScrollRestoration props is behavior-preserving. Also drop the now-unused isSafari helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
No description provided.