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.
- package/Libraries/Components/Button.windows.js +9 -0
- package/Libraries/Components/Pressable/Pressable.windows.js +9 -0
- package/Libraries/Components/TextInput/TextInput.windows.js +11 -1
- package/Libraries/Components/Touchable/TouchableBounce.windows.js +225 -0
- package/Libraries/Components/Touchable/TouchableNativeFeedback.windows.js +373 -0
- package/Libraries/Components/Touchable/TouchableOpacity.windows.js +7 -0
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +10 -0
- package/Libraries/Components/View/View.windows.js +11 -1
- package/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
- package/Libraries/Components/View/ViewAccessibility.windows.js +5 -2
- package/Libraries/Components/View/ViewPropTypes.windows.js +3 -0
- package/Libraries/Image/Image.windows.js +7 -0
- package/Libraries/Text/Text.windows.js +11 -1
- package/Libraries/Text/TextProps.windows.js +3 -0
- package/Microsoft.ReactNative/CompositionComponentView.idl +13 -1
- package/Microsoft.ReactNative/Fabric/ComponentView.cpp +1 -2
- package/Microsoft.ReactNative/Fabric/ComponentView.h +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/ComponentViewRegistry.cpp +0 -5
- package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +293 -9
- package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +28 -1
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +13 -32
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +1 -3
- package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.h +2 -1
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +18 -5
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +191 -329
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.h +3 -61
- package/Microsoft.ReactNative/Fabric/Composition/PortalComponentView.cpp +66 -0
- package/Microsoft.ReactNative/Fabric/Composition/PortalComponentView.h +52 -0
- package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +21 -0
- package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +7 -4
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +79 -19
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +12 -6
- package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +71 -17
- package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +16 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +62 -33
- package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +5 -2
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +1 -6
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +0 -3
- package/Microsoft.ReactNative/Fabric/WindowsComponentDescriptorRegistry.cpp +0 -2
- package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +5 -0
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +19 -1
- package/Microsoft.ReactNative/ReactNativeHost.cpp +5 -0
- package/Microsoft.ReactNative/ReactNativeIsland.idl +5 -1
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/AccessibilityPrimitives.h +253 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/accessibilityPropsConversions.h +799 -0
- package/Shared/Shared.vcxitems +3 -2
- package/Shared/Shared.vcxitems.filters +2 -3
- package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +204 -0
- package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +287 -0
- package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +192 -0
- package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +216 -0
- package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +242 -0
- package/codegen/react/components/rnwcore/AndroidSwitch.g.h +259 -0
- package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +226 -0
- package/codegen/react/components/rnwcore/InputAccessory.g.h +192 -0
- package/codegen/react/components/rnwcore/ModalHostView.g.h +271 -0
- package/codegen/react/components/rnwcore/PullToRefreshView.g.h +238 -0
- package/codegen/react/components/rnwcore/SafeAreaView.g.h +189 -0
- package/codegen/react/components/rnwcore/Switch.g.h +255 -0
- package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +192 -0
- package/just-task.js +1 -1
- package/package.json +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentDescriptor.h +0 -39
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewShadowNode.cpp +0 -18
- 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;
|