diff --git a/change/react-native-windows-03455d8f-7438-42c3-961f-8250bdfda7ae.json b/change/react-native-windows-03455d8f-7438-42c3-961f-8250bdfda7ae.json new file mode 100644 index 00000000000..23427d6d5fb --- /dev/null +++ b/change/react-native-windows-03455d8f-7438-42c3-961f-8250bdfda7ae.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "[Fabric] Implementation of accessibilityItemType", + "packageName": "react-native-windows", + "email": "kvineeth@microsoft.com", + "dependentChangeType": "patch" +} \ No newline at end of file diff --git a/change/react-native-windows-85efbfed-f980-402a-b3de-a9d07b97923f.json b/change/react-native-windows-85efbfed-f980-402a-b3de-a9d07b97923f.json new file mode 100644 index 00000000000..845e2b94d9d --- /dev/null +++ b/change/react-native-windows-85efbfed-f980-402a-b3de-a9d07b97923f.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "[Fabric] Implementation of accessibilityAccessKey", + "packageName": "react-native-windows", + "email": "kvineeth@microsoft.com", + "dependentChangeType": "patch" +} \ No newline at end of file diff --git a/packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx b/packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx index 03c92ed96a9..5a35062ffec 100644 --- a/packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx +++ b/packages/@react-native-windows/tester/src/js/examples-win/Accessibility/AccessibilityExampleWindows.tsx @@ -26,6 +26,8 @@ class AccessibilityBaseExample extends React.Component { accessibilityLabel="A blue box" accessibilityHint="A hint for the blue box." accessibilityLevel={1} + accessibilityItemType="comment" + accessibilityAccessKey="accessKey" accessibilityAnnotation={{ typeID: 'Comment', typeName: 'Check Comment', diff --git a/packages/e2e-test-app-fabric/test/__snapshots__/AccessibilityTest.test.ts.snap b/packages/e2e-test-app-fabric/test/__snapshots__/AccessibilityTest.test.ts.snap index 3dca071b3ab..000d77c4e41 100644 --- a/packages/e2e-test-app-fabric/test/__snapshots__/AccessibilityTest.test.ts.snap +++ b/packages/e2e-test-app-fabric/test/__snapshots__/AccessibilityTest.test.ts.snap @@ -32,6 +32,7 @@ exports[`Accessibility Tests Accessibility data for Label and Level 1`] = ` exports[`Accessibility Tests Accessibility data for Label,Level and Hint 1`] = ` { "Automation Tree": { + "AccessKey": "accessKey", "AnnotationPattern.Author": "Clint Westwood", "AnnotationPattern.DateTime": "3/19/2025 1:03 PM", "AnnotationPattern.TypeId": 60003, @@ -39,6 +40,7 @@ exports[`Accessibility Tests Accessibility data for Label,Level and Hint 1`] = ` "AutomationId": "accessibility-base-view-1", "ControlType": 50026, "HelpText": "A hint for the blue box.", + "ItemType": "comment", "Level": 1, "LocalizedControlType": "group", "Name": "A blue box", diff --git a/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap b/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap index 4b21ff071e6..b697369849f 100644 --- a/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap +++ b/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap @@ -8,6 +8,7 @@ exports[`snapshotAllPages Accessibility Windows 1`] = ` The following has accessibilityLabel and accessibilityHint: get_CurrentAutomationId(&automationId); pTarget->get_CurrentControlType(&controlType); @@ -532,6 +534,8 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse( pTarget->get_CurrentLocalizedControlType(&localizedControlType); pTarget->get_CurrentName(&name); pTarget->get_CurrentItemStatus(&itemStatus); + pTarget->get_CurrentItemType(&itemType); + pTarget->get_CurrentAccessKey(&accessKey); IUIAutomationElement4 *pTarget4; HRESULT hr = pTarget->QueryInterface(__uuidof(IUIAutomationElement4), reinterpret_cast(&pTarget4)); if (SUCCEEDED(hr) && pTarget4) { @@ -554,6 +558,8 @@ winrt::Windows::Data::Json::JsonObject DumpUIATreeRecurse( InsertIntValueIfNotDefault(result, L"Level", level); InsertLiveSettingValueIfNotDefault(result, L"LiveSetting", liveSetting); InsertStringValueIfNotEmpty(result, L"ItemStatus", itemStatus); + InsertStringValueIfNotEmpty(result, L"ItemType", itemType); + InsertStringValueIfNotEmpty(result, L"AccessKey", accessKey); DumpUIAPatternInfo(pTarget, result); IUIAutomationElement *pChild; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp index 366fe8f1533..b40c83eabe7 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp @@ -576,8 +576,19 @@ HRESULT __stdcall CompositionDynamicAutomationProvider::GetPropertyValue(PROPERT pRetVal->lVal = props->accessibilityLevel; break; } + case UIA_AccessKeyPropertyId: { + pRetVal->vt = VT_BSTR; + auto accessKey = ::Microsoft::Common::Unicode::Utf8ToUtf16(props->accessibilityAccessKey.value_or("")); + pRetVal->bstrVal = SysAllocString(accessKey.c_str()); + break; + } + case UIA_ItemTypePropertyId: { + pRetVal->vt = VT_BSTR; + auto itemtype = ::Microsoft::Common::Unicode::Utf8ToUtf16(props->accessibilityItemType.value_or("")); + pRetVal->bstrVal = SysAllocString(itemtype.c_str()); + break; + } } - return hr; } diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp index c23df8a9d06..f23ddcda0ff 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp @@ -807,6 +807,18 @@ void ComponentView::updateAccessibilityProps( winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty( EnsureUiaProvider(), UIA_LevelPropertyId, oldViewProps.accessibilityLevel, newViewProps.accessibilityLevel); + winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty( + EnsureUiaProvider(), + UIA_AccessKeyPropertyId, + oldViewProps.accessibilityAccessKey, + newViewProps.accessibilityAccessKey); + + winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty( + EnsureUiaProvider(), + UIA_ItemTypePropertyId, + oldViewProps.accessibilityItemType, + newViewProps.accessibilityItemType); + if ((oldViewProps.accessibilityState.has_value() && oldViewProps.accessibilityState->selected.has_value()) != ((newViewProps.accessibilityState.has_value() && newViewProps.accessibilityState->selected.has_value()))) { auto compProvider = diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp index 2a934615477..4d2ff6ae8a0 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp @@ -180,6 +180,16 @@ void UpdateUiaProperty( spProviderSimple.get(), propId, CComVariant(oldValue.c_str()), CComVariant(newValue.c_str())); } +void UpdateUiaProperty( + winrt::IInspectable provider, + PROPERTYID propId, + const std::optional &oldValue, + const std::optional &newValue) noexcept { + std::string oldData = oldValue.value_or(""); + std::string newData = newValue.value_or(""); + UpdateUiaProperty(provider, propId, oldData, newData); +} + long GetLiveSetting(const std::string &liveRegion) noexcept { if (liveRegion == "polite") { return LiveSetting::Polite; diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h b/vnext/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h index ee20324cfa1..19a90431330 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h @@ -31,6 +31,12 @@ void UpdateUiaProperty( const std::string &oldValue, const std::string &newValue) noexcept; +void UpdateUiaProperty( + winrt::IInspectable provider, + PROPERTYID propId, + const std::optional &oldValue, + const std::optional &newValue) noexcept; + long GetLiveSetting(const std::string &liveRegion) noexcept; long GetAnnotationTypeId(const std::string &annotationType) noexcept; diff --git a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp index bd9716c9f11..00b3a0afb17 100644 --- a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp @@ -48,6 +48,14 @@ HostPlatformViewProps::HostPlatformViewProps( ReactNativeFeatureFlags::enableCppPropsIteratorSetter() ? sourceProps.accessibilityLevel : convertRawProp(context, rawProps, "accessibilityLevel", sourceProps.accessibilityLevel, 0)), + accessibilityItemType( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.accessibilityItemType + : convertRawProp(context, rawProps, "accessibilityItemType", sourceProps.accessibilityItemType, {})), + accessibilityAccessKey( + ReactNativeFeatureFlags::enableCppPropsIteratorSetter() + ? sourceProps.accessibilityAccessKey + : convertRawProp(context, rawProps, "accessibilityAccessKey", sourceProps.accessibilityAccessKey, {})), accessibilityLiveRegion( ReactNativeFeatureFlags::enableCppPropsIteratorSetter() ? sourceProps.accessibilityLiveRegion : convertRawProp( @@ -94,6 +102,8 @@ void HostPlatformViewProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityPosInSet); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilitySetSize); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLevel); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityItemType); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityAccessKey); RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLiveRegion); RAW_SET_PROP_SWITCH_CASE_BASIC(keyDownEvents); RAW_SET_PROP_SWITCH_CASE_BASIC(keyUpEvents); diff --git a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h index 488c4a3c3d2..e1afe3f9683 100644 --- a/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +++ b/vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h @@ -30,6 +30,8 @@ class HostPlatformViewProps : public BaseViewProps { std::string accessibilityLiveRegion{"none"}; int accessibilityLevel{0}; std::optional accessibilityAnnotation{}; + std::optional accessibilityItemType{}; + std::optional accessibilityAccessKey{}; // std::optional overflowAnchor{}; std::optional tooltip{}; diff --git a/vnext/src-win/Libraries/Components/View/ViewAccessibility.d.ts b/vnext/src-win/Libraries/Components/View/ViewAccessibility.d.ts index ef1e52cced2..14d93975846 100644 --- a/vnext/src-win/Libraries/Components/View/ViewAccessibility.d.ts +++ b/vnext/src-win/Libraries/Components/View/ViewAccessibility.d.ts @@ -303,6 +303,18 @@ export interface AccessibilityPropsWindows { * Note: If typeID is 'Unknown', a typeName must be provided. */ accessibilityAnnotation?: AccessibilityAnnotationInfo; //Windows + + /** + * Identifies the ItemType property, which is a text string describing the type of the automation element. + * ItemType is used to obtain information about items in a list, tree view, or data grid. For example, an item in a file directory view might be a "Document File" or a "Folder". + */ + accessibilityItemType?: string; //Windows + + /** + * An access key to hook up to the UIA_AccessKey_Property. + * Access keys are used in keyboard navigation to allow quick navigation to UI in an application. + */ + accessibilityAccessKey?: string; //Windows } export interface AccessibilityPropsAndroid { diff --git a/vnext/src-win/Libraries/NativeComponent/BaseViewConfig.windows.js b/vnext/src-win/Libraries/NativeComponent/BaseViewConfig.windows.js index cfe551535f7..4e77ba1c7a0 100644 --- a/vnext/src-win/Libraries/NativeComponent/BaseViewConfig.windows.js +++ b/vnext/src-win/Libraries/NativeComponent/BaseViewConfig.windows.js @@ -372,6 +372,8 @@ const validAttributesForNonEventProps = { accessibilityPosInSet: true, // [Windows] accessibilitySetSize: true, // [Windows] accessibilityAnnotation: true, // [Windows] + accessibilityItemType: true, // [Windows] + accessibilityAccessKey: true, // [Windows] disabled: true, // [Windows] focusable: true, // [Windows] keyDownEvents: true, // [Windows]