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.
Files changed (64) hide show
  1. package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +1 -0
  2. package/Libraries/Components/ScrollView/ScrollView.d.ts +2 -1
  3. package/Libraries/Components/ScrollView/ScrollView.js +8 -1
  4. package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +2 -0
  5. package/Libraries/Components/ScrollView/ScrollViewNativeComponentType.js +2 -1
  6. package/Libraries/Components/TV/TVViewPropTypes.js +7 -0
  7. package/Libraries/Components/View/View.js +6 -0
  8. package/Libraries/Core/ReactNativeVersion.js +1 -1
  9. package/Libraries/Core/setUpReactDevTools.js +23 -6
  10. package/Libraries/NativeComponent/TVViewConfig.js +1 -0
  11. package/Libraries/Network/RCTHTTPRequestHandler.h +9 -0
  12. package/Libraries/Network/RCTHTTPRequestHandler.mm +15 -1
  13. package/Libraries/Pressability/Pressability.js +7 -0
  14. package/Libraries/WebSocket/RCTReconnectingWebSocket.m +4 -1
  15. package/React/Base/RCTBundleURLProvider.mm +5 -3
  16. package/React/Base/RCTDevSupportHttpHeaders.h +24 -0
  17. package/React/Base/RCTDevSupportHttpHeaders.m +65 -0
  18. package/React/Base/RCTMultipartDataTask.h +9 -0
  19. package/React/Base/RCTMultipartDataTask.m +16 -1
  20. package/React/Base/RCTVersion.m +1 -1
  21. package/React/CoreModules/RCTWebSocketModule.h +6 -0
  22. package/React/CoreModules/RCTWebSocketModule.mm +14 -1
  23. package/React/DevSupport/RCTInspectorDevServerHelper.mm +33 -22
  24. package/React/DevSupport/RCTInspectorNetworkHelper.mm +2 -0
  25. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.h +1 -0
  26. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm +3 -0
  27. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +110 -4
  28. package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +2 -0
  29. package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +31 -4
  30. package/React/Inspector/RCTCxxInspectorWebSocketAdapter.mm +5 -1
  31. package/ReactAndroid/api/ReactAndroid.api +1 -0
  32. package/ReactAndroid/gradle.properties +1 -1
  33. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/CxxInspectorPackagerConnection.kt +2 -8
  34. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.kt +17 -13
  35. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/PackagerStatusCheck.kt +10 -19
  36. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxContentView.kt +2 -2
  37. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/DevSupportHttpClient.kt +49 -0
  38. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt +1 -12
  39. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
  40. package/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.kt +3 -4
  41. package/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/JSPackagerClient.kt +2 -1
  42. package/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/ReconnectingWebSocket.kt +2 -8
  43. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +49 -5
  44. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt +7 -0
  45. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +46 -4
  46. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt +69 -0
  47. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt +7 -0
  48. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt +1 -0
  49. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +4 -0
  50. package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
  51. package/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.cpp +10 -0
  52. package/ReactCommon/react/renderer/components/scrollview/BaseScrollViewProps.h +1 -0
  53. package/ReactCommon/react/renderer/components/scrollview/conversions.h +6 -0
  54. package/ReactCommon/react/renderer/components/scrollview/platform/android/react/renderer/components/scrollview/HostPlatformScrollViewProps.cpp +18 -1
  55. package/ReactCommon/react/renderer/components/scrollview/platform/android/react/renderer/components/scrollview/HostPlatformScrollViewProps.h +2 -0
  56. package/ReactCommon/react/renderer/components/scrollview/primitives.h +1 -1
  57. package/ReactCommon/react/renderer/components/view/BaseViewProps.cpp +11 -1
  58. package/ReactCommon/react/renderer/components/view/BaseViewProps.h +4 -0
  59. package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.cpp +18 -0
  60. package/ReactCommon/react/renderer/components/view/platform/android/react/renderer/components/view/HostPlatformViewProps.h +1 -0
  61. package/package.json +8 -8
  62. package/scripts/replace-rncore-version.js +62 -8
  63. package/settings.gradle.kts +21 -1
  64. package/types/public/ReactNativeTVTypes.d.ts +19 -2
@@ -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 && !mPagingEnabled) {
551
- scrollToChild(focused);
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
- scrollToChild(focused);
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,
@@ -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 2
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 = 2;
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);
@@ -31,6 +31,7 @@ class BaseScrollViewProps : public ViewProps {
31
31
 
32
32
  #if TARGET_OS_TV
33
33
  bool showsScrollIndex{true};
34
+ Float snapToItemPadding{0};
34
35
  #endif
35
36
  bool alwaysBounceHorizontal{};
36
37
  bool 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
@@ -12,7 +12,7 @@
12
12
 
13
13
  namespace facebook::react {
14
14
 
15
- enum class ScrollViewSnapToAlignment { Start, Center, End };
15
+ enum class ScrollViewSnapToAlignment { Start, Center, End, Item };
16
16
 
17
17
  enum class ScrollViewIndicatorStyle { Default, Black, White };
18
18
 
@@ -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.2-0",
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.2",
169
- "@react-native/codegen": "0.83.2",
170
- "@react-native/community-cli-plugin": "0.83.2",
171
- "@react-native/gradle-plugin": "0.83.2",
172
- "@react-native/js-polyfills": "0.83.2",
173
- "@react-native/normalize-colors": "0.83.2",
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.2-0"
201
+ "@react-native-tvos/virtualized-lists": "0.83.4-0"
202
202
  },
203
203
  "codegenConfig": {
204
204
  "libraries": [