Skip to content

Commit 7e76849

Browse files
committed
Add HeadingLevel Behaviour for Fabric Arch
1 parent 3ef0d51 commit 7e76849

File tree

6 files changed

+211
-157
lines changed

6 files changed

+211
-157
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "Add UIA HeadingLevel behaviour for Fabric architecture",
4+
"packageName": "react-native-windows",
5+
"email": "kvineeth@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class AccessibilityBaseExample extends React.Component {
2424
style={{width: 50, height: 50, backgroundColor: 'blue'}}
2525
accessible={true}
2626
accessibilityLabel="A blue box"
27+
role="heading"
2728
accessibilityHint="A hint for the blue box."
2829
accessibilityLevel={1}
2930
accessibilityItemType="comment"
@@ -42,6 +43,7 @@ class AccessibilityBaseExample extends React.Component {
4243
style={{width: 50, height: 50, backgroundColor: 'red'}}
4344
accessible={true}
4445
accessibilityLabel="A hint for the red box."
46+
accessibilityRole="header"
4547
accessibilityLevel={2}
4648
testID="accessibility-base-view-2"
4749
/>

packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/RNTesterApp-Fabric.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse(
521521
int positionInSet = 0;
522522
int sizeOfSet = 0;
523523
int level = 0;
524+
int headingLevel = 0;
524525
LiveSetting liveSetting = LiveSetting::Off;
525526
BSTR itemStatus;
526527
BSTR itemType;
@@ -551,6 +552,11 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse(
551552
if (SUCCEEDED(hr) && pTarget6) {
552553
pTarget6->get_CurrentFullDescription(&description);
553554
}
555+
IUIAutomationElement8 *pTarget8;
556+
hr = pTarget->QueryInterface(__uuidof(IUIAutomationElement8), reinterpret_cast<void **>(&pTarget8));
557+
if (SUCCEEDED(hr) && pTarget8) {
558+
pTarget8->get_CurrentHeadingLevel(&headingLevel);
559+
}
554560
result.Insert(L"AutomationId", winrt::Windows::Data::Json::JsonValue::CreateStringValue(automationId));
555561
result.Insert(L"ControlType", winrt::Windows::Data::Json::JsonValue::CreateNumberValue(controlType));
556562
InsertStringValueIfNotEmpty(result, L"HelpText", helpText);
@@ -560,6 +566,7 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse(
560566
L"LocalizedControlType", winrt::Windows::Data::Json::JsonValue::CreateStringValue(localizedControlType));
561567
InsertStringValueIfNotEmpty(result, L"Name", name);
562568
InsertIntValueIfNotDefault(result, L"PositionInSet", positionInSet);
569+
InsertIntValueIfNotDefault(result, L"HeadingLevel", headingLevel, HeadingLevel_None);
563570
InsertIntValueIfNotDefault(result, L"SizeofSet", sizeOfSet);
564571
InsertIntValueIfNotDefault(result, L"Level", level);
565572
InsertLiveSettingValueIfNotDefault(result, L"LiveSetting", liveSetting);

vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp

Lines changed: 5 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -313,161 +313,6 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPatternProvider(PATTE
313313
return S_OK;
314314
}
315315

316-
long GetControlTypeFromString(const std::string &role) noexcept {
317-
if (role == "adjustable") {
318-
return UIA_SliderControlTypeId;
319-
} else if (role == "group" || role == "search" || role == "radiogroup" || role == "timer" || role.empty()) {
320-
return UIA_GroupControlTypeId;
321-
} else if (role == "button" || role == "imagebutton" || role == "switch" || role == "togglebutton") {
322-
return UIA_ButtonControlTypeId;
323-
} else if (role == "checkbox") {
324-
return UIA_CheckBoxControlTypeId;
325-
} else if (role == "combobox") {
326-
return UIA_ComboBoxControlTypeId;
327-
} else if (role == "alert" || role == "header" || role == "summary" || role == "text") {
328-
return UIA_TextControlTypeId;
329-
} else if (role == "image") {
330-
return UIA_ImageControlTypeId;
331-
} else if (role == "keyboardkey") {
332-
return UIA_CustomControlTypeId;
333-
} else if (role == "link") {
334-
return UIA_HyperlinkControlTypeId;
335-
}
336-
// list and listitem were added by RNW to better support UIA Control Types
337-
else if (role == "list") {
338-
return UIA_ListControlTypeId;
339-
} else if (role == "listitem") {
340-
return UIA_ListItemControlTypeId;
341-
} else if (role == "menu") {
342-
return UIA_MenuControlTypeId;
343-
} else if (role == "menubar") {
344-
return UIA_MenuBarControlTypeId;
345-
} else if (role == "menuitem") {
346-
return UIA_MenuItemControlTypeId;
347-
}
348-
// If role is "none", remove the element from the control tree
349-
// and expose it as a plain element would in the raw tree.
350-
else if (role == "none") {
351-
return UIA_GroupControlTypeId;
352-
} else if (role == "progressbar") {
353-
return UIA_ProgressBarControlTypeId;
354-
} else if (role == "radio") {
355-
return UIA_RadioButtonControlTypeId;
356-
} else if (role == "scrollbar") {
357-
return UIA_ScrollBarControlTypeId;
358-
} else if (role == "spinbutton") {
359-
return UIA_SpinnerControlTypeId;
360-
} else if (role == "splitbutton") {
361-
return UIA_SplitButtonControlTypeId;
362-
} else if (role == "tab") {
363-
return UIA_TabItemControlTypeId;
364-
} else if (role == "tablist") {
365-
return UIA_TabControlTypeId;
366-
} else if (role == "textinput" || role == "searchbox") {
367-
return UIA_EditControlTypeId;
368-
} else if (role == "toolbar") {
369-
return UIA_ToolBarControlTypeId;
370-
} else if (role == "tree") {
371-
return UIA_TreeControlTypeId;
372-
} else if (role == "treeitem") {
373-
return UIA_TreeItemControlTypeId;
374-
} else if (role == "pane") {
375-
return UIA_PaneControlTypeId;
376-
}
377-
assert(false);
378-
return UIA_GroupControlTypeId;
379-
}
380-
381-
long GetControlTypeFromRole(const facebook::react::Role &role) noexcept {
382-
switch (role) {
383-
case facebook::react::Role::Alert:
384-
return UIA_TextControlTypeId;
385-
case facebook::react::Role::Application:
386-
return UIA_WindowControlTypeId;
387-
case facebook::react::Role::Button:
388-
return UIA_ButtonControlTypeId;
389-
case facebook::react::Role::Checkbox:
390-
return UIA_CheckBoxControlTypeId;
391-
case facebook::react::Role::Columnheader:
392-
return UIA_HeaderControlTypeId;
393-
case facebook::react::Role::Combobox:
394-
return UIA_ComboBoxControlTypeId;
395-
case facebook::react::Role::Document:
396-
return UIA_DocumentControlTypeId;
397-
case facebook::react::Role::Grid:
398-
return UIA_GroupControlTypeId;
399-
case facebook::react::Role::Group:
400-
return UIA_GroupControlTypeId;
401-
case facebook::react::Role::Heading:
402-
return UIA_TextControlTypeId;
403-
case facebook::react::Role::Img:
404-
return UIA_ImageControlTypeId;
405-
case facebook::react::Role::Link:
406-
return UIA_HyperlinkControlTypeId;
407-
case facebook::react::Role::List:
408-
return UIA_ListControlTypeId;
409-
case facebook::react::Role::Listitem:
410-
return UIA_ListItemControlTypeId;
411-
case facebook::react::Role::Menu:
412-
return UIA_MenuControlTypeId;
413-
case facebook::react::Role::Menubar:
414-
return UIA_MenuBarControlTypeId;
415-
case facebook::react::Role::Menuitem:
416-
return UIA_MenuItemControlTypeId;
417-
case facebook::react::Role::None:
418-
return UIA_GroupControlTypeId;
419-
case facebook::react::Role::Presentation:
420-
return UIA_GroupControlTypeId;
421-
case facebook::react::Role::Progressbar:
422-
return UIA_ProgressBarControlTypeId;
423-
case facebook::react::Role::Radio:
424-
return UIA_RadioButtonControlTypeId;
425-
case facebook::react::Role::Radiogroup:
426-
return UIA_GroupControlTypeId;
427-
case facebook::react::Role::Rowgroup:
428-
return UIA_GroupControlTypeId;
429-
case facebook::react::Role::Rowheader:
430-
return UIA_HeaderControlTypeId;
431-
case facebook::react::Role::Scrollbar:
432-
return UIA_ScrollBarControlTypeId;
433-
case facebook::react::Role::Searchbox:
434-
return UIA_EditControlTypeId;
435-
case facebook::react::Role::Separator:
436-
return UIA_SeparatorControlTypeId;
437-
case facebook::react::Role::Slider:
438-
return UIA_SliderControlTypeId;
439-
case facebook::react::Role::Spinbutton:
440-
return UIA_SpinnerControlTypeId;
441-
case facebook::react::Role::Status:
442-
return UIA_StatusBarControlTypeId;
443-
case facebook::react::Role::Summary:
444-
return UIA_GroupControlTypeId;
445-
case facebook::react::Role::Switch:
446-
return UIA_ButtonControlTypeId;
447-
case facebook::react::Role::Tab:
448-
return UIA_TabItemControlTypeId;
449-
case facebook::react::Role::Table:
450-
return UIA_TableControlTypeId;
451-
case facebook::react::Role::Tablist:
452-
return UIA_TabControlTypeId;
453-
case facebook::react::Role::Tabpanel:
454-
return UIA_TabControlTypeId;
455-
case facebook::react::Role::Timer:
456-
return UIA_ButtonControlTypeId;
457-
case facebook::react::Role::Toolbar:
458-
return UIA_ToolBarControlTypeId;
459-
case facebook::react::Role::Tooltip:
460-
return UIA_ToolTipControlTypeId;
461-
case facebook::react::Role::Tree:
462-
return UIA_TreeControlTypeId;
463-
case facebook::react::Role::Treegrid:
464-
return UIA_TreeControlTypeId;
465-
case facebook::react::Role::Treeitem:
466-
return UIA_TreeItemControlTypeId;
467-
}
468-
return UIA_GroupControlTypeId;
469-
}
470-
471316
HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERTYID propertyId, VARIANT *pRetVal) {
472317
if (pRetVal == nullptr)
473318
return E_POINTER;
@@ -640,6 +485,11 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERT
640485
pRetVal->bstrVal = SysAllocString(desc.c_str());
641486
break;
642487
}
488+
case UIA_HeadingLevelPropertyId: {
489+
pRetVal->vt = VT_I4;
490+
pRetVal->lVal = GetHeadingLevel(props->accessibilityLevel, props->accessibilityRole, props->role);
491+
break;
492+
}
643493
}
644494
return hr;
645495
}

0 commit comments

Comments
 (0)