Skip to content

Commit

Permalink
feat: auto-scroll iframes
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvxd committed Mar 21, 2024
1 parent ce25b30 commit ebfeb3d
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 5 deletions.
67 changes: 67 additions & 0 deletions src/state/auto-scroller/fluid-scroller/get-iframe-scroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { BoxModel, getBox } from 'css-box-model';
import { DraggableDimension, DraggingState } from '../../../types';
import querySelectorAllIframe from '../../../view/iframe/query-selector-all-iframe';
import getScroll from './get-scroll';
import { AutoScrollerOptions } from './auto-scroller-options-types';

const resetToOrigin = (box: BoxModel) => ({
width: box.marginBox.width,
height: box.marginBox.height,
top: 0,
left: 0,
right: box.marginBox.width,
bottom: box.marginBox.height,
center: {
x: box.marginBox.width / 2,
y: box.marginBox.height / 2,
},
x: 0,
y: 0,
});

/**
* Get the scroll for a draggable inside an iframe
*
* - Since iframes are not fully managed by the state, we have to access the elements directly.
* - This will not work with multiple draggable contexts
*/
export default ({
draggable,
dragStartTime,
getAutoScrollerOptions,
shouldUseTimeDampening,
state,
}: {
state: DraggingState;
draggable: DraggableDimension;
dragStartTime: number;
shouldUseTimeDampening: boolean;
getAutoScrollerOptions: () => AutoScrollerOptions;
}) => {
const el = querySelectorAllIframe(
`[data-rfd-draggable-id="${state.critical.draggable.id}"]`,
)[0];

const win = el?.ownerDocument.defaultView || window;

const isInIframe = win !== window;

if (isInIframe) {
const iframe = win.frameElement as HTMLIFrameElement;
const viewportBox = getBox(iframe);
const box = getBox(el);

const change = getScroll({
dragStartTime,
container: resetToOrigin(viewportBox), // Reset to origin because we don't care about position of the iframe
subject: draggable.client.marginBox,
center: box.borderBox.center,
shouldUseTimeDampening,
getAutoScrollerOptions,
});

return { change, window: win };
}

return null;
};
2 changes: 1 addition & 1 deletion src/state/auto-scroller/fluid-scroller/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { AutoScrollerOptions } from './auto-scroller-options-types';
import { defaultAutoScrollerOptions } from './config';

export interface PublicArgs {
scrollWindow: (change: Position) => void;
scrollWindow: (change: Position, win?: Window) => void;
scrollDroppable: (id: DroppableId, change: Position) => void;
getAutoScrollerOptions?: () => AutoScrollerOptions;
}
Expand Down
17 changes: 16 additions & 1 deletion src/state/auto-scroller/fluid-scroller/scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import whatIsDraggedOver from '../../droppable/what-is-dragged-over';
import getWindowScrollChange from './get-window-scroll-change';
import getDroppableScrollChange from './get-droppable-scroll-change';
import { AutoScrollerOptions } from './auto-scroller-options-types';
import getIframeScroll from './get-iframe-scroll';

interface Args {
state: DraggingState;
dragStartTime: number;
shouldUseTimeDampening: boolean;
scrollWindow: (scroll: Position) => void;
scrollWindow: (scroll: Position, win?: Window) => void;
scrollDroppable: (id: DroppableId, scroll: Position) => void;
getAutoScrollerOptions: () => AutoScrollerOptions;
}
Expand Down Expand Up @@ -51,6 +52,20 @@ export default ({
}
}

const iframeScroll = getIframeScroll({
state,
dragStartTime,
shouldUseTimeDampening,
getAutoScrollerOptions,
draggable,
});

if (iframeScroll?.change) {
scrollWindow(iframeScroll.change, iframeScroll.window);

return;
}

const droppable: DroppableDimension | null = getBestScrollableDroppable({
center,
destination: whatIsDraggedOver(state.impact),
Expand Down
6 changes: 3 additions & 3 deletions src/view/window/scroll-window.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Position } from 'css-box-model';

// Not guarenteed to scroll by the entire amount
export default (change: Position): void => {
window.scrollBy(change.x, change.y);
// Not guaranteed to scroll by the entire amount
export default (change: Position, win: Window = window): void => {
win.scrollBy(change.x, change.y);
};

0 comments on commit ebfeb3d

Please sign in to comment.