197 lines
5.6 KiB
JavaScript
197 lines
5.6 KiB
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
|
||
|
* @format
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
const ReactNativeStyleAttributes = require('../Components/View/ReactNativeStyleAttributes');
|
||
|
const resolveAssetSource = require('../Image/resolveAssetSource');
|
||
|
const processColor = require('../StyleSheet/processColor').default;
|
||
|
const processColorArray = require('../StyleSheet/processColorArray');
|
||
|
const insetsDiffer = require('../Utilities/differ/insetsDiffer');
|
||
|
const matricesDiffer = require('../Utilities/differ/matricesDiffer');
|
||
|
const pointsDiffer = require('../Utilities/differ/pointsDiffer');
|
||
|
const sizesDiffer = require('../Utilities/differ/sizesDiffer');
|
||
|
const UIManager = require('./UIManager');
|
||
|
const invariant = require('invariant');
|
||
|
|
||
|
function getNativeComponentAttributes(uiViewClassName: string): any {
|
||
|
const viewConfig = UIManager.getViewManagerConfig(uiViewClassName);
|
||
|
|
||
|
invariant(
|
||
|
viewConfig != null && viewConfig.NativeProps != null,
|
||
|
'requireNativeComponent: "%s" was not found in the UIManager.',
|
||
|
uiViewClassName,
|
||
|
);
|
||
|
|
||
|
// TODO: This seems like a whole lot of runtime initialization for every
|
||
|
// native component that can be either avoided or simplified.
|
||
|
let {baseModuleName, bubblingEventTypes, directEventTypes} = viewConfig;
|
||
|
let nativeProps = viewConfig.NativeProps;
|
||
|
|
||
|
bubblingEventTypes = bubblingEventTypes ?? {};
|
||
|
directEventTypes = directEventTypes ?? {};
|
||
|
|
||
|
while (baseModuleName) {
|
||
|
const baseModule = UIManager.getViewManagerConfig(baseModuleName);
|
||
|
if (!baseModule) {
|
||
|
baseModuleName = null;
|
||
|
} else {
|
||
|
bubblingEventTypes = {
|
||
|
...baseModule.bubblingEventTypes,
|
||
|
...bubblingEventTypes,
|
||
|
};
|
||
|
directEventTypes = {
|
||
|
...baseModule.directEventTypes,
|
||
|
...directEventTypes,
|
||
|
};
|
||
|
nativeProps = {
|
||
|
...baseModule.NativeProps,
|
||
|
...nativeProps,
|
||
|
};
|
||
|
baseModuleName = baseModule.baseModuleName;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const validAttributes: {[string]: mixed} = {};
|
||
|
|
||
|
for (const key in nativeProps) {
|
||
|
const typeName = nativeProps[key];
|
||
|
const diff = getDifferForType(typeName);
|
||
|
const process = getProcessorForType(typeName);
|
||
|
|
||
|
// If diff or process == null, omit the corresponding property from the Attribute
|
||
|
// Why:
|
||
|
// 1. Consistency with AttributeType flow type
|
||
|
// 2. Consistency with Static View Configs, which omit the null properties
|
||
|
validAttributes[key] =
|
||
|
diff == null
|
||
|
? process == null
|
||
|
? true
|
||
|
: {process}
|
||
|
: process == null
|
||
|
? {diff}
|
||
|
: {diff, process};
|
||
|
}
|
||
|
|
||
|
// Unfortunately, the current setup declares style properties as top-level
|
||
|
// props. This makes it so we allow style properties in the `style` prop.
|
||
|
// TODO: Move style properties into a `style` prop and disallow them as
|
||
|
// top-level props on the native side.
|
||
|
validAttributes.style = ReactNativeStyleAttributes;
|
||
|
|
||
|
Object.assign(viewConfig, {
|
||
|
uiViewClassName,
|
||
|
validAttributes,
|
||
|
bubblingEventTypes,
|
||
|
directEventTypes,
|
||
|
});
|
||
|
|
||
|
attachDefaultEventTypes(viewConfig);
|
||
|
|
||
|
return viewConfig;
|
||
|
}
|
||
|
|
||
|
function attachDefaultEventTypes(viewConfig: any) {
|
||
|
// This is supported on UIManager platforms (ex: Android),
|
||
|
// as lazy view managers are not implemented for all platforms.
|
||
|
// See [UIManager] for details on constants and implementations.
|
||
|
const constants = UIManager.getConstants();
|
||
|
if (constants.ViewManagerNames || constants.LazyViewManagersEnabled) {
|
||
|
// Lazy view managers enabled.
|
||
|
viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes());
|
||
|
} else {
|
||
|
viewConfig.bubblingEventTypes = merge(
|
||
|
viewConfig.bubblingEventTypes,
|
||
|
constants.genericBubblingEventTypes,
|
||
|
);
|
||
|
viewConfig.directEventTypes = merge(
|
||
|
viewConfig.directEventTypes,
|
||
|
constants.genericDirectEventTypes,
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TODO: Figure out how to avoid all this runtime initialization cost.
|
||
|
function merge(destination: ?Object, source: ?Object): ?Object {
|
||
|
if (!source) {
|
||
|
return destination;
|
||
|
}
|
||
|
if (!destination) {
|
||
|
return source;
|
||
|
}
|
||
|
|
||
|
for (const key in source) {
|
||
|
if (!source.hasOwnProperty(key)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
let sourceValue = source[key];
|
||
|
if (destination.hasOwnProperty(key)) {
|
||
|
const destinationValue = destination[key];
|
||
|
if (
|
||
|
typeof sourceValue === 'object' &&
|
||
|
typeof destinationValue === 'object'
|
||
|
) {
|
||
|
sourceValue = merge(destinationValue, sourceValue);
|
||
|
}
|
||
|
}
|
||
|
destination[key] = sourceValue;
|
||
|
}
|
||
|
return destination;
|
||
|
}
|
||
|
|
||
|
function getDifferForType(
|
||
|
typeName: string,
|
||
|
): ?(prevProp: any, nextProp: any) => boolean {
|
||
|
switch (typeName) {
|
||
|
// iOS Types
|
||
|
case 'CATransform3D':
|
||
|
return matricesDiffer;
|
||
|
case 'CGPoint':
|
||
|
return pointsDiffer;
|
||
|
case 'CGSize':
|
||
|
return sizesDiffer;
|
||
|
case 'UIEdgeInsets':
|
||
|
return insetsDiffer;
|
||
|
// Android Types
|
||
|
case 'Point':
|
||
|
return pointsDiffer;
|
||
|
case 'EdgeInsets':
|
||
|
return insetsDiffer;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
function getProcessorForType(typeName: string): ?(nextProp: any) => any {
|
||
|
switch (typeName) {
|
||
|
// iOS Types
|
||
|
case 'CGColor':
|
||
|
case 'UIColor':
|
||
|
return processColor;
|
||
|
case 'CGColorArray':
|
||
|
case 'UIColorArray':
|
||
|
return processColorArray;
|
||
|
case 'CGImage':
|
||
|
case 'UIImage':
|
||
|
case 'RCTImageSource':
|
||
|
return resolveAssetSource;
|
||
|
// Android Types
|
||
|
case 'Color':
|
||
|
return processColor;
|
||
|
case 'ColorArray':
|
||
|
return processColorArray;
|
||
|
case 'ImageSource':
|
||
|
return resolveAssetSource;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
module.exports = getNativeComponentAttributes;
|