react-native-windows 0.74.29 → 0.74.31

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
@@ -235,6 +235,13 @@ 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
240
+ multiselectable:
241
+ this.props['aria-multiselectable'] ??
242
+ this.props.accessibilityState?.multiselectable, // Windows
243
+ required:
244
+ this.props['aria-required'] ?? this.props.accessibilityState?.required, // Windows
238
245
  };
239
246
 
240
247
  _accessibilityState =
@@ -59,6 +59,9 @@ type Props = $ReadOnly<{|
59
59
  'aria-disabled'?: ?boolean,
60
60
  'aria-expanded'?: ?boolean,
61
61
  'aria-selected'?: ?boolean,
62
+ 'aria-readonly'?: ?boolean, // Windows
63
+ 'aria-multiselectable'?: ?boolean, // Windows
64
+ 'aria-required'?: ?boolean, // Windows
62
65
  'aria-hidden'?: ?boolean,
63
66
  'aria-live'?: ?('polite' | 'assertive' | 'off'),
64
67
  'aria-label'?: ?Stringish,
@@ -158,6 +161,13 @@ class TouchableWithoutFeedback extends React.Component<Props, State> {
158
161
  this.props['aria-expanded'] ?? this.props.accessibilityState?.expanded,
159
162
  selected:
160
163
  this.props['aria-selected'] ?? this.props.accessibilityState?.selected,
164
+ readonly:
165
+ this.props['aria-readonly'] ?? this.props.accessibilityState?.readOnly, // Windows
166
+ multiselectable:
167
+ this.props['aria-multiselectable'] ??
168
+ this.props.accessibilityState?.multiselectable, // Windows
169
+ required:
170
+ this.props['aria-required'] ?? this.props.accessibilityState?.required, // Windows
161
171
  };
162
172
 
163
173
  // BACKWARD-COMPATIBILITY: Focus and blur events were never supported before
@@ -47,12 +47,15 @@ const View: React.AbstractComponent<
47
47
  'aria-checked': ariaChecked,
48
48
  'aria-disabled': ariaDisabled,
49
49
  'aria-expanded': ariaExpanded,
50
+ 'aria-multiselectable': ariaMultiselectable, // Windows
51
+ 'aria-required': ariaRequired, // Windows
50
52
  'aria-hidden': ariaHidden,
51
53
  'aria-label': ariaLabel,
52
54
  'aria-labelledby': ariaLabelledBy,
53
55
  'aria-level': ariaLevel,
54
56
  'aria-live': ariaLive,
55
57
  'aria-posinset': ariaPosinset, // Windows
58
+ 'aria-readonly': ariaReadOnly, // Windows
56
59
  'aria-selected': ariaSelected,
57
60
  'aria-setsize': ariaSetsize, // Windows
58
61
  'aria-valuemax': ariaValueMax,
@@ -80,7 +83,10 @@ const View: React.AbstractComponent<
80
83
  ariaChecked != null ||
81
84
  ariaDisabled != null ||
82
85
  ariaExpanded != null ||
83
- ariaSelected != null
86
+ ariaSelected != null ||
87
+ ariaReadOnly != null || // Windows
88
+ ariaMultiselectable != null || // Windows
89
+ ariaRequired != null // Windows
84
90
  ) {
85
91
  _accessibilityState = {
86
92
  busy: ariaBusy ?? accessibilityState?.busy,
@@ -88,6 +94,10 @@ const View: React.AbstractComponent<
88
94
  disabled: ariaDisabled ?? accessibilityState?.disabled,
89
95
  expanded: ariaExpanded ?? accessibilityState?.expanded,
90
96
  selected: ariaSelected ?? accessibilityState?.selected,
97
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly, // Windows
98
+ multiselectable:
99
+ ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
100
+ required: ariaRequired ?? accessibilityState?.required, // Windows
91
101
  };
92
102
  }
93
103
  let _accessibilityValue;
@@ -183,6 +183,21 @@ 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;
191
+ /**
192
+ * When present, informs accessible tools the element can have multiple items selected
193
+ * @platform windows
194
+ */
195
+ multiselectable?: boolean | undefined;
196
+ /**
197
+ * When present, informs accessible tools the element requires selection
198
+ * @platform windows
199
+ */
200
+ required?: boolean | undefined;
186
201
  }
