Skip to content

Commit dd08e4a

Browse files
committed
refactor: support scroll while dragging in an iframe
1 parent 3c032b7 commit dd08e4a

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

src/view/use-droppable-publisher/get-closest-scrollable.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const isBoth = (overflow: Overflow, fn: (value: string) => boolean) =>
2020
fn(overflow.overflowX) && fn(overflow.overflowY);
2121

2222
const isElementScrollable = (el: Element): boolean => {
23-
const style: CSSStyleDeclaration = window.getComputedStyle(el);
23+
const style: CSSStyleDeclaration =
24+
el.ownerDocument.defaultView!.getComputedStyle(el);
2425
const overflow: Overflow = {
2526
overflowX: style.overflowX,
2627
overflowY: style.overflowY,
@@ -31,22 +32,23 @@ const isElementScrollable = (el: Element): boolean => {
3132

3233
// Special case for a body element
3334
// Playground: https://codepen.io/alexreardon/pen/ZmyLgX?editors=1111
34-
const isBodyScrollable = (): boolean => {
35+
const isBodyScrollable = (el: HTMLElement): boolean => {
3536
// Because we always return false for now, we can skip any actual processing in production
3637
if (process.env.NODE_ENV === 'production') {
3738
return false;
3839
}
3940

4041
const body: HTMLBodyElement = getBodyElement();
41-
const html: HTMLElement | null = document.documentElement;
42+
const html: HTMLElement | null = el.ownerDocument.documentElement;
4243
invariant(html);
4344

4445
// 1. The `body` has `overflow-[x|y]: auto | scroll`
4546
if (!isElementScrollable(body)) {
4647
return false;
4748
}
4849

49-
const htmlStyle: CSSStyleDeclaration = window.getComputedStyle(html);
50+
const htmlStyle: CSSStyleDeclaration =
51+
el.ownerDocument.defaultView!.getComputedStyle(html);
5052
const htmlOverflow: Overflow = {
5153
overflowX: htmlStyle.overflowX,
5254
overflowY: htmlStyle.overflowY,
@@ -76,12 +78,20 @@ const getClosestScrollable = (el?: HTMLElement | null): HTMLElement | null => {
7678
}
7779

7880
// not allowing us to go higher then body
79-
if (el === document.body) {
80-
return isBodyScrollable() ? el : null;
81+
if (el === el.ownerDocument.body) {
82+
if (isBodyScrollable(el)) {
83+
return el;
84+
}
85+
86+
if (el.ownerDocument.defaultView?.frameElement) {
87+
return el.ownerDocument.defaultView?.frameElement as HTMLElement;
88+
}
89+
90+
return null;
8191
}
8292

8393
// Should never get here, but just being safe
84-
if (el === document.documentElement) {
94+
if (el === el.ownerDocument.documentElement) {
8595
return null;
8696
}
8797

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import type { Position } from 'css-box-model';
22

3-
export default (el: Element): Position => ({
4-
x: el.scrollLeft,
5-
y: el.scrollTop,
6-
});
3+
export default (el: Element): Position => {
4+
const isIframe = el.tagName === 'IFRAME';
5+
6+
if (isIframe) {
7+
const targetEl = (el as HTMLIFrameElement).contentWindow!;
8+
9+
return { x: targetEl.scrollX, y: targetEl.scrollY };
10+
}
11+
12+
return {
13+
x: el.scrollLeft,
14+
y: el.scrollTop,
15+
};
16+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default (scrollable: HTMLElement) => {
2+
const scrollableIsIframe = scrollable.tagName === 'IFRAME';
3+
4+
const scrollableTarget = scrollableIsIframe
5+
? (scrollable as HTMLIFrameElement).contentWindow!
6+
: scrollable;
7+
8+
return scrollableTarget;
9+
};

src/view/use-droppable-publisher/use-droppable-publisher.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import useRequiredContext from '../use-required-context';
3333
import usePreviousRef from '../use-previous-ref';
3434
import useLayoutEffect from '../use-isomorphic-layout-effect';
3535
import useUniqueId from '../use-unique-id';
36+
import getScrollable from './get-scrollable';
3637

3738
interface Props {
3839
droppableId: DroppableId;
@@ -153,7 +154,7 @@ export default function useDroppablePublisher(args: Props) {
153154
shouldClipSubject: !previous.ignoreContainerClipping,
154155
});
155156

156-
const scrollable: Element | null = env.closestScrollable;
157+
const scrollable = env.closestScrollable;
157158

158159
if (scrollable) {
159160
scrollable.setAttribute(
@@ -162,7 +163,7 @@ export default function useDroppablePublisher(args: Props) {
162163
);
163164

164165
// bind scroll listener
165-
scrollable.addEventListener(
166+
getScrollable(scrollable).addEventListener(
166167
'scroll',
167168
onClosestScroll,
168169
getListenerOptions(dragging.scrollOptions),
@@ -204,7 +205,7 @@ export default function useDroppablePublisher(args: Props) {
204205
// unwatch scroll
205206
scheduleScrollUpdate.cancel();
206207
closest.removeAttribute(dataAttr.scrollContainer.contextId);
207-
closest.removeEventListener(
208+
getScrollable(closest).removeEventListener(
208209
'scroll',
209210
onClosestScroll,
210211
// See: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener

0 commit comments

Comments
 (0)