react-native-windows 0.74.29 → 0.74.30

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 (70) hide show
  1. package/Libraries/Components/Button.windows.js +9 -0
  2. package/Libraries/Components/Pressable/Pressable.windows.js +9 -0
  3. package/Libraries/Components/TextInput/TextInput.windows.js +11 -1
  4. package/Libraries/Components/Touchable/TouchableBounce.windows.js +225 -0
  5. package/Libraries/Components/Touchable/TouchableNativeFeedback.windows.js +373 -0
  6. package/Libraries/Components/Touchable/TouchableOpacity.windows.js +7 -0
  7. package/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +10 -0
  8. package/Libraries/Components/View/View.windows.js +11 -1
  9. package/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  10. package/Libraries/Components/View/ViewAccessibility.windows.js +5 -2
  11. package/Libraries/Components/View/ViewPropTypes.windows.js +3 -0
  12. package/Libraries/Image/Image.windows.js +7 -0
  13. package/Libraries/Text/Text.windows.js +11 -1
  14. package/Libraries/Text/TextProps.windows.js +3 -0
  15. package/Microsoft.ReactNative/CompositionComponentView.idl +13 -1
  16. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +1 -2
  17. package/Microsoft.ReactNative/Fabric/ComponentView.h +1 -1
  18. package/Microsoft.ReactNative/Fabric/Composition/ComponentViewRegistry.cpp +0 -5
  19. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +293 -9
  20. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +28 -1
  21. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +13 -32
  22. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +1 -3
  23. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +1 -1
  24. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.h +2 -1
  25. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +18 -5
  26. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +1 -1
  27. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +191 -329
  28. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.h +3 -61
  29. package/Microsoft.ReactNative/Fabric/Composition/PortalComponentView.cpp +66 -0
  30. package/Microsoft.ReactNative/Fabric/Composition/PortalComponentView.h +52 -0
  31. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +21 -0
  32. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +7 -4
  33. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +79 -19
  34. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +12 -6
  35. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +71 -17
  36. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +16 -0
  37. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +1 -1
  38. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +1 -1
  39. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +62 -33
  40. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +5 -2
  41. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +1 -6
  42. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +0 -3
  43. package/Microsoft.ReactNative/Fabric/WindowsComponentDescriptorRegistry.cpp +0 -2
  44. package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +5 -0
  45. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +19 -1
  46. package/Microsoft.ReactNative/ReactNativeHost.cpp +5 -0
  47. package/Microsoft.ReactNative/ReactNativeIsland.idl +5 -1
  48. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  49. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/AccessibilityPrimitives.h +253 -0
  50. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/accessibilityPropsConversions.h +799 -0
  51. package/Shared/Shared.vcxitems +3 -2
  52. package/Shared/Shared.vcxitems.filters +2 -3
  53. package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +204 -0
  54. package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +287 -0
  55. package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +192 -0
  56. package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +216 -0
  57. package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +242 -0
  58. package/codegen/react/components/rnwcore/AndroidSwitch.g.h +259 -0
  59. package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +226 -0
  60. package/codegen/react/components/rnwcore/InputAccessory.g.h +192 -0
  61. package/codegen/react/components/rnwcore/ModalHostView.g.h +271 -0
  62. package/codegen/react/components/rnwcore/PullToRefreshView.g.h +238 -0
  63. package/codegen/react/components/rnwcore/SafeAreaView.g.h +189 -0
  64. package/codegen/react/components/rnwcore/Switch.g.h +255 -0
  65. package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +192 -0
  66. package/just-task.js +1 -1
  67. package/package.json +1 -1
  68. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentDescriptor.h +0 -39
  69. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewShadowNode.cpp +0 -18
  70. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewShadowNode.h +0 -39
