@@ -24,6 +24,7 @@ import {
2424import type { Fiber } from 'react-reconciler/src/ReactInternalTypes' ;
2525import { HostText } from 'react-reconciler/src/ReactWorkTags' ;
2626import {
27+ getFragmentParentHostFiber ,
2728 getInstanceFromHostFiber ,
2829 traverseFragmentInstance ,
2930} from 'react-reconciler/src/ReactFiberTreeReflection' ;
@@ -59,6 +60,7 @@ const {
5960} = nativeFabricUIManager ;
6061
6162import { getClosestInstanceFromNode } from './ReactFabricComponentTree' ;
63+ import { compareDocumentPositionForEmptyFragment } from 'shared/ReactDOMFragmentRefShared' ;
6264
6365import {
6466 getInspectorDataForViewTag ,
@@ -87,7 +89,7 @@ const {get: getViewConfigForType} = ReactNativeViewConfigRegistry;
8789let nextReactTag = 2 ;
8890
8991type InternalInstanceHandle = Object ;
90- type Node = Object ;
92+
9193export type Type = string ;
9294export type Props = Object ;
9395export type Instance = {
@@ -344,6 +346,15 @@ export function getPublicInstanceFromInternalInstanceHandle(
344346 return getPublicInstance ( elementInstance ) ;
345347}
346348
349+ function getPublicInstanceFromHostFiber ( fiber : Fiber ) : PublicInstance {
350+ const instance = getInstanceFromHostFiber < Instance > ( fiber ) ;
351+ const publicInstance = getPublicInstance ( instance ) ;
352+ if ( publicInstance == null ) {
353+ throw new Error ( 'Expected to find a host node. This is a bug in React.' ) ;
354+ }
355+ return publicInstance ;
356+ }
357+
347358export function prepareForCommit ( containerInfo : Container ) : null | Object {
348359 // Noop
349360 return null ;
@@ -610,6 +621,7 @@ export type FragmentInstanceType = {
610621 _observers : null | Set < IntersectionObserver > ,
611622 observeUsing : ( observer : IntersectionObserver ) = > void ,
612623 unobserveUsing : ( observer : IntersectionObserver ) = > void ,
624+ compareDocumentPosition : ( otherNode : PublicInstance ) = > number ,
613625} ;
614626
615627function FragmentInstance ( this : FragmentInstanceType , fragmentFiber : Fiber ) {
@@ -629,12 +641,8 @@ FragmentInstance.prototype.observeUsing = function (
629641 traverseFragmentInstance ( this . _fragmentFiber , observeChild , observer ) ;
630642} ;
631643function observeChild ( child : Fiber , observer : IntersectionObserver ) {
632- const instance = getInstanceFromHostFiber < Instance > ( child ) ;
633- const publicInstance = getPublicInstance ( instance ) ;
634- if ( publicInstance == null ) {
635- throw new Error ( 'Expected to find a host node. This is a bug in React.' ) ;
636- }
637- // $FlowFixMe[incompatible-call] Element types are behind a flag in RN
644+ const publicInstance = getPublicInstanceFromHostFiber ( child ) ;
645+ // $FlowFixMe[incompatible-call] DOM types expect Element
638646 observer . observe ( publicInstance ) ;
639647 return false ;
640648}
@@ -656,16 +664,72 @@ FragmentInstance.prototype.unobserveUsing = function (
656664 }
657665} ;
658666function unobserveChild ( child : Fiber , observer : IntersectionObserver ) {
659- const instance = getInstanceFromHostFiber < Instance > ( child ) ;
660- const publicInstance = getPublicInstance ( instance ) ;
661- if ( publicInstance == null ) {
662- throw new Error ( 'Expected to find a host node. This is a bug in React.' ) ;
663- }
664- // $FlowFixMe[incompatible-call] Element types are behind a flag in RN
667+ const publicInstance = getPublicInstanceFromHostFiber ( child ) ;
668+ // $FlowFixMe[incompatible-call] DOM types expect Element
665669 observer . unobserve ( publicInstance ) ;
666670 return false ;
667671}
668672
673+ // $FlowFixMe[prop-missing]
674+ FragmentInstance . prototype . compareDocumentPosition = function (
675+ this : FragmentInstanceType ,
676+ otherNode : PublicInstance ,
677+ ) : number {
678+ const parentHostFiber = getFragmentParentHostFiber ( this . _fragmentFiber ) ;
679+ if ( parentHostFiber === null ) {
680+ return Node . DOCUMENT_POSITION_DISCONNECTED ;
681+ }
682+ const parentHostInstance = getPublicInstanceFromHostFiber ( parentHostFiber ) ;
683+ const children : Array < Fiber > = [];
684+ traverseFragmentInstance(this._fragmentFiber, collectChildren, children);
685+ if (children.length === 0) {
686+ return compareDocumentPositionForEmptyFragment (
687+ this . _fragmentFiber ,
688+ parentHostInstance ,
689+ otherNode ,
690+ getPublicInstanceFromHostFiber ,
691+ ) ;
692+ }
693+
694+ const firstInstance = getPublicInstanceFromHostFiber(children[0]);
695+ const lastInstance = getPublicInstanceFromHostFiber(
696+ children[children.length - 1],
697+ );
698+
699+ // $FlowFixMe[incompatible-use] Fabric PublicInstance is opaque
700+ // $FlowFixMe[prop-missing]
701+ const firstResult = firstInstance.compareDocumentPosition(otherNode);
702+ // $FlowFixMe[incompatible-use] Fabric PublicInstance is opaque
703+ // $FlowFixMe[prop-missing]
704+ const lastResult = lastInstance.compareDocumentPosition(otherNode);
705+
706+ const otherNodeIsFirstOrLastChild =
707+ firstInstance === otherNode || lastInstance === otherNode;
708+ const otherNodeIsWithinFirstOrLastChild =
709+ firstResult & Node . DOCUMENT_POSITION_CONTAINED_BY ||
710+ lastResult & Node . DOCUMENT_POSITION_CONTAINED_BY ;
711+ const otherNodeIsBetweenFirstAndLastChildren =
712+ firstResult & Node . DOCUMENT_POSITION_FOLLOWING &&
713+ lastResult & Node . DOCUMENT_POSITION_PRECEDING ;
714+ let result ;
715+ if (
716+ otherNodeIsFirstOrLastChild ||
717+ otherNodeIsWithinFirstOrLastChild ||
718+ otherNodeIsBetweenFirstAndLastChildren
719+ ) {
720+ result = Node . DOCUMENT_POSITION_CONTAINED_BY ;
721+ } else {
722+ result = firstResult ;
723+ }
724+
725+ return result ;
726+ } ;
727+
728+ function collectChildren ( child : Fiber , collection : Array < Fiber > ) : boolean {
729+ collection . push ( child ) ;
730+ return false ;
731+ }
732+
669733export function createFragmentInstance (
670734 fragmentFiber : Fiber ,
671735) : FragmentInstanceType {
0 commit comments