WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
This repository was archived by the owner on Jun 3, 2025. It is now read-only.

Commit dcf051d

Browse files
committed
feat: auto-scroll iframes
1 parent ce25b30 commit dcf051d

File tree

4 files changed

+96
-5
lines changed

4 files changed

+96
-5
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { BoxModel, getBox } from 'css-box-model';
2+
import { DraggableDimension, DraggingState } from '../../../types';
3+
import querySelectorAllIframe from '../../../view/iframe/query-selector-all-iframe';
4+
import getScroll from './get-scroll';
5+
import { AutoScrollerOptions } from './auto-scroller-options-types';
6+
import { Transform, getTransform } from '../../../view/transform';
7+
8+
const resetToOrigin = (box: BoxModel, transform: Transform | null) => {
9+
const { scaleX = 1, scaleY = 1 } = transform?.matrix || {};
10+
11+
const width = box.marginBox.width / scaleX;
12+
const height = box.marginBox.height / scaleY;
13+
14+
return {
15+
width,
16+
height,
17+
top: 0,
18+
left: 0,
19+
right: width,
20+
bottom: height,
21+
center: {
22+
x: width / 2,
23+
y: height / 2,
24+
},
25+
x: 0,
26+
y: 0,
27+
};
28+
};
29+
30+
/**
31+
* Get the scroll for a draggable inside an iframe
32+
*
33+
* - Since iframes are not fully managed by the state, we have to access the elements directly.
34+
* - This will not work with multiple draggable contexts
35+
*/
36+
export default ({
37+
draggable,
38+
dragStartTime,
39+
getAutoScrollerOptions,
40+
shouldUseTimeDampening,
41+
state,
42+
}: {
43+
state: DraggingState;
44+
draggable: DraggableDimension;
45+
dragStartTime: number;
46+
shouldUseTimeDampening: boolean;
47+
getAutoScrollerOptions: () => AutoScrollerOptions;
48+
}) => {
49+
const el = querySelectorAllIframe(
50+
`[data-rfd-draggable-id="${state.critical.draggable.id}"]`,
51+
)[0];
52+
53+
const win = el?.ownerDocument.defaultView || window;
54+
55+
const isInIframe = win !== window;
56+
57+
if (isInIframe) {
58+
const iframe = win.frameElement as HTMLIFrameElement;
59+
const viewportBox = getBox(iframe);
60+
const box = getBox(el);
61+
const transform = getTransform(iframe);
62+
63+
const change = getScroll({
64+
dragStartTime,
65+
container: resetToOrigin(viewportBox, transform), // Reset to origin because we don't care about position of the iframe
66+
subject: draggable.client.marginBox,
67+
center: box.borderBox.center,
68+
shouldUseTimeDampening,
69+
getAutoScrollerOptions,
70+
});
71+
72+
return { change, window: win };
73+
}
74+
75+
return null;
76+
};

src/state/auto-scroller/fluid-scroller/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { AutoScrollerOptions } from './auto-scroller-options-types';
88
import { defaultAutoScrollerOptions } from './config';
99

1010
export interface PublicArgs {
11-
scrollWindow: (change: Position) => void;
11+
scrollWindow: (change: Position, win?: Window) => void;
1212
scrollDroppable: (id: DroppableId, change: Position) => void;
1313
getAutoScrollerOptions?: () => AutoScrollerOptions;
1414
}

src/state/auto-scroller/fluid-scroller/scroll.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ import whatIsDraggedOver from '../../droppable/what-is-dragged-over';
1111
import getWindowScrollChange from './get-window-scroll-change';
1212
import getDroppableScrollChange from './get-droppable-scroll-change';
1313
import { AutoScrollerOptions } from './auto-scroller-options-types';
14+
import getIframeScroll from './get-iframe-scroll';
1415

1516
interface Args {
1617
state: DraggingState;
1718
dragStartTime: number;
1819
shouldUseTimeDampening: boolean;
19-
scrollWindow: (scroll: Position) => void;
20+
scrollWindow: (scroll: Position, win?: Window) => void;
2021
scrollDroppable: (id: DroppableId, scroll: Position) => void;
2122
getAutoScrollerOptions: () => AutoScrollerOptions;
2223
}
@@ -51,6 +52,20 @@ export default ({
5152
}
5253
}
5354

55+
const iframeScroll = getIframeScroll({
56+
state,
57+
dragStartTime,
58+
shouldUseTimeDampening,
59+
getAutoScrollerOptions,
60+
draggable,
61+
});
62+
63+
if (iframeScroll?.change) {
64+
scrollWindow(iframeScroll.change, iframeScroll.window);
65+
66+
return;
67+
}
68+
5469
const droppable: DroppableDimension | null = getBestScrollableDroppable({
5570
center,
5671
destination: whatIsDraggedOver(state.impact),

src/view/window/scroll-window.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Position } from 'css-box-model';
22

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

0 commit comments

Comments
 (0)