mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
4e243ca7a3
Summary: We recently fixed RTL scrolling in Fabric on iOS: D26608231 (https://github.com/facebook/react-native/commit/e5921f7f384af45df4f355fa3fa1b58a20a269d3) Turns out, the mechanism for RTL scrolling on Android is completely different. It requires that content be wrapped in a "directional content view", which is `View` in LTR and `AndroidHorizontalScrollContentView` in RTL, backed by `ReactHorizontalScrollContainerView.java`. iOS doesn't require that and just uses View and some custom logic in ScrollView itself. In the future it would be great to align the platforms, but for now, for backwards-compat with non-Fabric and so we don't have to tear apart ScrollView.js, we codegen the AndroidHorizontalScrollContentView so it exists in C++, register the component, and stop mapping it to View explicitly in C++. Changelog: [Internal] Reviewed By: sammy-SC Differential Revision: D26659686 fbshipit-source-id: 3b9c646dbdb7fe9527d24d42bdc6acb1aca00945
218 lines
6.6 KiB
C++
218 lines
6.6 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/debug/react_native_assert.h>
|
|
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
|
#include <react/renderer/core/ShadowNodeFragment.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
ComponentDescriptorRegistry::ComponentDescriptorRegistry(
|
|
ComponentDescriptorParameters const ¶meters,
|
|
ComponentDescriptorProviderRegistry const &providerRegistry)
|
|
: parameters_(parameters), providerRegistry_(providerRegistry) {}
|
|
|
|
void ComponentDescriptorRegistry::add(
|
|
ComponentDescriptorProvider componentDescriptorProvider) const {
|
|
std::unique_lock<better::shared_mutex> lock(mutex_);
|
|
|
|
auto componentDescriptor = componentDescriptorProvider.constructor(
|
|
{parameters_.eventDispatcher,
|
|
parameters_.contextContainer,
|
|
componentDescriptorProvider.flavor});
|
|
react_native_assert(
|
|
componentDescriptor->getComponentHandle() ==
|
|
componentDescriptorProvider.handle);
|
|
react_native_assert(
|
|
componentDescriptor->getComponentName() ==
|
|
componentDescriptorProvider.name);
|
|
|
|
auto sharedComponentDescriptor = std::shared_ptr<ComponentDescriptor const>(
|
|
std::move(componentDescriptor));
|
|
_registryByHandle[componentDescriptorProvider.handle] =
|
|
sharedComponentDescriptor;
|
|
_registryByName[componentDescriptorProvider.name] = sharedComponentDescriptor;
|
|
}
|
|
|
|
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";
|
|
}
|
|
|
|
// TODO T63839307: remove this condition after deleting TextInlineImage from
|
|
// non-Fabric code
|
|
if (viewName == "TextInlineImage") {
|
|
return "Image";
|
|
}
|
|
if (viewName == "VirtualText") {
|
|
return "Text";
|
|
}
|
|
|
|
if (viewName == "ImageView") {
|
|
return "Image";
|
|
}
|
|
|
|
if (viewName == "AndroidHorizontalScrollView") {
|
|
return "ScrollView";
|
|
}
|
|
|
|
if (viewName == "RKShimmeringView") {
|
|
return "ShimmeringView";
|
|
}
|
|
|
|
if (viewName == "RefreshControl") {
|
|
return "PullToRefreshView";
|
|
}
|
|
|
|
// We need this temporarily for testing purposes until we have proper
|
|
// implementation of core components.
|
|
// iOS-only
|
|
if (viewName == "ScrollContentView") {
|
|
return "View";
|
|
}
|
|
|
|
// iOS-only
|
|
if (viewName == "MultilineTextInputView" ||
|
|
viewName == "SinglelineTextInputView") {
|
|
return "TextInput";
|
|
}
|
|
|
|
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()) {
|
|
mutex_.unlock_shared();
|
|
providerRegistry_.request(unifiedComponentName.c_str());
|
|
mutex_.lock_shared();
|
|
|
|
it = _registryByName.find(unifiedComponentName);
|
|
|
|
/*
|
|
* TODO: T54849676
|
|
* Uncomment the `assert` after the following block that checks
|
|
* `_fallbackComponentDescriptor` is no longer needed. The assert assumes
|
|
* that `componentDescriptorProviderRequest` is always not null and register
|
|
* some component on every single request.
|
|
*/
|
|
// assert(it != _registryByName.end());
|
|
}
|
|
|
|
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::
|
|
findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(
|
|
ComponentHandle componentHandle) const {
|
|
std::shared_lock<better::shared_mutex> lock(mutex_);
|
|
|
|
auto iterator = _registryByHandle.find(componentHandle);
|
|
if (iterator == _registryByHandle.end()) {
|
|
return nullptr;
|
|
}
|
|
|
|
return iterator->second.get();
|
|
}
|
|
|
|
ComponentDescriptor const &ComponentDescriptorRegistry::at(
|
|
ComponentHandle componentHandle) const {
|
|
std::shared_lock<better::shared_mutex> lock(mutex_);
|
|
|
|
return *_registryByHandle.at(componentHandle);
|
|
}
|
|
|
|
bool ComponentDescriptorRegistry::hasComponentDescriptorAt(
|
|
ComponentHandle componentHandle) const {
|
|
std::shared_lock<better::shared_mutex> lock(mutex_);
|
|
|
|
auto iterator = _registryByHandle.find(componentHandle);
|
|
if (iterator == _registryByHandle.end()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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 fragment = ShadowNodeFamilyFragment{tag, surfaceId, nullptr};
|
|
auto family =
|
|
componentDescriptor.createFamily(fragment, std::move(eventTarget));
|
|
auto const props =
|
|
componentDescriptor.cloneProps(nullptr, RawProps(propsDynamic));
|
|
auto const state =
|
|
componentDescriptor.createInitialState(ShadowNodeFragment{props}, family);
|
|
|
|
return componentDescriptor.createShadowNode(
|
|
{
|
|
/* .props = */ props,
|
|
/* .children = */ ShadowNodeFragment::childrenPlaceholder(),
|
|
/* .state = */ state,
|
|
},
|
|
family);
|
|
}
|
|
|
|
void ComponentDescriptorRegistry::setFallbackComponentDescriptor(
|
|
SharedComponentDescriptor descriptor) {
|
|
_fallbackComponentDescriptor = descriptor;
|
|
registerComponentDescriptor(descriptor);
|
|
}
|
|
|
|
ComponentDescriptor::Shared
|
|
ComponentDescriptorRegistry::getFallbackComponentDescriptor() const {
|
|
return _fallbackComponentDescriptor;
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|