@@ -164,6 +164,9 @@ type ButtonProps = $ReadOnly<{|
164
164
  'aria-disabled'?: ?boolean,
165
165
  'aria-expanded'?: ?boolean,
166
166
  'aria-selected'?: ?boolean,
167
+ 'aria-readonly'?: ?boolean, // Windows
168
+ 'aria-multiselectable'?: ?boolean, // Windows
169
+ 'aria-required'?: ?boolean, // Windows
167
170
 
168
171
  /**
169
172
  * [Android] Controlling if a view fires accessibility events and if it is reported to accessibility services.
@@ -308,6 +311,9 @@ const Button: React.AbstractComponent<
308
311
  'aria-expanded': ariaExpanded,
309
312
  'aria-label': ariaLabel,
310
313
  'aria-selected': ariaSelected,
314
+ 'aria-readonly': ariaReadOnly, // Windows
315
+ 'aria-multiselectable': ariaMultiselectable, // Windows
316
+ 'aria-required': ariaRequired, // Windows
311
317
  importantForAccessibility,
312
318
  color,
313
319
  onPress,
@@ -343,6 +349,9 @@ const Button: React.AbstractComponent<
343
349
  disabled: ariaDisabled ?? accessibilityState?.disabled,
344
350
  expanded: ariaExpanded ?? accessibilityState?.expanded,
345
351
  selected: ariaSelected ?? accessibilityState?.selected,
352
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly, // Windows
353
+ multiselectable: ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
354
+ required: ariaRequired ?? accessibilityState?.required, // Windows
346
355
  };
347
356
 
348
357
  const disabled =
@@ -75,6 +75,9 @@ type Props = $ReadOnly<{|
75
75
  'aria-disabled'?: ?boolean,
76
76
  'aria-expanded'?: ?boolean,
77
77
  'aria-selected'?: ?boolean,
78
+ 'aria-readonly'?: ?boolean, // Windows
79
+ 'aria-multiselectable'?: ?boolean, // Windows
80
+ 'aria-required'?: ?boolean, // Windows
78
81
  /**
79
82
  * A value indicating whether the accessibility elements contained within
80
83
  * this accessibility element are hidden.
@@ -259,6 +262,9 @@ function Pressable(props: Props, forwardedRef): React.Node {
259
262
  'aria-expanded': ariaExpanded,
260
263
  'aria-label': ariaLabel,
261
264
  'aria-selected': ariaSelected,
265
+ 'aria-readonly': ariaReadOnly,
266
+ 'aria-multiselectable': ariaMultiselectable, // Windows
267
+ 'aria-required': ariaRequired, // Windows
262
268
  cancelable,
263
269
  children,
264
270
  delayHoverIn,
@@ -299,6 +305,9 @@ function Pressable(props: Props, forwardedRef): React.Node {
299
305
  disabled: ariaDisabled ?? accessibilityState?.disabled,
300
306
  expanded: ariaExpanded ?? accessibilityState?.expanded,
301
307
  selected: ariaSelected ?? accessibilityState?.selected,
308
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly,
309
+ multiselectable: ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
310
+ required: ariaRequired ?? accessibilityState?.required, // Windows
302
311
  };
303
312
 
304
313
  _accessibilityState =
@@ -1190,6 +1190,9 @@ function InternalTextInput(props: Props): React.Node {
1190
1190
  'aria-disabled': ariaDisabled,
1191
1191
  'aria-expanded': ariaExpanded,
1192
1192
  'aria-selected': ariaSelected,
1193
+ 'aria-readonly': ariaReadOnly, // Windows
1194
+ 'aria-multiselectable': ariaMultiselectable, // Windows
1195
+ 'aria-required': ariaRequired, // Windows
1193
1196
  accessibilityState,
1194
1197
  id,
1195
1198
  tabIndex,
@@ -1590,7 +1593,10 @@ function InternalTextInput(props: Props): React.Node {
1590
1593
  ariaChecked != null ||
1591
1594
  ariaDisabled != null ||
1592
1595
  ariaExpanded != null ||
1593
- ariaSelected != null
1596
+ ariaSelected != null ||
1597
+ ariaReadOnly != null || // Windows
1598
+ ariaMultiselectable != null || // Windows
1599
+ ariaRequired != null // Windows
1594
1600
  ) {
1595
1601
  _accessibilityState = {
1596
1602
  busy: ariaBusy ?? accessibilityState?.busy,
@@ -1598,6 +1604,10 @@ function InternalTextInput(props: Props): React.Node {
1598
1604
  disabled: ariaDisabled ?? accessibilityState?.disabled,
1599
1605
  expanded: ariaExpanded ?? accessibilityState?.expanded,
1600
1606
  selected: ariaSelected ?? accessibilityState?.selected,
1607
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly, // Windows
1608
+ multiselectable:
1609
+ ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
1610
+ required: ariaRequired ?? accessibilityState?.required, // Windows
1601
1611
  };
1602
1612
  }
1603
1613
 
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
12
+ import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback';
13
+
14
+ import Animated from '../../Animated/Animated';
15
+ import Pressability, {
16
+ type PressabilityConfig,
17
+ } from '../../Pressability/Pressability';
18
+ import {PressabilityDebugView} from '../../Pressability/PressabilityDebug';
19
+ import Platform from '../../Utilities/Platform';
20
+ import * as React from 'react';
21
+
22
+ type Props = $ReadOnly<{|
23
+ ...React.ElementConfig<TouchableWithoutFeedback>,
24
+
25
+ onPressAnimationComplete?: ?() => void,
26
+ onPressWithCompletion?: ?(callback: () => void) => void,
27
+ releaseBounciness?: ?number,
28
+ releaseVelocity?: ?number,
29
+ style?: ?ViewStyleProp,
30
+
31
+ hostRef: React.Ref<typeof Animated.View>,
32
+ |}>;
33
+
34
+ type State = $ReadOnly<{|
35
+ pressability: Pressability,
36
+ scale: Animated.Value,
37
+ |}>;
38
+
39
+ class TouchableBounce extends React.Component<Props, State> {
40
+ state: State = {
41
+ pressability: new Pressability(this._createPressabilityConfig()),
42
+ scale: new Animated.Value(1),
43
+ };
44
+
45
+ _createPressabilityConfig(): PressabilityConfig {
46
+ return {
47
+ cancelable: !this.props.rejectResponderTermination,
48
+ disabled: this.props.disabled,
49
+ hitSlop: this.props.hitSlop,
50
+ delayLongPress: this.props.delayLongPress,
51
+ delayPressIn: this.props.delayPressIn,
52
+ delayPressOut: this.props.delayPressOut,
53
+ minPressDuration: 0,
54
+ pressRectOffset: this.props.pressRetentionOffset,
55
+ android_disableSound: this.props.touchSoundDisabled,
56
+ onBlur: event => {
57
+ if (Platform.isTV) {
58
+ this._bounceTo(1, 0.4, 0);
59
+ }
60
+ if (this.props.onBlur != null) {
61
+ this.props.onBlur(event);
62
+ }
63
+ },
64
+ onFocus: event => {
65
+ if (Platform.isTV) {
66
+ this._bounceTo(0.93, 0.1, 0);
67
+ }
68
+ if (this.props.onFocus != null) {
69
+ this.props.onFocus(event);
70
+ }
71
+ },
72
+ onLongPress: this.props.onLongPress,
73
+ onPress: event => {
74
+ const {onPressAnimationComplete, onPressWithCompletion} = this.props;
75
+ const releaseBounciness = this.props.releaseBounciness ?? 10;
76
+ const releaseVelocity = this.props.releaseVelocity ?? 10;
77
+
78
+ if (onPressWithCompletion != null) {
79
+ onPressWithCompletion(() => {
80
+ this.state.scale.setValue(0.93);
81
+ this._bounceTo(
82
+ 1,
83
+ releaseVelocity,
84
+ releaseBounciness,
85
+ onPressAnimationComplete,
86
+ );
87
+ });
88
+ return;
89
+ }
90
+
91
+ this._bounceTo(
92
+ 1,
93
+ releaseVelocity,
94
+ releaseBounciness,
95
+ onPressAnimationComplete,
96
+ );
97
+ if (this.props.onPress != null) {
98
+ this.props.onPress(event);
99
+ }
100
+ },
101
+ onPressIn: event => {
102
+ this._bounceTo(0.93, 0.1, 0);
103
+ if (this.props.onPressIn != null) {
104
+ this.props.onPressIn(event);
105
+ }
106
+ },
107
+ onPressOut: event => {
108
+ this._bounceTo(1, 0.4, 0);
109
+ if (this.props.onPressOut != null) {
110
+ this.props.onPressOut(event);
111
+ }
112
+ },
113
+ };
114
+ }
115
+
116
+ _bounceTo(
117
+ toValue: number,
118
+ velocity: number,
119
+ bounciness: number,
120
+ callback?: ?() => void,
121
+ ) {
122
+ Animated.spring(this.state.scale, {
123
+ toValue,
124
+ velocity,
125
+ bounciness,
126
+ useNativeDriver: true,
127
+ }).start(callback);
128
+ }
129
+
130
+ render(): React.Node {
131
+ // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before
132
+ // adopting `Pressability`, so preserve that behavior.
133
+ const {onBlur, onFocus, ...eventHandlersWithoutBlurAndFocus} =
134
+ this.state.pressability.getEventHandlers();
135
+ const accessibilityLiveRegion =
136
+ this.props['aria-live'] === 'off'
137
+ ? 'none'
138
+ : this.props['aria-live'] ?? this.props.accessibilityLiveRegion;
139
+ const _accessibilityState = {
140
+ busy: this.props['aria-busy'] ?? this.props.accessibilityState?.busy,
141
+ checked:
142
+ this.props['aria-checked'] ?? this.props.accessibilityState?.checked,
143
+ disabled:
144
+ this.props['aria-disabled'] ?? this.props.accessibilityState?.disabled,
145
+ expanded:
146
+ this.props['aria-expanded'] ?? this.props.accessibilityState?.expanded,
147
+ selected:
148
+ this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
149
+ readOnly:
150
+ this.props['aria-readonly'] ?? this.props.accessibilityState?.readOnly, // Windows
151
+ multiselectable:
152
+ this.props['aria-multiselectable'] ??
153
+ this.props.accessibilityState?.multiselectable, // Windows
154
+ required:
155
+ this.props['aria-required'] ?? this.props.accessibilityState?.required, // Windows
156
+ };
157
+
158
+ const accessibilityValue = {
159
+ max: this.props['aria-valuemax'] ?? this.props.accessibilityValue?.max,
160
+ min: this.props['aria-valuemin'] ?? this.props.accessibilityValue?.min,
161
+ now: this.props['aria-valuenow'] ?? this.props.accessibilityValue?.now,
162
+ text: this.props['aria-valuetext'] ?? this.props.accessibilityValue?.text,
163
+ };
164
+
165
+ const accessibilityLabel =
166
+ this.props['aria-label'] ?? this.props.accessibilityLabel;
167
+ return (
168
+ <Animated.View
169
+ style={[{transform: [{scale: this.state.scale}]}, this.props.style]}
170
+ accessible={this.props.accessible !== false}
171
+ accessibilityLabel={accessibilityLabel}
172
+ accessibilityHint={this.props.accessibilityHint}
173
+ accessibilityLanguage={this.props.accessibilityLanguage}
174
+ accessibilityRole={this.props.accessibilityRole}
175
+ accessibilityState={_accessibilityState}
176
+ accessibilityActions={this.props.accessibilityActions}
177
+ onAccessibilityAction={this.props.onAccessibilityAction}
178
+ accessibilityValue={accessibilityValue}
179
+ accessibilityLiveRegion={accessibilityLiveRegion}
180
+ importantForAccessibility={
181
+ this.props['aria-hidden'] === true
182
+ ? 'no-hide-descendants'
183
+ : this.props.importantForAccessibility
184
+ }
185
+ accessibilityViewIsModal={
186
+ this.props['aria-modal'] ?? this.props.accessibilityViewIsModal
187
+ }
188
+ accessibilityElementsHidden={
189
+ this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden
190
+ }
191
+ nativeID={this.props.id ?? this.props.nativeID}
192
+ testID={this.props.testID}
193
+ hitSlop={this.props.hitSlop}
194
+ focusable={
195
+ this.props.focusable !== false &&
196
+ this.props.onPress !== undefined &&
197
+ !this.props.disabled
198
+ }
199
+ ref={this.props.hostRef}
200
+ {...eventHandlersWithoutBlurAndFocus}>
201
+ {this.props.children}
202
+ {__DEV__ ? (
203
+ <PressabilityDebugView color="orange" hitSlop={this.props.hitSlop} />
204
+ ) : null}
205
+ </Animated.View>
206
+ );
207
+ }
208
+
209
+ componentDidUpdate(prevProps: Props, prevState: State) {
210
+ this.state.pressability.configure(this._createPressabilityConfig());
211
+ }
212
+
213
+ componentDidMount(): mixed {
214
+ this.state.pressability.configure(this._createPressabilityConfig());
215
+ }
216
+
217
+ componentWillUnmount(): void {
218
+ this.state.pressability.reset();
219
+ this.state.scale.resetAnimation();
220
+ }
221
+ }
222
+
223
+ module.exports = (React.forwardRef((props, hostRef) => (
224
+ <TouchableBounce {...props} hostRef={hostRef} />
225
+ )): React.AbstractComponent<$ReadOnly<$Diff<Props, {|hostRef: mixed|}>>>);
@@ -0,0 +1,373 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ import type {PressEvent} from '../../Types/CoreEventTypes';
12
+ import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback';
13
+
14
+ import View from '../../Components/View/View';
15
+ import Pressability, {
16
+ type PressabilityConfig,
17
+ } from '../../Pressability/Pressability';
18
+ import {PressabilityDebugView} from '../../Pressability/PressabilityDebug';
19
+ import {findHostInstance_DEPRECATED} from '../../ReactNative/RendererProxy';
20
+ import processColor from '../../StyleSheet/processColor';
21
+ import Platform from '../../Utilities/Platform';
22
+ import {Commands} from '../View/ViewNativeComponent';
23
+ import invariant from 'invariant';
24
+ import * as React from 'react';
25
+
26
+ type Props = $ReadOnly<{|
27
+ ...React.ElementConfig<TouchableWithoutFeedback>,
28
+
29
+ /**
30
+ * Determines the type of background drawable that's going to be used to
31
+ * display feedback. It takes an object with `type` property and extra data
32
+ * depending on the `type`. It's recommended to use one of the static
33
+ * methods to generate that dictionary.
34
+ */
35
+ background?: ?(
36
+ | $ReadOnly<{|
37
+ type: 'ThemeAttrAndroid',
38
+ attribute:
39
+ | 'selectableItemBackground'
40
+ | 'selectableItemBackgroundBorderless',
41
+ rippleRadius: ?number,
42
+ |}>
43
+ | $ReadOnly<{|
44
+ type: 'RippleAndroid',
45
+ color: ?number,
46
+ borderless: boolean,
47
+ rippleRadius: ?number,
48
+ |}>
49
+ ),
50
+
51
+ /**
52
+ * TV preferred focus (see documentation for the View component).
53
+ */
54
+ hasTVPreferredFocus?: ?boolean,
55
+
56
+ /**
57
+ * TV next focus down (see documentation for the View component).
58
+ */
59
+ nextFocusDown?: ?number,
60
+
61
+ /**
62
+ * TV next focus forward (see documentation for the View component).
63
+ */
64
+ nextFocusForward?: ?number,
65
+
66
+ /**
67
+ * TV next focus left (see documentation for the View component).
68
+ */
69
+ nextFocusLeft?: ?number,
70
+
71
+ /**
72
+ * TV next focus right (see documentation for the View component).
73
+ */
74
+ nextFocusRight?: ?number,
75
+
76
+ /**
77
+ * TV next focus up (see documentation for the View component).
78
+ */
79
+ nextFocusUp?: ?number,
80
+
81
+ /**
82
+ * Set to true to add the ripple effect to the foreground of the view, instead
83
+ * of the background. This is useful if one of your child views has a
84
+ * background of its own, or you're e.g. displaying images, and you don't want
85
+ * the ripple to be covered by them.
86
+ *
87
+ * Check TouchableNativeFeedback.canUseNativeForeground() first, as this is
88
+ * only available on Android 6.0 and above. If you try to use this on older
89
+ * versions, this will fallback to background.
90
+ */
91
+ useForeground?: ?boolean,
92
+ |}>;
93
+
94
+ type State = $ReadOnly<{|
95
+ pressability: Pressability,
96
+ |}>;
97
+
98
+ class TouchableNativeFeedback extends React.Component<Props, State> {
99
+ /**
100
+ * Creates a value for the `background` prop that uses the Android theme's
101
+ * default background for selectable elements.
102
+ */
103
+ static SelectableBackground: (rippleRadius: ?number) => $ReadOnly<{|
104
+ attribute: 'selectableItemBackground',
105
+ type: 'ThemeAttrAndroid',
106
+ rippleRadius: ?number,
107
+ |}> = (rippleRadius: ?number) => ({
108
+ type: 'ThemeAttrAndroid',
109
+ attribute: 'selectableItemBackground',
110
+ rippleRadius,
111
+ });
112
+
113
+ /**
114
+ * Creates a value for the `background` prop that uses the Android theme's
115
+ * default background for borderless selectable elements. Requires API 21+.
116
+ */
117
+ static SelectableBackgroundBorderless: (rippleRadius: ?number) => $ReadOnly<{|
118
+ attribute: 'selectableItemBackgroundBorderless',
119
+ type: 'ThemeAttrAndroid',
120
+ rippleRadius: ?number,
121
+ |}> = (rippleRadius: ?number) => ({
122
+ type: 'ThemeAttrAndroid',
123
+ attribute: 'selectableItemBackgroundBorderless',
124
+ rippleRadius,
125
+ });
126
+
127
+ /**
128
+ * Creates a value for the `background` prop that uses the Android ripple with
129
+ * the supplied color. If `borderless` is true, the ripple will render outside
130
+ * of the view bounds. Requires API 21+.
131
+ */
132
+ static Ripple: (
133
+ color: string,
134
+ borderless: boolean,
135
+ rippleRadius: ?number,
136
+ ) => $ReadOnly<{|
137
+ borderless: boolean,
138
+ color: ?number,
139
+ rippleRadius: ?number,
140
+ type: 'RippleAndroid',
141
+ |}> = (color: string, borderless: boolean, rippleRadius: ?number) => {
142
+ const processedColor = processColor(color);
143
+ invariant(
144
+ processedColor == null || typeof processedColor === 'number',
145
+ 'Unexpected color given for Ripple color',
146
+ );
147
+ return {
148
+ type: 'RippleAndroid',
149
+ // $FlowFixMe[incompatible-type]
150
+ color: processedColor,
151
+ borderless,
152
+ rippleRadius,
153
+ };
154
+ };
155
+
156
+ /**
157
+ * Whether `useForeground` is supported.
158
+ */
159
+ static canUseNativeForeground: () => boolean = () =>
160
+ Platform.OS === 'android';
161
+
162
+ state: State = {
163
+ pressability: new Pressability(this._createPressabilityConfig()),
164
+ };
165
+
166
+ _createPressabilityConfig(): PressabilityConfig {
167
+ const accessibilityStateDisabled =
168
+ this.props['aria-disabled'] ?? this.props.accessibilityState?.disabled;
169
+ return {
170
+ cancelable: !this.props.rejectResponderTermination,
171
+ disabled:
172
+ this.props.disabled != null
173
+ ? this.props.disabled
174
+ : accessibilityStateDisabled,
175
+ hitSlop: this.props.hitSlop,
176
+ delayLongPress: this.props.delayLongPress,
177
+ delayPressIn: this.props.delayPressIn,
178
+ delayPressOut: this.props.delayPressOut,
179
+ minPressDuration: 0,
180
+ pressRectOffset: this.props.pressRetentionOffset,
181
+ android_disableSound: this.props.touchSoundDisabled,
182
+ onLongPress: this.props.onLongPress,
183
+ onPress: this.props.onPress,
184
+ onPressIn: event => {
185
+ if (Platform.OS === 'android') {
186
+ this._dispatchHotspotUpdate(event);
187
+ this._dispatchPressedStateChange(true);
188
+ }
189
+ if (this.props.onPressIn != null) {
190
+ this.props.onPressIn(event);
191
+ }
192
+ },
193
+ onPressMove: event => {
194
+ if (Platform.OS === 'android') {
195
+ this._dispatchHotspotUpdate(event);
196
+ }
197
+ },
198
+ onPressOut: event => {
199
+ if (Platform.OS === 'android') {
200
+ this._dispatchPressedStateChange(false);
201
+ }
202
+ if (this.props.onPressOut != null) {
203
+ this.props.onPressOut(event);
204
+ }
205
+ },
206
+ };
207
+ }
208
+
209
+ _dispatchPressedStateChange(pressed: boolean): void {
210
+ if (Platform.OS === 'android') {
211
+ const hostComponentRef = findHostInstance_DEPRECATED(this);
212
+ if (hostComponentRef == null) {
213
+ console.warn(
214
+ 'Touchable: Unable to find HostComponent instance. ' +
215
+ 'Has your Touchable component been unmounted?',
216
+ );
217
+ } else {
218
+ Commands.setPressed(hostComponentRef, pressed);
219
+ }
220
+ }
221
+ }
222
+
223
+ _dispatchHotspotUpdate(event: PressEvent): void {
224
+ if (Platform.OS === 'android') {
225
+ const {locationX, locationY} = event.nativeEvent;
226
+ const hostComponentRef = findHostInstance_DEPRECATED(this);
227
+ if (hostComponentRef == null) {
228
+ console.warn(
229
+ 'Touchable: Unable to find HostComponent instance. ' +
230
+ 'Has your Touchable component been unmounted?',
231
+ );
232
+ } else {
233
+ Commands.hotspotUpdate(
234
+ hostComponentRef,
235
+ locationX ?? 0,
236
+ locationY ?? 0,
237
+ );
238
+ }
239
+ }
240
+ }
241
+
242
+ render(): React.Node {
243
+ const element = React.Children.only<$FlowFixMe>(this.props.children);
244
+ const children: Array<React.Node> = [element.props.children];
245
+ if (__DEV__) {
246
+ if (element.type === View) {
247
+ children.push(
248
+ <PressabilityDebugView color="brown" hitSlop={this.props.hitSlop} />,
249
+ );
250
+ }
251
+ }
252
+
253
+ // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before
254
+ // adopting `Pressability`, so preserve that behavior.
255
+ const {onBlur, onFocus, ...eventHandlersWithoutBlurAndFocus} =
256
+ this.state.pressability.getEventHandlers();
257
+
258
+ let _accessibilityState = {
259
+ busy: this.props['aria-busy'] ?? this.props.accessibilityState?.busy,
260
+ checked:
261
+ this.props['aria-checked'] ?? this.props.accessibilityState?.checked,
262
+ disabled:
263
+ this.props['aria-disabled'] ?? this.props.accessibilityState?.disabled,
264
+ expanded:
265
+ this.props['aria-expanded'] ?? this.props.accessibilityState?.expanded,
266
+ selected:
267
+ this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
268
+ readOnly:
269
+ this.props['aria-readonly'] ?? this.props.accessibilityState?.readOnly,
270
+ multiselectable:
271
+ this.props['aria-multiselectable'] ??
272
+ this.props.accessibilityState?.multiselectable, // Windows
273
+ required:
274
+ this.props['aria-required'] ?? this.props.accessibilityState?.required, // Windows
275
+ };
276
+
277
+ _accessibilityState =
278
+ this.props.disabled != null
279
+ ? {
280
+ ..._accessibilityState,
281
+ disabled: this.props.disabled,
282
+ }
283
+ : _accessibilityState;
284
+
285
+ const accessibilityValue = {
286
+ max: this.props['aria-valuemax'] ?? this.props.accessibilityValue?.max,
287
+ min: this.props['aria-valuemin'] ?? this.props.accessibilityValue?.min,
288
+ now: this.props['aria-valuenow'] ?? this.props.accessibilityValue?.now,
289
+ text: this.props['aria-valuetext'] ?? this.props.accessibilityValue?.text,
290
+ };
291
+
292
+ const accessibilityLiveRegion =
293
+ this.props['aria-live'] === 'off'
294
+ ? 'none'
295
+ : this.props['aria-live'] ?? this.props.accessibilityLiveRegion;
296
+
297
+ const accessibilityLabel =
298
+ this.props['aria-label'] ?? this.props.accessibilityLabel;
299
+ return React.cloneElement(
300
+ element,
301
+ {
302
+ ...eventHandlersWithoutBlurAndFocus,
303
+ ...getBackgroundProp(
304
+ this.props.background === undefined
305
+ ? TouchableNativeFeedback.SelectableBackground()
306
+ : this.props.background,
307
+ this.props.useForeground === true,
308
+ ),
309
+ accessible: this.props.accessible !== false,
310
+ accessibilityHint: this.props.accessibilityHint,
311
+ accessibilityLanguage: this.props.accessibilityLanguage,
312
+ accessibilityLabel: accessibilityLabel,
313
+ accessibilityRole: this.props.accessibilityRole,
314
+ accessibilityState: _accessibilityState,
315
+ accessibilityActions: this.props.accessibilityActions,
316
+ onAccessibilityAction: this.props.onAccessibilityAction,
317
+ accessibilityValue: accessibilityValue,
318
+ importantForAccessibility:
319
+ this.props['aria-hidden'] === true
320
+ ? 'no-hide-descendants'
321
+ : this.props.importantForAccessibility,
322
+ accessibilityViewIsModal:
323
+ this.props['aria-modal'] ?? this.props.accessibilityViewIsModal,
324
+ accessibilityLiveRegion: accessibilityLiveRegion,
325
+ accessibilityElementsHidden:
326
+ this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden,
327
+ hasTVPreferredFocus: this.props.hasTVPreferredFocus,
328
+ hitSlop: this.props.hitSlop,
329
+ focusable:
330
+ this.props.focusable !== false &&
331
+ this.props.onPress !== undefined &&
332
+ !this.props.disabled,
333
+ nativeID: this.props.id ?? this.props.nativeID,
334
+ nextFocusDown: this.props.nextFocusDown,
335
+ nextFocusForward: this.props.nextFocusForward,
336
+ nextFocusLeft: this.props.nextFocusLeft,
337
+ nextFocusRight: this.props.nextFocusRight,
338
+ nextFocusUp: this.props.nextFocusUp,
339
+ onLayout: this.props.onLayout,
340
+ testID: this.props.testID,
341
+ },
342
+ ...children,
343
+ );
344
+ }
345
+
346
+ componentDidUpdate(prevProps: Props, prevState: State) {
347
+ this.state.pressability.configure(this._createPressabilityConfig());
348
+ }
349
+
350
+ componentDidMount(): mixed {
351
+ this.state.pressability.configure(this._createPressabilityConfig());
352
+ }
353
+
354
+ componentWillUnmount(): void {
355
+ this.state.pressability.reset();
356
+ }
357
+ }
358
+
359
+ const getBackgroundProp =
360
+ Platform.OS === 'android'
361
+ ? /* $FlowFixMe[missing-local-annot] The type annotation(s) required by
362
+ * Flow's LTI update could not be added via codemod */
363
+ (background, useForeground: boolean) =>
364
+ useForeground && TouchableNativeFeedback.canUseNativeForeground()
365
+ ? {nativeForegroundAndroid: background}
366
+ : {nativeBackgroundAndroid: background}
367
+ : /* $FlowFixMe[missing-local-annot] The type annotation(s) required by
368
+ * Flow's LTI update could not be added via codemod */
369
+ (background, useForeground: boolean) => null;
370
+
371
+ TouchableNativeFeedback.displayName = 'TouchableNativeFeedback';
372
+
373
+ module.exports = TouchableNativeFeedback;