Skip to content

Commit

Permalink
refactor: support scroll while dragging in an iframe
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvxd committed Feb 28, 2024
1 parent 3c032b7 commit dd08e4a
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 14 deletions.
24 changes: 17 additions & 7 deletions src/view/use-droppable-publisher/get-closest-scrollable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const isBoth = (overflow: Overflow, fn: (value: string) => boolean) =>
fn(overflow.overflowX) && fn(overflow.overflowY);

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

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

const body: HTMLBodyElement = getBodyElement();
const html: HTMLElement | null = document.documentElement;
const html: HTMLElement | null = el.ownerDocument.documentElement;
invariant(html);

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

const htmlStyle: CSSStyleDeclaration = window.getComputedStyle(html);
const htmlStyle: CSSStyleDeclaration =
el.ownerDocument.defaultView!.getComputedStyle(html);
const htmlOverflow: Overflow = {
overflowX: htmlStyle.overflowX,
overflowY: htmlStyle.overflowY,
Expand Down Expand Up @@ -76,12 +78,20 @@ const getClosestScrollable = (el?: HTMLElement | null): HTMLElement | null => {
}

// not allowing us to go higher then body
if (el === document.body) {
return isBodyScrollable() ? el : null;
if (el === el.ownerDocument.body) {
if (isBodyScrollable(el)) {
return el;
}

if (el.ownerDocument.defaultView?.frameElement) {
return el.ownerDocument.defaultView?.frameElement as HTMLElement;
}

return null;
}

// Should never get here, but just being safe
if (el === document.documentElement) {
if (el === el.ownerDocument.documentElement) {
return null;
}

Expand Down
18 changes: 14 additions & 4 deletions src/view/use-droppable-publisher/get-scroll.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import type { Position } from 'css-box-model';

export default (el: Element): Position => ({
x: el.scrollLeft,
y: el.scrollTop,
});
export default (el: Element): Position => {
const isIframe = el.tagName === 'IFRAME';

if (isIframe) {
const targetEl = (el as HTMLIFrameElement).contentWindow!;

return { x: targetEl.scrollX, y: targetEl.scrollY };
}

return {
x: el.scrollLeft,
y: el.scrollTop,
};
};
9 changes: 9 additions & 0 deletions src/view/use-droppable-publisher/get-scrollable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default (scrollable: HTMLElement) => {
const scrollableIsIframe = scrollable.tagName === 'IFRAME';

const scrollableTarget = scrollableIsIframe
? (scrollable as HTMLIFrameElement).contentWindow!
: scrollable;

return scrollableTarget;
};
7 changes: 4 additions & 3 deletions src/view/use-droppable-publisher/use-droppable-publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import useRequiredContext from '../use-required-context';
import usePreviousRef from '../use-previous-ref';
import useLayoutEffect from '../use-isomorphic-layout-effect';
import useUniqueId from '../use-unique-id';
import getScrollable from './get-scrollable';

interface Props {
droppableId: DroppableId;
Expand Down Expand Up @@ -153,7 +154,7 @@ export default function useDroppablePublisher(args: Props) {
shouldClipSubject: !previous.ignoreContainerClipping,
});

const scrollable: Element | null = env.closestScrollable;
const scrollable = env.closestScrollable;

if (scrollable) {
scrollable.setAttribute(
Expand All @@ -162,7 +163,7 @@ export default function useDroppablePublisher(args: Props) {
);

// bind scroll listener
scrollable.addEventListener(
getScrollable(scrollable).addEventListener(
'scroll',
onClosestScroll,
getListenerOptions(dragging.scrollOptions),
Expand Down Expand Up @@ -204,7 +205,7 @@ export default function useDroppablePublisher(args: Props) {
// unwatch scroll
scheduleScrollUpdate.cancel();
closest.removeAttribute(dataAttr.scrollContainer.contextId);
closest.removeEventListener(
getScrollable(closest).removeEventListener(
'scroll',
onClosestScroll,
// See: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
Expand Down

0 comments on commit dd08e4a

Please sign in to comment.