react-native-tvos 0.87.0-0 → 0.87.1-0
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/Animated/AnimatedEvent.js +1 -1
- package/Libraries/Animated/AnimatedImplementation.js +6 -2
- package/Libraries/Animated/nodes/AnimatedNode.js +1 -1
- package/Libraries/Animated/nodes/AnimatedValue.js +2 -2
- package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +2 -0
- package/Libraries/Components/ScrollView/ScrollView.d.ts +26 -0
- package/Libraries/Components/ScrollView/ScrollView.js +32 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +2 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponentType.js +11 -0
- package/Libraries/Components/ScrollView/processScrollAnimationEasing.js +40 -0
- package/Libraries/Components/TV/TVFocusGuideView.js +31 -0
- package/Libraries/Components/TV/useFocusEnterLeave.js +112 -0
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/README.md +17 -0
- package/React/Base/RCTVersion.m +1 -1
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +30 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.kt +7 -3
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt +36 -13
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt +13 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt +25 -3
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt +62 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt +13 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/react/renderer/components/scrollview/platform/android/react/renderer/components/scrollview/HostPlatformScrollViewProps.cpp +26 -0
- package/ReactCommon/react/renderer/components/scrollview/platform/android/react/renderer/components/scrollview/HostPlatformScrollViewProps.h +3 -0
- package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm +1 -1
- package/package.json +8 -8
- package/scripts/cocoapods/rndependencies.rb +31 -25
- package/scripts/replace-rncore-version.js +18 -2
- package/scripts/setup-apple-spm.js +28 -12
- package/scripts/spm/autolinking-plugins.js +80 -0
- package/scripts/spm/download-spm-artifacts.js +64 -6
- package/scripts/spm/expand-spm-dependencies.js +249 -30
- package/scripts/spm/generate-spm-autolinking.js +157 -40
- package/scripts/spm/generate-spm-package.js +30 -18
- package/scripts/spm/generate-spm-xcodeproj.js +595 -71
- package/scripts/spm/scaffold-package-swift.js +65 -24
- package/scripts/spm/spm-pbxproj.js +158 -28
- package/scripts/spm/spm-types.js +29 -3
- package/scripts/spm/spm-utils.js +117 -2
- package/sdks/.hermesv1version +1 -1
- package/sdks/hermes-engine/version.properties +1 -1
- package/types/public/ReactNativeTVTypes.d.ts +40 -1
- package/scripts/spm/__doc__/rfc-spm-xcframework.md +0 -707
- package/scripts/spm/__doc__/spm-autolinking-plugins.md +0 -244
- package/scripts/spm/__doc__/spm-header-paths-contract.md +0 -97
- package/scripts/spm/__doc__/spm-plugins-assessment.md +0 -128
- package/scripts/spm/__doc__/spm-scripts.md +0 -486
|
@@ -42,6 +42,7 @@ import com.facebook.react.views.scroll.ReactScrollViewCommandHelper.Companion.re
|
|
|
42
42
|
import com.facebook.react.views.scroll.ReactScrollViewCommandHelper.ScrollCommandHandler
|
|
43
43
|
import com.facebook.react.views.scroll.ReactScrollViewCommandHelper.ScrollToCommandData
|
|
44
44
|
import com.facebook.react.views.scroll.ReactScrollViewCommandHelper.ScrollToEndCommandData
|
|
45
|
+
import com.facebook.react.views.scroll.ReactScrollViewHelper.createScrollAnimationInterpolator
|
|
45
46
|
import com.facebook.react.views.scroll.ReactScrollViewHelper.parseOverScrollMode
|
|
46
47
|
import com.facebook.react.views.scroll.ReactScrollViewHelper.parseSnapToAlignment
|
|
47
48
|
|
|
@@ -174,6 +175,18 @@ constructor(private val fpsListener: FpsListener? = null) :
|
|
|
174
175
|
view.scrollAnimationEnabled = value
|
|
175
176
|
}
|
|
176
177
|
|
|
178
|
+
@ReactProp(name = "scrollAnimationDuration")
|
|
179
|
+
public fun setScrollAnimationDuration(view: ReactHorizontalScrollView, value: Float) {
|
|
180
|
+
// Exposed as a float because of the JavaScript interface, see `snapToInterval`.
|
|
181
|
+
view.scrollAnimationDuration = value.toInt()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@ReactProp(name = "scrollAnimationEasing")
|
|
185
|
+
public fun setScrollAnimationEasing(view: ReactHorizontalScrollView, value: ReadableArray?) {
|
|
186
|
+
// Resolved here rather than per frame: the curve only changes when the prop does.
|
|
187
|
+
view.scrollAnimationInterpolator = createScrollAnimationInterpolator(value)
|
|
188
|
+
}
|
|
189
|
+
|
|
177
190
|
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
|
|
178
191
|
public fun setRemoveClippedSubviews(
|
|
179
192
|
view: ReactHorizontalScrollView,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
package com.facebook.react.views.scroll
|
|
9
9
|
|
|
10
10
|
import android.animation.ObjectAnimator
|
|
11
|
+
import android.animation.TimeInterpolator
|
|
11
12
|
import android.animation.ValueAnimator
|
|
12
13
|
import android.content.Context
|
|
13
14
|
import android.graphics.Canvas
|
|
@@ -207,6 +208,10 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) :
|
|
|
207
208
|
private var scrollsChildToFocus = true
|
|
208
209
|
internal var snapToItemPadding: Int = 0
|
|
209
210
|
internal var scrollAnimationEnabled: Boolean = true
|
|
211
|
+
/** Values <= 0 keep the platform default duration. */
|
|
212
|
+
internal var scrollAnimationDuration: Int = 0
|
|
213
|
+
/** `null` keeps the platform default curve. */
|
|
214
|
+
internal var scrollAnimationInterpolator: TimeInterpolator? = null
|
|
210
215
|
private var blockScrollDelta: Boolean = false
|
|
211
216
|
|
|
212
217
|
init {
|
|
@@ -264,6 +269,8 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) :
|
|
|
264
269
|
scrollsChildToFocus = true
|
|
265
270
|
snapToItemPadding = 0
|
|
266
271
|
scrollAnimationEnabled = true
|
|
272
|
+
scrollAnimationDuration = 0
|
|
273
|
+
scrollAnimationInterpolator = null
|
|
267
274
|
blockScrollDelta = false
|
|
268
275
|
}
|
|
269
276
|
|
|
@@ -505,12 +512,21 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) :
|
|
|
505
512
|
val currentFocused = findFocus()
|
|
506
513
|
val nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, direction)
|
|
507
514
|
if (nextFocused != null && nextFocused !== currentFocused && nextFocused !== this) {
|
|
508
|
-
nextFocused.requestFocus(direction)
|
|
515
|
+
if (nextFocused.requestFocus(direction)) {
|
|
516
|
+
ReactScrollViewHelper.playFocusNavigationSoundEffect(this, direction)
|
|
517
|
+
}
|
|
509
518
|
return true
|
|
510
519
|
}
|
|
511
520
|
return false
|
|
512
521
|
}
|
|
513
|
-
|
|
522
|
+
|
|
523
|
+
val focusedBeforeScroll = findFocus()
|
|
524
|
+
val handled = super.arrowScroll(direction)
|
|
525
|
+
// super.arrowScroll() can scroll without moving focus, so only click when focus moved.
|
|
526
|
+
if (handled && findFocus() !== focusedBeforeScroll) {
|
|
527
|
+
ReactScrollViewHelper.playFocusNavigationSoundEffect(this, direction)
|
|
528
|
+
}
|
|
529
|
+
return handled
|
|
514
530
|
}
|
|
515
531
|
|
|
516
532
|
/**
|
|
@@ -1374,7 +1390,13 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) :
|
|
|
1374
1390
|
|
|
1375
1391
|
override fun startFlingAnimator(start: Int, end: Int) {
|
|
1376
1392
|
defaultFlingAnimator.cancel()
|
|
1377
|
-
|
|
1393
|
+
// The animator is reused, so the interpolator must be re-applied on every call to undo whatever
|
|
1394
|
+
// a previous `scrollAnimationEasing` left on it.
|
|
1395
|
+
val duration =
|
|
1396
|
+
if (scrollAnimationDuration > 0) scrollAnimationDuration
|
|
1397
|
+
else ReactScrollViewHelper.getDefaultScrollAnimationDuration(context)
|
|
1398
|
+
defaultFlingAnimator.interpolator =
|
|
1399
|
+
scrollAnimationInterpolator ?: ReactScrollViewHelper.getDefaultScrollAnimationInterpolator()
|
|
1378
1400
|
defaultFlingAnimator.setDuration(duration.toLong()).setIntValues(start, end)
|
|
1379
1401
|
defaultFlingAnimator.start()
|
|
1380
1402
|
|
|
@@ -8,19 +8,24 @@
|
|
|
8
8
|
package com.facebook.react.views.scroll
|
|
9
9
|
|
|
10
10
|
import android.animation.Animator
|
|
11
|
+
import android.animation.TimeInterpolator
|
|
11
12
|
import android.animation.ValueAnimator
|
|
12
13
|
import android.content.Context
|
|
13
14
|
import android.graphics.Point
|
|
14
15
|
import android.graphics.Rect
|
|
15
16
|
import android.os.Build
|
|
17
|
+
import android.view.SoundEffectConstants
|
|
16
18
|
import android.view.View
|
|
17
19
|
import android.view.ViewGroup
|
|
20
|
+
import android.view.animation.AccelerateDecelerateInterpolator
|
|
21
|
+
import android.view.animation.PathInterpolator
|
|
18
22
|
import android.widget.OverScroller
|
|
19
23
|
import androidx.annotation.RequiresApi
|
|
20
24
|
import androidx.core.view.ViewCompat.FocusDirection
|
|
21
25
|
import androidx.core.view.ViewCompat.FocusRealDirection
|
|
22
26
|
import com.facebook.common.logging.FLog
|
|
23
27
|
import com.facebook.react.bridge.ReactContext
|
|
28
|
+
import com.facebook.react.bridge.ReadableArray
|
|
24
29
|
import com.facebook.react.bridge.WritableMap
|
|
25
30
|
import com.facebook.react.bridge.WritableNativeMap
|
|
26
31
|
import com.facebook.react.common.ReactConstants
|
|
@@ -67,6 +72,11 @@ public object ReactScrollViewHelper {
|
|
|
67
72
|
private var SMOOTH_SCROLL_DURATION = 250
|
|
68
73
|
private var smoothScrollDurationInitialized = false
|
|
69
74
|
|
|
75
|
+
// The curve `ValueAnimator` applies when no interpolator is set, kept here so the reused fling
|
|
76
|
+
// animator can be reset to it once a custom `scrollAnimationEasing` is cleared.
|
|
77
|
+
private val defaultScrollAnimationInterpolator: TimeInterpolator =
|
|
78
|
+
AccelerateDecelerateInterpolator()
|
|
79
|
+
|
|
70
80
|
/** Shared by [ReactScrollView] and [ReactHorizontalScrollView]. */
|
|
71
81
|
@JvmStatic
|
|
72
82
|
public fun <T> emitScrollEvent(scrollView: T, xVelocity: Float, yVelocity: Float)
|
|
@@ -225,6 +235,35 @@ public object ReactScrollViewHelper {
|
|
|
225
235
|
return SMOOTH_SCROLL_DURATION
|
|
226
236
|
}
|
|
227
237
|
|
|
238
|
+
/** Curve used by the fling animator when `scrollAnimationEasing` is not set. */
|
|
239
|
+
@JvmStatic
|
|
240
|
+
public fun getDefaultScrollAnimationInterpolator(): TimeInterpolator =
|
|
241
|
+
defaultScrollAnimationInterpolator
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Builds the `scrollAnimationEasing` curve from the CSS cubic-bezier control points `[x1, y1, x2,
|
|
245
|
+
* y2]` sent by JS. Returns `null` when the value is missing or does not describe a usable curve,
|
|
246
|
+
* so callers fall back to [getDefaultScrollAnimationInterpolator].
|
|
247
|
+
*/
|
|
248
|
+
@JvmStatic
|
|
249
|
+
public fun createScrollAnimationInterpolator(controlPoints: ReadableArray?): TimeInterpolator? {
|
|
250
|
+
if (controlPoints == null || controlPoints.size() != 4) {
|
|
251
|
+
return null
|
|
252
|
+
}
|
|
253
|
+
return try {
|
|
254
|
+
PathInterpolator(
|
|
255
|
+
controlPoints.getDouble(0).toFloat(),
|
|
256
|
+
controlPoints.getDouble(1).toFloat(),
|
|
257
|
+
controlPoints.getDouble(2).toFloat(),
|
|
258
|
+
controlPoints.getDouble(3).toFloat(),
|
|
259
|
+
)
|
|
260
|
+
} catch (e: IllegalArgumentException) {
|
|
261
|
+
// PathInterpolator rejects curves that leave 0..1 on x or loop back on themselves.
|
|
262
|
+
FLog.w(ReactConstants.TAG, e, "Invalid scrollAnimationEasing control points")
|
|
263
|
+
null
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
228
267
|
/**
|
|
229
268
|
* Adds a scroll listener.
|
|
230
269
|
*
|
|
@@ -574,6 +613,29 @@ public object ReactScrollViewHelper {
|
|
|
574
613
|
return host.findViewById(nextFocusableViewId)
|
|
575
614
|
}
|
|
576
615
|
|
|
616
|
+
/**
|
|
617
|
+
* Plays the system focus navigation sound for a D-pad move the scroll view handled itself.
|
|
618
|
+
*
|
|
619
|
+
* ViewRootImpl only sonifies focus moves it performs, so any key event a scroll view consumes
|
|
620
|
+
* (which it does as soon as its content is scrollable) navigates silently. Call this after a
|
|
621
|
+
* successful requestFocus to keep the click consistent. It is a no-op when the user has system
|
|
622
|
+
* sounds off.
|
|
623
|
+
*/
|
|
624
|
+
@JvmStatic
|
|
625
|
+
public fun playFocusNavigationSoundEffect(view: View, @FocusDirection direction: Int) {
|
|
626
|
+
val soundConstant =
|
|
627
|
+
when (direction) {
|
|
628
|
+
View.FOCUS_UP,
|
|
629
|
+
View.FOCUS_BACKWARD -> SoundEffectConstants.NAVIGATION_UP
|
|
630
|
+
View.FOCUS_DOWN,
|
|
631
|
+
View.FOCUS_FORWARD -> SoundEffectConstants.NAVIGATION_DOWN
|
|
632
|
+
View.FOCUS_LEFT -> SoundEffectConstants.NAVIGATION_LEFT
|
|
633
|
+
View.FOCUS_RIGHT -> SoundEffectConstants.NAVIGATION_RIGHT
|
|
634
|
+
else -> return
|
|
635
|
+
}
|
|
636
|
+
view.playSoundEffect(soundConstant)
|
|
637
|
+
}
|
|
638
|
+
|
|
577
639
|
/**
|
|
578
640
|
* Walks up the view hierarchy from the focused view to find a ReactViewGroup with
|
|
579
641
|
* either scrollSnapAlign or scrollSnapOffset set. Returns a Triple of (snapTarget,
|
package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt
CHANGED
|
@@ -41,6 +41,7 @@ import com.facebook.react.views.scroll.ReactScrollViewCommandHelper.Companion.re
|
|
|
41
41
|
import com.facebook.react.views.scroll.ReactScrollViewCommandHelper.ScrollCommandHandler
|
|
42
42
|
import com.facebook.react.views.scroll.ReactScrollViewCommandHelper.ScrollToCommandData
|
|
43
43
|
import com.facebook.react.views.scroll.ReactScrollViewCommandHelper.ScrollToEndCommandData
|
|
44
|
+
import com.facebook.react.views.scroll.ReactScrollViewHelper.createScrollAnimationInterpolator
|
|
44
45
|
import com.facebook.react.views.scroll.ReactScrollViewHelper.parseOverScrollMode
|
|
45
46
|
import com.facebook.react.views.scroll.ReactScrollViewHelper.parseSnapToAlignment
|
|
46
47
|
import com.facebook.react.views.scroll.ScrollEventType.Companion.getJSEventName
|
|
@@ -158,6 +159,18 @@ constructor(private val fpsListener: FpsListener? = null) :
|
|
|
158
159
|
view.scrollAnimationEnabled = value
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
@ReactProp(name = "scrollAnimationDuration")
|
|
163
|
+
public fun setScrollAnimationDuration(view: ReactScrollView, value: Float) {
|
|
164
|
+
// Exposed as a float because of the JavaScript interface, see `snapToInterval`.
|
|
165
|
+
view.scrollAnimationDuration = value.toInt()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@ReactProp(name = "scrollAnimationEasing")
|
|
169
|
+
public fun setScrollAnimationEasing(view: ReactScrollView, value: ReadableArray?) {
|
|
170
|
+
// Resolved here rather than per frame: the curve only changes when the prop does.
|
|
171
|
+
view.scrollAnimationInterpolator = createScrollAnimationInterpolator(value)
|
|
172
|
+
}
|
|
173
|
+
|
|
161
174
|
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
|
|
162
175
|
public fun setRemoveClippedSubviews(view: ReactScrollView, removeClippedSubviews: Boolean) {
|
|
163
176
|
view.removeClippedSubviews = removeClippedSubviews
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
|
|
15
15
|
#define REACT_NATIVE_VERSION_MAJOR 0
|
|
16
16
|
#define REACT_NATIVE_VERSION_MINOR 87
|
|
17
|
-
#define REACT_NATIVE_VERSION_PATCH
|
|
17
|
+
#define REACT_NATIVE_VERSION_PATCH 1
|
|
18
18
|
|
|
19
19
|
namespace facebook::react {
|
|
20
20
|
|
|
21
21
|
struct ReactNativeVersionType {
|
|
22
22
|
int32_t Major = 0;
|
|
23
23
|
int32_t Minor = 87;
|
|
24
|
-
int32_t Patch =
|
|
24
|
+
int32_t Patch = 1;
|
|
25
25
|
std::string_view Prerelease = "0";
|
|
26
26
|
};
|
|
27
27
|
|
|
@@ -55,6 +55,18 @@ HostPlatformScrollViewProps::HostPlatformScrollViewProps(
|
|
|
55
55
|
rawProps,
|
|
56
56
|
"snapToItemPadding",
|
|
57
57
|
sourceProps.snapToItemPadding,
|
|
58
|
+
{})),
|
|
59
|
+
scrollAnimationDuration(convertRawProp(
|
|
60
|
+
context,
|
|
61
|
+
rawProps,
|
|
62
|
+
"scrollAnimationDuration",
|
|
63
|
+
sourceProps.scrollAnimationDuration,
|
|
64
|
+
{})),
|
|
65
|
+
scrollAnimationEasing(convertRawProp(
|
|
66
|
+
context,
|
|
67
|
+
rawProps,
|
|
68
|
+
"scrollAnimationEasing",
|
|
69
|
+
sourceProps.scrollAnimationEasing,
|
|
58
70
|
{})) {}
|
|
59
71
|
|
|
60
72
|
void HostPlatformScrollViewProps::setProp(
|
|
@@ -76,6 +88,8 @@ void HostPlatformScrollViewProps::setProp(
|
|
|
76
88
|
RAW_SET_PROP_SWITCH_CASE_BASIC(overScrollMode);
|
|
77
89
|
RAW_SET_PROP_SWITCH_CASE_BASIC(endFillColor);
|
|
78
90
|
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToItemPadding);
|
|
91
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollAnimationDuration);
|
|
92
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollAnimationEasing);
|
|
79
93
|
}
|
|
80
94
|
}
|
|
81
95
|
|
|
@@ -394,6 +408,18 @@ folly::dynamic HostPlatformScrollViewProps::getDiffProps(
|
|
|
394
408
|
result["snapToItemPadding"] = snapToItemPadding;
|
|
395
409
|
}
|
|
396
410
|
|
|
411
|
+
if (scrollAnimationDuration != oldProps->scrollAnimationDuration) {
|
|
412
|
+
result["scrollAnimationDuration"] = scrollAnimationDuration;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (scrollAnimationEasing != oldProps->scrollAnimationEasing) {
|
|
416
|
+
auto scrollAnimationEasingArray = folly::dynamic::array();
|
|
417
|
+
for (const auto& controlPoint : scrollAnimationEasing) {
|
|
418
|
+
scrollAnimationEasingArray.push_back(controlPoint);
|
|
419
|
+
}
|
|
420
|
+
result["scrollAnimationEasing"] = scrollAnimationEasingArray;
|
|
421
|
+
}
|
|
422
|
+
|
|
397
423
|
return result;
|
|
398
424
|
}
|
|
399
425
|
|
|
@@ -35,6 +35,9 @@ class HostPlatformScrollViewProps : public BaseScrollViewProps {
|
|
|
35
35
|
|
|
36
36
|
Float snapToItemPadding{0};
|
|
37
37
|
|
|
38
|
+
Float scrollAnimationDuration{0};
|
|
39
|
+
std::vector<Float> scrollAnimationEasing{};
|
|
40
|
+
|
|
38
41
|
#pragma mark - DebugStringConvertible
|
|
39
42
|
|
|
40
43
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
|
@@ -361,7 +361,7 @@ UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties)
|
|
|
361
361
|
font = [UIFont fontWithName:fontProperties.family size:effectiveFontSize];
|
|
362
362
|
if (font != nullptr) {
|
|
363
363
|
fontNames = [UIFont fontNamesForFamilyName:font.familyName];
|
|
364
|
-
fontWeight = (fontWeight != 0.0)
|
|
364
|
+
fontWeight = (fontWeight != 0.0) ? fontWeight : RCTGetFontWeight(font);
|
|
365
365
|
} else {
|
|
366
366
|
// Failback to system font.
|
|
367
367
|
font = RCTDefaultFontWithFontProperties(fontProperties);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-tvos",
|
|
3
|
-
"version": "0.87.
|
|
3
|
+
"version": "0.87.1-0",
|
|
4
4
|
"description": "A framework for building native apps using React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -155,18 +155,18 @@
|
|
|
155
155
|
}
|
|
156
156
|
},
|
|
157
157
|
"dependencies": {
|
|
158
|
-
"@react-native/asset-utils": "0.87.
|
|
159
|
-
"@react-native/codegen": "0.87.
|
|
160
|
-
"@react-native/community-cli-plugin": "0.87.
|
|
161
|
-
"@react-native/gradle-plugin": "0.87.
|
|
162
|
-
"@react-native/normalize-colors": "0.87.
|
|
158
|
+
"@react-native/asset-utils": "0.87.1",
|
|
159
|
+
"@react-native/codegen": "0.87.1",
|
|
160
|
+
"@react-native/community-cli-plugin": "0.87.1",
|
|
161
|
+
"@react-native/gradle-plugin": "0.87.1",
|
|
162
|
+
"@react-native/normalize-colors": "0.87.1",
|
|
163
163
|
"anser": "^1.4.9",
|
|
164
164
|
"ansi-regex": "^5.0.0",
|
|
165
165
|
"babel-plugin-syntax-hermes-parser": "0.36.1",
|
|
166
166
|
"base64-js": "^1.5.1",
|
|
167
167
|
"commander": "^12.0.0",
|
|
168
168
|
"flow-enums-runtime": "^0.0.6",
|
|
169
|
-
"hermes-compiler": "250829098.0.
|
|
169
|
+
"hermes-compiler": "250829098.0.17",
|
|
170
170
|
"invariant": "^2.2.4",
|
|
171
171
|
"memoize-one": "^5.0.0",
|
|
172
172
|
"metro-runtime": "^0.87.0",
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
"whatwg-fetch": "^3.0.0",
|
|
185
185
|
"ws": "^7.5.10",
|
|
186
186
|
"yargs": "^17.6.2",
|
|
187
|
-
"@react-native-tvos/virtualized-lists": "0.87.
|
|
187
|
+
"@react-native-tvos/virtualized-lists": "0.87.1-0"
|
|
188
188
|
},
|
|
189
189
|
"codegenConfig": {
|
|
190
190
|
"libraries": [
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
require "json"
|
|
7
7
|
require 'net/http'
|
|
8
8
|
require 'rexml/document'
|
|
9
|
-
require 'shellwords'
|
|
10
9
|
|
|
11
10
|
require_relative './utils.rb'
|
|
12
11
|
|
|
@@ -34,38 +33,26 @@ def add_rn_third_party_dependencies(s)
|
|
|
34
33
|
s.dependency "RCT-Folly/Fabric"
|
|
35
34
|
end
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
header_search_paths << "$(PODS_ROOT)/fast_float/include"
|
|
47
|
-
header_search_paths << "$(PODS_ROOT)/fmt/include"
|
|
48
|
-
header_search_paths << "$(PODS_ROOT)/SocketRocket"
|
|
49
|
-
header_search_paths << "$(PODS_ROOT)/RCT-Folly"
|
|
50
|
-
|
|
51
|
-
# uniq so a second call on the same spec can't duplicate entries.
|
|
52
|
-
current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] = header_search_paths.uniq
|
|
36
|
+
ReactNativeDependenciesUtils.append_header_search_paths(current_pod_target_xcconfig, [
|
|
37
|
+
"$(PODS_ROOT)/glog",
|
|
38
|
+
"$(PODS_ROOT)/boost",
|
|
39
|
+
"$(PODS_ROOT)/DoubleConversion",
|
|
40
|
+
"$(PODS_ROOT)/fast_float/include",
|
|
41
|
+
"$(PODS_ROOT)/fmt/include",
|
|
42
|
+
"$(PODS_ROOT)/SocketRocket",
|
|
43
|
+
"$(PODS_ROOT)/RCT-Folly",
|
|
44
|
+
])
|
|
53
45
|
else
|
|
54
46
|
# Prebuilt-deps mode: this pod SELF-SERVES the third-party headers from its
|
|
55
47
|
# own xcframework (incl. SocketRocket - sole supplier in this mode). See
|
|
56
48
|
# scripts/cocoapods/__docs__/prebuilt-deps.md for the full contract.
|
|
57
49
|
s.dependency "ReactNativeDependencies"
|
|
58
50
|
|
|
59
|
-
header_search_paths = current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] || []
|
|
60
|
-
if header_search_paths.is_a?(String)
|
|
61
|
-
header_search_paths = Shellwords.shellsplit(header_search_paths)
|
|
62
|
-
end
|
|
63
51
|
# Artifact headers are flattened into the pod-local Headers/ by the podspec
|
|
64
52
|
# prepare_command (see __docs__/prebuilt-deps.md).
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] = header_search_paths.uniq
|
|
53
|
+
ReactNativeDependenciesUtils.append_header_search_paths(current_pod_target_xcconfig, [
|
|
54
|
+
"$(PODS_ROOT)/ReactNativeDependencies/Headers",
|
|
55
|
+
])
|
|
69
56
|
end
|
|
70
57
|
|
|
71
58
|
s.pod_target_xcconfig = current_pod_target_xcconfig
|
|
@@ -148,6 +135,25 @@ class ReactNativeDependenciesUtils
|
|
|
148
135
|
end
|
|
149
136
|
end
|
|
150
137
|
|
|
138
|
+
# Xcode splits HEADER_SEARCH_PATHS on whitespace, so every path we add is
|
|
139
|
+
# quoted - PODS_ROOT can expand to a directory with spaces in its name.
|
|
140
|
+
# Paths already in the xcconfig are left untouched: they carry the podspec
|
|
141
|
+
# author's own quoting, and re-quoting them would break it.
|
|
142
|
+
def self.append_header_search_paths(xcconfig, paths)
|
|
143
|
+
quoted = paths.map { |path| "\"#{path}\"" }
|
|
144
|
+
existing = xcconfig["HEADER_SEARCH_PATHS"]
|
|
145
|
+
|
|
146
|
+
# reject so a second call on the same spec can't duplicate entries.
|
|
147
|
+
case existing
|
|
148
|
+
when nil
|
|
149
|
+
xcconfig["HEADER_SEARCH_PATHS"] = quoted
|
|
150
|
+
when Array
|
|
151
|
+
xcconfig["HEADER_SEARCH_PATHS"] = existing + quoted.reject { |path| existing.include?(path) }
|
|
152
|
+
else
|
|
153
|
+
xcconfig["HEADER_SEARCH_PATHS"] = ([existing] + quoted.reject { |path| existing.include?(path) }).join(" ")
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
151
157
|
def self.abort_if_use_local_rndeps_with_no_file()
|
|
152
158
|
if !File.exist?(ENV["RCT_USE_LOCAL_RN_DEP"])
|
|
153
159
|
abort("RCT_USE_LOCAL_RN_DEP is set to #{ENV["RCT_USE_LOCAL_RN_DEP"]} but the file does not exist!")
|
|
@@ -18,6 +18,9 @@ const yargs = require('yargs');
|
|
|
18
18
|
|
|
19
19
|
const LAST_BUILD_FILENAME = 'React-Core-prebuilt/.last_build_configuration';
|
|
20
20
|
|
|
21
|
+
// Not a valid configuration, so finding it means the swap did not finish.
|
|
22
|
+
const REPLACEMENT_IN_PROGRESS = 'in-progress';
|
|
23
|
+
|
|
21
24
|
function validateBuildConfiguration(configuration /*: string */) {
|
|
22
25
|
if (!['Debug', 'Release'].includes(configuration)) {
|
|
23
26
|
throw new Error(`Invalid configuration ${configuration}`);
|
|
@@ -42,10 +45,12 @@ function shouldReplaceRnCoreConfiguration(configuration /*: string */) {
|
|
|
42
45
|
);
|
|
43
46
|
return false;
|
|
44
47
|
}
|
|
48
|
+
return true;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
//
|
|
48
|
-
|
|
51
|
+
// With no marker the on-disk flavor is Debug: the podspec installs the debug
|
|
52
|
+
// tarball (see resolve_podspec_source in scripts/cocoapods/rncore.rb).
|
|
53
|
+
if (configuration === 'Debug') {
|
|
49
54
|
console.log(
|
|
50
55
|
'No previous build detected, but Debug Configuration. No need to replace React-Core-prebuilt',
|
|
51
56
|
);
|
|
@@ -130,6 +135,10 @@ function updateLastBuildConfiguration(configuration /*: string */) {
|
|
|
130
135
|
fs.writeFileSync(LAST_BUILD_FILENAME, configuration);
|
|
131
136
|
}
|
|
132
137
|
|
|
138
|
+
function markReplacementInProgress() /*: void */ {
|
|
139
|
+
fs.writeFileSync(LAST_BUILD_FILENAME, REPLACEMENT_IN_PROGRESS);
|
|
140
|
+
}
|
|
141
|
+
|
|
133
142
|
function main(
|
|
134
143
|
configuration /*: string */,
|
|
135
144
|
version /*: string */,
|
|
@@ -139,9 +148,16 @@ function main(
|
|
|
139
148
|
validateVersion(version);
|
|
140
149
|
|
|
141
150
|
if (!shouldReplaceRnCoreConfiguration(configuration)) {
|
|
151
|
+
// A fresh install leaves no marker; record the flavor we skipped on.
|
|
152
|
+
if (!fs.existsSync(LAST_BUILD_FILENAME)) {
|
|
153
|
+
updateLastBuildConfiguration(configuration);
|
|
154
|
+
}
|
|
142
155
|
return;
|
|
143
156
|
}
|
|
144
157
|
|
|
158
|
+
// Invalidate before touching the framework so an interrupted swap is
|
|
159
|
+
// detectable on the next run.
|
|
160
|
+
markReplacementInProgress();
|
|
145
161
|
replaceRNCoreConfiguration(configuration, version, podsRoot);
|
|
146
162
|
updateLastBuildConfiguration(configuration);
|
|
147
163
|
console.log('Done replacing React Native prebuilt');
|
|
@@ -44,8 +44,10 @@
|
|
|
44
44
|
* directing you to `--deintegrate`).
|
|
45
45
|
*
|
|
46
46
|
* Options:
|
|
47
|
-
* --version <ver> React Native version
|
|
48
|
-
*
|
|
47
|
+
* --version <ver> React Native version. Pinned into
|
|
48
|
+
* .spm-injected.json and reused by later runs
|
|
49
|
+
* until a new one is passed (default: the
|
|
50
|
+
* resolved node_modules/react-native version).
|
|
49
51
|
* --yes Skip the dirty-pbxproj confirmation prompt.
|
|
50
52
|
* [add] --xcodeproj <path> Which .xcodeproj to inject into (when several).
|
|
51
53
|
* [add] --product-name <name> Which app target to inject into (when several).
|
|
@@ -96,6 +98,7 @@ const {
|
|
|
96
98
|
cleanupLeftoverPodsGroup,
|
|
97
99
|
findInjectedXcodeproj,
|
|
98
100
|
injectSpmIntoExistingXcodeproj,
|
|
101
|
+
readArtifactsVersionOverride,
|
|
99
102
|
readPinnedConfigCommand,
|
|
100
103
|
removeSpmInjection,
|
|
101
104
|
} = require('./spm/generate-spm-xcodeproj');
|
|
@@ -153,7 +156,7 @@ function parseArgs(argv /*: Array<string> */) /*: SetupArgs */ {
|
|
|
153
156
|
.option('version', {
|
|
154
157
|
type: 'string',
|
|
155
158
|
describe:
|
|
156
|
-
'React Native version (e.g. 0.80.0). Defaults to the version in node_modules/react-native/package.json',
|
|
159
|
+
'React Native version (e.g. 0.80.0). Sticks: later runs reuse it until you pass a new one. Defaults to the version in node_modules/react-native/package.json',
|
|
157
160
|
})
|
|
158
161
|
.option('yes', {
|
|
159
162
|
type: 'boolean',
|
|
@@ -377,19 +380,31 @@ function resolveReactNativeRoot(
|
|
|
377
380
|
return reactNativeRoot;
|
|
378
381
|
}
|
|
379
382
|
|
|
383
|
+
// Explicit `--version` → the version an earlier `--version` pinned into the
|
|
384
|
+
// injection marker → node_modules/react-native/package.json. The pin makes
|
|
385
|
+
// `--version` stick for later flagless runs, which would otherwise re-point the
|
|
386
|
+
// project at a different artifact slot than the one it was wired to.
|
|
380
387
|
function determineVersion(
|
|
381
388
|
args /*: SetupArgs */,
|
|
382
389
|
reactNativeRoot /*: string */,
|
|
390
|
+
appRoot /*: string */,
|
|
383
391
|
) /*: string */ {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
392
|
+
if (args.version != null) {
|
|
393
|
+
return args.version;
|
|
394
|
+
}
|
|
395
|
+
const pinned = readArtifactsVersionOverride(appRoot);
|
|
396
|
+
if (pinned != null) {
|
|
397
|
+
log(
|
|
398
|
+
`Using version ${pinned} pinned in ${SPM_INJECTED_MARKER} by an earlier ` +
|
|
399
|
+
'--version. Pass --version to change it.',
|
|
389
400
|
);
|
|
390
|
-
|
|
401
|
+
return pinned;
|
|
391
402
|
}
|
|
392
|
-
|
|
403
|
+
// $FlowFixMe[incompatible-type] JSON.parse returns any
|
|
404
|
+
const pkgJson /*: {version: string} */ = JSON.parse(
|
|
405
|
+
fs.readFileSync(path.join(reactNativeRoot, 'package.json'), 'utf8'),
|
|
406
|
+
);
|
|
407
|
+
return pkgJson.version;
|
|
393
408
|
}
|
|
394
409
|
|
|
395
410
|
function runCodegenStep(
|
|
@@ -442,7 +457,7 @@ async function runScaffold(
|
|
|
442
457
|
// a comment — that's how SPM's manifest hash bumps on slot transitions.
|
|
443
458
|
let cacheSlotLabel /*: ?string */ = null;
|
|
444
459
|
try {
|
|
445
|
-
const rawVersion =
|
|
460
|
+
const rawVersion = determineVersion(args, reactNativeRoot, appRoot);
|
|
446
461
|
const slotVersion = await resolveCacheSlotVersion(rawVersion);
|
|
447
462
|
cacheSlotLabel = `${slotVersion}/dual-flavor`;
|
|
448
463
|
} catch {
|
|
@@ -1094,7 +1109,7 @@ async function main(argv /*:: ?: Array<string> */) /*: Promise<void> */ {
|
|
|
1094
1109
|
autolinkingConfigResult,
|
|
1095
1110
|
projectRoot,
|
|
1096
1111
|
);
|
|
1097
|
-
const version = determineVersion(args, reactNativeRoot);
|
|
1112
|
+
const version = determineVersion(args, reactNativeRoot, appRoot);
|
|
1098
1113
|
log(`React Native version: ${version}`);
|
|
1099
1114
|
|
|
1100
1115
|
// Resolve remote SPM mode ONCE up front. remotePackageConfig throws
|
|
@@ -1256,6 +1271,7 @@ if (require.main === module) {
|
|
|
1256
1271
|
module.exports = {
|
|
1257
1272
|
main,
|
|
1258
1273
|
detectStandardRnLayoutRedirect,
|
|
1274
|
+
determineVersion,
|
|
1259
1275
|
findInjectedXcodeproj,
|
|
1260
1276
|
generateAutolinkingConfigOrFailClosed,
|
|
1261
1277
|
parseArgs,
|