187
202
 
188
203
  export interface AccessibilityValue {
@@ -179,8 +179,11 @@ export type AccessibilityState = {
179
179
  disabled?: boolean,
180
180
  selected?: boolean,
181
181
  checked?: ?boolean | 'mixed',
182
- busy?: boolean,
183
- expanded?: boolean,
182
+ busy?: ?boolean,
183
+ expanded?: ?boolean,
184
+ readOnly?: ?boolean, // Windows
185
+ multiselectable?: ?boolean, // Windows
186
+ required?: ?boolean, // Windows
184
187
  ...
185
188
  };
186
189
 
@@ -606,12 +606,15 @@ export type ViewProps = $ReadOnly<{|
606
606
  'aria-disabled'?: ?boolean,
607
607
  'aria-expanded'?: ?boolean,
608
608
  'aria-selected'?: ?boolean,
609
+ 'aria-readonly'?: ?boolean, // Windows
609
610
  /** A value indicating whether the accessibility elements contained within
610
611
  * this accessibility element are hidden.
611
612
  *
612
613
  * See https://reactnative.dev/docs/view#aria-hidden
613
614
  */
614
615
  'aria-hidden'?: ?boolean,
616
+ 'aria-multiselectable'?: ?boolean, // Windows
617
+ 'aria-required'?: ?boolean, // Windows
615
618
 
616
619
  /**
617
620
  * Views that are only used to layout their children or otherwise don't draw
@@ -148,6 +148,9 @@ let BaseImage: AbstractImageIOS = React.forwardRef((props, forwardedRef) => {
148
148
  'aria-disabled': ariaDisabled,
149
149
  'aria-expanded': ariaExpanded,
150
150
  'aria-selected': ariaSelected,
151
+ 'aria-readonly': ariaReadOnly, // Windows
152
+ 'aria-multiselectable': ariaMultiselectable, // Windows
153
+ 'aria-required': ariaRequired, // Windows
151
154
  height,
152
155
  src,
153
156
  width,
@@ -160,6 +163,10 @@ let BaseImage: AbstractImageIOS = React.forwardRef((props, forwardedRef) => {
160
163
  disabled: ariaDisabled ?? props.accessibilityState?.disabled,
161
164
  expanded: ariaExpanded ?? props.accessibilityState?.expanded,
162
165
  selected: ariaSelected ?? props.accessibilityState?.selected,
166
+ readOnly: ariaReadOnly ?? props.accessibilityState?.readOnly, // Windows
167
+ multiselectable:
168
+ ariaMultiselectable ?? props.accessibilityState?.multiselectable, // Windows
169
+ required: ariaRequired ?? props.accessibilityState?.required, // Windows
163
170
  };
164
171
  const accessibilityLabel = props['aria-label'] ?? props.accessibilityLabel;
165
172
 
@@ -46,11 +46,14 @@ const Text: React.AbstractComponent<
46
46
  'aria-checked': ariaChecked,
47
47
  'aria-disabled': ariaDisabled,
48
48
  'aria-expanded': ariaExpanded,
49
+ 'aria-multiselectable': ariaMultiselectable, // Windows
50
+ 'aria-required': ariaRequired, // Windows
49
51
  'aria-label': ariaLabel,
50
52
  'aria-level': ariaLevel, // Windows
51
53
  'aria-posinset': ariaPosinset, // Windows
52
54
  'aria-setsize': ariaSetsize, // Windows
53
55
  'aria-selected': ariaSelected,
56
+ 'aria-readonly': ariaReadOnly, //Windows
54
57
  ellipsizeMode,
55
58
  id,
56
59
  nativeID,
@@ -78,7 +81,10 @@ const Text: React.AbstractComponent<
78
81
  ariaChecked != null ||
79
82
  ariaDisabled != null ||
80
83
  ariaExpanded != null ||
81
- ariaSelected != null
84
+ ariaSelected != null ||
85
+ ariaReadOnly != null || // Windows
86
+ ariaMultiselectable != null || // Windows
87
+ ariaRequired != null // Windows
82
88
  ) {
83
89
  _accessibilityState = {
84
90
  busy: ariaBusy ?? accessibilityState?.busy,
@@ -86,6 +92,10 @@ const Text: React.AbstractComponent<
86
92
  disabled: ariaDisabled ?? accessibilityState?.disabled,
87
93
  expanded: ariaExpanded ?? accessibilityState?.expanded,
88
94
  selected: ariaSelected ?? accessibilityState?.selected,
95
+ readOnly: ariaReadOnly ?? accessibilityState?.readOnly, // Windows
96
+ multiselectable:
97
+ ariaMultiselectable ?? accessibilityState?.multiselectable, // Windows
98
+ required: ariaRequired ?? accessibilityState?.required, // Windows
89
99
  };
90
100
  }
91
101
 
@@ -97,6 +97,9 @@ 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
101
+ 'aria-multiselectable'?: ?boolean, // Windows
102
+ 'aria-required'?: ?boolean, // Windows
100
103
 
101
104
  /**
102
105
  * Represents the nativeID of the associated label text. When the assistive technology focuses on the component with this props, the text is read aloud.
@@ -7,6 +7,7 @@ import "ViewProps.idl";
7
7
  import "Composition.Input.idl";
8
8
  import "CompositionSwitcher.idl";
9
9
  import "IReactContext.idl";
10
+ import "ReactNativeIsland.idl";
10
11
 
11
12
  #include "DocString.h"
12
13
 
@@ -110,8 +111,19 @@ namespace Microsoft.ReactNative.Composition
110
111
  [default_interface]
111
112
  runtimeclass RootComponentView : ViewComponentView {
112
113
  Microsoft.ReactNative.ComponentView GetFocusedComponent();
114
+ Microsoft.ReactNative.ReactNativeIsland ReactNativeIsland { get; };
115
+ DOC_STRING("Is non-null if this RootComponentView is the content of a portal")
116
+ PortalComponentView Portal { get; };
113
117
  };
114
-
118
+
119
+ [experimental]
120
+ [webhosthidden]
121
+ [default_interface]
122
+ DOC_STRING("Used to implement UI that is hosted outside the main UI tree, such as modal.")
123
+ runtimeclass PortalComponentView : Microsoft.ReactNative.ComponentView {
124
+ RootComponentView ContentRoot { get; };
125
+ };
126
+
115
127
  [experimental]
116
128
  [webhosthidden]
117
129
  [default_interface]
@@ -639,11 +639,10 @@ facebook::react::Tag ComponentView::hitTest(
639
639
  }
640
640
 
641
641
  winrt::IInspectable ComponentView::EnsureUiaProvider() noexcept {
642
- assert(false);
643
642
  return nullptr;
644
643
  }
645
644
 
646
- std::optional<std::string> ComponentView::getAcccessiblityValue() noexcept {
645
+ std::optional<std::string> ComponentView::getAccessiblityValue() noexcept {
647
646
  return std::nullopt;
648
647
  }
649
648
 
@@ -207,7 +207,7 @@ struct ComponentView
207
207
  virtual facebook::react::Tag
208
208
  hitTest(facebook::react::Point pt, facebook::react::Point &localPt, bool ignorePointerEvents = false) const noexcept;
209
209
  virtual winrt::IInspectable EnsureUiaProvider() noexcept;
210
- virtual std::optional<std::string> getAcccessiblityValue() noexcept;
210
+ virtual std::optional<std::string> getAccessiblityValue() noexcept;
211
211
  virtual void setAcccessiblityValue(std::string &&value) noexcept;
212
212
  virtual bool getAcccessiblityIsReadOnly() noexcept;
213
213
  virtual ToggleState getToggleState() noexcept;
@@ -15,8 +15,6 @@
15
15
  #include <Fabric/Composition/CompositionViewComponentView.h>
16
16
  #include <Fabric/Composition/DebuggingOverlayComponentView.h>
17
17
  #include <Fabric/Composition/ImageComponentView.h>
18
- #include <Fabric/Composition/Modal/WindowsModalHostViewComponentView.h>
19
- #include <Fabric/Composition/Modal/WindowsModalHostViewShadowNode.h>
20
18
  #include <Fabric/Composition/ParagraphComponentView.h>
21
19
  #include <Fabric/Composition/RootComponentView.h>
22
20
  #include <Fabric/Composition/ScrollViewComponentView.h>
@@ -59,9 +57,6 @@ ComponentViewDescriptor const &ComponentViewRegistry::dequeueComponentViewWithCo
59
57
  } else if (componentHandle == facebook::react::ImageShadowNode::Handle()) {
60
58
  view = winrt::Microsoft::ReactNative::Composition::implementation::ImageComponentView::Create(
61
59
  compContext, tag, m_context);
62
- } else if (componentHandle == facebook::react::WindowsModalHostViewShadowNode::Handle()) {
63
- view = winrt::Microsoft::ReactNative::Composition::implementation::WindowsModalHostComponentView::Create(
64
- compContext, tag, m_context);
65
60
  } else if (componentHandle == facebook::react::WindowsTextInputShadowNode::Handle()) {
66
61
  view = winrt::Microsoft::ReactNative::Composition::implementation::WindowsTextInputComponentView::Create(
67
62
  compContext, tag, m_context);
@@ -11,7 +11,21 @@ namespace winrt::Microsoft::ReactNative::implementation {
11
11
 
12
12
  CompositionDynamicAutomationProvider::CompositionDynamicAutomationProvider(
13
13
  const winrt::Microsoft::ReactNative::Composition::ComponentView &componentView) noexcept
14
- : m_view{componentView} {}
14
+ : m_view{componentView} {
15
+ auto strongView = m_view.view();
16
+
17
+ if (!strongView)
18
+ return;
19
+
20
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
21
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
22
+ if (!props)
23
+ return;
24
+
25
+ if (props->accessibilityState.has_value() && props->accessibilityState->selected.has_value()) {
26
+ AddSelectionItemsToContainer(this);
27
+ }
28
+ }
15
29
 
16
30
  HRESULT __stdcall CompositionDynamicAutomationProvider::Navigate(
17
31
  NavigateDirection direction,
@@ -127,8 +141,12 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::get_ProviderOptions(Prov
127
141
  return S_OK;
128
142
  }
129
143
 
130
- bool accessibilityValueHasValue(const facebook::react::AccessibilityValue &value) {
131
- return (value.min.has_value() && value.max.has_value()) || value.now.has_value() || value.text.has_value();
144
+ bool accessibilityValueHasTextValue(const facebook::react::AccessibilityValue &value) {
145
+ return value.text.has_value();
146
+ }
147
+
148
+ bool accessibilityValueHasNumericValue(const facebook::react::AccessibilityValue &value) {
149
+ return (value.min.has_value() && value.max.has_value() && value.now.has_value());
132
150
  }
133
151
 
134
152
  bool expandableControl(const facebook::react::SharedViewProps props) {
@@ -171,7 +189,6 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE
171
189
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
172
190
  if (props == nullptr)
173
191
  return UIA_E_ELEMENTNOTAVAILABLE;
174
- auto accessibilityRole = props->accessibilityRole;
175
192
  // Invoke control pattern is used to support controls that do not maintain state
176
193
  // when activated but rather initiate or perform a single, unambiguous action.
177
194
  if (patternId == UIA_InvokePatternId && (props->onAccessibilityTap)) {
@@ -185,8 +202,15 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE
185
202
  }
186
203
 
187
204
  if (patternId == UIA_ValuePatternId &&
188
- (strongView.try_as<winrt::Microsoft::ReactNative::Composition::implementation::WindowsTextInputComponentView>() ||
189
- accessibilityValueHasValue(props->accessibilityValue))) {
205
+ ((strongView
206
+ .try_as<winrt::Microsoft::ReactNative::Composition::implementation::WindowsTextInputComponentView>() &&
207
+ !accessibilityValueHasNumericValue(props->accessibilityValue)) ||
208
+ accessibilityValueHasTextValue(props->accessibilityValue))) {
209
+ *pRetVal = static_cast<IValueProvider *>(this);
210
+ AddRef();
211
+ }
212
+
213
+ if (patternId == UIA_RangeValuePatternId && accessibilityValueHasNumericValue(props->accessibilityValue)) {
190
214
  *pRetVal = static_cast<IValueProvider *>(this);
191
215
  AddRef();
192
216
  }
@@ -203,6 +227,18 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE
203
227
  AddRef();
204
228
  }
205
229
 
230
+ if (patternId == UIA_SelectionPatternId && props->accessibilityState.has_value() &&
231
+ props->accessibilityState->multiselectable.has_value() && props->accessibilityState->required.has_value()) {
232
+ *pRetVal = static_cast<ISelectionProvider *>(this);
233
+ AddRef();
234
+ }
235
+
236
+ if (patternId == UIA_SelectionItemPatternId && props->accessibilityState.has_value() &&
237
+ props->accessibilityState->selected.has_value()) {
238
+ *pRetVal = static_cast<ISelectionItemProvider *>(this);
239
+ AddRef();
240
+ }
241
+
206
242
  return S_OK;
207
243
  }
208
244
 
@@ -346,6 +382,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERT
346
382
  case UIA_IsOffscreenPropertyId: {
347
383
  pRetVal->vt = VT_BOOL;
348
384
  pRetVal->boolVal = (compositionView->getClipState() == ClipState::FullyClipped) ? VARIANT_TRUE : VARIANT_FALSE;
385
+ break;
349
386
  }
350
387
  case UIA_HelpTextPropertyId: {
351
388
  pRetVal->vt = VT_BSTR;
@@ -454,6 +491,8 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::SetValue(LPCWSTR val) {
454
491
 
455
492
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)
456
493
  ->setAcccessiblityValue(winrt::to_string(val));
494
+ // TODO: Edit once/if onAccessibilityAction props supports returning UIA event data. See
495
+ // https://github.com/react-native-community/discussions-and-proposals/issues/843.
457
496
  DispatchAccessibilityAction(m_view, "setValue");
458
497
  return S_OK;
459
498
  }
@@ -467,7 +506,7 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::get_Value(BSTR *pRetVal)
467
506
  return UIA_E_ELEMENTNOTAVAILABLE;
468
507
 
469
508
  *pRetVal = StringToBSTR(winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)
470
- ->getAcccessiblityValue()
509
+ ->getAccessiblityValue()
471
510
  .value_or(""));
472
511
  return S_OK;
473
512
  }
@@ -480,8 +519,88 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::get_IsReadOnly(BOOL *pRe
480
519
  if (!strongView)
481
520
  return UIA_E_ELEMENTNOTAVAILABLE;
482
521
 
483
- *pRetVal = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)
484
- ->getAcccessiblityIsReadOnly();
522
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
523
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
524
+ if (props == nullptr)
525
+ return UIA_E_ELEMENTNOTAVAILABLE;
526
+ auto accessibilityRole = props->accessibilityRole;
527
+ if (props->accessibilityState.has_value() && props->accessibilityState->readOnly.has_value()) {
528
+ *pRetVal = props->accessibilityState->readOnly.value();
529
+ } else {
530
+ // Use default IsReadOnly value.
531
+ *pRetVal = false;
532
+ }
533
+ return S_OK;
534
+ }
535
+
536
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_LargeChange(double *pRetVal) {
537
+ // no-op
538
+ return S_OK;
539
+ }
540
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_Maximum(double *pRetVal) {
541
+ if (pRetVal == nullptr)
542
+ return E_POINTER;
543
+ auto strongView = m_view.view();
544
+
545
+ if (!strongView)
546
+ return UIA_E_ELEMENTNOTAVAILABLE;
547
+
548
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
549
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
550
+
551
+ if (props == nullptr)
552
+ return UIA_E_ELEMENTNOTAVAILABLE;
553
+
554
+ *pRetVal = props->accessibilityValue.max.value();
555
+ return S_OK;
556
+ }
557
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_Minimum(double *pRetVal) {
558
+ if (pRetVal == nullptr)
559
+ return E_POINTER;
560
+ auto strongView = m_view.view();
561
+
562
+ if (!strongView)
563
+ return UIA_E_ELEMENTNOTAVAILABLE;
564
+
565
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
566
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
567
+
568
+ if (props == nullptr)
569
+ return UIA_E_ELEMENTNOTAVAILABLE;
570
+
571
+ *pRetVal = props->accessibilityValue.min.value();
572
+ return S_OK;
573
+ }
574
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_SmallChange(double *pRetVal) {
575
+ // no-op
576
+ return S_OK;
577
+ }
578
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_Value(double *pRetVal) {
579
+ if (pRetVal == nullptr)
580
+ return E_POINTER;
581
+ auto strongView = m_view.view();
582
+
583
+ if (!strongView)
584
+ return UIA_E_ELEMENTNOTAVAILABLE;
585
+
586
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
587
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
588
+
589
+ if (props == nullptr)
590
+ return UIA_E_ELEMENTNOTAVAILABLE;
591
+
592
+ *pRetVal = props->accessibilityValue.now.value();
593
+ return S_OK;
594
+ }
595
+ HRESULT __stdcall CompositionDynamicAutomationProvider::SetValue(double val) {
596
+ auto strongView = m_view.view();
597
+
598
+ if (!strongView)
599
+ return UIA_E_ELEMENTNOTAVAILABLE;
600
+
601
+ // TODO: Edit once/if onAccessibilityAction props supports returning UIA event data. See
602
+ // https://github.com/react-native-community/discussions-and-proposals/issues/843.
603
+ DispatchAccessibilityAction(m_view, "setValue");
485
604
  return S_OK;
486
605
  }
487
606
 
@@ -552,4 +671,169 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::Collapse() {
552
671
  return S_OK;
553
672
  }
554
673
 
674
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_CanSelectMultiple(BOOL *pRetVal) {
675
+ if (pRetVal == nullptr)
676
+ return E_POINTER;
677
+ auto strongView = m_view.view();
678
+
679
+ if (!strongView)
680
+ return UIA_E_ELEMENTNOTAVAILABLE;
681
+
682
+ auto props =
683
+ std::static_pointer_cast<const facebook::react::ViewProps>(winrt::get_self<ComponentView>(strongView)->props());
684
+
685
+ if (props == nullptr)
686
+ return UIA_E_ELEMENTNOTAVAILABLE;
687
+
688
+ *pRetVal = (props->accessibilityState.has_value() && props->accessibilityState->multiselectable.has_value())
689
+ ? props->accessibilityState->multiselectable.value()
690
+ : false;
691
+
692
+ return S_OK;
693
+ }
694
+
695
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_IsSelectionRequired(BOOL *pRetVal) {
696
+ if (pRetVal == nullptr)
697
+ return E_POINTER;
698
+ auto strongView = m_view.view();
699
+
700
+ if (!strongView)
701
+ return UIA_E_ELEMENTNOTAVAILABLE;
702
+
703
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
704
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
705
+
706
+ if (props == nullptr)
707
+ return UIA_E_ELEMENTNOTAVAILABLE;
708
+
709
+ *pRetVal = (props->accessibilityState.has_value() && props->accessibilityState->required.has_value())
710
+ ? props->accessibilityState->required.value()
711
+ : false;
712
+
713
+ return S_OK;
714
+ }
715
+
716
+ HRESULT __stdcall CompositionDynamicAutomationProvider::GetSelection(SAFEARRAY **pRetVal) {
717
+ auto strongView = m_view.view();
718
+
719
+ if (!strongView)
720
+ return UIA_E_ELEMENTNOTAVAILABLE;
721
+
722
+ std::vector<int> selectedItems;
723
+ for (size_t i = 0; i < m_selectionItems.size(); i++) {
724
+ auto selectionItem = m_selectionItems.at(i);
725
+ auto provider = selectionItem.as<CompositionDynamicAutomationProvider>();
726
+ BOOL selected;
727
+ auto hr = provider->get_IsSelected(&selected);
728
+ if (hr == S_OK && selected) {
729
+ selectedItems.push_back(int(i));
730
+ }
731
+ }
732
+
733
+ *pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, ULONG(selectedItems.size()));
734
+ if (*pRetVal == nullptr)
735
+ return E_OUTOFMEMORY;
736
+
737
+ for (size_t i = 0; i < selectedItems.size(); i++) {
738
+ auto pos = static_cast<long>(i);
739
+ SafeArrayPutElement(*pRetVal, &pos, m_selectionItems.at(selectedItems.at(i)).get());
740
+ }
741
+ return S_OK;
742
+ }
743
+
744
+ void CompositionDynamicAutomationProvider::AddToSelectionItems(winrt::com_ptr<IRawElementProviderSimple> &item) {
745
+ if (std::find(m_selectionItems.begin(), m_selectionItems.end(), item) != m_selectionItems.end()) {
746
+ return;
747
+ }
748
+ m_selectionItems.push_back(item);
749
+ }
750
+
751
+ void CompositionDynamicAutomationProvider::RemoveFromSelectionItems(winrt::com_ptr<IRawElementProviderSimple> &item) {
752
+ std::erase(m_selectionItems, item);
753
+ }
754
+
755
+ HRESULT __stdcall CompositionDynamicAutomationProvider::AddToSelection() {
756
+ auto strongView = m_view.view();
757
+
758
+ if (!strongView)
759
+ return UIA_E_ELEMENTNOTAVAILABLE;
760
+
761
+ DispatchAccessibilityAction(m_view, "addToSelection");
762
+ return S_OK;
763
+ }
764
+
765
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_IsSelected(BOOL *pRetVal) {
766
+ if (pRetVal == nullptr)
767
+ return E_POINTER;
768
+ auto strongView = m_view.view();
769
+
770
+ if (!strongView)
771
+ return UIA_E_ELEMENTNOTAVAILABLE;
772
+
773
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
774
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(strongView)->props());
775
+
776
+ if (props == nullptr)
777
+ return UIA_E_ELEMENTNOTAVAILABLE;
778
+
779
+ *pRetVal = (props->accessibilityState.has_value() && props->accessibilityState->selected.has_value())
780
+ ? props->accessibilityState->selected.value()
781
+ : false;
782
+
783
+ return S_OK;
784
+ }
785
+
786
+ IRawElementProviderSimple *findSelectionContainer(winrt::Microsoft::ReactNative::ComponentView current) {
787
+ if (!current)
788
+ return nullptr;
789
+
790
+ auto props = std::static_pointer_cast<const facebook::react::ViewProps>(
791
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(current)->props());
792
+ if (props->accessibilityState.has_value() && props->accessibilityState->multiselectable.has_value() &&
793
+ props->accessibilityState->required.has_value()) {
794
+ auto uiaProvider =
795
+ current.as<winrt::Microsoft::ReactNative::Composition::implementation::ComponentView>()->EnsureUiaProvider();
796
+ if (uiaProvider != nullptr) {
797
+ auto spProviderSimple = uiaProvider.try_as<IRawElementProviderSimple>();
798
+ if (spProviderSimple != nullptr) {
799
+ spProviderSimple->AddRef();
800
+ return spProviderSimple.get();
801
+ }
802
+ }
803
+ } else {
804
+ return findSelectionContainer(current.Parent());
805
+ }
806
+ return nullptr;
807
+ }
808
+
809
+ HRESULT __stdcall CompositionDynamicAutomationProvider::get_SelectionContainer(IRawElementProviderSimple **pRetVal) {
810
+ if (pRetVal == nullptr)
811
+ return E_POINTER;
812
+ auto strongView = m_view.view();
813
+
814
+ if (!strongView)
815
+ return UIA_E_ELEMENTNOTAVAILABLE;
816
+
817
+ *pRetVal = findSelectionContainer(strongView.Parent());
818
+ return S_OK;
819
+ }
820
+
821
+ HRESULT __stdcall CompositionDynamicAutomationProvider::RemoveFromSelection() {
822
+ auto strongView = m_view.view();
823
+
824
+ if (!strongView)
825
+ return UIA_E_ELEMENTNOTAVAILABLE;
826
+ DispatchAccessibilityAction(m_view, "removeFromSelection");
827
+ return S_OK;
828
+ }
829
+
830
+ HRESULT __stdcall CompositionDynamicAutomationProvider::Select() {
831
+ auto strongView = m_view.view();
832
+
833
+ if (!strongView)
834
+ return UIA_E_ELEMENTNOTAVAILABLE;
835
+ DispatchAccessibilityAction(m_view, "select");
836
+ return S_OK;
837
+ }
838
+
555
839
  } // namespace winrt::Microsoft::ReactNative::implementation