@office-iss/react-native-win32 0.66.4 → 0.67.0

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 (118) hide show
  1. package/.eslintignore +2 -0
  2. package/.flowconfig +1 -1
  3. package/CHANGELOG.json +228 -46
  4. package/CHANGELOG.md +102 -25
  5. package/Libraries/ActionSheetIOS/ActionSheetIOS.js +14 -1
  6. package/Libraries/ActionSheetIOS/NativeActionSheetManager.js +2 -0
  7. package/Libraries/Animated/AnimatedEvent.js +23 -4
  8. package/Libraries/Animated/NativeAnimatedHelper.js +2 -2
  9. package/Libraries/Animated/components/AnimatedImage.js +3 -3
  10. package/Libraries/Animated/components/AnimatedScrollView.js +3 -3
  11. package/Libraries/Animated/components/AnimatedText.js +3 -3
  12. package/Libraries/Animated/components/AnimatedView.js +1 -3
  13. package/Libraries/Animated/createAnimatedComponent.js +3 -34
  14. package/Libraries/Components/Button/ButtonWin32.js +2 -2
  15. package/Libraries/Components/Button/ButtonWin32.js.map +1 -1
  16. package/Libraries/Components/Button.js +3 -0
  17. package/Libraries/Components/DatePicker/DatePickerIOS.ios.js +3 -6
  18. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +4 -7
  19. package/Libraries/Components/EnterString.win32.js +3 -3
  20. package/Libraries/Components/EnterString.win32.js.map +1 -1
  21. package/Libraries/Components/Keyboard/Keyboard.js +2 -2
  22. package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +1 -0
  23. package/Libraries/Components/ScrollView/ScrollView.js +17 -16
  24. package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +268 -252
  25. package/Libraries/Components/Text/Tests/TextWin32Test.d.ts +0 -1
  26. package/Libraries/Components/Text/TextWin32.Props.d.ts +2 -2
  27. package/Libraries/Components/Text/TextWin32.Props.js.map +1 -1
  28. package/Libraries/Components/Text/TextWin32.js +1 -1
  29. package/Libraries/Components/Text/TextWin32.js.map +1 -1
  30. package/Libraries/Components/TextInput/Tests/TextInputTest.d.ts +0 -1
  31. package/Libraries/Components/TextInput/TextInput.win32.js +6 -6
  32. package/Libraries/Components/TextInput/TextInput.win32.js.map +1 -1
  33. package/Libraries/Components/Touchable/Tests/TouchableWin32Test.d.ts +0 -1
  34. package/Libraries/Components/Touchable/Tests/TouchableWin32Test.js +1 -1
  35. package/Libraries/Components/Touchable/Tests/TouchableWin32Test.js.map +1 -1
  36. package/Libraries/Components/Touchable/TouchableNativeFeedback.win32.js +2 -2
  37. package/Libraries/Components/Touchable/TouchableNativeFeedback.win32.js.map +1 -1
  38. package/Libraries/Components/Touchable/TouchableWin32.js +2 -2
  39. package/Libraries/Components/Touchable/TouchableWin32.js.map +1 -1
  40. package/Libraries/Components/View/Tests/ViewWin32Test.d.ts +0 -1
  41. package/Libraries/Components/View/View.js +1 -1
  42. package/Libraries/Components/View/View.win32.js +1 -1
  43. package/Libraries/Components/View/ViewAccessibility.js +1 -1
  44. package/Libraries/Components/View/ViewWin32.Props.d.ts +3 -6
  45. package/Libraries/Components/View/ViewWin32.Props.js.map +1 -1
  46. package/Libraries/Components/View/ViewWin32.js +5 -5
  47. package/Libraries/Components/View/ViewWin32.js.map +1 -1
  48. package/Libraries/Core/ExceptionsManager.js +45 -80
  49. package/Libraries/Core/ExtendedError.js +0 -1
  50. package/Libraries/Core/ReactNativeVersion.js +3 -3
  51. package/Libraries/Core/setUpBatchedBridge.js +1 -1
  52. package/Libraries/Core/setUpGlobals.js +2 -4
  53. package/Libraries/Core/setUpTimers.js +2 -2
  54. package/Libraries/Image/Image.ios.js +6 -0
  55. package/Libraries/Image/Image.win32.js +6 -0
  56. package/Libraries/Image/ImageBackground.js +10 -8
  57. package/Libraries/Image/ImageProps.js +28 -0
  58. package/Libraries/Image/Tests/ImageWin32Test.d.ts +0 -1
  59. package/Libraries/LogBox/Data/LogBoxData.js +18 -19
  60. package/Libraries/LogBox/UI/LogBoxImages/alert-triangle.png +0 -0
  61. package/Libraries/LogBox/UI/LogBoxImages/chevron-left.png +0 -0
  62. package/Libraries/LogBox/UI/LogBoxImages/chevron-right.png +0 -0
  63. package/Libraries/LogBox/UI/LogBoxImages/close.png +0 -0
  64. package/Libraries/LogBox/UI/LogBoxImages/loader.png +0 -0
  65. package/Libraries/NewAppScreen/components/logo.png +0 -0
  66. package/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +2 -1
  67. package/Libraries/PermissionsAndroid/PermissionsAndroid.js +2 -0
  68. package/Libraries/PersonaCoin/PersonaCoin.js +3 -2
  69. package/Libraries/PersonaCoin/PersonaCoin.js.map +1 -1
  70. package/Libraries/Pressability/Pressability.js +13 -13
  71. package/Libraries/Pressability/Pressability.win32.js +13 -13
  72. package/Libraries/Pressability/PressabilityPerformanceEventEmitter.js +1 -1
  73. package/Libraries/ReactNative/AppRegistry.js +4 -2
  74. package/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +1569 -875
  75. package/Libraries/Renderer/implementations/ReactFabric-prod.fb.js +529 -319
  76. package/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js +570 -362
  77. package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +1592 -891
  78. package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js +521 -311
  79. package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js +562 -354
  80. package/Libraries/Share/Share.js +1 -1
  81. package/Libraries/StyleSheet/normalizeColor.js +2 -2
  82. package/Libraries/Text/TextProps.js +1 -7
  83. package/Libraries/TurboModule/TurboModuleRegistry.js +1 -1
  84. package/Libraries/Utilities/HMRClient.js +1 -1
  85. package/flow/global.js +45 -0
  86. package/index.js +15 -10
  87. package/index.win32.js +15 -10
  88. package/jest/mockModal.js +31 -0
  89. package/jest/preprocessor.js +7 -75
  90. package/jest/setup.js +5 -3
  91. package/overrides.json +8 -14
  92. package/package.json +19 -17
  93. package/rntypes/BatchedBridge.d.ts +23 -0
  94. package/rntypes/Devtools.d.ts +20 -0
  95. package/rntypes/LaunchScreen.d.ts +9 -0
  96. package/rntypes/globals.d.ts +496 -0
  97. package/rntypes/index.d.ts +9966 -0
  98. package/rntypes/legacy-properties.d.ts +266 -0
  99. package/src/Libraries/Components/Text/TextWin32.Props.ts +2 -2
  100. package/src/Libraries/Components/View/ViewWin32.Props.ts +6 -12
  101. package/src/rntypes/BatchedBridge.d.ts +23 -0
  102. package/src/rntypes/Devtools.d.ts +20 -0
  103. package/src/rntypes/LaunchScreen.d.ts +9 -0
  104. package/src/rntypes/globals.d.ts +496 -0
  105. package/src/rntypes/index.d.ts +9966 -0
  106. package/src/rntypes/legacy-properties.d.ts +266 -0
  107. package/src/typings-index.ts +11 -4
  108. package/typings-index.d.ts +3 -1
  109. package/typings-index.js +7 -5
  110. package/typings-index.js.map +1 -1
  111. package/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js +0 -87
  112. package/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js +0 -30
  113. package/Libraries/Components/DatePickerAndroid/DatePickerAndroid.win32.js +0 -30
  114. package/Libraries/Components/DatePickerAndroid/DatePickerAndroidTypes.js +0 -30
  115. package/Libraries/Components/StaticContainer.react.js +0 -51
  116. package/Libraries/Components/Touchable/ensurePositiveDelayProps.js +0 -25
  117. package/Libraries/Interaction/InteractionMixin.js +0 -54
  118. package/Libraries/ReactNative/queryLayoutByID.js +0 -58
