@office-iss/react-native-win32 0.0.0-canary.264 → 0.0.0-canary.265

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/.flowconfig +1 -1
  2. package/CHANGELOG.json +14981 -14942
  3. package/CHANGELOG.md +31 -19
  4. package/Libraries/Animated/AnimatedImplementation.js +2 -2
  5. package/Libraries/Animated/NativeAnimatedAllowlist.js +20 -9
  6. package/Libraries/Animated/animations/Animation.js +1 -4
  7. package/Libraries/Animated/createAnimatedComponent.js +13 -0
  8. package/Libraries/Animated/nodes/AnimatedNode.js +39 -45
  9. package/Libraries/Animated/nodes/AnimatedObject.js +13 -3
  10. package/Libraries/Animated/nodes/AnimatedProps.js +81 -37
  11. package/Libraries/Animated/nodes/AnimatedStyle.js +104 -39
  12. package/Libraries/Animated/nodes/AnimatedTransform.js +55 -22
  13. package/Libraries/Animated/nodes/AnimatedWithChildren.js +1 -3
  14. package/Libraries/Animated/useAnimatedProps.js +38 -20
  15. package/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js +3 -1
  16. package/Libraries/Components/ScrollView/ScrollView.js +12 -9
  17. package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +3 -0
  18. package/Libraries/Components/TextInput/RCTTextInputViewConfig.js +10 -0
  19. package/Libraries/Components/TextInput/TextInput.d.ts +19 -0
  20. package/Libraries/Components/TextInput/TextInput.flow.js +17 -1
  21. package/Libraries/Components/TextInput/TextInput.js +17 -1
  22. package/Libraries/Components/TextInput/TextInput.win32.js +17 -1
  23. package/Libraries/Components/Touchable/TouchableBounce.js +1 -1
  24. package/Libraries/Components/Touchable/TouchableHighlight.js +2 -2
  25. package/Libraries/Components/Touchable/TouchableOpacity.js +1 -1
  26. package/Libraries/Components/View/ReactNativeStyleAttributes.js +6 -2
  27. package/Libraries/Core/ReactNativeVersion.js +2 -2
  28. package/Libraries/Image/AssetSourceResolver.js +12 -1
  29. package/Libraries/Modal/Modal.d.ts +7 -0
  30. package/Libraries/Modal/Modal.js +9 -1
  31. package/Libraries/NativeComponent/BaseViewConfig.android.js +7 -2
  32. package/Libraries/NativeComponent/BaseViewConfig.ios.js +11 -2
  33. package/Libraries/NativeComponent/BaseViewConfig.win32.js +1 -1
  34. package/Libraries/NativeComponent/StaticViewConfigValidator.js +0 -1
  35. package/Libraries/ReactNative/AppRegistry.js +2 -6
  36. package/Libraries/ReactNative/getNativeComponentAttributes.js +4 -0
  37. package/Libraries/Renderer/shims/ReactNativeTypes.js +3 -3
  38. package/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +5 -6
  39. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +102 -5
  40. package/Libraries/StyleSheet/StyleSheetTypes.js +9 -5
  41. package/Libraries/StyleSheet/processBoxShadow.js +5 -7
  42. package/Libraries/StyleSheet/processFilter.js +4 -4
  43. package/Libraries/Text/TextNativeComponent.js +0 -1
  44. package/Libraries/Utilities/HMRClient.js +5 -5
  45. package/overrides.json +6 -6
  46. package/package.json +18 -16
  47. package/src/private/animated/NativeAnimatedHelper.js +12 -8
  48. package/src/private/animated/NativeAnimatedHelper.win32.js +12 -8
  49. package/src/private/animated/useAnimatedPropsMemo.js +349 -0
  50. package/src/private/components/HScrollViewNativeComponents.js +9 -8
  51. package/src/private/components/SafeAreaView_INTERNAL_DO_NOT_USE.js +13 -9
  52. package/src/private/components/VScrollViewNativeComponents.js +9 -8
  53. package/src/private/featureflags/ReactNativeFeatureFlags.js +50 -22
  54. package/src/private/featureflags/ReactNativeFeatureFlagsBase.js +8 -2
  55. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +7 -4
  56. package/src/private/webapis/dom/geometry/DOMRect.js +2 -2
  57. package/src/private/webapis/dom/geometry/DOMRectReadOnly.js +2 -2
  58. package/types/experimental.d.ts +0 -105
  59. package/types/modules/Codegen.d.ts +6 -0
