react-native-windows 0.77.2 → 0.77.4

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 (35) hide show
  1. package/Libraries/Components/Button.windows.js +3 -0
  2. package/Libraries/Components/Pressable/Pressable.windows.js +3 -0
  3. package/Libraries/Components/TextInput/TextInput.windows.js +3 -0
  4. package/Libraries/Components/Touchable/TouchableBounce.windows.js +2 -0
  5. package/Libraries/Components/Touchable/TouchableNativeFeedback.windows.js +2 -0
  6. package/Libraries/Components/Touchable/TouchableOpacity.windows.js +2 -0
  7. package/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +2 -0
  8. package/Libraries/Components/View/View.windows.js +3 -0
  9. package/Libraries/Components/View/ViewAccessibility.d.ts +7 -2
  10. package/Libraries/Components/View/ViewAccessibility.windows.js +1 -0
  11. package/Libraries/Components/View/ViewPropTypes.windows.js +1 -0
  12. package/Libraries/Core/ReactNativeVersion.js +1 -1
  13. package/Libraries/Core/setUpDeveloperTools.js +2 -3
  14. package/Libraries/Image/Image.windows.js +2 -0
  15. package/Libraries/Text/Text.windows.js +4 -0
  16. package/Libraries/Text/TextProps.windows.js +1 -0
  17. package/Libraries/Utilities/HMRClient.js +0 -28
  18. package/Libraries/Utilities/HMRClientProdShim.js +0 -1
  19. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +215 -21
  20. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +10 -0
  21. package/Microsoft.ReactNative/Fabric/Composition/CompositionTextProvider.cpp +115 -0
  22. package/Microsoft.ReactNative/Fabric/Composition/CompositionTextProvider.h +41 -0
  23. package/Microsoft.ReactNative/Fabric/Composition/CompositionTextRangeProvider.cpp +298 -0
  24. package/Microsoft.ReactNative/Fabric/Composition/CompositionTextRangeProvider.h +59 -0
  25. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +1 -2
  26. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +14 -10
  27. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +3 -2
  28. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  29. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/AccessibilityPrimitives.h +1 -0
  30. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/accessibilityPropsConversions.h +4 -0
  31. package/Shared/Networking/WinRTWebSocketResource.cpp +369 -7
  32. package/Shared/Networking/WinRTWebSocketResource.h +118 -0
  33. package/Shared/Shared.vcxitems +6 -0
  34. package/Shared/Shared.vcxitems.filters +8 -0
  35. package/package.json +12 -12
