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.
- package/Libraries/Components/Pressable/Pressable.d.ts +1 -0
- package/Libraries/Components/Pressable/useAndroidRippleForView.js +7 -8
- package/Libraries/Components/Touchable/TouchableNativeFeedback.js +6 -10
- package/Libraries/Components/View/ViewPropTypes.js +3 -1
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/React/Base/RCTVersion.m +1 -1
- package/ReactAndroid/api/ReactAndroid.api +1 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.kt +59 -20
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt +30 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +2 -7
- package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
- package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp +19 -2
- package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/NativeDrawable.h +47 -16
- package/package.json +9 -9
- package/scripts/cocoapods/rncore.rb +65 -11
- package/scripts/cocoapods/rndependencies.rb +65 -11
- package/scripts/cocoapods/utils.rb +52 -0
- package/sdks/hermes-engine/hermes-utils.rb +92 -5
- package/types_generated/Libraries/Components/Pressable/useAndroidRippleForView.d.ts +5 -2
- package/types_generated/Libraries/Components/Touchable/TouchableNativeFeedback.d.ts +8 -6
- package/types_generated/Libraries/Components/View/ViewPropTypes.d.ts +4 -2
|
@@ -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: ?
|
|
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: ?
|
|
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:
|
|
181
|
+
color: ColorValue,
|
|
181
182
|
borderless: boolean,
|
|
182
183
|
rippleRadius?: ?number,
|
|
183
184
|
) => Readonly<{
|
|
184
185
|
borderless: boolean,
|
|
185
|
-
color: ?
|
|
186
|
+
color: ?ProcessedColorValue,
|
|
186
187
|
rippleRadius: ?number,
|
|
187
188
|
type: 'RippleAndroid',
|
|
188
|
-
}> = (color:
|
|
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?: ?
|
|
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.
|
|
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}` : ''}`;
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -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
|
|
@@ -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
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
resolveOutValue,
|
|
102
|
-
true,
|
|
103
|
-
)
|
|
114
|
+
drawableDescriptionDict.hasKey(ViewProps.COLOR) &&
|
|
115
|
+
!drawableDescriptionDict.isNull(ViewProps.COLOR)
|
|
104
116
|
) {
|
|
105
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
317
|
-
ReactDrawableHelper.createDrawableFromJSDescription(view.context, it)
|
|
318
|
-
}
|
|
313
|
+
view.applyNativeForeground(foreground)
|
|
319
314
|
}
|
|
320
315
|
|
|
321
316
|
@ReactProp(name = ViewProps.NEEDS_OFFSCREEN_ALPHA_COMPOSITING)
|
|
@@ -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
|
-
|
|
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<
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
166
|
-
"@react-native/codegen": "0.86.0-rc.
|
|
167
|
-
"@react-native/community-cli-plugin": "0.86.0-rc.
|
|
168
|
-
"@react-native/gradle-plugin": "0.86.0-rc.
|
|
169
|
-
"@react-native/js-polyfills": "0.86.0-rc.
|
|
170
|
-
"@react-native/normalize-colors": "0.86.0-rc.
|
|
171
|
-
"@react-native/virtualized-lists": "0.86.0-rc.
|
|
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 =>
|
|
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 =>
|
|
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 =>
|
|
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
|
-
|
|
408
|
-
"
|
|
409
|
-
"
|
|
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
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
-
`
|
|
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("
|
|
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 =>
|
|
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
|
-
|
|
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 =>
|
|
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
|
-
|
|
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 =>
|
|
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
|
-
|
|
237
|
-
"
|
|
238
|
-
"
|
|
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
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
241
|
-
"
|
|
242
|
-
"
|
|
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
|
-
|
|
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
|
-
`
|
|
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<<
|
|
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:
|
|
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<<
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
214
|
+
static Ripple: (color: ColorValue, borderless: boolean, rippleRadius?: null | undefined | number) => Readonly<{
|
|
213
215
|
borderless: boolean;
|
|
214
|
-
color:
|
|
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<<
|
|
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?:
|
|
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<{
|