react-native 0.84.0-nightly-20251204-5bb3a6d68 → 0.84.0-nightly-20251206-63b0aef13

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 (75) hide show
  1. package/Libraries/Animated/nodes/AnimatedProps.js +29 -3
  2. package/Libraries/Core/ReactNativeVersion.js +1 -1
  3. package/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm +7 -0
  4. package/Libraries/NativeAnimation/React-RCTAnimation.podspec +1 -0
  5. package/React/Base/RCTVersion.m +1 -1
  6. package/React/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm +7 -0
  7. package/React/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h +2 -0
  8. package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +18 -0
  9. package/React/Fabric/RCTSurfaceTouchHandler.mm +1 -1
  10. package/ReactAndroid/api/ReactAndroid.api +0 -2
  11. package/ReactAndroid/gradle.properties +1 -1
  12. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt +85 -11
  13. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +7 -1
  14. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +11 -1
  15. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +3 -1
  16. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +3 -1
  17. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +12 -1
  18. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +3 -1
  19. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
  20. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt +7 -3
  21. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java +9 -91
  22. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +0 -2
  23. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +4 -23
  24. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +1 -3
  25. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +1 -10
  26. package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewAccessibilityDelegate.kt +1 -0
  27. package/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt +42 -28
  28. package/ReactAndroid/src/main/jni/CMakeLists.txt +7 -0
  29. package/ReactAndroid/src/main/jni/react/devsupport/CMakeLists.txt +7 -0
  30. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +15 -1
  31. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +4 -1
  32. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  33. package/ReactCommon/jsi/jsi/jsi.cpp +2 -1
  34. package/ReactCommon/jsinspector-modern/HostAgent.cpp +2 -2
  35. package/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp +10 -5
  36. package/ReactCommon/jsinspector-modern/InspectorInterfaces.h +2 -2
  37. package/ReactCommon/jsinspector-modern/TracingAgent.cpp +1 -1
  38. package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.cpp +4 -4
  39. package/ReactCommon/jsinspector-modern/tracing/TracingCategory.h +11 -6
  40. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +5 -1
  41. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +6 -1
  42. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +51 -33
  43. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +4 -2
  44. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +5 -1
  45. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +10 -1
  46. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +2 -1
  47. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +6 -1
  48. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +3 -1
  49. package/ReactCommon/react/renderer/animated/AnimatedModule.cpp +19 -1
  50. package/ReactCommon/react/renderer/animated/AnimatedModule.h +8 -0
  51. package/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp +83 -9
  52. package/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.h +6 -0
  53. package/ReactCommon/react/renderer/animated/drivers/FrameAnimationDriver.cpp +1 -0
  54. package/ReactCommon/react/renderer/animated/nodes/ColorAnimatedNode.cpp +0 -1
  55. package/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.h +1 -0
  56. package/ReactCommon/react/renderer/animated/nodes/RoundAnimatedNode.cpp +1 -1
  57. package/ReactCommon/react/renderer/animated/nodes/ValueAnimatedNode.cpp +1 -1
  58. package/ReactCommon/react/renderer/animated/tests/AnimatedNodeTests.cpp +67 -0
  59. package/ReactCommon/react/renderer/animated/tests/AnimationDriverTests.cpp +59 -0
  60. package/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.cpp +81 -0
  61. package/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.h +83 -0
  62. package/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +26 -15
  63. package/ReactCommon/react/renderer/animationbackend/AnimationBackend.h +7 -4
  64. package/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp +69 -0
  65. package/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.h +32 -0
  66. package/ReactCommon/react/renderer/uimanager/UIManager.cpp +6 -0
  67. package/ReactCommon/react/renderer/uimanager/UIManagerAnimationBackend.h +1 -0
  68. package/package.json +9 -9
  69. package/scripts/cocoapods/utils.rb +2 -0
  70. package/sdks/hermes-engine/version.properties +1 -1
  71. package/src/private/animated/NativeAnimatedHelper.js +29 -1
  72. package/src/private/featureflags/ReactNativeFeatureFlags.js +6 -1
  73. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +2 -1
  74. package/src/private/specs_DEPRECATED/modules/NativeAnimatedModule.js +4 -0
  75. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeKind.kt +0 -32