@@ -164,6 +164,7 @@ type ButtonProps = $ReadOnly<{|
164
164
  'aria-disabled'?: ?boolean,
165
165
  'aria-expanded'?: ?boolean,
166
166
  'aria-selected'?: ?boolean,
167
+ 'aria-readonly'?: ?boolean, // Windows
167
168
  'aria-multiselectable'?: ?boolean, // Windows
168
169
  'aria-required'?: ?boolean, // Windows
169
170
 
@@ -312,6 +313,7 @@ const Button: component(
312
313
  'aria-expanded': ariaExpanded,
313
314
  'aria-label': ariaLabel,
314
315
  'aria-selected': ariaSelected,
316
+ 'aria-readonly': ariaReadOnly, // Windows
315
317
  'aria-multiselectable': ariaMultiselectable, // Windows
316
318
  'aria-required': ariaRequired, // Windows
317
319
  importantForAccessibility,
@@ -349,6 +351,7 @@ const Button: component(
349
351
  disabled: ariaDisabled ?? accessibilityState?.disabled,
350
352
  expanded: ariaExpanded ?? accessibilityState?.expanded,
351
353
  selected: ariaSelected ?? accessibilityState?.selected,
354
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly, // Windows
352
355
  multiselectable: ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
353
356
  required: ariaRequired ?? accessibilityState?.required, // Windows
354
357
  };
@@ -75,6 +75,7 @@ type Props = $ReadOnly<{|
75
75
  'aria-disabled'?: ?boolean,
76
76
  'aria-expanded'?: ?boolean,
77
77
  'aria-selected'?: ?boolean,
78
+ 'aria-readonly'?: ?boolean, // Windows
78
79
  'aria-multiselectable'?: ?boolean, // Windows
79
80
  'aria-required'?: ?boolean, // Windows
80
81
  /**
@@ -264,6 +265,7 @@ function Pressable(
264
265
  'aria-expanded': ariaExpanded,
265
266
  'aria-label': ariaLabel,
266
267
  'aria-selected': ariaSelected,
268
+ 'aria-readonly': ariaReadOnly,
267
269
  'aria-multiselectable': ariaMultiselectable, // Windows
268
270
  'aria-required': ariaRequired, // Windows
269
271
  cancelable,
@@ -309,6 +311,7 @@ function Pressable(
309
311
  disabled: ariaDisabled ?? accessibilityState?.disabled,
310
312
  expanded: ariaExpanded ?? accessibilityState?.expanded,
311
313
  selected: ariaSelected ?? accessibilityState?.selected,
314
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly,
312
315
  multiselectable: ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
313
316
  required: ariaRequired ?? accessibilityState?.required, // Windows
314
317
  };
@@ -1360,6 +1360,7 @@ function InternalTextInput(props: Props): React.Node {
1360
1360
  'aria-disabled': ariaDisabled,
1361
1361
  'aria-expanded': ariaExpanded,
1362
1362
  'aria-selected': ariaSelected,
1363
+ 'aria-readonly': ariaReadOnly, // Windows
1363
1364
  'aria-multiselectable': ariaMultiselectable, // Windows
1364
1365
  'aria-required': ariaRequired, // Windows
1365
1366
  accessibilityState,
@@ -1691,6 +1692,7 @@ function InternalTextInput(props: Props): React.Node {
1691
1692
  ariaDisabled != null ||
1692
1693
  ariaExpanded != null ||
1693
1694
  ariaSelected != null ||
1695
+ ariaReadOnly != null || // Windows
1694
1696
  ariaMultiselectable != null || // Windows
1695
1697
  ariaRequired != null // Windows
1696
1698
  ) {
@@ -1700,6 +1702,7 @@ function InternalTextInput(props: Props): React.Node {
1700
1702
  disabled: ariaDisabled ?? accessibilityState?.disabled,
1701
1703
  expanded: ariaExpanded ?? accessibilityState?.expanded,
1702
1704
  selected: ariaSelected ?? accessibilityState?.selected,
1705
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly, // Windows
1703
1706
  multiselectable:
1704
1707
  ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
1705
1708
  required: ariaRequired ?? accessibilityState?.required, // Windows
@@ -146,6 +146,8 @@ class TouchableBounce extends React.Component<Props, State> {
146
146
  this.props['aria-expanded'] ?? this.props.accessibilityState?.expanded,
147
147
  selected:
148
148
  this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
149
+ readOnly:
150
+ this.props['aria-readonly'] ?? this.props.accessibilityState?.readOnly, // Windows
149
151
  multiselectable:
150
152
  this.props['aria-multiselectable'] ??
151
153
  this.props.accessibilityState?.multiselectable, // Windows
@@ -265,6 +265,8 @@ class TouchableNativeFeedback extends React.Component<Props, State> {
265
265
  this.props['aria-expanded'] ?? this.props.accessibilityState?.expanded,
266
266
  selected:
267
267
  this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
268
+ readOnly:
269
+ this.props['aria-readonly'] ?? this.props.accessibilityState?.readOnly,
268
270
  multiselectable:
269
271
  this.props['aria-multiselectable'] ??
270
272
  this.props.accessibilityState?.multiselectable, // Windows
@@ -235,6 +235,8 @@ class TouchableOpacity extends React.Component<Props, State> {
235
235
  this.props['aria-expanded'] ?? this.props.accessibilityState?.expanded,
236
236
  selected:
237
237
  this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
238
+ readOnly:
239
+ this.props['aria-readonly'] ?? this.props.accessibilityState?.readOnly, // Windows
238
240
  multiselectable:
239
241
  this.props['aria-multiselectable'] ??
240
242
  this.props.accessibilityState?.multiselectable, // Windows
@@ -59,6 +59,7 @@ type Props = $ReadOnly<{|
59
59
  'aria-disabled'?: ?boolean,
60
60
  'aria-expanded'?: ?boolean,
61
61
  'aria-selected'?: ?boolean,
62
+ 'aria-readonly'?: ?boolean, // Windows
62
63
  'aria-multiselectable'?: ?boolean, // Windows
63
64
  'aria-required'?: ?boolean, // Windows
64
65
  'aria-hidden'?: ?boolean,
@@ -224,6 +225,7 @@ const TouchableWithoutFeedback: React.AbstractComponent<
224
225
  disabled: props['aria-disabled'] ?? props.accessibilityState?.disabled,
225
226
  expanded: props['aria-expanded'] ?? props.accessibilityState?.expanded,
226
227
  selected: props['aria-selected'] ?? props.accessibilityState?.selected,
228
+ readonly: props['aria-readonly'] ?? props.accessibilityState?.readOnly, // Windows
227
229
  multiselectable:
228
230
  props['aria-multiselectable'] ??
229
231
  props.accessibilityState?.multiselectable, // Windows
@@ -84,6 +84,7 @@ const View: component(
84
84
  'aria-level': ariaLevel,
85
85
  'aria-live': ariaLive,
86
86
  'aria-posinset': ariaPosinset, // Windows
87
+ 'aria-readonly': ariaReadOnly, // Windows
87
88
  'aria-selected': ariaSelected,
88
89
  'aria-setsize': ariaSetsize, // Windows
89
90
  'aria-valuemax': ariaValueMax,
@@ -111,6 +112,7 @@ const View: component(
111
112
  ariaDisabled != null ||
112
113
  ariaExpanded != null ||
113
114
  ariaSelected != null ||
115
+ ariaReadOnly != null || // Windows
114
116
  ariaMultiselectable != null || // Windows
115
117
  ariaRequired != null // Windows
116
118
  ) {
@@ -120,6 +122,7 @@ const View: component(
120
122
  disabled: ariaDisabled ?? accessibilityState?.disabled,
121
123
  expanded: ariaExpanded ?? accessibilityState?.expanded,
122
124
  selected: ariaSelected ?? accessibilityState?.selected,
125
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly, // Windows
123
126
  multiselectable:
124
127
  ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
125
128
  required: ariaRequired ?? accessibilityState?.required, // Windows
@@ -183,14 +183,19 @@ export interface AccessibilityState {
183
183
  * When present, informs accessible tools the element is expanded or collapsed
184
184
  */
185
185
  expanded?: boolean | undefined;
186
+ /**
187
+ * When present, informs accessible tools the element is read only
188
+ * @platform windows
189
+ */
190
+ readOnly?: boolean | undefined;
186
191
  /**
187
192
  * When present, informs accessible tools the element can have multiple items selected
188
- * @platform windows
193
+ * @platform windows
189
194
  */
190
195
  multiselectable?: boolean | undefined;
191
196
  /**
192
197
  * When present, informs accessible tools the element requires selection
193
- * @platform windows
198
+ * @platform windows
194
199
  */
195
200
  required?: boolean | undefined;
196
201
  }
@@ -181,6 +181,7 @@ export type AccessibilityState = {
181
181
  checked?: ?boolean | 'mixed',
182
182
  busy?: ?boolean,
183
183
  expanded?: ?boolean,
184
+ readOnly?: ?boolean, // Windows
184
185
  multiselectable?: ?boolean, // Windows
185
186
  required?: ?boolean, // Windows
186
187
  ...
@@ -620,6 +620,7 @@ export type ViewProps = $ReadOnly<{|
620
620
  'aria-disabled'?: ?boolean,
621
621
  'aria-expanded'?: ?boolean,
622
622
  'aria-selected'?: ?boolean,
623
+ 'aria-readonly'?: ?boolean, // Windows
623
624
  /** A value indicating whether the accessibility elements contained within
624
625
  * this accessibility element are hidden.
625
626
  *
@@ -16,7 +16,7 @@ const version: $ReadOnly<{
16
16
  }> = {
17
17
  major: 0,
18
18
  minor: 77,
19
- patch: 0,
19
+ patch: 1,
20
20
  prerelease: null,
21
21
  };
22
22
 
@@ -42,9 +42,8 @@ if (__DEV__) {
42
42
  if (!Platform.isTesting) {
43
43
  const HMRClient = require('../Utilities/HMRClient');
44
44
 
45
- if (global.__FUSEBOX_HAS_FULL_CONSOLE_SUPPORT__) {
46
- HMRClient.unstable_notifyFuseboxConsoleEnabled();
47
- } else if (console._isPolyfilled) {
45
+ // TODO(T214991636): Remove legacy Metro log forwarding
46
+ if (console._isPolyfilled) {
48
47
  // We assume full control over the console and send JavaScript logs to Metro.
49
48
  [
50
49
  'trace',
@@ -147,6 +147,7 @@ let BaseImage: AbstractImageIOS = React.forwardRef((props, forwardedRef) => {
147
147
  'aria-disabled': ariaDisabled,
148
148
  'aria-expanded': ariaExpanded,
149
149
  'aria-selected': ariaSelected,
150
+ 'aria-readonly': ariaReadOnly, // Windows
150
151
  'aria-multiselectable': ariaMultiselectable, // Windows
151
152
  'aria-required': ariaRequired, // Windows
152
153
  height,
@@ -160,6 +161,7 @@ let BaseImage: AbstractImageIOS = React.forwardRef((props, forwardedRef) => {
160
161
  disabled: ariaDisabled ?? props.accessibilityState?.disabled,
161
162
  expanded: ariaExpanded ?? props.accessibilityState?.expanded,
162
163
  selected: ariaSelected ?? props.accessibilityState?.selected,
164
+ readOnly: ariaReadOnly ?? props.accessibilityState?.readOnly, // Windows
163
165
  multiselectable:
164
166
  ariaMultiselectable ?? props.accessibilityState?.multiselectable, // Windows
165
167
  required: ariaRequired ?? props.accessibilityState?.required, // Windows
@@ -60,6 +60,7 @@ const Text: component(
60
60
  'aria-posinset': ariaPosinset, // Windows
61
61
  'aria-setsize': ariaSetsize, // Windows
62
62
  'aria-selected': ariaSelected,
63
+ 'aria-readonly': ariaReadOnly, //Windows
63
64
  children,
64
65
  ellipsizeMode,
65
66
  disabled,
@@ -98,6 +99,7 @@ const Text: component(
98
99
  ariaDisabled != null ||
99
100
  ariaExpanded != null ||
100
101
  ariaSelected != null ||
102
+ ariaReadOnly != null || // Windows
101
103
  ariaMultiselectable != null || // Windows
102
104
  ariaRequired != null // Windows
103
105
  ) {
@@ -108,6 +110,7 @@ const Text: component(
108
110
  disabled: ariaDisabled ?? _accessibilityState.disabled,
109
111
  expanded: ariaExpanded ?? _accessibilityState.expanded,
110
112
  selected: ariaSelected ?? _accessibilityState.selected,
113
+ readOnly: ariaReadOnly ?? _accessibilityState.readOnly, // Windows
111
114
  multiselectable:
112
115
  ariaMultiselectable ?? _accessibilityState.multiselectable, // Windows
113
116
  required: ariaRequired ?? _accessibilityState.required, // Windows
@@ -119,6 +122,7 @@ const Text: component(
119
122
  disabled: ariaDisabled,
120
123
  expanded: ariaExpanded,
121
124
  selected: ariaSelected,
125
+ readOnly: ariaReadOnly, // Windows
122
126
  multiselectable: ariaMultiselectable, // Windows
123
127
  required: ariaRequired, // Windows
124
128
  };
@@ -97,6 +97,7 @@ export type TextProps = $ReadOnly<{
97
97
  'aria-posinset'?: ?number, // Windows
98
98
  'aria-setsize'?: ?number, // Windows
99
99
  'aria-level'?: ?number, // Windows
100
+ 'aria-readonly'?: ?boolean, // Windows
100
101
  'aria-multiselectable'?: ?boolean, // Windows
101
102
  'aria-required'?: ?boolean, // Windows
102
103
 
@@ -26,7 +26,6 @@ let hmrUnavailableReason: string | null = null;
26
26
  let currentCompileErrorMessage: string | null = null;
27
27
  let didConnect: boolean = false;
28
28
  let pendingLogs: Array<[LogLevel, $ReadOnlyArray<mixed>]> = [];
29
- let pendingFuseboxConsoleNotification = false;
30
29
 
31
30
  type LogLevel =
32
31
  | 'trace'
@@ -52,7 +51,6 @@ export type HMRClientNativeInterface = {|
52
51
  isEnabled: boolean,
53
52
  scheme?: string,
54
53
  ): void,
55
- unstable_notifyFuseboxConsoleEnabled(): void,
56
54
  |};
57
55
 
58
56
  /**
@@ -142,29 +140,6 @@ const HMRClient: HMRClientNativeInterface = {
142
140
  }
143
141
  },
144
142
 
145
- unstable_notifyFuseboxConsoleEnabled() {
146
- if (!hmrClient) {
147
- pendingFuseboxConsoleNotification = true;
148
- return;
149
- }
150
- hmrClient.send(
151
- JSON.stringify({
152
- type: 'log',
153
- level: 'info',
154
- data: [
155
- '\n' +
156
- '\u001B[7m' +
157
- ' \u001B[1m💡 JavaScript logs have moved!\u001B[22m They can now be ' +
158
- 'viewed in React Native DevTools. Tip: Type \u001B[1mj\u001B[22m in ' +
159
- 'the terminal to open (requires Google Chrome or Microsoft Edge).' +
160
- '\u001B[27m' +
161
- '\n',
162
- ],
163
- }),
164
- );
165
- pendingFuseboxConsoleNotification = false;
166
- },
167
-
168
143
  // Called once by the bridge on startup, even if Fast Refresh is off.
169
144
  // It creates the HMR client but doesn't actually set up the socket yet.
170
145
  setup(
@@ -341,9 +316,6 @@ function flushEarlyLogs(client: MetroHMRClient) {
341
316
  pendingLogs.forEach(([level, data]) => {
342
317
  HMRClient.log(level, data);
343
318
  });
344
- if (pendingFuseboxConsoleNotification) {
345
- HMRClient.unstable_notifyFuseboxConsoleEnabled();
346
- }
347
319
  } finally {
348
320
  pendingLogs.length = 0;
349
321
  }
@@ -25,7 +25,6 @@ const HMRClientProdShim: HMRClientNativeInterface = {
25
25
  disable() {},
26
26
  registerBundle() {},
27
27
  log() {},
28
- unstable_notifyFuseboxConsoleEnabled() {},
29
28
  };
30
29
 
31
30
  module.exports = HMRClientProdShim;
@@ -1,6 +1,8 @@
1
1
  #include "pch.h"
2
2
  #include "CompositionDynamicAutomationProvider.h"
3
3
  #include <Fabric/ComponentView.h>
4
+ #include <Fabric/Composition/CompositionTextRangeProvider.h>
5
+ #include <Fabric/Composition/ParagraphComponentView.h>
4
6
  #include <Fabric/Composition/SwitchComponentView.h>
5
7
  #include <Fabric/Composition/TextInput/WindowsTextInputComponentView.h>
6
8
  #include <Unicode.h>
@@ -25,6 +27,13 @@ CompositionDynamicAutomationProvider::CompositionDynamicAutomationProvider(
25
27
  if (props->accessibilityState.has_value() && props->accessibilityState->selected.has_value()) {
26
28
  AddSelectionItemsToContainer(this);
27
29
  }
30
+
31
+ if (strongView.try_as<winrt::Microsoft::ReactNative::Composition::implementation::WindowsTextInputComponentView>() ||
32
+ strongView.try_as<winrt::Microsoft::ReactNative::Composition::implementation::ParagraphComponentView>()) {
33
+ m_textProvider = winrt::make<CompositionTextProvider>(
34
+ strongView.as<winrt::Microsoft::ReactNative::Composition::ComponentView>(), this)
35
+ .try_as<ITextProvider2>();
36
+ }
28
37
  }
29
38
 
30
39
  HRESULT __stdcall CompositionDynamicAutomationProvider::Navigate(
@@ -141,8 +150,12 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::get_ProviderOptions(Prov
141
150
  return S_OK;
142
151
  }
143
152
 
144
- bool accessibilityValueHasValue(const facebook::react::AccessibilityValue &value) {
145
- return (value.min.has_value() && value.max.has_value()) || value.now.has_value() || value.text.has_value();
153
+ bool accessibilityValueHasTextValue(const facebook::react::AccessibilityValue &value) {
154
+ return value.text.has_value();
155
+ }
156
+
157
+ bool accessibilityValueHasNumericValue(const facebook::react::AccessibilityValue &value) {
158
+ return (value.min.has_value() && value.max.has_value() && value.now.has_value());
146
159
  }
147
160
 
148
161
  bool expandableControl(const facebook::react::SharedViewProps props) {
@@ -203,8 +216,15 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE
203
216
  }
204
217
 
205
218
  if (patternId == UIA_ValuePatternId &&
206
- (strongView.try_as<winrt::Microsoft::ReactNative::Composition::implementation::WindowsTextInputComponentView>() ||
207
- accessibilityValueHasValue(props->accessibilityValue))) {
219
+ ((strongView
220
+ .try_as<winrt::Microsoft::ReactNative::Composition::implementation::WindowsTextInputComponentView>() &&
221
+ !accessibilityValueHasNumericValue(props->accessibilityValue)) ||
222
+ accessibilityValueHasTextValue(props->accessibilityValue))) {
223
+ *pRetVal = static_cast<IValueProvider *>(this);
224
+ AddRef();
225
+ }
226
+
227
+ if (patternId == UIA_RangeValuePatternId && accessibilityValueHasNumericValue(props->accessibilityValue)) {
208
228
  *pRetVal = static_cast<IValueProvider *>(this);
209
229
  AddRef();
210
230
  }
@@ -233,10 +253,21 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE
233
253
  AddRef();
234
254
  }
235
255
 
256
+ if (patternId == UIA_TextPatternId &&
257
+ (strongView.try_as<winrt::Microsoft::ReactNative::Composition::implementation::WindowsTextInputComponentView>() ||
258
+ strongView.try_as<winrt::Microsoft::ReactNative::Composition::implementation::ParagraphComponentView>())) {
259
+ m_textProvider.as<IUnknown>().copy_to(pRetVal);
260
+ }
261
+
262
+ if (patternId == UIA_TextPattern2Id &&
263
+ strongView.try_as<winrt::Microsoft::ReactNative::Composition::implementation::WindowsTextInputComponentView>()) {
264
+ m_textProvider.as<IUnknown>().copy_to(pRetVal);
265
+ }
266
+
236
267
  return S_OK;
237
268
  }
238
269
 
239
- long GetControlType(const std::string &role) noexcept {
270
+ long GetControlTypeFromString(const std::string &role) noexcept {
240
271
  if (role == "adjustable") {
241
272
  return UIA_SliderControlTypeId;
242
273
  } else if (role == "group" || role == "search" || role == "radiogroup" || role == "timer" || role.empty()) {
@@ -299,6 +330,96 @@ long GetControlType(const std::string &role) noexcept {
299
330
  return UIA_GroupControlTypeId;
300
331
  }
301
332
 
333
+ long GetControlTypeFromRole(const facebook::react::Role &role) noexcept {
334
+ switch (role) {
335
+ case facebook::react::Role::Alert:
336
+ return UIA_TextControlTypeId;
337
+ case facebook::react::Role::Application:
338
+ return UIA_WindowControlTypeId;
339
+ case facebook::react::Role::Button:
340
+ return UIA_ButtonControlTypeId;
341
+ case facebook::react::Role::Checkbox:
342
+ return UIA_CheckBoxControlTypeId;
343
+ case facebook::react::Role::Columnheader:
344
+ return UIA_HeaderControlTypeId;
345
+ case facebook::react::Role::Combobox:
346
+ return UIA_ComboBoxControlTypeId;
347
+ case facebook::react::Role::Document:
348
+ return UIA_DocumentControlTypeId;
349
+ case facebook::react::Role::Grid:
350
+ return UIA_GroupControlTypeId;
351
+ case facebook::react::Role::Group:
352
+ return UIA_GroupControlTypeId;
353
+ case facebook::react::Role::Heading:
354
+ return UIA_TextControlTypeId;
355
+ case facebook::react::Role::Img:
356
+ return UIA_ImageControlTypeId;
357
+ case facebook::react::Role::Link:
358
+ return UIA_HyperlinkControlTypeId;
359
+ case facebook::react::Role::List:
360
+ return UIA_ListControlTypeId;
361
+ case facebook::react::Role::Listitem:
362
+ return UIA_ListItemControlTypeId;
363
+ case facebook::react::Role::Menu:
364
+ return UIA_MenuControlTypeId;
365
+ case facebook::react::Role::Menubar:
366
+ return UIA_MenuBarControlTypeId;
367
+ case facebook::react::Role::Menuitem:
368
+ return UIA_MenuItemControlTypeId;
369
+ case facebook::react::Role::None:
370
+ return UIA_GroupControlTypeId;
371
+ case facebook::react::Role::Presentation:
372
+ return UIA_GroupControlTypeId;
373
+ case facebook::react::Role::Progressbar:
374
+ return UIA_ProgressBarControlTypeId;
375
+ case facebook::react::Role::Radio:
376
+ return UIA_RadioButtonControlTypeId;
377
+ case facebook::react::Role::Radiogroup:
378
+ return UIA_GroupControlTypeId;
379
+ case facebook::react::Role::Rowgroup:
380
+ return UIA_GroupControlTypeId;
381
+ case facebook::react::Role::Rowheader:
382
+ return UIA_HeaderControlTypeId;
383
+ case facebook::react::Role::Scrollbar:
384
+ return UIA_ScrollBarControlTypeId;
385
+ case facebook::react::Role::Searchbox:
386
+ return UIA_EditControlTypeId;
387
+ case facebook::react::Role::Separator:
388
+ return UIA_SeparatorControlTypeId;
389
+ case facebook::react::Role::Slider:
390
+ return UIA_SliderControlTypeId;
391
+ case facebook::react::Role::Spinbutton:
392
+ return UIA_SpinnerControlTypeId;
393
+ case facebook::react::Role::Status:
394
+ return UIA_StatusBarControlTypeId;
395
+ case facebook::react::Role::Summary:
396
+ return UIA_GroupControlTypeId;
397
+ case facebook::react::Role::Switch:
398
+ return UIA_ButtonControlTypeId;
399
+ case facebook::react::Role::Tab:
400
+ return UIA_TabItemControlTypeId;
401
+ case facebook::react::Role::Table:
402
+ return UIA_TableControlTypeId;
403
+ case facebook::react::Role::Tablist:
404
+ return UIA_TabControlTypeId;
405
+ case facebook::react::Role::Tabpanel:
406
+ return UIA_TabControlTypeId;
407
+ case facebook::react::Role::Timer:
408
+ return UIA_ButtonControlTypeId;
409
+ case facebook::react::Role::Toolbar:
410
+ return UIA_ToolBarControlTypeId;
411
+ case facebook::react::Role::Tooltip:
412
+ return UIA_ToolTipControlTypeId;
413
+ case facebook::react::Role::Tree:
414
+ return UIA_TreeControlTypeId;
415
+ case facebook::react::Role::Treegrid:
416
+ return UIA_TreeControlTypeId;
417
+ case facebook::react::Role::Treeitem:
418
+ return UIA_TreeItemControlTypeId;
419
+ }
420
+ return UIA_GroupControlTypeId;
421
+ }
422
+
302
423
  HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERTYID propertyId, VARIANT *pRetVal) {
303
424
  if (pRetVal == nullptr)
304
425
  return E_POINTER;
@@ -324,8 +445,10 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERT
324
445
  switch (propertyId) {
325
446
  case UIA_ControlTypePropertyId: {
326
447
  pRetVal->vt = VT_I4;
327
- auto role = props->accessibilityRole.empty() ? compositionView->DefaultControlType() : props->accessibilityRole;
328
- pRetVal->lVal = GetControlType(role);
448
+ pRetVal->lVal = props->role == facebook::react::Role::None ? props->accessibilityRole.empty()
449
+ ? GetControlTypeFromString(compositionView->DefaultControlType())
450
+ : GetControlTypeFromString(props->accessibilityRole)
451
+ : GetControlTypeFromRole(props->role);
329
452
  break;
330
453
  }
331
454
  case UIA_AutomationIdPropertyId: {
@@ -365,12 +488,18 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERT
365
488
  }
366
489
  case UIA_IsContentElementPropertyId: {
367
490
  pRetVal->vt = VT_BOOL;
368
- pRetVal->boolVal = (props->accessible && props->accessibilityRole != "none") ? VARIANT_TRUE : VARIANT_FALSE;
491
+ pRetVal->boolVal =
492
+ (props->accessible && (props->accessibilityRole != "none" || props->role != facebook::react::Role::None))
493
+ ? VARIANT_TRUE
494
+ : VARIANT_FALSE;
369
495
  break;
370
496
  }
371
497
  case UIA_IsControlElementPropertyId: {
372
498
  pRetVal->vt = VT_BOOL;
373
- pRetVal->boolVal = (props->accessible && props->accessibilityRole != "none") ? VARIANT_TRUE : VARIANT_FALSE;
499
+ pRetVal->boolVal =
500
+ (props->accessible && (props->accessibilityRole != "none" || props->role != facebook::react::Role::None))
501
+ ? VARIANT_TRUE
502
+ : VARIANT_FALSE;
374
503
  break;
375
504
  }
376
505
  case UIA_IsOffscreenPropertyId: {
@@ -485,6 +614,8 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::SetValue(LPCWSTR val) {
485
614
 
486
615
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)
487
616
  ->setAcccessiblityValue(winrt::to_string(val));
617
+ // TODO: Edit once/if onAccessibilityAction props supports returning UIA event data. See
618
+ // https://github.com/react-native-community/discussions-and-proposals/issues/843.
488
619
  DispatchAccessibilityAction(m_view, "setValue");
489
620
  return S_OK;
490
621
  }
@@ -515,23 +646,86 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::get_IsReadOnly(BOOL *pRe
515
646
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
516
647
  if (props == nullptr)
517
648
  return UIA_E_ELEMENTNOTAVAILABLE;
518
- auto accessibilityRole = props->accessibilityRole;
519
- if (accessibilityRole.empty()) {
520
- // Control is using default control type. Use default IsReadOnly value.
521
- *pRetVal = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)
522
- ->getAcccessiblityIsReadOnly();
523
- } else if (
524
- accessibilityRole == "textinput" || accessibilityRole == "searchbox" || accessibilityRole == "adjustable" ||
525
- accessibilityRole == "spinbutton" || accessibilityRole == "combobox") {
526
- // Control is using customized control type which should not be IsReadOnly for value pattern.
527
- *pRetVal = false;
649
+ if (props->accessibilityState.has_value() && props->accessibilityState->readOnly.has_value()) {
650
+ *pRetVal = props->accessibilityState->readOnly.value();
528
651
  } else {
529
- // Control is using customized control type which should be IsReadOnly for value pattern.
530
- *pRetVal = true;
652
+ // Use default IsReadOnly value.
653
+ *pRetVal = false;
531
654
  }
532
655
  return S_OK;
533
656
  }
534
657
 
658
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_LargeChange(double *pRetVal) {
659
+ // no-op
660
+ return S_OK;
661
+ }
662
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_Maximum(double *pRetVal) {
663
+ if (pRetVal == nullptr)
664
+ return E_POINTER;
665
+ auto strongView = m_view.view();
666
+
667
+ if (!strongView)
668
+ return UIA_E_ELEMENTNOTAVAILABLE;
669
+
670
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
671
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
672
+
673
+ if (props == nullptr)
674
+ return UIA_E_ELEMENTNOTAVAILABLE;
675
+
676
+ *pRetVal = props->accessibilityValue.max.value();
677
+ return S_OK;
678
+ }
679
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_Minimum(double *pRetVal) {
680
+ if (pRetVal == nullptr)
681
+ return E_POINTER;
682
+ auto strongView = m_view.view();
683
+
684
+ if (!strongView)
685
+ return UIA_E_ELEMENTNOTAVAILABLE;
686
+
687
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
688
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
689
+
690
+ if (props == nullptr)
691
+ return UIA_E_ELEMENTNOTAVAILABLE;
692
+
693
+ *pRetVal = props->accessibilityValue.min.value();
694
+ return S_OK;
695
+ }
696
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_SmallChange(double *pRetVal) {
697
+ // no-op
698
+ return S_OK;
699
+ }
700
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_Value(double *pRetVal) {
701
+ if (pRetVal == nullptr)
702
+ return E_POINTER;
703
+ auto strongView = m_view.view();
704
+
705
+ if (!strongView)
706
+ return UIA_E_ELEMENTNOTAVAILABLE;
707
+
708
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
709
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
710
+
711
+ if (props == nullptr)
712
+ return UIA_E_ELEMENTNOTAVAILABLE;
713
+
714
+ *pRetVal = props->accessibilityValue.now.value();
715
+ return S_OK;
716
+ }
717
+ HRESULT __stdcall CompositionDynamicAutomationProvider::SetValue(double val) {
718
+ auto strongView = m_view.view();
719
+
720
+ if (!strongView)
721
+ return UIA_E_ELEMENTNOTAVAILABLE;
722
+
723
+ // TODO: Edit once/if onAccessibilityAction props supports returning UIA event data. See
724
+ // https://github.com/react-native-community/discussions-and-proposals/issues/843.
725
+ DispatchAccessibilityAction(m_view, "setValue");
726
+ return S_OK;
727
+ }
728
+
535
729
  HRESULT __stdcall CompositionDynamicAutomationProvider::get_ToggleState(ToggleState *pRetVal) {
536
730
  if (pRetVal == nullptr)
537
731
  return E_POINTER;