react-native 0.86.0-rc.1 → 0.86.0-rc.2

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 (23) hide show
  1. package/Libraries/Components/Pressable/Pressable.d.ts +1 -0
  2. package/Libraries/Components/Pressable/useAndroidRippleForView.js +7 -8
  3. package/Libraries/Components/Touchable/TouchableNativeFeedback.js +6 -10
  4. package/Libraries/Components/View/ViewPropTypes.js +3 -1
  5. package/Libraries/Core/ReactNativeVersion.js +1 -1
  6. package/React/Base/RCTVersion.m +1 -1
  7. package/ReactAndroid/api/ReactAndroid.api +1 -0
  8. package/ReactAndroid/gradle.properties +1 -1
  9. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
  10. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.kt +59 -20
  11. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt +30 -0
  12. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +2 -7
  13. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  14. package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp +19 -2
  15. package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/NativeDrawable.h +47 -16
  16. package/package.json +9 -9
  17. package/scripts/cocoapods/rncore.rb +65 -11
  18. package/scripts/cocoapods/rndependencies.rb +65 -11
  19. package/scripts/cocoapods/utils.rb +52 -0
  20. package/sdks/hermes-engine/hermes-utils.rb +92 -5
  21. package/types_generated/Libraries/Components/Pressable/useAndroidRippleForView.d.ts +5 -2
  22. package/types_generated/Libraries/Components/Touchable/TouchableNativeFeedback.d.ts +8 -6
  23. package/types_generated/Libraries/Components/View/ViewPropTypes.d.ts +4 -2
@@ -30,6 +30,7 @@ export interface PressableAndroidRippleConfig {
30
30
  borderless?: null | boolean | undefined;
31
31
  radius?: null | number | undefined;
32
32
  foreground?: null | boolean | undefined;
33
+ alpha?: null | number | undefined;
33
34
  }
34
35
 
35
36
  export interface PressableProps
@@ -8,6 +8,7 @@
8
8
  * @format
9
9
  */
10
10
 
11
+ import type {ProcessedColorValue} from '../../StyleSheet/processColor';
11
12
  import type {ColorValue} from '../../StyleSheet/StyleSheet';
12
13
  import type {GestureResponderEvent} from '../../Types/CoreEventTypes';
13
14
 
@@ -15,15 +16,15 @@ import processColor from '../../StyleSheet/processColor';
15
16
  import Platform from '../../Utilities/Platform';
16
17
  import View from '../View/View';
17
18
  import {Commands} from '../View/ViewNativeComponent';
18
- import invariant from 'invariant';
19
19
  import * as React from 'react';
20
20
  import {useMemo} from 'react';
21
21
 
22
22
  type NativeBackgroundProp = Readonly<{
23
23
  type: 'RippleAndroid',
24
- color: ?number,
24
+ color: ?ProcessedColorValue,
25
25
  borderless: boolean,
26
26
  rippleRadius: ?number,
27
+ alpha: ?number,
27
28
  }>;
28
29
 
