Skip to content

Commit

Permalink
fix(dom): calculate reference element offset relative to `offsetParen…
Browse files Browse the repository at this point in the history
…t` iframe (#2785)

Co-authored-by: GitHub Actions <github-actions@github.com>
  • Loading branch information
jsnajdr and GitHub Actions committed Feb 12, 2024
1 parent 53973c8 commit d036f52
Show file tree
Hide file tree
Showing 16 changed files with 119 additions and 3 deletions.
16 changes: 16 additions & 0 deletions .changeset/great-bags-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@floating-ui/dom": patch
---

fix: calculate reference element offset relative to `offsetParent` iframe. Fixes issue with positioning in nested iframes, such as the following:

```html
<html>
<iframe>
<div>floating</div>
<iframe>
<div>reference</div>
</iframe>
</iframe>
</html>
```
8 changes: 5 additions & 3 deletions packages/dom/src/utils/getBoundingClientRect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ export function getBoundingClientRect(
? getWindow(offsetParent)
: offsetParent;

let currentIFrame = win.frameElement;
while (currentIFrame && offsetParent && offsetWin !== win) {
let currentWin = win;
let currentIFrame = currentWin.frameElement;
while (currentIFrame && offsetParent && offsetWin !== currentWin) {
const iframeScale = getScale(currentIFrame);
const iframeRect = currentIFrame.getBoundingClientRect();
const css = getComputedStyle(currentIFrame);
Expand All @@ -69,7 +70,8 @@ export function getBoundingClientRect(
x += left;
y += top;

currentIFrame = getWindow(currentIFrame).frameElement;
currentWin = getWindow(currentIFrame);
currentIFrame = currentWin.frameElement;
}
}

Expand Down
11 changes: 11 additions & 0 deletions packages/dom/test/functional/iframe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ import {click} from './utils/click';
).toMatchSnapshot(`outside-${scroll}.png`);
});

test(`[outside-embedded] ${scroll} correctly positioned on bottom with clipping detection`, async ({
page,
}) => {
await page.goto('http://localhost:1234/iframe');
await click(page, `[data-testid="scroll-${scroll}"]`);

expect(
await page.locator('#outside-embedded-container').screenshot(),
).toMatchSnapshot(`outside-embedded-${scroll}.png`);
});

test(`[inside] ${scroll} correctly positioned on bottom with clipping detection`, async ({
page,
}) => {
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
87 changes: 87 additions & 0 deletions packages/dom/test/visual/spec/IFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,92 @@ function Outside({scroll}: {scroll: number[]}) {
);
}

function OutsideEmbedded({scroll}: {scroll: number[]}) {
const [rootIFrame, setRootIFrame] = useState<HTMLIFrameElement | null>(null);
const [nestedIFrame, setNestedIFrame] = useState<HTMLIFrameElement | null>(
null,
);

const {x, y, refs, strategy} = useFloating({
whileElementsMounted: autoUpdate,
middleware: [
shift({
crossAxis: true,
limiter: limitShift(),
boundary: nestedIFrame || undefined,
}),
],
});

const rootNode = rootIFrame?.contentWindow?.document.body;
const nestedNode = nestedIFrame?.contentWindow?.document.body;

useLayoutEffect(() => {
if (nestedNode && scroll) {
nestedNode.scrollLeft = scroll[0];
nestedNode.scrollTop = scroll[1];
}
}, [nestedNode, scroll]);

return (
<>
<h2>Outside Embedded</h2>
<div className="container" id="outside-embedded-container">
<iframe
ref={setRootIFrame}
width={350}
height={350}
style={{transform: 'scale(1.25)', border: '5px solid black'}}
>
{rootNode &&
createPortal(
<div style={{width: 2000, height: 2000, position: 'relative'}}>
<iframe
ref={setNestedIFrame}
width={200}
height={200}
style={{transform: 'scale(1.25)', border: '5px solid black'}}
>
{nestedNode &&
createPortal(
<div
style={{
width: 2000,
height: 2000,
position: 'relative',
}}
>
<button
ref={refs.setReference}
className="reference"
style={{position: 'absolute', left: 1000, top: 1000}}
>
Reference
</button>
</div>,
nestedNode,
)}
</iframe>
<div
ref={refs.setFloating}
className="floating"
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
}}
>
Floating
</div>
</div>,
rootNode,
)}
</iframe>
</div>
</>
);
}

function Inside({scroll}: {scroll: number[]}) {
const [iframe, setIFrame] = useState<HTMLIFrameElement | null>(null);
const {x, y, refs, strategy} = useFloating({
Expand Down Expand Up @@ -393,6 +479,7 @@ export function IFrame() {
<h1>iframe</h1>
<p></p>
<Outside scroll={scroll} />
<OutsideEmbedded scroll={scroll} />
<Inside scroll={scroll} />
<Nested scroll={scroll} />
<Virtual scroll={scroll} />
Expand Down

0 comments on commit d036f52

Please sign in to comment.