main
js 112 lines 3.18 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow strict-local
8 */
9
10 'use strict';
11
12 import {type ViewConfig} from './ReactNativeTypes';
13
14 // Event configs
15 export const customBubblingEventTypes = {};
16 export const customDirectEventTypes = {};
17
18 const viewConfigCallbacks = new Map();
19 const viewConfigs = new Map();
20
21 function processEventTypes(viewConfig: ViewConfig): void {
22 const {bubblingEventTypes, directEventTypes} = viewConfig;
23
24 if (__DEV__) {
25 if (bubblingEventTypes != null && directEventTypes != null) {
26 for (const topLevelType in directEventTypes) {
27 if (bubblingEventTypes[topLevelType] != null) {
28 throw new Error(
29 `Event cannot be both direct and bubbling: ${topLevelType}`,
30 );
31 }
32 }
33 }
34 }
35
36 if (bubblingEventTypes != null) {
37 for (const topLevelType in bubblingEventTypes) {
38 if (customBubblingEventTypes[topLevelType] == null) {
39 customBubblingEventTypes[topLevelType] =
40 bubblingEventTypes[topLevelType];
41 }
42 }
43 }
44
45 if (directEventTypes != null) {
46 for (const topLevelType in directEventTypes) {
47 if (customDirectEventTypes[topLevelType] == null) {
48 customDirectEventTypes[topLevelType] = directEventTypes[topLevelType];
49 }
50 }
51 }
52 }
53
54 /**
55 * Registers a native view/component by name.
56 * A callback is provided to load the view config from UIManager.
57 * The callback is deferred until the view is actually rendered.
58 */
59 export function register(name: string, callback: () => ViewConfig): string {
60 if (viewConfigCallbacks.has(name)) {
61 throw new Error(`Tried to register two views with the same name ${name}`);
62 }
63
64 if (typeof callback !== 'function') {
65 throw new Error(
66 `View config getter callback for component \`${name}\` must be a function (received \`${
67 callback === null ? 'null' : typeof callback
68 }\`)`,
69 );
70 }
71
72 viewConfigCallbacks.set(name, callback);
73 return name;
74 }
75
76 /**
77 * Retrieves a config for the specified view.
78 * If this is the first time the view has been used,
79 * This configuration will be lazy-loaded from UIManager.
80 */
81 export function get(name: string): ViewConfig {
82 let viewConfig;
83 if (!viewConfigs.has(name)) {
84 const callback = viewConfigCallbacks.get(name);
85 if (typeof callback !== 'function') {
86 throw new Error(
87 `View config getter callback for component \`${name}\` must be a function (received \`${
88 callback === null ? 'null' : typeof callback
89 }\`).${
90 typeof name[0] === 'string' && /[a-z]/.test(name[0])
91 ? ' Make sure to start component names with a capital letter.'
92 : ''
93 }`,
94 );
95 }
96 viewConfig = callback();
97 processEventTypes(viewConfig);
98 viewConfigs.set(name, viewConfig);
99
100 // Clear the callback after the config is set so that
101 // we don't mask any errors during registration.
102 viewConfigCallbacks.set(name, null);
103 } else {
104 viewConfig = viewConfigs.get(name);
105 }
106
107 if (!viewConfig) {
108 throw new Error(`View config not found for name ${name}`);
109 }
110
111 return viewConfig;
112 }