123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- /**
- * Copyright (c) Facebook, Inc. and its 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 UIManager = require('./UIManager');
- const insetsDiffer = require('../Utilities/differ/insetsDiffer');
- const invariant = require('invariant');
- const matricesDiffer = require('../Utilities/differ/matricesDiffer');
- const pointsDiffer = require('../Utilities/differ/pointsDiffer');
- const processColor = require('../StyleSheet/processColor');
- const processColorArray = require('../StyleSheet/processColorArray');
- const resolveAssetSource = require('../Image/resolveAssetSource');
- const sizesDiffer = require('../Utilities/differ/sizesDiffer');
- const warning = require('fbjs/lib/warning');
- 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;
- while (baseModuleName) {
- const baseModule = UIManager.getViewManagerConfig(baseModuleName);
- if (!baseModule) {
- warning(false, 'Base module "%s" does not exist', baseModuleName);
- baseModuleName = null;
- } else {
- bubblingEventTypes = {
- ...baseModule.bubblingEventTypes,
- ...bubblingEventTypes,
- };
- directEventTypes = {
- ...baseModule.directEventTypes,
- ...directEventTypes,
- };
- nativeProps = {
- ...baseModule.NativeProps,
- ...nativeProps,
- };
- baseModuleName = baseModule.baseModuleName;
- }
- }
- const validAttributes = {};
- for (const key in nativeProps) {
- const typeName = nativeProps[key];
- const diff = getDifferForType(typeName);
- const process = getProcessorForType(typeName);
- validAttributes[key] =
- diff == null && process == null ? true : {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,
- });
- if (!hasAttachedDefaultEventTypes) {
- attachDefaultEventTypes(viewConfig);
- hasAttachedDefaultEventTypes = true;
- }
- return viewConfig;
- }
- // TODO: Figure out how this makes sense. We're using a global boolean to only
- // initialize this on the first eagerly initialized native component.
- let hasAttachedDefaultEventTypes = false;
- 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
- // (not yet implemented)
- }
- 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;
- }
- return null;
- }
- module.exports = getNativeComponentAttributes;
|