react-native-windows 0.79.2 → 0.80.0-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/.flowconfig +12 -3
  2. package/Directory.Build.props +5 -2
  3. package/Libraries/Alert/Alert.d.ts +4 -1
  4. package/Libraries/Alert/Alert.js +3 -0
  5. package/Libraries/Alert/Alert.windows.js +3 -0
  6. package/Libraries/Alert/RCTAlertManager.js +17 -0
  7. package/Libraries/Animated/Animated.js.flow +1 -3
  8. package/Libraries/Animated/AnimatedEvent.js +4 -3
  9. package/Libraries/Animated/AnimatedExports.js +2 -2
  10. package/Libraries/Animated/AnimatedExports.js.flow +140 -0
  11. package/Libraries/Animated/AnimatedImplementation.js +2 -123
  12. package/Libraries/Animated/Easing.js +13 -15
  13. package/Libraries/Animated/animations/Animation.js +8 -4
  14. package/Libraries/Animated/components/AnimatedFlatList.js +7 -6
  15. package/Libraries/Animated/components/AnimatedScrollView.js +48 -42
  16. package/Libraries/Animated/components/AnimatedSectionList.js +11 -7
  17. package/Libraries/Animated/createAnimatedComponent.js +105 -57
  18. package/Libraries/Animated/nodes/AnimatedNode.js +4 -3
  19. package/Libraries/Animated/nodes/AnimatedProps.js +46 -26
  20. package/Libraries/Animated/nodes/AnimatedValue.js +16 -7
  21. package/Libraries/Animated/nodes/AnimatedValueXY.js +3 -1
  22. package/Libraries/AppState/AppState.js +7 -2
  23. package/Libraries/BatchedBridge/MessageQueue.js +2 -2
  24. package/Libraries/BatchedBridge/NativeModules.js +2 -0
  25. package/Libraries/Blob/BlobManager.js +1 -0
  26. package/Libraries/Blob/FileReader.js +219 -8
  27. package/Libraries/Blob/URL.js +37 -12
  28. package/Libraries/Blob/URLSearchParams.js +106 -31
  29. package/Libraries/Blob/URLSearchParams.js.flow +12 -7
  30. package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +1 -1
  31. package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.windows.js +1 -1
  32. package/Libraries/Components/AccessibilityInfo/legacySendAccessibilityEvent.js +17 -0
  33. package/Libraries/Components/ActivityIndicator/ActivityIndicator.js +1 -0
  34. package/Libraries/Components/Button.d.ts +3 -0
  35. package/Libraries/Components/Button.js +1 -1
  36. package/Libraries/Components/Button.windows.js +27 -1
  37. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +1 -3
  38. package/Libraries/{NewAppScreen/components/Colors.js → Components/DrawerAndroid/DrawerLayoutAndroid.ios.js} +6 -10
  39. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.js +6 -66
  40. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.js.flow +18 -0
  41. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroidFallback.js +71 -0
  42. package/Libraries/Components/Flyout/Flyout.js +11 -0
  43. package/Libraries/Components/Keyboard/Keyboard.js +5 -3
  44. package/Libraries/Components/Keyboard/KeyboardAvoidingView.js +6 -3
  45. package/Libraries/Components/Keyboard/KeyboardExt.js.map +1 -1
  46. package/Libraries/Components/Popup/Popup.js +11 -0
  47. package/Libraries/Components/Pressable/Pressable.js +20 -4
  48. package/Libraries/Components/Pressable/Pressable.windows.js +20 -4
  49. package/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.js +25 -3
  50. package/Libraries/Components/ProgressBarAndroid/ProgressBarAndroidTypes.js +29 -20
  51. package/Libraries/Components/RefreshControl/RefreshControl.js +1 -1
  52. package/Libraries/Components/RefreshControl/RefreshControl.windows.js +1 -1
  53. package/Libraries/Components/ScrollView/ScrollView.d.ts +3 -3
  54. package/Libraries/Components/ScrollView/ScrollView.js +132 -122
  55. package/Libraries/Components/ScrollView/ScrollView.windows.js +131 -122
  56. package/Libraries/Components/StaticRenderer.js +1 -1
  57. package/Libraries/Components/Switch/Switch.d.ts +3 -0
  58. package/Libraries/Components/Switch/Switch.js +8 -4
  59. package/Libraries/Components/Switch/Switch.windows.js +17 -4
  60. package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +2 -1
  61. package/Libraries/Components/TextInput/RCTTextInputViewConfig.js +2 -4
  62. package/Libraries/Components/TextInput/TextInput.d.ts +70 -33
  63. package/Libraries/Components/TextInput/TextInput.flow.js +100 -51
  64. package/Libraries/Components/TextInput/TextInput.flow.windows.js +1246 -0
  65. package/Libraries/Components/TextInput/TextInput.js +88 -1027
  66. package/Libraries/Components/TextInput/TextInput.windows.js +104 -1092
  67. package/Libraries/Components/TextInput/TextInputState.js +1 -1
  68. package/Libraries/Components/TextInput/TextInputState.windows.js +1 -1
  69. package/Libraries/Components/TextInput/WindowsTextInputNativeComponent.js +2 -1
  70. package/Libraries/{Modal/ModalInjection.js → Components/ToastAndroid/ToastAndroid.ios.js} +3 -5
  71. package/Libraries/Components/ToastAndroid/ToastAndroid.js +4 -32
  72. package/Libraries/Components/ToastAndroid/ToastAndroid.js.flow +109 -0
  73. package/Libraries/Components/ToastAndroid/ToastAndroidFallback.js +45 -0
  74. package/Libraries/Components/Touchable/Touchable.js +5 -5
  75. package/Libraries/Components/Touchable/Touchable.windows.js +5 -5
  76. package/Libraries/Components/Touchable/TouchableBounce.js +14 -7
  77. package/Libraries/Components/Touchable/TouchableBounce.windows.js +14 -7
  78. package/Libraries/Components/Touchable/TouchableHighlight.js +10 -7
  79. package/Libraries/Components/Touchable/TouchableHighlight.windows.js +10 -7
  80. package/Libraries/Components/Touchable/TouchableNativeFeedback.js +6 -6
  81. package/Libraries/Components/Touchable/TouchableNativeFeedback.windows.js +6 -6
  82. package/Libraries/Components/Touchable/TouchableOpacity.js +13 -6
  83. package/Libraries/Components/Touchable/TouchableOpacity.windows.js +13 -6
  84. package/Libraries/Components/View/View.js +18 -21
  85. package/Libraries/Components/View/View.windows.js +39 -41
  86. package/Libraries/Components/View/ViewAccessibility.d.ts +8 -0
  87. package/Libraries/Components/View/ViewAccessibility.js +25 -1
  88. package/Libraries/Components/View/ViewAccessibility.windows.js +9 -1
  89. package/Libraries/Components/View/ViewPropTypes.js +49 -3
  90. package/Libraries/Components/View/ViewPropTypes.windows.js +50 -2
  91. package/Libraries/Core/ReactNativeVersion.js +1 -1
  92. package/Libraries/Core/setUpReactDevTools.js +5 -5
  93. package/Libraries/Debugging/DebuggingOverlayRegistry.js +3 -3
  94. package/Libraries/EventEmitter/NativeEventEmitter.js +9 -4
  95. package/Libraries/Image/AssetSourceResolver.js +17 -4
  96. package/Libraries/Image/AssetSourceResolver.windows.js +17 -4
  97. package/Libraries/Image/Image.d.ts +26 -10
  98. package/Libraries/Image/Image.js +17 -0
  99. package/Libraries/Image/Image.js.flow +5 -5
  100. package/Libraries/Image/Image.windows.js +13 -1
  101. package/Libraries/Image/ImageBackground.js +2 -0
  102. package/Libraries/Image/ImageInjection.js +1 -1
  103. package/Libraries/Image/ImageProps.js +22 -17
  104. package/Libraries/Image/ImageSource.js +3 -1
  105. package/Libraries/Image/ImageSourceUtils.js +4 -2
  106. package/Libraries/Image/ImageTypes.flow.js +1 -1
  107. package/Libraries/Interaction/InteractionManager.d.ts +13 -0
  108. package/Libraries/Interaction/InteractionManager.js +1 -1
  109. package/Libraries/Interaction/PanResponder.js +3 -3
  110. package/Libraries/Interaction/TaskQueue.js +1 -0
  111. package/Libraries/LayoutAnimation/LayoutAnimation.js +2 -2
  112. package/Libraries/Linking/Linking.js +1 -1
  113. package/Libraries/Lists/FlatList.d.ts +2 -2
  114. package/Libraries/Lists/FlatList.js +8 -11
  115. package/Libraries/Lists/SectionList.js +39 -42
  116. package/Libraries/Lists/SectionListModern.js +25 -34
  117. package/Libraries/Lists/VirtualizedList.js +1 -0
  118. package/Libraries/Lists/VirtualizedSectionList.js +1 -0
  119. package/Libraries/LogBox/Data/LogBoxData.js +1 -1
  120. package/Libraries/LogBox/LogBoxNotificationContainer.js +1 -1
  121. package/Libraries/Modal/Modal.js +33 -7
  122. package/Libraries/Modal/Modal.windows.js +33 -10
  123. package/Libraries/NativeComponent/BaseViewConfig.android.js +2 -0
  124. package/Libraries/NativeComponent/BaseViewConfig.ios.js +2 -0
  125. package/Libraries/NativeComponent/BaseViewConfig.js +17 -0
  126. package/Libraries/NativeComponent/BaseViewConfig.windows.js +3 -0
  127. package/Libraries/NativeComponent/PlatformBaseViewConfig.js +2 -2
  128. package/Libraries/NativeModules/specs/NativeDevMenu.js +2 -2
  129. package/Libraries/Network/RCTNetworking.android.js +1 -1
  130. package/Libraries/Network/RCTNetworking.ios.js +1 -1
  131. package/Libraries/Network/RCTNetworking.js +17 -0
  132. package/Libraries/Network/RCTNetworking.js.flow +1 -1
  133. package/Libraries/Network/RCTNetworking.windows.js +1 -1
  134. package/Libraries/Network/XMLHttpRequest.js +781 -10
  135. package/Libraries/Performance/Systrace.js +7 -7
  136. package/Libraries/Pressability/Pressability.js +1 -1
  137. package/Libraries/Pressability/Pressability.windows.js +1 -1
  138. package/Libraries/ReactNative/AppContainer-dev.js +5 -4
  139. package/Libraries/ReactNative/AppRegistry.flow.js +49 -0
  140. package/Libraries/ReactNative/AppRegistry.js +2 -322
  141. package/Libraries/ReactNative/AppRegistry.js.flow +23 -0
  142. package/Libraries/ReactNative/AppRegistryImpl.js +316 -0
  143. package/Libraries/ReactNative/FabricUIManager.js +10 -0
  144. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent.js +2 -4
  145. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstance.js +1 -4
  146. package/Libraries/ReactNative/RendererImplementation.js +10 -5
  147. package/Libraries/ReactNative/getNativeComponentAttributes.js +1 -0
  148. package/Libraries/ReactNative/renderApplication.js +9 -0
  149. package/Libraries/ReactPrivate/ReactNativePrivateInterface.js +3 -3
  150. package/Libraries/ReactPrivate/ReactNativePrivateInterface.js.flow +51 -0
  151. package/Libraries/Renderer/implementations/ReactFabric-dev.js +4840 -4748
  152. package/Libraries/Renderer/implementations/ReactFabric-prod.js +4947 -4829
  153. package/Libraries/Renderer/implementations/ReactFabric-profiling.js +3998 -3888
  154. package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +5005 -4948
  155. package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +2744 -2652
  156. package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +5020 -4933
  157. package/Libraries/Renderer/shims/ReactNativeTypes.js +3 -3
  158. package/Libraries/Settings/Settings.ios.js +1 -0
  159. package/Libraries/Settings/Settings.js +13 -19
  160. package/Libraries/Settings/SettingsFallback.js +33 -0
  161. package/Libraries/StyleSheet/PlatformColorValueTypes.js +15 -0
  162. package/Libraries/StyleSheet/PlatformColorValueTypesIOS.js +6 -0
  163. package/Libraries/StyleSheet/Rect.js +1 -0
  164. package/Libraries/StyleSheet/StyleSheet.js +31 -200
  165. package/Libraries/StyleSheet/StyleSheet.js.flow +188 -0
  166. package/Libraries/StyleSheet/StyleSheetExports.js +210 -0
  167. package/Libraries/StyleSheet/StyleSheetExports.js.flow +112 -0
  168. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +1 -1
  169. package/Libraries/StyleSheet/StyleSheetTypes.js +130 -52
  170. package/Libraries/StyleSheet/flattenStyle.js +14 -4
  171. package/Libraries/StyleSheet/private/_TransformStyle.js +49 -21
  172. package/Libraries/StyleSheet/processBackgroundImage.js +670 -214
  173. package/Libraries/Text/Text.d.ts +2 -5
  174. package/Libraries/Text/Text.js +3 -3
  175. package/Libraries/Text/Text.windows.js +3 -3
  176. package/Libraries/Text/TextNativeComponent.js +0 -4
  177. package/Libraries/Text/TextProps.js +5 -33
  178. package/Libraries/Text/TextProps.windows.js +5 -32
  179. package/Libraries/Types/CodegenTypesNamespace.d.ts +45 -0
  180. package/Libraries/{Blob/__mocks__/BlobModule.js → Types/CodegenTypesNamespace.js} +4 -6
  181. package/Libraries/Types/CoreEventTypes.d.ts +6 -1
  182. package/Libraries/Types/CoreEventTypes.js +1 -1
  183. package/Libraries/Types/CoreEventTypes.windows.js +1 -1
  184. package/Libraries/Utilities/Appearance.js +2 -0
  185. package/Libraries/Utilities/BackHandler.js +17 -0
  186. package/Libraries/Utilities/DeviceInfo.js +2 -0
  187. package/Libraries/Utilities/Dimensions.js +1 -1
  188. package/Libraries/Utilities/Platform.js +17 -0
  189. package/Libraries/Utilities/PlatformTypes.js +11 -3
  190. package/Libraries/Utilities/ReactNativeTestTools.js +2 -2
  191. package/Libraries/Utilities/codegenNativeCommands.d.ts +18 -0
  192. package/Libraries/Utilities/codegenNativeComponent.d.ts +26 -0
  193. package/Libraries/WebSocket/WebSocket.js +313 -8
  194. package/Libraries/vendor/core/ErrorUtils.js +28 -2
  195. package/Libraries/vendor/emitter/EventEmitter.js +6 -2
  196. package/Microsoft.ReactNative/CompositionSwitcher.idl +8 -0
  197. package/Microsoft.ReactNative/Fabric/AbiComponentDescriptor.cpp +0 -6
  198. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +197 -1
  199. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +34 -4
  200. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +12 -0
  201. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +36 -33
  202. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +81 -0
  203. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +5 -0
  204. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +148 -14
  205. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +4 -0
  206. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.cpp +29 -0
  207. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.h +2 -0
  208. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +17 -34
  209. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +4 -0
  210. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +2 -0
  211. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.cpp +16 -0
  212. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.h +1 -0
  213. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +9 -0
  214. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +1 -0
  215. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewTraitsInitializer.h +4 -0
  216. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager.cpp +34 -94
  217. package/Microsoft.ReactNative/Modules/SampleTurboModule.cpp +4 -0
  218. package/Microsoft.ReactNative/Modules/SampleTurboModule.h +3 -0
  219. package/Microsoft.ReactNative/TurboModulesProvider.h +1 -1
  220. package/Microsoft.ReactNative.Cxx/JSI/JsiApiContext.h +1 -1
  221. package/Microsoft.ReactNative.Cxx/JSI/LongLivedJsiValue.h +1 -1
  222. package/PropertySheets/Generated/PackageVersion.g.props +4 -4
  223. package/PropertySheets/React.Cpp.props +4 -0
  224. package/README.md +2 -2
  225. package/ReactCommon/ReactCommon.vcxproj +9 -4
  226. package/ReactCommon/ReactCommon.vcxproj.filters +6 -0
  227. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/CxxNativeModule.cpp +253 -0
  228. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.cpp +5 -2
  229. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/NativeToJsBridge.cpp +4 -8
  230. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/TraceSection.h +184 -0
  231. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/NetworkIOAgent.cpp +22 -0
  232. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/NetworkIOAgent.h +2 -4
  233. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModuleWithJSIBindings.cpp +27 -0
  234. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp +2 -1
  235. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/AccessibilityPrimitives.h +1 -1
  236. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/AccessibilityProps.cpp +308 -0
  237. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/core/DynamicEventPayload.cpp +42 -0
  238. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/css/CSSTokenizer.h +7 -51
  239. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/runtime/ReactInstance.cpp +10 -5
  240. package/Scripts/creaternwapp.cmd +9 -3
  241. package/Shared/Shared.vcxitems +3 -2
  242. package/Shared/Shared.vcxitems.filters +2 -1
  243. package/codegen/NativeAnimatedModuleSpec.g.h +2 -0
  244. package/codegen/NativeAnimatedTurboModuleSpec.g.h +2 -0
  245. package/codegen/NativePerformanceSpec.g.h +14 -0
  246. package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +151 -127
  247. package/codegen/NativeSampleTurboModuleSpec.g.h +14 -8
  248. package/codegen/react/components/rnwcore/EventEmitters.cpp +48 -48
  249. package/codegen/rnwcoreJSI-generated.cpp +159 -129
  250. package/codegen/rnwcoreJSI.h +534 -408
  251. package/index.js +51 -331
  252. package/index.windows.js +70 -352
  253. package/interface.js +0 -4
  254. package/jest/resolver.js +31 -0
  255. package/jest/setup.js +6 -2
  256. package/package.json +29 -28
  257. package/src/private/animated/NativeAnimatedHelper.js +21 -8
  258. package/src/private/animated/createAnimatedPropsHook.js +11 -16
  259. package/src/private/animated/createAnimatedPropsMemoHook.js +1 -2
  260. package/src/private/components/{SafeAreaView_INTERNAL_DO_NOT_USE.js → safeareaview/SafeAreaView_INTERNAL_DO_NOT_USE.js} +6 -6
  261. package/src/private/components/{HScrollViewNativeComponents.js → scrollview/HScrollViewNativeComponents.js} +8 -8
  262. package/src/private/components/scrollview/VScrollViewNativeComponents.js +25 -0
  263. package/src/private/{devmenu → devsupport/devmenu}/DevMenu.js +1 -1
  264. package/src/private/{inspector → devsupport/devmenu/elementinspector}/BorderBox.js +3 -3
  265. package/src/private/{inspector → devsupport/devmenu/elementinspector}/BoxInspector.js +6 -5
  266. package/src/private/{inspector → devsupport/devmenu/elementinspector}/ElementBox.js +8 -6
  267. package/src/private/{inspector → devsupport/devmenu/elementinspector}/ElementProperties.js +11 -10
  268. package/src/private/{inspector → devsupport/devmenu/elementinspector}/Inspector.js +14 -12
  269. package/src/private/{inspector → devsupport/devmenu/elementinspector}/InspectorOverlay.js +5 -4
  270. package/src/private/{inspector → devsupport/devmenu/elementinspector}/InspectorPanel.js +9 -8
  271. package/src/private/{inspector → devsupport/devmenu/elementinspector}/NetworkOverlay.js +10 -9
  272. package/src/private/{inspector → devsupport/devmenu/elementinspector}/ReactDevToolsOverlay.js +7 -7
  273. package/src/private/{inspector → devsupport/devmenu/elementinspector}/StyleInspector.js +7 -6
  274. package/src/private/{inspector → devsupport/devmenu/elementinspector}/XHRInterceptor.js +2 -2
  275. package/src/private/{inspector → devsupport/devmenu/elementinspector}/getInspectorDataForViewAtPoint.js +4 -4
  276. package/src/private/{inspector → devsupport/devmenu/elementinspector}/resolveBoxStyle.js +1 -1
  277. package/src/private/{inspector → devsupport/devmenu/perfmonitor}/PerformanceOverlay.js +6 -5
  278. package/src/private/{specs_DEPRECATED/modules → devsupport/devmenu/specs}/NativeDevMenu.js +2 -2
  279. package/src/private/{debugging → devsupport/rndevtools}/ReactDevToolsSettingsManager.android.js +1 -1
  280. package/src/private/{debugging → devsupport/rndevtools}/ReactDevToolsSettingsManager.ios.js +1 -1
  281. package/src/private/{debugging → devsupport/rndevtools}/ReactDevToolsSettingsManager.windows.js +1 -1
  282. package/src/private/{debugging → devsupport/rndevtools}/setUpFuseboxReactDevToolsDispatcher.js +1 -1
  283. package/src/private/{fusebox → devsupport/rndevtools}/specs/NativeReactDevToolsRuntimeSettingsModule.js +2 -2
  284. package/src/private/{specs_DEPRECATED/modules → devsupport/rndevtools/specs}/NativeReactDevToolsSettingsManager.js +2 -2
  285. package/src/private/featureflags/ReactNativeFeatureFlags.js +82 -80
  286. package/src/private/featureflags/ReactNativeFeatureFlagsBase.js +12 -1
  287. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +17 -13
  288. package/src/private/renderer/errorhandling/ErrorHandlers.js +2 -2
  289. package/src/private/specs_DEPRECATED/modules/NativeAnimatedModule.js +1 -1
  290. package/src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule.js +1 -1
  291. package/src/private/specs_DEPRECATED/modules/NativeSampleTurboModule.js +3 -0
  292. package/src/private/styles/composeStyles.js +12 -5
  293. package/src/private/types/HostComponent.js +1 -1
  294. package/src/private/types/HostInstance.js +67 -1
  295. package/src/private/webapis/dom/nodes/ReactNativeElement.js +2 -5
  296. package/src/private/webapis/dom/nodes/ReadOnlyNode.js +5 -18
  297. package/src/private/webapis/dom/nodes/internals/NodeInternals.js +6 -0
  298. package/src/private/webapis/performance/Performance.js +1 -3
  299. package/src/private/webapis/performance/PerformanceEntry.js +6 -1
  300. package/src/private/webapis/performance/internals/RawPerformanceEntry.js +3 -0
  301. package/src/private/webapis/performance/specs/NativePerformance.js +10 -1
  302. package/src/types/globals.d.ts +42 -0
  303. package/stubs/double-conversion/double-conversion.h +3 -1
  304. package/templates/cpp-app/windows/MyApp/MyApp.vcxproj +4 -0
  305. package/templates/cpp-lib/windows/MyLib/MyLib.vcxproj +4 -0
  306. package/types/index.d.ts +6 -3
  307. package/types/public/ReactNativeTypes.d.ts +2 -2
  308. package/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js +0 -38
  309. package/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js +0 -22
  310. package/Libraries/Blob/FileReader_new.js +0 -231
  311. package/Libraries/Blob/FileReader_old.js +0 -186
  312. package/Libraries/Blob/__mocks__/FileReaderModule.js +0 -20
  313. package/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +0 -32
  314. package/Libraries/Core/__mocks__/ErrorUtils.js +0 -33
  315. package/Libraries/Core/__mocks__/NativeExceptionsManager.js +0 -19
  316. package/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js +0 -49
  317. package/Libraries/Events/CustomEvent.js +0 -32
  318. package/Libraries/Events/EventPolyfill.js +0 -239
  319. package/Libraries/Lists/__flowtests__/FlatList-flowtest.js +0 -118
  320. package/Libraries/Lists/__flowtests__/SectionList-flowtest.js +0 -134
  321. package/Libraries/Network/XMLHttpRequest_new.js +0 -794
  322. package/Libraries/Network/XMLHttpRequest_old.js +0 -701
  323. package/Libraries/NewAppScreen/components/DebugInstructions.js +0 -41
  324. package/Libraries/NewAppScreen/components/DebugInstructions.windows.js +0 -30
  325. package/Libraries/NewAppScreen/components/Header.js +0 -77
  326. package/Libraries/NewAppScreen/components/HermesBadge.js +0 -53
  327. package/Libraries/NewAppScreen/components/LearnMoreLinks.js +0 -148
  328. package/Libraries/NewAppScreen/components/ReloadInstructions.js +0 -39
  329. package/Libraries/NewAppScreen/components/ReloadInstructions.windows.js +0 -31
  330. package/Libraries/NewAppScreen/components/logo.png +0 -0
  331. package/Libraries/NewAppScreen/index.js +0 -25
  332. package/Libraries/StyleSheet/__flowtests__/StyleSheet-flowtest.js +0 -58
  333. package/Libraries/Utilities/__mocks__/BackHandler.js +0 -45
  334. package/Libraries/Utilities/__mocks__/GlobalPerformanceLogger.js +0 -16
  335. package/Libraries/Utilities/__mocks__/PixelRatio.js +0 -25
  336. package/Libraries/WebSocket/WebSocketEvent.js +0 -30
  337. package/Libraries/WebSocket/WebSocket_new.js +0 -325
  338. package/Libraries/WebSocket/WebSocket_old.js +0 -297
  339. package/Libraries/WebSocket/__mocks__/event-target-shim.js +0 -27
  340. package/Libraries/__flowtests__/ReactNativeTypes-flowtest.js +0 -30
  341. package/Libraries/vendor/emitter/__flowtests__/EventEmitter-flowtest.js +0 -81
  342. package/jest/__tests__/setup-test.js +0 -18
  343. package/src/private/components/VScrollViewNativeComponents.js +0 -25
  344. package/src/private/utilities/ensureInstance.js +0 -21
  345. package/src/private/webapis/performance/specs/__mocks__/NativePerformanceMock.js +0 -267
  346. package/types/modules/LaunchScreen.d.ts +0 -18
  347. /package/src/private/{devmenu → devsupport/devmenu}/DevMenu.d.ts +0 -0
  348. /package/src/private/{debugging → devsupport/rndevtools}/FuseboxSessionObserver.js +0 -0
