diff --git a/packages/react-native-renderer/src/ReactFabric.js b/packages/react-native-renderer/src/ReactFabric.js index fa406703fce79..edd6047270989 100644 --- a/packages/react-native-renderer/src/ReactFabric.js +++ b/packages/react-native-renderer/src/ReactFabric.js @@ -21,7 +21,6 @@ import ReactNativeComponent from './ReactNativeComponent'; import * as ReactNativeComponentTree from './ReactNativeComponentTree'; import ReactFabricRenderer from './ReactFabricRenderer'; import {getInspectorDataForViewTag} from './ReactNativeFiberInspector'; -import createReactNativeComponentClass from './createReactNativeComponentClass'; import {injectFindHostInstance} from './findNodeHandle'; import findNumericNodeHandle from './findNumericNodeHandle'; @@ -73,7 +72,6 @@ const ReactFabric: ReactFabricType = { NativeMethodsMixin, // Used by react-native-github/Libraries/ components ReactNativeComponentTree, // ScrollResponder - createReactNativeComponentClass, // RCTText, RCTView, ReactNativeART }, }; diff --git a/packages/react-native-renderer/src/ReactFabricRenderer.js b/packages/react-native-renderer/src/ReactFabricRenderer.js index 007c3772e5807..0ec040bddf05b 100644 --- a/packages/react-native-renderer/src/ReactFabricRenderer.js +++ b/packages/react-native-renderer/src/ReactFabricRenderer.js @@ -18,7 +18,7 @@ import type { import {mountSafeCallback, warnForStyleProps} from './NativeMethodsMixinUtils'; import * as ReactNativeAttributePayload from './ReactNativeAttributePayload'; import * as ReactNativeFrameScheduling from './ReactNativeFrameScheduling'; -import * as ReactNativeViewConfigRegistry from './ReactNativeViewConfigRegistry'; +import * as ReactNativeViewConfigRegistry from 'ReactNativeViewConfigRegistry'; import ReactFiberReconciler from 'react-reconciler'; import deepFreezeAndThrowOnMutationInDev from 'deepFreezeAndThrowOnMutationInDev'; diff --git a/packages/react-native-renderer/src/ReactNativeBridgeEventPlugin.js b/packages/react-native-renderer/src/ReactNativeBridgeEventPlugin.js index 19f6938d52648..69bc7a260a558 100644 --- a/packages/react-native-renderer/src/ReactNativeBridgeEventPlugin.js +++ b/packages/react-native-renderer/src/ReactNativeBridgeEventPlugin.js @@ -12,7 +12,7 @@ import { accumulateTwoPhaseDispatches, accumulateDirectDispatches, } from 'events/EventPropagators'; -import * as ReactNativeViewConfigRegistry from './ReactNativeViewConfigRegistry'; +import * as ReactNativeViewConfigRegistry from 'ReactNativeViewConfigRegistry'; import SyntheticEvent from 'events/SyntheticEvent'; import invariant from 'fbjs/lib/invariant'; diff --git a/packages/react-native-renderer/src/ReactNativeFiberRenderer.js b/packages/react-native-renderer/src/ReactNativeFiberRenderer.js index ebb4e17d1f09a..7de768b3b2981 100644 --- a/packages/react-native-renderer/src/ReactNativeFiberRenderer.js +++ b/packages/react-native-renderer/src/ReactNativeFiberRenderer.js @@ -16,7 +16,7 @@ import invariant from 'fbjs/lib/invariant'; import UIManager from 'UIManager'; import deepFreezeAndThrowOnMutationInDev from 'deepFreezeAndThrowOnMutationInDev'; -import * as ReactNativeViewConfigRegistry from './ReactNativeViewConfigRegistry'; +import * as ReactNativeViewConfigRegistry from 'ReactNativeViewConfigRegistry'; import * as ReactNativeAttributePayload from './ReactNativeAttributePayload'; import { precacheFiberNode, diff --git a/packages/react-native-renderer/src/ReactNativeRenderer.js b/packages/react-native-renderer/src/ReactNativeRenderer.js index 6419ef9ca1d96..faef67d42993b 100644 --- a/packages/react-native-renderer/src/ReactNativeRenderer.js +++ b/packages/react-native-renderer/src/ReactNativeRenderer.js @@ -25,7 +25,6 @@ import ReactNativeComponent from './ReactNativeComponent'; import * as ReactNativeComponentTree from './ReactNativeComponentTree'; import ReactNativeFiberRenderer from './ReactNativeFiberRenderer'; import {getInspectorDataForViewTag} from './ReactNativeFiberInspector'; -import createReactNativeComponentClass from './createReactNativeComponentClass'; import {injectFindHostInstance} from './findNodeHandle'; import findNumericNodeHandle from './findNumericNodeHandle'; @@ -98,7 +97,6 @@ const ReactNativeRenderer: ReactNativeType = { NativeMethodsMixin, // Used by react-native-github/Libraries/ components ReactNativeComponentTree, // ScrollResponder - createReactNativeComponentClass, // RCTText, RCTView, ReactNativeART computeComponentStackForErrorReporting, }, }; diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index 8f9305d0358a6..fdee974ae88aa 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -71,10 +71,6 @@ export type NativeMethodsMixinType = { type SecretInternalsType = { NativeMethodsMixin: NativeMethodsMixinType, - createReactNativeComponentClass( - name: string, - callback: ViewConfigGetter, - ): any, ReactNativeComponentTree: any, // TODO (bvaughn) Decide which additional types to expose here? // And how much information to fill in for the above types. diff --git a/packages/react-native-renderer/src/ReactNativeViewConfigRegistry.js b/packages/react-native-renderer/src/__mocks__/ReactNativeViewConfigRegistry.js similarity index 84% rename from packages/react-native-renderer/src/ReactNativeViewConfigRegistry.js rename to packages/react-native-renderer/src/__mocks__/ReactNativeViewConfigRegistry.js index 929bd8d4e52da..c8ed940a86095 100644 --- a/packages/react-native-renderer/src/ReactNativeViewConfigRegistry.js +++ b/packages/react-native-renderer/src/__mocks__/ReactNativeViewConfigRegistry.js @@ -6,18 +6,23 @@ * * @flow */ +'use strict'; import type { ReactNativeBaseComponentViewConfig, ViewConfigGetter, } from './ReactNativeTypes'; -import invariant from 'fbjs/lib/invariant'; +const invariant = require('fbjs/lib/invariant'); // Event configs -export const customBubblingEventTypes = {}; -export const customDirectEventTypes = {}; -export const eventTypes = {}; +const customBubblingEventTypes = {}; +const customDirectEventTypes = {}; +const eventTypes = {}; + +exports.customBubblingEventTypes = customBubblingEventTypes; +exports.customDirectEventTypes = customDirectEventTypes; +exports.eventTypes = eventTypes; const viewConfigCallbacks = new Map(); const viewConfigs = new Map(); @@ -64,7 +69,7 @@ function processEventTypes( * The callback is deferred until the view is actually rendered. * This is done to avoid causing Prepack deopts. */ -export function register(name: string, callback: ViewConfigGetter): string { +exports.register = function(name: string, callback: ViewConfigGetter): string { invariant( !viewConfigCallbacks.has(name), 'Tried to register two views with the same name %s', @@ -72,14 +77,14 @@ export function register(name: string, callback: ViewConfigGetter): string { ); viewConfigCallbacks.set(name, callback); return name; -} +}; /** * Retrieves a config for the specified view. * If this is the first time the view has been used, * This configuration will be lazy-loaded from UIManager. */ -export function get(name: string): ReactNativeBaseComponentViewConfig { +exports.get = function(name: string): ReactNativeBaseComponentViewConfig { let viewConfig; if (!viewConfigs.has(name)) { const callback = viewConfigCallbacks.get(name); @@ -97,4 +102,4 @@ export function get(name: string): ReactNativeBaseComponentViewConfig { } invariant(viewConfig, 'View config not found for name %s', name); return viewConfig; -} +}; diff --git a/packages/react-native-renderer/src/__mocks__/View.js b/packages/react-native-renderer/src/__mocks__/View.js deleted file mode 100644 index 5d5b57bd55134..0000000000000 --- a/packages/react-native-renderer/src/__mocks__/View.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -'use strict'; - -const createReactNativeComponentClass = require('../createReactNativeComponentClass') - .default; - -const View = createReactNativeComponentClass({ - validAttributes: {}, - uiViewClassName: 'View', -}); - -module.exports = View; diff --git a/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js index f1e5b462b0e47..9d60af7ef8add 100644 --- a/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js @@ -28,8 +28,8 @@ describe('ReactFabric', () => { ReactFabric = require('react-native-renderer/fabric'); FabricUIManager = require('FabricUIManager'); UIManager = require('UIManager'); - createReactNativeComponentClass = require('../createReactNativeComponentClass') - .default; + createReactNativeComponentClass = require('ReactNativeViewConfigRegistry') + .register; }); it('should be able to create and render a native component', () => { diff --git a/packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js index 24c31f45eaa02..793f3bd3e70d6 100644 --- a/packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js @@ -26,8 +26,8 @@ describe('ReactFabric', () => { React = require('react'); ReactFabric = require('react-native-renderer/fabric'); - createReactNativeComponentClass = require('../createReactNativeComponentClass') - .default; + createReactNativeComponentClass = require('ReactNativeViewConfigRegistry') + .register; }); it('find Fabric nodes with the RN renderer', () => { diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeError-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeError-test.internal.js index 4724db55f4621..d92c45c6fb915 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeError-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeError-test.internal.js @@ -25,8 +25,8 @@ describe('ReactNativeError', () => { React = require('react'); ReactNative = require('react-native-renderer'); - createReactNativeComponentClass = require('../createReactNativeComponentClass') - .default; + createReactNativeComponentClass = require('ReactNativeViewConfigRegistry') + .register; computeComponentStackForErrorReporting = ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED .computeComponentStackForErrorReporting; diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js index e61f1c2d29d5a..07fbe1692aa6a 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js @@ -69,8 +69,8 @@ beforeEach(() => { ReactNative = require('react-native-renderer'); ResponderEventPlugin = require('events/ResponderEventPlugin').default; UIManager = require('UIManager'); - createReactNativeComponentClass = require('../createReactNativeComponentClass') - .default; + createReactNativeComponentClass = require('ReactNativeViewConfigRegistry') + .register; }); it('fails if unknown/unsupported event types are dispatched', () => { diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js index c8d669e504f5b..f93a369d87251 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js @@ -22,8 +22,8 @@ describe('ReactNative', () => { React = require('react'); ReactNative = require('react-native-renderer'); UIManager = require('UIManager'); - createReactNativeComponentClass = require('../createReactNativeComponentClass') - .default; + createReactNativeComponentClass = require('ReactNativeViewConfigRegistry') + .register; }); it('should be able to create and render a native component', () => { diff --git a/packages/react-native-renderer/src/__tests__/createReactNativeComponentClass-test.internal.js b/packages/react-native-renderer/src/__tests__/createReactNativeComponentClass-test.internal.js index 47f943fcd67c8..6ff7e8aeccbbe 100644 --- a/packages/react-native-renderer/src/__tests__/createReactNativeComponentClass-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/createReactNativeComponentClass-test.internal.js @@ -18,8 +18,8 @@ describe('createReactNativeComponentClass', () => { beforeEach(() => { jest.resetModules(); - createReactNativeComponentClass = require('../createReactNativeComponentClass') - .default; + createReactNativeComponentClass = require('ReactNativeViewConfigRegistry') + .register; React = require('react'); ReactNative = require('react-native-renderer'); }); diff --git a/packages/react-native-renderer/src/createReactNativeComponentClass.js b/packages/react-native-renderer/src/createReactNativeComponentClass.js deleted file mode 100644 index d4308a2a715cc..0000000000000 --- a/packages/react-native-renderer/src/createReactNativeComponentClass.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -import type {ViewConfigGetter} from './ReactNativeTypes'; - -import {register} from './ReactNativeViewConfigRegistry'; - -/** - * Creates a renderable ReactNative host component. - * Use this method for view configs that are loaded from UIManager. - * Use createReactNativeComponentClass() for view configs defined within JavaScript. - * - * @param {string} config iOS View configuration. - * @private - */ -const createReactNativeComponentClass = function( - name: string, - callback: ViewConfigGetter, -): string { - return register(name, callback); -}; - -export default createReactNativeComponentClass; diff --git a/scripts/flow/react-native-host-hooks.js b/scripts/flow/react-native-host-hooks.js index a6fe506c4ac34..de0bdbf012af8 100644 --- a/scripts/flow/react-native-host-hooks.js +++ b/scripts/flow/react-native-host-hooks.js @@ -9,6 +9,11 @@ /* eslint-disable */ +import type { + ReactNativeBaseComponentViewConfig, + ViewConfigGetter, +} from 'react-native-renderer/src/ReactNativeTypes'; + declare module 'deepDiffer' { declare module.exports: (one: any, two: any) => boolean; } @@ -142,11 +147,11 @@ declare module 'BatchedBridge' { declare function registerCallableModule(name: string, module: Object): void; } -declare module 'CSComponent' { - declare type Element = any; - declare type Options = any; -} +declare module 'ReactNativeViewConfigRegistry' { + declare var customBubblingEventTypes: Object; + declare var customDirectEventTypes: Object; + declare var eventTypes: Object; -declare module 'CSStatefulComponent' { - declare function CSStatefulComponent(spec: any): any; + declare function register(name: string, callback: ViewConfigGetter): string; + declare function get(name: string): ReactNativeBaseComponentViewConfig; } diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 2108c442d650d..138017b5d8a8a 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -124,10 +124,10 @@ const bundles = [ 'RCTEventEmitter', 'TextInputState', 'UIManager', - 'View', 'deepDiffer', 'deepFreezeAndThrowOnMutationInDev', 'flattenStyle', + 'ReactNativeViewConfigRegistry', ], }, @@ -146,10 +146,10 @@ const bundles = [ 'TextInputState', 'UIManager', 'FabricUIManager', - 'View', 'deepDiffer', 'deepFreezeAndThrowOnMutationInDev', 'flattenStyle', + 'ReactNativeViewConfigRegistry', ], }, diff --git a/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js b/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js new file mode 100644 index 0000000000000..ffb0fa213f3b3 --- /dev/null +++ b/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule ReactNativeViewConfigRegistry + * @flow + */ +'use strict'; + +import type { + ReactNativeBaseComponentViewConfig, + ViewConfigGetter, +} from './ReactNativeTypes'; + +const invariant = require('fbjs/lib/invariant'); + +// Event configs +const customBubblingEventTypes = {}; +const customDirectEventTypes = {}; +const eventTypes = {}; + +exports.customBubblingEventTypes = customBubblingEventTypes; +exports.customDirectEventTypes = customDirectEventTypes; +exports.eventTypes = eventTypes; + +const viewConfigCallbacks = new Map(); +const viewConfigs = new Map(); + +function processEventTypes( + viewConfig: ReactNativeBaseComponentViewConfig, +): void { + const {bubblingEventTypes, directEventTypes} = viewConfig; + + if (__DEV__) { + if (bubblingEventTypes != null && directEventTypes != null) { + for (const topLevelType in directEventTypes) { + invariant( + bubblingEventTypes[topLevelType] == null, + 'Event cannot be both direct and bubbling: %s', + topLevelType, + ); + } + } + } + + if (bubblingEventTypes != null) { + for (const topLevelType in bubblingEventTypes) { + if (customBubblingEventTypes[topLevelType] == null) { + eventTypes[topLevelType] = customBubblingEventTypes[topLevelType] = + bubblingEventTypes[topLevelType]; + } + } + } + + if (directEventTypes != null) { + for (const topLevelType in directEventTypes) { + if (customDirectEventTypes[topLevelType] == null) { + eventTypes[topLevelType] = customDirectEventTypes[topLevelType] = + directEventTypes[topLevelType]; + } + } + } +} + +/** + * Registers a native view/component by name. + * A callback is provided to load the view config from UIManager. + * The callback is deferred until the view is actually rendered. + * This is done to avoid causing Prepack deopts. + */ +exports.register = function(name: string, callback: ViewConfigGetter): string { + invariant( + !viewConfigCallbacks.has(name), + 'Tried to register two views with the same name %s', + name, + ); + viewConfigCallbacks.set(name, callback); + return name; +}; + +/** + * Retrieves a config for the specified view. + * If this is the first time the view has been used, + * This configuration will be lazy-loaded from UIManager. + */ +exports.get = function(name: string): ReactNativeBaseComponentViewConfig { + let viewConfig; + if (!viewConfigs.has(name)) { + const callback = viewConfigCallbacks.get(name); + invariant( + typeof callback === 'function', + 'View config not found for name %s', + name, + ); + viewConfigCallbacks.set(name, null); + viewConfig = callback(); + processEventTypes(viewConfig); + viewConfigs.set(name, viewConfig); + } else { + viewConfig = viewConfigs.get(name); + } + invariant(viewConfig, 'View config not found for name %s', name); + return viewConfig; +}; diff --git a/scripts/rollup/shims/react-native/createReactNativeComponentClass.js b/scripts/rollup/shims/react-native/createReactNativeComponentClass.js index d5d2b8c590093..c368255b6133e 100644 --- a/scripts/rollup/shims/react-native/createReactNativeComponentClass.js +++ b/scripts/rollup/shims/react-native/createReactNativeComponentClass.js @@ -10,9 +10,23 @@ 'use strict'; -const { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, -} = require('ReactNative'); +import type {ViewConfigGetter} from './ReactNativeTypes'; -module.exports = - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.createReactNativeComponentClass; +const {register} = require('ReactNativeViewConfigRegistry'); + +/** + * Creates a renderable ReactNative host component. + * Use this method for view configs that are loaded from UIManager. + * Use createReactNativeComponentClass() for view configs defined within JavaScript. + * + * @param {string} config iOS View configuration. + * @private + */ +const createReactNativeComponentClass = function( + name: string, + callback: ViewConfigGetter, +): string { + return register(name, callback); +}; + +export default createReactNativeComponentClass;