react-native 0.84.0-nightly-20251205-95cc1e767 → 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.
- package/Libraries/Animated/nodes/AnimatedProps.js +29 -3
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm +7 -0
- package/Libraries/NativeAnimation/React-RCTAnimation.podspec +1 -0
- package/React/Base/RCTVersion.m +1 -1
- package/React/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm +7 -0
- package/React/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h +2 -0
- package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +10 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +1 -10
- package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewAccessibilityDelegate.kt +1 -0
- package/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt +42 -28
- package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
- package/ReactCommon/jsi/jsi/jsi.cpp +2 -1
- package/ReactCommon/jsinspector-modern/HostAgent.cpp +2 -2
- package/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp +10 -5
- package/ReactCommon/jsinspector-modern/InspectorInterfaces.h +2 -2
- package/ReactCommon/jsinspector-modern/TracingAgent.cpp +1 -1
- package/ReactCommon/react/renderer/animated/AnimatedModule.cpp +19 -1
- package/ReactCommon/react/renderer/animated/AnimatedModule.h +8 -0
- package/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp +83 -9
- package/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.h +6 -0
- package/ReactCommon/react/renderer/animated/drivers/FrameAnimationDriver.cpp +1 -0
- package/ReactCommon/react/renderer/animated/nodes/ColorAnimatedNode.cpp +0 -1
- package/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.h +1 -0
- package/ReactCommon/react/renderer/animated/nodes/RoundAnimatedNode.cpp +1 -1
- package/ReactCommon/react/renderer/animated/nodes/ValueAnimatedNode.cpp +1 -1
- package/ReactCommon/react/renderer/animated/tests/AnimatedNodeTests.cpp +67 -0
- package/ReactCommon/react/renderer/animated/tests/AnimationDriverTests.cpp +59 -0
- package/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.cpp +81 -0
- package/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.h +83 -0
- package/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +26 -15
- package/ReactCommon/react/renderer/animationbackend/AnimationBackend.h +7 -4
- package/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp +69 -0
- package/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.h +32 -0
- package/ReactCommon/react/renderer/uimanager/UIManager.cpp +6 -0
- package/ReactCommon/react/renderer/uimanager/UIManagerAnimationBackend.h +1 -0
- package/package.json +9 -9
- package/sdks/hermes-engine/version.properties +1 -1
- package/src/private/animated/NativeAnimatedHelper.js +29 -1
- package/src/private/specs_DEPRECATED/modules/NativeAnimatedModule.js +4 -0
|
@@ -14,7 +14,9 @@ import type {AnimatedNodeConfig} from './AnimatedNode';
|
|
|
14
14
|
import type {AnimatedStyleAllowlist} from './AnimatedStyle';
|
|
15
15
|
|
|
16
16
|
import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
|
|
17
|
+
import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
|
|
17
18
|
import {findNodeHandle} from '../../ReactNative/RendererProxy';
|
|
19
|
+
import {getNodeFromPublicInstance} from '../../ReactPrivate/ReactNativePrivateInterface';
|
|
18
20
|
import flattenStyle from '../../StyleSheet/flattenStyle';
|
|
19
21
|
import {AnimatedEvent} from '../AnimatedEvent';
|
|
20
22
|
import AnimatedNode from './AnimatedNode';
|
|
@@ -251,7 +253,9 @@ export default class AnimatedProps extends AnimatedNode {
|
|
|
251
253
|
super.__setPlatformConfig(platformConfig);
|
|
252
254
|
|
|
253
255
|
if (this._target != null) {
|
|
254
|
-
this
|
|
256
|
+
const target = this._target;
|
|
257
|
+
this.#connectAnimatedView(target);
|
|
258
|
+
this.#connectShadowNode(target);
|
|
255
259
|
}
|
|
256
260
|
}
|
|
257
261
|
}
|
|
@@ -260,9 +264,10 @@ export default class AnimatedProps extends AnimatedNode {
|
|
|
260
264
|
if (this._target?.instance === instance) {
|
|
261
265
|
return;
|
|
262
266
|
}
|
|
263
|
-
this._target = {instance, connectedViewTag: null};
|
|
267
|
+
const target = (this._target = {instance, connectedViewTag: null});
|
|
264
268
|
if (this.__isNative) {
|
|
265
|
-
this.#connectAnimatedView(
|
|
269
|
+
this.#connectAnimatedView(target);
|
|
270
|
+
this.#connectShadowNode(target);
|
|
266
271
|
}
|
|
267
272
|
}
|
|
268
273
|
|
|
@@ -283,6 +288,27 @@ export default class AnimatedProps extends AnimatedNode {
|
|
|
283
288
|
target.connectedViewTag = viewTag;
|
|
284
289
|
}
|
|
285
290
|
|
|
291
|
+
#connectShadowNode(target: TargetView): void {
|
|
292
|
+
if (
|
|
293
|
+
!ReactNativeFeatureFlags.cxxNativeAnimatedEnabled() ||
|
|
294
|
+
//eslint-disable-next-line
|
|
295
|
+
!ReactNativeFeatureFlags.useSharedAnimatedBackend()
|
|
296
|
+
) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
invariant(this.__isNative, 'Expected node to be marked as "native"');
|
|
301
|
+
// $FlowExpectedError[incompatible-type] - target.instance may be an HTMLElement but we need ReactNativeElement for Fabric
|
|
302
|
+
const shadowNode = getNodeFromPublicInstance(target.instance);
|
|
303
|
+
if (shadowNode == null) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
NativeAnimatedHelper.API.connectAnimatedNodeToShadowNodeFamily(
|
|
307
|
+
this.__getNativeTag(),
|
|
308
|
+
shadowNode,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
286
312
|
#disconnectAnimatedView(target: TargetView): void {
|
|
287
313
|
invariant(this.__isNative, 'Expected node to be marked as "native"');
|
|
288
314
|
const viewTag = target.connectedViewTag;
|
|
@@ -29,7 +29,7 @@ export default class ReactNativeVersion {
|
|
|
29
29
|
static major: number = 0;
|
|
30
30
|
static minor: number = 84;
|
|
31
31
|
static patch: number = 0;
|
|
32
|
-
static prerelease: string | null = 'nightly-
|
|
32
|
+
static prerelease: string | null = 'nightly-20251206-63b0aef13';
|
|
33
33
|
|
|
34
34
|
static getVersionString(): string {
|
|
35
35
|
return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#import <React/RCTInitializing.h>
|
|
11
11
|
#import <React/RCTNativeAnimatedNodesManager.h>
|
|
12
12
|
#import <React/RCTNativeAnimatedTurboModule.h>
|
|
13
|
+
#import <react/debug/react_native_assert.h>
|
|
13
14
|
#import <react/featureflags/ReactNativeFeatureFlags.h>
|
|
14
15
|
|
|
15
16
|
#import "RCTAnimationPlugins.h"
|
|
@@ -165,6 +166,12 @@ RCT_EXPORT_METHOD(connectAnimatedNodeToView : (double)nodeTag viewTag : (double)
|
|
|
165
166
|
}];
|
|
166
167
|
}
|
|
167
168
|
|
|
169
|
+
RCT_EXPORT_METHOD(connectAnimatedNodeToShadowNodeFamily : (double)nodeTag shadowNode : (NSDictionary *)shadowNode)
|
|
170
|
+
{
|
|
171
|
+
// This method should only be called when using CxxNativeAnimated
|
|
172
|
+
react_native_assert(false);
|
|
173
|
+
}
|
|
174
|
+
|
|
168
175
|
RCT_EXPORT_METHOD(disconnectAnimatedNodeFromView : (double)nodeTag viewTag : (double)viewTag)
|
|
169
176
|
{
|
|
170
177
|
[self queueOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
|
|
@@ -48,6 +48,7 @@ Pod::Spec.new do |s|
|
|
|
48
48
|
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
|
49
49
|
add_dependency(s, "React-NativeModulesApple")
|
|
50
50
|
add_dependency(s, "React-featureflags")
|
|
51
|
+
add_dependency(s, "React-debug")
|
|
51
52
|
|
|
52
53
|
add_rn_third_party_dependencies(s)
|
|
53
54
|
add_rncore_dependency(s)
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(84),
|
|
26
26
|
RCTVersionPatch: @(0),
|
|
27
|
-
RCTVersionPrerelease: @"nightly-
|
|
27
|
+
RCTVersionPrerelease: @"nightly-20251206-63b0aef13",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -365,6 +365,10 @@ namespace facebook::react {
|
|
|
365
365
|
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "connectAnimatedNodeToView", @selector(connectAnimatedNodeToView:viewTag:), args, count);
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
+
static facebook::jsi::Value __hostFunction_NativeAnimatedModuleSpecJSI_connectAnimatedNodeToShadowNodeFamily(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
369
|
+
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "connectAnimatedNodeToShadowNodeFamily", @selector(connectAnimatedNodeToShadowNodeFamily:shadowNode:), args, count);
|
|
370
|
+
}
|
|
371
|
+
|
|
368
372
|
static facebook::jsi::Value __hostFunction_NativeAnimatedModuleSpecJSI_disconnectAnimatedNodeFromView(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
369
373
|
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "disconnectAnimatedNodeFromView", @selector(disconnectAnimatedNodeFromView:viewTag:), args, count);
|
|
370
374
|
}
|
|
@@ -448,6 +452,9 @@ namespace facebook::react {
|
|
|
448
452
|
methodMap_["connectAnimatedNodeToView"] = MethodMetadata {2, __hostFunction_NativeAnimatedModuleSpecJSI_connectAnimatedNodeToView};
|
|
449
453
|
|
|
450
454
|
|
|
455
|
+
methodMap_["connectAnimatedNodeToShadowNodeFamily"] = MethodMetadata {2, __hostFunction_NativeAnimatedModuleSpecJSI_connectAnimatedNodeToShadowNodeFamily};
|
|
456
|
+
|
|
457
|
+
|
|
451
458
|
methodMap_["disconnectAnimatedNodeFromView"] = MethodMetadata {2, __hostFunction_NativeAnimatedModuleSpecJSI_disconnectAnimatedNodeFromView};
|
|
452
459
|
|
|
453
460
|
|
|
@@ -323,6 +323,8 @@ saveValueCallback:(RCTResponseSenderBlock)saveValueCallback;
|
|
|
323
323
|
- (void)extractAnimatedNodeOffset:(double)nodeTag;
|
|
324
324
|
- (void)connectAnimatedNodeToView:(double)nodeTag
|
|
325
325
|
viewTag:(double)viewTag;
|
|
326
|
+
- (void)connectAnimatedNodeToShadowNodeFamily:(double)nodeTag
|
|
327
|
+
shadowNode:(NSDictionary *)shadowNode;
|
|
326
328
|
- (void)disconnectAnimatedNodeFromView:(double)nodeTag
|
|
327
329
|
viewTag:(double)viewTag;
|
|
328
330
|
- (void)restoreDefaultValues:(double)nodeTag;
|
|
@@ -1490,6 +1490,7 @@ protected:
|
|
|
1490
1490
|
methodMap_["flattenAnimatedNodeOffset"] = MethodMetadata {.argCount = 1, .invoker = __flattenAnimatedNodeOffset};
|
|
1491
1491
|
methodMap_["extractAnimatedNodeOffset"] = MethodMetadata {.argCount = 1, .invoker = __extractAnimatedNodeOffset};
|
|
1492
1492
|
methodMap_["connectAnimatedNodeToView"] = MethodMetadata {.argCount = 2, .invoker = __connectAnimatedNodeToView};
|
|
1493
|
+
methodMap_["connectAnimatedNodeToShadowNodeFamily"] = MethodMetadata {.argCount = 2, .invoker = __connectAnimatedNodeToShadowNodeFamily};
|
|
1493
1494
|
methodMap_["disconnectAnimatedNodeFromView"] = MethodMetadata {.argCount = 2, .invoker = __disconnectAnimatedNodeFromView};
|
|
1494
1495
|
methodMap_["restoreDefaultValues"] = MethodMetadata {.argCount = 1, .invoker = __restoreDefaultValues};
|
|
1495
1496
|
methodMap_["dropAnimatedNode"] = MethodMetadata {.argCount = 1, .invoker = __dropAnimatedNode};
|
|
@@ -1638,6 +1639,15 @@ private:
|
|
|
1638
1639
|
count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asNumber());return jsi::Value::undefined();
|
|
1639
1640
|
}
|
|
1640
1641
|
|
|
1642
|
+
static jsi::Value __connectAnimatedNodeToShadowNodeFamily(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
|
|
1643
|
+
static_assert(
|
|
1644
|
+
bridging::getParameterCount(&T::connectAnimatedNodeToShadowNodeFamily) == 3,
|
|
1645
|
+
"Expected connectAnimatedNodeToShadowNodeFamily(...) to have 3 parameters");
|
|
1646
|
+
bridging::callFromJs<void>(rt, &T::connectAnimatedNodeToShadowNodeFamily, static_cast<NativeAnimatedModuleCxxSpec*>(&turboModule)->jsInvoker_, static_cast<T*>(&turboModule),
|
|
1647
|
+
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(),
|
|
1648
|
+
count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt));return jsi::Value::undefined();
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1641
1651
|
static jsi::Value __disconnectAnimatedNodeFromView(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
|
|
1642
1652
|
static_assert(
|
|
1643
1653
|
bridging::getParameterCount(&T::disconnectAnimatedNodeFromView) == 3,
|
|
@@ -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
|
-
|
|
933
|
-
|
|
934
|
-
|
|
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
|
-
|
|
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
|
|
|
@@ -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-
|
|
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().
|
|
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().
|
|
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
|
|
71
|
-
state_.
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
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
|
|
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().
|
|
53
|
+
if (inspector.getSystemState().registeredHostsCount > 1) {
|
|
54
54
|
frontendChannel_(
|
|
55
55
|
cdp::jsonError(
|
|
56
56
|
req.id,
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
#include <glog/logging.h>
|
|
11
11
|
#include <jsi/JSIDynamic.h>
|
|
12
|
+
#include <react/renderer/bridging/bridging.h>
|
|
12
13
|
|
|
13
14
|
namespace facebook::react {
|
|
14
|
-
|
|
15
15
|
AnimatedModule::AnimatedModule(
|
|
16
16
|
std::shared_ptr<CallInvoker> jsInvoker,
|
|
17
17
|
std::shared_ptr<NativeAnimatedNodesManagerProvider> nodesManagerProvider)
|
|
@@ -160,6 +160,19 @@ void AnimatedModule::connectAnimatedNodeToView(
|
|
|
160
160
|
ConnectAnimatedNodeToViewOp{.nodeTag = nodeTag, .viewTag = viewTag});
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
void AnimatedModule::connectAnimatedNodeToShadowNodeFamily(
|
|
164
|
+
jsi::Runtime& rt,
|
|
165
|
+
Tag nodeTag,
|
|
166
|
+
jsi::Object shadowNodeObj) {
|
|
167
|
+
const auto& shadowNode = Bridging<std::shared_ptr<const ShadowNode>>::fromJs(
|
|
168
|
+
rt, jsi::Value(rt, shadowNodeObj));
|
|
169
|
+
|
|
170
|
+
operations_.emplace_back(
|
|
171
|
+
ConnectAnimatedNodeToShadowNodeFamilyOp{
|
|
172
|
+
.nodeTag = nodeTag,
|
|
173
|
+
.shadowNodeFamily = shadowNode->getFamilyShared()});
|
|
174
|
+
}
|
|
175
|
+
|
|
163
176
|
void AnimatedModule::disconnectAnimatedNodeFromView(
|
|
164
177
|
jsi::Runtime& /*rt*/,
|
|
165
178
|
Tag nodeTag,
|
|
@@ -282,6 +295,11 @@ void AnimatedModule::executeOperation(
|
|
|
282
295
|
DisconnectAnimatedNodeFromViewOp>) {
|
|
283
296
|
nodesManager->disconnectAnimatedNodeFromView(
|
|
284
297
|
op.nodeTag, op.viewTag);
|
|
298
|
+
} else if constexpr (std::is_same_v<
|
|
299
|
+
T,
|
|
300
|
+
ConnectAnimatedNodeToShadowNodeFamilyOp>) {
|
|
301
|
+
nodesManager->connectAnimatedNodeToShadowNodeFamily(
|
|
302
|
+
op.nodeTag, op.shadowNodeFamily);
|
|
285
303
|
} else if constexpr (std::is_same_v<T, RestoreDefaultValuesOp>) {
|
|
286
304
|
nodesManager->restoreDefaultValues(op.nodeTag);
|
|
287
305
|
} else if constexpr (std::is_same_v<T, DropAnimatedNodeOp>) {
|
|
@@ -87,6 +87,11 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec<AnimatedModule>, publi
|
|
|
87
87
|
Tag viewTag{};
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
+
struct ConnectAnimatedNodeToShadowNodeFamilyOp {
|
|
91
|
+
Tag nodeTag{};
|
|
92
|
+
std::shared_ptr<const ShadowNodeFamily> shadowNodeFamily{};
|
|
93
|
+
};
|
|
94
|
+
|
|
90
95
|
struct DisconnectAnimatedNodeFromViewOp {
|
|
91
96
|
Tag nodeTag{};
|
|
92
97
|
Tag viewTag{};
|
|
@@ -124,6 +129,7 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec<AnimatedModule>, publi
|
|
|
124
129
|
SetAnimatedNodeOffsetOp,
|
|
125
130
|
SetAnimatedNodeValueOp,
|
|
126
131
|
ConnectAnimatedNodeToViewOp,
|
|
132
|
+
ConnectAnimatedNodeToShadowNodeFamilyOp,
|
|
127
133
|
DisconnectAnimatedNodeFromViewOp,
|
|
128
134
|
RestoreDefaultValuesOp,
|
|
129
135
|
FlattenAnimatedNodeOffsetOp,
|
|
@@ -176,6 +182,8 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec<AnimatedModule>, publi
|
|
|
176
182
|
|
|
177
183
|
void connectAnimatedNodeToView(jsi::Runtime &rt, Tag nodeTag, Tag viewTag);
|
|
178
184
|
|
|
185
|
+
void connectAnimatedNodeToShadowNodeFamily(jsi::Runtime &rt, Tag nodeTag, jsi::Object shadowNode);
|
|
186
|
+
|
|
179
187
|
void disconnectAnimatedNodeFromView(jsi::Runtime &rt, Tag nodeTag, Tag viewTag);
|
|
180
188
|
|
|
181
189
|
void restoreDefaultValues(jsi::Runtime &rt, Tag nodeTag);
|
|
@@ -238,6 +238,20 @@ void NativeAnimatedNodesManager::connectAnimatedNodeToView(
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
void NativeAnimatedNodesManager::connectAnimatedNodeToShadowNodeFamily(
|
|
242
|
+
Tag propsNodeTag,
|
|
243
|
+
std::shared_ptr<const ShadowNodeFamily> family) noexcept {
|
|
244
|
+
react_native_assert(propsNodeTag);
|
|
245
|
+
auto node = getAnimatedNode<PropsAnimatedNode>(propsNodeTag);
|
|
246
|
+
if (node != nullptr && family != nullptr) {
|
|
247
|
+
std::lock_guard<std::mutex> lock(tagToShadowNodeFamilyMutex_);
|
|
248
|
+
tagToShadowNodeFamily_[family->getTag()] = family;
|
|
249
|
+
} else {
|
|
250
|
+
LOG(WARNING)
|
|
251
|
+
<< "Cannot ConnectAnimatedNodeToShadowNodeFamily, animated node has to be props type";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
241
255
|
void NativeAnimatedNodesManager::disconnectAnimatedNodeFromView(
|
|
242
256
|
Tag propsNodeTag,
|
|
243
257
|
Tag viewTag) noexcept {
|
|
@@ -251,6 +265,10 @@ void NativeAnimatedNodesManager::disconnectAnimatedNodeFromView(
|
|
|
251
265
|
std::lock_guard<std::mutex> lock(connectedAnimatedNodesMutex_);
|
|
252
266
|
connectedAnimatedNodes_.erase(viewTag);
|
|
253
267
|
}
|
|
268
|
+
{
|
|
269
|
+
std::lock_guard<std::mutex> lock(tagToShadowNodeFamilyMutex_);
|
|
270
|
+
tagToShadowNodeFamily_.erase(viewTag);
|
|
271
|
+
}
|
|
254
272
|
updatedNodeTags_.insert(node->tag());
|
|
255
273
|
|
|
256
274
|
onManagedPropsRemoved(viewTag);
|
|
@@ -705,7 +723,8 @@ void NativeAnimatedNodesManager::updateNodes(
|
|
|
705
723
|
for (auto childTag : nextNode.node->getChildren()) {
|
|
706
724
|
auto child = getAnimatedNode<AnimatedNode>(childTag);
|
|
707
725
|
child->activeIncomingNodes--;
|
|
708
|
-
if (child->activeIncomingNodes == 0 &&
|
|
726
|
+
if (child->activeIncomingNodes == 0 &&
|
|
727
|
+
child->bfsColor != animatedGraphBFSColor_) {
|
|
709
728
|
child->bfsColor = animatedGraphBFSColor_;
|
|
710
729
|
#ifdef REACT_NATIVE_DEBUG
|
|
711
730
|
updatedNodesCount++;
|
|
@@ -985,15 +1004,47 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() {
|
|
|
985
1004
|
}
|
|
986
1005
|
|
|
987
1006
|
for (auto& [tag, props] : updateViewPropsDirect_) {
|
|
988
|
-
// TODO: also handle layout props (updateViewProps_). It is skipped for
|
|
989
|
-
// now, because the backend requires shadowNodeFamilies to be able to
|
|
990
|
-
// commit to the ShadowTree
|
|
991
1007
|
propsBuilder.storeDynamic(props);
|
|
992
1008
|
mutations.push_back(
|
|
993
1009
|
AnimationMutation{tag, nullptr, propsBuilder.get()});
|
|
994
1010
|
containsChange = true;
|
|
995
1011
|
}
|
|
996
|
-
|
|
1012
|
+
{
|
|
1013
|
+
std::lock_guard<std::mutex> lock(tagToShadowNodeFamilyMutex_);
|
|
1014
|
+
for (auto& [tag, props] : updateViewProps_) {
|
|
1015
|
+
auto familyIt = tagToShadowNodeFamily_.find(tag);
|
|
1016
|
+
if (familyIt == tagToShadowNodeFamily_.end()) {
|
|
1017
|
+
continue;
|
|
1018
|
+
}
|
|
1019
|
+
if (auto family = familyIt->second.lock()) {
|
|
1020
|
+
// C++ Animated produces props in the form of a folly::dynamic, so
|
|
1021
|
+
// it wouldn't make sense to unpack it here. However, for the
|
|
1022
|
+
// purposes of testing, we want to be able to use the statically
|
|
1023
|
+
// typed AnimationMutation. At a later stage we will instead just
|
|
1024
|
+
// pass the dynamic directly to propsBuilder and the new API could
|
|
1025
|
+
// be used by 3rd party libraries or in the fututre by Animated.
|
|
1026
|
+
if (props.find("width") != props.items().end()) {
|
|
1027
|
+
propsBuilder.setWidth(
|
|
1028
|
+
yoga::Style::SizeLength::points(props["width"].asDouble()));
|
|
1029
|
+
}
|
|
1030
|
+
if (props.find("height") != props.items().end()) {
|
|
1031
|
+
propsBuilder.setHeight(
|
|
1032
|
+
yoga::Style::SizeLength::points(props["height"].asDouble()));
|
|
1033
|
+
}
|
|
1034
|
+
mutations.push_back(
|
|
1035
|
+
AnimationMutation{
|
|
1036
|
+
.tag = tag,
|
|
1037
|
+
.family = family,
|
|
1038
|
+
.props = propsBuilder.get(),
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
containsChange = true;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
if (containsChange) {
|
|
1045
|
+
updateViewPropsDirect_.clear();
|
|
1046
|
+
updateViewProps_.clear();
|
|
1047
|
+
}
|
|
997
1048
|
}
|
|
998
1049
|
|
|
999
1050
|
if (!containsChange) {
|
|
@@ -1013,16 +1064,38 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() {
|
|
|
1013
1064
|
}
|
|
1014
1065
|
}
|
|
1015
1066
|
|
|
1016
|
-
// Step 2: update all nodes that are connected to the finished
|
|
1067
|
+
// Step 2: update all nodes that are connected to the finished
|
|
1068
|
+
// animations.
|
|
1017
1069
|
updateNodes(finishedAnimationValueNodes);
|
|
1018
1070
|
|
|
1019
1071
|
isEventAnimationInProgress_ = false;
|
|
1020
1072
|
|
|
1021
1073
|
for (auto& [tag, props] : updateViewPropsDirect_) {
|
|
1022
|
-
// TODO: handle layout props
|
|
1023
1074
|
propsBuilder.storeDynamic(props);
|
|
1024
1075
|
mutations.push_back(
|
|
1025
|
-
AnimationMutation{
|
|
1076
|
+
AnimationMutation{
|
|
1077
|
+
.tag = tag,
|
|
1078
|
+
.family = nullptr,
|
|
1079
|
+
.props = propsBuilder.get(),
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
{
|
|
1083
|
+
std::lock_guard<std::mutex> lock(tagToShadowNodeFamilyMutex_);
|
|
1084
|
+
for (auto& [tag, props] : updateViewProps_) {
|
|
1085
|
+
auto familyIt = tagToShadowNodeFamily_.find(tag);
|
|
1086
|
+
if (familyIt == tagToShadowNodeFamily_.end()) {
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (auto family = familyIt->second.lock()) {
|
|
1090
|
+
propsBuilder.storeDynamic(props);
|
|
1091
|
+
mutations.push_back(
|
|
1092
|
+
AnimationMutation{
|
|
1093
|
+
.tag = tag,
|
|
1094
|
+
.family = family,
|
|
1095
|
+
.props = propsBuilder.get(),
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1026
1099
|
}
|
|
1027
1100
|
}
|
|
1028
1101
|
} else {
|
|
@@ -1103,7 +1176,8 @@ void NativeAnimatedNodesManager::onRender() {
|
|
|
1103
1176
|
}
|
|
1104
1177
|
}
|
|
1105
1178
|
|
|
1106
|
-
// Step 2: update all nodes that are connected to the finished
|
|
1179
|
+
// Step 2: update all nodes that are connected to the finished
|
|
1180
|
+
// animations.
|
|
1107
1181
|
updateNodes(finishedAnimationValueNodes);
|
|
1108
1182
|
|
|
1109
1183
|
isEventAnimationInProgress_ = false;
|