@@ -11,24 +11,31 @@
11
11
  'use strict';
12
12
 
13
13
  import type {ProcessedColorValue} from './processColor';
14
- import type {GradientValue} from './StyleSheetTypes';
14
+ import type {
15
+ BackgroundImageValue,
16
+ RadialGradientPosition,
17
+ RadialGradientShape,
18
+ RadialGradientSize,
19
+ } from './StyleSheetTypes';
15
20
 
16
21
  const processColor = require('./processColor').default;
17
- const DIRECTION_KEYWORD_REGEX =
22
+
23
+ // Linear Gradient
24
+ const LINEAR_GRADIENT_DIRECTION_REGEX =
18
25
  /^to\s+(?:top|bottom|left|right)(?:\s+(?:top|bottom|left|right))?/i;
19
- const ANGLE_UNIT_REGEX = /^([+-]?\d*\.?\d+)(deg|grad|rad|turn)$/i;
26
+ const LINEAR_GRADIENT_ANGLE_UNIT_REGEX =
27
+ /^([+-]?\d*\.?\d+)(deg|grad|rad|turn)$/i;
28
+ const LINEAR_GRADIENT_DEFAULT_DIRECTION: LinearGradientDirection = {
29
+ type: 'angle',
30
+ value: 180,
31
+ };
20
32
 