29
30
  export type PressableAndroidRippleConfig = {
@@ -31,6 +32,7 @@ export type PressableAndroidRippleConfig = {
31
32
  borderless?: boolean,
32
33
  radius?: number,
33
34
  foreground?: boolean,
35
+ alpha?: number,
34
36
  };
35
37
 
36
38
  /**
@@ -48,7 +50,7 @@ export default function useAndroidRippleForView(
48
50
  | Readonly<{nativeBackgroundAndroid: NativeBackgroundProp}>
49
51
  | Readonly<{nativeForegroundAndroid: NativeBackgroundProp}>,
50
52
  }> {
51
- const {color, borderless, radius, foreground} = rippleConfig ?? {};
53
+ const {color, borderless, radius, foreground, alpha} = rippleConfig ?? {};
52
54
 
53
55
  return useMemo(() => {
54
56
  if (
@@ -56,16 +58,13 @@ export default function useAndroidRippleForView(
56
58
  (color != null || borderless != null || radius != null)
57
59
  ) {
58
60
  const processedColor = processColor(color);
59
- invariant(
60
- processedColor == null || typeof processedColor === 'number',
61
- 'Unexpected color given for Ripple color',
62
- );
63
61
 
64
62
  const nativeRippleValue = {
65
63
  type: 'RippleAndroid',
66
64
  color: processedColor,
67
65
  borderless: borderless === true,
68
66
  rippleRadius: radius,
67
+ alpha: alpha ?? null,
69
68
  };
70
69
 
71
70
  return {
@@ -105,5 +104,5 @@ export default function useAndroidRippleForView(
105
104
  };
106
105
  }
107
106
  return null;
108
- }, [borderless, color, foreground, radius, viewRef]);
107
+ }, [alpha, borderless, color, foreground, radius, viewRef]);
109
108
  }
@@ -8,6 +8,8 @@
8
8
  * @format
9
9
  */
10
10
 
11
+ import type {ProcessedColorValue} from '../../StyleSheet/processColor';
12
+ import type {ColorValue} from '../../StyleSheet/StyleSheet';
11
13
  import type {GestureResponderEvent} from '../../Types/CoreEventTypes';
12
14
  import type {TouchableWithoutFeedbackProps} from './TouchableWithoutFeedback';
13
15
 
@@ -20,7 +22,6 @@ import {findHostInstance_DEPRECATED} from '../../ReactNative/RendererProxy';
20
22
  import processColor from '../../StyleSheet/processColor';
21
23
  import Platform from '../../Utilities/Platform';
22
24
  import {Commands} from '../View/ViewNativeComponent';
23
- import invariant from 'invariant';
24
25
  import * as React from 'react';
25
26
  import {cloneElement} from 'react';
26
27
 
@@ -96,7 +97,7 @@ export type TouchableNativeFeedbackProps = Readonly<{
96
97
  }>
97
98
  | Readonly<{
98
99
  type: 'RippleAndroid',
99
- color: ?number,
100
+ color: ?ProcessedColorValue,
100
101
  borderless: boolean,
101
102
  rippleRadius: ?number,
102
103
  }>
@@ -177,23 +178,18 @@ class TouchableNativeFeedback extends React.Component<
177
178
  * @param rippleRadius The radius of ripple effect
178
179
  */
179
180
  static Ripple: (
180
- color: string,
181
+ color: ColorValue,
181
182
  borderless: boolean,
182
183
  rippleRadius?: ?number,
183
184
  ) => Readonly<{
184
185
  borderless: boolean,
185
- color: ?number,
186
+ color: ?ProcessedColorValue,
186
187
  rippleRadius: ?number,
187
188
  type: 'RippleAndroid',
188
- }> = (color: string, borderless: boolean, rippleRadius?: ?number) => {
189
+ }> = (color: ColorValue, borderless: boolean, rippleRadius?: ?number) => {
189
190
  const processedColor = processColor(color);
190
- invariant(
191
- processedColor == null || typeof processedColor === 'number',
192
- 'Unexpected color given for Ripple color',
193
- );
194
191
  return {
195
192
  type: 'RippleAndroid',
196
- // $FlowFixMe[incompatible-type]
197
193
  color: processedColor,
198
194
  borderless,
199
195
  rippleRadius,
@@ -11,6 +11,7 @@
11
11
  'use strict';
12
12
 
13
13
  import type {EdgeInsetsOrSizeProp} from '../../StyleSheet/EdgeInsetsPropType';
14
+ import type {ProcessedColorValue} from '../../StyleSheet/processColor';
14
15
  import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
15
16
  import type {
16
17
  BlurEvent,
@@ -264,9 +265,10 @@ type AndroidDrawableThemeAttr = Readonly<{
264
265
 
265
266
  type AndroidDrawableRipple = Readonly<{
266
267
  type: 'RippleAndroid',
267
- color?: ?number,
268
+ color?: ?ProcessedColorValue,
268
269
  borderless?: ?boolean,
269
270
  rippleRadius?: ?number,
271
+ alpha?: ?number,
270
272
  }>;
271
273
 
272
274
  type AndroidDrawable = AndroidDrawableThemeAttr | AndroidDrawableRipple;
@@ -29,7 +29,7 @@ export default class ReactNativeVersion {
29
29
  static major: number = 0;
30
30
  static minor: number = 86;
31
31
  static patch: number = 0;
32
- static prerelease: string | null = 'rc.1';
32
+ static prerelease: string | null = 'rc.2';
33
33
 
34
34
  static getVersionString(): string {
35
35
  return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(86),
26
26
  RCTVersionPatch: @(0),
27
- RCTVersionPrerelease: @"rc.1",
27
+ RCTVersionPrerelease: @"rc.2",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -6468,6 +6468,7 @@ public class com/facebook/react/views/view/ReactViewGroup : android/view/ViewGro
6468
6468
  public fun getZIndexMappedChildIndex (I)I
6469
6469
  public fun hasOverlappingRendering ()Z
6470
6470
  protected fun onAttachedToWindow ()V
6471
+ protected fun onConfigurationChanged (Landroid/content/res/Configuration;)V
6471
6472
  public fun onHoverEvent (Landroid/view/MotionEvent;)Z
6472
6473
  public fun onInterceptTouchEvent (Landroid/view/MotionEvent;)Z
6473
6474
  protected fun onLayout (ZIIII)V
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.86.0-rc.1
1
+ VERSION_NAME=0.86.0-rc.2
2
2
  react.internal.publishingGroup=com.facebook.react
3
3
  react.internal.hermesPublishingGroup=com.facebook.hermes
4
4
 
@@ -15,6 +15,6 @@ public object ReactNativeVersion {
15
15
  "major" to 0,
16
16
  "minor" to 86,
17
17
  "patch" to 0,
18
- "prerelease" to "rc.1"
18
+ "prerelease" to "rc.2"
19
19
  )
20
20
  }
@@ -15,10 +15,16 @@ import android.graphics.drawable.ColorDrawable
15
15
  import android.graphics.drawable.Drawable
16
16
  import android.graphics.drawable.RippleDrawable
17
17
  import android.util.TypedValue
18
+ import com.facebook.common.logging.FLog
19
+ import com.facebook.react.bridge.ColorPropConverter
20
+ import com.facebook.react.bridge.JSApplicationCausedNativeException
18
21
  import com.facebook.react.bridge.JSApplicationIllegalArgumentException
19
22
  import com.facebook.react.bridge.ReadableMap
23
+ import com.facebook.react.bridge.ReadableType
24
+ import com.facebook.react.common.ReactConstants
20
25
  import com.facebook.react.uimanager.PixelUtil
21
26
  import com.facebook.react.uimanager.ViewProps
27
+ import kotlin.math.roundToInt
22
28
 
23
29
  /**
24
30
  * Utility class that helps with converting android drawable description used in JS to an actual
@@ -73,11 +79,21 @@ public object ReactDrawableHelper {
73
79
  context: Context,
74
80
  drawableDescriptionDict: ReadableMap,
75
81
  ): RippleDrawable {
76
- val color = getColor(context, drawableDescriptionDict)
77
- val mask = getMask(drawableDescriptionDict)
78
- val colorStateList = ColorStateList(arrayOf(intArrayOf()), intArrayOf(color))
82
+ val resolvedColor = getColor(context, drawableDescriptionDict)
83
+ var color = resolvedColor ?: getFallbackColor(context)
84
+
85
+ if (
86
+ resolvedColor != null &&
87
+ drawableDescriptionDict.hasKey("alpha") &&
88
+ !drawableDescriptionDict.isNull("alpha")
89
+ ) {
90
+ val alphaFactor = drawableDescriptionDict.getDouble("alpha").coerceIn(0.0, 1.0)
91
+ val newAlpha = (Color.alpha(color) * alphaFactor).roundToInt()
92
+ color = Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color))
93
+ }
79
94
 
80
- return RippleDrawable(colorStateList, null, mask)
95
+ val mask = getMask(drawableDescriptionDict)
96
+ return RippleDrawable(ColorStateList(arrayOf(intArrayOf()), intArrayOf(color)), null, mask)
81
97
  }
82
98
 
83
99
  private fun setRadius(drawableDescriptionDict: ReadableMap, drawable: Drawable?): Drawable? {
@@ -88,26 +104,49 @@ public object ReactDrawableHelper {
88
104
  return drawable
89
105
  }
90
106
 
91
- private fun getColor(context: Context, drawableDescriptionDict: ReadableMap): Int =
92
- if (
93
- drawableDescriptionDict.hasKey(ViewProps.COLOR) &&
94
- !drawableDescriptionDict.isNull(ViewProps.COLOR)
95
- ) {
96
- drawableDescriptionDict.getInt(ViewProps.COLOR)
97
- } else {
107
+ /**
108
+ * Returns the resolved ripple color, or null if none was provided or the PlatformColor resource
109
+ * couldn't be found.
110
+ */
111
+ private fun getColor(context: Context, drawableDescriptionDict: ReadableMap): Int? {
112
+ val rawColor: Any? =
98
113
  if (
99
- context.theme.resolveAttribute(
100
- android.R.attr.colorControlHighlight,
101
- resolveOutValue,
102
- true,
103
- )
114
+ drawableDescriptionDict.hasKey(ViewProps.COLOR) &&
115
+ !drawableDescriptionDict.isNull(ViewProps.COLOR)
104
116
  ) {
105
- context.resources.getColor(resolveOutValue.resourceId, context.theme)
117
+ when (drawableDescriptionDict.getType(ViewProps.COLOR)) {
118
+ ReadableType.Number -> drawableDescriptionDict.getDouble(ViewProps.COLOR)
119
+ ReadableType.Map -> drawableDescriptionDict.getMap(ViewProps.COLOR)
120
+ else -> null
121
+ }
106
122
  } else {
107
- throw JSApplicationIllegalArgumentException(
108
- "Attribute colorControlHighlight couldn't be resolved into a drawable"
109
- )
123
+ null
110
124
  }
125
+ return try {
126
+ ColorPropConverter.getColor(rawColor, context)
127
+ } catch (e: JSApplicationCausedNativeException) {
128
+ FLog.w(
129
+ ReactConstants.TAG,
130
+ e,
131
+ "android_ripple: color resource not found, using colorControlHighlight",
132
+ )
133
+ null
134
+ }
135
+ }
136
+
137
+ private fun getFallbackColor(context: Context): Int =
138
+ if (
139
+ context.theme.resolveAttribute(
140
+ android.R.attr.colorControlHighlight,
141
+ resolveOutValue,
142
+ true,
143
+ )
144
+ ) {
145
+ context.resources.getColor(resolveOutValue.resourceId, context.theme)
146
+ } else {
147
+ throw JSApplicationIllegalArgumentException(
148
+ "Attribute colorControlHighlight couldn't be resolved into a drawable"
149
+ )
111
150
  }
112
151
 
113
152
  private fun getMask(drawableDescriptionDict: ReadableMap): Drawable? {
@@ -12,6 +12,7 @@ package com.facebook.react.views.view
12
12
  import android.annotation.SuppressLint
13
13
  import android.annotation.TargetApi
14
14
  import android.content.Context
15
+ import android.content.res.Configuration
15
16
  import android.graphics.BlendMode
16
17
  import android.graphics.Canvas
17
18
  import android.graphics.Paint
@@ -28,6 +29,7 @@ import com.facebook.react.R
28
29
  import com.facebook.react.bridge.ReactNoCrashSoftException
29
30
  import com.facebook.react.bridge.ReactSoftExceptionLogger
30
31
  import com.facebook.react.bridge.ReactSoftExceptionLogger.logSoftException
32
+ import com.facebook.react.bridge.ReadableMap
31
33
  import com.facebook.react.bridge.UiThreadUtil.assertOnUiThread
32
34
  import com.facebook.react.bridge.UiThreadUtil.runOnUiThread
33
35
  import com.facebook.react.common.ReactConstants.TAG
@@ -154,6 +156,9 @@ public open class ReactViewGroup public constructor(context: Context?) :
154
156
  null
155
157
  private var focusOnAttach = false
156
158
 
159
+ internal var nativeBackgroundMap: ReadableMap? = null
160
+ internal var nativeForegroundMap: ReadableMap? = null
161
+
157
162
  init {
158
163
  initView()
159
164
  }
@@ -181,6 +186,8 @@ public open class ReactViewGroup public constructor(context: Context?) :
181
186
  backfaceOpacity = 1f
182
187
  backfaceVisible = true
183
188
  childrenRemovedWhileTransitioning = null
189
+ nativeBackgroundMap = null
190
+ nativeForegroundMap = null
184
191
  }
185
192
 
186
193
  internal open fun recycleView() {
@@ -587,6 +594,29 @@ public open class ReactViewGroup public constructor(context: Context?) :
587
594
  }
588
595
  }
589
596
 
597
+ override fun onConfigurationChanged(newConfig: Configuration) {
598
+ super.onConfigurationChanged(newConfig)
599
+ if (nativeBackgroundMap != null) {
600
+ applyNativeBackground(nativeBackgroundMap)
601
+ }
602
+ if (nativeForegroundMap != null) {
603
+ applyNativeForeground(nativeForegroundMap)
604
+ }
605
+ }
606
+
607
+ internal fun applyNativeBackground(map: ReadableMap?) {
608
+ nativeBackgroundMap = map
609
+ setFeedbackUnderlay(
610
+ this,
611
+ map?.let { ReactDrawableHelper.createDrawableFromJSDescription(context, it) },
612
+ )
613
+ }
614
+
615
+ internal fun applyNativeForeground(map: ReadableMap?) {
616
+ nativeForegroundMap = map
617
+ foreground = map?.let { ReactDrawableHelper.createDrawableFromJSDescription(context, it) }
618
+ }
619
+
590
620
  override fun onViewAdded(child: View) {
591
621
  assertOnUiThread()
592
622
  checkViewClippingTag(child, false)
@@ -305,17 +305,12 @@ public open class ReactViewManager : ReactClippingViewManager<ReactViewGroup>()
305
305
 
306
306
  @ReactProp(name = "nativeBackgroundAndroid")
307
307
  public open fun setNativeBackground(view: ReactViewGroup, background: ReadableMap?) {
308
- val bg = background?.let {
309
- ReactDrawableHelper.createDrawableFromJSDescription(view.context, it)
310
- }
311
- BackgroundStyleApplicator.setFeedbackUnderlay(view, bg)
308
+ view.applyNativeBackground(background)
312
309
  }
313
310
 
314
311
  @ReactProp(name = "nativeForegroundAndroid")
315
312
  public open fun setNativeForeground(view: ReactViewGroup, foreground: ReadableMap?) {
316
- view.foreground = foreground?.let {
317
- ReactDrawableHelper.createDrawableFromJSDescription(view.context, it)
318
- }
313
+ view.applyNativeForeground(foreground)
319
314
  }
320
315
 
321
316
  @ReactProp(name = ViewProps.NEEDS_OFFSCREEN_ALPHA_COMPOSITING)
@@ -22,7 +22,7 @@ struct ReactNativeVersionType {
22
22
  int32_t Major = 0;
23
23
  int32_t Minor = 86;
24
24
  int32_t Patch = 0;
25
- std::string_view Prerelease = "rc.1";
25
+ std::string_view Prerelease = "rc.2";
26
26
  };
27
27
 
28
28
  constexpr ReactNativeVersionType ReactNativeVersion;
@@ -450,8 +450,25 @@ inline static void updateNativeDrawableProp(
450
450
  nativeDrawableResult["rippleRadius"] =
451
451
  nativeDrawableValue.ripple.rippleRadius.value();
452
452
  }
453
- if (nativeDrawableValue.ripple.color.has_value()) {
454
- nativeDrawableResult["color"] = nativeDrawableValue.ripple.color.value();
453
+ if (nativeDrawableValue.ripple.color.has_value() ||
454
+ nativeDrawableValue.ripple.colorResourcePaths.has_value()) {
455
+ if (nativeDrawableValue.ripple.colorResourcePaths.has_value()) {
456
+ folly::dynamic resourcePaths = folly::dynamic::array();
457
+ for (const auto& path :
458
+ nativeDrawableValue.ripple.colorResourcePaths.value()) {
459
+ resourcePaths.push_back(path);
460
+ }
461
+ folly::dynamic platformColorMap = folly::dynamic::object();
462
+ platformColorMap["resource_paths"] = resourcePaths;
463
+ nativeDrawableResult["color"] = platformColorMap;
464
+ } else {
465
+ nativeDrawableResult["color"] =
466
+ toAndroidRepr(nativeDrawableValue.ripple.color.value());
467
+ }
468
+ if (nativeDrawableValue.ripple.alpha.has_value()) {
469
+ nativeDrawableResult["alpha"] =
470
+ nativeDrawableValue.ripple.alpha.value();
471
+ }
455
472
  }
456
473
  nativeDrawableResult["borderless"] = nativeDrawableValue.ripple.borderless;
457
474
  } else {
@@ -10,6 +10,7 @@
10
10
  #include <glog/logging.h>
11
11
  #include <react/debug/react_native_expect.h>
12
12
  #include <react/renderer/core/PropsParserContext.h>
13
+ #include <react/renderer/core/graphicsConversions.h>
13
14
  #include <react/renderer/graphics/Float.h>
14
15
  #include <unordered_map>
15
16
 
@@ -22,14 +23,16 @@ struct NativeDrawable {
22
23
  };
23
24
 
24
25
  struct Ripple {
25
- std::optional<int32_t> color{};
26
+ std::optional<SharedColor> color{};
27
+ std::optional<std::vector<std::string>> colorResourcePaths{};
26
28
  std::optional<Float> rippleRadius{};
27
29
  bool borderless{false};
30
+ std::optional<Float> alpha{};
28
31
 
29
32
  bool operator==(const Ripple &rhs) const
30
33
  {
31
- return std::tie(this->color, this->borderless, this->rippleRadius) ==
32
- std::tie(rhs.color, rhs.borderless, rhs.rippleRadius);
34
+ return std::tie(this->color, this->colorResourcePaths, this->borderless, this->rippleRadius, this->alpha) ==
35
+ std::tie(rhs.color, rhs.colorResourcePaths, rhs.borderless, rhs.rippleRadius, rhs.alpha);
33
36
  }
34
37
  };
35
38
 
@@ -59,8 +62,7 @@ struct NativeDrawable {
59
62
  ~NativeDrawable() = default;
60
63
  };
61
64
 
62
- static inline void
63
- fromRawValue(const PropsParserContext & /*context*/, const RawValue &rawValue, NativeDrawable &result)
65
+ static inline void fromRawValue(const PropsParserContext &context, const RawValue &rawValue, NativeDrawable &result)
64
66
  {
65
67
  auto map = (std::unordered_map<std::string, RawValue>)rawValue;
66
68
 
@@ -73,24 +75,53 @@ fromRawValue(const PropsParserContext & /*context*/, const RawValue &rawValue, N
73
75
  react_native_expect(attrIterator != map.end() && attrIterator->second.hasType<std::string>());
74
76
 
75
77
  result = NativeDrawable{
76
- (std::string)attrIterator->second,
77
- {},
78
- NativeDrawable::Kind::ThemeAttr,
78
+ .themeAttr = (std::string)attrIterator->second,
79
+ .ripple = {},
80
+ .kind = NativeDrawable::Kind::ThemeAttr,
79
81
  };
80
82
  } else if (type == "RippleAndroid") {
81
83
  auto color = map.find("color");
82
84
  auto borderless = map.find("borderless");
83
85
  auto rippleRadius = map.find("rippleRadius");
86
+ auto alpha = map.find("alpha");
87
+
88
+ std::optional<SharedColor> parsedColor{};
89
+ std::optional<std::vector<std::string>> parsedColorResourcePaths{};
90
+ if (color != map.end()) {
91
+ if (color->second.hasType<std::unordered_map<std::string, std::vector<std::string>>>()) {
92
+ auto colorMap = (std::unordered_map<std::string, std::vector<std::string>>)color->second;
93
+ auto pathsIt = colorMap.find("resource_paths");
94
+ if (pathsIt != colorMap.end()) {
95
+ parsedColorResourcePaths = pathsIt->second;
96
+ }
97
+ } else {
98
+ SharedColor resolved;
99
+ fromRawValue(context, color->second, resolved);
100
+ if (resolved) {
101
+ parsedColor = resolved;
102
+ }
103
+ }
104
+ }
105
+
106
+ std::optional<Float> parsedAlpha{};
107
+ if (alpha != map.end() && alpha->second.hasType<Float>()) {
108
+ parsedAlpha = (Float)alpha->second;
109
+ }
84
110
 
85
111
  result = NativeDrawable{
86
- std::string{},
87
- NativeDrawable::Ripple{
88
- color != map.end() && color->second.hasType<int32_t>() ? (int32_t)color->second : std::optional<int32_t>{},
89
- rippleRadius != map.end() && rippleRadius->second.hasType<Float>() ? (Float)rippleRadius->second
90
- : std::optional<Float>{},
91
- borderless != map.end() && borderless->second.hasType<bool>() ? (bool)borderless->second : false,
92
- },
93
- NativeDrawable::Kind::Ripple,
112
+ .themeAttr = std::string{},
113
+ .ripple =
114
+ NativeDrawable::Ripple{
115
+ .color = parsedColor,
116
+ .colorResourcePaths = parsedColorResourcePaths,
117
+ .rippleRadius = rippleRadius != map.end() && rippleRadius->second.hasType<Float>()
118
+ ? (Float)rippleRadius->second
119
+ : std::optional<Float>{},
120
+ .borderless =
121
+ borderless != map.end() && borderless->second.hasType<bool>() ? (bool)borderless->second : false,
122
+ .alpha = parsedAlpha,
123
+ },
124
+ .kind = NativeDrawable::Kind::Ripple,
94
125
  };
95
126
  } else {
96
127
  LOG(ERROR) << "Unknown native drawable type: " << type;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.86.0-rc.1",
3
+ "version": "0.86.0-rc.2",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -149,7 +149,7 @@
149
149
  "featureflags": "node ./scripts/featureflags/index.js"
150
150
  },
151
151
  "peerDependencies": {
152
- "@react-native/jest-preset": "0.86.0-rc.1",
152
+ "@react-native/jest-preset": "0.86.0-rc.2",
153
153
  "@types/react": "^19.1.1",
154
154
  "react": "^19.2.3"
155
155
  },
@@ -162,13 +162,13 @@
162
162
  }
163
163
  },
164
164
  "dependencies": {
165
- "@react-native/assets-registry": "0.86.0-rc.1",
166
- "@react-native/codegen": "0.86.0-rc.1",
167
- "@react-native/community-cli-plugin": "0.86.0-rc.1",
168
- "@react-native/gradle-plugin": "0.86.0-rc.1",
169
- "@react-native/js-polyfills": "0.86.0-rc.1",
170
- "@react-native/normalize-colors": "0.86.0-rc.1",
171
- "@react-native/virtualized-lists": "0.86.0-rc.1",
165
+ "@react-native/assets-registry": "0.86.0-rc.2",
166
+ "@react-native/codegen": "0.86.0-rc.2",
167
+ "@react-native/community-cli-plugin": "0.86.0-rc.2",
168
+ "@react-native/gradle-plugin": "0.86.0-rc.2",
169
+ "@react-native/js-polyfills": "0.86.0-rc.2",
170
+ "@react-native/normalize-colors": "0.86.0-rc.2",
171
+ "@react-native/virtualized-lists": "0.86.0-rc.2",
172
172
  "abort-controller": "^3.0.0",
173
173
  "anser": "^1.4.9",
174
174
  "ansi-regex": "^5.0.0",
@@ -103,7 +103,7 @@ class ReactNativeCoreUtils
103
103
  if ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]
104
104
  abort_if_use_local_rncore_with_no_file()
105
105
  rncore_log("Using local xcframework at #{ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]}")
106
- return {:http => "file://#{ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]}" }
106
+ return {:http => ReactNativePodsUtils.local_file_uri(ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]) }
107
107
  end
108
108
 
109
109
  if ENV["RCT_USE_PREBUILT_RNCORE"] == "1"
@@ -160,7 +160,8 @@ class ReactNativeCoreUtils
160
160
  rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}")
161
161
  rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}")
162
162
 
163
- return {:http => URI::File.build(path: destinationDebug).to_s }
163
+ return {:http => stable_tarball_url(@@react_native_version, :debug) } unless @@download_dsyms
164
+ return {:http => ReactNativePodsUtils.local_file_uri(destinationDebug) }
164
165
  end
165
166
 
166
167
  def self.podspec_source_download_prebuilt_nightly_tarball()
@@ -196,7 +197,8 @@ class ReactNativeCoreUtils
196
197
  rncore_log("Resolved nightly ReactNativeCore-prebuilt version:")
197
198
  rncore_log(" #{Pathname.new(destinationDebug).relative_path_from(Pathname.pwd).to_s}")
198
199
  rncore_log(" #{Pathname.new(destinationRelease).relative_path_from(Pathname.pwd).to_s}")
199
- return {:http => URI::File.build(path: destinationDebug).to_s }
200
+ return {:http => nightly_tarball_url(@@react_native_version, :debug) } unless @@download_dsyms
201
+ return {:http => ReactNativePodsUtils.local_file_uri(destinationDebug) }
200
202
  end
201
203
 
202
204
  def self.process_dsyms(frameworkTarball, dSymsTarball)
@@ -404,17 +406,69 @@ class ReactNativeCoreUtils
404
406
  end
405
407
 
406
408
  def self.download_rncore_tarball(react_native_path, tarball_url, version, configuration, dsyms = false)
407
- destination_path = configuration == nil ?
408
- "#{artifacts_dir()}/reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}.tar.gz" :
409
- "#{artifacts_dir()}/reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}-#{configuration}.tar.gz"
409
+ filename = configuration == nil ?
410
+ "reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}.tar.gz" :
411
+ "reactnative-core-#{version}#{dsyms ? "-dSYM" : ""}-#{configuration}.tar.gz"
412
+ destination_path = "#{artifacts_dir()}/#{filename}"
413
+
414
+ if File.exist?(destination_path)
415
+ rncore_log("Tarball #{filename} already exists in Pods. Skipping download.")
416
+ return destination_path
417
+ end
410
418
 
411
- unless File.exist?(destination_path)
412
- # Download to a temporary file first so we don't cache incomplete downloads.
413
- rncore_log("Downloading ReactNativeCore-prebuilt #{dsyms ? "dSYMs " : ""}#{configuration ? configuration.to_s : ""} tarball from #{tarball_url} to #{Pathname.new(destination_path).relative_path_from(Pathname.pwd).to_s}")
419
+ `mkdir -p "#{artifacts_dir()}"`
420
+
421
+ if ReactNativePodsUtils.skip_caches?
422
+ rncore_log("RCT_SKIP_CACHES is set. Downloading #{filename} directly (bypassing shared cache).")
414
423
  tmp_file = "#{artifacts_dir()}/reactnative-core.download"
415
- `mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
424
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
425
+ unless File.exist?(destination_path)
426
+ abort("[ReactNativeCore] Failed to download #{filename} from #{tarball_url}. Aborting.")
427
+ end
428
+ return destination_path
429
+ end
430
+
431
+ cached_path = File.join(ReactNativePodsUtils.shared_cache_dir(), filename)
432
+ if File.exist?(cached_path)
433
+ rncore_log("Verifying checksum for cached #{filename}...")
434
+ if ReactNativePodsUtils.validate_tarball(cached_path, tarball_url)
435
+ rncore_log("Cache hit: copying #{filename} from shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
436
+ FileUtils.cp(cached_path, destination_path)
437
+ else
438
+ rncore_log("Shared cache file #{filename} failed SHA verification. Re-downloading.")
439
+ File.delete(cached_path)
440
+ tmp_file = "#{artifacts_dir()}/reactnative-core.download"
441
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
442
+ unless File.exist?(destination_path)
443
+ abort("[ReactNativeCore] Failed to download #{filename} from #{tarball_url}. Aborting.")
444
+ end
445
+ rncore_log("Verifying checksum for downloaded #{filename}...")
446
+ if ReactNativePodsUtils.validate_tarball(destination_path, tarball_url)
447
+ FileUtils.cp(destination_path, cached_path)
448
+ rncore_log("Saved #{filename} to shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
449
+ else
450
+ File.delete(destination_path) if File.exist?(destination_path)
451
+ abort("[ReactNativeCore] Downloaded file #{filename} failed SHA verification. Aborting.")
452
+ end
453
+ end
416
454
  else
417
- rncore_log("Using downloaded ReactNativeCore-prebuilt #{dsyms ? "dSYMs " : ""}#{configuration ? configuration.to_s : ""} tarball at #{Pathname.new(destination_path).relative_path_from(Pathname.pwd).to_s}")
455
+ rncore_log("Cache miss: downloading #{filename} from #{tarball_url}")
456
+ # Download to a temporary file first so we don't cache incomplete downloads.
457
+ tmp_file = "#{artifacts_dir()}/reactnative-core.download"
458
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
459
+ unless File.exist?(destination_path)
460
+ abort("[ReactNativeCore] Failed to download #{filename} from #{tarball_url}. Aborting.")
461
+ end
462
+ rncore_log("Verifying checksum for downloaded #{filename}...")
463
+ if ReactNativePodsUtils.validate_tarball(destination_path, tarball_url)
464
+ # Save to shared cache for future use
465
+ `mkdir -p "#{ReactNativePodsUtils.shared_cache_dir()}"`
466
+ FileUtils.cp(destination_path, cached_path)
467
+ rncore_log("Saved #{filename} to shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
468
+ else
469
+ File.delete(destination_path) if File.exist?(destination_path)
470
+ abort("[ReactNativeCore] Downloaded file #{filename} failed SHA verification. Aborting.")
471
+ end
418
472
  end
419
473
 
420
474
  return destination_path
@@ -70,7 +70,7 @@ class ReactNativeDependenciesUtils
70
70
  if ENV["RCT_USE_LOCAL_RN_DEP"]
71
71
  abort_if_use_local_rndeps_with_no_file()
72
72
  rndeps_log("Using local xcframework at #{ENV["RCT_USE_LOCAL_RN_DEP"]}")
73
- return {:http => "file://#{ENV["RCT_USE_LOCAL_RN_DEP"]}" }
73
+ return {:http => ReactNativePodsUtils.local_file_uri(ENV["RCT_USE_LOCAL_RN_DEP"]) }
74
74
  end
75
75
 
76
76
  if ENV["RCT_USE_RN_DEP"] && ENV["RCT_USE_RN_DEP"] == "1"
@@ -158,10 +158,10 @@ class ReactNativeDependenciesUtils
158
158
 
159
159
  url = release_tarball_url(@@react_native_version, :debug)
160
160
  rndeps_log("Using tarball from URL: #{url}")
161
- destinationDebug = download_stable_rndeps(@@react_native_path, @@react_native_version, :debug)
161
+ download_stable_rndeps(@@react_native_path, @@react_native_version, :debug)
162
162
  download_stable_rndeps(@@react_native_path, @@react_native_version, :release)
163
163
 
164
- return {:http => URI::File.build(path: destinationDebug).to_s }
164
+ return {:http => url }
165
165
  end
166
166
 
167
167
  def self.release_tarball_url(version, build_type)
@@ -225,22 +225,76 @@ class ReactNativeDependenciesUtils
225
225
 
226
226
  url = nightly_tarball_url(version, :debug)
227
227
  rndeps_log("Using tarball from URL: #{url}")
228
- destinationDebug = download_nightly_rndeps(@@react_native_path, @@react_native_version, :debug)
228
+ download_nightly_rndeps(@@react_native_path, @@react_native_version, :debug)
229
229
  download_nightly_rndeps(@@react_native_path, @@react_native_version, :release)
230
230
 
231
- return {:http => URI::File.build(path: destinationDebug).to_s }
232
- return {:http => url}
231
+ return {:http => url }
233
232
  end
234
233
 
235
234
  def self.download_rndeps_tarball(react_native_path, tarball_url, version, configuration)
236
- destination_path = configuration == nil ?
237
- "#{artifacts_dir()}/reactnative-dependencies-#{version}.tar.gz" :
238
- "#{artifacts_dir()}/reactnative-dependencies-#{version}-#{configuration}.tar.gz"
235
+ filename = configuration == nil ?
236
+ "reactnative-dependencies-#{version}.tar.gz" :
237
+ "reactnative-dependencies-#{version}-#{configuration}.tar.gz"
238
+ destination_path = "#{artifacts_dir()}/#{filename}"
239
+
240
+ if File.exist?(destination_path)
241
+ rndeps_log("Tarball #{filename} already exists in Pods. Skipping download.")
242
+ return destination_path
243
+ end
244
+
245
+ `mkdir -p "#{artifacts_dir()}"`
246
+
247
+ if ReactNativePodsUtils.skip_caches?
248
+ rndeps_log("RCT_SKIP_CACHES is set. Downloading #{filename} directly (bypassing shared cache).")
249
+ tmp_file = "#{artifacts_dir()}/reactnative-dependencies.download"
250
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
251
+ unless File.exist?(destination_path)
252
+ abort("[ReactNativeDependencies] Failed to download #{filename} from #{tarball_url}. Aborting.")
253
+ end
254
+ return destination_path
255
+ end
239
256
 
240
- unless File.exist?(destination_path)
257
+ cached_path = File.join(ReactNativePodsUtils.shared_cache_dir(), filename)
258
+ if File.exist?(cached_path)
259
+ rndeps_log("Verifying checksum for cached #{filename}...")
260
+ if ReactNativePodsUtils.validate_tarball(cached_path, tarball_url)
261
+ rndeps_log("Cache hit: copying #{filename} from shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
262
+ FileUtils.cp(cached_path, destination_path)
263
+ else
264
+ rndeps_log("Shared cache file #{filename} failed SHA verification. Re-downloading.")
265
+ File.delete(cached_path)
266
+ tmp_file = "#{artifacts_dir()}/reactnative-dependencies.download"
267
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
268
+ unless File.exist?(destination_path)
269
+ abort("[ReactNativeDependencies] Failed to download #{filename} from #{tarball_url}. Aborting.")
270
+ end
271
+ rndeps_log("Verifying checksum for downloaded #{filename}...")
272
+ if ReactNativePodsUtils.validate_tarball(destination_path, tarball_url)
273
+ FileUtils.cp(destination_path, cached_path)
274
+ rndeps_log("Saved #{filename} to shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
275
+ else
276
+ File.delete(destination_path) if File.exist?(destination_path)
277
+ abort("[ReactNativeDependencies] Downloaded file #{filename} failed SHA verification. Aborting.")
278
+ end
279
+ end
280
+ else
281
+ rndeps_log("Cache miss: downloading #{filename} from #{tarball_url}")
241
282
  # Download to a temporary file first so we don't cache incomplete downloads.
242
283
  tmp_file = "#{artifacts_dir()}/reactnative-dependencies.download"
243
- `mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
284
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
285
+ unless File.exist?(destination_path)
286
+ abort("[ReactNativeDependencies] Failed to download #{filename} from #{tarball_url}. Aborting.")
287
+ end
288
+ rndeps_log("Verifying checksum for downloaded #{filename}...")
289
+ if ReactNativePodsUtils.validate_tarball(destination_path, tarball_url)
290
+ # Save to shared cache for future use
291
+ `mkdir -p "#{ReactNativePodsUtils.shared_cache_dir()}"`
292
+ FileUtils.cp(destination_path, cached_path)
293
+ rndeps_log("Saved #{filename} to shared cache (#{ReactNativePodsUtils.shared_cache_dir()})")
294
+ else
295
+ File.delete(destination_path) if File.exist?(destination_path)
296
+ abort("[ReactNativeDependencies] Downloaded file #{filename} failed SHA verification. Aborting.")
297
+ end
244
298
  end
245
299
 
246
300
  return destination_path
@@ -4,12 +4,19 @@
4
4
  # LICENSE file in the root directory of this source tree.
5
5
 
6
6
  require 'shellwords'
7
+ require 'digest'
8
+ require 'uri'
7
9
 
8
10
  require_relative "./helpers.rb"
9
11
  require_relative "./jsengine.rb"
10
12
 
11
13
  # Utilities class for React Native Cocoapods
12
14
  class ReactNativePodsUtils
15
+ # URI::File.build validates path components as ASCII, so escape the filesystem path first.
16
+ def self.local_file_uri(path)
17
+ URI::File.build(path: URI::DEFAULT_PARSER.escape(path)).to_s
18
+ end
19
+
13
20
  def self.warn_if_not_on_arm64
14
21
  if SysctlChecker.new().call_sysctl_arm64() == 1 && !Environment.new().ruby_platform().include?('arm64')
15
22
  Pod::UI.warn 'Do not use "pod install" from inside Rosetta2 (x86_64 emulation on arm64).'
@@ -727,4 +734,49 @@ class ReactNativePodsUtils
727
734
  spec.header_mappings_dir = header_mappings_dir
728
735
  end
729
736
  end
737
+
738
+ # ==================== #
739
+ # Shared download cache #
740
+ # ==================== #
741
+
742
+ def self.skip_caches?
743
+ ENV['RCT_SKIP_CACHES'] == '1'
744
+ end
745
+
746
+ def self.shared_cache_dir()
747
+ return File.join(Dir.home, "Library", "Caches", "ReactNative")
748
+ end
749
+
750
+ def self.fetch_maven_sha1(tarball_url)
751
+ sha1 = `curl -sL "#{tarball_url}.sha1"`.strip
752
+ return sha1.downcase if $?.success? && sha1.match?(/\A[a-fA-F0-9]{40}\z/)
753
+ nil
754
+ end
755
+
756
+ def self.validate_tarball(path, tarball_url)
757
+ expected_sha1 = fetch_maven_sha1(tarball_url)
758
+ basename = File.basename(path)
759
+ if expected_sha1.nil?
760
+ cache_log("SHA1 not available from Maven for #{basename}. Skipping validation.")
761
+ return true
762
+ end
763
+ actual_sha1 = Digest::SHA1.file(path).hexdigest
764
+ if actual_sha1 == expected_sha1
765
+ cache_log("SHA1 verified for #{basename}")
766
+ return true
767
+ end
768
+ cache_log("SHA1 mismatch for #{basename}: expected #{expected_sha1}, got #{actual_sha1}", :error)
769
+ return false
770
+ end
771
+
772
+ def self.cache_log(message, level = :info)
773
+ return unless Object.const_defined?("Pod::UI")
774
+ prefix = '[Cache] '
775
+ case level
776
+ when :error
777
+ Pod::UI.puts prefix.red + message
778
+ else
779
+ Pod::UI.puts prefix.green + message
780
+ end
781
+ end
730
782
  end
@@ -3,6 +3,7 @@
3
3
  # This source code is licensed under the MIT license found in the
4
4
  # LICENSE file in the root directory of this source tree.
5
5
 
6
+ require 'digest'
6
7
  require 'net/http'
7
8
  require 'rexml/document'
8
9
 
@@ -236,16 +237,102 @@ def download_stable_hermes(react_native_path, version, configuration)
236
237
  download_hermes_tarball(react_native_path, tarball_url, version, configuration)
237
238
  end
238
239
 
240
+ def shared_cache_dir()
241
+ return File.join(Dir.home, "Library", "Caches", "ReactNative")
242
+ end
243
+
244
+ def fetch_maven_sha1(tarball_url)
245
+ sha1 = `curl -sL "#{tarball_url}.sha1"`.strip
246
+ return sha1.downcase if $?.success? && sha1.match?(/\A[a-fA-F0-9]{40}\z/)
247
+ nil
248
+ end
249
+
250
+ def skip_caches?
251
+ ENV['RCT_SKIP_CACHES'] == '1'
252
+ end
253
+
254
+ def validate_hermes_tarball(path, tarball_url)
255
+ expected_sha1 = fetch_maven_sha1(tarball_url)
256
+ basename = File.basename(path)
257
+ if expected_sha1.nil?
258
+ hermes_log("SHA1 not available from Maven for #{basename}. Skipping validation.", :info)
259
+ return true
260
+ end
261
+ actual_sha1 = Digest::SHA1.file(path).hexdigest
262
+ if actual_sha1 == expected_sha1
263
+ hermes_log("SHA1 verified for #{basename}", :info)
264
+ return true
265
+ end
266
+ hermes_log("SHA1 mismatch for #{basename}: expected #{expected_sha1}, got #{actual_sha1}", :error)
267
+ return false
268
+ end
269
+
239
270
  def download_hermes_tarball(react_native_path, tarball_url, version, configuration)
240
- destination_path = configuration == nil ?
241
- "#{artifacts_dir()}/hermes-ios-#{version}.tar.gz" :
242
- "#{artifacts_dir()}/hermes-ios-#{version}-#{configuration}.tar.gz"
271
+ filename = configuration == nil ?
272
+ "hermes-ios-#{version}.tar.gz" :
273
+ "hermes-ios-#{version}-#{configuration}.tar.gz"
274
+ destination_path = "#{artifacts_dir()}/#{filename}"
275
+
276
+ if File.exist?(destination_path)
277
+ hermes_log("Tarball #{filename} already exists in Pods. Skipping download.", :info)
278
+ return destination_path
279
+ end
280
+
281
+ `mkdir -p "#{artifacts_dir()}"`
282
+
283
+ if skip_caches?
284
+ hermes_log("RCT_SKIP_CACHES is set. Downloading #{filename} directly (bypassing shared cache).", :info)
285
+ tmp_file = "#{artifacts_dir()}/hermes-ios.download"
286
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
287
+ unless File.exist?(destination_path)
288
+ abort("[Hermes] Failed to download #{filename} from #{tarball_url}. Aborting.")
289
+ end
290
+ return destination_path
291
+ end
243
292
 
244
- unless File.exist?(destination_path)
293
+ cached_path = File.join(shared_cache_dir(), filename)
294
+ if File.exist?(cached_path)
295
+ hermes_log("Verifying checksum for cached #{filename}...", :info)
296
+ if validate_hermes_tarball(cached_path, tarball_url)
297
+ hermes_log("Cache hit: copying #{filename} from shared cache (#{shared_cache_dir()})", :info)
298
+ FileUtils.cp(cached_path, destination_path)
299
+ else
300
+ hermes_log("Shared cache file #{filename} failed SHA verification. Re-downloading.", :info)
301
+ File.delete(cached_path)
302
+ tmp_file = "#{artifacts_dir()}/hermes-ios.download"
303
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
304
+ unless File.exist?(destination_path)
305
+ abort("[Hermes] Failed to download #{filename} from #{tarball_url}. Aborting.")
306
+ end
307
+ hermes_log("Verifying checksum for downloaded #{filename}...", :info)
308
+ if validate_hermes_tarball(destination_path, tarball_url)
309
+ FileUtils.cp(destination_path, cached_path)
310
+ hermes_log("Saved #{filename} to shared cache (#{shared_cache_dir()})", :info)
311
+ else
312
+ File.delete(destination_path) if File.exist?(destination_path)
313
+ abort("[Hermes] Downloaded file #{filename} failed SHA verification. Aborting.")
314
+ end
315
+ end
316
+ else
317
+ hermes_log("Cache miss: downloading #{filename} from #{tarball_url}", :info)
245
318
  # Download to a temporary file first so we don't cache incomplete downloads.
246
319
  tmp_file = "#{artifacts_dir()}/hermes-ios.download"
247
- `mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
320
+ `curl -A "react-native-#{version}" "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
321
+ unless File.exist?(destination_path)
322
+ abort("[Hermes] Failed to download #{filename} from #{tarball_url}. Aborting.")
323
+ end
324
+ hermes_log("Verifying checksum for downloaded #{filename}...", :info)
325
+ if validate_hermes_tarball(destination_path, tarball_url)
326
+ # Save to shared cache for future use
327
+ `mkdir -p "#{shared_cache_dir()}"`
328
+ FileUtils.cp(destination_path, cached_path)
329
+ hermes_log("Saved #{filename} to shared cache (#{shared_cache_dir()})", :info)
330
+ else
331
+ File.delete(destination_path) if File.exist?(destination_path)
332
+ abort("[Hermes] Downloaded file #{filename} failed SHA verification. Aborting.")
333
+ end
248
334
  end
335
+
249
336
  return destination_path
250
337
  end
251
338
 
@@ -4,27 +4,30 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<63db1ca1373b98ac95b88f2b3a707ea3>>
7
+ * @generated SignedSource<<92efce69dca1861d7bdfc6d9c5ee3a62>>
8
8
  *
9
9
  * This file was translated from Flow by scripts/js-api/build-types/index.js.
10
10
  * Original file: packages/react-native/Libraries/Components/Pressable/useAndroidRippleForView.js
11
11
  */
12
12
 
13
+ import type { ProcessedColorValue } from "../../StyleSheet/processColor";
13
14
  import type { ColorValue } from "../../StyleSheet/StyleSheet";
14
15
  import type { GestureResponderEvent } from "../../Types/CoreEventTypes";
15
16
  import View from "../View/View";
16
17
  import * as React from "react";
17
18
  type NativeBackgroundProp = Readonly<{
18
19
  type: "RippleAndroid";
19
- color: number | undefined;
20
+ color: ProcessedColorValue | undefined;
20
21
  borderless: boolean;
21
22
  rippleRadius: number | undefined;
23
+ alpha: number | undefined;
22
24
  }>;
23
25
  export type PressableAndroidRippleConfig = {
24
26
  color?: ColorValue;
25
27
  borderless?: boolean;
26
28
  radius?: number;
27
29
  foreground?: boolean;
30
+ alpha?: number;
28
31
  };
29
32
  /**
30
33
  * Provides the event handlers and props for configuring the ripple effect on
@@ -4,12 +4,14 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<88b166ae928743c59b84378a127d90b9>>
7
+ * @generated SignedSource<<0aac502f73085740692f52be116cfe25>>
8
8
  *
9
9
  * This file was translated from Flow by scripts/js-api/build-types/index.js.
10
10
  * Original file: packages/react-native/Libraries/Components/Touchable/TouchableNativeFeedback.js
11
11
  */
12
12
 
13
+ import type { ProcessedColorValue } from "../../StyleSheet/processColor";
14
+ import type { ColorValue } from "../../StyleSheet/StyleSheet";
13
15
  import type { TouchableWithoutFeedbackProps } from "./TouchableWithoutFeedback";
14
16
  import Pressability from "../../Pressability/Pressability";
15
17
  import * as React from "react";
@@ -73,7 +75,7 @@ export type TouchableNativeFeedbackProps = Readonly<Omit<TouchableWithoutFeedbac
73
75
  rippleRadius: number | undefined;
74
76
  }> | Readonly<{
75
77
  type: "RippleAndroid";
76
- color: number | undefined;
78
+ color: ProcessedColorValue | undefined;
77
79
  borderless: boolean;
78
80
  rippleRadius: number | undefined;
79
81
  }>) | undefined;
@@ -109,7 +111,7 @@ export type TouchableNativeFeedbackProps = Readonly<Omit<TouchableWithoutFeedbac
109
111
  rippleRadius: number | undefined;
110
112
  }> | Readonly<{
111
113
  type: "RippleAndroid";
112
- color: number | undefined;
114
+ color: ProcessedColorValue | undefined;
113
115
  borderless: boolean;
114
116
  rippleRadius: number | undefined;
115
117
  }>) | undefined;
