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.
@@ -131,6 +131,7 @@ export class URLSearchParams {
131
131
  }
132
132
  }
133
133
 
134
+ // $FlowFixMe[incompatible-use]
134
135
  return entries[Symbol.iterator]();
135
136
  }
136
137
 
@@ -149,7 +149,7 @@ type TextInputStateType = $ReadOnly<{
149
149
  blurTextInput: (textField: ?HostInstance) => void,
150
150
  }>;
151
151
 
152
- type ViewCommands = $NonMaybeType<
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
- selection: {start: -1, end: -1},
192
- mostRecentEventCount: mostRecentEventCount,
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({selection, mostRecentEventCount});
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 {setLastNativeText, setLastNativeSelection};
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: onPressIn,
603
- onPressOut: 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
- email: 'email-address',
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
- currentlyFocusedInput: TextInputState.currentlyFocusedInput,
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-20251218-c7f433a41';
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(): $NonMaybeType<typeof lazyState> {
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: $NonMaybeType<typeof lazyState> = {
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
- let rejectionTrackingOptions: $NonMaybeType<Parameters<enable>[0]> = {
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;
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(84),
26
26
  RCTVersionPatch: @(0),
27
- RCTVersionPrerelease: @"nightly-20251218-c7f433a41",
27
+ RCTVersionPrerelease: @"nightly-20251220-00eba5504",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.84.0-nightly-20251218-c7f433a41
1
+ VERSION_NAME=0.84.0-nightly-20251220-00eba5504
2
2
  react.internal.publishingGroup=com.facebook.react
3
3
  react.internal.hermesPublishingGroup=com.facebook.hermes
4
4
 
@@ -15,6 +15,6 @@ public object ReactNativeVersion {
15
15
  "major" to 0,
16
16
  "minor" to 84,
17
17
  "patch" to 0,
18
- "prerelease" to "nightly-20251218-c7f433a41"
18
+ "prerelease" to "nightly-20251220-00eba5504"
19
19
  )
20
20
  }
@@ -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-20251218-c7f433a41";
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
- propsBuilder.storeDynamic(props);
1012
- mutations.push_back(
1013
- AnimationMutation{tag, nullptr, propsBuilder.get()});
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
- if (auto family = familyIt->second.lock()) {
1024
- // C++ Animated produces props in the form of a folly::dynamic, so
1025
- // it wouldn't make sense to unpack it here. However, for the
1026
- // purposes of testing, we want to be able to use the statically
1027
- // typed AnimationMutation. At a later stage we will instead just
1028
- // pass the dynamic directly to propsBuilder and the new API could
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
- propsBuilder.storeDynamic(props);
1079
- mutations.push_back(
1080
- AnimationMutation{
1081
- .tag = tag,
1082
- .family = nullptr,
1083
- .props = propsBuilder.get(),
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
- if (auto family = familyIt->second.lock()) {
1103
+
1104
+ auto weakFamily = familyIt->second;
1105
+ if (auto family = weakFamily.lock()) {
1094
1106
  propsBuilder.storeDynamic(props);
1095
- mutations.push_back(
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
- for (auto& mutation : muatations) {
89
- hasAnyLayoutUpdates |= mutationHasLayoutUpdates(mutation);
90
- const auto family = mutation.family;
91
- if (family != nullptr) {
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
- } else {
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 (hasAnyLayoutUpdates) {
104
+ if (!surfaceUpdates.empty()) {
104
105
  commitUpdates(surfaceUpdates);
105
- } else {
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 of
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
- using AnimationMutations = std::vector<AnimationMutation>;
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
- newProps = shadowNode.getComponentDescriptor().cloneProps(
52
- propsParserContext, shadowNode.getProps(), {});
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-20251218-c7f433a41",
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-20251218-c7f433a41",
164
- "@react-native/codegen": "0.84.0-nightly-20251218-c7f433a41",
165
- "@react-native/community-cli-plugin": "0.84.0-nightly-20251218-c7f433a41",
166
- "@react-native/gradle-plugin": "0.84.0-nightly-20251218-c7f433a41",
167
- "@react-native/js-polyfills": "0.84.0-nightly-20251218-c7f433a41",
168
- "@react-native/normalize-colors": "0.84.0-nightly-20251218-c7f433a41",
169
- "@react-native/virtualized-lists": "0.84.0-nightly-20251218-c7f433a41",
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
- let waitingForQueuedOperations = new Set<string>();
51
+ const waitingForQueuedOperations = new Set<string>();
52
52
  let queueOperations = false;
53
- let queue: Array<() => void> = [];
54
- let singleOpQueue: Array<mixed> = [];
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(): $NonMaybeType<typeof NativeAnimatedModule> {
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
- getValue: (isSingleOpBatching
160
- ? (tag, saveValueCallback) => {
161
- /* $FlowFixMe[constant-condition] Error discovered during Constant
162
- * Condition roll out. See https://fburl.com/workplace/1v97vimq. */
163
- if (saveValueCallback) {
164
- eventListenerGetValueCallbacks[tag] = saveValueCallback;
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
- unsetWaitingForIdentifier(id: string): void {
190
- if (shouldSignalBatch) {
191
- return;
192
- }
193
-
194
- waitingForQueuedOperations.delete(id);
195
-
196
- if (waitingForQueuedOperations.size === 0) {
197
- queueOperations = false;
198
- API.disableQueue();
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
- createAnimatedNode(tag: number, config: AnimatedNodeConfig): void {
262
- if (config.disableBatchingForNativeCreate) {
263
- NativeAnimatedModule?.createAnimatedNode(tag, config);
264
- } else {
265
- NativeOperations.createAnimatedNode(tag, config);
266
- }
267
- },
268
-
269
- updateAnimatedNodeConfig(tag: number, config: AnimatedNodeConfig): void {
270
- NativeOperations.updateAnimatedNodeConfig?.(tag, config);
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
- startListeningToAnimatedNodeValue(tag: number): void {
274
- NativeOperations.startListeningToAnimatedNodeValue(tag);
285
+ restoreDefaultValues(nodeTag: number): void {
286
+ NativeOperations.restoreDefaultValues?.(nodeTag);
275
287
  },
276
-
277
- stopListeningToAnimatedNodeValue(tag: number): void {
278
- NativeOperations.stopListeningToAnimatedNodeValue(tag);
288
+ setAnimatedNodeOffset(nodeTag: number, offset: number): void {
289
+ NativeOperations.setAnimatedNodeOffset(nodeTag, offset);
279
290
  },
280
-
281
- connectAnimatedNodes(parentTag: number, childTag: number): void {
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
- disconnectAnimatedNodes(parentTag: number, childTag: number): void {
286
- NativeOperations.disconnectAnimatedNodes(parentTag, childTag);
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 $NonMaybeType<typeof NativeAnimatedModule>['startAnimatingNode'],
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
- setAnimatedNodeValue(nodeTag: number, value: number): void {
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
- dropAnimatedNode(tag: number): void {
352
- NativeOperations.dropAnimatedNode(tag);
353
- },
341
+ waitingForQueuedOperations.delete(id);
354
342
 
355
- addAnimatedEventToView(
356
- viewTag: number,
357
- eventName: string,
358
- eventMapping: EventMapping,
359
- ) {
360
- NativeOperations.addAnimatedEventToView(viewTag, eventName, eventMapping);
343
+ if (waitingForQueuedOperations.size === 0) {
344
+ queueOperations = false;
345
+ API.disableQueue();
346
+ }
361
347
  },
362
-
363
- removeAnimatedEventFromView(
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
- shouldUseNativeDriver,
484
- shouldSignalBatch,
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 = $NonMaybeType<typeof NativeReactNativeFeatureFlags>;
70
+ type NativeFeatureFlags = NonNullable<typeof NativeReactNativeFeatureFlags>;
71
71
 
72
72
  export function createNativeFlagGetter<K: $Keys<NativeFeatureFlags>>(
73
73
  configName: K,
74
- defaultValue: ReturnType<$NonMaybeType<NativeFeatureFlags[K]>>,
74
+ defaultValue: ReturnType<NonNullable<NativeFeatureFlags[K]>>,
75
75
  skipUnavailableNativeModuleError: boolean = false,
76
- ): Getter<ReturnType<$NonMaybeType<NativeFeatureFlags[K]>>> {
76
+ ): Getter<ReturnType<NonNullable<NativeFeatureFlags[K]>>> {
77
77
  return createGetter(
78
78
  configName,
79
79
  () => {