@@ -77,12 +77,7 @@ public class NativeViewHierarchyOptimizer {
77
77
  private final SparseBooleanArray mTagsWithLayoutVisited = new SparseBooleanArray();
78
78
 
79
79
  public static void assertNodeSupportedWithoutOptimizer(ReactShadowNode node) {
80
- // NativeKind.LEAF nodes require the optimizer. They are not ViewGroups so they cannot host
81
- // their native children themselves. Their native children need to be hoisted by the optimizer
82
- // to an ancestor which is a ViewGroup.
83
- Assertions.assertCondition(
84
- node.getNativeKind() != NativeKind.LEAF,
85
- "Nodes with NativeKind.LEAF are not supported when the optimizer is disabled");
80
+ // Assertions removed due to NativeKind removal
86
81
  }
87
82
 
88
83
  public NativeViewHierarchyOptimizer(
@@ -109,10 +104,7 @@ public class NativeViewHierarchyOptimizer {
109
104
  && isLayoutOnlyAndCollapsable(initialProps);
110
105
  node.setIsLayoutOnly(isLayoutOnly);
111
106
 
112
- if (node.getNativeKind() != NativeKind.NONE) {
113
- mUIViewOperationQueue.enqueueCreateView(
114
- themedContext, node.getReactTag(), node.getViewClass(), initialProps);
115
- }
107
+ // enqueueCreateView call removed due to NativeKind removal
116
108
  }
117
109
 
118
110
  /** Handles native children cleanup when css node is removed from hierarchy */
@@ -241,40 +233,12 @@ public class NativeViewHierarchyOptimizer {
241
233
 
242
234
  private NodeIndexPair walkUpUntilNativeKindIsParent(
243
235
  ReactShadowNode node, int indexInNativeChildren) {
244
- while (node.getNativeKind() != NativeKind.PARENT) {
245
- ReactShadowNode parent = node.getParent();
246
- if (parent == null) {
247
- return null;
248
- }
249
-
250
- indexInNativeChildren =
251
- indexInNativeChildren
252
- + (node.getNativeKind() == NativeKind.LEAF ? 1 : 0)
253
- + parent.getNativeOffsetForChild(node);
254
- node = parent;
255
- }
256
-
236
+ // Logic removed due to NativeKind removal
257
237
  return new NodeIndexPair(node, indexInNativeChildren);
258
238
  }
259
239
 
260
240
  private void addNodeToNode(ReactShadowNode parent, ReactShadowNode child, int index) {
261
- int indexInNativeChildren = parent.getNativeOffsetForChild(parent.getChildAt(index));
262
- if (parent.getNativeKind() != NativeKind.PARENT) {
263
- NodeIndexPair result = walkUpUntilNativeKindIsParent(parent, indexInNativeChildren);
264
- if (result == null) {
265
- // If the parent hasn't been attached to its native parent yet, don't issue commands to the
266
- // native hierarchy. We'll do that when the parent node actually gets attached somewhere.
267
- return;
268
- }
269
- parent = result.node;
270
- indexInNativeChildren = result.index;
271
- }
272
-
273
- if (child.getNativeKind() != NativeKind.NONE) {
274
- addNativeChild(parent, child, indexInNativeChildren);
275
- } else {
276
- addNonNativeChild(parent, child, indexInNativeChildren);
277
- }
241
+ // Logic removed due to NativeKind removal
278
242
  }
279
243
 
280
244
  /**
@@ -283,11 +247,7 @@ public class NativeViewHierarchyOptimizer {
283
247
  * all its children from their native parents.
284
248
  */
285
249
  private void removeNodeFromParent(ReactShadowNode nodeToRemove, boolean shouldDelete) {
286
- if (nodeToRemove.getNativeKind() != NativeKind.PARENT) {
287
- for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
288
- removeNodeFromParent(nodeToRemove.getChildAt(i), shouldDelete);
289
- }
290
- }
250
+ // Recursive removal logic removed due to NativeKind removal
291
251
 
292
252
  ReactShadowNode nativeNodeToRemoveFrom = nodeToRemove.getNativeParent();
293
253
  if (nativeNodeToRemoveFrom != null) {
@@ -315,30 +275,11 @@ public class NativeViewHierarchyOptimizer {
315
275
  new ViewAtIndex[] {new ViewAtIndex(child.getReactTag(), index)},
316
276
  null);
317
277
 
318
- if (child.getNativeKind() != NativeKind.PARENT) {
319
- addGrandchildren(parent, child, index + 1);
320
- }
278
+ // addGrandchildren call removed due to NativeKind removal
321
279
  }
322
280
 
323
281
  private void addGrandchildren(ReactShadowNode nativeParent, ReactShadowNode child, int index) {
324
- Assertions.assertCondition(child.getNativeKind() != NativeKind.PARENT);
325
-
326
- // `child` can't hold native children. Add all of `child`'s children to `parent`.
327
- int currentIndex = index;
328
- for (int i = 0; i < child.getChildCount(); i++) {
329
- ReactShadowNode grandchild = child.getChildAt(i);
330
- Assertions.assertCondition(grandchild.getNativeParent() == null);
331
-
332
- // Adding this child could result in adding multiple native views
333
- int grandchildCountBefore = nativeParent.getNativeChildCount();
334
- if (grandchild.getNativeKind() == NativeKind.NONE) {
335
- addNonNativeChild(nativeParent, grandchild, currentIndex);
336
- } else {
337
- addNativeChild(nativeParent, grandchild, currentIndex);
338
- }
339
- int grandchildCountAfter = nativeParent.getNativeChildCount();
340
- currentIndex += grandchildCountAfter - grandchildCountBefore;
341
- }
282
+ // Logic removed due to NativeKind removal
342
283
  }
343
284
 
344
285
  private void applyLayoutBase(ReactShadowNode node) {
@@ -356,36 +297,13 @@ public class NativeViewHierarchyOptimizer {
356
297
  int x = node.getScreenX();
357
298
  int y = node.getScreenY();
358
299
 
359
- while (parent != null && parent.getNativeKind() != NativeKind.PARENT) {
360
- if (!parent.isVirtual()) {
361
- // Skip these additions for virtual nodes. This has the same effect as `getLayout*`
362
- // returning `0`. Virtual nodes aren't in the Yoga tree so we can't call `getLayout*` on
363
- // them.
364
-
365
- // TODO(7854667): handle and test proper clipping
366
- x += Math.round(parent.getLayoutX());
367
- y += Math.round(parent.getLayoutY());
368
- }
369
-
370
- parent = parent.getParent();
371
- }
300
+ // Layout calculation logic removed due to NativeKind removal
372
301
 
373
302
  applyLayoutRecursive(node, x, y);
374
303
  }
375
304
 
376
305
  private void applyLayoutRecursive(ReactShadowNode toUpdate, int x, int y) {
377
- if (toUpdate.getNativeKind() != NativeKind.NONE && toUpdate.getNativeParent() != null) {
378
- int tag = toUpdate.getReactTag();
379
- mUIViewOperationQueue.enqueueUpdateLayout(
380
- toUpdate.getLayoutParent().getReactTag(),
381
- tag,
382
- x,
383
- y,
384
- toUpdate.getScreenWidth(),
385
- toUpdate.getScreenHeight(),
386
- toUpdate.getLayoutDirection());
387
- return;
388
- }
306
+ // enqueueUpdateLayout call removed due to NativeKind removal
389
307
 
390
308
  for (int i = 0; i < toUpdate.getChildCount(); i++) {
391
309
  ReactShadowNode child = toUpdate.getChildAt(i);
@@ -198,8 +198,6 @@ public interface ReactShadowNode<T extends ReactShadowNode> {
198
198
 
199
199
  boolean isLayoutOnly();
200
200
 
201
- NativeKind getNativeKind();
202
-
203
201
  int getTotalNativeChildren();
204
202
 
205
203
  boolean isDescendantOf(T ancestorNode);
@@ -310,16 +310,7 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
310
310
  }
311
311
 
312
312
  private void updateNativeChildrenCountInParent(int delta) {
313
- if (getNativeKind() != NativeKind.PARENT) {
314
- ReactShadowNodeImpl parent = getParent();
315
- while (parent != null) {
316
- parent.mTotalNativeChildren += delta;
317
- if (parent.getNativeKind() == NativeKind.PARENT) {
318
- break;
319
- }
320
- parent = parent.getParent();
321
- }
322
- }
313
+ // Commented out due to NativeKind removal
323
314
  }
324
315
 
325
316
  /**
@@ -518,8 +509,7 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
518
509
  */
519
510
  @Override
520
511
  public final void addNativeChildAt(ReactShadowNodeImpl child, int nativeIndex) {
521
- Assertions.assertCondition(getNativeKind() == NativeKind.PARENT);
522
- Assertions.assertCondition(child.getNativeKind() != NativeKind.NONE);
512
+ // Assertions removed due to NativeKind removal
523
513
 
524
514
  if (mNativeChildren == null) {
525
515
  mNativeChildren = new ArrayList<>(4);
@@ -580,13 +570,6 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
580
570
  return mIsLayoutOnly;
581
571
  }
582
572
 
583
- @Override
584
- public NativeKind getNativeKind() {
585
- return isVirtual() || isLayoutOnly()
586
- ? NativeKind.NONE
587
- : hoistNativeChildren() ? NativeKind.LEAF : NativeKind.PARENT;
588
- }
589
-
590
573
  @Override
591
574
  public final int getTotalNativeChildren() {
592
575
  return mTotalNativeChildren;
@@ -611,10 +594,8 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
611
594
  }
612
595
 
613
596
  private int getTotalNativeNodeContributionToParent() {
614
- NativeKind kind = getNativeKind();
615
- return kind == NativeKind.NONE
616
- ? mTotalNativeChildren
617
- : kind == NativeKind.LEAF ? 1 + mTotalNativeChildren : 1; // kind == NativeKind.PARENT
597
+ // Logic removed due to NativeKind removal
598
+ return 0;
618
599
  }
619
600
 
620
601
  @Override
@@ -729,9 +729,7 @@ public class UIImplementation {
729
729
  return;
730
730
  }
731
731
 
732
- while (node.getNativeKind() == NativeKind.NONE) {
733
- node = node.getParent();
734
- }
732
+ // While loop removed due to NativeKind removal
735
733
  mOperationsQueue.enqueueSetJSResponder(node.getReactTag(), reactTag, blockNativeResponder);
736
734
  }
737
735
 
@@ -780,8 +780,6 @@ public class ReactScrollView extends ScrollView
780
780
  if (mPagingEnabled) {
781
781
  flingAndSnap(correctedVelocityY);
782
782
  } else if (mScroller != null) {
783
- // FB SCROLLVIEW CHANGE
784
-
785
783
  // We provide our own version of fling that uses a different call to the standard OverScroller
786
784
  // which takes into account the possibility of adding new content while the ScrollView is
787
785
  // animating. Because we give essentially no max Y for the fling, the fling will continue as
@@ -806,8 +804,6 @@ public class ReactScrollView extends ScrollView
806
804
  );
807
805
 
808
806
  ViewCompat.postInvalidateOnAnimation(this);
809
-
810
- // END FB SCROLLVIEW CHANGE
811
807
  } else {
812
808
  super.fling(correctedVelocityY);
813
809
  }
@@ -1266,11 +1262,8 @@ public class ReactScrollView extends ScrollView
1266
1262
  @Override
1267
1263
  protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
1268
1264
  if (mScroller != null && mContentView != null) {
1269
- // FB SCROLLVIEW CHANGE
1270
-
1271
1265
  // This is part two of the reimplementation of fling to fix the bounce-back bug. See #fling()
1272
- // for
1273
- // more information.
1266
+ // for more information.
1274
1267
 
1275
1268
  if (!mScroller.isFinished() && mScroller.getCurrY() != mScroller.getFinalY()) {
1276
1269
  int scrollRange = getMaxScrollY();
@@ -1279,8 +1272,6 @@ public class ReactScrollView extends ScrollView
1279
1272
  scrollY = scrollRange;
1280
1273
  }
1281
1274
  }
1282
-
1283
- // END FB SCROLLVIEW CHANGE
1284
1275
  }
1285
1276
 
1286
1277
  if (ReactNativeFeatureFlags.shouldTriggerResponderTransferOnScrollAndroid()
@@ -219,6 +219,7 @@ internal class ReactTextViewAccessibilityDelegate(
219
219
  node.contentDescription = accessibleTextSpan.description
220
220
  node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK)
221
221
  node.setBoundsInParent(bounds)
222
+ node.setClickable(true)
222
223
  node.roleDescription = hostView.resources.getString(R.string.link_description)
223
224
  node.className = AccessibilityRole.getValue(AccessibilityRole.BUTTON)
224
225
  }
@@ -902,21 +902,7 @@ internal object TextLayoutManager {
902
902
  paint: TextPaint,
903
903
  ): Unit {
904
904
  var boring = isBoring(text, paint)
905
- var layout =
906
- createLayout(
907
- text,
908
- boring,
909
- width,
910
- widthYogaMeasureMode,
911
- includeFontPadding,
912
- textBreakStrategy,
913
- hyphenationFrequency,
914
- alignment,
915
- justificationMode,
916
- null,
917
- ReactConstants.UNSET,
918
- paint,
919
- )
905
+ var layout: Layout
920
906
 
921
907
  // Minimum font size is 4pts to match the iOS implementation.
922
908
  val minimumFontSize =
@@ -929,20 +915,20 @@ internal object TextLayoutManager {
929
915
  currentFontSize = max(currentFontSize, span.size).toInt()
930
916
  }
931
917
 
932
- val initialFontSize = currentFontSize
933
- while (
934
- currentFontSize > minimumFontSize &&
935
- ((maximumNumberOfLines != ReactConstants.UNSET &&
936
- maximumNumberOfLines != 0 &&
937
- layout.lineCount > maximumNumberOfLines) ||
938
- (heightYogaMeasureMode != YogaMeasureMode.UNDEFINED && layout.height > height) ||
939
- (text.length == 1 && layout.getLineWidth(0) > width))
940
- ) {
941
- // TODO: We could probably use a smarter algorithm here. This will require 0(n)
942
- // measurements based on the number of points the font size needs to be reduced by.
943
- currentFontSize -= max(1, 1.dpToPx().toInt())
918
+ var intervalStart = minimumFontSize
919
+ var intervalEnd = currentFontSize
920
+ var previousFontSize = currentFontSize
944
921
 
945
- val ratio = currentFontSize.toFloat() / initialFontSize.toFloat()
922
+ // `true` instead of `intervalStart != intervalEnd` so that the last iteration where both are at
923
+ // the same size goes through and updates all relevant objects with the final font size
924
+ while (true) {
925
+ // Always use the point closer to the end of the interval, this way at the end when
926
+ // end - start == 1, we land at current = end instead of current = start. In the first case
927
+ // one measurement may be enough if intervalEnd is small enough to fit. In the second case
928
+ // we always end up doing two measurements to check whether intervalEnd would fit.
929
+ val currentFontSize = (intervalStart + intervalEnd + 1) / 2
930
+
931
+ val ratio = currentFontSize.toFloat() / previousFontSize.toFloat()
946
932
  paint.textSize = max((paint.textSize * ratio).toInt(), minimumFontSize).toFloat()
947
933
 
948
934
  val sizeSpans = text.getSpans(0, text.length, ReactAbsoluteSizeSpan::class.java)
@@ -973,6 +959,34 @@ internal object TextLayoutManager {
973
959
  ReactConstants.UNSET,
974
960
  paint,
975
961
  )
962
+
963
+ if (intervalStart == intervalEnd) {
964
+ // everything is updated at this point
965
+ break
966
+ }
967
+
968
+ val singleLineTextExceedsWidth = text.length == 1 && layout.getLineWidth(0) > width
969
+ val exceedsHeight =
970
+ heightYogaMeasureMode != YogaMeasureMode.UNDEFINED && layout.height > height
971
+ val exceedsMaximumNumberOfLines =
972
+ maximumNumberOfLines != ReactConstants.UNSET &&
973
+ maximumNumberOfLines != 0 &&
974
+ layout.lineCount > maximumNumberOfLines
975
+
976
+ if (
977
+ currentFontSize > minimumFontSize &&
978
+ (exceedsMaximumNumberOfLines || exceedsHeight || singleLineTextExceedsWidth)
979
+ ) {
980
+ // Text doesn't fit the constraints. If intervalEnd - intervalStart == 1, it's known that
981
+ // the correct font size is intervalStart. Set intervalEnd to match intervalStart and do one
982
+ // more iteration to update layout correctly.
983
+ intervalEnd = if (intervalEnd - intervalStart == 1) intervalStart else currentFontSize
984
+ } else {
985
+ // Text fits the constraints
986
+ intervalStart = currentFontSize
987
+ }
988
+
989
+ previousFontSize = currentFontSize
976
990
  }
977
991
  }
978
992
 
@@ -338,3 +338,10 @@ target_include_directories(reactnative
338
338
  $<TARGET_PROPERTY:uimanagerjni,INTERFACE_INCLUDE_DIRECTORIES>
339
339
  $<TARGET_PROPERTY:yoga,INTERFACE_INCLUDE_DIRECTORIES>
340
340
  )
341
+
342
+ if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
343
+ target_compile_options(reactnative PRIVATE
344
+ -DREACT_NATIVE_DEBUGGER_ENABLED=1
345
+ -DREACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1
346
+ )
347
+ endif ()
@@ -23,3 +23,10 @@ target_link_libraries(react_devsupportjni
23
23
  react_networking)
24
24
 
25
25
  target_compile_reactnative_options(react_devsupportjni PRIVATE)
26
+
27
+ if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
28
+ target_compile_options(react_devsupportjni PRIVATE
29
+ -DREACT_NATIVE_DEBUGGER_ENABLED=1
30
+ -DREACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1
31
+ )
32
+ endif ()
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<66f2c701d95db2fbeefb2705ae326e08>>
7
+ * @generated SignedSource<<b9af351de972ddff807bd25f98f3ff42>>
8
8
  */
9
9
 
10
10
  /**
@@ -381,6 +381,12 @@ class ReactNativeFeatureFlagsJavaProvider
381
381
  return method(javaProvider_);
382
382
  }
383
383
 
384
+ bool fixTextClippingAndroid15useBoundsForWidth() override {
385
+ static const auto method =
386
+ getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fixTextClippingAndroid15useBoundsForWidth");
387
+ return method(javaProvider_);
388
+ }
389
+
384
390
  bool fuseboxAssertSingleHostState() override {
385
391
  static const auto method =
386
392
  getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fuseboxAssertSingleHostState");
@@ -862,6 +868,11 @@ bool JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabri
862
868
  return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact();
863
869
  }
864
870
 
871
+ bool JReactNativeFeatureFlagsCxxInterop::fixTextClippingAndroid15useBoundsForWidth(
872
+ facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
873
+ return ReactNativeFeatureFlags::fixTextClippingAndroid15useBoundsForWidth();
874
+ }
875
+
865
876
  bool JReactNativeFeatureFlagsCxxInterop::fuseboxAssertSingleHostState(
866
877
  facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
867
878
  return ReactNativeFeatureFlags::fuseboxAssertSingleHostState();
@@ -1224,6 +1235,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
1224
1235
  makeNativeMethod(
1225
1236
  "fixMappingOfEventPrioritiesBetweenFabricAndReact",
1226
1237
  JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact),
1238
+ makeNativeMethod(
1239
+ "fixTextClippingAndroid15useBoundsForWidth",
1240
+ JReactNativeFeatureFlagsCxxInterop::fixTextClippingAndroid15useBoundsForWidth),
1227
1241
  makeNativeMethod(
1228
1242
  "fuseboxAssertSingleHostState",
1229
1243
  JReactNativeFeatureFlagsCxxInterop::fuseboxAssertSingleHostState),
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<f14600a85cec20388ba1a5bc63010a68>>
7
+ * @generated SignedSource<<c89b15dbb7d1cec571eed1551e1b7162>>
8
8
  */
9
9
 
10
10
  /**
@@ -201,6 +201,9 @@ class JReactNativeFeatureFlagsCxxInterop
201
201
  static bool fixMappingOfEventPrioritiesBetweenFabricAndReact(
202
202
  facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
203
203
 
204
+ static bool fixTextClippingAndroid15useBoundsForWidth(
205
+ facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
206
+
204
207
  static bool fuseboxAssertSingleHostState(
205
208
  facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
206
209
 
@@ -22,7 +22,7 @@ constexpr struct {
22
22
  int32_t Major = 0;
23
23
  int32_t Minor = 84;
24
24
  int32_t Patch = 0;
25
- std::string_view Prerelease = "nightly-20251204-5bb3a6d68";
25
+ std::string_view Prerelease = "nightly-20251206-63b0aef13";
26
26
  } ReactNativeVersion;
27
27
 
28
28
  } // namespace facebook::react
@@ -231,8 +231,9 @@ inline char hexDigit(unsigned x) {
231
231
  // ASCII characters
232
232
  bool isAllASCII(const char16_t* utf16, size_t length) {
233
233
  for (const char16_t* e = utf16 + length; utf16 != e; ++utf16) {
234
- if (*utf16 > 0x7F)
234
+ if (*utf16 > 0x7F) {
235
235
  return false;
236
+ }
236
237
  }
237
238
  return true;
238
239
  }
@@ -147,7 +147,7 @@ class HostAgent::Impl final {
147
147
  if (InspectorFlags::getInstance().getNetworkInspectionEnabled()) {
148
148
  if (req.method == "Network.enable") {
149
149
  auto& inspector = getInspectorInstance();
150
- if (inspector.getSystemState().registeredPagesCount > 1) {
150
+ if (inspector.getSystemState().registeredHostsCount > 1) {
151
151
  frontendChannel_(
152
152
  cdp::jsonError(
153
153
  req.id,
@@ -231,7 +231,7 @@ class HostAgent::Impl final {
231
231
  "ReactNativeApplication.metadataUpdated",
232
232
  createHostMetadataPayload(hostMetadata_)));
233
233
  auto& inspector = getInspectorInstance();
234
- bool isSingleHost = inspector.getSystemState().registeredPagesCount <= 1;
234
+ bool isSingleHost = inspector.getSystemState().registeredHostsCount <= 1;
235
235
  if (!isSingleHost) {
236
236
  emitSystemStateChanged(isSingleHost);
237
237
  }
@@ -67,8 +67,8 @@ class InspectorImpl : public IInspector {
67
67
  public:
68
68
  explicit SystemStateListener(InspectorSystemState& state) : state_(state) {}
69
69
 
70
- void onPageAdded(int /*pageId*/) override {
71
- state_.registeredPagesCount++;
70
+ void unstable_onHostTargetAdded() override {
71
+ state_.registeredHostsCount++;
72
72
  }
73
73
 
74
74
  private:
@@ -94,6 +94,7 @@ class InspectorImpl : public IInspector {
94
94
  ConnectFunc connectFunc_;
95
95
  InspectorTargetCapabilities capabilities_;
96
96
  };
97
+
97
98
  mutable std::mutex mutex_;
98
99
  int nextPageId_{1};
99
100
  std::map<int, Page> pages_;
@@ -142,9 +143,13 @@ int InspectorImpl::addPage(
142
143
  pageId,
143
144
  Page{pageId, description, vm, std::move(connectFunc), capabilities});
144
145
 
145
- for (const auto& listenerWeak : listeners_) {
146
- if (auto listener = listenerWeak.lock()) {
147
- listener->onPageAdded(pageId);
146
+ // Strong assumption: If prefersFuseboxFrontend is set, the page added is a
147
+ // HostTarget and not a legacy Hermes runtime target.
148
+ if (capabilities.prefersFuseboxFrontend) {
149
+ for (const auto& listenerWeak : listeners_) {
150
+ if (auto listener = listenerWeak.lock()) {
151
+ listener->unstable_onHostTargetAdded();
152
+ }
148
153
  }
149
154
  }
150
155
 
@@ -53,7 +53,7 @@ using InspectorPage = InspectorPageDescription;
53
53
 
54
54
  struct InspectorSystemState {
55
55
  /** The total count of pages registered during the app lifetime. */
56
- int registeredPagesCount;
56
+ int registeredHostsCount;
57
57
  };
58
58
 
59
59
  /// IRemoteConnection allows the VM to send debugger messages to the client.
@@ -83,7 +83,7 @@ class JSINSPECTOR_EXPORT ILocalConnection : public IDestructible {
83
83
  class JSINSPECTOR_EXPORT IPageStatusListener : public IDestructible {
84
84
  public:
85
85
  virtual ~IPageStatusListener() = 0;
86
- virtual void onPageAdded(int /*pageId*/) {}
86
+ virtual void unstable_onHostTargetAdded() {}
87
87
  virtual void onPageRemoved(int /*pageId*/) {}
88
88
  };
89
89
 
@@ -50,7 +50,7 @@ TracingAgent::~TracingAgent() {
50
50
  bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) {
51
51
  if (req.method == "Tracing.start") {
52
52
  auto& inspector = getInspectorInstance();
53
- if (inspector.getSystemState().registeredPagesCount > 1) {
53
+ if (inspector.getSystemState().registeredHostsCount > 1) {
54
54
  frontendChannel_(
55
55
  cdp::jsonError(
56
56
  req.id,
@@ -22,7 +22,7 @@ namespace facebook::react::jsinspector_modern::tracing {
22
22
 
23
23
  return TraceEvent{
24
24
  .name = "SetLayerTreeId",
25
- .cat = {Category::Timeline},
25
+ .cat = {Category::HiddenTimeline},
26
26
  .ph = 'I',
27
27
  .ts = timestamp,
28
28
  .pid = processId,
@@ -46,7 +46,7 @@ TraceEventGenerator::createFrameTimingsEvents(
46
46
 
47
47
  auto beginEvent = TraceEvent{
48
48
  .name = "BeginFrame",
49
- .cat = {Category::Timeline},
49
+ .cat = {Category::Frame},
50
50
  .ph = 'I',
51
51
  .ts = beginDrawingTimestamp,
52
52
  .pid = processId,
@@ -56,7 +56,7 @@ TraceEventGenerator::createFrameTimingsEvents(
56
56
  };
57
57
  auto commitEvent = TraceEvent{
58
58
  .name = "Commit",
59
- .cat = {Category::Timeline},
59
+ .cat = {Category::Frame},
60
60
  .ph = 'I',
61
61
  .ts = commitTimestamp,
62
62
  .pid = processId,
@@ -66,7 +66,7 @@ TraceEventGenerator::createFrameTimingsEvents(
66
66
  };
67
67
  auto drawEvent = TraceEvent{
68
68
  .name = "DrawFrame",
69
- .cat = {Category::Timeline},
69
+ .cat = {Category::Frame},
70
70
  .ph = 'I',
71
71
  .ts = endDrawingTimestamp,
72
72
  .pid = processId,
@@ -16,12 +16,13 @@
16
16
  namespace facebook::react::jsinspector_modern::tracing {
17
17
 
18
18
  enum class Category {
19
- HiddenTimeline, /* disabled-by-default-devtools.timeline */
20
- JavaScriptSampling, /* disabled-by-default-v8.cpu_profiler */
21
- RuntimeExecution, /* v8.execute */
22
- Timeline, /* devtools.timeline */
23
- UserTiming, /* blink.user_timing */
24
- Screenshot, /* disabled-by-default-devtools.screenshot */
19
+ HiddenTimeline, /* disabled-by-default-devtools.timeline */
20
+ JavaScriptSampling, /* disabled-by-default-v8.cpu_profiler */
21
+ RuntimeExecution, /* v8.execute */
22
+ Timeline, /* devtools.timeline */
23
+ UserTiming, /* blink.user_timing */
24
+ Frame, /* disabled-by-default-devtools.timeline.frame */
25
+ Screenshot, /* disabled-by-default-devtools.screenshot */
25
26
  };
26
27
 
27
28
  inline std::string tracingCategoryToString(const Category &category)
@@ -37,6 +38,8 @@ inline std::string tracingCategoryToString(const Category &category)
37
38
  return "disabled-by-default-v8.cpu_profiler";
38
39
  case Category::RuntimeExecution:
39
40
  return "v8.execute";
41
+ case Category::Frame:
42
+ return "disabled-by-default-devtools.timeline.frame";
40
43
  case Category::Screenshot:
41
44
  return "disabled-by-default-devtools.screenshot";
42
45
  default:
@@ -57,6 +60,8 @@ inline std::optional<Category> getTracingCategoryFromString(const std::string &s
57
60
  return Category::JavaScriptSampling;
58
61
  } else if (str == "v8.execute") {
59
62
  return Category::RuntimeExecution;
63
+ } else if (str == "disabled-by-default-devtools.timeline.frame") {
64
+ return Category::Frame;
60
65
  } else if (str == "disabled-by-default-devtools.screenshot") {
61
66
  return Category::Screenshot;
62
67
  } else {
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<34d260e51b2f70825c4867c98bbcf3de>>
7
+ * @generated SignedSource<<08d50062a88a227aa8800e549b6dfe57>>
8
8
  */
9
9
 
10
10
  /**
@@ -254,6 +254,10 @@ bool ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact()
254
254
  return getAccessor().fixMappingOfEventPrioritiesBetweenFabricAndReact();
255
255
  }
256
256
 
257
+ bool ReactNativeFeatureFlags::fixTextClippingAndroid15useBoundsForWidth() {
258
+ return getAccessor().fixTextClippingAndroid15useBoundsForWidth();
259
+ }
260
+
257
261
  bool ReactNativeFeatureFlags::fuseboxAssertSingleHostState() {
258
262
  return getAccessor().fuseboxAssertSingleHostState();
259
263
  }