@@ -4,25 +4,29 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @flow strict-local
7
+ * @flow
8
8
  * @format
9
9
  */
10
10
 
11
- import type {LayoutEvent} from '../../Types/CoreEventTypes';
12
- import setAndForwardRef from 'react-native/Libraries/Utilities/setAndForwardRef';
13
- import Platform from '../../Utilities/Platform';
14
- import StyleSheet from '../../StyleSheet/StyleSheet';
15
- import Animated from '../../Animated/Animated';
11
+ import AnimatedImplementation from '../../Animated/AnimatedImplementation';
12
+ import AnimatedAddition from '../../Animated/nodes/AnimatedAddition';
13
+ import AnimatedDiffClamp from '../../Animated/nodes/AnimatedDiffClamp';
14
+ import AnimatedNode from '../../Animated/nodes/AnimatedNode';
15
+
16
16
  import * as React from 'react';
17
- import {useEffect, useMemo, useRef, useCallback} from 'react';
17
+ import StyleSheet from '../../StyleSheet/StyleSheet';
18
+ import View from '../View/View';
19
+ import Platform from '../../Utilities/Platform';
20
+
21
+ import type {LayoutEvent} from '../../Types/CoreEventTypes';
18
22
 
19
- const AnimatedView = Animated.View;
23
+ const AnimatedView = AnimatedImplementation.createAnimatedComponent(View);
20
24
 
