24
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
25
import {HostText} from 'react-reconciler/src/ReactWorkTags';
26
import {
27
+ getFragmentParentHostFiber,
28
getInstanceFromHostFiber,
29
traverseFragmentInstance,
30
} from 'react-reconciler/src/ReactFiberTreeReflection';
60
} = nativeFabricUIManager;
61
62
import {getClosestInstanceFromNode} from './ReactFabricComponentTree';
63
+import {compareDocumentPositionForEmptyFragment} from 'shared/ReactDOMFragmentRefShared';
64
65
import {
66
getInspectorDataForViewTag,
89
let nextReactTag = 2;
90
91
type InternalInstanceHandle = Object;
90
-type Node = Object;
92
+
93
export type Type = string;
94
export type Props = Object;
95
export type Instance = {
346
return getPublicInstance(elementInstance);
347
}
348
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
+
358
export function prepareForCommit(containerInfo: Container): null | Object {
359
// Noop
360
return null;
621
_observers: null | Set<IntersectionObserver>,
622
observeUsing: (observer: IntersectionObserver) => void,
623
unobserveUsing: (observer: IntersectionObserver) => void,
624
+ compareDocumentPosition: (otherNode: PublicInstance) => number,
625
};
626
627
function FragmentInstance(this: FragmentInstanceType, fragmentFiber: Fiber) {
641
traverseFragmentInstance(this._fragmentFiber, observeChild, observer);
642
};
643
function 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
646
observer.observe(publicInstance);
647
return false;
648
}
664
}
665
};
666
function 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
669
observer.unobserve(publicInstance);
670
return false;
671
}
672
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
+
733
export function createFragmentInstance(
734
fragmentFiber: Fiber,
735
): FragmentInstanceType {