react-native-tvos 0.83.2-0 → 0.83.4-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/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +1 -0
- package/Libraries/Components/ScrollView/ScrollView.d.ts +2 -1
- package/Libraries/Components/ScrollView/ScrollView.js +8 -1
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +2 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponentType.js +2 -1
- package/Libraries/Components/TV/TVViewPropTypes.js +7 -0
- package/Libraries/Components/View/View.js +6 -0
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Core/setUpReactDevTools.js +23 -6
- package/Libraries/NativeComponent/TVViewConfig.js +1 -0
- package/Libraries/Network/RCTHTTPRequestHandler.h +9 -0
- package/Libraries/Network/RCTHTTPRequestHandler.mm +15 -1
- package/Libraries/Pressability/Pressability.js +7 -0
- package/Libraries/WebSocket/RCTReconnectingWebSocket.m +4 -1
- package/React/Base/RCTBundleURLProvider.mm +5 -3
- package/React/Base/RCTDevSupportHttpHeaders.h +24 -0
- package/React/Base/RCTDevSupportHttpHeaders.m +65 -0
- package/React/Base/RCTMultipartDataTask.h +9 -0
- package/React/Base/RCTMultipartDataTask.m +16 -1
- package/React/Base/RCTVersion.m +1 -1
- package/React/CoreModules/RCTWebSocketModule.h +6 -0
- package/React/CoreModules/RCTWebSocketModule.mm +14 -1
- package/React/DevSupport/RCTInspectorDevServerHelper.mm +33 -22
- package/React/DevSupport/RCTInspectorNetworkHelper.mm +2 -0
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.h +1 -0
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm +3 -0
- package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +110 -4
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +2 -0
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +31 -4
- package/React/Inspector/RCTCxxInspectorWebSocketAdapter.mm +5 -1
- package/ReactAndroid/api/ReactAndroid.api +1 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/CxxInspectorPackagerConnection.kt +2 -8
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.kt +17 -13
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/PackagerStatusCheck.kt +10 -19
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxContentView.kt +2 -2
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/DevSupportHttpClient.kt +49 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt +1 -12
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.kt +3 -4
- package/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/JSPackagerClient.kt +2 -1
- package/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/ReconnectingWebSocket.kt +2 -8
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +49 -5
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt +7 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +46 -4
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt +69 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt +7 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt +1 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +4 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.cpp +10 -0
- package/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.h +1 -0
- package/ReactCommon/react/renderer/components/scrollview/conversions.h +6 -0
- package/ReactCommon/react/renderer/components/scrollview/platform/android/react/renderer/components/scrollview/HostPlatformScrollViewProps.cpp +18 -1
- package/ReactCommon/react/renderer/components/scrollview/platform/android/react/renderer/components/scrollview/HostPlatformScrollViewProps.h +2 -0
- package/ReactCommon/react/renderer/components/scrollview/primitives.h +1 -1
- package/ReactCommon/react/renderer/components/view/BaseViewProps.cpp +11 -1
- package/ReactCommon/react/renderer/components/view/BaseViewProps.h +4 -0
- package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp +18 -0
- package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.h +1 -0
- package/package.json +8 -8
- package/scripts/replace-rncore-version.js +62 -8
- package/settings.gradle.kts +21 -1
- package/types/public/ReactNativeTVTypes.d.ts +19 -2
package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
CHANGED
|
@@ -10,6 +10,7 @@ package com.facebook.react.views.scroll;
|
|
|
10
10
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_CENTER;
|
|
11
11
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_DISABLED;
|
|
12
12
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_END;
|
|
13
|
+
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_ITEM;
|
|
13
14
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_START;
|
|
14
15
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.findNextFocusableView;
|
|
15
16
|
|
|
@@ -134,6 +135,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
|
|
134
135
|
private @Nullable MaintainVisibleScrollPositionHelper mMaintainVisibleContentPositionHelper;
|
|
135
136
|
private int mFadingEdgeLengthStart = 0;
|
|
136
137
|
private int mFadingEdgeLengthEnd = 0;
|
|
138
|
+
private int mSnapToItemPadding;
|
|
137
139
|
|
|
138
140
|
public ReactHorizontalScrollView(Context context) {
|
|
139
141
|
this(context, null);
|
|
@@ -382,6 +384,10 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
|
|
382
384
|
invalidate();
|
|
383
385
|
}
|
|
384
386
|
|
|
387
|
+
public void setSnapToItemPadding(int snapToItemPadding) {
|
|
388
|
+
mSnapToItemPadding = snapToItemPadding;
|
|
389
|
+
}
|
|
390
|
+
|
|
385
391
|
@Override
|
|
386
392
|
protected float getLeftFadingEdgeStrength() {
|
|
387
393
|
float max = Math.max(mFadingEdgeLengthStart, mFadingEdgeLengthEnd);
|
|
@@ -538,6 +544,40 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
|
|
538
544
|
}
|
|
539
545
|
}
|
|
540
546
|
|
|
547
|
+
/**
|
|
548
|
+
* Attempts to scroll-snap to the focused child based on snapToAlignment/scrollSnapAlign.
|
|
549
|
+
* Returns true if snap scrolling was performed, false otherwise.
|
|
550
|
+
*/
|
|
551
|
+
private boolean tryScrollSnapToChild(View focused) {
|
|
552
|
+
if (mSnapToAlignment != SNAP_ALIGNMENT_ITEM) {
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
kotlin.Pair<View, String> result = ReactScrollViewHelper.findScrollSnapAlign(focused, this);
|
|
557
|
+
if (result == null) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
View snapTarget = result.getFirst();
|
|
562
|
+
String alignment = result.getSecond();
|
|
563
|
+
|
|
564
|
+
Rect rect = new Rect();
|
|
565
|
+
snapTarget.getDrawingRect(rect);
|
|
566
|
+
offsetDescendantRectToMyCoords(snapTarget, rect);
|
|
567
|
+
|
|
568
|
+
int viewportWidth = getWidth() - getPaddingLeft() - getPaddingRight();
|
|
569
|
+
int maxScrollX = Math.max(0, computeHorizontalScrollRange() - getWidth());
|
|
570
|
+
|
|
571
|
+
Integer targetOffset = ReactScrollViewHelper.computeScrollSnapOffset(
|
|
572
|
+
rect.left, rect.right, viewportWidth, alignment, mSnapInterval, mSnapToItemPadding, maxScrollX);
|
|
573
|
+
if (targetOffset == null) {
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
reactSmoothScrollTo(targetOffset, getScrollY());
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
|
|
541
581
|
/**
|
|
542
582
|
* Since ReactHorizontalScrollView handles layout changes on JS side, it does not call
|
|
543
583
|
* super.onlayout due to which mIsLayoutDirty flag in HorizontalScrollView remains true and
|
|
@@ -547,8 +587,12 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
|
|
547
587
|
*/
|
|
548
588
|
@Override
|
|
549
589
|
public void requestChildFocus(View child, View focused) {
|
|
550
|
-
if (focused != null
|
|
551
|
-
|
|
590
|
+
if (focused != null) {
|
|
591
|
+
if (!tryScrollSnapToChild(focused)) {
|
|
592
|
+
if (!mPagingEnabled) {
|
|
593
|
+
scrollToChild(focused);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
552
596
|
}
|
|
553
597
|
requestChildFocusWithoutScroll(child, focused);
|
|
554
598
|
}
|
|
@@ -832,7 +876,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
|
|
832
876
|
&& (mPagingEnabled
|
|
833
877
|
|| mSnapInterval != 0
|
|
834
878
|
|| mSnapOffsets != null
|
|
835
|
-
|| mSnapToAlignment != SNAP_ALIGNMENT_DISABLED)) {
|
|
879
|
+
|| (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED && mSnapToAlignment != SNAP_ALIGNMENT_ITEM))) {
|
|
836
880
|
// Cancel any pending runnable and reschedule
|
|
837
881
|
if (mPostTouchRunnable != null) {
|
|
838
882
|
removeCallbacks(mPostTouchRunnable);
|
|
@@ -1280,7 +1324,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
|
|
1280
1324
|
}
|
|
1281
1325
|
|
|
1282
1326
|
// pagingEnabled only allows snapping one interval at a time
|
|
1283
|
-
if (mSnapInterval == 0 && mSnapOffsets == null && mSnapToAlignment == SNAP_ALIGNMENT_DISABLED) {
|
|
1327
|
+
if (mSnapInterval == 0 && mSnapOffsets == null && (mSnapToAlignment == SNAP_ALIGNMENT_DISABLED || mSnapToAlignment == SNAP_ALIGNMENT_ITEM)) {
|
|
1284
1328
|
smoothScrollAndSnap(velocityX);
|
|
1285
1329
|
return;
|
|
1286
1330
|
}
|
|
@@ -1324,7 +1368,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
|
|
1324
1368
|
}
|
|
1325
1369
|
}
|
|
1326
1370
|
}
|
|
1327
|
-
} else if (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED) {
|
|
1371
|
+
} else if (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED && mSnapToAlignment != SNAP_ALIGNMENT_ITEM) {
|
|
1328
1372
|
if (mSnapInterval > 0) {
|
|
1329
1373
|
double ratio = (double) targetOffset / mSnapInterval;
|
|
1330
1374
|
smallerOffset =
|
|
@@ -157,6 +157,13 @@ constructor(private val fpsListener: FpsListener? = null) :
|
|
|
157
157
|
view.setSnapToEnd(snapToEnd)
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
@ReactProp(name = "snapToItemPadding")
|
|
161
|
+
public fun setSnapToItemPadding(view: ReactHorizontalScrollView, value: Float) {
|
|
162
|
+
val density = getDisplayMetricDensity()
|
|
163
|
+
val px = (value * density).toInt()
|
|
164
|
+
view.setSnapToItemPadding(px)
|
|
165
|
+
}
|
|
166
|
+
|
|
160
167
|
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
|
|
161
168
|
public fun setRemoveClippedSubviews(
|
|
162
169
|
view: ReactHorizontalScrollView,
|
|
@@ -10,6 +10,7 @@ package com.facebook.react.views.scroll;
|
|
|
10
10
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_CENTER;
|
|
11
11
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_DISABLED;
|
|
12
12
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_END;
|
|
13
|
+
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_ITEM;
|
|
13
14
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.SNAP_ALIGNMENT_START;
|
|
14
15
|
import static com.facebook.react.views.scroll.ReactScrollViewHelper.findNextFocusableView;
|
|
15
16
|
|
|
@@ -132,6 +133,7 @@ public class ReactScrollView extends ScrollView
|
|
|
132
133
|
private @Nullable MaintainVisibleScrollPositionHelper mMaintainVisibleContentPositionHelper;
|
|
133
134
|
private int mFadingEdgeLengthStart;
|
|
134
135
|
private int mFadingEdgeLengthEnd;
|
|
136
|
+
private int mSnapToItemPadding;
|
|
135
137
|
|
|
136
138
|
public ReactScrollView(Context context) {
|
|
137
139
|
this(context, null);
|
|
@@ -352,6 +354,10 @@ public class ReactScrollView extends ScrollView
|
|
|
352
354
|
invalidate();
|
|
353
355
|
}
|
|
354
356
|
|
|
357
|
+
public void setSnapToItemPadding(int snapToItemPadding) {
|
|
358
|
+
mSnapToItemPadding = snapToItemPadding;
|
|
359
|
+
}
|
|
360
|
+
|
|
355
361
|
@Override
|
|
356
362
|
protected float getTopFadingEdgeStrength() {
|
|
357
363
|
float max = Math.max(mFadingEdgeLengthStart, mFadingEdgeLengthEnd);
|
|
@@ -499,6 +505,40 @@ public class ReactScrollView extends ScrollView
|
|
|
499
505
|
return nextFocus;
|
|
500
506
|
}
|
|
501
507
|
|
|
508
|
+
/**
|
|
509
|
+
* Attempts to scroll-snap to the focused child based on snapToAlignment/scrollSnapAlign.
|
|
510
|
+
* Returns true if snap scrolling was performed, false otherwise.
|
|
511
|
+
*/
|
|
512
|
+
private boolean tryScrollSnapToChild(View focused) {
|
|
513
|
+
if (mSnapToAlignment != SNAP_ALIGNMENT_ITEM) {
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
kotlin.Pair<View, String> result = ReactScrollViewHelper.findScrollSnapAlign(focused, this);
|
|
518
|
+
if (result == null) {
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
View snapTarget = result.getFirst();
|
|
523
|
+
String alignment = result.getSecond();
|
|
524
|
+
|
|
525
|
+
Rect rect = new Rect();
|
|
526
|
+
snapTarget.getDrawingRect(rect);
|
|
527
|
+
offsetDescendantRectToMyCoords(snapTarget, rect);
|
|
528
|
+
|
|
529
|
+
int viewportHeight = getHeight() - getPaddingTop() - getPaddingBottom();
|
|
530
|
+
int maxScrollY = getMaxScrollY();
|
|
531
|
+
|
|
532
|
+
Integer targetOffset = ReactScrollViewHelper.computeScrollSnapOffset(
|
|
533
|
+
rect.top, rect.bottom, viewportHeight, alignment, mSnapInterval, mSnapToItemPadding, maxScrollY);
|
|
534
|
+
if (targetOffset == null) {
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
reactSmoothScrollTo(getScrollX(), targetOffset);
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
|
|
502
542
|
/**
|
|
503
543
|
* Since ReactScrollView handles layout changes on JS side, it does not call super.onlayout due to
|
|
504
544
|
* which mIsLayoutDirty flag in ScrollView remains true and prevents scrolling to child when
|
|
@@ -509,7 +549,9 @@ public class ReactScrollView extends ScrollView
|
|
|
509
549
|
@Override
|
|
510
550
|
public void requestChildFocus(View child, View focused) {
|
|
511
551
|
if (focused != null) {
|
|
512
|
-
|
|
552
|
+
if (!tryScrollSnapToChild(focused)) {
|
|
553
|
+
scrollToChild(focused);
|
|
554
|
+
}
|
|
513
555
|
}
|
|
514
556
|
requestChildFocusWithoutScroll(child, focused);
|
|
515
557
|
}
|
|
@@ -686,7 +728,7 @@ public class ReactScrollView extends ScrollView
|
|
|
686
728
|
&& (mPagingEnabled
|
|
687
729
|
|| mSnapInterval != 0
|
|
688
730
|
|| mSnapOffsets != null
|
|
689
|
-
|| mSnapToAlignment != SNAP_ALIGNMENT_DISABLED)) {
|
|
731
|
+
|| (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED && mSnapToAlignment != SNAP_ALIGNMENT_ITEM))) {
|
|
690
732
|
// Cancel any pending post-touch runnable and reschedule
|
|
691
733
|
if (mPostTouchRunnable != null) {
|
|
692
734
|
removeCallbacks(mPostTouchRunnable);
|
|
@@ -1043,7 +1085,7 @@ public class ReactScrollView extends ScrollView
|
|
|
1043
1085
|
}
|
|
1044
1086
|
|
|
1045
1087
|
// pagingEnabled only allows snapping one interval at a time
|
|
1046
|
-
if (mSnapInterval == 0 && mSnapOffsets == null && mSnapToAlignment == SNAP_ALIGNMENT_DISABLED) {
|
|
1088
|
+
if (mSnapInterval == 0 && mSnapOffsets == null && (mSnapToAlignment == SNAP_ALIGNMENT_DISABLED || mSnapToAlignment == SNAP_ALIGNMENT_ITEM)) {
|
|
1047
1089
|
smoothScrollAndSnap(velocityY);
|
|
1048
1090
|
return;
|
|
1049
1091
|
}
|
|
@@ -1082,7 +1124,7 @@ public class ReactScrollView extends ScrollView
|
|
|
1082
1124
|
}
|
|
1083
1125
|
}
|
|
1084
1126
|
|
|
1085
|
-
} else if (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED) {
|
|
1127
|
+
} else if (mSnapToAlignment != SNAP_ALIGNMENT_DISABLED && mSnapToAlignment != SNAP_ALIGNMENT_ITEM) {
|
|
1086
1128
|
if (mSnapInterval > 0) {
|
|
1087
1129
|
double ratio = (double) targetOffset / mSnapInterval;
|
|
1088
1130
|
smallerOffset =
|
|
@@ -11,6 +11,7 @@ import android.animation.Animator
|
|
|
11
11
|
import android.animation.ValueAnimator
|
|
12
12
|
import android.content.Context
|
|
13
13
|
import android.graphics.Point
|
|
14
|
+
import android.graphics.Rect
|
|
14
15
|
import android.os.Build
|
|
15
16
|
import android.view.View
|
|
16
17
|
import android.view.ViewGroup
|
|
@@ -32,6 +33,7 @@ import com.facebook.react.uimanager.StateWrapper
|
|
|
32
33
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
33
34
|
import com.facebook.react.uimanager.common.UIManagerType
|
|
34
35
|
import com.facebook.react.uimanager.common.ViewUtil
|
|
36
|
+
import com.facebook.react.views.view.ReactViewGroup
|
|
35
37
|
import java.lang.ref.WeakReference
|
|
36
38
|
import java.util.concurrent.CopyOnWriteArrayList
|
|
37
39
|
import kotlin.math.abs
|
|
@@ -54,6 +56,7 @@ public object ReactScrollViewHelper {
|
|
|
54
56
|
public const val SNAP_ALIGNMENT_START: Int = 1
|
|
55
57
|
public const val SNAP_ALIGNMENT_CENTER: Int = 2
|
|
56
58
|
public const val SNAP_ALIGNMENT_END: Int = 3
|
|
59
|
+
public const val SNAP_ALIGNMENT_ITEM: Int = 4
|
|
57
60
|
|
|
58
61
|
// Support global native listeners for scroll events
|
|
59
62
|
private val scrollListeners = CopyOnWriteArrayList<WeakReference<ScrollListener>>()
|
|
@@ -209,6 +212,8 @@ public object ReactScrollViewHelper {
|
|
|
209
212
|
SNAP_ALIGNMENT_CENTER
|
|
210
213
|
} else if ("end" == alignment) {
|
|
211
214
|
SNAP_ALIGNMENT_END
|
|
215
|
+
} else if ("item".equals(alignment, ignoreCase = true)) {
|
|
216
|
+
SNAP_ALIGNMENT_ITEM
|
|
212
217
|
} else {
|
|
213
218
|
FLog.w(ReactConstants.TAG, "wrong snap alignment value: $alignment")
|
|
214
219
|
SNAP_ALIGNMENT_DISABLED
|
|
@@ -569,6 +574,70 @@ public object ReactScrollViewHelper {
|
|
|
569
574
|
return host.findViewById(nextFocusableViewId)
|
|
570
575
|
}
|
|
571
576
|
|
|
577
|
+
/**
|
|
578
|
+
* Walks up the view hierarchy from the focused view to find a ReactViewGroup with
|
|
579
|
+
* scrollSnapAlign set. Returns a Pair of (snapTarget, alignment) or null if not found.
|
|
580
|
+
*
|
|
581
|
+
* Shared by [ReactScrollView] and [ReactHorizontalScrollView].
|
|
582
|
+
*/
|
|
583
|
+
@JvmStatic
|
|
584
|
+
public fun findScrollSnapAlign(focused: View, scrollView: ViewGroup): Pair<View, String>? {
|
|
585
|
+
var view: View? = focused
|
|
586
|
+
var snapTarget: View? = null
|
|
587
|
+
var alignment: String? = null
|
|
588
|
+
while (view != null && view !== scrollView) {
|
|
589
|
+
if (view is ReactViewGroup) {
|
|
590
|
+
val snap = view.scrollSnapAlign
|
|
591
|
+
if (snap != null) {
|
|
592
|
+
alignment = snap
|
|
593
|
+
snapTarget = view
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
val parent = view.parent
|
|
597
|
+
view = if (parent is View) parent else null
|
|
598
|
+
}
|
|
599
|
+
return if (alignment != null && snapTarget != null) Pair(snapTarget, alignment) else null
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Computes the target scroll offset for scroll-snap based on the focused view's position,
|
|
604
|
+
* alignment, snap interval, scroll padding, and maximum scroll range.
|
|
605
|
+
*
|
|
606
|
+
* Returns the clamped target offset, or null if the alignment is unknown.
|
|
607
|
+
*
|
|
608
|
+
* Shared by [ReactScrollView] and [ReactHorizontalScrollView].
|
|
609
|
+
*
|
|
610
|
+
* @param focusedStart the start coordinate of the snap target in scroll view coordinates
|
|
611
|
+
* @param focusedEnd the end coordinate of the snap target in scroll view coordinates
|
|
612
|
+
* @param viewportSize the visible viewport size on the scroll axis
|
|
613
|
+
* @param alignment the scrollSnapAlign value ("start", "center", or "end")
|
|
614
|
+
* @param snapInterval the snap interval (0 if not set)
|
|
615
|
+
* @param snapToItemPadding the snap-to-item padding value
|
|
616
|
+
* @param maxScrollOffset the maximum scroll offset for clamping
|
|
617
|
+
*/
|
|
618
|
+
@JvmStatic
|
|
619
|
+
public fun computeScrollSnapOffset(
|
|
620
|
+
focusedStart: Int,
|
|
621
|
+
focusedEnd: Int,
|
|
622
|
+
viewportSize: Int,
|
|
623
|
+
alignment: String,
|
|
624
|
+
snapInterval: Int,
|
|
625
|
+
snapToItemPadding: Int,
|
|
626
|
+
maxScrollOffset: Int,
|
|
627
|
+
): Int? {
|
|
628
|
+
val focusedCenter = (focusedStart + focusedEnd) / 2
|
|
629
|
+
var targetOffset = when (alignment) {
|
|
630
|
+
"start" -> focusedStart - snapToItemPadding
|
|
631
|
+
"center" -> focusedCenter - (viewportSize / 2) + (snapToItemPadding / 2)
|
|
632
|
+
"end" -> focusedEnd - viewportSize + snapToItemPadding
|
|
633
|
+
else -> return null
|
|
634
|
+
}
|
|
635
|
+
if (snapInterval > 0) {
|
|
636
|
+
targetOffset = (Math.floor(targetOffset.toDouble() / snapInterval) * snapInterval).toInt()
|
|
637
|
+
}
|
|
638
|
+
return Math.max(0, Math.min(targetOffset, maxScrollOffset))
|
|
639
|
+
}
|
|
640
|
+
|
|
572
641
|
@JvmStatic
|
|
573
642
|
public fun resolveAbsoluteDirection(
|
|
574
643
|
@FocusRealDirection direction: Int,
|
package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt
CHANGED
|
@@ -141,6 +141,13 @@ constructor(private val fpsListener: FpsListener? = null) :
|
|
|
141
141
|
view.setSnapToEnd(snapToEnd)
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
@ReactProp(name = "snapToItemPadding")
|
|
145
|
+
public fun setSnapToItemPadding(view: ReactScrollView, value: Float) {
|
|
146
|
+
val density = getDisplayMetricDensity()
|
|
147
|
+
val px = (value * density).toInt()
|
|
148
|
+
view.setSnapToItemPadding(px)
|
|
149
|
+
}
|
|
150
|
+
|
|
144
151
|
@ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
|
|
145
152
|
public fun setRemoveClippedSubviews(view: ReactScrollView, removeClippedSubviews: Boolean) {
|
|
146
153
|
view.removeClippedSubviews = removeClippedSubviews
|
|
@@ -173,6 +173,7 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
|
|
173
173
|
private var childrenLayoutChangeListener: ChildrenLayoutChangeListener? = null
|
|
174
174
|
private var onInterceptTouchEventListener: OnInterceptTouchEventListener? = null
|
|
175
175
|
private var needsOffscreenAlphaCompositing = false
|
|
176
|
+
public var scrollSnapAlign: String? = null
|
|
176
177
|
private var backfaceOpacity = 0f
|
|
177
178
|
private var backfaceVisible = false
|
|
178
179
|
private var childrenRemovedWhileTransitioning: MutableSet<Int>? = null
|
|
@@ -190,6 +190,10 @@ public open class ReactViewManager : ReactClippingViewManager<ReactViewGroup>()
|
|
|
190
190
|
view.setTrapFocusRight(enabled)
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
@ReactProp(name = "scrollSnapAlign")
|
|
194
|
+
public open fun setScrollSnapAlign(view: ReactViewGroup, value: String?) {
|
|
195
|
+
view.scrollSnapAlign = value
|
|
196
|
+
}
|
|
193
197
|
|
|
194
198
|
@ReactProp(name = ViewProps.BACKGROUND_IMAGE, customType = "BackgroundImage")
|
|
195
199
|
public open fun setBackgroundImage(view: ReactViewGroup, backgroundImage: ReadableArray?) {
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
|
|
15
15
|
#define REACT_NATIVE_VERSION_MAJOR 0
|
|
16
16
|
#define REACT_NATIVE_VERSION_MINOR 83
|
|
17
|
-
#define REACT_NATIVE_VERSION_PATCH
|
|
17
|
+
#define REACT_NATIVE_VERSION_PATCH 4
|
|
18
18
|
|
|
19
19
|
namespace facebook::react {
|
|
20
20
|
|
|
21
21
|
constexpr struct {
|
|
22
22
|
int32_t Major = 0;
|
|
23
23
|
int32_t Minor = 83;
|
|
24
|
-
int32_t Patch =
|
|
24
|
+
int32_t Patch = 4;
|
|
25
25
|
std::string_view Prerelease = "0";
|
|
26
26
|
} ReactNativeVersion;
|
|
27
27
|
|
|
@@ -32,6 +32,15 @@ BaseScrollViewProps::BaseScrollViewProps(
|
|
|
32
32
|
"showsScrollIndex",
|
|
33
33
|
sourceProps.showsScrollIndex,
|
|
34
34
|
{})),
|
|
35
|
+
snapToItemPadding(
|
|
36
|
+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
|
|
37
|
+
? sourceProps.snapToItemPadding
|
|
38
|
+
: convertRawProp(
|
|
39
|
+
context,
|
|
40
|
+
rawProps,
|
|
41
|
+
"snapToItemPadding",
|
|
42
|
+
sourceProps.snapToItemPadding,
|
|
43
|
+
(Float)0)),
|
|
35
44
|
#endif
|
|
36
45
|
alwaysBounceHorizontal(
|
|
37
46
|
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
|
|
@@ -400,6 +409,7 @@ void BaseScrollViewProps::setProp(
|
|
|
400
409
|
switch (hash) {
|
|
401
410
|
#if TARGET_OS_TV
|
|
402
411
|
RAW_SET_PROP_SWITCH_CASE_BASIC(showsScrollIndex);
|
|
412
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToItemPadding);
|
|
403
413
|
#endif
|
|
404
414
|
RAW_SET_PROP_SWITCH_CASE_BASIC(alwaysBounceHorizontal);
|
|
405
415
|
RAW_SET_PROP_SWITCH_CASE_BASIC(alwaysBounceVertical);
|
|
@@ -30,6 +30,10 @@ inline void fromRawValue(const PropsParserContext &context, const RawValue &valu
|
|
|
30
30
|
result = ScrollViewSnapToAlignment::End;
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
+
if (string == "item") {
|
|
34
|
+
result = ScrollViewSnapToAlignment::Item;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
33
37
|
abort();
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -117,6 +121,8 @@ inline std::string toString(const ScrollViewSnapToAlignment &value)
|
|
|
117
121
|
return "center";
|
|
118
122
|
case ScrollViewSnapToAlignment::End:
|
|
119
123
|
return "end";
|
|
124
|
+
case ScrollViewSnapToAlignment::Item:
|
|
125
|
+
return "item";
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
|
|
@@ -65,7 +65,16 @@ HostPlatformScrollViewProps::HostPlatformScrollViewProps(
|
|
|
65
65
|
rawProps,
|
|
66
66
|
"endFillColor",
|
|
67
67
|
sourceProps.endFillColor,
|
|
68
|
-
clearColor()))
|
|
68
|
+
clearColor())),
|
|
69
|
+
snapToItemPadding(
|
|
70
|
+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
|
|
71
|
+
? sourceProps.snapToItemPadding
|
|
72
|
+
: convertRawProp(
|
|
73
|
+
context,
|
|
74
|
+
rawProps,
|
|
75
|
+
"snapToItemPadding",
|
|
76
|
+
sourceProps.snapToItemPadding,
|
|
77
|
+
{})) {}
|
|
69
78
|
|
|
70
79
|
void HostPlatformScrollViewProps::setProp(
|
|
71
80
|
const PropsParserContext& context,
|
|
@@ -85,6 +94,7 @@ void HostPlatformScrollViewProps::setProp(
|
|
|
85
94
|
RAW_SET_PROP_SWITCH_CASE_BASIC(fadingEdgeLength);
|
|
86
95
|
RAW_SET_PROP_SWITCH_CASE_BASIC(overScrollMode);
|
|
87
96
|
RAW_SET_PROP_SWITCH_CASE_BASIC(endFillColor);
|
|
97
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToItemPadding);
|
|
88
98
|
}
|
|
89
99
|
}
|
|
90
100
|
|
|
@@ -327,6 +337,9 @@ folly::dynamic HostPlatformScrollViewProps::getDiffProps(
|
|
|
327
337
|
case ScrollViewSnapToAlignment::End:
|
|
328
338
|
result["snapToAlignment"] = "end";
|
|
329
339
|
break;
|
|
340
|
+
case ScrollViewSnapToAlignment::Item:
|
|
341
|
+
result["snapToAlignment"] = "item";
|
|
342
|
+
break;
|
|
330
343
|
}
|
|
331
344
|
}
|
|
332
345
|
|
|
@@ -396,6 +409,10 @@ folly::dynamic HostPlatformScrollViewProps::getDiffProps(
|
|
|
396
409
|
result["endFillColor"] = *endFillColor;
|
|
397
410
|
}
|
|
398
411
|
|
|
412
|
+
if (snapToItemPadding != oldProps->snapToItemPadding) {
|
|
413
|
+
result["snapToItemPadding"] = snapToItemPadding;
|
|
414
|
+
}
|
|
415
|
+
|
|
399
416
|
return result;
|
|
400
417
|
}
|
|
401
418
|
|
|
@@ -33,6 +33,8 @@ class HostPlatformScrollViewProps : public BaseScrollViewProps {
|
|
|
33
33
|
std::string overScrollMode{"auto"};
|
|
34
34
|
SharedColor endFillColor{clearColor()};
|
|
35
35
|
|
|
36
|
+
Float snapToItemPadding{0};
|
|
37
|
+
|
|
36
38
|
#pragma mark - DebugStringConvertible
|
|
37
39
|
|
|
38
40
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
|
@@ -447,7 +447,16 @@ BaseViewProps::BaseViewProps(
|
|
|
447
447
|
rawProps,
|
|
448
448
|
"removeClippedSubviews",
|
|
449
449
|
sourceProps.removeClippedSubviews,
|
|
450
|
-
false))
|
|
450
|
+
false))
|
|
451
|
+
#if TARGET_OS_TV
|
|
452
|
+
,scrollSnapAlign(ReactNativeFeatureFlags::enableCppPropsIteratorSetter() ? sourceProps.scrollSnapAlign : convertRawProp(
|
|
453
|
+
context,
|
|
454
|
+
rawProps,
|
|
455
|
+
"scrollSnapAlign",
|
|
456
|
+
sourceProps.scrollSnapAlign,
|
|
457
|
+
{}))
|
|
458
|
+
#endif
|
|
459
|
+
{}
|
|
451
460
|
|
|
452
461
|
#define VIEW_EVENT_CASE(eventType) \
|
|
453
462
|
case CONSTEXPR_RAW_PROPS_KEY_HASH("on" #eventType): { \
|
|
@@ -518,6 +527,7 @@ void BaseViewProps::setProp(
|
|
|
518
527
|
RAW_SET_PROP_SWITCH_CASE_BASIC(trapFocusDown);
|
|
519
528
|
RAW_SET_PROP_SWITCH_CASE_BASIC(trapFocusLeft);
|
|
520
529
|
RAW_SET_PROP_SWITCH_CASE_BASIC(trapFocusRight);
|
|
530
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollSnapAlign);
|
|
521
531
|
#endif
|
|
522
532
|
// events field
|
|
523
533
|
VIEW_EVENT_CASE(PointerEnter);
|
|
@@ -124,6 +124,10 @@ class BaseViewProps : public YogaStylableProps, public AccessibilityProps {
|
|
|
124
124
|
|
|
125
125
|
bool removeClippedSubviews{false};
|
|
126
126
|
|
|
127
|
+
#if TARGET_OS_TV
|
|
128
|
+
std::optional<std::string> scrollSnapAlign;
|
|
129
|
+
#endif
|
|
130
|
+
|
|
127
131
|
#pragma mark - Convenience Methods
|
|
128
132
|
|
|
129
133
|
CascadedBorderWidths getBorderWidths() const;
|
|
@@ -99,6 +99,15 @@ HostPlatformViewProps::HostPlatformViewProps(
|
|
|
99
99
|
"trapFocusRight",
|
|
100
100
|
sourceProps.trapFocusRight,
|
|
101
101
|
false)),
|
|
102
|
+
scrollSnapAlign(
|
|
103
|
+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
|
|
104
|
+
? sourceProps.scrollSnapAlign
|
|
105
|
+
: convertRawProp(
|
|
106
|
+
context,
|
|
107
|
+
rawProps,
|
|
108
|
+
"scrollSnapAlign",
|
|
109
|
+
sourceProps.scrollSnapAlign,
|
|
110
|
+
{})),
|
|
102
111
|
needsOffscreenAlphaCompositing(
|
|
103
112
|
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
|
|
104
113
|
? sourceProps.needsOffscreenAlphaCompositing
|
|
@@ -201,6 +210,7 @@ void HostPlatformViewProps::setProp(
|
|
|
201
210
|
RAW_SET_PROP_SWITCH_CASE(nativeForeground, "nativeForegroundAndroid");
|
|
202
211
|
RAW_SET_PROP_SWITCH_CASE_BASIC(focusable);
|
|
203
212
|
RAW_SET_PROP_SWITCH_CASE_BASIC(hasTVPreferredFocus);
|
|
213
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollSnapAlign);
|
|
204
214
|
RAW_SET_PROP_SWITCH_CASE_BASIC(needsOffscreenAlphaCompositing);
|
|
205
215
|
RAW_SET_PROP_SWITCH_CASE_BASIC(renderToHardwareTextureAndroid);
|
|
206
216
|
RAW_SET_PROP_SWITCH_CASE_BASIC(screenReaderFocusable);
|
|
@@ -1105,6 +1115,14 @@ folly::dynamic HostPlatformViewProps::getDiffProps(
|
|
|
1105
1115
|
}
|
|
1106
1116
|
}
|
|
1107
1117
|
|
|
1118
|
+
if (scrollSnapAlign != oldProps->scrollSnapAlign) {
|
|
1119
|
+
if (scrollSnapAlign.has_value()) {
|
|
1120
|
+
result["scrollSnapAlign"] = scrollSnapAlign.value();
|
|
1121
|
+
} else {
|
|
1122
|
+
result["scrollSnapAlign"] = folly::dynamic(nullptr);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1108
1126
|
return result;
|
|
1109
1127
|
}
|
|
1110
1128
|
|
|
@@ -47,6 +47,7 @@ class HostPlatformViewProps : public BaseViewProps {
|
|
|
47
47
|
bool trapFocusDown{false};
|
|
48
48
|
bool trapFocusLeft{false};
|
|
49
49
|
bool trapFocusRight{false};
|
|
50
|
+
std::optional<std::string> scrollSnapAlign{};
|
|
50
51
|
|
|
51
52
|
bool needsOffscreenAlphaCompositing{false};
|
|
52
53
|
bool renderToHardwareTextureAndroid{false};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-tvos",
|
|
3
|
-
"version": "0.83.
|
|
3
|
+
"version": "0.83.4-0",
|
|
4
4
|
"description": "A framework for building native apps using React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -165,12 +165,12 @@
|
|
|
165
165
|
},
|
|
166
166
|
"dependencies": {
|
|
167
167
|
"@jest/create-cache-key-function": "^29.7.0",
|
|
168
|
-
"@react-native/assets-registry": "0.83.
|
|
169
|
-
"@react-native/codegen": "0.83.
|
|
170
|
-
"@react-native/community-cli-plugin": "0.83.
|
|
171
|
-
"@react-native/gradle-plugin": "0.83.
|
|
172
|
-
"@react-native/js-polyfills": "0.83.
|
|
173
|
-
"@react-native/normalize-colors": "0.83.
|
|
168
|
+
"@react-native/assets-registry": "0.83.4",
|
|
169
|
+
"@react-native/codegen": "0.83.4",
|
|
170
|
+
"@react-native/community-cli-plugin": "0.83.4",
|
|
171
|
+
"@react-native/gradle-plugin": "0.83.4",
|
|
172
|
+
"@react-native/js-polyfills": "0.83.4",
|
|
173
|
+
"@react-native/normalize-colors": "0.83.4",
|
|
174
174
|
"abort-controller": "^3.0.0",
|
|
175
175
|
"anser": "^1.4.9",
|
|
176
176
|
"ansi-regex": "^5.0.0",
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
"whatwg-fetch": "^3.0.0",
|
|
199
199
|
"ws": "^7.5.10",
|
|
200
200
|
"yargs": "^17.6.2",
|
|
201
|
-
"@react-native-tvos/virtualized-lists": "0.83.
|
|
201
|
+
"@react-native-tvos/virtualized-lists": "0.83.4-0"
|
|
202
202
|
},
|
|
203
203
|
"codegenConfig": {
|
|
204
204
|
"libraries": [
|