mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
c5cc27f1e9
Summary: Currently, the same ComponentDescriptor class cannot be registered as a responder for components with different names. However, we have marginal cases where we really need it. The examples are `UnimplementedView` or possible universal interop with the classic RN or any other UI framework. This change adds a special optional argument to ComponentDescript constructor that allows implementing this functionality. Reviewed By: fkgozali Differential Revision: D17211915 fbshipit-source-id: 18f59e09fe06b875a8e8975b7b2ab423489238bb
182 lines
5.8 KiB
C++
182 lines
5.8 KiB
C++
// 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.
|
|
|
|
#include "ComponentDescriptorRegistry.h"
|
|
|
|
#include <react/core/ShadowNodeFragment.h>
|
|
#include <react/uimanager/primitives.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
ComponentDescriptorRegistry::ComponentDescriptorRegistry(
|
|
ComponentDescriptorParameters const ¶meters)
|
|
: parameters_(parameters) {}
|
|
|
|
void ComponentDescriptorRegistry::add(
|
|
ComponentDescriptorProvider componentDescriptorProvider) const {
|
|
std::unique_lock<better::shared_mutex> lock(mutex_);
|
|
|
|
auto componentDescriptor = componentDescriptorProvider.constructor(
|
|
{parameters_.eventDispatcher,
|
|
parameters_.contextContainer,
|
|
componentDescriptorProvider.flavor});
|
|
assert(
|
|
componentDescriptor->getComponentHandle() ==
|
|
componentDescriptorProvider.handle);
|
|
assert(
|
|
componentDescriptor->getComponentName() ==
|
|
componentDescriptorProvider.name);
|
|
|
|
auto sharedComponentDescriptor = std::shared_ptr<ComponentDescriptor const>(
|
|
std::move(componentDescriptor));
|
|
_registryByHandle[componentDescriptorProvider.handle] =
|
|
sharedComponentDescriptor;
|
|
_registryByName[componentDescriptorProvider.name] = sharedComponentDescriptor;
|
|
|
|
if (strcmp(componentDescriptorProvider.name, "UnimplementedNativeView") ==
|
|
0) {
|
|
auto *self = const_cast<ComponentDescriptorRegistry *>(this);
|
|
self->setFallbackComponentDescriptor(sharedComponentDescriptor);
|
|
}
|
|
}
|
|
|
|
void ComponentDescriptorRegistry::remove(
|
|
ComponentDescriptorProvider componentDescriptorProvider) const {
|
|
std::unique_lock<better::shared_mutex> lock(mutex_);
|
|
|
|
assert(
|
|
_registryByHandle.find(componentDescriptorProvider.handle) !=
|
|
_registryByHandle.end());
|
|
assert(
|
|
_registryByName.find(componentDescriptorProvider.name) !=
|
|
_registryByName.end());
|
|
|
|
_registryByHandle.erase(componentDescriptorProvider.handle);
|
|
_registryByName.erase(componentDescriptorProvider.name);
|
|
}
|
|
|
|
void ComponentDescriptorRegistry::registerComponentDescriptor(
|
|
SharedComponentDescriptor componentDescriptor) const {
|
|
ComponentHandle componentHandle = componentDescriptor->getComponentHandle();
|
|
_registryByHandle[componentHandle] = componentDescriptor;
|
|
|
|
ComponentName componentName = componentDescriptor->getComponentName();
|
|
_registryByName[componentName] = componentDescriptor;
|
|
}
|
|
|
|
static std::string componentNameByReactViewName(std::string viewName) {
|
|
// We need this function only for the transition period;
|
|
// eventually, all names will be unified.
|
|
|
|
std::string rctPrefix("RCT");
|
|
if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin())
|
|
.first == rctPrefix.end()) {
|
|
// If `viewName` has "RCT" prefix, remove it.
|
|
viewName.erase(0, rctPrefix.length());
|
|
}
|
|
|
|
// Fabric uses slightly new names for Text components because of differences
|
|
// in semantic.
|
|
if (viewName == "Text") {
|
|
return "Paragraph";
|
|
}
|
|
if (viewName == "VirtualText") {
|
|
return "Text";
|
|
}
|
|
|
|
if (viewName == "ImageView") {
|
|
return "Image";
|
|
}
|
|
|
|
if (viewName == "AndroidHorizontalScrollView") {
|
|
return "ScrollView";
|
|
}
|
|
|
|
if (viewName == "RKShimmeringView") {
|
|
return "ShimmeringView";
|
|
}
|
|
|
|
if (viewName == "AndroidProgressBar") {
|
|
return "ActivityIndicatorView";
|
|
}
|
|
|
|
// We need this temporarily for testing purposes until we have proper
|
|
// implementation of core components.
|
|
if (viewName == "SafeAreaView" || viewName == "ScrollContentView" ||
|
|
viewName == "AndroidHorizontalScrollContentView" // Android
|
|
) {
|
|
return "View";
|
|
}
|
|
|
|
return viewName;
|
|
}
|
|
|
|
ComponentDescriptor const &ComponentDescriptorRegistry::at(
|
|
std::string const &componentName) const {
|
|
std::shared_lock<better::shared_mutex> lock(mutex_);
|
|
|
|
auto unifiedComponentName = componentNameByReactViewName(componentName);
|
|
|
|
auto it = _registryByName.find(unifiedComponentName);
|
|
if (it == _registryByName.end()) {
|
|
if (_fallbackComponentDescriptor == nullptr) {
|
|
throw std::invalid_argument(
|
|
("Unable to find componentDescriptor for " + unifiedComponentName)
|
|
.c_str());
|
|
}
|
|
return *_fallbackComponentDescriptor.get();
|
|
}
|
|
return *it->second;
|
|
}
|
|
|
|
ComponentDescriptor const &ComponentDescriptorRegistry::at(
|
|
ComponentHandle componentHandle) const {
|
|
std::shared_lock<better::shared_mutex> lock(mutex_);
|
|
|
|
return *_registryByHandle.at(componentHandle);
|
|
}
|
|
|
|
SharedShadowNode ComponentDescriptorRegistry::createNode(
|
|
Tag tag,
|
|
std::string const &viewName,
|
|
SurfaceId surfaceId,
|
|
folly::dynamic const &propsDynamic,
|
|
SharedEventTarget const &eventTarget) const {
|
|
auto unifiedComponentName = componentNameByReactViewName(viewName);
|
|
auto const &componentDescriptor = this->at(unifiedComponentName);
|
|
|
|
auto const eventEmitter =
|
|
componentDescriptor.createEventEmitter(std::move(eventTarget), tag);
|
|
auto const props =
|
|
componentDescriptor.cloneProps(nullptr, RawProps(propsDynamic));
|
|
auto const state = componentDescriptor.createInitialState(
|
|
ShadowNodeFragment{surfaceId, tag, props, eventEmitter});
|
|
|
|
return componentDescriptor.createShadowNode({
|
|
/* .tag = */ tag,
|
|
/* .surfaceId = */ surfaceId,
|
|
/* .props = */ props,
|
|
/* .eventEmitter = */ eventEmitter,
|
|
/* .children = */ ShadowNodeFragment::childrenPlaceholder(),
|
|
/* .localData = */ ShadowNodeFragment::localDataPlaceholder(),
|
|
/* .state = */ state,
|
|
});
|
|
}
|
|
|
|
void ComponentDescriptorRegistry::setFallbackComponentDescriptor(
|
|
SharedComponentDescriptor descriptor) {
|
|
_fallbackComponentDescriptor = descriptor;
|
|
registerComponentDescriptor(descriptor);
|
|
}
|
|
|
|
ComponentDescriptor::Shared
|
|
ComponentDescriptorRegistry::getFallbackComponentDescriptor() const {
|
|
return _fallbackComponentDescriptor;
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|