From f385ee11cab024c3d387c0452f4c3c36f8009011 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 23 Feb 2026 20:35:30 -0800 Subject: [PATCH] Export ViewConfig processor attributes from ReactNativeStyleAttributes (#55674) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Centralize gated ViewConfig processor attributes into exported constants in `ReactNativeStyleAttributes.js`. This is a pure refactor — no new behavior. When `enableNativeCSSParsing()` is on, the JS processor is bypassed and the raw value is sent directly to native. Exported attributes: `colorAttribute`, `filterAttribute`, `boxShadowAttribute`, `backgroundImageAttribute`, `backgroundSizeAttribute`, `backgroundPositionAttribute`, `backgroundRepeatAttribute`. All ViewConfig files now import these constants instead of inlining `{process: require(...)}` or feature flag checks. Changelog: [Internal] Reviewed By: jorge-cab Differential Revision: D94052734 --- .../View/ReactNativeStyleAttributes.js | 47 +++++++++++++++---- .../NativeComponent/BaseViewConfig.android.js | 33 ++++++------- .../NativeComponent/BaseViewConfig.ios.js | 13 +++-- 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js index 93c3d1004bff..54b64fc50db5 100644 --- a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -24,8 +24,39 @@ import processTransform from '../../StyleSheet/processTransform'; import processTransformOrigin from '../../StyleSheet/processTransformOrigin'; import sizesDiffer from '../../Utilities/differ/sizesDiffer'; +const nativeCSSParsing = ReactNativeFeatureFlags.enableNativeCSSParsing(); + const colorAttributes = {process: processColor}; +/** + * Gated style attribute types. When native CSS parsing is enabled, the JS + * processor is bypassed and the raw value is sent directly to native. + * These are exported so that other ViewConfigs can reuse them. + */ +export const filterAttribute: AnyAttributeType = nativeCSSParsing + ? true + : {process: processFilter}; + +export const boxShadowAttribute: AnyAttributeType = nativeCSSParsing + ? true + : {process: processBoxShadow}; + +export const backgroundImageAttribute: AnyAttributeType = nativeCSSParsing + ? true + : {process: processBackgroundImage}; + +export const backgroundSizeAttribute: AnyAttributeType = nativeCSSParsing + ? true + : {process: processBackgroundSize}; + +export const backgroundPositionAttribute: AnyAttributeType = nativeCSSParsing + ? true + : {process: processBackgroundPosition}; + +export const backgroundRepeatAttribute: AnyAttributeType = nativeCSSParsing + ? true + : {process: processBackgroundRepeat}; + const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { /** * Layout @@ -125,9 +156,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { /** * Filter */ - filter: ReactNativeFeatureFlags.enableNativeCSSParsing() - ? true - : {process: processFilter}, + filter: filterAttribute, /** * MixBlendMode @@ -142,29 +171,27 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { /* * BoxShadow */ - boxShadow: ReactNativeFeatureFlags.enableNativeCSSParsing() - ? true - : {process: processBoxShadow}, + boxShadow: boxShadowAttribute, /** * BackgroundImage */ - experimental_backgroundImage: {process: processBackgroundImage}, + experimental_backgroundImage: backgroundImageAttribute, /** * BackgroundSize */ - experimental_backgroundSize: {process: processBackgroundSize}, + experimental_backgroundSize: backgroundSizeAttribute, /** * BackgroundPosition */ - experimental_backgroundPosition: {process: processBackgroundPosition}, + experimental_backgroundPosition: backgroundPositionAttribute, /** * BackgroundRepeat */ - experimental_backgroundRepeat: {process: processBackgroundRepeat}, + experimental_backgroundRepeat: backgroundRepeatAttribute, /** * View diff --git a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js index 728515be9bc4..e34d2e0436a3 100644 --- a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js +++ b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.android.js @@ -10,8 +10,15 @@ import type {PartialViewConfigWithoutName} from './PlatformBaseViewConfig'; -import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags'; import ReactNativeStyleAttributes from '../Components/View/ReactNativeStyleAttributes'; +import { + backgroundImageAttribute, + backgroundPositionAttribute, + backgroundRepeatAttribute, + backgroundSizeAttribute, + boxShadowAttribute, + filterAttribute, +} from '../Components/View/ReactNativeStyleAttributes'; import {DynamicallyInjectedByGestureHandler} from './ViewConfigIgnore'; const bubblingEventTypes = { @@ -191,24 +198,12 @@ const validAttributesForNonEventProps = { backgroundColor: {process: require('../StyleSheet/processColor').default}, transform: true, transformOrigin: true, - experimental_backgroundImage: ReactNativeFeatureFlags.enableNativeCSSParsing() - ? (true as const) - : {process: require('../StyleSheet/processBackgroundImage').default}, - experimental_backgroundSize: { - process: require('../StyleSheet/processBackgroundSize').default, - }, - experimental_backgroundPosition: { - process: require('../StyleSheet/processBackgroundPosition').default, - }, - experimental_backgroundRepeat: { - process: require('../StyleSheet/processBackgroundRepeat').default, - }, - boxShadow: ReactNativeFeatureFlags.enableNativeCSSParsing() - ? (true as const) - : {process: require('../StyleSheet/processBoxShadow').default}, - filter: ReactNativeFeatureFlags.enableNativeCSSParsing() - ? (true as const) - : {process: require('../StyleSheet/processFilter').default}, + experimental_backgroundImage: backgroundImageAttribute, + experimental_backgroundSize: backgroundSizeAttribute, + experimental_backgroundPosition: backgroundPositionAttribute, + experimental_backgroundRepeat: backgroundRepeatAttribute, + boxShadow: boxShadowAttribute, + filter: filterAttribute, mixBlendMode: true, isolation: true, opacity: true, diff --git a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js index 5c96ddeabeff..825ebfc6f81e 100644 --- a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js +++ b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js @@ -10,8 +10,11 @@ import type {PartialViewConfigWithoutName} from './PlatformBaseViewConfig'; -import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags'; import ReactNativeStyleAttributes from '../Components/View/ReactNativeStyleAttributes'; +import { + boxShadowAttribute, + filterAttribute, +} from '../Components/View/ReactNativeStyleAttributes'; import { ConditionallyIgnoredEventHandlers, DynamicallyInjectedByGestureHandler, @@ -228,12 +231,8 @@ const validAttributesForNonEventProps = { hitSlop: {diff: require('../Utilities/differ/insetsDiffer').default}, collapsable: true, collapsableChildren: true, - filter: ReactNativeFeatureFlags.enableNativeCSSParsing() - ? (true as const) - : {process: require('../StyleSheet/processFilter').default}, - boxShadow: ReactNativeFeatureFlags.enableNativeCSSParsing() - ? (true as const) - : {process: require('../StyleSheet/processBoxShadow').default}, + filter: filterAttribute, + boxShadow: boxShadowAttribute, mixBlendMode: true, isolation: true,