7
* @flow
8
*/
9
10
-import type {ElementRef} from 'react';
11
-import type {
12
- HostComponent,
13
- MeasureInWindowOnSuccessCallback,
14
- MeasureLayoutOnSuccessCallback,
15
- MeasureOnSuccessCallback,
16
- INativeMethods,
17
- ViewConfig,
18
- TouchedViewDataAtPoint,
19
-} from './ReactNativeTypes';
20
-
21
-import {warnForStyleProps} from './NativeMethodsMixinUtils';
10
+import type {TouchedViewDataAtPoint, ViewConfig} from './ReactNativeTypes';
11
+import {
12
+ createPublicInstance,
13
+ type ReactFabricHostComponent,
14
+} from './ReactFabricPublicInstance';
15
import {create, diff} from './ReactNativeAttributePayload';
23
-
16
import {dispatchEvent} from './ReactFabricEventEmitter';
25
-
17
import {
18
DefaultEventPriority,
19
DiscreteEventPriority,
22
// Modules provided by RN:
23
import {
24
ReactNativeViewConfigRegistry,
34
- TextInputState,
25
deepFreezeAndThrowOnMutationInDev,
26
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
27
36
appendChildToSet: appendChildNodeToSet,
37
completeRoot,
38
registerEventHandler,
49
- measure: fabricMeasure,
50
- measureInWindow: fabricMeasureInWindow,
51
- measureLayout: fabricMeasureLayout,
39
unstable_DefaultEventPriority: FabricDefaultPriority,
40
unstable_DiscreteEventPriority: FabricDiscretePriority,
41
unstable_getCurrentEventPriority: fabricGetCurrentEventPriority,
55
- setNativeProps,
56
- getBoundingClientRect: fabricGetBoundingClientRect,
42
} = nativeFabricUIManager;
43
44
const {get: getViewConfigForType} = ReactNativeViewConfigRegistry;
53
export type Type = string;
54
export type Props = Object;
55
export type Instance = {
56
+ // Reference to the shadow node.
57
node: Node,
72
- canonical: ReactFabricHostComponent,
73
- ...
58
+ nativeTag: number,
59
+ viewConfig: ViewConfig,
60
+ currentProps: Props,
61
+ // Reference to the React handle (the fiber)
62
+ internalInstanceHandle: Object,
63
+ // Exposed through refs.
64
+ publicInstance: ReactFabricHostComponent,
65
};
66
export type TextInstance = {node: Node, ...};
67
export type HydratableInstance = Instance | TextInstance;
95
registerEventHandler(dispatchEvent);
96
}
97
107
-const noop = () => {};
108
-
109
-/**
110
- * This is used for refs on host components.
111
- */
112
-class ReactFabricHostComponent implements INativeMethods {
113
- _nativeTag: number;
114
- viewConfig: ViewConfig;
115
- currentProps: Props;
116
- _internalInstanceHandle: Object;
117
-
118
- constructor(
119
- tag: number,
120
- viewConfig: ViewConfig,
121
- props: Props,
122
- internalInstanceHandle: Object,
123
- ) {
124
- this._nativeTag = tag;
125
- this.viewConfig = viewConfig;
126
- this.currentProps = props;
127
- this._internalInstanceHandle = internalInstanceHandle;
128
- }
129
-
130
- blur() {
131
- TextInputState.blurTextInput(this);
132
- }
133
-
134
- focus() {
135
- TextInputState.focusTextInput(this);
136
- }
137
-
138
- measure(callback: MeasureOnSuccessCallback) {
139
- const node = getShadowNodeFromInternalInstanceHandle(
140
- this._internalInstanceHandle,
141
- );
142
- if (node != null) {
143
- fabricMeasure(node, callback);
144
- }
145
- }
146
-
147
- measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
148
- const node = getShadowNodeFromInternalInstanceHandle(
149
- this._internalInstanceHandle,
150
- );
151
- if (node != null) {
152
- fabricMeasureInWindow(node, callback);
153
- }
154
- }
155
-
156
- measureLayout(
157
- relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
158
- onSuccess: MeasureLayoutOnSuccessCallback,
159
- onFail?: () => void /* currently unused */,
160
- ) {
161
- if (
162
- typeof relativeToNativeNode === 'number' ||
163
- !(relativeToNativeNode instanceof ReactFabricHostComponent)
164
- ) {
165
- if (__DEV__) {
166
- console.error(
167
- 'Warning: ref.measureLayout must be called with a ref to a native component.',
168
- );
169
- }
170
-
171
- return;
172
- }
173
-
174
- const toStateNode = getShadowNodeFromInternalInstanceHandle(
175
- this._internalInstanceHandle,
176
- );
177
- const fromStateNode = getShadowNodeFromInternalInstanceHandle(
178
- relativeToNativeNode._internalInstanceHandle,
179
- );
180
-
181
- if (toStateNode != null && fromStateNode != null) {
182
- fabricMeasureLayout(
183
- toStateNode,
184
- fromStateNode,
185
- onFail != null ? onFail : noop,
186
- onSuccess != null ? onSuccess : noop,
187
- );
188
- }
189
- }
190
-
191
- unstable_getBoundingClientRect(): DOMRect {
192
- const node = getShadowNodeFromInternalInstanceHandle(
193
- this._internalInstanceHandle,
194
- );
195
- if (node != null) {
196
- const rect = fabricGetBoundingClientRect(node);
197
-
198
- if (rect) {
199
- return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
200
- }
201
- }
202
-
203
- // Empty rect if any of the above failed
204
- return new DOMRect(0, 0, 0, 0);
205
- }
206
-
207
- setNativeProps(nativeProps: Object) {
208
- if (__DEV__) {
209
- warnForStyleProps(nativeProps, this.viewConfig.validAttributes);
210
- }
211
- const updatePayload = create(nativeProps, this.viewConfig.validAttributes);
212
-
213
- const node = getShadowNodeFromInternalInstanceHandle(
214
- this._internalInstanceHandle,
215
- );
216
- if (node != null && updatePayload != null) {
217
- setNativeProps(node, updatePayload);
218
- }
219
- }
220
-}
221
-
222
-type ParamOf<Fn> = $Call<<T>((arg: T) => mixed) => T, Fn>;
223
-type ShadowNode = ParamOf<(typeof nativeFabricUIManager)['measure']>;
224
-
225
-export function getShadowNodeFromInternalInstanceHandle(
226
- internalInstanceHandle: mixed,
227
-): ?ShadowNode {
228
- return (
229
- // $FlowExpectedError[incompatible-return] internalInstanceHandle is opaque but we need to make an exception here.
230
- internalInstanceHandle &&
231
- // $FlowExpectedError[incompatible-return]
232
- internalInstanceHandle.stateNode &&
233
- // $FlowExpectedError[incompatible-use]
234
- internalInstanceHandle.stateNode.node
235
- );
236
-}
237
-
98
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMutation';
99
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
100
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
140
internalInstanceHandle, // internalInstanceHandle
141
);
142
283
- const component = new ReactFabricHostComponent(
143
+ const component = createPublicInstance(
144
tag,
145
viewConfig,
286
- props,
146
internalInstanceHandle,
147
);
148
149
return {
150
node: node,
292
- canonical: component,
151
+ nativeTag: tag,
152
+ viewConfig,
153
+ currentProps: props,
154
+ internalInstanceHandle,
155
+ publicInstance: component,
156
};
157
}
158
222
}
223
224
export function getPublicInstance(instance: Instance): null | PublicInstance {
362
- if (instance.canonical) {
363
- return instance.canonical;
225
+ if (instance.publicInstance != null) {
226
+ return instance.publicInstance;
227
}
228
366
- // For compatibility with Paper
229
+ // For compatibility with the legacy renderer, in case it's used with Fabric
230
+ // in the same app.
231
+ // $FlowExpectedError[prop-missing]
232
if (instance._nativeTag != null) {
233
+ // $FlowExpectedError[incompatible-return]
234
return instance;
235
}
236
249
newProps: Props,
250
hostContext: HostContext,
251
): null | Object {
386
- const viewConfig = instance.canonical.viewConfig;
252
+ const viewConfig = instance.viewConfig;
253
const updatePayload = diff(oldProps, newProps, viewConfig.validAttributes);
254
// TODO: If the event handlers have changed, we need to update the current props
255
// in the commit phase but there is no host config hook to do it yet.
256
// So instead we hack it by updating it in the render phase.
391
- instance.canonical.currentProps = newProps;
257
+ instance.currentProps = newProps;
258
return updatePayload;
259
}
260
333
}
334
return {
335
node: clone,
470
- canonical: instance.canonical,
336
+ nativeTag: instance.nativeTag,
337
+ viewConfig: instance.viewConfig,
338
+ currentProps: instance.currentProps,
339
+ internalInstanceHandle: instance.internalInstanceHandle,
340
+ publicInstance: instance.publicInstance,
341
};
342
}
343
347
props: Props,
348
internalInstanceHandle: Object,
349
): Instance {
480
- const viewConfig = instance.canonical.viewConfig;
350
+ const viewConfig = instance.viewConfig;
351
const node = instance.node;
352
const updatePayload = create(
353
{style: {display: 'none'}},
355
);
356
return {
357
node: cloneNodeWithNewProps(node, updatePayload),
488
- canonical: instance.canonical,
358
+ nativeTag: instance.nativeTag,
359
+ viewConfig: instance.viewConfig,
360
+ currentProps: instance.currentProps,
361
+ internalInstanceHandle: instance.internalInstanceHandle,
362
+ publicInstance: instance.publicInstance,
363
};
364
}
365