Skip to content

Commit 4a14191

Browse files
committed
Support empty fragment positions
1 parent 73cf5d8 commit 4a14191

File tree

3 files changed

+50
-18
lines changed

3 files changed

+50
-18
lines changed

packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import {
5959
import {
6060
traverseFragmentInstance,
6161
getFragmentParentHostInstance,
62+
getNextSiblingHostInstance,
6263
} from 'react-reconciler/src/ReactFiberTreeReflection';
6364

6465
export {detachDeletedInstance};
@@ -2637,10 +2638,32 @@ FragmentInstance.prototype.compareDocumentPosition = function (
26372638
traverseFragmentInstance(this._fragmentFiber, collectChildren, children);
26382639

26392640
if (children.length === 0) {
2640-
return (
2641-
Node.DOCUMENT_POSITION_DISCONNECTED |
2642-
Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
2643-
);
2641+
// If the fragment has no children, we can use the parent and
2642+
// siblings to determine a position.
2643+
if (parentHostInstance === otherNode) {
2644+
return Node.DOCUMENT_POSITION_CONTAINS;
2645+
}
2646+
const parentResult = parentHostInstance.compareDocumentPosition(otherNode);
2647+
if (parentResult & Node.DOCUMENT_POSITION_CONTAINED_BY) {
2648+
// otherNode is one of the fragment's siblings. Use the next
2649+
// sibling to determine if its preceding or following.
2650+
const nextSiblingInstance = getNextSiblingHostInstance(
2651+
this._fragmentFiber,
2652+
);
2653+
if (nextSiblingInstance === null) {
2654+
return Node.DOCUMENT_POSITION_PRECEDING;
2655+
}
2656+
if (
2657+
nextSiblingInstance === otherNode ||
2658+
nextSiblingInstance.compareDocumentPosition(otherNode) &
2659+
Node.DOCUMENT_POSITION_FOLLOWING
2660+
) {
2661+
return Node.DOCUMENT_POSITION_FOLLOWING;
2662+
} else {
2663+
return Node.DOCUMENT_POSITION_PRECEDING;
2664+
}
2665+
}
2666+
return parentResult;
26442667
}
26452668

26462669
const firstElement = children[0];

packages/react-dom/src/__tests__/ReactDOMFragmentRefs-test.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,7 @@ describe('FragmentRefs', () => {
11931193
});
11941194

11951195
// @gate enableFragmentRefs
1196-
it('returns disconnected and implementation specific for any comparison with empty fragment instances', async () => {
1196+
it('handles empty fragment instances', async () => {
11971197
const fragmentRef = React.createRef();
11981198
const beforeRef = React.createRef();
11991199
const afterRef = React.createRef();
@@ -1215,45 +1215,45 @@ describe('FragmentRefs', () => {
12151215
expectPosition(
12161216
fragmentRef.current.compareDocumentPosition(document.body),
12171217
{
1218-
preceding: false,
1218+
preceding: true,
12191219
following: false,
1220-
contains: false,
1220+
contains: true,
12211221
containedBy: false,
1222-
disconnected: true,
1223-
implementationSpecific: true,
1222+
disconnected: false,
1223+
implementationSpecific: false,
12241224
},
12251225
);
12261226
expectPosition(
12271227
fragmentRef.current.compareDocumentPosition(beforeRef.current),
12281228
{
1229-
preceding: false,
1229+
preceding: true,
12301230
following: false,
12311231
contains: false,
12321232
containedBy: false,
1233-
disconnected: true,
1234-
implementationSpecific: true,
1233+
disconnected: false,
1234+
implementationSpecific: false,
12351235
},
12361236
);
12371237
expectPosition(
12381238
fragmentRef.current.compareDocumentPosition(afterRef.current),
12391239
{
12401240
preceding: false,
1241-
following: false,
1241+
following: true,
12421242
contains: false,
12431243
containedBy: false,
1244-
disconnected: true,
1245-
implementationSpecific: true,
1244+
disconnected: false,
1245+
implementationSpecific: false,
12461246
},
12471247
);
12481248
expectPosition(
12491249
fragmentRef.current.compareDocumentPosition(containerRef.current),
12501250
{
12511251
preceding: false,
12521252
following: false,
1253-
contains: false,
1253+
contains: true,
12541254
containedBy: false,
1255-
disconnected: true,
1256-
implementationSpecific: true,
1255+
disconnected: false,
1256+
implementationSpecific: false,
12571257
},
12581258
);
12591259
});

packages/react-reconciler/src/ReactFiberTreeReflection.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,12 @@ export function getFragmentParentHostInstance(fiber: Fiber): null | Instance {
367367

368368
return null;
369369
}
370+
371+
export function getNextSiblingHostInstance(fiber: Fiber): null | Instance {
372+
let nextSibling = null;
373+
traverseFragmentInstanceChildren(fiber.sibling, instance => {
374+
nextSibling = instance;
375+
return true;
376+
});
377+
return nextSibling;
378+
}

0 commit comments

Comments
 (0)