@@ -145,7 +147,7 @@ export type TouchableNativeFeedbackProps = Readonly<Omit<TouchableWithoutFeedbac
145
147
  rippleRadius: number | undefined;
146
148
  }> | Readonly<{
147
149
  type: "RippleAndroid";
148
- color: number | undefined;
150
+ color: ProcessedColorValue | undefined;
149
151
  borderless: boolean;
150
152
  rippleRadius: number | undefined;
151
153
  }>) | undefined;
@@ -209,9 +211,9 @@ declare class TouchableNativeFeedback extends React.Component<TouchableNativeFee
209
211
  * @param borderless If the ripple can render outside it's bounds
210
212
  * @param rippleRadius The radius of ripple effect
211
213
  */
212
- static Ripple: (color: string, borderless: boolean, rippleRadius?: null | undefined | number) => Readonly<{
214
+ static Ripple: (color: ColorValue, borderless: boolean, rippleRadius?: null | undefined | number) => Readonly<{
213
215
  borderless: boolean;
214
- color: number | undefined;
216
+ color: ProcessedColorValue | undefined;
215
217
  rippleRadius: number | undefined;
216
218
  type: "RippleAndroid";
217
219
  }>;
@@ -4,13 +4,14 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<e4fd9057301628b1c4a12dffd674e809>>
7
+ * @generated SignedSource<<d1a4f181b6cc5fe82a9b3bb504574692>>
8
8
  *
9
9
  * This file was translated from Flow by scripts/js-api/build-types/index.js.
10
10
  * Original file: packages/react-native/Libraries/Components/View/ViewPropTypes.js
11
11
  */
12
12
 
13
13
  import type { EdgeInsetsOrSizeProp } from "../../StyleSheet/EdgeInsetsPropType";
14
+ import type { ProcessedColorValue } from "../../StyleSheet/processColor";
14
15
  import type { ViewStyleProp } from "../../StyleSheet/StyleSheet";
15
16
  import type { BlurEvent, FocusEvent, GestureResponderEvent, KeyDownEvent, KeyUpEvent, LayoutChangeEvent, LayoutRectangle, MouseEvent, PointerEvent } from "../../Types/CoreEventTypes";
16
17
  import type { AccessibilityActionEvent, AccessibilityProps } from "./ViewAccessibility";
@@ -225,9 +226,10 @@ type AndroidDrawableThemeAttr = Readonly<{
225
226
  }>;
226
227
  type AndroidDrawableRipple = Readonly<{
227
228
  type: "RippleAndroid";
228
- color?: number | undefined;
229
+ color?: ProcessedColorValue | undefined;
229
230
  borderless?: boolean | undefined;
230
231
  rippleRadius?: number | undefined;
232
+ alpha?: number | undefined;
231
233
  }>;
232
234
  type AndroidDrawable = AndroidDrawableThemeAttr | AndroidDrawableRipple;
233
235
  export type ViewPropsAndroid = Readonly<{