Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Sheet.scroller from within and Shadow DOM #179

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions example/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { DisableDrag } from './DisableDrag';
import { ScrollableSnapPoints } from './ScrollableSnapPoints';
import { ContentHeight } from './ContentHeight';
import { AvoidKeyboard } from './AvoidKeyboard';
import { ScrollableShadowDOM } from './ScrollableShadowDOM';

export function App() {
return (
Expand Down Expand Up @@ -53,6 +54,16 @@ export function App() {
</Screen>
}
/>

<Route
path="scrollable-shadow-dom/*"
element={
<Screen bg="light">
<ScrollableShadowDOM />
</Screen>
}
/>

<Route
path="scrollable/*"
element={
Expand All @@ -61,6 +72,7 @@ export function App() {
</Screen>
}
/>

<Route
path="avoid-keyboard/*"
element={
Expand Down Expand Up @@ -153,6 +165,13 @@ const ExampleSelector = () => {
</ExampleLink>
</li>

<li>
<ExampleLink to="scrollable-shadow-dom">
<ScrollIcon size={48} />
<span>Scrollable (in a Shadow DOM)</span>
</ExampleLink>
</li>

<li>
<ExampleLink to="disable-drag">
<LockIcon size={48} />
Expand Down
90 changes: 90 additions & 0 deletions example/components/ScrollableShadowDOM.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { useState, useEffect } from 'react';
import { Sheet } from 'react-modal-sheet';

import { Button } from './common';

const SHADOW_ROOT_ID = 'react-modal-sheet-shadow-root';

export function ScrollableShadowDOM() {
const [isOpen, setOpen] = useState(false);
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);

useEffect(() => {
// Create a shadow DOM root dynamically if it doesn't already exist
let shadowRootContainer = document.getElementById(SHADOW_ROOT_ID);
if (!shadowRootContainer) {
shadowRootContainer = document.createElement('div');
shadowRootContainer.id = SHADOW_ROOT_ID;
document.body.appendChild(shadowRootContainer);
}

// Attach shadow root and update state
if (!shadowRoot) {
const root = shadowRootContainer.attachShadow({ mode: 'open' });
setShadowRoot(root);
}

return () => {
// Clean up the shadow root when the component is unmounted
if (shadowRoot) {
shadowRoot.host.remove();
setShadowRoot(null);
}
};
}, [shadowRoot]);

const open = () => setOpen(true);
const close = () => setOpen(false);

return (
<>
<Button onClick={open}>Scrollable + Shadow DOM</Button>

{/* Render the Sheet only when the shadowRoot is ready */}
{shadowRoot && (
<Sheet
isOpen={isOpen}
onClose={close}
mountPoint={shadowRoot as unknown as HTMLElement}
>
<Sheet.Container>
<Sheet.Header />
<Sheet.Content>
<Sheet.Scroller>
{/* We used inline styles because the CSS in document.head is outside the shadow DOM */}
<div
style={{
display: 'flex',
flexDirection: 'column',
padding: '16px',
paddingTop: '0px',
}}
>
{Array.from({ length: 50 }).map((_, i) => (
<div
key={i}
style={{
backgroundColor: '#eee',
borderRadius: '12px',
minHeight: '200px',
marginBottom: '16px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: '700',
fontSize: '24px',
}}
>
{i}
</div>
))}
</div>
</Sheet.Scroller>
</Sheet.Content>
</Sheet.Container>
<Sheet.Backdrop />
</Sheet>
)}
</>
);
}
3 changes: 0 additions & 3 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions src/use-prevent-scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,9 @@ function preventScrollMobileSafari() {
let lastY = 0;

const onTouchStart = (e: TouchEvent) => {
const target = e.composedPath()?.[0] as HTMLElement;
// Store the nearest scrollable parent element from the element that the user touched.
scrollable = getScrollParent(e.target as Element, true);
scrollable = getScrollParent(target, true);
if (
scrollable === document.documentElement &&
scrollable === document.body
Expand Down Expand Up @@ -207,7 +208,7 @@ function preventScrollMobileSafari() {
};

const onTouchEnd = (e: TouchEvent) => {
const target = e.target as HTMLElement;
const target = e.composedPath()?.[0] as HTMLElement;

// Apply this change if we're not already focused on the target element
if (willOpenKeyboard(target) && target !== document.activeElement) {
Expand All @@ -225,7 +226,7 @@ function preventScrollMobileSafari() {
};

const onFocus = (e: FocusEvent) => {
const target = e.target as HTMLElement;
const target = e.composedPath()?.[0] as HTMLElement;
if (willOpenKeyboard(target)) {
// Transform also needs to be applied in the focus event in cases where focus moves
// other than tapping on an input directly, e.g. the next/previous buttons in the
Expand Down