From 17017d2b8181acf6e1ce6543f333cd6653b6945b Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Thu, 15 Aug 2024 16:55:26 -0700 Subject: [PATCH] Add `isolate` property (#45883) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45883 Isolate property lets us easily define when a should set a stacking context. This is particularly useful when used with `mix-blend-mode` Changelog: [Internal] Reviewed By: christophpurrer, NickGerleman Differential Revision: D60604683 fbshipit-source-id: 449079abe45ae57e98315bdf27b54ec5cf9d6fdc --- .../View/ReactNativeStyleAttributes.js | 5 +++ .../NativeComponent/BaseViewConfig.android.js | 1 + .../NativeComponent/BaseViewConfig.ios.js | 2 ++ .../Libraries/StyleSheet/StyleSheetTypes.d.ts | 1 + .../Libraries/StyleSheet/StyleSheetTypes.js | 1 + .../__snapshots__/public-api-test.js.snap | 1 + .../components/view/BaseViewProps.cpp | 9 ++++++ .../renderer/components/view/BaseViewProps.h | 6 +++- .../components/view/ViewShadowNode.cpp | 1 + .../renderer/components/view/conversions.h | 22 +++++++++++++ .../react/renderer/graphics/BlendMode.h | 4 --- .../react/renderer/graphics/Isolation.h | 31 +++++++++++++++++++ 12 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 packages/react-native/ReactCommon/react/renderer/graphics/Isolation.h diff --git a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js index e739919845e..c186586d9a0 100644 --- a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -127,6 +127,11 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { */ experimental_mixBlendMode: true, + /** + * Isolation + */ + isolation: true, + /* * BoxShadow */ diff --git a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js index 29f303eec7a..b8a3a9d57c5 100644 --- a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js +++ b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js @@ -170,6 +170,7 @@ const validAttributesForNonEventProps = { process: require('../StyleSheet/processFilter').default, }, experimental_mixBlendMode: true, + isolation: true, opacity: true, elevation: true, shadowColor: {process: require('../StyleSheet/processColor').default}, diff --git a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js index bcea251752d..d2259be0f8e 100644 --- a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js +++ b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js @@ -228,6 +228,8 @@ const validAttributesForNonEventProps = { experimental_boxShadow: { process: require('../StyleSheet/processBoxShadow').default, }, + experimental_mixBlendMode: true, + isolation: true, borderTopWidth: true, borderTopColor: {process: require('../StyleSheet/processColor').default}, diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts index ac67b1901b1..016c8b86096 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -332,6 +332,7 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { * Controls whether the View can be the target of touch events. */ pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined; + isolation?: 'auto' | 'isolate' | undefined; cursor?: CursorValue | undefined; } diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js index c92c63016dc..16e44fdfaa5 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js @@ -792,6 +792,7 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{ experimental_filter?: $ReadOnlyArray | string, experimental_mixBlendMode?: ____BlendMode_Internal, experimental_backgroundImage?: $ReadOnlyArray | string, + isolation?: 'auto' | 'isolate', }>; export type ____ViewStyle_Internal = $ReadOnly<{ diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index ad9ca9e408a..1e2c11f9295 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -8408,6 +8408,7 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{ experimental_filter?: $ReadOnlyArray | string, experimental_mixBlendMode?: ____BlendMode_Internal, experimental_backgroundImage?: $ReadOnlyArray | string, + isolation?: \\"auto\\" | \\"isolate\\", }>; export type ____ViewStyle_Internal = $ReadOnly<{ ...____ViewStyle_InternalCore, diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp index f23240ec914..8228b501f65 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.cpp @@ -184,6 +184,14 @@ BaseViewProps::BaseViewProps( "experimental_mixBlendMode", sourceProps.mixBlendMode, {})), + isolation( + CoreFeatures::enablePropIteratorSetter ? sourceProps.isolation + : convertRawProp( + context, + rawProps, + "isolation", + sourceProps.isolation, + {})), transform( CoreFeatures::enablePropIteratorSetter ? sourceProps.transform : convertRawProp( @@ -330,6 +338,7 @@ void BaseViewProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(shouldRasterize); RAW_SET_PROP_SWITCH_CASE_BASIC(zIndex); RAW_SET_PROP_SWITCH_CASE_BASIC(pointerEvents); + RAW_SET_PROP_SWITCH_CASE_BASIC(isolation); RAW_SET_PROP_SWITCH_CASE_BASIC(hitSlop); RAW_SET_PROP_SWITCH_CASE_BASIC(onLayout); RAW_SET_PROP_SWITCH_CASE_BASIC(collapsable); diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.h b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.h index 1e37eec1d69..edc01556c91 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/BaseViewProps.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -68,7 +69,10 @@ class BaseViewProps : public YogaStylableProps, public AccessibilityProps { std::vector backgroundImage{}; // MixBlendMode - BlendMode mixBlendMode; + BlendMode mixBlendMode{BlendMode::Normal}; + + // Isolate + Isolation isolation{Isolation::Auto}; // Transform Transform transform{}; diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.cpp index 49099f87ef7..ef13a094524 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/ViewShadowNode.cpp @@ -63,6 +63,7 @@ void ViewShadowNode::initialize() noexcept { viewProps.removeClippedSubviews || viewProps.cursor != Cursor::Auto || !viewProps.filter.empty() || viewProps.mixBlendMode != BlendMode::Normal || + viewProps.isolation == Isolation::Isolate || HostPlatformViewTraitsInitializer::formsStackingContext(viewProps); bool formsView = formsStackingContext || diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h index fdb4251b16e..6681c69dfeb 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1184,6 +1185,27 @@ inline void fromRawValue( result = backgroundImage; } +inline void fromRawValue( + const PropsParserContext& /*context*/, + const RawValue& value, + Isolation& result) { + react_native_expect(value.hasType()); + result = Isolation::Auto; + if (!value.hasType()) { + return; + } + + auto rawIsolation = static_cast(value); + std::optional isolation = isolationFromString(rawIsolation); + + if (!isolation) { + LOG(ERROR) << "Could not parse isolation: " << rawIsolation; + return; + } + + result = isolation.value(); +} + template inline std::string toString(const std::array vec) { std::string s; diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/BlendMode.h b/packages/react-native/ReactCommon/react/renderer/graphics/BlendMode.h index 9399ff8e4b5..1afd7864f1f 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/BlendMode.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/BlendMode.h @@ -7,12 +7,8 @@ #pragma once -#include - #include -#include #include -#include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/Isolation.h b/packages/react-native/ReactCommon/react/renderer/graphics/Isolation.h new file mode 100644 index 00000000000..941c4a1c28a --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/graphics/Isolation.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace facebook::react { + +// https://www.w3.org/TR/compositing-1/#isolation +enum class Isolation { + Auto, + Isolate, +}; + +inline std::optional isolationFromString( + std::string_view isolationSetting) { + if (isolationSetting == "auto") { + return Isolation::Auto; + } else if (isolationSetting == "isolate") { + return Isolation::Isolate; + } else { + return std::nullopt; + } +} +} // namespace facebook::react