react-native 0.83.0-nightly-20250913-4fb42c84d → 0.83.0-nightly-20250915-56e5dff73

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.
@@ -29,7 +29,7 @@ export default class ReactNativeVersion {
29
29
  static major: number = 0;
30
30
  static minor: number = 83;
31
31
  static patch: number = 0;
32
- static prerelease: string | null = 'nightly-20250913-4fb42c84d';
32
+ static prerelease: string | null = 'nightly-20250915-56e5dff73';
33
33
 
34
34
  static getVersionString(): string {
35
35
  return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(83),
26
26
  RCTVersionPatch: @(0),
27
- RCTVersionPrerelease: @"nightly-20250913-4fb42c84d",
27
+ RCTVersionPrerelease: @"nightly-20250915-56e5dff73",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -22,7 +22,8 @@ VirtualViewExperimentalProps::VirtualViewExperimentalProps(
22
22
  const RawProps &rawProps): ViewProps(context, sourceProps, rawProps),
23
23
 
24
24
  initialHidden(convertRawProp(context, rawProps, "initialHidden", sourceProps.initialHidden, {false})),
25
- renderState(convertRawProp(context, rawProps, "renderState", sourceProps.renderState, {0})) {}
25
+ renderState(convertRawProp(context, rawProps, "renderState", sourceProps.renderState, {0})),
26
+ removeClippedSubviews(convertRawProp(context, rawProps, "removeClippedSubviews", sourceProps.removeClippedSubviews, {false})) {}
26
27
 
27
28
  #ifdef RN_SERIALIZABLE_STATE
28
29
  ComponentName VirtualViewExperimentalProps::getDiffPropsImplementationTarget() const {
@@ -47,6 +48,10 @@ folly::dynamic VirtualViewExperimentalProps::getDiffProps(
47
48
  if (renderState != oldProps->renderState) {
48
49
  result["renderState"] = renderState;
49
50
  }
51
+
52
+ if (removeClippedSubviews != oldProps->removeClippedSubviews) {
53
+ result["removeClippedSubviews"] = removeClippedSubviews;
54
+ }
50
55
  return result;
51
56
  }
52
57
  #endif
@@ -55,7 +60,8 @@ SharedDebugStringConvertibleList VirtualViewExperimentalProps::getDebugProps() c
55
60
  return ViewProps::getDebugProps() +
56
61
  SharedDebugStringConvertibleList{
57
62
  debugStringConvertibleItem("initialHidden", initialHidden, false),
58
- debugStringConvertibleItem("renderState", renderState, 0)
63
+ debugStringConvertibleItem("renderState", renderState, 0),
64
+ debugStringConvertibleItem("removeClippedSubviews", removeClippedSubviews, false)
59
65
  };
60
66
  }
61
67
  #endif
@@ -27,6 +27,7 @@ class VirtualViewExperimentalProps final : public ViewProps {
27
27
 
28
28
  bool initialHidden{false};
29
29
  int renderState{0};
30
+ bool removeClippedSubviews{false};
30
31
 
31
32
  #ifdef RN_SERIALIZABLE_STATE
32
33
  ComponentName getDiffPropsImplementationTarget() const override;
@@ -5246,6 +5246,7 @@ public class com/facebook/react/viewmanagers/VirtualViewExperimentalManagerDeleg
5246
5246
 
5247
5247
  public abstract interface class com/facebook/react/viewmanagers/VirtualViewExperimentalManagerInterface : com/facebook/react/uimanager/ViewManagerWithGeneratedInterface {
5248
5248
  public abstract fun setInitialHidden (Landroid/view/View;Z)V
5249
+ public abstract fun setRemoveClippedSubviews (Landroid/view/View;Z)V
5249
5250
  public abstract fun setRenderState (Landroid/view/View;I)V
5250
5251
  }
5251
5252
 
@@ -6725,9 +6726,10 @@ public final class com/facebook/react/views/virtual/viewexperimental/ReactVirtua
6725
6726
  public fun onLayoutChange (Landroid/view/View;IIIIIIII)V
6726
6727
  public fun onModeChange (Lcom/facebook/react/views/virtual/VirtualViewMode;Landroid/graphics/Rect;)V
6727
6728
  public synthetic fun recycleView$xplat_js_react_native_github_packages_react_native_ReactAndroid_src_main_java_com_facebook_react_views_view_viewAndroid ()V
6729
+ public fun updateClippingRect (Ljava/util/Set;)V
6728
6730
  }
6729
6731
 
6730
- public final class com/facebook/react/views/virtual/viewexperimental/ReactVirtualViewExperimentalManager : com/facebook/react/uimanager/ViewGroupManager, com/facebook/react/viewmanagers/VirtualViewExperimentalManagerInterface {
6732
+ public final class com/facebook/react/views/virtual/viewexperimental/ReactVirtualViewExperimentalManager : com/facebook/react/views/view/ReactClippingViewManager, com/facebook/react/viewmanagers/VirtualViewExperimentalManagerInterface {
6731
6733
  public static final field Companion Lcom/facebook/react/views/virtual/viewexperimental/ReactVirtualViewExperimentalManager$Companion;
6732
6734
  public static final field REACT_CLASS Ljava/lang/String;
6733
6735
  public fun <init> ()V
@@ -6739,6 +6741,7 @@ public final class com/facebook/react/views/virtual/viewexperimental/ReactVirtua
6739
6741
  public fun setInitialHidden (Lcom/facebook/react/views/virtual/viewexperimental/ReactVirtualViewExperimental;Z)V
6740
6742
  public synthetic fun setNativeId (Landroid/view/View;Ljava/lang/String;)V
6741
6743
  public fun setNativeId (Lcom/facebook/react/views/virtual/viewexperimental/ReactVirtualViewExperimental;Ljava/lang/String;)V
6744
+ public synthetic fun setRemoveClippedSubviews (Landroid/view/View;Z)V
6742
6745
  public synthetic fun setRenderState (Landroid/view/View;I)V
6743
6746
  public fun setRenderState (Lcom/facebook/react/views/virtual/viewexperimental/ReactVirtualViewExperimental;I)V
6744
6747
  }
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.83.0-nightly-20250913-4fb42c84d
1
+ VERSION_NAME=0.83.0-nightly-20250915-56e5dff73
2
2
  react.internal.publishingGroup=com.facebook.react
3
3
  react.internal.hermesPublishingGroup=com.facebook.hermes
4
4
 
@@ -106,7 +106,14 @@ internal class PerfMonitorOverlayView(
106
106
  containerLayout.addView(statusIndicator)
107
107
  containerLayout.addView(textContainer)
108
108
 
109
- return createAnchoredDialog(dpToPx(12f), dpToPx(12f)).apply { setContentView(containerLayout) }
109
+ val dialog =
110
+ createAnchoredDialog(dpToPx(12f), dpToPx(12f)).apply { setContentView(containerLayout) }
111
+ dialog.window?.apply {
112
+ attributes =
113
+ attributes?.apply { flags = flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE }
114
+ }
115
+
116
+ return dialog
110
117
  }
111
118
 
112
119
  private fun createAnchoredDialog(offsetX: Float, offsetY: Float): Dialog {
@@ -15,6 +15,6 @@ public object ReactNativeVersion {
15
15
  "major" to 0,
16
16
  "minor" to 83,
17
17
  "patch" to 0,
18
- "prerelease" to "nightly-20250913-4fb42c84d"
18
+ "prerelease" to "nightly-20250915-56e5dff73"
19
19
  )
20
20
  }
@@ -50,11 +50,13 @@ private fun rectsOverlap(rect1: Rect, rect2: Rect): Boolean {
50
50
  internal class VirtualViewContainerState {
51
51
 
52
52
  private val prerenderRatio: Double = ReactNativeFeatureFlags.virtualViewPrerenderRatio()
53
+ private val hysteresisRatio: Double = ReactNativeFeatureFlags.virtualViewHysteresisRatio()
53
54
 
54
55
  private val virtualViews: MutableSet<VirtualView> = mutableSetOf()
55
56
  private val emptyRect: Rect = Rect()
56
57
  private val visibleRect: Rect = Rect()
57
58
  private val prerenderRect: Rect = Rect()
59
+ private val hysteresisRect: Rect = Rect()
58
60
  private val onWindowFocusChangeListener =
59
61
  if (ReactNativeFeatureFlags.enableVirtualViewWindowFocusDetection()) {
60
62
  ViewTreeObserver.OnWindowFocusChangeListener {
@@ -119,11 +121,12 @@ internal class VirtualViewContainerState {
119
121
  (-prerenderRect.height() * prerenderRatio).toInt(),
120
122
  )
121
123
 
122
- val virtualViewsIt = if (virtualView != null) listOf(virtualView) else virtualViews
124
+ val virtualViewsIt =
125
+ if (virtualView != null) listOf(virtualView) else virtualViews.toMutableSet()
123
126
  virtualViewsIt.forEach { vv ->
124
127
  val rect = vv.containerRelativeRect
125
128
 
126
- var mode = VirtualViewMode.Hidden
129
+ var mode: VirtualViewMode? = VirtualViewMode.Hidden
127
130
  var thresholdRect = emptyRect
128
131
  when {
129
132
  rectsOverlap(rect, visibleRect) -> {
@@ -142,14 +145,29 @@ internal class VirtualViewContainerState {
142
145
  mode = VirtualViewMode.Prerender
143
146
  thresholdRect = prerenderRect
144
147
  }
145
- else -> {}
148
+ else -> {
149
+ if (hysteresisRatio > 0.0) {
150
+ hysteresisRect.set(prerenderRect)
151
+ hysteresisRect.inset(
152
+ (-visibleRect.width() * hysteresisRatio).toInt(),
153
+ (-visibleRect.height() * hysteresisRatio).toInt(),
154
+ )
155
+ if (rectsOverlap(rect, hysteresisRect)) {
156
+ mode = null
157
+ }
158
+ }
159
+ }
146
160
  }
147
161
 
148
- debugLog(
149
- "updateModes",
150
- { "virtualView=${vv.virtualViewID} mode=$mode rect=$rect thresholdRect=$thresholdRect" },
151
- )
152
- vv.onModeChange(mode, thresholdRect)
162
+ if (mode != null) {
163
+ vv.onModeChange(mode, thresholdRect)
164
+ debugLog(
165
+ "updateModes",
166
+ {
167
+ "virtualView=${vv.virtualViewID} mode=$mode rect=$rect thresholdRect=$thresholdRect"
168
+ },
169
+ )
170
+ }
153
171
  }
154
172
  }
155
173
  }
@@ -16,9 +16,11 @@ import com.facebook.common.logging.FLog
16
16
  import com.facebook.react.R
17
17
  import com.facebook.react.common.build.ReactBuildConfig
18
18
  import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
19
+ import com.facebook.react.uimanager.ReactClippingViewGroup
19
20
  import com.facebook.react.uimanager.ReactRoot
20
21
  import com.facebook.react.views.scroll.VirtualView
21
22
  import com.facebook.react.views.scroll.VirtualViewContainer
23
+ import com.facebook.react.views.scroll.debugLog
22
24
  import com.facebook.react.views.view.ReactViewGroup
23
25
  import com.facebook.react.views.virtual.VirtualViewMode
24
26
  import com.facebook.react.views.virtual.VirtualViewModeChangeEmitter
@@ -34,6 +36,7 @@ public class ReactVirtualViewExperimental(context: Context) :
34
36
  private var scrollView: VirtualViewContainer? = null
35
37
 
36
38
  private val lastContainerRelativeRect: Rect = Rect()
39
+ private val lastClippingRect: Rect = Rect()
37
40
  override val containerRelativeRect: Rect = Rect()
38
41
  private var offsetX: Int = 0
39
42
  private var offsetY: Int = 0
@@ -120,6 +123,7 @@ public class ReactVirtualViewExperimental(context: Context) :
120
123
  modeChangeEmitter = null
121
124
  hadLayout = false
122
125
  lastContainerRelativeRect.setEmpty()
126
+ lastClippingRect.setEmpty()
123
127
  containerRelativeRect.setEmpty()
124
128
  }
125
129
 
@@ -132,7 +136,12 @@ public class ReactVirtualViewExperimental(context: Context) :
132
136
  modeChangeEmitter ?: return
133
137
  scrollView ?: return
134
138
 
139
+ if (newMode == VirtualViewMode.Visible) {
140
+ updateClippingRect(null)
141
+ }
142
+
135
143
  if (newMode == mode) {
144
+ debugLog("onModeChange") { "no change $newMode" }
136
145
  return
137
146
  }
138
147
 
@@ -141,6 +150,10 @@ public class ReactVirtualViewExperimental(context: Context) :
141
150
 
142
151
  debugLog("onModeChange") { "$oldMode->$newMode" }
143
152
 
153
+ if (oldMode == VirtualViewMode.Visible) {
154
+ updateClippingRect(null)
155
+ }
156
+
144
157
  when (newMode) {
145
158
  VirtualViewMode.Visible -> {
146
159
  if (renderState == VirtualViewRenderState.Unknown) {
@@ -187,6 +200,37 @@ public class ReactVirtualViewExperimental(context: Context) :
187
200
  }
188
201
  }
189
202
 
203
+ // Note: We co-opt subview clipping on ReactVirtualView by returning the
204
+ // clipping rect of the ScrollView. This means we clip the children of ReactVirtualView
205
+ // when they are out of the viewport, but not ReactVirtualView itself.
206
+ override fun updateClippingRect(excludedViews: Set<Int>?) {
207
+ if (!_removeClippedSubviews) {
208
+ return
209
+ }
210
+
211
+ // If no ScrollView, or ScrollView has disabled removeClippedSubviews, use default behavior
212
+ if (
213
+ scrollView == null ||
214
+ !((scrollView as ReactClippingViewGroup)?.removeClippedSubviews ?: false)
215
+ ) {
216
+ super.updateClippingRect(excludedViews)
217
+ return
218
+ }
219
+
220
+ val clippingRect = checkNotNull(clippingRect)
221
+
222
+ (scrollView as ReactClippingViewGroup).getClippingRect(clippingRect)
223
+ clippingRect.intersect(containerRelativeRect)
224
+ clippingRect.offset(-containerRelativeRect.left, -containerRelativeRect.top)
225
+
226
+ if (lastClippingRect == clippingRect) {
227
+ return
228
+ }
229
+
230
+ updateClippingToRect(clippingRect, excludedViews)
231
+ lastClippingRect.set(clippingRect)
232
+ }
233
+
190
234
  private fun updateParentOffset() {
191
235
  val virtualViewScrollView = scrollView ?: return
192
236
  offsetX = 0
@@ -212,8 +256,11 @@ public class ReactVirtualViewExperimental(context: Context) :
212
256
  debugLog("reportRectChangeToContainer") { "no rect change $containerRelativeRect" }
213
257
  return
214
258
  }
215
- scrollView?.virtualViewContainerState?.onChange(this)
216
- lastContainerRelativeRect.set(containerRelativeRect)
259
+
260
+ if (scrollView != null) {
261
+ scrollView?.virtualViewContainerState?.onChange(this)
262
+ lastContainerRelativeRect.set(containerRelativeRect)
263
+ }
217
264
  }
218
265
 
219
266
  private fun getScrollView(): VirtualViewContainer? = traverseParentStack(true)
@@ -13,12 +13,12 @@ import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
13
13
  import com.facebook.react.module.annotations.ReactModule
14
14
  import com.facebook.react.uimanager.ThemedReactContext
15
15
  import com.facebook.react.uimanager.UIManagerHelper
16
- import com.facebook.react.uimanager.ViewGroupManager
17
16
  import com.facebook.react.uimanager.ViewManagerDelegate
18
17
  import com.facebook.react.uimanager.annotations.ReactProp
19
18
  import com.facebook.react.uimanager.events.EventDispatcher
20
19
  import com.facebook.react.viewmanagers.VirtualViewExperimentalManagerDelegate
21
20
  import com.facebook.react.viewmanagers.VirtualViewExperimentalManagerInterface
21
+ import com.facebook.react.views.view.ReactClippingViewManager
22
22
  import com.facebook.react.views.virtual.VirtualViewMode
23
23
  import com.facebook.react.views.virtual.VirtualViewModeChangeEmitter
24
24
  import com.facebook.react.views.virtual.VirtualViewModeChangeEvent
@@ -26,7 +26,7 @@ import com.facebook.react.views.virtual.VirtualViewRenderState
26
26
 
27
27
  @ReactModule(name = ReactVirtualViewExperimentalManager.REACT_CLASS)
28
28
  public class ReactVirtualViewExperimentalManager :
29
- ViewGroupManager<ReactVirtualViewExperimental>(),
29
+ ReactClippingViewManager<ReactVirtualViewExperimental>(),
30
30
  VirtualViewExperimentalManagerInterface<ReactVirtualViewExperimental> {
31
31
 
32
32
  private val _delegate = VirtualViewExperimentalManagerDelegate(this)
@@ -22,7 +22,7 @@ constexpr struct {
22
22
  int32_t Major = 0;
23
23
  int32_t Minor = 83;
24
24
  int32_t Patch = 0;
25
- std::string_view Prerelease = "nightly-20250913-4fb42c84d";
25
+ std::string_view Prerelease = "nightly-20250915-56e5dff73";
26
26
  } ReactNativeVersion;
27
27
 
28
28
  } // namespace facebook::react
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.83.0-nightly-20250913-4fb42c84d",
3
+ "version": "0.83.0-nightly-20250915-56e5dff73",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -159,13 +159,13 @@
159
159
  },
160
160
  "dependencies": {
161
161
  "@jest/create-cache-key-function": "^29.7.0",
162
- "@react-native/assets-registry": "0.83.0-nightly-20250913-4fb42c84d",
163
- "@react-native/codegen": "0.83.0-nightly-20250913-4fb42c84d",
164
- "@react-native/community-cli-plugin": "0.83.0-nightly-20250913-4fb42c84d",
165
- "@react-native/gradle-plugin": "0.83.0-nightly-20250913-4fb42c84d",
166
- "@react-native/js-polyfills": "0.83.0-nightly-20250913-4fb42c84d",
167
- "@react-native/normalize-colors": "0.83.0-nightly-20250913-4fb42c84d",
168
- "@react-native/virtualized-lists": "0.83.0-nightly-20250913-4fb42c84d",
162
+ "@react-native/assets-registry": "0.83.0-nightly-20250915-56e5dff73",
163
+ "@react-native/codegen": "0.83.0-nightly-20250915-56e5dff73",
164
+ "@react-native/community-cli-plugin": "0.83.0-nightly-20250915-56e5dff73",
165
+ "@react-native/gradle-plugin": "0.83.0-nightly-20250915-56e5dff73",
166
+ "@react-native/js-polyfills": "0.83.0-nightly-20250915-56e5dff73",
167
+ "@react-native/normalize-colors": "0.83.0-nightly-20250915-56e5dff73",
168
+ "@react-native/virtualized-lists": "0.83.0-nightly-20250915-56e5dff73",
169
169
  "abort-controller": "^3.0.0",
170
170
  "anser": "^1.4.9",
171
171
  "ansi-regex": "^5.0.0",
Binary file
Binary file
Binary file
@@ -79,6 +79,12 @@ type VirtualViewExperimentalNativeProps = $ReadOnly<{
79
79
  */
80
80
  renderState: Int32,
81
81
 
82
+ /**
83
+ * This was needed to get VirtualViewManagerDelegate to set this property.
84
+ * TODO: Investigate why spread ViewProps doesn't call setter
85
+ */
86
+ removeClippedSubviews?: boolean,
87
+
82
88
  /**
83
89
  * See `NativeModeChangeEvent`.
84
90
  */