Skip to content

Commit 7750d4d

Browse files
fix: detect iframe DOM nodes
Co-authored-by: Codex <codex@openai.com>
1 parent b7731c3 commit 7750d4d

4 files changed

Lines changed: 60 additions & 5 deletions

File tree

src/Dom/findDOMNode.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import React from 'react';
1+
import type React from 'react';
22

33
export function isDOM(node: any): node is HTMLElement | SVGElement {
4-
// https://developer.mozilla.org/en-US/docs/Web/API/Element
5-
// Since XULElement is also subclass of Element, we only need HTMLElement and SVGElement
6-
return node instanceof HTMLElement || node instanceof SVGElement;
4+
// Cross-frame safe check: `instanceof` fails for elements created in a
5+
// different frame (e.g. iframe via createPortal) because each frame has its
6+
// own HTMLElement/SVGElement constructors.
7+
return typeof node === 'object' && node !== null && node.nodeType === 1;
78
}
89

910
/**

src/Dom/isVisible.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export default (element: Element): boolean => {
33
return false;
44
}
55

6-
if (element instanceof Element) {
6+
if (element.nodeType === 1) {
77
if ((element as HTMLElement).offsetParent) {
88
return true;
99
}

tests/findDOMNode.test.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,27 @@ describe('findDOMNode', () => {
6363
expect(findDOMNode(svg)).toBe(svg);
6464
});
6565

66+
it('supports DOM nodes from iframe', () => {
67+
const iframe = document.createElement('iframe');
68+
document.body.appendChild(iframe);
69+
70+
try {
71+
const iframeWindow = iframe.contentWindow!;
72+
const iframeDocument = iframeWindow.document;
73+
const div = iframeDocument.createElement('div');
74+
iframeDocument.body.appendChild(div);
75+
76+
expect(div).toBeInstanceOf(iframeWindow.HTMLElement);
77+
expect(div).not.toBeInstanceOf(HTMLElement);
78+
expect(isDOM(div)).toBe(true);
79+
expect(getDOM(div)).toBe(div);
80+
expect(findDOMNode(div)).toBe(div);
81+
expect(getDOM({ nativeElement: div })).toBe(div);
82+
} finally {
83+
document.body.removeChild(iframe);
84+
}
85+
});
86+
6687
it('isDOM type', () => {
6788
const svg: any = document.createElementNS(
6889
'http://www.w3.org/2000/svg',

tests/isVisible.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import isVisible from '../src/Dom/isVisible';
2+
3+
describe('isVisible', () => {
4+
it('supports DOM nodes from iframe', () => {
5+
const iframe = document.createElement('iframe');
6+
document.body.appendChild(iframe);
7+
8+
try {
9+
const iframeWindow = iframe.contentWindow!;
10+
const iframeDocument = iframeWindow.document;
11+
const div = iframeDocument.createElement('div');
12+
iframeDocument.body.appendChild(div);
13+
14+
jest.spyOn(div, 'getBoundingClientRect').mockReturnValue({
15+
bottom: 10,
16+
height: 10,
17+
left: 0,
18+
right: 10,
19+
toJSON: () => {},
20+
top: 0,
21+
width: 10,
22+
x: 0,
23+
y: 0,
24+
});
25+
26+
expect(div).toBeInstanceOf(iframeWindow.HTMLElement);
27+
expect(div).not.toBeInstanceOf(Element);
28+
expect(isVisible(div)).toBe(true);
29+
} finally {
30+
document.body.removeChild(iframe);
31+
}
32+
});
33+
});

0 commit comments

Comments
 (0)