21
33
  type LinearGradientDirection =
22
34
  | {type: 'angle', value: number}
23
35
  | {type: 'keyword', value: string};
24
36
 
25
- // null color indicate that the transition hint syntax is used. e.g. red, 20%, blue
26
- type ColorStopColor = ProcessedColorValue | null;
27
- // percentage or pixel value
28
- type ColorStopPosition = number | string | null;
29
-
30
- type ParsedGradientValue = {
31
- type: 'linearGradient',
37
+ type LinearGradientBackgroundImage = {
38
+ type: 'linear-gradient',
32
39
  direction: LinearGradientDirection,
33
40
  colorStops: $ReadOnlyArray<{
34
41
  color: ColorStopColor,
@@ -36,261 +43,682 @@ type ParsedGradientValue = {
36
43
  }>,
37
44
  };
38
45
 
39
- const DEFAULT_DIRECTION: LinearGradientDirection = {
40
- type: 'angle',
41
- value: 180,
46
+ // Radial Gradient
47
+ const DEFAULT_RADIAL_SHAPE = 'ellipse';
48
+ const DEFAULT_RADIAL_SIZE = 'farthest-corner';
49
+ // center
50
+ const DEFAULT_RADIAL_POSITION: RadialGradientPosition = {
51
+ top: '50%',
52
+ left: '50%',
53
+ };
54
+
55
+ type RadialGradientBackgroundImage = {
56
+ type: 'radial-gradient',
57
+ shape: RadialGradientShape,
58
+ size: RadialGradientSize,
59
+ position: RadialGradientPosition,
60
+ colorStops: $ReadOnlyArray<{
61
+ color: ColorStopColor,
62
+ position: ColorStopPosition,
63
+ }>,
42
64
  };
43
65
 
66
+ // null color indicate that the transition hint syntax is used. e.g. red, 20%, blue
67
+ type ColorStopColor = ProcessedColorValue | null;
68
+ // percentage or pixel value
69
+ type ColorStopPosition = number | string | null;
70
+
71
+ type ParsedBackgroundImageValue =
72
+ | LinearGradientBackgroundImage
73
+ | RadialGradientBackgroundImage;
74
+
44
75
  export default function processBackgroundImage(
45
- backgroundImage: ?($ReadOnlyArray<GradientValue> | string),
46
- ): $ReadOnlyArray<ParsedGradientValue> {
47
- let result: $ReadOnlyArray<ParsedGradientValue> = [];
76
+ backgroundImage: ?($ReadOnlyArray<BackgroundImageValue> | string),
77
+ ): $ReadOnlyArray<ParsedBackgroundImageValue> {
78
+ let result: $ReadOnlyArray<ParsedBackgroundImageValue> = [];
48
79
  if (backgroundImage == null) {
49
80
  return result;
50
81
  }
51
82
 
52
83
  if (typeof backgroundImage === 'string') {
53
- result = parseCSSLinearGradient(backgroundImage.replace(/\n/g, ' '));
84
+ result = parseBackgroundImageCSSString(backgroundImage.replace(/\n/g, ' '));
54
85
  } else if (Array.isArray(backgroundImage)) {
55
86
  for (const bgImage of backgroundImage) {
56
- const processedColorStops: Array<{
57
- color: ColorStopColor,
58
- position: ColorStopPosition,
59
- }> = [];
60
- for (let index = 0; index < bgImage.colorStops.length; index++) {
61
- const colorStop = bgImage.colorStops[index];
62
- const positions = colorStop.positions;
63
- // Color transition hint syntax (red, 20%, blue)
64
- if (
65
- colorStop.color == null &&
66
- Array.isArray(positions) &&
67
- positions.length === 1
68
- ) {
69
- const position = positions[0];
70
- if (
71
- typeof position === 'number' ||
72
- (typeof position === 'string' && position.endsWith('%'))
73
- ) {
74
- processedColorStops.push({
75
- color: null,
76
- position,
77
- });
78
- } else {
79
- // If a position is invalid, return an empty array and do not apply gradient. Same as web.
80
- return [];
81
- }
82
- } else {
83
- const processedColor = processColor(colorStop.color);
84
- if (processedColor == null) {
85
- // If a color is invalid, return an empty array and do not apply gradient. Same as web.
86
- return [];
87
- }
88
- if (positions != null && positions.length > 0) {
89
- for (const position of positions) {
90
- if (
91
- typeof position === 'number' ||
92
- (typeof position === 'string' && position.endsWith('%'))
93
- ) {
94
- processedColorStops.push({
95
- color: processedColor,
96
- position,
97
- });
98
- } else {
99
- // If a position is invalid, return an empty array and do not apply gradient. Same as web.
100
- return [];
101
- }
87
+ const processedColorStops = processColorStops(bgImage);
88
+ if (processedColorStops == null) {
89
+ // If a color stop is invalid, return an empty array and do not apply any gradient. Same as web.
90
+ return [];
91
+ }
92
+
93
+ if (bgImage.type === 'linear-gradient') {
94
+ let direction: LinearGradientDirection =
95
+ LINEAR_GRADIENT_DEFAULT_DIRECTION;
96
+ const bgDirection =
97
+ bgImage.direction != null ? bgImage.direction.toLowerCase() : null;
98
+
99
+ if (bgDirection != null) {
100
+ if (LINEAR_GRADIENT_ANGLE_UNIT_REGEX.test(bgDirection)) {
101
+ const parsedAngle = getAngleInDegrees(bgDirection);
102
+ if (parsedAngle != null) {
103
+ direction = {
104
+ type: 'angle',
105
+ value: parsedAngle,
106
+ };
107
+ } else {
108
+ // If an angle is invalid, return an empty array and do not apply any gradient. Same as web.
109
+ return [];
110
+ }
111
+ } else if (LINEAR_GRADIENT_DIRECTION_REGEX.test(bgDirection)) {
112
+ const parsedDirection = getDirectionForKeyword(bgDirection);
113
+ if (parsedDirection != null) {
114
+ direction = parsedDirection;
115
+ } else {
116
+ // If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
117
+ return [];
102
118
  }
103
119
  } else {
104
- processedColorStops.push({
105
- color: processedColor,
106
- position: null,
107
- });
120
+ // If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
121
+ return [];
108
122
  }
109
123
  }
110
- }
111
124
 
112
- let direction: LinearGradientDirection = DEFAULT_DIRECTION;
113
- const bgDirection =
114
- bgImage.direction != null ? bgImage.direction.toLowerCase() : null;
115
-
116
- if (bgDirection != null) {
117
- if (ANGLE_UNIT_REGEX.test(bgDirection)) {
118
- const parsedAngle = getAngleInDegrees(bgDirection);
119
- if (parsedAngle != null) {
120
- direction = {
121
- type: 'angle',
122
- value: parsedAngle,
123
- };
125
+ result = result.concat({
126
+ type: 'linear-gradient',
127
+ direction,
128
+ colorStops: processedColorStops,
129
+ });
130
+ } else if (bgImage.type === 'radial-gradient') {
131
+ let shape: RadialGradientShape = DEFAULT_RADIAL_SHAPE;
132
+ let size: RadialGradientSize = DEFAULT_RADIAL_SIZE;
133
+ let position: RadialGradientPosition = {...DEFAULT_RADIAL_POSITION};
134
+
135
+ if (bgImage.shape != null) {
136
+ if (bgImage.shape === 'circle' || bgImage.shape === 'ellipse') {
137
+ shape = bgImage.shape;
124
138
  } else {
125
- // If an angle is invalid, return an empty array and do not apply any gradient. Same as web.
139
+ // If the shape is invalid, return an empty array and do not apply any gradient. Same as web.
126
140
  return [];
127
141
  }
128
- } else if (DIRECTION_KEYWORD_REGEX.test(bgDirection)) {
129
- const parsedDirection = getDirectionForKeyword(bgDirection);
130
- if (parsedDirection != null) {
131
- direction = parsedDirection;
142
+ }
143
+
144
+ if (bgImage.size != null) {
145
+ if (
146
+ typeof bgImage.size === 'string' &&
147
+ (bgImage.size === 'closest-side' ||
148
+ bgImage.size === 'closest-corner' ||
149
+ bgImage.size === 'farthest-side' ||
150
+ bgImage.size === 'farthest-corner')
151
+ ) {
152
+ size = bgImage.size;
153
+ } else if (
154
+ typeof bgImage.size === 'object' &&
155
+ bgImage.size.x != null &&
156
+ bgImage.size.y != null
157
+ ) {
158
+ size = {
159
+ x: bgImage.size.x,
160
+ y: bgImage.size.y,
161
+ };
132
162
  } else {
133
- // If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
163
+ // If the size is invalid, return an empty array and do not apply any gradient. Same as web.
134
164
  return [];
135
165
  }
136
- } else {
137
- // If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
138
- return [];
139
166
  }
140
- }
141
167
 
142
- result = result.concat({
143
- type: 'linearGradient',
144
- direction,
145
- colorStops: processedColorStops,
146
- });
168
+ if (bgImage.position != null) {
169
+ position = bgImage.position;
170
+ }
171
+
172
+ result = result.concat({
173
+ type: 'radial-gradient',
174
+ shape,
175
+ size,
176
+ position,
177
+ colorStops: processedColorStops,
178
+ });
179
+ }
147
180
  }
148
181
  }
149
182
 
150
183
  return result;
151
184
  }
152
185
 
153
- function parseCSSLinearGradient(
154
- cssString: string,
155
- ): $ReadOnlyArray<ParsedGradientValue> {
156
- const gradients = [];
157
- let match;
158
-
159
- // matches one or more linear-gradient functions in CSS
160
- const linearGradientRegex = /linear-gradient\s*\(((?:\([^)]*\)|[^())])*)\)/gi;
161
-
162
- while ((match = linearGradientRegex.exec(cssString))) {
163
- const gradientContent = match[1];
164
- const parts = gradientContent.split(',');
165
- let direction: LinearGradientDirection = DEFAULT_DIRECTION;
166
- const trimmedDirection = parts[0].trim().toLowerCase();
167
-
168
- if (ANGLE_UNIT_REGEX.test(trimmedDirection)) {
169
- const parsedAngle = getAngleInDegrees(trimmedDirection);
170
- if (parsedAngle != null) {
171
- direction = {
172
- type: 'angle',
173
- value: parsedAngle,
174
- };
175
- parts.shift();
186
+ function processColorStops(bgImage: BackgroundImageValue): $ReadOnlyArray<{
187
+ color: ColorStopColor,
188
+ position: ColorStopPosition,
189
+ }> | null {
190
+ const processedColorStops: Array<{
191
+ color: ColorStopColor,
192
+ position: ColorStopPosition,
193
+ }> = [];
194
+
195
+ for (let index = 0; index < bgImage.colorStops.length; index++) {
196
+ const colorStop = bgImage.colorStops[index];
197
+ const positions = colorStop.positions;
198
+ // Color transition hint syntax (red, 20%, blue)
199
+ if (
200
+ colorStop.color == null &&
201
+ Array.isArray(positions) &&
202
+ positions.length === 1
203
+ ) {
204
+ const position = positions[0];
205
+ if (
206
+ typeof position === 'number' ||
207
+ (typeof position === 'string' && position.endsWith('%'))
208
+ ) {
209
+ processedColorStops.push({
210
+ color: null,
211
+ position,
212
+ });
176
213
  } else {
177
- // If an angle is invalid, return an empty array and do not apply any gradient. Same as web.
178
- return [];
214
+ // If a position is invalid, return null and do not apply gradient. Same as web.
215
+ return null;
179
216
  }
180
- } else if (DIRECTION_KEYWORD_REGEX.test(trimmedDirection)) {
181
- const parsedDirection = getDirectionForKeyword(trimmedDirection);
182
- if (parsedDirection != null) {
183
- direction = parsedDirection;
184
- parts.shift();
217
+ } else {
218
+ const processedColor = processColor(colorStop.color);
219
+ if (processedColor == null) {
220
+ // If a color is invalid, return null and do not apply gradient. Same as web.
221
+ return null;
222
+ }
223
+ if (positions != null && positions.length > 0) {
224
+ for (const position of positions) {
225
+ if (
226
+ typeof position === 'number' ||
227
+ (typeof position === 'string' && position.endsWith('%'))
228
+ ) {
229
+ processedColorStops.push({
230
+ color: processedColor,
231
+ position,
232
+ });
233
+ } else {
234
+ // If a position is invalid, return null and do not apply gradient. Same as web.
235
+ return null;
236
+ }
237
+ }
185
238
  } else {
186
- // If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
187
- return [];
239
+ processedColorStops.push({
240
+ color: processedColor,
241
+ position: null,
242
+ });
188
243
  }
189
244
  }
245
+ }
190
246
 
191
- const colorStopsString = parts.join(',');
192
- const colorStops = [];
193
- // split by comma, but not if it's inside a parentheses. e.g. red, rgba(0, 0, 0, 0.5), green => ["red", "rgba(0, 0, 0, 0.5)", "green"]
194
- const stops = colorStopsString.split(/,(?![^(]*\))/);
195
- let prevStop = null;
196
- for (let i = 0; i < stops.length; i++) {
197
- const stop = stops[i];
198
- const trimmedStop = stop.trim().toLowerCase();
199
- // Match function like pattern or single words
200
- const colorStopParts = trimmedStop.match(/\S+\([^)]*\)|\S+/g);
201
- if (colorStopParts == null) {
202
- // If a color stop is invalid, return an empty array and do not apply any gradient. Same as web.
203
- return [];
247
+ return processedColorStops;
248
+ }
249
+
250
+ function parseBackgroundImageCSSString(
251
+ cssString: string,
252
+ ): $ReadOnlyArray<ParsedBackgroundImageValue> {
253
+ const gradients = [];
254
+ const bgImageStrings = splitGradients(cssString);
255
+
256
+ for (const bgImageString of bgImageStrings) {
257
+ const bgImage = bgImageString.toLowerCase();
258
+ const gradientRegex = /^(linear|radial)-gradient\(((?:\([^)]*\)|[^()])*)\)/;
259
+
260
+ const match = gradientRegex.exec(bgImage);
261
+ if (match) {
262
+ const [, type, gradientContent] = match;
263
+ const isRadial = type.toLowerCase() === 'radial';
264
+ const gradient = isRadial
265
+ ? parseRadialGradientCSSString(gradientContent)
266
+ : parseLinearGradientCSSString(gradientContent);
267
+
268
+ if (gradient != null) {
269
+ gradients.push(gradient);
204
270
  }
205
- // Case 1: [color, position, position]
206
- if (colorStopParts.length === 3) {
207
- const color = colorStopParts[0];
208
- const position1 = getPositionFromCSSValue(colorStopParts[1]);
209
- const position2 = getPositionFromCSSValue(colorStopParts[2]);
210
- const processedColor = processColor(color);
211
- if (processedColor == null) {
212
- // If a color is invalid, return an empty array and do not apply any gradient. Same as web.
213
- return [];
214
- }
271
+ }
272
+ }
273
+ return gradients;
274
+ }
275
+
276
+ function parseRadialGradientCSSString(
277
+ gradientContent: string,
278
+ ): RadialGradientBackgroundImage | null {
279
+ let shape: RadialGradientShape = DEFAULT_RADIAL_SHAPE;
280
+ let size: RadialGradientSize = DEFAULT_RADIAL_SIZE;
281
+ let position: RadialGradientPosition = {...DEFAULT_RADIAL_POSITION};
282
+
283
+ // split the content by commas, but not if inside parentheses (for color values)
284
+ const parts = gradientContent.split(/,(?![^(]*\))/);
285
+ // first part may contain shape, size, and position
286
+ // [ <radial-shape> || <radial-size> ]? [ at <position> ]?
287
+ const firstPartStr = parts[0].trim();
288
+ const remainingParts = [...parts];
289
+ let hasShapeSizeOrPositionString = false;
290
+ let hasExplicitSingleSize = false;
291
+ let hasExplicitShape = false;
292
+ const firstPartTokens = firstPartStr.split(/\s+/);
293
+
294
+ // firstPartTokens is the shape, size, and position
295
+ while (firstPartTokens.length > 0) {
296
+ let token = firstPartTokens.shift();
297
+ if (token == null) {
298
+ continue;
299
+ }
300
+ let tokenTrimmed = token.toLowerCase().trim();
215
301
 
216
- if (position1 == null || position2 == null) {
217
- // If a position is invalid, return an empty array and do not apply any gradient. Same as web.
218
- return [];
302
+ if (tokenTrimmed === 'circle' || tokenTrimmed === 'ellipse') {
303
+ shape = tokenTrimmed === 'circle' ? 'circle' : 'ellipse';
304
+ hasShapeSizeOrPositionString = true;
305
+ hasExplicitShape = true;
306
+ } else if (
307
+ tokenTrimmed === 'closest-corner' ||
308
+ tokenTrimmed === 'farthest-corner' ||
309
+ tokenTrimmed === 'closest-side' ||
310
+ tokenTrimmed === 'farthest-side'
311
+ ) {
312
+ size = tokenTrimmed;
313
+ hasShapeSizeOrPositionString = true;
314
+ } else if (tokenTrimmed.endsWith('px') || tokenTrimmed.endsWith('%')) {
315
+ let sizeX = getPositionFromCSSValue(tokenTrimmed);
316
+ if (sizeX == null) {
317
+ // If a size is invalid, return null and do not apply any gradient. Same as web.
318
+ return null;
319
+ }
320
+ if (typeof sizeX === 'number' && sizeX < 0) {
321
+ // If a size is invalid, return null and do not apply any gradient. Same as web.
322
+ return null;
323
+ }
324
+ hasShapeSizeOrPositionString = true;
325
+ size = {x: sizeX, y: sizeX};
326
+ token = firstPartTokens.shift();
327
+ if (token == null) {
328
+ hasExplicitSingleSize = true;
329
+ continue;
330
+ }
331
+ tokenTrimmed = token.toLowerCase().trim();
332
+ if (tokenTrimmed.endsWith('px') || tokenTrimmed.endsWith('%')) {
333
+ const sizeY = getPositionFromCSSValue(tokenTrimmed);
334
+ if (sizeY == null) {
335
+ // If a size is invalid, return null and do not apply any gradient. Same as web.
336
+ return null;
337
+ }
338
+ if (typeof sizeY === 'number' && sizeY < 0) {
339
+ // If a size is invalid, return null and do not apply any gradient. Same as web.
340
+ return null;
219
341
  }
342
+ size = {x: sizeX, y: sizeY};
343
+ } else {
344
+ hasExplicitSingleSize = true;
345
+ }
346
+ } else if (tokenTrimmed === 'at') {
347
+ let top: string | number;
348
+ let left: string | number;
349
+ let right: string | number;
350
+ let bottom: string | number;
351
+ hasShapeSizeOrPositionString = true;
220
352
 
221
- colorStops.push({
222
- color: processedColor,
223
- position: position1,
224
- });
225
- colorStops.push({
226
- color: processedColor,
227
- position: position2,
228
- });
353
+ if (firstPartTokens.length === 0) {
354
+ // If 'at' is not followed by a position, return null and do not apply any gradient. Same as web.
355
+ return null;
229
356
  }
230
- // Case 2: [color, position]
231
- else if (colorStopParts.length === 2) {
232
- const color = colorStopParts[0];
233
- const position = getPositionFromCSSValue(colorStopParts[1]);
234
- const processedColor = processColor(color);
235
- if (processedColor == null) {
236
- // If a color is invalid, return an empty array and do not apply any gradient. Same as web.
237
- return [];
357
+
358
+ // 1. [ left | center | right | top | bottom | <length-percentage> ]
359
+ if (firstPartTokens.length === 1) {
360
+ token = firstPartTokens.shift();
361
+ if (token == null) {
362
+ // If 'at' is not followed by a position, return null and do not apply any gradient. Same as web.
363
+ return null;
238
364
  }
239
- if (position == null) {
240
- // If a position is invalid, return an empty array and do not apply any gradient. Same as web.
241
- return [];
365
+ tokenTrimmed = token.toLowerCase().trim();
366
+ if (tokenTrimmed === 'left') {
367
+ left = '0%';
368
+ top = '50%';
369
+ } else if (tokenTrimmed === 'center') {
370
+ left = '50%';
371
+ top = '50%';
372
+ } else if (tokenTrimmed === 'right') {
373
+ left = '100%';
374
+ top = '50%';
375
+ } else if (tokenTrimmed === 'top') {
376
+ left = '50%';
377
+ top = '0%';
378
+ } else if (tokenTrimmed === 'bottom') {
379
+ left = '50%';
380
+ top = '100%';
381
+ } else if (tokenTrimmed.endsWith('px') || tokenTrimmed.endsWith('%')) {
382
+ const value = getPositionFromCSSValue(tokenTrimmed);
383
+ if (value == null) {
384
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
385
+ return null;
386
+ }
387
+ left = value;
388
+ top = '50%';
242
389
  }
243
- colorStops.push({
244
- color: processedColor,
245
- position,
246
- });
247
390
  }
248
- // Case 3: [color]
249
- // Case 4: [position] => transition hint syntax
250
- else if (colorStopParts.length === 1) {
251
- const position = getPositionFromCSSValue(colorStopParts[0]);
252
- if (position != null) {
253
- // handle invalid transition hint syntax. transition hint syntax must have color before and after the position. e.g. red, 20%, blue
254
- if (
255
- (prevStop != null &&
256
- prevStop.length === 1 &&
257
- getPositionFromCSSValue(prevStop[0]) != null) ||
258
- i === stops.length - 1 ||
259
- i === 0
260
- ) {
261
- // If the last stop is a transition hint syntax, return an empty array and do not apply any gradient. Same as web.
262
- return [];
391
+
392
+ if (firstPartTokens.length === 2) {
393
+ const t1 = firstPartTokens.shift();
394
+ const t2 = firstPartTokens.shift();
395
+ if (t1 == null || t2 == null) {
396
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
397
+ return null;
398
+ }
399
+
400
+ const token1 = t1.toLowerCase().trim();
401
+ const token2 = t2.toLowerCase().trim();
402
+
403
+ // 2. [ left | center | right ] && [ top | center | bottom ]
404
+ const horizontalPositions = ['left', 'center', 'right'];
405
+ const verticalPositions = ['top', 'center', 'bottom'];
406
+
407
+ if (
408
+ horizontalPositions.includes(token1) &&
409
+ verticalPositions.includes(token2)
410
+ ) {
411
+ left =
412
+ token1 === 'left' ? '0%' : token1 === 'center' ? '50%' : '100%';
413
+ top = token2 === 'top' ? '0%' : token2 === 'center' ? '50%' : '100%';
414
+ } else if (
415
+ verticalPositions.includes(token1) &&
416
+ horizontalPositions.includes(token2)
417
+ ) {
418
+ left =
419
+ token2 === 'left' ? '0%' : token2 === 'center' ? '50%' : '100%';
420
+ top = token1 === 'top' ? '0%' : token1 === 'center' ? '50%' : '100%';
421
+ }
422
+ // 3. [ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ]
423
+ else {
424
+ if (token1 === 'left') {
425
+ left = '0%';
426
+ } else if (token1 === 'center') {
427
+ left = '50%';
428
+ } else if (token1 === 'right') {
429
+ left = '100%';
430
+ } else if (token1.endsWith('px') || token1.endsWith('%')) {
431
+ const value = getPositionFromCSSValue(token1);
432
+ if (value == null) {
433
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
434
+ return null;
435
+ }
436
+ left = value;
437
+ } else {
438
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
439
+ return null;
263
440
  }
264
- colorStops.push({
265
- color: null,
266
- position,
267
- });
268
- } else {
269
- const processedColor = processColor(colorStopParts[0]);
270
- if (processedColor == null) {
271
- // If a color is invalid, return an empty array and do not apply any gradient. Same as web.
272
- return [];
441
+
442
+ if (token2 === 'top') {
443
+ top = '0%';
444
+ } else if (token2 === 'center') {
445
+ top = '50%';
446
+ } else if (token2 === 'bottom') {
447
+ top = '100%';
448
+ } else if (token2.endsWith('px') || token2.endsWith('%')) {
449
+ const value = getPositionFromCSSValue(token2);
450
+ if (value == null) {
451
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
452
+ return null;
453
+ }
454
+ top = value;
455
+ } else {
456
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
457
+ return null;
273
458
  }
274
- colorStops.push({
275
- color: processedColor,
276
- position: null,
277
- });
278
459
  }
460
+ }
461
+
462
+ // 4. [ [ left | right ] <length-percentage> ] && [ [ top | bottom ] <length-percentage> ]
463
+ if (firstPartTokens.length === 4) {
464
+ const t1 = firstPartTokens.shift();
465
+ const t2 = firstPartTokens.shift();
466
+ const t3 = firstPartTokens.shift();
467
+ const t4 = firstPartTokens.shift();
468
+
469
+ if (t1 == null || t2 == null || t3 == null || t4 == null) {
470
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
471
+ return null;
472
+ }
473
+ const token1 = t1.toLowerCase().trim();
474
+ const token2 = t2.toLowerCase().trim();
475
+ const token3 = t3.toLowerCase().trim();
476
+ const token4 = t4.toLowerCase().trim();
477
+ const keyword1 = token1;
478
+ const value1 = getPositionFromCSSValue(token2);
479
+ const keyword2 = token3;
480
+ const value2 = getPositionFromCSSValue(token4);
481
+ if (value1 == null || value2 == null) {
482
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
483
+ return null;
484
+ }
485
+
486
+ if (keyword1 === 'left') {
487
+ left = value1;
488
+ } else if (keyword1 === 'right') {
489
+ right = value1;
490
+ } else if (keyword1 === 'top') {
491
+ top = value1;
492
+ } else if (keyword1 === 'bottom') {
493
+ bottom = value1;
494
+ } else {
495
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
496
+ return null;
497
+ }
498
+
499
+ if (keyword2 === 'left') {
500
+ left = value2;
501
+ } else if (keyword2 === 'right') {
502
+ right = value2;
503
+ } else if (keyword2 === 'top') {
504
+ top = value2;
505
+ } else if (keyword2 === 'bottom') {
506
+ bottom = value2;
507
+ } else {
508
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
509
+ return null;
510
+ }
511
+ }
512
+
513
+ if (top != null && left != null) {
514
+ position = {
515
+ top,
516
+ left,
517
+ };
518
+ } else if (bottom != null && right != null) {
519
+ position = {
520
+ bottom,
521
+ right,
522
+ };
523
+ } else if (top != null && right != null) {
524
+ position = {
525
+ top,
526
+ right,
527
+ };
528
+ } else if (bottom != null && left != null) {
529
+ position = {
530
+ bottom,
531
+ left,
532
+ };
279
533
  } else {
280
- // If a color stop is invalid, return an empty array and do not apply any gradient. Same as web.
281
- return [];
534
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
535
+ return null;
282
536
  }
283
- prevStop = colorStopParts;
537
+ // 'at' comes at the end of first part of radial gradient syntax;
538
+ break;
284
539
  }
285
540
 
286
- gradients.push({
287
- type: 'linearGradient',
288
- direction,
289
- colorStops,
290
- });
541
+ // if there is no shape, size, or position string found in first token, break
542
+ // if might be a color stop
543
+ if (!hasShapeSizeOrPositionString) {
544
+ break;
545
+ }
291
546
  }
292
547
 
293
- return gradients;
548
+ if (hasShapeSizeOrPositionString) {
549
+ remainingParts.shift();
550
+
551
+ if (!hasExplicitShape && hasExplicitSingleSize) {
552
+ shape = 'circle';
553
+ }
554
+
555
+ if (hasExplicitSingleSize && hasExplicitShape && shape === 'ellipse') {
556
+ // If a single size is explicitly set and the shape is an ellipse, return null and do not apply any gradient. Same as web.
557
+ return null;
558
+ }
559
+ }
560
+
561
+ const colorStops = parseColorStopsCSSString(remainingParts);
562
+ if (colorStops == null) {
563
+ // If color stops are invalid, return null and do not apply any gradient. Same as web.
564
+ return null;
565
+ }
566
+
567
+ return {
568
+ type: 'radial-gradient',
569
+ shape,
570
+ size,
571
+ position,
572
+ colorStops,
573
+ };
574
+ }
575
+
576
+ function parseLinearGradientCSSString(
577
+ gradientContent: string,
578
+ ): LinearGradientBackgroundImage | null {
579
+ const parts = gradientContent.split(',');
580
+ let direction: LinearGradientDirection = LINEAR_GRADIENT_DEFAULT_DIRECTION;
581
+ const trimmedDirection = parts[0].trim().toLowerCase();
582
+
583
+ if (LINEAR_GRADIENT_ANGLE_UNIT_REGEX.test(trimmedDirection)) {
584
+ const parsedAngle = getAngleInDegrees(trimmedDirection);
585
+ if (parsedAngle != null) {
586
+ direction = {
587
+ type: 'angle',
588
+ value: parsedAngle,
589
+ };
590
+ parts.shift();
591
+ } else {
592
+ // If an angle is invalid, return null and do not apply any gradient. Same as web.
593
+ return null;
594
+ }
595
+ } else if (LINEAR_GRADIENT_DIRECTION_REGEX.test(trimmedDirection)) {
596
+ const parsedDirection = getDirectionForKeyword(trimmedDirection);
597
+ if (parsedDirection != null) {
598
+ direction = parsedDirection;
599
+ parts.shift();
600
+ } else {
601
+ // If a direction is invalid, return null and do not apply any gradient. Same as web.
602
+ return null;
603
+ }
604
+ }
605
+
606
+ const colorStops = parseColorStopsCSSString(parts);
607
+ if (colorStops == null) {
608
+ // If a color stop is invalid, return null and do not apply any gradient. Same as web.
609
+ return null;
610
+ }
611
+
612
+ return {
613
+ type: 'linear-gradient',
614
+ direction,
615
+ colorStops,
616
+ };
617
+ }
618
+
619
+ function parseColorStopsCSSString(parts: Array<string>): Array<{
620
+ color: ColorStopColor,
621
+ position: ColorStopPosition,
622
+ }> | null {
623
+ const colorStopsString = parts.join(',');
624
+ const colorStops: Array<{
625
+ color: ColorStopColor,
626
+ position: ColorStopPosition,
627
+ }> = [];
628
+ // split by comma, but not if it's inside a parentheses. e.g. red, rgba(0, 0, 0, 0.5), green => ["red", "rgba(0, 0, 0, 0.5)", "green"]
629
+ const stops = colorStopsString.split(/,(?![^(]*\))/);
630
+ let prevStop = null;
631
+ for (let i = 0; i < stops.length; i++) {
632
+ const stop = stops[i];
633
+ const trimmedStop = stop.trim().toLowerCase();
634
+ // Match function like pattern or single words
635
+ const colorStopParts = trimmedStop.match(/\S+\([^)]*\)|\S+/g);
636
+ if (colorStopParts == null) {
637
+ // If a color stop is invalid, return null and do not apply any gradient. Same as web.
638
+ return null;
639
+ }
640
+ // Case 1: [color, position, position]
641
+ if (colorStopParts.length === 3) {
642
+ const color = colorStopParts[0];
643
+ const position1 = getPositionFromCSSValue(colorStopParts[1]);
644
+ const position2 = getPositionFromCSSValue(colorStopParts[2]);
645
+ const processedColor = processColor(color);
646
+ if (processedColor == null) {
647
+ // If a color is invalid, return null and do not apply any gradient. Same as web.
648
+ return null;
649
+ }
650
+
651
+ if (position1 == null || position2 == null) {
652
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
653
+ return null;
654
+ }
655
+
656
+ colorStops.push({
657
+ color: processedColor,
658
+ position: position1,
659
+ });
660
+ colorStops.push({
661
+ color: processedColor,
662
+ position: position2,
663
+ });
664
+ }
665
+ // Case 2: [color, position]
666
+ else if (colorStopParts.length === 2) {
667
+ const color = colorStopParts[0];
668
+ const position = getPositionFromCSSValue(colorStopParts[1]);
669
+ const processedColor = processColor(color);
670
+ if (processedColor == null) {
671
+ // If a color is invalid, return null and do not apply any gradient. Same as web.
672
+ return null;
673
+ }
674
+ if (position == null) {
675
+ // If a position is invalid, return null and do not apply any gradient. Same as web.
676
+ return null;
677
+ }
678
+ colorStops.push({
679
+ color: processedColor,
680
+ position,
681
+ });
682
+ }
683
+ // Case 3: [color]
684
+ // Case 4: [position] => transition hint syntax
685
+ else if (colorStopParts.length === 1) {
686
+ const position = getPositionFromCSSValue(colorStopParts[0]);
687
+ if (position != null) {
688
+ // handle invalid transition hint syntax. transition hint syntax must have color before and after the position. e.g. red, 20%, blue
689
+ if (
690
+ (prevStop != null &&
691
+ prevStop.length === 1 &&
692
+ getPositionFromCSSValue(prevStop[0]) != null) ||
693
+ i === stops.length - 1 ||
694
+ i === 0
695
+ ) {
696
+ // If the last stop is a transition hint syntax, return null and do not apply any gradient. Same as web.
697
+ return null;
698
+ }
699
+ colorStops.push({
700
+ color: null,
701
+ position,
702
+ });
703
+ } else {
704
+ const processedColor = processColor(colorStopParts[0]);
705
+ if (processedColor == null) {
706
+ // If a color is invalid, return null and do not apply any gradient. Same as web.
707
+ return null;
708
+ }
709
+ colorStops.push({
710
+ color: processedColor,
711
+ position: null,
712
+ });
713
+ }
714
+ } else {
715
+ // If a color stop is invalid, return null and do not apply any gradient. Same as web.
716
+ return null;
717
+ }
718
+ prevStop = colorStopParts;
719
+ }
720
+
721
+ return colorStops;
294
722
  }
295
723
 
296
724
  function getDirectionForKeyword(direction?: string): ?LinearGradientDirection {
@@ -330,7 +758,7 @@ function getAngleInDegrees(angle?: string): ?number {
330
758
  if (angle == null) {
331
759
  return null;
332
760
  }
333
- const match = angle.match(ANGLE_UNIT_REGEX);
761
+ const match = angle.match(LINEAR_GRADIENT_ANGLE_UNIT_REGEX);
334
762
  if (!match) {
335
763
  return null;
336
764
  }
@@ -361,3 +789,31 @@ function getPositionFromCSSValue(position: string) {
361
789
  return position;
362
790
  }
363
791
  }
792
+
793
+ function splitGradients(input: string) {
794
+ const result = [];
795
+ let current = '';
796
+ let depth = 0;
797
+
798
+ for (let i = 0; i < input.length; i++) {
799
+ const char = input[i];
800
+
801
+ if (char === '(') {
802
+ depth++;
803
+ } else if (char === ')') {
804
+ depth--;
805
+ } else if (char === ',' && depth === 0) {
806
+ result.push(current.trim());
807
+ current = '';
808
+ continue;
809
+ }
810
+
811
+ current += char;
812
+ }
813
+
814
+ if (current.trim() !== '') {
815
+ result.push(current.trim());
816
+ }
817
+
818
+ return result;
819
+ }