21
25
  export type Props = $ReadOnly<{
22
- children?: React.Element<$FlowFixMe>,
26
+ children?: React.Element<any>,
23
27
  nextHeaderLayoutY: ?number,
24
28
  onLayout: (event: LayoutEvent) => void,
25
- scrollAnimatedValue: Animated.Value,
29
+ scrollAnimatedValue: AnimatedImplementation.Value,
26
30
  // Will cause sticky headers to stick at the bottom of the ScrollView instead
27
31
  // of the top.
28
32
  inverted: ?boolean,
@@ -32,275 +36,287 @@ export type Props = $ReadOnly<{
32
36
  hiddenOnScroll?: ?boolean,
33
37
  }>;
34
38
 
35
- const ScrollViewStickyHeaderWithForwardedRef: React.AbstractComponent<
36
- Props,
37
- $ReadOnly<{
38
- setNextHeaderY: number => void,
39
- ...$Exact<React.ElementRef<typeof AnimatedView>>,
40
- }>,
41
- > = React.forwardRef(function ScrollViewStickyHeader(props, forwardedRef) {
42
- const {
43
- inverted,
44
- scrollViewHeight,
45
- hiddenOnScroll,
46
- scrollAnimatedValue,
47
- nextHeaderLayoutY: _nextHeaderLayoutY,
48
- } = props;
39
+ type State = {
40
+ measured: boolean,
41
+ layoutY: number,
42
+ layoutHeight: number,
43
+ nextHeaderLayoutY: ?number,
44
+ translateY: ?number,
45
+ ...
46
+ };
49
47
 
50
- const [measured, setMeasured] = React.useState<boolean>(false);
51
- const [layoutY, setLayoutY] = React.useState<number>(0);
52
- const [layoutHeight, setLayoutHeight] = React.useState<number>(0);
53
- const [translateY, setTranslateY] = React.useState<?number>(null);
54
- const [nextHeaderLayoutY, setNextHeaderLayoutY] = React.useState<?number>(
55
- _nextHeaderLayoutY,
56
- );
57
- const [isFabric, setIsFabric] = React.useState<boolean>(false);
48
+ class ScrollViewStickyHeader extends React.Component<Props, State> {
49
+ state: State = {
50
+ measured: false,
51
+ layoutY: 0,
52
+ layoutHeight: 0,
53
+ nextHeaderLayoutY: this.props.nextHeaderLayoutY,
54
+ translateY: null,
55
+ };
58
56
 
59
- const componentRef = React.useRef<?React.ElementRef<typeof AnimatedView>>();
60
- const _setNativeRef = setAndForwardRef({
61
- getForwardedRef: () => forwardedRef,
62
- setLocalRef: ref => {
63
- componentRef.current = ref;
64
- if (ref) {
65
- ref.setNextHeaderY = value => {
66
- setNextHeaderLayoutY(value);
67
- };
68
- setIsFabric(
69
- !!(
70
- // An internal transform mangles variables with leading "_" as private.
71
- // eslint-disable-next-line dot-notation
72
- ref['_internalInstanceHandle']?.stateNode?.canonical
73
- ),
74
- );
75
- }
76
- },
77
- });
57
+ _translateY: ?AnimatedNode = null;
58
+ _shouldRecreateTranslateY: boolean = true;
59
+ _haveReceivedInitialZeroTranslateY: boolean = true;
60
+ _ref: any; // TODO T53738161: flow type this, and the whole file
78
61
 
79
- const offset = useMemo(
80
- () =>
81
- hiddenOnScroll === true
82
- ? Animated.diffClamp(
83
- scrollAnimatedValue
84
- .interpolate({
85
- extrapolateLeft: 'clamp',
86
- inputRange: [layoutY, layoutY + 1],
87
- outputRange: ([0, 1]: Array<number>),
88
- })
89
- .interpolate({
90
- inputRange: [0, 1],
91
- outputRange: ([0, -1]: Array<number>),
92
- }),
93
- -layoutHeight,
94
- 0,
95
- )
96
- : null,
97
- [scrollAnimatedValue, layoutHeight, layoutY, hiddenOnScroll],
98
- );
62
+ // Fabric-only:
63
+ _timer: ?TimeoutID;
64
+ _animatedValueListenerId: string;
65
+ _animatedValueListener: (valueObject: $ReadOnly<{|value: number|}>) => void;
66
+ _debounceTimeout: number = Platform.OS === 'android' ? 15 : 64;
99
67
 
100
- const [
101
- animatedTranslateY,
102
- setAnimatedTranslateY,
103
- ] = React.useState<Animated.Node>(() => {
104
- const inputRange: Array<number> = [-1, 0];
105
- const outputRange: Array<number> = [0, 0];
106
- const initialTranslateY: Animated.Interpolation = scrollAnimatedValue.interpolate(
107
- {
108
- inputRange,
109
- outputRange,
110
- },
111
- );
68
+ setNextHeaderY: (y: number) => void = (y: number): void => {
69
+ this._shouldRecreateTranslateY = true;
70
+ this.setState({nextHeaderLayoutY: y});
71
+ };
112
72
 
113
- if (offset != null) {
114
- return Animated.add(initialTranslateY, offset);
73
+ componentWillUnmount() {
74
+ if (this._translateY != null && this._animatedValueListenerId != null) {
75
+ this._translateY.removeListener(this._animatedValueListenerId);
76
+ }
77
+ if (this._timer) {
78
+ clearTimeout(this._timer);
115
79
  }
116
- return initialTranslateY;
117
- });
80
+ }
118
81
 
119
- const _haveReceivedInitialZeroTranslateY = useRef<boolean>(true);
120
- const _timer = useRef<?TimeoutID>(null);
82
+ UNSAFE_componentWillReceiveProps(nextProps: Props) {
83
+ if (
84
+ nextProps.scrollViewHeight !== this.props.scrollViewHeight ||
85
+ nextProps.scrollAnimatedValue !== this.props.scrollAnimatedValue ||
86
+ nextProps.inverted !== this.props.inverted
87
+ ) {
88
+ this._shouldRecreateTranslateY = true;
89
+ }
90
+ }
121
91
 
122
- useEffect(() => {
123
- if (translateY !== 0 && translateY != null) {
124
- _haveReceivedInitialZeroTranslateY.current = false;
92
+ updateTranslateListener(
93
+ translateY: AnimatedImplementation.Interpolation,
94
+ isFabric: boolean,
95
+ offset: AnimatedDiffClamp | null,
96
+ ) {
97
+ if (this._translateY != null && this._animatedValueListenerId != null) {
98
+ this._translateY.removeListener(this._animatedValueListenerId);
125
99
  }
126
- }, [translateY]);
100
+ offset
101
+ ? (this._translateY = new AnimatedAddition(translateY, offset))
102
+ : (this._translateY = translateY);
127
103
 
128
- // This is called whenever the (Interpolated) Animated Value
129
- // updates, which is several times per frame during scrolling.
130
- // To ensure that the Fabric ShadowTree has the most recent
131
- // translate style of this node, we debounce the value and then
132
- // pass it through to the underlying node during render.
133
- // This is:
134
- // 1. Only an issue in Fabric.
135
- // 2. Worse in Android than iOS. In Android, but not iOS, you
136
- // can touch and move your finger slightly and still trigger
137
- // a "tap" event. In iOS, moving will cancel the tap in
138
- // both Fabric and non-Fabric. On Android when you move
139
- // your finger, the hit-detection moves from the Android
140
- // platform to JS, so we need the ShadowTree to have knowledge
141
- // of the current position.
142
- const animatedValueListener = useCallback(
143
- ({value}) => {
144
- const _debounceTimeout: number = Platform.OS === 'android' ? 15 : 64;
145
- // When the AnimatedInterpolation is recreated, it always initializes
146
- // to a value of zero and emits a value change of 0 to its listeners.
147
- if (value === 0 && !_haveReceivedInitialZeroTranslateY.current) {
148
- _haveReceivedInitialZeroTranslateY.current = true;
149
- return;
150
- }
151
- if (_timer.current != null) {
152
- clearTimeout(_timer.current);
153
- }
154
- _timer.current = setTimeout(() => {
155
- if (value !== translateY) {
156
- setTranslateY(value);
157
- }
158
- }, _debounceTimeout);
159
- },
160
- [translateY],
161
- );
104
+ this._shouldRecreateTranslateY = false;
162
105
 
163
- useEffect(() => {
164
- const inputRange: Array<number> = [-1, 0];
165
- const outputRange: Array<number> = [0, 0];
106
+ if (!isFabric) {
107
+ return;
108
+ }
166
109
 
167
- if (measured) {
168
- if (inverted === true) {
169
- // The interpolation looks like:
170
- // - Negative scroll: no translation
171
- // - `stickStartPoint` is the point at which the header will start sticking.
172
- // It is calculated using the ScrollView viewport height so it is a the bottom.
173
- // - Headers that are in the initial viewport will never stick, `stickStartPoint`
174
- // will be negative.
175
- // - From 0 to `stickStartPoint` no translation. This will cause the header
176
- // to scroll normally until it reaches the top of the scroll view.
177
- // - From `stickStartPoint` to when the next header y hits the bottom edge of the header: translate
178
- // equally to scroll. This will cause the header to stay at the top of the scroll view.
179
- // - Past the collision with the next header y: no more translation. This will cause the
180
- // header to continue scrolling up and make room for the next sticky header.
181
- // In the case that there is no next header just translate equally to
182
- // scroll indefinitely.
183
- if (scrollViewHeight != null) {
184
- const stickStartPoint = layoutY + layoutHeight - scrollViewHeight;
185
- if (stickStartPoint > 0) {
186
- inputRange.push(stickStartPoint);
187
- outputRange.push(0);
188
- inputRange.push(stickStartPoint + 1);
189
- outputRange.push(1);
190
- // If the next sticky header has not loaded yet (probably windowing) or is the last
191
- // we can just keep it sticked forever.
192
- const collisionPoint =
193
- (nextHeaderLayoutY || 0) - layoutHeight - scrollViewHeight;
194
- if (collisionPoint > stickStartPoint) {
195
- inputRange.push(collisionPoint, collisionPoint + 1);
196
- outputRange.push(
197
- collisionPoint - stickStartPoint,
198
- collisionPoint - stickStartPoint,
199
- );
200
- }
201
- }
110
+ if (!this._animatedValueListener) {
111
+ // This is called whenever the (Interpolated) Animated Value
112
+ // updates, which is several times per frame during scrolling.
113
+ // To ensure that the Fabric ShadowTree has the most recent
114
+ // translate style of this node, we debounce the value and then
115
+ // pass it through to the underlying node during render.
116
+ // This is:
117
+ // 1. Only an issue in Fabric.
118
+ // 2. Worse in Android than iOS. In Android, but not iOS, you
119
+ // can touch and move your finger slightly and still trigger
120
+ // a "tap" event. In iOS, moving will cancel the tap in
121
+ // both Fabric and non-Fabric. On Android when you move
122
+ // your finger, the hit-detection moves from the Android
123
+ // platform to JS, so we need the ShadowTree to have knowledge
124
+ // of the current position.
125
+ this._animatedValueListener = ({value}) => {
126
+ // When the AnimatedInterpolation is recreated, it always initializes
127
+ // to a value of zero and emits a value change of 0 to its listeners.
128
+ if (value === 0 && !this._haveReceivedInitialZeroTranslateY) {
129
+ this._haveReceivedInitialZeroTranslateY = true;
130
+ return;
202
131
  }
203
- } else {
204
- // The interpolation looks like:
205
- // - Negative scroll: no translation
206
- // - From 0 to the y of the header: no translation. This will cause the header
207
- // to scroll normally until it reaches the top of the scroll view.
208
- // - From header y to when the next header y hits the bottom edge of the header: translate
209
- // equally to scroll. This will cause the header to stay at the top of the scroll view.
210
- // - Past the collision with the next header y: no more translation. This will cause the
211
- // header to continue scrolling up and make room for the next sticky header.
212
- // In the case that there is no next header just translate equally to
213
- // scroll indefinitely.
214
- inputRange.push(layoutY);
215
- outputRange.push(0);
216
- // If the next sticky header has not loaded yet (probably windowing) or is the last
217
- // we can just keep it sticked forever.
218
- const collisionPoint = (nextHeaderLayoutY || 0) - layoutHeight;
219
- if (collisionPoint >= layoutY) {
220
- inputRange.push(collisionPoint, collisionPoint + 1);
221
- outputRange.push(collisionPoint - layoutY, collisionPoint - layoutY);
222
- } else {
223
- inputRange.push(layoutY + 1);
224
- outputRange.push(1);
132
+ if (this._timer) {
133
+ clearTimeout(this._timer);
225
134
  }
226
- }
227
- }
228
-
229
- let newAnimatedTranslateY: Animated.Node = scrollAnimatedValue.interpolate({
230
- inputRange,
231
- outputRange,
232
- });
233
-
234
- if (offset != null) {
235
- newAnimatedTranslateY = Animated.add(newAnimatedTranslateY, offset);
135
+ this._timer = setTimeout(() => {
136
+ if (value !== this.state.translateY) {
137
+ this.setState({
138
+ translateY: value,
139
+ });
140
+ }
141
+ }, this._debounceTimeout);
142
+ };
236
143
  }
237
-
238
- // add the event listener
239
- let animatedListenerId;
240
- if (isFabric) {
241
- animatedListenerId = newAnimatedTranslateY.addListener(
242
- animatedValueListener,
243
- );
144
+ if (this.state.translateY !== 0 && this.state.translateY != null) {
145
+ this._haveReceivedInitialZeroTranslateY = false;
244
146
  }
147
+ this._animatedValueListenerId = translateY.addListener(
148
+ this._animatedValueListener,
149
+ );
150
+ }
245
151
 
246
- setAnimatedTranslateY(newAnimatedTranslateY);
152
+ _onLayout = event => {
153
+ const layoutY = event.nativeEvent.layout.y;
154
+ const layoutHeight = event.nativeEvent.layout.height;
155
+ const measured = true;
247
156
 
248
- // clean up the event listener and timer
249
- return () => {
250
- if (animatedListenerId) {
251
- newAnimatedTranslateY.removeListener(animatedListenerId);
252
- }
253
- if (_timer.current != null) {
254
- clearTimeout(_timer.current);
255
- }
256
- };
257
- }, [nextHeaderLayoutY, measured, layoutHeight, layoutY, scrollViewHeight, scrollAnimatedValue, inverted, offset, animatedValueListener, isFabric]);
157
+ if (
158
+ layoutY !== this.state.layoutY ||
159
+ layoutHeight !== this.state.layoutHeight ||
160
+ measured !== this.state.measured
161
+ ) {
162
+ this._shouldRecreateTranslateY = true;
163
+ }
258
164
 
259
- const _onLayout = (event: LayoutEvent) => {
260
- setLayoutY(event.nativeEvent.layout.y);
261
- setLayoutHeight(event.nativeEvent.layout.height);
262
- setMeasured(true);
165
+ this.setState({
166
+ measured,
167
+ layoutY,
168
+ layoutHeight,
169
+ });
263
170
 
264
- props.onLayout(event);
265
- const child = React.Children.only(props.children);
171
+ this.props.onLayout(event);
172
+ const child = React.Children.only(this.props.children);
266
173
  if (child.props.onLayout) {
267
174
  child.props.onLayout(event);
268
175
  }
269
176
  };
270
177
 
271
- const child = React.Children.only(props.children);
178
+ _setComponentRef = ref => {
179
+ this._ref = ref;
180
+ };
181
+
182
+ render(): React.Node {
183
+ // Fabric Detection
184
+ const isFabric = !!(
185
+ // An internal transform mangles variables with leading "_" as private.
186
+ // eslint-disable-next-line dot-notation
187
+ (this._ref && this._ref['_internalInstanceHandle']?.stateNode?.canonical)
188
+ );
189
+ // Initially and in the case of updated props or layout, we
190
+ // recreate this interpolated value. Otherwise, we do not recreate
191
+ // when there are state changes.
192
+ if (this._shouldRecreateTranslateY) {
193
+ const {inverted, scrollViewHeight} = this.props;
194
+ const {measured, layoutHeight, layoutY, nextHeaderLayoutY} = this.state;
195
+ const inputRange: Array<number> = [-1, 0];
196
+ const outputRange: Array<number> = [0, 0];
272
197
 
273
- // TODO T68319535: remove this if NativeAnimated is rewritten for Fabric
274
- const passthroughAnimatedPropExplicitValues =
275
- isFabric && translateY != null
276
- ? {
277
- style: {transform: [{translateY: translateY}]},
198
+ if (measured) {
199
+ if (inverted) {
200
+ // The interpolation looks like:
201
+ // - Negative scroll: no translation
202
+ // - `stickStartPoint` is the point at which the header will start sticking.
203
+ // It is calculated using the ScrollView viewport height so it is a the bottom.
204
+ // - Headers that are in the initial viewport will never stick, `stickStartPoint`
205
+ // will be negative.
206
+ // - From 0 to `stickStartPoint` no translation. This will cause the header
207
+ // to scroll normally until it reaches the top of the scroll view.
208
+ // - From `stickStartPoint` to when the next header y hits the bottom edge of the header: translate
209
+ // equally to scroll. This will cause the header to stay at the top of the scroll view.
210
+ // - Past the collision with the next header y: no more translation. This will cause the
211
+ // header to continue scrolling up and make room for the next sticky header.
212
+ // In the case that there is no next header just translate equally to
213
+ // scroll indefinitely.
214
+ if (scrollViewHeight != null) {
215
+ const stickStartPoint = layoutY + layoutHeight - scrollViewHeight;
216
+ if (stickStartPoint > 0) {
217
+ inputRange.push(stickStartPoint);
218
+ outputRange.push(0);
219
+ inputRange.push(stickStartPoint + 1);
220
+ outputRange.push(1);
221
+ // If the next sticky header has not loaded yet (probably windowing) or is the last
222
+ // we can just keep it sticked forever.
223
+ const collisionPoint =
224
+ (nextHeaderLayoutY || 0) - layoutHeight - scrollViewHeight;
225
+ if (collisionPoint > stickStartPoint) {
226
+ inputRange.push(collisionPoint, collisionPoint + 1);
227
+ outputRange.push(
228
+ collisionPoint - stickStartPoint,
229
+ collisionPoint - stickStartPoint,
230
+ );
231
+ }
232
+ }
233
+ }
234
+ } else {
235
+ // The interpolation looks like:
236
+ // - Negative scroll: no translation
237
+ // - From 0 to the y of the header: no translation. This will cause the header
238
+ // to scroll normally until it reaches the top of the scroll view.
239
+ // - From header y to when the next header y hits the bottom edge of the header: translate
240
+ // equally to scroll. This will cause the header to stay at the top of the scroll view.
241
+ // - Past the collision with the next header y: no more translation. This will cause the
242
+ // header to continue scrolling up and make room for the next sticky header.
243
+ // In the case that there is no next header just translate equally to
244
+ // scroll indefinitely.
245
+ inputRange.push(layoutY);
246
+ outputRange.push(0);
247
+ // If the next sticky header has not loaded yet (probably windowing) or is the last
248
+ // we can just keep it sticked forever.
249
+ const collisionPoint = (nextHeaderLayoutY || 0) - layoutHeight;
250
+ if (collisionPoint >= layoutY) {
251
+ inputRange.push(collisionPoint, collisionPoint + 1);
252
+ outputRange.push(
253
+ collisionPoint - layoutY,
254
+ collisionPoint - layoutY,
255
+ );
256
+ } else {
257
+ inputRange.push(layoutY + 1);
258
+ outputRange.push(1);
259
+ }
278
260
  }
279
- : null;
261
+ }
280
262
 
281
- return (
282
- /* $FlowFixMe[prop-missing] passthroughAnimatedPropExplicitValues isn't properly
283
- included in the Animated.View flow type. */
284
- <AnimatedView
285
- collapsable={false}
286
- nativeID={props.nativeID}
287
- onLayout={_onLayout}
288
- ref={_setNativeRef}
289
- style={[
290
- child.props.style,
291
- styles.header,
292
- {transform: [{translateY: animatedTranslateY}]},
293
- ]}
294
- passthroughAnimatedPropExplicitValues={
295
- passthroughAnimatedPropExplicitValues
296
- }>
297
- {React.cloneElement(child, {
298
- style: styles.fill, // We transfer the child style to the wrapper.
299
- onLayout: undefined, // we call this manually through our this._onLayout
300
- })}
301
- </AnimatedView>
302
- );
303
- });
263
+ this.updateTranslateListener(
264
+ this.props.scrollAnimatedValue.interpolate({
265
+ inputRange,
266
+ outputRange,
267
+ }),
268
+ isFabric,
269
+ this.props.hiddenOnScroll
270
+ ? new AnimatedDiffClamp(
271
+ this.props.scrollAnimatedValue
272
+ .interpolate({
273
+ extrapolateLeft: 'clamp',
274
+ inputRange: [layoutY, layoutY + 1],
275
+ outputRange: ([0, 1]: Array<number>),
276
+ })
277
+ .interpolate({
278
+ inputRange: [0, 1],
279
+ outputRange: ([0, -1]: Array<number>),
280
+ }),
281
+ -this.state.layoutHeight,
282
+ 0,
283
+ )
284
+ : null,
285
+ );
286
+ }
287
+
288
+ const child = React.Children.only(this.props.children);
289
+
290
+ // TODO T68319535: remove this if NativeAnimated is rewritten for Fabric
291
+ const passthroughAnimatedPropExplicitValues =
292
+ isFabric && this.state.translateY != null
293
+ ? {
294
+ style: {transform: [{translateY: this.state.translateY}]},
295
+ }
296
+ : null;
297
+
298
+ return (
299
+ <AnimatedView
300
+ collapsable={false}
301
+ nativeID={this.props.nativeID}
302
+ onLayout={this._onLayout}
303
+ ref={this._setComponentRef}
304
+ style={[
305
+ child.props.style,
306
+ styles.header,
307
+ {transform: [{translateY: this._translateY}]},
308
+ ]}
309
+ passthroughAnimatedPropExplicitValues={
310
+ passthroughAnimatedPropExplicitValues
311
+ }>
312
+ {React.cloneElement(child, {
313
+ style: styles.fill, // We transfer the child style to the wrapper.
314
+ onLayout: undefined, // we call this manually through our this._onLayout
315
+ })}
316
+ </AnimatedView>
317
+ );
318
+ }
319
+ }
304
320
 
305
321
  const styles = StyleSheet.create({
306
322
  header: {
@@ -312,4 +328,4 @@ const styles = StyleSheet.create({
312
328
  },
313
329
  });
314
330
 
315
- export default ScrollViewStickyHeaderWithForwardedRef;
331
+ module.exports = ScrollViewStickyHeader;
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  export declare const title = "TextWin32";
3
2
  export declare const displayName = "TextWin32";
4
3
  export declare const description = "TextWin32 Examples and Tests";
@@ -8,7 +8,7 @@ export declare type SharedTextPropsAndroidandWin32 = {
8
8
  /**
9
9
  * Role-based text style names.
10
10
  */
11
- export declare type TextStyle = 'None' | 'SmallStandard' | 'SmallSecondary' | 'MediumStandard' | 'MediumSecondary' | 'MediumApp' | 'MediumBold' | 'MediumBoldApp' | 'LargeStandard' | 'LargePlusStandard' | 'ExtraLargeStandard' | 'HugeStandard';
11
+ export declare type TextWin32TextStyle = 'None' | 'SmallStandard' | 'SmallSecondary' | 'MediumStandard' | 'MediumSecondary' | 'MediumApp' | 'MediumBold' | 'MediumBoldApp' | 'LargeStandard' | 'LargePlusStandard' | 'ExtraLargeStandard' | 'HugeStandard';
12
12
  export interface ITextWin32Props extends Omit<RN.TextProps, TextWin32OmitTypes>, BasePropsWin32 {
13
13
  onKeyDown?: (args: IKeyboardEvent) => void;
14
14
  onKeyDownCapture?: (args: IKeyboardEvent) => void;
@@ -62,7 +62,7 @@ export interface ITextWin32Props extends Omit<RN.TextProps, TextWin32OmitTypes>,
62
62
  *
63
63
  * @deprecated Use `style` instead.
64
64
  */
65
- textStyle?: TextStyle;
65
+ textStyle?: TextWin32TextStyle;
66
66
  /** Tooltip displayed on mouse hover of this element */
67
67
  tooltip?: string;
68
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TextWin32.Props.js","sourceRoot":"","sources":["../../../src/Libraries/Components/Text/TextWin32.Props.ts"],"names":[],"mappings":"","sourcesContent":["import RN = require('react-native');\nimport { SharedAccessibilityPropsIOSandWin32, OmittedAccessibilityPropsWin32, BasePropsWin32, IKeyboardEvent, IHandledKeyboardEvent } from '../View/ViewWin32.Props';\n\n// removes from interface T the members of interface K\ntype Omit<T, K> = Pick<T, Exclude<keyof T, keyof K>>;\n\nexport type TextWin32OmitTypes = Omit<RN.TextPropsAndroid, SharedTextPropsAndroidandWin32> &\n RN.TextPropsIOS &\n RN.AccessibilityPropsAndroid &\n Omit<RN.AccessibilityPropsIOS, SharedAccessibilityPropsIOSandWin32> &\n OmittedAccessibilityPropsWin32;\n\nexport type SharedTextPropsAndroidandWin32 = {\n selectable?: boolean;\n};\n\n/**\n * Role-based text style names.\n */\nexport type TextStyle =\n | 'None'\n | 'SmallStandard'\n | 'SmallSecondary'\n | 'MediumStandard'\n | 'MediumSecondary'\n | 'MediumApp'\n | 'MediumBold'\n | 'MediumBoldApp'\n | 'LargeStandard'\n | 'LargePlusStandard'\n | 'ExtraLargeStandard'\n | 'HugeStandard';\n\nexport interface ITextWin32Props extends Omit<RN.TextProps, TextWin32OmitTypes>, BasePropsWin32 {\n onKeyDown?: (args: IKeyboardEvent) => void;\n onKeyDownCapture?: (args: IKeyboardEvent) => void;\n onKeyUp?: (args: IKeyboardEvent) => void;\n onKeyUpCapture?: (args: IKeyboardEvent) => void;\n\n keyDownEvents?: IHandledKeyboardEvent[];\n keyUpEvents?: IHandledKeyboardEvent[];\n\n /** Enables a focusable label with copyability but without character selectability (property:selectable) */\n focusable?: boolean;\n\n /**\n * The onBlur event occurs when an element loses focus. The opposite of onBlur is onFocus. Note that in React\n * Native, unlike in the web, the onBlur event bubbles (similar to onFocusOut in the web).\n *\n * `ev.target === ev.currentTarget` when the focus is being lost from this component.\n * `ev.target !== ev.currentTarget` when the focus is being lost from a descendant.\n */\n onBlur?: (ev: RN.NativeSyntheticEvent<{}>) => void;\n /**\n * The onBlur event occurs when an element loses focus. The opposite of onBlur is onFocus. Note that in React\n * Native, unlike in the web, the onBlur event bubbles (similar to onFocusOut in the web).\n *\n * `ev.target === ev.currentTarget` when the focus is being lost from this component.\n * `ev.target !== ev.currentTarget` when the focus is being lost from a descendant.\n */\n onBlurCapture?: (ev: RN.NativeSyntheticEvent<{}>) => void;\n /**\n * The onFocus event occurs when an element gets focus. The opposite of onFocus is onBlur. Note that in React\n * Native, unlike in the web, the onFocus event bubbles (similar to onFocusIn in the web).\n *\n * `ev.target === ev.currentTarget` when the focus is being lost from this component.\n * `ev.target !== ev.currentTarget` when the focus is being lost from a descendant.\n */\n onFocus?: (ev: RN.NativeSyntheticEvent<{}>) => void;\n /**\n * The onFocus event occurs when an element gets focus. The opposite of onFocus is onBlur. Note that in React\n * Native, unlike in the web, the onFocus event bubbles (similar to onFocusIn in the web).\n *\n * `ev.target === ev.currentTarget` when the focus is being lost from this component.\n * `ev.target !== ev.currentTarget` when the focus is being lost from a descendant.\n */\n onFocusCapture?: (ev: RN.NativeSyntheticEvent<{}>) => void;\n \n /**\n * Role-based styling of the text control. The styles applied include\n * font face, size, weight and color. These styles take precedence over\n * the `style` property.\n *\n * @remarks\n * The default value is `MediumStandard`.\n *\n * When set to `None`, role-based styling is disabled.\n *\n * @deprecated Use `style` instead.\n */\n textStyle?: TextStyle;\n\n /** Tooltip displayed on mouse hover of this element */\n tooltip?: string;\n}\n"]}
1
+ {"version":3,"file":"TextWin32.Props.js","sourceRoot":"","sources":["../../../src/Libraries/Components/Text/TextWin32.Props.ts"],"names":[],"mappings":"","sourcesContent":["import RN = require('react-native');\nimport { SharedAccessibilityPropsIOSandWin32, OmittedAccessibilityPropsWin32, BasePropsWin32, IKeyboardEvent, IHandledKeyboardEvent } from '../View/ViewWin32.Props';\n\n// removes from interface T the members of interface K\ntype Omit<T, K> = Pick<T, Exclude<keyof T, keyof K>>;\n\nexport type TextWin32OmitTypes = Omit<RN.TextPropsAndroid, SharedTextPropsAndroidandWin32> &\n RN.TextPropsIOS &\n RN.AccessibilityPropsAndroid &\n Omit<RN.AccessibilityPropsIOS, SharedAccessibilityPropsIOSandWin32> &\n OmittedAccessibilityPropsWin32;\n\nexport type SharedTextPropsAndroidandWin32 = {\n selectable?: boolean;\n};\n\n/**\n * Role-based text style names.\n */\nexport type TextWin32TextStyle =\n | 'None'\n | 'SmallStandard'\n | 'SmallSecondary'\n | 'MediumStandard'\n | 'MediumSecondary'\n | 'MediumApp'\n | 'MediumBold'\n | 'MediumBoldApp'\n | 'LargeStandard'\n | 'LargePlusStandard'\n | 'ExtraLargeStandard'\n | 'HugeStandard';\n\nexport interface ITextWin32Props extends Omit<RN.TextProps, TextWin32OmitTypes>, BasePropsWin32 {\n onKeyDown?: (args: IKeyboardEvent) => void;\n onKeyDownCapture?: (args: IKeyboardEvent) => void;\n onKeyUp?: (args: IKeyboardEvent) => void;\n onKeyUpCapture?: (args: IKeyboardEvent) => void;\n\n keyDownEvents?: IHandledKeyboardEvent[];\n keyUpEvents?: IHandledKeyboardEvent[];\n\n /** Enables a focusable label with copyability but without character selectability (property:selectable) */\n focusable?: boolean;\n\n /**\n * The onBlur event occurs when an element loses focus. The opposite of onBlur is onFocus. Note that in React\n * Native, unlike in the web, the onBlur event bubbles (similar to onFocusOut in the web).\n *\n * `ev.target === ev.currentTarget` when the focus is being lost from this component.\n * `ev.target !== ev.currentTarget` when the focus is being lost from a descendant.\n */\n onBlur?: (ev: RN.NativeSyntheticEvent<{}>) => void;\n /**\n * The onBlur event occurs when an element loses focus. The opposite of onBlur is onFocus. Note that in React\n * Native, unlike in the web, the onBlur event bubbles (similar to onFocusOut in the web).\n *\n * `ev.target === ev.currentTarget` when the focus is being lost from this component.\n * `ev.target !== ev.currentTarget` when the focus is being lost from a descendant.\n */\n onBlurCapture?: (ev: RN.NativeSyntheticEvent<{}>) => void;\n /**\n * The onFocus event occurs when an element gets focus. The opposite of onFocus is onBlur. Note that in React\n * Native, unlike in the web, the onFocus event bubbles (similar to onFocusIn in the web).\n *\n * `ev.target === ev.currentTarget` when the focus is being lost from this component.\n * `ev.target !== ev.currentTarget` when the focus is being lost from a descendant.\n */\n onFocus?: (ev: RN.NativeSyntheticEvent<{}>) => void;\n /**\n * The onFocus event occurs when an element gets focus. The opposite of onFocus is onBlur. Note that in React\n * Native, unlike in the web, the onFocus event bubbles (similar to onFocusIn in the web).\n *\n * `ev.target === ev.currentTarget` when the focus is being lost from this component.\n * `ev.target !== ev.currentTarget` when the focus is being lost from a descendant.\n */\n onFocusCapture?: (ev: RN.NativeSyntheticEvent<{}>) => void;\n \n /**\n * Role-based styling of the text control. The styles applied include\n * font face, size, weight and color. These styles take precedence over\n * the `style` property.\n *\n * @remarks\n * The default value is `MediumStandard`.\n *\n * When set to `None`, role-based styling is disabled.\n *\n * @deprecated Use `style` instead.\n */\n textStyle?: TextWin32TextStyle;\n\n /** Tooltip displayed on mouse hover of this element */\n tooltip?: string;\n}\n"]}
@@ -11,7 +11,7 @@ class TextWin32 extends react_1.default.Component {
11
11
  super(props);
12
12
  }
13
13
  render() {
14
- return react_1.default.createElement(RN.Text, Object.assign({}, this.props));
14
+ return react_1.default.createElement(RN.Text, { ...this.props });
15
15
  }
16
16
  }
17
17
  exports.TextWin32 = TextWin32;
@@ -1 +1 @@
1
- {"version":3,"file":"TextWin32.js","sourceRoot":"","sources":["../../../src/Libraries/Components/Text/TextWin32.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,mCAAoC;AAWpC,MAAa,SAAU,SAAQ,eAAK,CAAC,SAA8B;IACjE,YAAY,KAAsB;QAChC,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAEM,MAAM;QACX,OAAO,8BAAC,EAAE,CAAC,IAAI,oBAAM,IAAI,CAAC,KAAwB,EAAI,CAAC;IACzD,CAAC;CACF;AARD,8BAQC","sourcesContent":["import React from 'react'\nimport RN = require('react-native');\nimport { ITextWin32Props } from './TextWin32.Props';\nimport { UseFrom } from '../View/ViewWin32.Props';\n\n/**\n * React-native <Text> control with additional Win32-specific functionality.\n */\n\ntype InnerViewProps = UseFrom<ITextWin32Props, RN.TextProps, 'accessibilityRole'> &\n UseFrom<ITextWin32Props, RN.TextProps, 'accessibilityState'> &\n UseFrom<ITextWin32Props, RN.TextProps, 'accessibilityActions'>;\nexport class TextWin32 extends React.Component<ITextWin32Props, {}> {\n constructor(props: ITextWin32Props) {\n super(props);\n }\n\n public render() {\n return <RN.Text {...(this.props as InnerViewProps)} />;\n }\n}\n"]}
1
+ {"version":3,"file":"TextWin32.js","sourceRoot":"","sources":["../../../src/Libraries/Components/Text/TextWin32.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,mCAAoC;AAWpC,MAAa,SAAU,SAAQ,eAAK,CAAC,SAA8B;IACjE,YAAY,KAAsB;QAChC,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAEM,MAAM;QACX,OAAO,8BAAC,EAAE,CAAC,IAAI,OAAM,IAAI,CAAC,KAAwB,GAAI,CAAC;IACzD,CAAC;CACF;AARD,8BAQC","sourcesContent":["import React from 'react'\nimport RN = require('react-native');\nimport { ITextWin32Props } from './TextWin32.Props';\nimport { UseFrom } from '../View/ViewWin32.Props';\n\n/**\n * React-native <Text> control with additional Win32-specific functionality.\n */\n\ntype InnerViewProps = UseFrom<ITextWin32Props, RN.TextProps, 'accessibilityRole'> &\n UseFrom<ITextWin32Props, RN.TextProps, 'accessibilityState'> &\n UseFrom<ITextWin32Props, RN.TextProps, 'accessibilityActions'>;\nexport class TextWin32 extends React.Component<ITextWin32Props, {}> {\n constructor(props: ITextWin32Props) {\n super(props);\n }\n\n public render() {\n return <RN.Text {...(this.props as InnerViewProps)} />;\n }\n}\n"]}
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  export declare const title = "TextInput";
3
2
  export declare const displayName = "TextInput";
4
3
  export declare const description = "TextInput Examples and Tests";