@@ -8,8 +8,6 @@
8
8
  * @format
9
9
  */
10
10
 
11
- 'use strict';
12
-
13
11
  import type {PlatformConfig} from '../AnimatedPlatformConfig';
14
12
 
15
13
  import {validateStyles} from '../../../src/private/animated/NativeAnimatedValidation';
@@ -21,24 +19,34 @@ import AnimatedObject from './AnimatedObject';
21
19
  import AnimatedTransform from './AnimatedTransform';
22
20
  import AnimatedWithChildren from './AnimatedWithChildren';
23
21
 
22
+ export type AnimatedStyleAllowlist = $ReadOnly<{[string]: true}>;
23
+
24
24
  function createAnimatedStyle(
25
25
  inputStyle: {[string]: mixed},
26
+ allowlist: ?AnimatedStyleAllowlist,
26
27
  keepUnanimatedValues: boolean,
27
- ): [$ReadOnlyArray<string>, $ReadOnlyArray<AnimatedNode>, Object] {
28
+ ): [$ReadOnlyArray<string>, $ReadOnlyArray<AnimatedNode>, {[string]: mixed}] {
28
29
  const nodeKeys: Array<string> = [];
29
30
  const nodes: Array<AnimatedNode> = [];
30
- const style: {[string]: any} = {};
31
+ const style: {[string]: mixed} = {};
31
32
 
32
33
  const keys = Object.keys(inputStyle);
33
34
  for (let ii = 0, length = keys.length; ii < length; ii++) {
34
35
  const key = keys[ii];
35
36
  const value = inputStyle[key];
36
37
 
37
- if (value != null && key === 'transform') {
38
- const node = ReactNativeFeatureFlags.shouldUseAnimatedObjectForTransform()
39
- ? AnimatedObject.from(value)
40
- : // $FlowFixMe[incompatible-call] - `value` is mixed.
41
- new AnimatedTransform(value);
38
+ if (allowlist == null || Object.hasOwn(allowlist, key)) {
39
+ let node;
40
+ if (value != null && key === 'transform') {
41
+ node = ReactNativeFeatureFlags.shouldUseAnimatedObjectForTransform()
42
+ ? AnimatedObject.from(value)
43
+ : // $FlowFixMe[incompatible-call] - `value` is mixed.
44
+ AnimatedTransform.from(value);
45
+ } else if (value instanceof AnimatedNode) {
46
+ node = value;
47
+ } else {
48
+ node = AnimatedObject.from(value);
49
+ }
42
50
  if (node == null) {
43
51
  if (keepUnanimatedValues) {
44
52
  style[key] = value;
@@ -48,21 +56,21 @@ function createAnimatedStyle(
48
56
  nodes.push(node);
49
57
  style[key] = node;
50
58
  }
51
- } else if (value instanceof AnimatedNode) {
52
- const node = value;
53
- nodeKeys.push(key);
54
- nodes.push(node);
55
- style[key] = value;
56
59
  } else {
57
- const node = AnimatedObject.from(value);
58
- if (node == null) {
59
- if (keepUnanimatedValues) {
60
- style[key] = value;
60
+ if (__DEV__) {
61
+ // WARNING: This is a potentially expensive check that we should only
62
+ // do in development. Without this check in development, it might be
63
+ // difficult to identify which styles need to be allowlisted.
64
+ if (AnimatedObject.from(inputStyle[key]) != null) {
65
+ console.error(
66
+ `AnimatedStyle: ${key} is not allowlisted for animation, but it ` +
67
+ 'contains AnimatedNode values; styles allowing animation: ',
68
+ allowlist,
69
+ );
61
70
  }
62
- } else {
63
- nodeKeys.push(key);
64
- nodes.push(node);
65
- style[key] = node;
71
+ }
72
+ if (keepUnanimatedValues) {
73
+ style[key] = value;
66
74
  }
67
75
  }
68
76
  }
@@ -71,34 +79,54 @@ function createAnimatedStyle(
71
79
  }
72
80
 
73
81
  export default class AnimatedStyle extends AnimatedWithChildren {
82
+ #inputStyle: any;
74
83
  #nodeKeys: $ReadOnlyArray<string>;
75
84
  #nodes: $ReadOnlyArray<AnimatedNode>;
76
-
77
- _inputStyle: any;
78
- _style: {[string]: any};
79
-
80
- constructor(inputStyle: any) {
81
- super();
82
- this._inputStyle = inputStyle;
85
+ #style: {[string]: mixed};
86
+
87
+ /**
88
+ * Creates an `AnimatedStyle` if `value` contains `AnimatedNode` instances.
89
+ * Otherwise, returns `null`.
90
+ */
91
+ static from(
92
+ inputStyle: any,
93
+ allowlist: ?AnimatedStyleAllowlist,
94
+ ): ?AnimatedStyle {
95
+ const flatStyle = flattenStyle(inputStyle);
96
+ if (flatStyle == null) {
97
+ return null;
98
+ }
83
99
  const [nodeKeys, nodes, style] = createAnimatedStyle(
84
- // NOTE: This null check should not be necessary, but the types are not
85
- // strong nor enforced as of this writing. This check should be hoisted
86
- // to instantiation sites.
87
- flattenStyle(inputStyle) ?? {},
100
+ flatStyle,
101
+ allowlist,
88
102
  Platform.OS !== 'web',
89
103
  );
104
+ if (nodes.length === 0) {
105
+ return null;
106
+ }
107
+ return new AnimatedStyle(nodeKeys, nodes, style, inputStyle);
108
+ }
109
+
110
+ constructor(
111
+ nodeKeys: $ReadOnlyArray<string>,
112
+ nodes: $ReadOnlyArray<AnimatedNode>,
113
+ style: {[string]: mixed},
114
+ inputStyle: any,
115
+ ) {
116
+ super();
90
117
  this.#nodeKeys = nodeKeys;
91
118
  this.#nodes = nodes;
92
- this._style = style;
119
+ this.#style = style;
120
+ this.#inputStyle = inputStyle;
93
121
  }
94
122
 
95
123
  __getValue(): Object | Array<Object> {
96
- const style: {[string]: any} = {};
124
+ const style: {[string]: mixed} = {};
97
125
 
98
- const keys = Object.keys(this._style);
126
+ const keys = Object.keys(this.#style);
99
127
  for (let ii = 0, length = keys.length; ii < length; ii++) {
100
128
  const key = keys[ii];
101
- const value = this._style[key];
129
+ const value = this.#style[key];
102
130
 
103
131
  if (value instanceof AnimatedNode) {
104
132
  style[key] = value.__getValue();
@@ -107,11 +135,48 @@ export default class AnimatedStyle extends AnimatedWithChildren {
107
135
  }
108
136
  }
109
137
 
110
- return Platform.OS === 'web' ? [this._inputStyle, style] : style;
138
+ return Platform.OS === 'web' ? [this.#inputStyle, style] : style;
139
+ }
140
+
141
+ /**
142
+ * Creates a new `style` object that contains the same style properties as
143
+ * the supplied `staticStyle` object, except with animated nodes for any
144
+ * style properties that were created by this `AnimatedStyle` instance.
145
+ */
146
+ __getValueWithStaticStyle(staticStyle: Object): Object | Array<Object> {
147
+ const flatStaticStyle = flattenStyle(staticStyle);
148
+ const style: {[string]: mixed} =
149
+ flatStaticStyle == null
150
+ ? {}
151
+ : flatStaticStyle === staticStyle
152
+ ? // Copy the input style, since we'll mutate it below.
153
+ {...flatStaticStyle}
154
+ : // Reuse `flatStaticStyle` if it is a newly created object.
155
+ flatStaticStyle;
156
+
157
+ const keys = Object.keys(style);
158
+ for (let ii = 0, length = keys.length; ii < length; ii++) {
159
+ const key = keys[ii];
160
+ const maybeNode = this.#style[key];
161
+
162
+ if (key === 'transform' && maybeNode instanceof AnimatedTransform) {
163
+ style[key] = maybeNode.__getValueWithStaticTransforms(
164
+ // NOTE: This check should not be necessary, but the types are not
165
+ // enforced as of this writing.
166
+ Array.isArray(style[key]) ? style[key] : [],
167
+ );
168
+ } else if (maybeNode instanceof AnimatedObject) {
169
+ style[key] = maybeNode.__getValueWithStaticObject(style[key]);
170
+ } else if (maybeNode instanceof AnimatedNode) {
171
+ style[key] = maybeNode.__getValue();
172
+ }
173
+ }
174
+
175
+ return Platform.OS === 'web' ? [this.#inputStyle, style] : style;
111
176
  }
112
177
 
113
178
  __getAnimatedValue(): Object {
114
- const style: {[string]: any} = {};
179
+ const style: {[string]: mixed} = {};
115
180
 
116
181
  const nodeKeys = this.#nodeKeys;
117
182
  const nodes = this.#nodes;
@@ -26,37 +26,58 @@ type Transform<T = AnimatedNode> = {
26
26
  | {[string]: number | string | T},
27
27
  };
28
28
 
29
+ function flatAnimatedNodes(
30
+ transforms: $ReadOnlyArray<Transform<>>,
31
+ ): Array<AnimatedNode> {
32
+ const nodes = [];
33
+ for (let ii = 0, length = transforms.length; ii < length; ii++) {
34
+ const transform = transforms[ii];
35
+ // There should be exactly one property in `transform`.
36
+ for (const key in transform) {
37
+ const value = transform[key];
38
+ if (value instanceof AnimatedNode) {
39
+ nodes.push(value);
40
+ }
41
+ }
42
+ }
43
+ return nodes;
44
+ }
45
+
29
46
  export default class AnimatedTransform extends AnimatedWithChildren {
30
47
  // NOTE: For potentially historical reasons, some operations only operate on
31
48
  // the first level of AnimatedNode instances. This optimizes that bevavior.
32
- #shallowNodes: $ReadOnlyArray<AnimatedNode>;
49
+ #nodes: $ReadOnlyArray<AnimatedNode>;
33
50
 
34
51
  _transforms: $ReadOnlyArray<Transform<>>;
35
52
 
36
- constructor(transforms: $ReadOnlyArray<Transform<>>) {
53
+ /**
54
+ * Creates an `AnimatedTransform` if `transforms` contains `AnimatedNode`
55
+ * instances. Otherwise, returns `null`.
56
+ */
57
+ static from(transforms: $ReadOnlyArray<Transform<>>): ?AnimatedTransform {
58
+ const nodes = flatAnimatedNodes(
59
+ // NOTE: This check should not be necessary, but the types are not
60
+ // enforced as of this writing. This check should be hoisted to
61
+ // instantiation sites.
62
+ Array.isArray(transforms) ? transforms : [],
63
+ );
64
+ if (nodes.length === 0) {
65
+ return null;
66
+ }
67
+ return new AnimatedTransform(nodes, transforms);
68
+ }
69
+
70
+ constructor(
71
+ nodes: $ReadOnlyArray<AnimatedNode>,
72
+ transforms: $ReadOnlyArray<Transform<>>,
73
+ ) {
37
74
  super();
75
+ this.#nodes = nodes;
38
76
  this._transforms = transforms;
39
-
40
- const shallowNodes = [];
41
- // NOTE: This check should not be necessary, but the types are not enforced
42
- // as of this writing. This check should be hoisted to instantiation sites.
43
- if (Array.isArray(transforms)) {
44
- for (let ii = 0, length = transforms.length; ii < length; ii++) {
45
- const transform = transforms[ii];
46
- // There should be exactly one property in `transform`.
47
- for (const key in transform) {
48
- const value = transform[key];
49
- if (value instanceof AnimatedNode) {
50
- shallowNodes.push(value);
51
- }
52
- }
53
- }
54
- }
55
- this.#shallowNodes = shallowNodes;
56
77
  }
57
78
 
58
79
  __makeNative(platformConfig: ?PlatformConfig) {
59
- const nodes = this.#shallowNodes;
80
+ const nodes = this.#nodes;
60
81
  for (let ii = 0, length = nodes.length; ii < length; ii++) {
61
82
  const node = nodes[ii];
62
83
  node.__makeNative(platformConfig);
@@ -70,6 +91,18 @@ export default class AnimatedTransform extends AnimatedWithChildren {
70
91
  );
71
92
  }
72
93
 
94
+ __getValueWithStaticTransforms(
95
+ staticTransforms: $ReadOnlyArray<Object>,
96
+ ): $ReadOnlyArray<Object> {
97
+ const values = [];
98
+ mapTransforms(this._transforms, node => {
99
+ values.push(node.__getValue());
100
+ });
101
+ // NOTE: We can depend on `this._transforms` and `staticTransforms` sharing
102
+ // a structure because of `useAnimatedPropsMemo`.
103
+ return mapTransforms(staticTransforms, () => values.shift());
104
+ }
105
+
73
106
  __getAnimatedValue(): $ReadOnlyArray<Transform<any>> {
74
107
  return mapTransforms(this._transforms, animatedNode =>
75
108
  animatedNode.__getAnimatedValue(),
@@ -77,7 +110,7 @@ export default class AnimatedTransform extends AnimatedWithChildren {
77
110
  }
78
111
 
79
112
  __attach(): void {
80
- const nodes = this.#shallowNodes;
113
+ const nodes = this.#nodes;
81
114
  for (let ii = 0, length = nodes.length; ii < length; ii++) {
82
115
  const node = nodes[ii];
83
116
  node.__addChild(this);
@@ -85,7 +118,7 @@ export default class AnimatedTransform extends AnimatedWithChildren {
85
118
  }
86
119
 
87
120
  __detach(): void {
88
- const nodes = this.#shallowNodes;
121
+ const nodes = this.#nodes;
89
122
  for (let ii = 0, length = nodes.length; ii < length; ii++) {
90
123
  const node = nodes[ii];
91
124
  node.__removeChild(this);
@@ -28,12 +28,10 @@ export default class AnimatedWithChildren extends AnimatedNode {
28
28
  const children = this._children;
29
29
  let length = children.length;
30
30
  if (length > 0) {
31
- const nativeTag = this.__getNativeTag();
32
-
33
31
  for (let ii = 0; ii < length; ii++) {
34
32
  const child = children[ii];
35
33
  child.__makeNative(platformConfig);
36
- connectAnimatedNodes(nativeTag, child.__getNativeTag());
34
+ connectAnimatedNodes(this.__getNativeTag(), child.__getNativeTag());
37
35
  }
38
36
  }
39
37
  }
@@ -8,8 +8,7 @@
8
8
  * @format
9
9
  */
10
10
 
11
- 'use strict';
12
-
11
+ import type {AnimatedPropsAllowlist} from './nodes/AnimatedProps';
13
12
  import type {EventSubscription} from '../EventEmitter/NativeEventEmitter';
14
13
 
15
14
  import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
@@ -23,11 +22,13 @@ import AnimatedValue from './nodes/AnimatedValue';
23
22
  import {
24
23
  useCallback,
25
24
  useEffect,
25
+ useInsertionEffect,
26
26
  useLayoutEffect,
27
27
  useMemo,
28
28
  useReducer,
29
29
  useRef,
30
30
  } from 'react';
31
+ import {useAnimatedPropsMemo} from '../../src/private/animated/useAnimatedPropsMemo';
31
32
 
32
33
  type ReducedProps<TProps> = {
33
34
  ...TProps,
@@ -36,34 +37,48 @@ type ReducedProps<TProps> = {
36
37
  };
37
38
  type CallbackRef<T> = T => mixed;
38
39
 
40
+ type UpdateCallback = () => void;
41
+
39
42
  type AnimatedValueListeners = Array<{
40
43
  propValue: AnimatedValue,
41
44
  listenerId: string,
42
45
  }>;
43
46
 
47
+ const useMemoOrAnimatedPropsMemo =
48
+ ReactNativeFeatureFlags.enableAnimatedPropsMemo()
49
+ ? useAnimatedPropsMemo
50
+ : useMemo;
51
+
44
52
  export default function useAnimatedProps<TProps: {...}, TInstance>(
45
53
  props: TProps,
54
+ allowlist?: ?AnimatedPropsAllowlist,
46
55
  ): [ReducedProps<TProps>, CallbackRef<TInstance | null>] {
47
56
  const [, scheduleUpdate] = useReducer<number, void>(count => count + 1, 0);
48
- const onUpdateRef = useRef<?() => void>(null);
57
+ const onUpdateRef = useRef<UpdateCallback | null>(null);
49
58
  const timerRef = useRef<TimeoutID | null>(null);
50
59
 
51
- // TODO: Only invalidate `node` if animated props or `style` change. In the
52
- // previous implementation, we permitted `style` to override props with the
53
- // same name property name as styles, so we can probably continue doing that.
54
- // The ordering of other props *should* not matter.
55
- const node = useMemo(
56
- () => new AnimatedProps(props, () => onUpdateRef.current?.()),
57
- [props],
60
+ const allowlistIfEnabled = ReactNativeFeatureFlags.enableAnimatedAllowlist()
61
+ ? allowlist
62
+ : null;
63
+
64
+ const node = useMemoOrAnimatedPropsMemo(
65
+ () =>
66
+ new AnimatedProps(
67
+ props,
68
+ () => onUpdateRef.current?.(),
69
+ allowlistIfEnabled,
70
+ ),
71
+ [allowlistIfEnabled, props],
58
72
  );
73
+
59
74
  const useNativePropsInFabric =
60
75
  ReactNativeFeatureFlags.shouldUseSetNativePropsInFabric();
61
76
  const useSetNativePropsInNativeAnimationsInFabric =
62
77
  ReactNativeFeatureFlags.shouldUseSetNativePropsInNativeAnimationsInFabric();
63
78
 
64
79
  const useAnimatedPropsLifecycle =
65
- ReactNativeFeatureFlags.usePassiveEffectsForAnimations()
66
- ? useAnimatedPropsLifecycle_passiveEffects
80
+ ReactNativeFeatureFlags.useInsertionEffectsForAnimations()
81
+ ? useAnimatedPropsLifecycle_insertionEffects
67
82
  : useAnimatedPropsLifecycle_layoutEffects;
68
83
 
69
84
  useAnimatedPropsLifecycle(node);
@@ -195,14 +210,19 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
195
210
  );
196
211
  const callbackRef = useRefEffect<TInstance>(refEffect);
197
212
 
198
- return [reduceAnimatedProps<TProps>(node), callbackRef];
213
+ return [reduceAnimatedProps<TProps>(node, props), callbackRef];
199
214
  }
200
215
 
201
- function reduceAnimatedProps<TProps>(node: AnimatedNode): ReducedProps<TProps> {
216
+ function reduceAnimatedProps<TProps>(
217
+ node: AnimatedProps,
218
+ props: TProps,
219
+ ): ReducedProps<TProps> {
202
220
  // Force `collapsable` to be false so that the native view is not flattened.
203
221
  // Flattened views cannot be accurately referenced by the native driver.
204
222
  return {
205
- ...node.__getValue(),
223
+ ...(ReactNativeFeatureFlags.enableAnimatedPropsMemo()
224
+ ? node.__getValueWithStaticProps(props)
225
+ : node.__getValue()),
206
226
  collapsable: false,
207
227
  };
208
228
  }
@@ -301,10 +321,8 @@ function useAnimatedPropsLifecycle_layoutEffects(node: AnimatedProps): void {
301
321
  * uses reference counting to determine when to recursively detach its children
302
322
  * nodes. So in order to optimize this, we avoid detaching until the next attach
303
323
  * unless we are unmounting.
304
- *
305
- * NOTE: unlike `useAnimatedPropsLifecycle_layoutEffects`, this version uses passive effects to setup animation graph.
306
324
  */
307
- function useAnimatedPropsLifecycle_passiveEffects(node: AnimatedProps): void {
325
+ function useAnimatedPropsLifecycle_insertionEffects(node: AnimatedProps): void {
308
326
  const prevNodeRef = useRef<?AnimatedProps>(null);
309
327
  const isUnmountingRef = useRef<boolean>(false);
310
328
 
@@ -315,14 +333,14 @@ function useAnimatedPropsLifecycle_passiveEffects(node: AnimatedProps): void {
315
333
  NativeAnimatedHelper.API.flushQueue();
316
334
  });
317
335
 
318
- useEffect(() => {
336
+ useInsertionEffect(() => {
319
337
  isUnmountingRef.current = false;
320
338
  return () => {
321
339
  isUnmountingRef.current = true;
322
340
  };
323
341
  }, []);
324
342
 
325
- useEffect(() => {
343
+ useInsertionEffect(() => {
326
344
  node.__attach();
327
345
  let drivenAnimationEndedListener: ?EventSubscription = null;
328
346
 
@@ -85,7 +85,9 @@ const ProgressBarAndroid = (
85
85
  animating = true,
86
86
  ...restProps
87
87
  }: ProgressBarAndroidProps,
88
- forwardedRef: ?React.Ref<typeof ProgressBarAndroidNativeComponent>,
88
+ forwardedRef: ?React.RefSetter<
89
+ React.ElementRef<typeof ProgressBarAndroidNativeComponent>,
90
+ >,
89
91
  ) => {
90
92
  return (
91
93
  <ProgressBarAndroidNativeComponent
@@ -1931,19 +1931,22 @@ function createRefForwarder<TNativeInstance, TPublicInstance>(
1931
1931
  return state;
1932
1932
  }
1933
1933
 
1934
+ // TODO: After upgrading to React 19, remove `forwardRef` from this component.
1934
1935
  // NOTE: This wrapper component is necessary because `ScrollView` is a class
1935
1936
  // component and we need to map `ref` to a differently named prop. This can be
1936
1937
  // removed when `ScrollView` is a functional component.
1937
- function Wrapper({
1938
- ref,
1939
- ...props
1940
- }: {
1941
- ...Props,
1942
- ref: React.RefSetter<PublicScrollViewInstance>,
1943
- }): React.Node {
1944
- return <ScrollView {...props} scrollViewRef={ref} />;
1945
- }
1938
+ const Wrapper = React.forwardRef(function Wrapper(
1939
+ props: Props,
1940
+ ref: ?React.RefSetter<PublicScrollViewInstance>,
1941
+ ): React.Node {
1942
+ return ref == null ? (
1943
+ <ScrollView {...props} />
1944
+ ) : (
1945
+ <ScrollView {...props} scrollViewRef={ref} />
1946
+ );
1947
+ });
1946
1948
  Wrapper.displayName = 'ScrollView';
1949
+ // $FlowExpectedError[prop-missing]
1947
1950
  Wrapper.Context = ScrollViewContext;
1948
1951
 
1949
1952
  module.exports = ((Wrapper: $FlowFixMe): React.AbstractComponent<
@@ -160,6 +160,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
160
160
  snapToInterval: true,
161
161
  snapToOffsets: true,
162
162
  snapToStart: true,
163
+ verticalScrollIndicatorInsets: {
164
+ diff: require('../../Utilities/differ/insetsDiffer'),
165
+ },
163
166
  zoomScale: true,
164
167
  ...ConditionallyIgnoredEventHandlers({
165
168
  onScrollBeginDrag: true,
@@ -85,8 +85,15 @@ const RCTTextInputViewConfig = {
85
85
  topContentSizeChange: {
86
86
  registrationName: 'onContentSizeChange',
87
87
  },
88
+ topChangeSync: {
89
+ registrationName: 'onChangeSync',
90
+ },
91
+ topKeyPressSync: {
92
+ registrationName: 'onKeyPressSync',
93
+ },
88
94
  },
89
95
  validAttributes: {
96
+ dynamicTypeRamp: true,
90
97
  fontSize: true,
91
98
  fontWeight: true,
92
99
  fontVariant: true,
@@ -144,12 +151,15 @@ const RCTTextInputViewConfig = {
144
151
  showSoftInputOnFocus: true,
145
152
  autoFocus: true,
146
153
  lineBreakStrategyIOS: true,
154
+ lineBreakModeIOS: true,
147
155
  smartInsertDelete: true,
148
156
  ...ConditionallyIgnoredEventHandlers({
149
157
  onChange: true,
150
158
  onSelectionChange: true,
151
159
  onContentSizeChange: true,
152
160
  onScroll: true,
161
+ onChangeSync: true,
162
+ onKeyPressSync: true,
153
163
  }),
154
164
  },
155
165
  };
@@ -255,6 +255,9 @@ export interface TextInputIOSProps {
255
255
  * - `'birthdateDay'` (iOS 17+)
256
256
  * - `'birthdateMonth'` (iOS 17+)
257
257
  * - `'birthdateYear'` (iOS 17+)
258
+ * - `'dateTime'` (iOS 15+)
259
+ * - `'flightNumber'` (iOS 15+)
260
+ * - `'shipmentTrackingNumber'` (iOS 15+)
258
261
  *
259
262
  */
260
263
  textContentType?:
@@ -299,6 +302,9 @@ export interface TextInputIOSProps {
299
302
  | 'birthdateDay'
300
303
  | 'birthdateMonth'
301
304
  | 'birthdateYear'
305
+ | 'dateTime'
306
+ | 'flightNumber'
307
+ | 'shipmentTrackingNumber'
302
308
  | undefined;
303
309
 
304
310
  /**
@@ -316,6 +322,19 @@ export interface TextInputIOSProps {
316
322
  | 'push-out'
317
323
  | undefined;
318
324
 
325
+ /**
326
+ * Set line break mode on iOS.
327
+ * @platform ios
328
+ */
329
+ lineBreakModeIOS?:
330
+ | 'wordWrapping'
331
+ | 'char'
332
+ | 'clip'
333
+ | 'head'
334
+ | 'middle'
335
+ | 'tail'
336
+ | undefined;
337
+
319
338
  /**
320
339
  * If `false`, the iOS system will not insert an extra space after a paste operation
321
340
  * neither delete one or two spaces after a cut or delete operation.
@@ -198,7 +198,10 @@ export type TextContentType =
198
198
  | 'birthdate'
199
199
  | 'birthdateDay'
200
200
  | 'birthdateMonth'
201
- | 'birthdateYear';
201
+ | 'birthdateYear'
202
+ | 'dateTime'
203
+ | 'flightNumber'
204
+ | 'shipmentTrackingNumber';
202
205
 
203
206
  export type enterKeyHintType =
204
207
  | 'enter'
@@ -312,6 +315,19 @@ type IOSProps = $ReadOnly<{|
312
315
  */
313
316
  lineBreakStrategyIOS?: ?('none' | 'standard' | 'hangul-word' | 'push-out'),
314
317
 
318
+ /**
319
+ * Set line break mode on iOS.
320
+ * @platform ios
321
+ */
322
+ lineBreakModeIOS?: ?(
323
+ | 'wordWrapping'
324
+ | 'char'
325
+ | 'clip'
326
+ | 'head'
327
+ | 'middle'
328
+ | 'tail'
329
+ ),
330
+
315
331
  /**
316
332
  * If `false`, the iOS system will not insert an extra space after a paste operation
317
333
  * neither delete one or two spaces after a cut or delete operation.
@@ -238,7 +238,10 @@ export type TextContentType =
238
238
  | 'birthdate'
239
239
  | 'birthdateDay'
240
240
  | 'birthdateMonth'
241
- | 'birthdateYear';
241
+ | 'birthdateYear'
242
+ | 'dateTime'
243
+ | 'flightNumber'
244
+ | 'shipmentTrackingNumber';
242
245
 
243
246
  export type enterKeyHintType =
244
247
  // Cross Platform
@@ -358,6 +361,19 @@ type IOSProps = $ReadOnly<{|
358
361
  */
359
362
  lineBreakStrategyIOS?: ?('none' | 'standard' | 'hangul-word' | 'push-out'),
360
363
 
364
+ /**
365
+ * Set line break mode on iOS.
366
+ * @platform ios
367
+ */
368
+ lineBreakModeIOS?: ?(
369
+ | 'wordWrapping'
370
+ | 'char'
371
+ | 'clip'
372
+ | 'head'
373
+ | 'middle'
374
+ | 'tail'
375
+ ),
376
+
361
377
  /**
362
378
  * If `false`, the iOS system will not insert an extra space after a paste operation
363
379
  * neither delete one or two spaces after a cut or delete operation.