react-native
Version:
A framework for building native apps using React
469 lines (403 loc) • 15.2 kB
JavaScript
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {
InternalInstanceHandle as InstanceHandle,
Node as ShadowNode,
} from '../../../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {TurboModule} from '../../../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../../../Libraries/TurboModule/TurboModuleRegistry';
import nullthrows from 'nullthrows';
export type MeasureInWindowOnSuccessCallback = (
x: number,
y: number,
width: number,
height: number,
) => void;
export type MeasureOnSuccessCallback = (
x: number,
y: number,
width: number,
height: number,
pageX: number,
pageY: number,
) => void;
export type MeasureLayoutOnSuccessCallback = (
left: number,
top: number,
width: number,
height: number,
) => void;
export interface Spec extends TurboModule {
+getParentNode: (
shadowNode: mixed /* ShadowNode */,
) => mixed /* ?InstanceHandle */;
+getChildNodes: (
shadowNode: mixed /* ShadowNode */,
) => $ReadOnlyArray<mixed> /* $ReadOnlyArray<InstanceHandle> */;
+isConnected: (shadowNode: mixed /* ShadowNode */) => boolean;
+compareDocumentPosition: (
shadowNode: mixed /* ShadowNode */,
otherShadowNode: mixed /* ShadowNode */,
) => number;
+getTextContent: (shadowNode: mixed /* ShadowNode */) => string;
+getBoundingClientRect: (
shadowNode: mixed /* ShadowNode */,
includeTransform: boolean,
) => $ReadOnlyArray<number> /* [x: number, y: number, width: number, height: number] */;
+getOffset: (
shadowNode: mixed /* ShadowNode */,
) => $ReadOnlyArray<mixed> /* [offsetParent: ?InstanceHandle, top: number, left: number] */;
+getScrollPosition: (
shadowNode: mixed /* ShadowNode */,
) => $ReadOnlyArray<number> /* [scrollLeft: number, scrollTop: number] */;
+getScrollSize: (
shadowNode: mixed /* ShadowNode */,
) => $ReadOnlyArray<number> /* [scrollWidth: number, scrollHeight: number] */;
+getInnerSize: (
shadowNode: mixed /* ShadowNode */,
) => $ReadOnlyArray<number> /* [width: number, height: number] */;
+getBorderWidth: (
shadowNode: mixed /* ShadowNode */,
) => $ReadOnlyArray<number> /* [topWidth: number, rightWidth: number, bottomWidth: number, leftWidth: number] */;
+getTagName: (shadowNode: mixed /* ShadowNode */) => string;
+hasPointerCapture: (
shadowNode: mixed /* ShadowNode */,
pointerId: number,
) => boolean;
+setPointerCapture: (
shadowNode: mixed /* ShadowNode */,
pointerId: number,
) => void;
+releasePointerCapture: (
shadowNode: mixed /* ShadowNode */,
pointerId: number,
) => void;
/**
* Legacy layout APIs
*/
+measure: (shadowNode: mixed, callback: MeasureOnSuccessCallback) => void;
+measureInWindow: (
shadowNode: mixed,
callback: MeasureInWindowOnSuccessCallback,
) => void;
+measureLayout: (
shadowNode: mixed,
relativeNode: mixed,
onFail: () => void,
onSuccess: MeasureLayoutOnSuccessCallback,
) => void;
}
const RawNativeDOM = (TurboModuleRegistry.get<Spec>('NativeDOMCxx'): ?Spec);
// This is the actual interface of this module, but the native module codegen
// isn't expressive enough yet.
export interface RefinedSpec {
/**
* This is a React Native implementation of `Node.prototype.parentNode`
* (see https://developer.mozilla.org/en-US/docs/Web/API/Node/parentNode).
*
* If a version of the given shadow node is present in the current revision of
* an active shadow tree, it returns the instance handle of its parent.
* Otherwise, it returns `null`.
*/
+getParentNode: (shadowNode: ShadowNode) => ?InstanceHandle;
/**
* This is a React Native implementation of `Node.prototype.childNodes`
* (see https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes).
*
* If a version of the given shadow node is present in the current revision
* of an active shadow tree, it returns an array of instance handles of its
* children. Otherwise, it returns an empty array.
*/
+getChildNodes: (shadowNode: ShadowNode) => $ReadOnlyArray<InstanceHandle>;
/**
* This is a React Native implementation of `Node.prototype.isConnected`
* (see https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected).
*
* Indicates whether a version of the given shadow node is present in the
* current revision of an active shadow tree.
*/
+isConnected: (shadowNode: ShadowNode) => boolean;
/**
* This is a React Native implementation of `Node.prototype.compareDocumentPosition`
* (see https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition).
*
* It uses the version of the shadow nodes that are present in the current
* revision of the shadow tree (if any). If any of the nodes is not present,
* it just indicates they are disconnected.
*/
+compareDocumentPosition: (
shadowNode: ShadowNode,
otherShadowNode: ShadowNode,
) => number;
/**
* This is a React Native implementation of `Element.prototype.textContent`
* (see https://developer.mozilla.org/en-US/docs/Web/API/Element/textContent).
*
* It uses the version of the shadow node that is present in the current
* revision of the shadow tree.
* If the version is present, is traverses all its children in DFS and
* concatenates all the text contents. Otherwise, it returns an empty string.
*
* This is also used to access the text content of text nodes, which does not
* need any traversal.
*/
+getTextContent: (shadowNode: ShadowNode) => string;
/**
* This is a React Native implementation of `Element.prototype.getBoundingClientRect`
* (see https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
*
* This is similar to `measureInWindow`, except it's explicitly synchronous
* (returns the result instead of passing it to a callback).
*
* It allows indicating whether to include transforms so it can also be used
* to implement methods like [`offsetWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetWidth)
* and [`offsetHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetHeight).
*/
+getBoundingClientRect: (
shadowNode: ShadowNode,
includeTransform: boolean,
) => $ReadOnly<
[
/* x: */ number,
/* y: */ number,
/* width: */ number,
/* height: */ number,
],
>;
/**
* This is a method to access the offset information for a shadow node, to
* implement these methods:
* - `HTMLElement.prototype.offsetParent`: see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent.
* - `HTMLElement.prototype.offsetTop`: see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop.
* - `HTMLElement.prototype.offsetLeft`: see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft.
*
* It uses the version of the shadow node that is present in the current
* revision of the shadow tree. If the node is not present or is not
* displayed (because any of its ancestors or itself have 'display: none'),
* it returns `undefined`. Otherwise, it returns its parent (as all nodes in
* React Native are currently "positioned") and its offset relative to its
* parent.
*/
+getOffset: (
shadowNode: ShadowNode,
) => $ReadOnly<
[
/* offsetParent: */ ?InstanceHandle,
/* top: */ number,
/* left: */ number,
],
>;
/**
* This is a method to access scroll information for a shadow node, to
* implement these methods:
* - `Element.prototype.scrollLeft`: see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft.
* - `Element.prototype.scrollTop`: see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop.
*
* It uses the version of the shadow node that is present in the current
* revision of the shadow tree. If the node is not present or is not displayed
* (because any of its ancestors or itself have 'display: none'), it returns
* `undefined`. Otherwise, it returns the scroll position.
*/
+getScrollPosition: (
shadowNode: ShadowNode,
) => $ReadOnly<[/* scrollLeft: */ number, /* scrollTop: */ number]>;
/**
*
* This is a method to access the scroll information of a shadow node, to
* implement these methods:
* - `Element.prototype.scrollWidth`: see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollWidth.
* - `Element.prototype.scrollHeight`: see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight.
*
* It uses the version of the shadow node that is present in the current
* revision of the shadow tree. If the node is not present or is not displayed
* (because any of its ancestors or itself have 'display: none'), it returns
* `undefined`. Otherwise, it returns the scroll size.
*/
+getScrollSize: (
shadowNode: ShadowNode,
) => $ReadOnly<[/* scrollWidth: */ number, /* scrollHeight: */ number]>;
/**
* This is a method to access the inner size of a shadow node, to implement
* these methods:
* - `Element.prototype.clientWidth`: see https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth.
* - `Element.prototype.clientHeight`: see https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight.
*
* It uses the version of the shadow node that is present in the current
* revision of the shadow tree. If the node is not present, it is not
* displayed (because any of its ancestors or itself have 'display: none'), or
* it has an inline display, it returns `undefined`. Otherwise, it returns its
* inner size.
*/
+getInnerSize: (
shadowNode: ShadowNode,
) => $ReadOnly<[/* width: */ number, /* height: */ number]>;
/**
* This is a method to access the border size of a shadow node, to implement
* these methods:
* - `Element.prototype.clientLeft`: see https://developer.mozilla.org/en-US/docs/Web/API/Element/clientLeft.
* - `Element.prototype.clientTop`: see https://developer.mozilla.org/en-US/docs/Web/API/Element/clientTop.
*
* It uses the version of the shadow node that is present in the current
* revision of the shadow tree. If the node is not present, it is not
* displayed (because any of its ancestors or itself have 'display: none'), or
* it has an inline display, it returns `undefined`. Otherwise, it returns its
* border size.
*/
+getBorderWidth: (
shadowNode: ShadowNode,
) => $ReadOnly<
[
/* topWidth: */ number,
/* rightWidth: */ number,
/* bottomWidth: */ number,
/* leftWidth: */ number,
],
>;
/**
* This is a method to access the normalized tag name of a shadow node, to
* implement `Element.prototype.tagName` (see https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName).
*/
+getTagName: (shadowNode: ShadowNode) => string;
/**
* Pointer Capture APIs
*/
+hasPointerCapture: (shadowNode: ShadowNode, pointerId: number) => boolean;
+setPointerCapture: (shadowNode: ShadowNode, pointerId: number) => void;
+releasePointerCapture: (shadowNode: ShadowNode, pointerId: number) => void;
/**
* Legacy layout APIs
*/
+measure: (
shadowNode: ShadowNode,
callback: MeasureOnSuccessCallback,
) => void;
+measureInWindow: (
shadowNode: ShadowNode,
callback: MeasureInWindowOnSuccessCallback,
) => void;
+measureLayout: (
shadowNode: ShadowNode,
relativeNode: ShadowNode,
onFail: () => void,
onSuccess: MeasureLayoutOnSuccessCallback,
) => void;
}
const NativeDOM: RefinedSpec = {
getParentNode(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getParentNode(
shadowNode,
): ?InstanceHandle);
},
getChildNodes(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getChildNodes(
shadowNode,
): $ReadOnlyArray<InstanceHandle>);
},
isConnected(shadowNode) {
return nullthrows(RawNativeDOM).isConnected(shadowNode);
},
compareDocumentPosition(shadowNode, otherShadowNode) {
return nullthrows(RawNativeDOM).compareDocumentPosition(
shadowNode,
otherShadowNode,
);
},
getTextContent(shadowNode) {
return nullthrows(RawNativeDOM).getTextContent(shadowNode);
},
getBoundingClientRect(shadowNode, includeTransform: boolean) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getBoundingClientRect(
shadowNode,
includeTransform,
): $ReadOnly<
[
/* x: */ number,
/* y: */ number,
/* width: */ number,
/* height: */ number,
],
>);
},
getOffset(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getOffset(shadowNode): $ReadOnly<
[
/* offsetParent: */ ?InstanceHandle,
/* top: */ number,
/* left: */ number,
],
>);
},
getScrollPosition(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getScrollPosition(shadowNode): $ReadOnly<
[/* scrollLeft: */ number, /* scrollTop: */ number],
>);
},
getScrollSize(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getScrollSize(shadowNode): $ReadOnly<
[/* scrollWidth: */ number, /* scrollHeight: */ number],
>);
},
getInnerSize(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getInnerSize(shadowNode): $ReadOnly<
[/* width: */ number, /* height: */ number],
>);
},
getBorderWidth(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getBorderWidth(shadowNode): $ReadOnly<
[
/* topWidth: */ number,
/* rightWidth: */ number,
/* bottomWidth: */ number,
/* leftWidth: */ number,
],
>);
},
getTagName(shadowNode) {
return nullthrows(RawNativeDOM).getTagName(shadowNode);
},
hasPointerCapture(shadowNode, pointerId) {
return nullthrows(RawNativeDOM).hasPointerCapture(shadowNode, pointerId);
},
setPointerCapture(shadowNode, pointerId) {
return nullthrows(RawNativeDOM).setPointerCapture(shadowNode, pointerId);
},
releasePointerCapture(shadowNode, pointerId) {
return nullthrows(RawNativeDOM).releasePointerCapture(
shadowNode,
pointerId,
);
},
/**
* Legacy layout APIs
*/
measure(shadowNode, callback) {
return nullthrows(RawNativeDOM).measure(shadowNode, callback);
},
measureInWindow(shadowNode, callback) {
return nullthrows(RawNativeDOM).measureInWindow(shadowNode, callback);
},
measureLayout(shadowNode, relativeNode, onFail, onSuccess) {
return nullthrows(RawNativeDOM).measureLayout(
shadowNode,
relativeNode,
onFail,
onSuccess,
);
},
};
export default NativeDOM;