New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds ARIA role support to Paper UIManager #12792
Changes from 4 commits
80e6c96
ddb4eac
a762efe
47ed254
e8226ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"type": "prerelease", | ||
"comment": "Adds ARIA role support to Paper UIManager", | ||
"packageName": "react-native-windows", | ||
"email": "erozell@outlook.com", | ||
"dependentChangeType": "patch" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,164 @@ winrt::hstring DynamicAutomationPeer::GetNameCore() const { | |
} | ||
|
||
winrt::AutomationControlType DynamicAutomationPeer::GetAutomationControlTypeCore() const { | ||
const auto automationControlType = GetAutomationControlTypeFromAriaRole(); | ||
return automationControlType ? automationControlType.value() : GetAutomationControlTypeFromAccessibilityRole(); | ||
} | ||
|
||
std::optional<winrt::AutomationControlType> DynamicAutomationPeer::GetAutomationControlTypeFromAriaRole() const { | ||
const auto ariaRole = GetAriaRole(); | ||
// Unless otherwise specified, mappings sourced from: | ||
// https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-ariaspecification#w3c-aria-role-mapped-to-microsoft-active-accessibility-and-ui-automation | ||
// Remaining mappings are: | ||
// "cell": DataItem (based on "gridcell" mapping) | ||
// "feed": List (based on "directory" mapping) | ||
// "figure": Image (based on "img" mapping) | ||
// "math": Group (based on "definition" mapping) | ||
// "meter": Pane (based on "timer" mapping) | ||
// "none": Group (based on "presentation") | ||
// "rowgroup": Group (based on "group" mapping) | ||
// "searchbox": Group (based on "group" mapping) | ||
// "summary": N/A (based on missing ARIA documentation) | ||
// "switch": CheckBox (based on "checkbox" mapping) | ||
// "table": Grid (based on "grid" mapping) | ||
// "term": Group (based on "definition" mapping) | ||
switch (ariaRole) { | ||
case winrt::Microsoft::ReactNative::AriaRole::Alert: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this implementation persists the problem I described in #11432 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My preference would be to fix Alert and RadioGroup to use the correct core-aam mapping, at the very least in this new 'role' prop if we can't fix accessibilityRole for backward compatibility reasons. I'd like the new ARIA inspired prop to be more rigorous in it's implementation of the aria spec. |
||
return winrt::AutomationControlType::Text; | ||
case winrt::Microsoft::ReactNative::AriaRole::AlertDialog: | ||
return winrt::AutomationControlType::Pane; | ||
case winrt::Microsoft::ReactNative::AriaRole::Application: | ||
return winrt::AutomationControlType::Pane; | ||
case winrt::Microsoft::ReactNative::AriaRole::Article: | ||
return winrt::AutomationControlType::Document; | ||
case winrt::Microsoft::ReactNative::AriaRole::Banner: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Button: | ||
return winrt::AutomationControlType::Button; | ||
case winrt::Microsoft::ReactNative::AriaRole::Cell: | ||
return winrt::AutomationControlType::DataItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::CheckBox: | ||
return winrt::AutomationControlType::CheckBox; | ||
case winrt::Microsoft::ReactNative::AriaRole::ColumnHeader: | ||
return winrt::AutomationControlType::DataItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::ComboBox: | ||
return winrt::AutomationControlType::ComboBox; | ||
case winrt::Microsoft::ReactNative::AriaRole::Complementary: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::ContentInfo: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Definition: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Dialog: | ||
return winrt::AutomationControlType::Pane; | ||
case winrt::Microsoft::ReactNative::AriaRole::Directory: | ||
return winrt::AutomationControlType::List; | ||
case winrt::Microsoft::ReactNative::AriaRole::Document: | ||
return winrt::AutomationControlType::Document; | ||
case winrt::Microsoft::ReactNative::AriaRole::Feed: | ||
return winrt::AutomationControlType::List; | ||
case winrt::Microsoft::ReactNative::AriaRole::Figure: | ||
return winrt::AutomationControlType::Image; | ||
case winrt::Microsoft::ReactNative::AriaRole::Form: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Grid: | ||
return winrt::AutomationControlType::DataGrid; | ||
case winrt::Microsoft::ReactNative::AriaRole::Group: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Heading: | ||
return winrt::AutomationControlType::Text; | ||
case winrt::Microsoft::ReactNative::AriaRole::Img: | ||
return winrt::AutomationControlType::Image; | ||
case winrt::Microsoft::ReactNative::AriaRole::Link: | ||
return winrt::AutomationControlType::Hyperlink; | ||
case winrt::Microsoft::ReactNative::AriaRole::List: | ||
return winrt::AutomationControlType::List; | ||
case winrt::Microsoft::ReactNative::AriaRole::ListItem: | ||
return winrt::AutomationControlType::ListItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::Log: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Main: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Marquee: | ||
return winrt::AutomationControlType::Text; | ||
case winrt::Microsoft::ReactNative::AriaRole::Math: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Menu: | ||
return winrt::AutomationControlType::Menu; | ||
case winrt::Microsoft::ReactNative::AriaRole::MenuBar: | ||
return winrt::AutomationControlType::MenuBar; | ||
case winrt::Microsoft::ReactNative::AriaRole::MenuItem: | ||
return winrt::AutomationControlType::MenuItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::Meter: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Navigation: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::None: | ||
return winrt::AutomationControlType::Pane; | ||
case winrt::Microsoft::ReactNative::AriaRole::Note: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Option: | ||
return winrt::AutomationControlType::ListItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::Presentation: | ||
return winrt::AutomationControlType::Pane; | ||
case winrt::Microsoft::ReactNative::AriaRole::ProgressBar: | ||
return winrt::AutomationControlType::ProgressBar; | ||
case winrt::Microsoft::ReactNative::AriaRole::Radio: | ||
return winrt::AutomationControlType::RadioButton; | ||
case winrt::Microsoft::ReactNative::AriaRole::RadioGroup: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Region: | ||
return winrt::AutomationControlType::Pane; | ||
case winrt::Microsoft::ReactNative::AriaRole::Row: | ||
return winrt::AutomationControlType::DataItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::RowGroup: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::RowHeader: | ||
return winrt::AutomationControlType::DataItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::ScrollBar: | ||
return winrt::AutomationControlType::ScrollBar; | ||
case winrt::Microsoft::ReactNative::AriaRole::SearchBox: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Separator: | ||
return winrt::AutomationControlType::Separator; | ||
case winrt::Microsoft::ReactNative::AriaRole::Slider: | ||
return winrt::AutomationControlType::Slider; | ||
case winrt::Microsoft::ReactNative::AriaRole::SpinButton: | ||
return winrt::AutomationControlType::Spinner; | ||
case winrt::Microsoft::ReactNative::AriaRole::Status: | ||
return winrt::AutomationControlType::StatusBar; | ||
case winrt::Microsoft::ReactNative::AriaRole::Switch: | ||
return winrt::AutomationControlType::CheckBox; | ||
case winrt::Microsoft::ReactNative::AriaRole::Tab: | ||
return winrt::AutomationControlType::TabItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::Table: | ||
return winrt::AutomationControlType::DataGrid; | ||
case winrt::Microsoft::ReactNative::AriaRole::TabList: | ||
return winrt::AutomationControlType::Tab; | ||
case winrt::Microsoft::ReactNative::AriaRole::TabPanel: | ||
return winrt::AutomationControlType::Pane; | ||
case winrt::Microsoft::ReactNative::AriaRole::Term: | ||
return winrt::AutomationControlType::Group; | ||
case winrt::Microsoft::ReactNative::AriaRole::Timer: | ||
return winrt::AutomationControlType::Pane; | ||
case winrt::Microsoft::ReactNative::AriaRole::ToolBar: | ||
return winrt::AutomationControlType::ToolBar; | ||
case winrt::Microsoft::ReactNative::AriaRole::ToolTip: | ||
return winrt::AutomationControlType::ToolTip; | ||
case winrt::Microsoft::ReactNative::AriaRole::Tree: | ||
return winrt::AutomationControlType::Tree; | ||
case winrt::Microsoft::ReactNative::AriaRole::TreeGrid: | ||
return winrt::AutomationControlType::DataGrid; | ||
case winrt::Microsoft::ReactNative::AriaRole::TreeItem: | ||
return winrt::AutomationControlType::TreeItem; | ||
case winrt::Microsoft::ReactNative::AriaRole::Summary: | ||
case winrt::Microsoft::ReactNative::AriaRole::Unknown: | ||
default: | ||
return std::nullopt; | ||
} | ||
} | ||
|
||
winrt::AutomationControlType DynamicAutomationPeer::GetAutomationControlTypeFromAccessibilityRole() const { | ||
auto accessibilityRole = GetAccessibilityRole(); | ||
|
||
switch (accessibilityRole) { | ||
|
@@ -342,6 +500,15 @@ winrt::Microsoft::ReactNative::AccessibilityRoles DynamicAutomationPeer::GetAcce | |
return winrt::Microsoft::ReactNative::AccessibilityRoles::None; | ||
} | ||
|
||
winrt::Microsoft::ReactNative::AriaRole DynamicAutomationPeer::GetAriaRole() const { | ||
try { | ||
return DynamicAutomationProperties::GetAriaRole(Owner()); | ||
} catch (...) { | ||
} | ||
|
||
return winrt::Microsoft::ReactNative::AriaRole::Unknown; | ||
} | ||
|
||
bool DynamicAutomationPeer::HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates state) const { | ||
try { | ||
auto const &owner = Owner(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably worth using the ARIA Core Accessibility API Mapping as a reference since that's the source of truth for how ARIA should map to each platform's native a11y API in browsers. It should agree with the MSDN page and gives mappings for some of the ones you're missing here (for example, I noticed it says feed, figure should map to group, but I would check the other roles, too)