react-native 0.84.0-nightly-20251218-c7f433a41 → 0.84.0-nightly-20251220-00eba5504
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/Blob/URLSearchParams.js +1 -0
- package/Libraries/Components/TextInput/TextInput.js +33 -34
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Utilities/Appearance.js +2 -2
- package/Libraries/promiseRejectionTrackingOptions.js +8 -8
- package/React/Base/RCTVersion.m +1 -1
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
- package/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp +41 -28
- package/ReactCommon/react/renderer/animationbackend/AnimatedPropSerializer.cpp +18 -0
- package/ReactCommon/react/renderer/animationbackend/AnimatedProps.h +91 -1
- package/ReactCommon/react/renderer/animationbackend/AnimatedPropsBuilder.h +72 -0
- package/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.cpp +12 -0
- package/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.h +77 -0
- package/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +28 -25
- package/ReactCommon/react/renderer/animationbackend/AnimationBackend.h +4 -1
- package/ReactCommon/react/renderer/animationbackend/AnimationBackendCommitHook.cpp +10 -4
- package/package.json +8 -8
- package/src/private/animated/NativeAnimatedHelper.js +109 -132
- package/src/private/featureflags/ReactNativeFeatureFlagsBase.js +3 -3
|
@@ -149,7 +149,7 @@ type TextInputStateType = $ReadOnly<{
|
|
|
149
149
|
blurTextInput: (textField: ?HostInstance) => void,
|
|
150
150
|
}>;
|
|
151
151
|
|
|
152
|
-
type ViewCommands =
|
|
152
|
+
type ViewCommands = NonNullable<
|
|
153
153
|
| typeof AndroidTextInputCommands
|
|
154
154
|
| typeof RCTMultilineTextInputNativeCommands
|
|
155
155
|
| typeof RCTSinglelineTextInputNativeCommands,
|
|
@@ -188,8 +188,8 @@ function useTextInputStateSynchronization({
|
|
|
188
188
|
const [lastNativeText, setLastNativeText] = useState<?Stringish>(props.value);
|
|
189
189
|
const [lastNativeSelectionState, setLastNativeSelection] =
|
|
190
190
|
useState<LastNativeSelection>({
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
mostRecentEventCount,
|
|
192
|
+
selection: {end: -1, start: -1},
|
|
193
193
|
});
|
|
194
194
|
|
|
195
195
|
const lastNativeSelection = lastNativeSelectionState.selection;
|
|
@@ -212,7 +212,7 @@ function useTextInputStateSynchronization({
|
|
|
212
212
|
lastNativeSelection.end !== selection.end)
|
|
213
213
|
) {
|
|
214
214
|
nativeUpdate.selection = selection;
|
|
215
|
-
setLastNativeSelection({
|
|
215
|
+
setLastNativeSelection({mostRecentEventCount, selection});
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
if (Object.keys(nativeUpdate).length === 0) {
|
|
@@ -240,7 +240,7 @@ function useTextInputStateSynchronization({
|
|
|
240
240
|
viewCommands,
|
|
241
241
|
]);
|
|
242
242
|
|
|
243
|
-
return {
|
|
243
|
+
return {setLastNativeSelection, setLastNativeText};
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
/**
|
|
@@ -377,8 +377,8 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
|
|
377
377
|
propsSelection == null
|
|
378
378
|
? null
|
|
379
379
|
: {
|
|
380
|
-
start: propsSelection.start,
|
|
381
380
|
end: propsSelection.end ?? propsSelection.start,
|
|
381
|
+
start: propsSelection.start,
|
|
382
382
|
};
|
|
383
383
|
|
|
384
384
|
const text =
|
|
@@ -397,9 +397,9 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
|
|
397
397
|
const [mostRecentEventCount, setMostRecentEventCount] = useState<number>(0);
|
|
398
398
|
const {setLastNativeText, setLastNativeSelection} =
|
|
399
399
|
useTextInputStateSynchronization({
|
|
400
|
-
props,
|
|
401
400
|
inputRef,
|
|
402
401
|
mostRecentEventCount,
|
|
402
|
+
props,
|
|
403
403
|
selection,
|
|
404
404
|
text,
|
|
405
405
|
viewCommands,
|
|
@@ -469,13 +469,13 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
|
|
469
469
|
);
|
|
470
470
|
}
|
|
471
471
|
},
|
|
472
|
+
getNativeRef(): ?TextInputInstance {
|
|
473
|
+
return inputRef.current;
|
|
474
|
+
},
|
|
472
475
|
// TODO: Fix this returning true on null === null, when no input is focused
|
|
473
476
|
isFocused(): boolean {
|
|
474
477
|
return TextInputState.currentlyFocusedInput() === inputRef.current;
|
|
475
478
|
},
|
|
476
|
-
getNativeRef(): ?TextInputInstance {
|
|
477
|
-
return inputRef.current;
|
|
478
|
-
},
|
|
479
479
|
setSelection(start: number, end: number): void {
|
|
480
480
|
if (inputRef.current != null) {
|
|
481
481
|
viewCommands.setTextAndSelection(
|
|
@@ -525,8 +525,8 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
|
|
525
525
|
}
|
|
526
526
|
|
|
527
527
|
setLastNativeSelection({
|
|
528
|
-
selection: event.nativeEvent.selection,
|
|
529
528
|
mostRecentEventCount,
|
|
529
|
+
selection: event.nativeEvent.selection,
|
|
530
530
|
});
|
|
531
531
|
};
|
|
532
532
|
|
|
@@ -590,6 +590,7 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
|
|
590
590
|
|
|
591
591
|
const config = useMemo(
|
|
592
592
|
() => ({
|
|
593
|
+
cancelable: Platform.OS === 'ios' ? !rejectResponderTermination : null,
|
|
593
594
|
hitSlop,
|
|
594
595
|
onPress: (event: GestureResponderEvent) => {
|
|
595
596
|
onPress?.(event);
|
|
@@ -599,9 +600,8 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
|
|
599
600
|
}
|
|
600
601
|
}
|
|
601
602
|
},
|
|
602
|
-
onPressIn
|
|
603
|
-
onPressOut
|
|
604
|
-
cancelable: Platform.OS === 'ios' ? !rejectResponderTermination : null,
|
|
603
|
+
onPressIn,
|
|
604
|
+
onPressOut,
|
|
605
605
|
}),
|
|
606
606
|
[
|
|
607
607
|
editable,
|
|
@@ -740,12 +740,12 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
|
|
740
740
|
}
|
|
741
741
|
// For consistency with iOS set cursor/selectionHandle color as selectionColor
|
|
742
742
|
const colorProps = {
|
|
743
|
+
cursorColor: cursorColor === undefined ? selectionColor : cursorColor,
|
|
743
744
|
selectionColor,
|
|
744
745
|
selectionHandleColor:
|
|
745
746
|
selectionHandleColor === undefined
|
|
746
747
|
? selectionColor
|
|
747
748
|
: selectionHandleColor,
|
|
748
|
-
cursorColor: cursorColor === undefined ? selectionColor : cursorColor,
|
|
749
749
|
};
|
|
750
750
|
textInput = (
|
|
751
751
|
/* $FlowFixMe[prop-missing] the types for AndroidTextInput don't match up
|
|
@@ -799,8 +799,8 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
|
|
799
799
|
}
|
|
800
800
|
|
|
801
801
|
const enterKeyHintToReturnTypeMap = {
|
|
802
|
-
enter: 'default',
|
|
803
802
|
done: 'done',
|
|
803
|
+
enter: 'default',
|
|
804
804
|
go: 'go',
|
|
805
805
|
next: 'next',
|
|
806
806
|
previous: 'previous',
|
|
@@ -809,19 +809,20 @@ const enterKeyHintToReturnTypeMap = {
|
|
|
809
809
|
} as const;
|
|
810
810
|
|
|
811
811
|
const inputModeToKeyboardTypeMap = {
|
|
812
|
-
none: 'default',
|
|
813
|
-
text: 'default',
|
|
814
812
|
decimal: 'decimal-pad',
|
|
813
|
+
email: 'email-address',
|
|
814
|
+
none: 'default',
|
|
815
815
|
numeric: 'number-pad',
|
|
816
|
-
tel: 'phone-pad',
|
|
817
816
|
search:
|
|
818
817
|
Platform.OS === 'ios' ? ('web-search' as const) : ('default' as const),
|
|
819
|
-
|
|
818
|
+
tel: 'phone-pad',
|
|
819
|
+
text: 'default',
|
|
820
820
|
url: 'url',
|
|
821
821
|
} as const;
|
|
822
822
|
|
|
823
823
|
// Map HTML autocomplete values to Android autoComplete values
|
|
824
824
|
const autoCompleteWebToAutoCompleteAndroidMap = {
|
|
825
|
+
'additional-name': 'name-middle',
|
|
825
826
|
'address-line1': 'postal-address-region',
|
|
826
827
|
'address-line2': 'postal-address-locality',
|
|
827
828
|
bday: 'birthdate-full',
|
|
@@ -836,12 +837,11 @@ const autoCompleteWebToAutoCompleteAndroidMap = {
|
|
|
836
837
|
country: 'postal-address-country',
|
|
837
838
|
'current-password': 'password',
|
|
838
839
|
email: 'email',
|
|
840
|
+
'family-name': 'name-family',
|
|
841
|
+
'given-name': 'name-given',
|
|
839
842
|
'honorific-prefix': 'name-prefix',
|
|
840
843
|
'honorific-suffix': 'name-suffix',
|
|
841
844
|
name: 'name',
|
|
842
|
-
'additional-name': 'name-middle',
|
|
843
|
-
'family-name': 'name-family',
|
|
844
|
-
'given-name': 'name-given',
|
|
845
845
|
'new-password': 'password-new',
|
|
846
846
|
off: 'off',
|
|
847
847
|
'one-time-code': 'sms-otp',
|
|
@@ -856,33 +856,33 @@ const autoCompleteWebToAutoCompleteAndroidMap = {
|
|
|
856
856
|
|
|
857
857
|
// Map HTML autocomplete values to iOS textContentType values
|
|
858
858
|
const autoCompleteWebToTextContentTypeMap = {
|
|
859
|
+
'additional-name': 'middleName',
|
|
859
860
|
'address-line1': 'streetAddressLine1',
|
|
860
861
|
'address-line2': 'streetAddressLine2',
|
|
861
862
|
bday: 'birthdate',
|
|
862
863
|
'bday-day': 'birthdateDay',
|
|
863
864
|
'bday-month': 'birthdateMonth',
|
|
864
865
|
'bday-year': 'birthdateYear',
|
|
866
|
+
'cc-additional-name': 'creditCardMiddleName',
|
|
865
867
|
'cc-csc': 'creditCardSecurityCode',
|
|
868
|
+
'cc-exp': 'creditCardExpiration',
|
|
866
869
|
'cc-exp-month': 'creditCardExpirationMonth',
|
|
867
870
|
'cc-exp-year': 'creditCardExpirationYear',
|
|
868
|
-
'cc-exp': 'creditCardExpiration',
|
|
869
|
-
'cc-given-name': 'creditCardGivenName',
|
|
870
|
-
'cc-additional-name': 'creditCardMiddleName',
|
|
871
871
|
'cc-family-name': 'creditCardFamilyName',
|
|
872
|
+
'cc-given-name': 'creditCardGivenName',
|
|
872
873
|
'cc-name': 'creditCardName',
|
|
873
874
|
'cc-number': 'creditCardNumber',
|
|
874
875
|
'cc-type': 'creditCardType',
|
|
875
|
-
'current-password': 'password',
|
|
876
876
|
country: 'countryName',
|
|
877
|
+
'current-password': 'password',
|
|
877
878
|
email: 'emailAddress',
|
|
878
|
-
name: 'name',
|
|
879
|
-
'additional-name': 'middleName',
|
|
880
879
|
'family-name': 'familyName',
|
|
881
880
|
'given-name': 'givenName',
|
|
882
|
-
nickname: 'nickname',
|
|
883
881
|
'honorific-prefix': 'namePrefix',
|
|
884
882
|
'honorific-suffix': 'nameSuffix',
|
|
883
|
+
name: 'name',
|
|
885
884
|
'new-password': 'newPassword',
|
|
885
|
+
nickname: 'nickname',
|
|
886
886
|
off: 'none',
|
|
887
887
|
'one-time-code': 'oneTimeCode',
|
|
888
888
|
organization: 'organizationName',
|
|
@@ -959,11 +959,10 @@ TextInput.displayName = 'TextInput';
|
|
|
959
959
|
|
|
960
960
|
// $FlowFixMe[prop-missing]
|
|
961
961
|
TextInput.State = {
|
|
962
|
-
|
|
963
|
-
|
|
962
|
+
blurTextInput: TextInputState.blurTextInput,
|
|
964
963
|
currentlyFocusedField: TextInputState.currentlyFocusedField,
|
|
964
|
+
currentlyFocusedInput: TextInputState.currentlyFocusedInput,
|
|
965
965
|
focusTextInput: TextInputState.focusTextInput,
|
|
966
|
-
blurTextInput: TextInputState.blurTextInput,
|
|
967
966
|
};
|
|
968
967
|
|
|
969
968
|
export type TextInputComponentStatics = $ReadOnly<{
|
|
@@ -981,9 +980,9 @@ const styles = StyleSheet.create({
|
|
|
981
980
|
|
|
982
981
|
const verticalAlignToTextAlignVerticalMap = {
|
|
983
982
|
auto: 'auto',
|
|
984
|
-
top: 'top',
|
|
985
983
|
bottom: 'bottom',
|
|
986
984
|
middle: 'center',
|
|
985
|
+
top: 'top',
|
|
987
986
|
} as const;
|
|
988
987
|
|
|
989
988
|
// $FlowFixMe[unclear-type] Unclear type. Using `any` type is not safe.
|
|
@@ -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-20251220-00eba5504';
|
|
33
33
|
|
|
34
34
|
static getVersionString(): string {
|
|
35
35
|
return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
|
|
@@ -35,7 +35,7 @@ let lazyState: ?{
|
|
|
35
35
|
/**
|
|
36
36
|
* Ensures that all state and listeners are lazily initialized correctly.
|
|
37
37
|
*/
|
|
38
|
-
function getState():
|
|
38
|
+
function getState(): NonNullable<typeof lazyState> {
|
|
39
39
|
if (lazyState != null) {
|
|
40
40
|
return lazyState;
|
|
41
41
|
}
|
|
@@ -50,7 +50,7 @@ function getState(): $NonMaybeType<typeof lazyState> {
|
|
|
50
50
|
eventEmitter,
|
|
51
51
|
};
|
|
52
52
|
} else {
|
|
53
|
-
const state:
|
|
53
|
+
const state: NonNullable<typeof lazyState> = {
|
|
54
54
|
NativeAppearance,
|
|
55
55
|
appearance: null,
|
|
56
56
|
eventEmitter,
|
|
@@ -12,8 +12,15 @@ import typeof {enable} from 'promise/setimmediate/rejection-tracking';
|
|
|
12
12
|
|
|
13
13
|
import ExceptionsManager from './Core/ExceptionsManager';
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const rejectionTrackingOptions: NonNullable<Parameters<enable>[0]> = {
|
|
16
16
|
allRejections: true,
|
|
17
|
+
onHandled: id => {
|
|
18
|
+
const warning =
|
|
19
|
+
`Promise rejection handled (id: ${id})\n` +
|
|
20
|
+
'This means you can ignore any previous messages of the form ' +
|
|
21
|
+
`"Uncaught (in promise, id: ${id})"`;
|
|
22
|
+
console.warn(warning);
|
|
23
|
+
},
|
|
17
24
|
onUnhandled: (id, rejection) => {
|
|
18
25
|
let message: string;
|
|
19
26
|
|
|
@@ -46,13 +53,6 @@ let rejectionTrackingOptions: $NonMaybeType<Parameters<enable>[0]> = {
|
|
|
46
53
|
false /* isFatal */,
|
|
47
54
|
);
|
|
48
55
|
},
|
|
49
|
-
onHandled: id => {
|
|
50
|
-
const warning =
|
|
51
|
-
`Promise rejection handled (id: ${id})\n` +
|
|
52
|
-
'This means you can ignore any previous messages of the form ' +
|
|
53
|
-
`"Uncaught (in promise, id: ${id})"`;
|
|
54
|
-
console.warn(warning);
|
|
55
|
-
},
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
export default rejectionTrackingOptions;
|
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-20251220-00eba5504",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
|
@@ -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-20251220-00eba5504";
|
|
26
26
|
} ReactNativeVersion;
|
|
27
27
|
|
|
28
28
|
} // namespace facebook::react
|
|
@@ -1008,9 +1008,21 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() {
|
|
|
1008
1008
|
}
|
|
1009
1009
|
|
|
1010
1010
|
for (auto& [tag, props] : updateViewPropsDirect_) {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1011
|
+
auto familyIt = tagToShadowNodeFamily_.find(tag);
|
|
1012
|
+
if (familyIt == tagToShadowNodeFamily_.end()) {
|
|
1013
|
+
continue;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
auto weakFamily = familyIt->second;
|
|
1017
|
+
if (auto family = weakFamily.lock()) {
|
|
1018
|
+
propsBuilder.storeDynamic(props);
|
|
1019
|
+
mutations.batch.push_back(
|
|
1020
|
+
AnimationMutation{
|
|
1021
|
+
.tag = tag,
|
|
1022
|
+
.family = family,
|
|
1023
|
+
.props = propsBuilder.get(),
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1014
1026
|
containsChange = true;
|
|
1015
1027
|
}
|
|
1016
1028
|
{
|
|
@@ -1020,22 +1032,12 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() {
|
|
|
1020
1032
|
if (familyIt == tagToShadowNodeFamily_.end()) {
|
|
1021
1033
|
continue;
|
|
1022
1034
|
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
// be used by 3rd party libraries or in the fututre by Animated.
|
|
1030
|
-
if (props.find("width") != props.items().end()) {
|
|
1031
|
-
propsBuilder.setWidth(
|
|
1032
|
-
yoga::Style::SizeLength::points(props["width"].asDouble()));
|
|
1033
|
-
}
|
|
1034
|
-
if (props.find("height") != props.items().end()) {
|
|
1035
|
-
propsBuilder.setHeight(
|
|
1036
|
-
yoga::Style::SizeLength::points(props["height"].asDouble()));
|
|
1037
|
-
}
|
|
1038
|
-
mutations.push_back(
|
|
1035
|
+
|
|
1036
|
+
auto weakFamily = familyIt->second;
|
|
1037
|
+
if (auto family = weakFamily.lock()) {
|
|
1038
|
+
propsBuilder.storeDynamic(props);
|
|
1039
|
+
mutations.hasLayoutUpdates = true;
|
|
1040
|
+
mutations.batch.push_back(
|
|
1039
1041
|
AnimationMutation{
|
|
1040
1042
|
.tag = tag,
|
|
1041
1043
|
.family = family,
|
|
@@ -1075,13 +1077,21 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() {
|
|
|
1075
1077
|
isEventAnimationInProgress_ = false;
|
|
1076
1078
|
|
|
1077
1079
|
for (auto& [tag, props] : updateViewPropsDirect_) {
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1080
|
+
auto familyIt = tagToShadowNodeFamily_.find(tag);
|
|
1081
|
+
if (familyIt == tagToShadowNodeFamily_.end()) {
|
|
1082
|
+
continue;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
auto weakFamily = familyIt->second;
|
|
1086
|
+
if (auto family = weakFamily.lock()) {
|
|
1087
|
+
propsBuilder.storeDynamic(props);
|
|
1088
|
+
mutations.batch.push_back(
|
|
1089
|
+
AnimationMutation{
|
|
1090
|
+
.tag = tag,
|
|
1091
|
+
.family = family,
|
|
1092
|
+
.props = propsBuilder.get(),
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1085
1095
|
}
|
|
1086
1096
|
{
|
|
1087
1097
|
std::lock_guard<std::mutex> lock(tagToShadowNodeFamilyMutex_);
|
|
@@ -1090,9 +1100,12 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() {
|
|
|
1090
1100
|
if (familyIt == tagToShadowNodeFamily_.end()) {
|
|
1091
1101
|
continue;
|
|
1092
1102
|
}
|
|
1093
|
-
|
|
1103
|
+
|
|
1104
|
+
auto weakFamily = familyIt->second;
|
|
1105
|
+
if (auto family = weakFamily.lock()) {
|
|
1094
1106
|
propsBuilder.storeDynamic(props);
|
|
1095
|
-
mutations.
|
|
1107
|
+
mutations.hasLayoutUpdates = true;
|
|
1108
|
+
mutations.batch.push_back(
|
|
1096
1109
|
AnimationMutation{
|
|
1097
1110
|
.tag = tag,
|
|
1098
1111
|
.family = family,
|
|
@@ -265,6 +265,24 @@ void packAnimatedProp(
|
|
|
265
265
|
case MARGIN:
|
|
266
266
|
case POSITION:
|
|
267
267
|
case BORDER_WIDTH:
|
|
268
|
+
case ALIGN_CONTENT:
|
|
269
|
+
case ALIGN_ITEMS:
|
|
270
|
+
case ALIGN_SELF:
|
|
271
|
+
case ASPECT_RATIO:
|
|
272
|
+
case BOX_SIZING:
|
|
273
|
+
case DISPLAY:
|
|
274
|
+
case FLEX_BASIS:
|
|
275
|
+
case FLEX_DIRECTION:
|
|
276
|
+
case ROW_GAP:
|
|
277
|
+
case COLUMN_GAP:
|
|
278
|
+
case FLEX_GROW:
|
|
279
|
+
case FLEX_SHRINK:
|
|
280
|
+
case FLEX_WRAP:
|
|
281
|
+
case JUSTIFY_CONTENT:
|
|
282
|
+
case MAX_HEIGHT:
|
|
283
|
+
case MAX_WIDTH:
|
|
284
|
+
case MIN_HEIGHT:
|
|
285
|
+
case MIN_WIDTH:
|
|
268
286
|
throw std::runtime_error("Tried to synchronously update layout props");
|
|
269
287
|
}
|
|
270
288
|
}
|
|
@@ -33,7 +33,25 @@ enum PropName {
|
|
|
33
33
|
OUTLINE_COLOR,
|
|
34
34
|
OUTLINE_OFFSET,
|
|
35
35
|
OUTLINE_STYLE,
|
|
36
|
-
OUTLINE_WIDTH
|
|
36
|
+
OUTLINE_WIDTH,
|
|
37
|
+
ALIGN_CONTENT,
|
|
38
|
+
ALIGN_ITEMS,
|
|
39
|
+
ALIGN_SELF,
|
|
40
|
+
ASPECT_RATIO,
|
|
41
|
+
BOX_SIZING,
|
|
42
|
+
DISPLAY,
|
|
43
|
+
FLEX_BASIS,
|
|
44
|
+
FLEX_DIRECTION,
|
|
45
|
+
ROW_GAP,
|
|
46
|
+
COLUMN_GAP,
|
|
47
|
+
FLEX_GROW,
|
|
48
|
+
FLEX_SHRINK,
|
|
49
|
+
FLEX_WRAP,
|
|
50
|
+
JUSTIFY_CONTENT,
|
|
51
|
+
MAX_HEIGHT,
|
|
52
|
+
MAX_WIDTH,
|
|
53
|
+
MIN_HEIGHT,
|
|
54
|
+
MIN_WIDTH
|
|
37
55
|
};
|
|
38
56
|
|
|
39
57
|
struct AnimatedPropBase {
|
|
@@ -265,6 +283,78 @@ inline void cloneProp(BaseViewProps &viewProps, const AnimatedPropBase &animated
|
|
|
265
283
|
viewProps.outlineWidth = get<Float>(animatedProp);
|
|
266
284
|
break;
|
|
267
285
|
|
|
286
|
+
case ALIGN_CONTENT:
|
|
287
|
+
viewProps.yogaStyle.setAlignContent(get<yoga::Align>(animatedProp));
|
|
288
|
+
break;
|
|
289
|
+
|
|
290
|
+
case ALIGN_ITEMS:
|
|
291
|
+
viewProps.yogaStyle.setAlignItems(get<yoga::Align>(animatedProp));
|
|
292
|
+
break;
|
|
293
|
+
|
|
294
|
+
case ALIGN_SELF:
|
|
295
|
+
viewProps.yogaStyle.setAlignSelf(get<yoga::Align>(animatedProp));
|
|
296
|
+
break;
|
|
297
|
+
|
|
298
|
+
case ASPECT_RATIO:
|
|
299
|
+
viewProps.yogaStyle.setAspectRatio(get<yoga::FloatOptional>(animatedProp));
|
|
300
|
+
break;
|
|
301
|
+
|
|
302
|
+
case BOX_SIZING:
|
|
303
|
+
viewProps.yogaStyle.setBoxSizing(get<yoga::BoxSizing>(animatedProp));
|
|
304
|
+
break;
|
|
305
|
+
|
|
306
|
+
case DISPLAY:
|
|
307
|
+
viewProps.yogaStyle.setDisplay(get<yoga::Display>(animatedProp));
|
|
308
|
+
break;
|
|
309
|
+
|
|
310
|
+
case FLEX_BASIS:
|
|
311
|
+
viewProps.yogaStyle.setFlexBasis(get<yoga::Style::SizeLength>(animatedProp));
|
|
312
|
+
break;
|
|
313
|
+
|
|
314
|
+
case FLEX_DIRECTION:
|
|
315
|
+
viewProps.yogaStyle.setFlexDirection(get<yoga::FlexDirection>(animatedProp));
|
|
316
|
+
break;
|
|
317
|
+
|
|
318
|
+
case ROW_GAP:
|
|
319
|
+
viewProps.yogaStyle.setGap(yoga::Gutter::Row, get<yoga::Style::Length>(animatedProp));
|
|
320
|
+
break;
|
|
321
|
+
|
|
322
|
+
case COLUMN_GAP:
|
|
323
|
+
viewProps.yogaStyle.setGap(yoga::Gutter::Column, get<yoga::Style::Length>(animatedProp));
|
|
324
|
+
break;
|
|
325
|
+
|
|
326
|
+
case FLEX_GROW:
|
|
327
|
+
viewProps.yogaStyle.setFlexGrow(get<yoga::FloatOptional>(animatedProp));
|
|
328
|
+
break;
|
|
329
|
+
|
|
330
|
+
case FLEX_SHRINK:
|
|
331
|
+
viewProps.yogaStyle.setFlexShrink(get<yoga::FloatOptional>(animatedProp));
|
|
332
|
+
break;
|
|
333
|
+
|
|
334
|
+
case FLEX_WRAP:
|
|
335
|
+
viewProps.yogaStyle.setFlexWrap(get<yoga::Wrap>(animatedProp));
|
|
336
|
+
break;
|
|
337
|
+
|
|
338
|
+
case JUSTIFY_CONTENT:
|
|
339
|
+
viewProps.yogaStyle.setJustifyContent(get<yoga::Justify>(animatedProp));
|
|
340
|
+
break;
|
|
341
|
+
|
|
342
|
+
case MAX_HEIGHT:
|
|
343
|
+
viewProps.yogaStyle.setMaxDimension(yoga::Dimension::Height, get<yoga::Style::SizeLength>(animatedProp));
|
|
344
|
+
break;
|
|
345
|
+
|
|
346
|
+
case MAX_WIDTH:
|
|
347
|
+
viewProps.yogaStyle.setMaxDimension(yoga::Dimension::Width, get<yoga::Style::SizeLength>(animatedProp));
|
|
348
|
+
break;
|
|
349
|
+
|
|
350
|
+
case MIN_HEIGHT:
|
|
351
|
+
viewProps.yogaStyle.setMinDimension(yoga::Dimension::Height, get<yoga::Style::SizeLength>(animatedProp));
|
|
352
|
+
break;
|
|
353
|
+
|
|
354
|
+
case MIN_WIDTH:
|
|
355
|
+
viewProps.yogaStyle.setMinDimension(yoga::Dimension::Width, get<yoga::Style::SizeLength>(animatedProp));
|
|
356
|
+
break;
|
|
357
|
+
|
|
268
358
|
default:
|
|
269
359
|
break;
|
|
270
360
|
}
|
|
@@ -96,6 +96,78 @@ struct AnimatedPropsBuilder {
|
|
|
96
96
|
{
|
|
97
97
|
props.push_back(std::make_unique<AnimatedProp<Float>>(OUTLINE_WIDTH, value));
|
|
98
98
|
}
|
|
99
|
+
void setAlignContent(yoga::Align value)
|
|
100
|
+
{
|
|
101
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Align>>(ALIGN_CONTENT, value));
|
|
102
|
+
}
|
|
103
|
+
void setAlignItems(yoga::Align value)
|
|
104
|
+
{
|
|
105
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Align>>(ALIGN_ITEMS, value));
|
|
106
|
+
}
|
|
107
|
+
void setAlignSelf(yoga::Align value)
|
|
108
|
+
{
|
|
109
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Align>>(ALIGN_SELF, value));
|
|
110
|
+
}
|
|
111
|
+
void setAspectRatio(yoga::FloatOptional value)
|
|
112
|
+
{
|
|
113
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::FloatOptional>>(ASPECT_RATIO, value));
|
|
114
|
+
}
|
|
115
|
+
void setBoxSizing(yoga::BoxSizing value)
|
|
116
|
+
{
|
|
117
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::BoxSizing>>(BOX_SIZING, value));
|
|
118
|
+
}
|
|
119
|
+
void setDisplay(yoga::Display value)
|
|
120
|
+
{
|
|
121
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Display>>(DISPLAY, value));
|
|
122
|
+
}
|
|
123
|
+
void setFlexBasis(yoga::Style::SizeLength value)
|
|
124
|
+
{
|
|
125
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Style::SizeLength>>(FLEX_BASIS, value));
|
|
126
|
+
}
|
|
127
|
+
void setFlexDirection(yoga::FlexDirection value)
|
|
128
|
+
{
|
|
129
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::FlexDirection>>(FLEX_DIRECTION, value));
|
|
130
|
+
}
|
|
131
|
+
void setRowGap(yoga::Style::Length value)
|
|
132
|
+
{
|
|
133
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Style::Length>>(ROW_GAP, value));
|
|
134
|
+
}
|
|
135
|
+
void setColumnGap(yoga::Style::Length value)
|
|
136
|
+
{
|
|
137
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Style::Length>>(COLUMN_GAP, value));
|
|
138
|
+
}
|
|
139
|
+
void setFlexGrow(yoga::FloatOptional value)
|
|
140
|
+
{
|
|
141
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::FloatOptional>>(FLEX_GROW, value));
|
|
142
|
+
}
|
|
143
|
+
void setFlexShrink(yoga::FloatOptional value)
|
|
144
|
+
{
|
|
145
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::FloatOptional>>(FLEX_SHRINK, value));
|
|
146
|
+
}
|
|
147
|
+
void setFlexWrap(yoga::Wrap value)
|
|
148
|
+
{
|
|
149
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Wrap>>(FLEX_WRAP, value));
|
|
150
|
+
}
|
|
151
|
+
void setJustifyContent(yoga::Justify value)
|
|
152
|
+
{
|
|
153
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Justify>>(JUSTIFY_CONTENT, value));
|
|
154
|
+
}
|
|
155
|
+
void setMaxHeight(yoga::Style::SizeLength value)
|
|
156
|
+
{
|
|
157
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Style::SizeLength>>(MAX_HEIGHT, value));
|
|
158
|
+
}
|
|
159
|
+
void setMaxWidth(yoga::Style::SizeLength value)
|
|
160
|
+
{
|
|
161
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Style::SizeLength>>(MAX_WIDTH, value));
|
|
162
|
+
}
|
|
163
|
+
void setMinHeight(yoga::Style::SizeLength value)
|
|
164
|
+
{
|
|
165
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Style::SizeLength>>(MIN_HEIGHT, value));
|
|
166
|
+
}
|
|
167
|
+
void setMinWidth(yoga::Style::SizeLength value)
|
|
168
|
+
{
|
|
169
|
+
props.push_back(std::make_unique<AnimatedProp<yoga::Style::SizeLength>>(MIN_WIDTH, value));
|
|
170
|
+
}
|
|
99
171
|
void storeDynamic(folly::dynamic &d)
|
|
100
172
|
{
|
|
101
173
|
rawProps = std::make_unique<RawProps>(std::move(d));
|
|
@@ -35,6 +35,18 @@ void AnimatedPropsRegistry::update(
|
|
|
35
35
|
auto& snapshot = it->second;
|
|
36
36
|
auto& viewProps = snapshot->props;
|
|
37
37
|
|
|
38
|
+
if (animatedProps.rawProps) {
|
|
39
|
+
const auto& newRawProps = *animatedProps.rawProps;
|
|
40
|
+
auto& currentRawProps = snapshot->rawProps;
|
|
41
|
+
|
|
42
|
+
if (currentRawProps) {
|
|
43
|
+
auto newRawPropsDynamic = newRawProps.toDynamic();
|
|
44
|
+
currentRawProps->merge_patch(newRawPropsDynamic);
|
|
45
|
+
} else {
|
|
46
|
+
currentRawProps =
|
|
47
|
+
std::make_unique<folly::dynamic>(newRawProps.toDynamic());
|
|
48
|
+
}
|
|
49
|
+
}
|
|
38
50
|
for (const auto& animatedProp : animatedProps.props) {
|
|
39
51
|
snapshot->propNames.insert(animatedProp->propName);
|
|
40
52
|
cloneProp(viewProps, *animatedProp);
|
|
@@ -19,6 +19,7 @@ namespace facebook::react {
|
|
|
19
19
|
struct PropsSnapshot {
|
|
20
20
|
BaseViewProps props;
|
|
21
21
|
std::unordered_set<PropName> propNames;
|
|
22
|
+
std::unique_ptr<folly::dynamic> rawProps;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
struct SurfaceContext {
|
|
@@ -162,6 +163,82 @@ inline void updateProp(const PropName propName, BaseViewProps &viewProps, const
|
|
|
162
163
|
case OUTLINE_WIDTH:
|
|
163
164
|
viewProps.outlineWidth = snapshot.props.outlineWidth;
|
|
164
165
|
break;
|
|
166
|
+
|
|
167
|
+
case ALIGN_CONTENT:
|
|
168
|
+
viewProps.yogaStyle.setAlignContent(snapshot.props.yogaStyle.alignContent());
|
|
169
|
+
break;
|
|
170
|
+
|
|
171
|
+
case ALIGN_ITEMS:
|
|
172
|
+
viewProps.yogaStyle.setAlignItems(snapshot.props.yogaStyle.alignItems());
|
|
173
|
+
break;
|
|
174
|
+
|
|
175
|
+
case ALIGN_SELF:
|
|
176
|
+
viewProps.yogaStyle.setAlignSelf(snapshot.props.yogaStyle.alignSelf());
|
|
177
|
+
break;
|
|
178
|
+
|
|
179
|
+
case ASPECT_RATIO:
|
|
180
|
+
viewProps.yogaStyle.setAspectRatio(snapshot.props.yogaStyle.aspectRatio());
|
|
181
|
+
break;
|
|
182
|
+
|
|
183
|
+
case BOX_SIZING:
|
|
184
|
+
viewProps.yogaStyle.setBoxSizing(snapshot.props.yogaStyle.boxSizing());
|
|
185
|
+
break;
|
|
186
|
+
|
|
187
|
+
case DISPLAY:
|
|
188
|
+
viewProps.yogaStyle.setDisplay(snapshot.props.yogaStyle.display());
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
case FLEX_BASIS:
|
|
192
|
+
viewProps.yogaStyle.setFlexBasis(snapshot.props.yogaStyle.flexBasis());
|
|
193
|
+
break;
|
|
194
|
+
|
|
195
|
+
case FLEX_DIRECTION:
|
|
196
|
+
viewProps.yogaStyle.setFlexDirection(snapshot.props.yogaStyle.flexDirection());
|
|
197
|
+
break;
|
|
198
|
+
|
|
199
|
+
case ROW_GAP:
|
|
200
|
+
viewProps.yogaStyle.setGap(yoga::Gutter::Row, snapshot.props.yogaStyle.gap(yoga::Gutter::Row));
|
|
201
|
+
break;
|
|
202
|
+
|
|
203
|
+
case COLUMN_GAP:
|
|
204
|
+
viewProps.yogaStyle.setGap(yoga::Gutter::Column, snapshot.props.yogaStyle.gap(yoga::Gutter::Column));
|
|
205
|
+
break;
|
|
206
|
+
|
|
207
|
+
case FLEX_GROW:
|
|
208
|
+
viewProps.yogaStyle.setFlexGrow(snapshot.props.yogaStyle.flexGrow());
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
case FLEX_SHRINK:
|
|
212
|
+
viewProps.yogaStyle.setFlexShrink(snapshot.props.yogaStyle.flexShrink());
|
|
213
|
+
break;
|
|
214
|
+
|
|
215
|
+
case FLEX_WRAP:
|
|
216
|
+
viewProps.yogaStyle.setFlexWrap(snapshot.props.yogaStyle.flexWrap());
|
|
217
|
+
break;
|
|
218
|
+
|
|
219
|
+
case JUSTIFY_CONTENT:
|
|
220
|
+
viewProps.yogaStyle.setJustifyContent(snapshot.props.yogaStyle.justifyContent());
|
|
221
|
+
break;
|
|
222
|
+
|
|
223
|
+
case MAX_HEIGHT:
|
|
224
|
+
viewProps.yogaStyle.setMaxDimension(
|
|
225
|
+
yoga::Dimension::Height, snapshot.props.yogaStyle.maxDimension(yoga::Dimension::Height));
|
|
226
|
+
break;
|
|
227
|
+
|
|
228
|
+
case MAX_WIDTH:
|
|
229
|
+
viewProps.yogaStyle.setMaxDimension(
|
|
230
|
+
yoga::Dimension::Width, snapshot.props.yogaStyle.maxDimension(yoga::Dimension::Width));
|
|
231
|
+
break;
|
|
232
|
+
|
|
233
|
+
case MIN_HEIGHT:
|
|
234
|
+
viewProps.yogaStyle.setMinDimension(
|
|
235
|
+
yoga::Dimension::Height, snapshot.props.yogaStyle.minDimension(yoga::Dimension::Height));
|
|
236
|
+
break;
|
|
237
|
+
|
|
238
|
+
case MIN_WIDTH:
|
|
239
|
+
viewProps.yogaStyle.setMinDimension(
|
|
240
|
+
yoga::Dimension::Width, snapshot.props.yogaStyle.minDimension(yoga::Dimension::Width));
|
|
241
|
+
break;
|
|
165
242
|
}
|
|
166
243
|
}
|
|
167
244
|
|
|
@@ -6,13 +6,27 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
#include "AnimationBackend.h"
|
|
9
|
+
#include <react/debug/react_native_assert.h>
|
|
9
10
|
#include <react/renderer/animationbackend/AnimatedPropsSerializer.h>
|
|
10
11
|
#include <react/renderer/graphics/Color.h>
|
|
11
12
|
#include <chrono>
|
|
13
|
+
#include <set>
|
|
12
14
|
#include "AnimatedPropsRegistry.h"
|
|
13
15
|
|
|
14
16
|
namespace facebook::react {
|
|
15
17
|
|
|
18
|
+
static const auto layoutProps = std::set<PropName>{
|
|
19
|
+
PropName::WIDTH, PropName::HEIGHT, PropName::FLEX,
|
|
20
|
+
PropName::MARGIN, PropName::PADDING, PropName::POSITION,
|
|
21
|
+
PropName::BORDER_WIDTH, PropName::ALIGN_CONTENT, PropName::ALIGN_ITEMS,
|
|
22
|
+
PropName::ALIGN_SELF, PropName::ASPECT_RATIO, PropName::BOX_SIZING,
|
|
23
|
+
PropName::DISPLAY, PropName::FLEX_BASIS, PropName::FLEX_DIRECTION,
|
|
24
|
+
PropName::ROW_GAP, PropName::COLUMN_GAP, PropName::FLEX_GROW,
|
|
25
|
+
PropName::FLEX_SHRINK, PropName::FLEX_WRAP, PropName::JUSTIFY_CONTENT,
|
|
26
|
+
PropName::MAX_HEIGHT, PropName::MAX_WIDTH, PropName::MIN_HEIGHT,
|
|
27
|
+
PropName::MIN_WIDTH,
|
|
28
|
+
};
|
|
29
|
+
|
|
16
30
|
UIManagerNativeAnimatedDelegateBackendImpl::
|
|
17
31
|
UIManagerNativeAnimatedDelegateBackendImpl(
|
|
18
32
|
std::weak_ptr<UIManagerAnimationBackend> animationBackend)
|
|
@@ -49,21 +63,6 @@ static inline Props::Shared cloneProps(
|
|
|
49
63
|
return newProps;
|
|
50
64
|
}
|
|
51
65
|
|
|
52
|
-
static inline bool mutationHasLayoutUpdates(
|
|
53
|
-
facebook::react::AnimationMutation& mutation) {
|
|
54
|
-
for (auto& animatedProp : mutation.props.props) {
|
|
55
|
-
// TODO: there should also be a check for the dynamic part
|
|
56
|
-
if (animatedProp->propName == WIDTH || animatedProp->propName == HEIGHT ||
|
|
57
|
-
animatedProp->propName == FLEX || animatedProp->propName == MARGIN ||
|
|
58
|
-
animatedProp->propName == PADDING ||
|
|
59
|
-
animatedProp->propName == POSITION ||
|
|
60
|
-
animatedProp->propName == BORDER_WIDTH) {
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
66
|
AnimationBackend::AnimationBackend(
|
|
68
67
|
StartOnRenderCallback&& startOnRenderCallback,
|
|
69
68
|
StopOnRenderCallback&& stopOnRenderCallback,
|
|
@@ -82,17 +81,19 @@ void AnimationBackend::onAnimationFrame(double timestamp) {
|
|
|
82
81
|
std::unordered_map<Tag, AnimatedProps> synchronousUpdates;
|
|
83
82
|
std::unordered_map<SurfaceId, SurfaceUpdates> surfaceUpdates;
|
|
84
83
|
|
|
85
|
-
bool hasAnyLayoutUpdates = false;
|
|
86
84
|
for (auto& callback : callbacks) {
|
|
87
85
|
auto muatations = callback(static_cast<float>(timestamp));
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
if (muatations.hasLayoutUpdates) {
|
|
87
|
+
for (auto& mutation : muatations.batch) {
|
|
88
|
+
const auto family = mutation.family;
|
|
89
|
+
react_native_assert(family != nullptr);
|
|
90
|
+
|
|
92
91
|
auto& [families, updates] = surfaceUpdates[family->getSurfaceId()];
|
|
93
92
|
families.insert(family.get());
|
|
94
93
|
updates[mutation.tag] = std::move(mutation.props);
|
|
95
|
-
}
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
for (auto& mutation : muatations.batch) {
|
|
96
97
|
synchronousUpdates[mutation.tag] = std::move(mutation.props);
|
|
97
98
|
}
|
|
98
99
|
}
|
|
@@ -100,9 +101,11 @@ void AnimationBackend::onAnimationFrame(double timestamp) {
|
|
|
100
101
|
|
|
101
102
|
animatedPropsRegistry_->update(surfaceUpdates);
|
|
102
103
|
|
|
103
|
-
if (
|
|
104
|
+
if (!surfaceUpdates.empty()) {
|
|
104
105
|
commitUpdates(surfaceUpdates);
|
|
105
|
-
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!synchronousUpdates.empty()) {
|
|
106
109
|
synchronouslyUpdateProps(synchronousUpdates);
|
|
107
110
|
}
|
|
108
111
|
}
|
|
@@ -168,8 +171,8 @@ void AnimationBackend::commitUpdates(
|
|
|
168
171
|
void AnimationBackend::synchronouslyUpdateProps(
|
|
169
172
|
const std::unordered_map<Tag, AnimatedProps>& updates) {
|
|
170
173
|
for (auto& [tag, animatedProps] : updates) {
|
|
171
|
-
// TODO: We shouldn't repack it into dynamic, but for that a rewrite
|
|
172
|
-
// directManipulationCallback_ is needed
|
|
174
|
+
// TODO: We shouldn't repack it into dynamic, but for that a rewrite
|
|
175
|
+
// of directManipulationCallback_ is needed
|
|
173
176
|
auto dyn = animationbackend::packAnimatedProps(animatedProps);
|
|
174
177
|
directManipulationCallback_(tag, std::move(dyn));
|
|
175
178
|
}
|
|
@@ -38,7 +38,10 @@ struct AnimationMutation {
|
|
|
38
38
|
AnimatedProps props;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
struct AnimationMutations {
|
|
42
|
+
std::vector<AnimationMutation> batch;
|
|
43
|
+
bool hasLayoutUpdates{false};
|
|
44
|
+
};
|
|
42
45
|
|
|
43
46
|
class AnimationBackend : public UIManagerAnimationBackend {
|
|
44
47
|
public:
|
|
@@ -43,13 +43,19 @@ RootShadowNode::Unshared AnimationBackendCommitHook::shadowTreeWillCommit(
|
|
|
43
43
|
if (surfaceFamilies.contains(&shadowNode.getFamily()) &&
|
|
44
44
|
updates.contains(shadowNode.getTag())) {
|
|
45
45
|
auto& snapshot = updates.at(shadowNode.getTag());
|
|
46
|
-
if (!snapshot->propNames.empty()) {
|
|
46
|
+
if (!snapshot->propNames.empty() || snapshot->rawProps) {
|
|
47
47
|
PropsParserContext propsParserContext{
|
|
48
48
|
shadowNode.getSurfaceId(),
|
|
49
49
|
*shadowNode.getContextContainer()};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
if (snapshot->rawProps) {
|
|
51
|
+
newProps = shadowNode.getComponentDescriptor().cloneProps(
|
|
52
|
+
propsParserContext,
|
|
53
|
+
shadowNode.getProps(),
|
|
54
|
+
RawProps(*snapshot->rawProps));
|
|
55
|
+
} else {
|
|
56
|
+
newProps = shadowNode.getComponentDescriptor().cloneProps(
|
|
57
|
+
propsParserContext, shadowNode.getProps(), {});
|
|
58
|
+
}
|
|
53
59
|
viewProps = std::const_pointer_cast<BaseViewProps>(
|
|
54
60
|
std::static_pointer_cast<const BaseViewProps>(newProps));
|
|
55
61
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native",
|
|
3
|
-
"version": "0.84.0-nightly-
|
|
3
|
+
"version": "0.84.0-nightly-20251220-00eba5504",
|
|
4
4
|
"description": "A framework for building native apps using React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -160,13 +160,13 @@
|
|
|
160
160
|
},
|
|
161
161
|
"dependencies": {
|
|
162
162
|
"@jest/create-cache-key-function": "^29.7.0",
|
|
163
|
-
"@react-native/assets-registry": "0.84.0-nightly-
|
|
164
|
-
"@react-native/codegen": "0.84.0-nightly-
|
|
165
|
-
"@react-native/community-cli-plugin": "0.84.0-nightly-
|
|
166
|
-
"@react-native/gradle-plugin": "0.84.0-nightly-
|
|
167
|
-
"@react-native/js-polyfills": "0.84.0-nightly-
|
|
168
|
-
"@react-native/normalize-colors": "0.84.0-nightly-
|
|
169
|
-
"@react-native/virtualized-lists": "0.84.0-nightly-
|
|
163
|
+
"@react-native/assets-registry": "0.84.0-nightly-20251220-00eba5504",
|
|
164
|
+
"@react-native/codegen": "0.84.0-nightly-20251220-00eba5504",
|
|
165
|
+
"@react-native/community-cli-plugin": "0.84.0-nightly-20251220-00eba5504",
|
|
166
|
+
"@react-native/gradle-plugin": "0.84.0-nightly-20251220-00eba5504",
|
|
167
|
+
"@react-native/js-polyfills": "0.84.0-nightly-20251220-00eba5504",
|
|
168
|
+
"@react-native/normalize-colors": "0.84.0-nightly-20251220-00eba5504",
|
|
169
|
+
"@react-native/virtualized-lists": "0.84.0-nightly-20251220-00eba5504",
|
|
170
170
|
"abort-controller": "^3.0.0",
|
|
171
171
|
"anser": "^1.4.9",
|
|
172
172
|
"ansi-regex": "^5.0.0",
|
|
@@ -48,10 +48,10 @@ let __nativeAnimationIdCount = 1; /* used for started animations */
|
|
|
48
48
|
|
|
49
49
|
let nativeEventEmitter;
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
const waitingForQueuedOperations = new Set<string>();
|
|
52
52
|
let queueOperations = false;
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
const queue: Array<() => void> = [];
|
|
54
|
+
const singleOpQueue: Array<mixed> = [];
|
|
55
55
|
|
|
56
56
|
const isSingleOpBatching =
|
|
57
57
|
Platform.OS === 'android' &&
|
|
@@ -71,7 +71,7 @@ let globalEventEmitterAnimationFinishedListener: ?EventSubscription = null;
|
|
|
71
71
|
const shouldSignalBatch: boolean =
|
|
72
72
|
ReactNativeFeatureFlags.cxxNativeAnimatedEnabled();
|
|
73
73
|
|
|
74
|
-
function createNativeOperations():
|
|
74
|
+
function createNativeOperations(): NonNullable<typeof NativeAnimatedModule> {
|
|
75
75
|
const methodNames = [
|
|
76
76
|
'createAnimatedNode', // 1
|
|
77
77
|
'updateAnimatedNodeConfig', // 2
|
|
@@ -156,49 +156,35 @@ const NativeOperations = createNativeOperations();
|
|
|
156
156
|
* the native module methods, and automatic queue management on Android
|
|
157
157
|
*/
|
|
158
158
|
const API = {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
/* $FlowExpectedError[incompatible-type] - `saveValueCallback` is handled
|
|
167
|
-
differently when `isSingleOpBatching` is enabled. */
|
|
168
|
-
NativeOperations.getValue(tag);
|
|
169
|
-
}
|
|
170
|
-
: (tag, saveValueCallback) => {
|
|
171
|
-
NativeOperations.getValue(tag, saveValueCallback);
|
|
172
|
-
}) as $NonMaybeType<typeof NativeAnimatedModule>['getValue'],
|
|
173
|
-
|
|
174
|
-
setWaitingForIdentifier(id: string): void {
|
|
175
|
-
if (shouldSignalBatch) {
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
waitingForQueuedOperations.add(id);
|
|
180
|
-
queueOperations = true;
|
|
181
|
-
if (
|
|
182
|
-
ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush() &&
|
|
183
|
-
flushQueueImmediate
|
|
184
|
-
) {
|
|
185
|
-
clearImmediate(flushQueueImmediate);
|
|
186
|
-
}
|
|
159
|
+
addAnimatedEventToView(
|
|
160
|
+
viewTag: number,
|
|
161
|
+
eventName: string,
|
|
162
|
+
eventMapping: EventMapping,
|
|
163
|
+
) {
|
|
164
|
+
NativeOperations.addAnimatedEventToView(viewTag, eventName, eventMapping);
|
|
187
165
|
},
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
166
|
+
connectAnimatedNodes(parentTag: number, childTag: number): void {
|
|
167
|
+
NativeOperations.connectAnimatedNodes(parentTag, childTag);
|
|
168
|
+
},
|
|
169
|
+
connectAnimatedNodeToShadowNodeFamily(
|
|
170
|
+
nodeTag: number,
|
|
171
|
+
shadowNode: Node,
|
|
172
|
+
): void {
|
|
173
|
+
NativeOperations.connectAnimatedNodeToShadowNodeFamily?.(
|
|
174
|
+
nodeTag,
|
|
175
|
+
shadowNode,
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
connectAnimatedNodeToView(nodeTag: number, viewTag: number): void {
|
|
179
|
+
NativeOperations.connectAnimatedNodeToView(nodeTag, viewTag);
|
|
180
|
+
},
|
|
181
|
+
createAnimatedNode(tag: number, config: AnimatedNodeConfig): void {
|
|
182
|
+
if (config.disableBatchingForNativeCreate) {
|
|
183
|
+
NativeAnimatedModule?.createAnimatedNode(tag, config);
|
|
184
|
+
} else {
|
|
185
|
+
NativeOperations.createAnimatedNode(tag, config);
|
|
199
186
|
}
|
|
200
187
|
},
|
|
201
|
-
|
|
202
188
|
disableQueue(): void {
|
|
203
189
|
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
|
204
190
|
|
|
@@ -210,7 +196,21 @@ const API = {
|
|
|
210
196
|
API.flushQueue();
|
|
211
197
|
}
|
|
212
198
|
},
|
|
213
|
-
|
|
199
|
+
disconnectAnimatedNodeFromView(nodeTag: number, viewTag: number): void {
|
|
200
|
+
NativeOperations.disconnectAnimatedNodeFromView(nodeTag, viewTag);
|
|
201
|
+
},
|
|
202
|
+
disconnectAnimatedNodes(parentTag: number, childTag: number): void {
|
|
203
|
+
NativeOperations.disconnectAnimatedNodes(parentTag, childTag);
|
|
204
|
+
},
|
|
205
|
+
dropAnimatedNode(tag: number): void {
|
|
206
|
+
NativeOperations.dropAnimatedNode(tag);
|
|
207
|
+
},
|
|
208
|
+
extractAnimatedNodeOffset(nodeTag: number): void {
|
|
209
|
+
NativeOperations.extractAnimatedNodeOffset(nodeTag);
|
|
210
|
+
},
|
|
211
|
+
flattenAnimatedNodeOffset(nodeTag: number): void {
|
|
212
|
+
NativeOperations.flattenAnimatedNodeOffset(nodeTag);
|
|
213
|
+
},
|
|
214
214
|
flushQueue: (isSingleOpBatching
|
|
215
215
|
? (): void => {
|
|
216
216
|
invariant(
|
|
@@ -257,35 +257,54 @@ const API = {
|
|
|
257
257
|
NativeAnimatedModule?.finishOperationBatch?.();
|
|
258
258
|
}
|
|
259
259
|
}) as () => void,
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
260
|
+
getValue: (isSingleOpBatching
|
|
261
|
+
? (tag, saveValueCallback) => {
|
|
262
|
+
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
|
263
|
+
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
|
264
|
+
if (saveValueCallback) {
|
|
265
|
+
eventListenerGetValueCallbacks[tag] = saveValueCallback;
|
|
266
|
+
}
|
|
267
|
+
/* $FlowExpectedError[incompatible-type] - `saveValueCallback` is handled
|
|
268
|
+
differently when `isSingleOpBatching` is enabled. */
|
|
269
|
+
NativeOperations.getValue(tag);
|
|
270
|
+
}
|
|
271
|
+
: (tag, saveValueCallback) => {
|
|
272
|
+
NativeOperations.getValue(tag, saveValueCallback);
|
|
273
|
+
}) as NonNullable<typeof NativeAnimatedModule>['getValue'],
|
|
274
|
+
removeAnimatedEventFromView(
|
|
275
|
+
viewTag: number,
|
|
276
|
+
eventName: string,
|
|
277
|
+
animatedNodeTag: number,
|
|
278
|
+
) {
|
|
279
|
+
NativeOperations.removeAnimatedEventFromView(
|
|
280
|
+
viewTag,
|
|
281
|
+
eventName,
|
|
282
|
+
animatedNodeTag,
|
|
283
|
+
);
|
|
271
284
|
},
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
NativeOperations.startListeningToAnimatedNodeValue(tag);
|
|
285
|
+
restoreDefaultValues(nodeTag: number): void {
|
|
286
|
+
NativeOperations.restoreDefaultValues?.(nodeTag);
|
|
275
287
|
},
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
NativeOperations.stopListeningToAnimatedNodeValue(tag);
|
|
288
|
+
setAnimatedNodeOffset(nodeTag: number, offset: number): void {
|
|
289
|
+
NativeOperations.setAnimatedNodeOffset(nodeTag, offset);
|
|
279
290
|
},
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
NativeOperations.connectAnimatedNodes(parentTag, childTag);
|
|
291
|
+
setAnimatedNodeValue(nodeTag: number, value: number): void {
|
|
292
|
+
NativeOperations.setAnimatedNodeValue(nodeTag, value);
|
|
283
293
|
},
|
|
294
|
+
setWaitingForIdentifier(id: string): void {
|
|
295
|
+
if (shouldSignalBatch) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
284
298
|
|
|
285
|
-
|
|
286
|
-
|
|
299
|
+
waitingForQueuedOperations.add(id);
|
|
300
|
+
queueOperations = true;
|
|
301
|
+
if (
|
|
302
|
+
ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush() &&
|
|
303
|
+
flushQueueImmediate
|
|
304
|
+
) {
|
|
305
|
+
clearImmediate(flushQueueImmediate);
|
|
306
|
+
}
|
|
287
307
|
},
|
|
288
|
-
|
|
289
308
|
startAnimatingNode: (isSingleOpBatching
|
|
290
309
|
? (animationId, nodeTag, config, endCallback) => {
|
|
291
310
|
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
|
@@ -304,72 +323,30 @@ const API = {
|
|
|
304
323
|
config,
|
|
305
324
|
endCallback,
|
|
306
325
|
);
|
|
307
|
-
}) as
|
|
308
|
-
|
|
326
|
+
}) as NonNullable<typeof NativeAnimatedModule>['startAnimatingNode'],
|
|
327
|
+
startListeningToAnimatedNodeValue(tag: number): void {
|
|
328
|
+
NativeOperations.startListeningToAnimatedNodeValue(tag);
|
|
329
|
+
},
|
|
309
330
|
stopAnimation(animationId: number) {
|
|
310
331
|
NativeOperations.stopAnimation(animationId);
|
|
311
332
|
},
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
NativeOperations.setAnimatedNodeValue(nodeTag, value);
|
|
315
|
-
},
|
|
316
|
-
|
|
317
|
-
setAnimatedNodeOffset(nodeTag: number, offset: number): void {
|
|
318
|
-
NativeOperations.setAnimatedNodeOffset(nodeTag, offset);
|
|
319
|
-
},
|
|
320
|
-
|
|
321
|
-
flattenAnimatedNodeOffset(nodeTag: number): void {
|
|
322
|
-
NativeOperations.flattenAnimatedNodeOffset(nodeTag);
|
|
323
|
-
},
|
|
324
|
-
|
|
325
|
-
extractAnimatedNodeOffset(nodeTag: number): void {
|
|
326
|
-
NativeOperations.extractAnimatedNodeOffset(nodeTag);
|
|
327
|
-
},
|
|
328
|
-
|
|
329
|
-
connectAnimatedNodeToView(nodeTag: number, viewTag: number): void {
|
|
330
|
-
NativeOperations.connectAnimatedNodeToView(nodeTag, viewTag);
|
|
331
|
-
},
|
|
332
|
-
|
|
333
|
-
connectAnimatedNodeToShadowNodeFamily(
|
|
334
|
-
nodeTag: number,
|
|
335
|
-
shadowNode: Node,
|
|
336
|
-
): void {
|
|
337
|
-
NativeOperations.connectAnimatedNodeToShadowNodeFamily?.(
|
|
338
|
-
nodeTag,
|
|
339
|
-
shadowNode,
|
|
340
|
-
);
|
|
341
|
-
},
|
|
342
|
-
|
|
343
|
-
disconnectAnimatedNodeFromView(nodeTag: number, viewTag: number): void {
|
|
344
|
-
NativeOperations.disconnectAnimatedNodeFromView(nodeTag, viewTag);
|
|
345
|
-
},
|
|
346
|
-
|
|
347
|
-
restoreDefaultValues(nodeTag: number): void {
|
|
348
|
-
NativeOperations.restoreDefaultValues?.(nodeTag);
|
|
333
|
+
stopListeningToAnimatedNodeValue(tag: number): void {
|
|
334
|
+
NativeOperations.stopListeningToAnimatedNodeValue(tag);
|
|
349
335
|
},
|
|
336
|
+
unsetWaitingForIdentifier(id: string): void {
|
|
337
|
+
if (shouldSignalBatch) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
350
340
|
|
|
351
|
-
|
|
352
|
-
NativeOperations.dropAnimatedNode(tag);
|
|
353
|
-
},
|
|
341
|
+
waitingForQueuedOperations.delete(id);
|
|
354
342
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
) {
|
|
360
|
-
NativeOperations.addAnimatedEventToView(viewTag, eventName, eventMapping);
|
|
343
|
+
if (waitingForQueuedOperations.size === 0) {
|
|
344
|
+
queueOperations = false;
|
|
345
|
+
API.disableQueue();
|
|
346
|
+
}
|
|
361
347
|
},
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
viewTag: number,
|
|
365
|
-
eventName: string,
|
|
366
|
-
animatedNodeTag: number,
|
|
367
|
-
) {
|
|
368
|
-
NativeOperations.removeAnimatedEventFromView(
|
|
369
|
-
viewTag,
|
|
370
|
-
eventName,
|
|
371
|
-
animatedNodeTag,
|
|
372
|
-
);
|
|
348
|
+
updateAnimatedNodeConfig(tag: number, config: AnimatedNodeConfig): void {
|
|
349
|
+
NativeOperations.updateAnimatedNodeConfig?.(tag, config);
|
|
373
350
|
},
|
|
374
351
|
};
|
|
375
352
|
|
|
@@ -477,12 +454,9 @@ function transformDataType(value: number | string): number | string {
|
|
|
477
454
|
|
|
478
455
|
export default {
|
|
479
456
|
API,
|
|
480
|
-
generateNewNodeTag,
|
|
481
|
-
generateNewAnimationId,
|
|
482
457
|
assertNativeAnimatedModule,
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
transformDataType,
|
|
458
|
+
generateNewAnimationId,
|
|
459
|
+
generateNewNodeTag,
|
|
486
460
|
// $FlowExpectedError[unsafe-getters-setters] - unsafe getter lint suppression
|
|
487
461
|
// $FlowExpectedError[missing-type-arg] - unsafe getter lint suppression
|
|
488
462
|
get nativeEventEmitter(): NativeEventEmitter {
|
|
@@ -496,4 +470,7 @@ export default {
|
|
|
496
470
|
}
|
|
497
471
|
return nativeEventEmitter;
|
|
498
472
|
},
|
|
473
|
+
shouldSignalBatch,
|
|
474
|
+
shouldUseNativeDriver,
|
|
475
|
+
transformDataType,
|
|
499
476
|
};
|
|
@@ -67,13 +67,13 @@ export function createJavaScriptFlagGetter<
|
|
|
67
67
|
);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
type NativeFeatureFlags =
|
|
70
|
+
type NativeFeatureFlags = NonNullable<typeof NativeReactNativeFeatureFlags>;
|
|
71
71
|
|
|
72
72
|
export function createNativeFlagGetter<K: $Keys<NativeFeatureFlags>>(
|
|
73
73
|
configName: K,
|
|
74
|
-
defaultValue: ReturnType
|
|
74
|
+
defaultValue: ReturnType<NonNullable<NativeFeatureFlags[K]>>,
|
|
75
75
|
skipUnavailableNativeModuleError: boolean = false,
|
|
76
|
-
): Getter<ReturnType
|
|
76
|
+
): Getter<ReturnType<NonNullable<NativeFeatureFlags[K]>>> {
|
|
77
77
|
return createGetter(
|
|
78
78
|
configName,
|
|
79
79
|
() => {
|