Fix crash when accessing offsetParent from documentElement (#51773)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/51773

Changelog: [internal]

(This isn't a public API yet so not marking it as a bugfix).

This fixes a crash in the `offsetParent` DOM API when called on a node whose parent is the `documentElement`.

Reviewed By: andrewdacenko

Differential Revision: D75876349

fbshipit-source-id: d90fcc3cb98f592c396cb0f5ee6ec80c9570745a
This commit is contained in:
Rubén Norte
2025-06-03 10:58:00 -07:00
committed by Facebook GitHub Bot
parent b4ae5c1de1
commit 638933418e
3 changed files with 16 additions and 6 deletions
@@ -72,9 +72,15 @@ ShadowNode::Shared getPositionedAncestorOfShadowNodeInRevision(
auto ancestors = shadowNode.getFamily().getAncestors(*currentRevision);
if (ancestors.empty()) {
// The node is no longer part of an active shadow tree, or is the root.
return nullptr;
}
if (ancestors.size() == 1) {
// The parent is the root
return currentRevision;
}
for (auto it = ancestors.rbegin(); it != ancestors.rend(); it++) {
const auto layoutableAncestorShadowNode =
dynamic_cast<const LayoutableShadowNode*>(&(it->first.get()));
@@ -86,11 +92,9 @@ ShadowNode::Shared getPositionedAncestorOfShadowNodeInRevision(
// We have found our nearest positioned ancestor, now to get a shared
// pointer of it
it++;
if (it != ancestors.rend()) {
return it->first.get().getChildren().at(it->second);
}
// else the positioned ancestor is the root which we return outside of the
// loop
return it == ancestors.rend()
? currentRevision
: it->first.get().getChildren().at(it->second);
}
}
@@ -122,6 +122,10 @@ describe('ReactNativeDocument', () => {
expect(y).toBe(0);
expect(width).toBe(200);
expect(height).toBe(100);
expect(document.documentElement.offsetParent).toBe(null);
expect(document.documentElement.offsetTop).toBe(0);
expect(document.documentElement.offsetLeft).toBe(0);
});
it('implements compareDocumentPosition correctly', () => {
@@ -1064,7 +1064,7 @@ describe('ReactNativeElement', () => {
});
describe('offsetParent / offsetTop / offsetLeft', () => {
it('retun the rounded offset values and the parent, or null and zeros when disconnected or hidden', () => {
it('return the rounded offset values and the parent, or null and zeros when disconnected or hidden', () => {
const parentRef = createRef<HostInstance>();
const elementRef = createRef<HostInstance>();
@@ -1089,6 +1089,8 @@ describe('ReactNativeElement', () => {
expect(element.offsetLeft).toBe(5);
expect(element.offsetParent).toBe(parentElement);
expect(parentElement.offsetParent).toBe(root.document.documentElement);
Fantom.runTask(() => {
root.render(
<View key="parent" style={{display: 'none'}}>