diff --git a/Libraries/Components/SafeAreaView/RCTSafeAreaViewNativeComponent.js b/Libraries/Components/SafeAreaView/RCTSafeAreaViewNativeComponent.js index 1c3e9e7e823..9025f1a8819 100644 --- a/Libraries/Components/SafeAreaView/RCTSafeAreaViewNativeComponent.js +++ b/Libraries/Components/SafeAreaView/RCTSafeAreaViewNativeComponent.js @@ -23,6 +23,7 @@ type NativeProps = $ReadOnly<{| emulateUnlessSupported?: WithDefault, |}>; -export default (codegenNativeComponent( - 'RCTSafeAreaView', -): HostComponent); +export default (codegenNativeComponent('SafeAreaView', { + paperComponentName: 'RCTSafeAreaView', + interfaceOnly: true, +}): HostComponent); diff --git a/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.h b/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.h new file mode 100644 index 00000000000..6e310e32e9d --- /dev/null +++ b/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.h @@ -0,0 +1,21 @@ +/** + * 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. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * UIView class for root component. + */ +@interface RCTSafeAreaViewComponentView : RCTViewComponentView + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm new file mode 100644 index 00000000000..a12f2f8a31d --- /dev/null +++ b/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm @@ -0,0 +1,81 @@ +/** + * 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. + */ + +#import "RCTSafeAreaViewComponentView.h" + +#import +#import +#import "RCTConversions.h" + +using namespace facebook::react; + +static UIScrollView *findScrollView(UIView *view, uint recursionDepth = 0) +{ + if (recursionDepth >= 3) { + return NULL; + } + if ([view isKindOfClass:[UIScrollView class]]) { + return (UIScrollView *)view; + } + + if (view.subviews.count >= 1) { + for (UIView *subview in view.subviews) { + UIScrollView *scrollView = findScrollView(subview.subviews.firstObject, recursionDepth + 1); + if (scrollView) { + return scrollView; + } + } + } + + return NULL; +} + +@implementation RCTSafeAreaViewComponentView { + SafeAreaViewShadowNode::ConcreteState::Shared _state; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + self.clipsToBounds = YES; + } + + return self; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + UIScrollView *scrollView = findScrollView(self); + if (scrollView && CGSizeEqualToSize(scrollView.bounds.size, self.bounds.size)) { + [scrollView setContentInset:self.safeAreaInsets]; + } else { + if (_state != nullptr) { + CGSize size = self.bounds.size; + size.height -= self.safeAreaInsets.bottom; + auto newState = SafeAreaViewState{RCTSizeFromCGSize(size)}; + _state->updateState(std::move(newState)); + } + } +} + +#pragma mark - RCTComponentViewProtocol + +- (void)updateState:(facebook::react::State::Shared const &)state + oldState:(facebook::react::State::Shared const &)oldState +{ + _state = std::static_pointer_cast(state); +} + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +@end diff --git a/React/Fabric/Mounting/RCTComponentViewFactory.mm b/React/Fabric/Mounting/RCTComponentViewFactory.mm index ab3f3be3e26..f2d0796f4f4 100644 --- a/React/Fabric/Mounting/RCTComponentViewFactory.mm +++ b/React/Fabric/Mounting/RCTComponentViewFactory.mm @@ -23,6 +23,7 @@ #import "RCTParagraphComponentView.h" #import "RCTPullToRefreshViewComponentView.h" #import "RCTRootComponentView.h" +#import "RCTSafeAreaViewComponentView.h" #import "RCTScrollViewComponentView.h" #import "RCTSliderComponentView.h" #import "RCTSwitchComponentView.h" @@ -53,6 +54,7 @@ using namespace facebook::react; [componentViewFactory registerComponentViewClass:[RCTUnimplementedNativeComponentView class]]; [componentViewFactory registerComponentViewClass:[RCTModalHostViewComponentView class]]; [componentViewFactory registerComponentViewClass:[RCTARTSurfaceViewComponentView class]]; + [componentViewFactory registerComponentViewClass:[RCTSafeAreaViewComponentView class]]; auto providerRegistry = &componentViewFactory->_providerRegistry; diff --git a/ReactCommon/fabric/components/safeareaview/BUCK b/ReactCommon/fabric/components/safeareaview/BUCK new file mode 100644 index 00000000000..242fd43ce17 --- /dev/null +++ b/ReactCommon/fabric/components/safeareaview/BUCK @@ -0,0 +1,47 @@ +load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags") +load( + "//tools/build_defs/oss:rn_defs.bzl", + "APPLE", + "get_apple_compiler_flags", + "get_apple_inspector_flags", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) + +APPLE_COMPILER_FLAGS = get_apple_compiler_flags() + +rn_xplat_cxx_library( + name = "safeareaview", + srcs = glob( + ["**/*.cpp"], + ), + headers = [], + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ], + prefix = "react/components/safeareaview", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), + force_static = True, + labels = ["supermodule:ios/isolation/infra.react_native"], + platforms = (APPLE), + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + "-DWITH_FBSYSTRACE=1", + ], + visibility = ["PUBLIC"], + deps = [ + react_native_xplat_target("fabric/core:core"), + "fbsource//xplat/js/react-native-github:generated_components-rncore", + ], +) diff --git a/ReactCommon/fabric/components/safeareaview/SafeAreaViewComponentDescriptor.h b/ReactCommon/fabric/components/safeareaview/SafeAreaViewComponentDescriptor.h new file mode 100644 index 00000000000..c4f7760fd6f --- /dev/null +++ b/ReactCommon/fabric/components/safeareaview/SafeAreaViewComponentDescriptor.h @@ -0,0 +1,50 @@ +/** + * 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. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +/* + * Descriptor for component. + */ +class SafeAreaViewComponentDescriptor final + : public ConcreteComponentDescriptor { + using ConcreteComponentDescriptor::ConcreteComponentDescriptor; + void adopt(UnsharedShadowNode shadowNode) const override { + assert(std::dynamic_pointer_cast(shadowNode)); + auto safeAreaViewShadowNode = + std::static_pointer_cast(shadowNode); + + assert(std::dynamic_pointer_cast( + safeAreaViewShadowNode)); + auto layoutableShadowNode = + std::static_pointer_cast( + safeAreaViewShadowNode); + + auto state = + std::static_pointer_cast( + shadowNode->getState()); + auto stateData = state->getData(); + + if (stateData.safeAreaSize.width != 0 && + stateData.safeAreaSize.height != 0) { + layoutableShadowNode->setSize( + Size{stateData.safeAreaSize.width, stateData.safeAreaSize.height}); + layoutableShadowNode->setPositionType(YGPositionTypeAbsolute); + } + + ConcreteComponentDescriptor::adopt(shadowNode); + } +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/safeareaview/SafeAreaViewShadowNode.cpp b/ReactCommon/fabric/components/safeareaview/SafeAreaViewShadowNode.cpp new file mode 100644 index 00000000000..082c0cd3edd --- /dev/null +++ b/ReactCommon/fabric/components/safeareaview/SafeAreaViewShadowNode.cpp @@ -0,0 +1,16 @@ +/** + * 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 "SafeAreaViewShadowNode.h" + +namespace facebook { +namespace react { + +extern const char SafeAreaViewComponentName[] = "SafeAreaView"; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/safeareaview/SafeAreaViewShadowNode.h b/ReactCommon/fabric/components/safeareaview/SafeAreaViewShadowNode.h new file mode 100644 index 00000000000..f00be199061 --- /dev/null +++ b/ReactCommon/fabric/components/safeareaview/SafeAreaViewShadowNode.h @@ -0,0 +1,32 @@ +/** + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +extern const char SafeAreaViewComponentName[]; + +/* + * `ShadowNode` for component. + */ +class SafeAreaViewShadowNode final : public ConcreteViewShadowNode< + SafeAreaViewComponentName, + SafeAreaViewProps, + ViewEventEmitter, + SafeAreaViewState> { + using ConcreteViewShadowNode::ConcreteViewShadowNode; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/safeareaview/SafeAreaViewState.cpp b/ReactCommon/fabric/components/safeareaview/SafeAreaViewState.cpp new file mode 100644 index 00000000000..2ddefb563fd --- /dev/null +++ b/ReactCommon/fabric/components/safeareaview/SafeAreaViewState.cpp @@ -0,0 +1,12 @@ +/** + * 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 "SafeAreaViewState.h" + +namespace facebook { +namespace react {} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/safeareaview/SafeAreaViewState.h b/ReactCommon/fabric/components/safeareaview/SafeAreaViewState.h new file mode 100644 index 00000000000..20fdb66994b --- /dev/null +++ b/ReactCommon/fabric/components/safeareaview/SafeAreaViewState.h @@ -0,0 +1,31 @@ +/** + * 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. + */ + +#pragma once + +#include + +namespace facebook { +namespace react { + +/* + * State for component. + */ +class SafeAreaViewState final { + public: + using Shared = std::shared_ptr; + + SafeAreaViewState(){}; + SafeAreaViewState(Size screenSize_) : safeAreaSize(screenSize_){}; + + const Size safeAreaSize{}; + +#pragma mark - Getters +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp index 7325e225a47..c0d82f9dc99 100644 --- a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp +++ b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp @@ -111,7 +111,7 @@ static std::string componentNameByReactViewName(std::string viewName) { // We need this temporarily for testing purposes until we have proper // implementation of core components. - if (viewName == "SafeAreaView" || viewName == "ScrollContentView" || + if (viewName == "ScrollContentView" || viewName == "AndroidHorizontalScrollContentView" // Android ) { return "View";