diff --git a/change/react-native-windows-ed4b1594-95cb-4689-a8de-053a7e2e31dc.json b/change/react-native-windows-ed4b1594-95cb-4689-a8de-053a7e2e31dc.json new file mode 100644 index 00000000000..26539d7ae88 --- /dev/null +++ b/change/react-native-windows-ed4b1594-95cb-4689-a8de-053a7e2e31dc.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Add Support for ControlType Specification", + "packageName": "react-native-windows", + "email": "34109996+chiaramooney@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp index 466a0c4bb0d..52a8a4ed0bd 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp @@ -126,4 +126,8 @@ bool ActivityIndicatorComponentView::focusable() const noexcept { return false; } +std::string ActivityIndicatorComponentView::DefaultControlType() const noexcept { + return "progressbar"; +} + } // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h index 359f214ba8f..ca1afa63e03 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h @@ -40,6 +40,7 @@ struct ActivityIndicatorComponentView : CompositionBaseComponentView { facebook::react::Tag hitTest(facebook::react::Point pt, facebook::react::Point &localPt, bool ignorePointerEvents) const noexcept override; winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept override; + virtual std::string DefaultControlType() const noexcept; private: ActivityIndicatorComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 4975fcfc64f..25de87e540d 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -182,6 +182,8 @@ long GetControlType(const std::string &role) noexcept { return UIA_TabItemControlTypeId; } else if (role == "tablist") { return UIA_TabControlTypeId; + } else if (role == "textinput" || role == "searchbox") { + return UIA_EditControlTypeId; } else if (role == "toolbar") { return UIA_ToolBarControlTypeId; } else if (role == "tree") { @@ -205,12 +207,16 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERT if (props == nullptr) return UIA_E_ELEMENTNOTAVAILABLE; + auto baseView = std::static_pointer_cast<::Microsoft::ReactNative::CompositionBaseComponentView>(strongView); + if (baseView == nullptr) + return UIA_E_ELEMENTNOTAVAILABLE; + auto hr = S_OK; switch (propertyId) { case UIA_ControlTypePropertyId: { pRetVal->vt = VT_I4; - auto role = props->accessibilityRole; + auto role = props->accessibilityRole == "" ? baseView.get()->DefaultControlType() : props->accessibilityRole; pRetVal->lVal = GetControlType(role); break; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index 0a67532ea24..bf2bda3478e 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -1091,6 +1091,9 @@ void CompositionBaseComponentView::updateAccessibilityProps( UIA_IsEnabledPropertyId, !oldViewProps.accessibilityState.disabled, !newViewProps.accessibilityState.disabled); + + winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty( + provider, UIA_ControlTypePropertyId, oldViewProps.accessibilityRole, newViewProps.accessibilityRole); } void CompositionBaseComponentView::updateBorderLayoutMetrics( @@ -1212,6 +1215,10 @@ bool CompositionBaseComponentView::focusable() const noexcept { return false; } +std::string CompositionBaseComponentView::DefaultControlType() const noexcept { + return "group"; +} + CompositionViewComponentView::CompositionViewComponentView( const winrt::Microsoft::ReactNative::Composition::ICompositionContext &compContext, facebook::react::Tag tag) @@ -1413,6 +1420,10 @@ bool CompositionViewComponentView::focusable() const noexcept { return m_props->focusable; } +std::string CompositionViewComponentView::DefaultControlType() const noexcept { + return "group"; +} + IComponentView *lastDeepChild(IComponentView &view) noexcept { auto current = &view; while (current) { diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h index c47e704940f..9c9db7c33a7 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h @@ -66,6 +66,8 @@ struct CompositionBaseComponentView : public IComponentView, winrt::IInspectable EnsureUiaProvider() noexcept override; + virtual std::string DefaultControlType() const noexcept; + protected: std::array FindSpecialBorderLayers() const noexcept; @@ -116,6 +118,7 @@ struct CompositionViewComponentView : public CompositionBaseComponentView { void finalizeUpdates(RNComponentViewUpdateMask updateMask) noexcept override; void prepareForRecycle() noexcept override; bool focusable() const noexcept override; + std::string DefaultControlType() const noexcept override; facebook::react::Props::Shared props() noexcept override; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp index 4f73b625964..9ba850d67aa 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp @@ -409,6 +409,10 @@ bool ImageComponentView::focusable() const noexcept { return m_props->focusable; } +std::string ImageComponentView::DefaultControlType() const noexcept { + return "image"; +} + std::shared_ptr ImageComponentView::Create( const winrt::Microsoft::ReactNative::Composition::ICompositionContext &compContext, facebook::react::Tag tag, diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h index ab80d091e9f..041bbf54bba 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h @@ -53,6 +53,7 @@ struct ImageComponentView : CompositionBaseComponentView { const noexcept override; winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept override; bool focusable() const noexcept override; + virtual std::string DefaultControlType() const noexcept; private: ImageComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp index f6b20b95df3..cca1f273352 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp @@ -474,6 +474,10 @@ void ParagraphComponentView::DrawText() noexcept { } } +std::string ParagraphComponentView::DefaultControlType() const noexcept { + return "text"; +} + winrt::Microsoft::ReactNative::Composition::IVisual ParagraphComponentView::Visual() const noexcept { return m_visual; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h index 530785676f1..10fb1b7765b 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h @@ -42,6 +42,7 @@ struct ParagraphComponentView : CompositionBaseComponentView { facebook::react::SharedTouchEventEmitter touchEventEmitterAtPoint(facebook::react::Point pt) noexcept override; winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept override; + virtual std::string DefaultControlType() const noexcept; private: ParagraphComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp index 93c47aa8f48..3d7ceab58e4 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp @@ -460,4 +460,8 @@ winrt::Microsoft::ReactNative::Composition::IVisual ScrollViewComponentView::Vis return m_visual; } +std::string ScrollViewComponentView::DefaultControlType() const noexcept { + return "scrollbar"; +} + } // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h index 343e5152f30..c6e53f0d93d 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h @@ -79,6 +79,7 @@ struct ScrollInteractionTrackerOwner : public winrt::implements< bool ScrollWheel(facebook::react::Point pt, int32_t delta) noexcept override; void StartBringIntoView(BringIntoViewOptions &&args) noexcept override; + virtual std::string DefaultControlType() const noexcept; private: ScrollViewComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp index fc10b0bc5ad..05642ac0a26 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp @@ -266,4 +266,8 @@ bool SwitchComponentView::focusable() const noexcept { return m_props->focusable; } +std::string SwitchComponentView::DefaultControlType() const noexcept { + return "switch"; +} + } // namespace Microsoft::ReactNative diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h index 46f53e28301..545fc09d112 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h @@ -42,6 +42,7 @@ struct SwitchComponentView : CompositionBaseComponentView { const noexcept override; winrt::Microsoft::ReactNative::Composition::IVisual Visual() const noexcept override; int64_t sendMessage(uint32_t msg, uint64_t wParam, int64_t lParam) noexcept override; + std::string DefaultControlType() const noexcept override; private: SwitchComponentView( diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp index 81b16f77204..e7189a12d17 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp @@ -594,6 +594,10 @@ bool WindowsTextInputComponentView::focusable() const noexcept { return m_props->focusable; } +std::string WindowsTextInputComponentView::DefaultControlType() const noexcept { + return "textinput"; +} + void WindowsTextInputComponentView::updateProps( facebook::react::Props::Shared const &props, facebook::react::Props::Shared const &oldProps) noexcept { diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h index 4e949bc1298..56a86ab26ad 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h @@ -52,6 +52,7 @@ struct WindowsTextInputComponentView : CompositionBaseComponentView { void onFocusLost() noexcept override; void onFocusGained() noexcept override; bool focusable() const noexcept override; + std::string DefaultControlType() const noexcept override; private: WindowsTextInputComponentView(