[0.73] Add support for announceForAccessibilityWithOptions (#13230)

* [Win32] Add support for announceForAccessibilityWithOptions  (#12237)

* initial commit

* add NativeAccessibilityInfoWin32.js

* update example

* Change files

* add override and .d.ts file

* add another override

* add comma

* extend options type instead of redefine

* try [prop-missing] to fix lint error

* fix comment in RNTesterList.win32

* try ignoring AccessibilityInfo.js in .flowconfig

* Revert flowconfig version

* Lint script runs succesfully locally

---------

Co-authored-by: Krystal Kramer <krsiler@microsoft.com>

* update change type to patch

---------

Co-authored-by: Lawrence Win <dehunter456@gmail.com>
This commit is contained in:
Krystal Kramer 2024-05-14 12:46:52 -04:00 коммит произвёл GitHub
Родитель eb65816d4d
Коммит 239531987a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
8 изменённых файлов: 293 добавлений и 16 удалений

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "add support for announceForAccessibilityWithOptions",
"packageName": "@office-iss/react-native-win32",
"email": "krsiler@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -474,10 +474,27 @@ const AccessibilityInfoExample: React.FunctionComponent<{}> =() => {
const onClick = React.useCallback(() => {
AccessibilityInfo.announceForAccessibility('AccessibilityInfo announcement succeeded!');
}, []);
const onClickDelayed = React.useCallback(() => {
setTimeout(() => {
AccessibilityInfo.announceForAccessibilityWithOptions(
'AccessibilityInfo announcement succeeded!',
{ nativeID: 'AnnouncementTarget' });
}, 3000);
}, []);
return (
<View style={styles.box}>
<TouchableHighlight onPress={onClick}>
<Text>AccessibilityInfo.announceForAccessibility</Text>
<View>
<TouchableHighlight onPress={onClick} underlayColor={'transparent'}>
<ViewWin32 style={styles.box} accessible focusable>
<Text>AccessibilityInfo.announceForAccessibility</Text>
</ViewWin32>
</TouchableHighlight>
<TouchableHighlight onPress={onClickDelayed} underlayColor={'transparent'}>
<ViewWin32 style={styles.box} accessible focusable nativeID={'AnnouncementTarget'}>
<Text>AccessibilityInfo.announceForAccessibilityWithOptions</Text>
</ViewWin32>
</TouchableHighlight>
</View>
);

Просмотреть файл

@ -19,9 +19,11 @@ const Components: Array<RNTesterModuleInfo> = [
key: 'DrawerLayoutAndroid',
category: 'UI',
module: require('../examples/DrawerLayoutAndroid/DrawerLayoutAndroidExample'),
},*/
{
key: 'AccessibilityExampleWin32',
module: require('../examples-win32/Accessibility/AccessibilityExampleWin32'),
},*/
},
{
key: 'ActivityIndicatorExample',
category: 'UI',

Просмотреть файл

@ -10,6 +10,7 @@
; initRNLibraries build step
<PROJECT_ROOT>/index.js
<PROJECT_ROOT>/Libraries/Alert/Alert.js
<PROJECT_ROOT>/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js
<PROJECT_ROOT>/Libraries/Components/Button.js
<PROJECT_ROOT>/Libraries/Components/Pressable/Pressable.js
<PROJECT_ROOT>/Libraries/Components/SafeAreaView/SafeAreaView.js

Просмотреть файл

@ -39,11 +39,16 @@
"issue": 11041
},
{
"type": "patch",
"type": "derived",
"file": "src/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts",
"baseFile": "packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts",
"baseHash": "f55fda723b8dc0f9836f2fa4a4a766ed45c71c00"
},
{
"type": "derived",
"file": "src/Libraries/Components/AccessibilityInfo/AccessibilityInfo.win32.js",
"baseFile": "packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js",
"baseHash": "163927cc271b53109f06eaf5fc6d30a9af8cb27e",
"issue": 4578
"baseHash": "163927cc271b53109f06eaf5fc6d30a9af8cb27e"
},
{
"type": "copy",
@ -52,6 +57,12 @@
"baseHash": "d37b2f72125246ababf3260e99ef790ce76fe3bb",
"issue": 4578
},
{
"type": "derived",
"file": "src/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfoWin32.js",
"baseFile": "packages/react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js",
"baseHash": "9427a7feebfbe3de606b2d100439cabf2faa8661"
},
{
"type": "derived",
"file": "src/Libraries/Components/Button.win32.js",

Просмотреть файл

@ -0,0 +1,161 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import type * as React from 'react';
import {HostComponent} from '../../../types/public/ReactNativeTypes';
import {EmitterSubscription} from '../../vendor/emitter/EventEmitter';
type AccessibilityChangeEventName =
| 'change' // deprecated, maps to screenReaderChanged
| 'boldTextChanged' // iOS-only Event
| 'grayscaleChanged' // iOS-only Event
| 'invertColorsChanged' // iOS-only Event
| 'reduceMotionChanged'
| 'screenReaderChanged'
| 'reduceTransparencyChanged'; // iOS-only Event
type AccessibilityChangeEvent = boolean;
type AccessibilityChangeEventHandler = (
event: AccessibilityChangeEvent,
) => void;
type AccessibilityAnnouncementEventName = 'announcementFinished'; // iOS-only Event
type AccessibilityAnnouncementFinishedEvent = {
announcement: string;
success: boolean;
};
type AccessibilityAnnouncementFinishedEventHandler = (
event: AccessibilityAnnouncementFinishedEvent,
) => void;
type AccessibilityEventTypes = 'click' | 'focus' | 'viewHoverEnter';
/**
* @see https://reactnative.dev/docs/accessibilityinfo
*/
export interface AccessibilityInfoStatic {
/**
* Query whether bold text is currently enabled.
*
* @platform ios
*/
isBoldTextEnabled: () => Promise<boolean>;
/**
* Query whether grayscale is currently enabled.
*
* @platform ios
*/
isGrayscaleEnabled: () => Promise<boolean>;
/**
* Query whether invert colors is currently enabled.
*
* @platform ios
*/
isInvertColorsEnabled: () => Promise<boolean>;
/**
* Query whether reduce motion is currently enabled.
*/
isReduceMotionEnabled: () => Promise<boolean>;
/**
* Query whether reduce motion and prefer cross-fade transitions settings are currently enabled.
*
* Returns a promise which resolves to a boolean.
* The result is `true` when prefer cross-fade transitions is enabled and `false` otherwise.
*/
prefersCrossFadeTransitions(): Promise<boolean>;
/**
* Query whether reduce transparency is currently enabled.
*
* @platform ios
*/
isReduceTransparencyEnabled: () => Promise<boolean>;
/**
* Query whether a screen reader is currently enabled.
*/
isScreenReaderEnabled: () => Promise<boolean>;
/**
* Query whether Accessibility Service is currently enabled.
*
* Returns a promise which resolves to a boolean.
* The result is `true` when any service is enabled and `false` otherwise.
*
* @platform android
*/
isAccessibilityServiceEnabled(): Promise<boolean>;
/**
* Add an event handler. Supported events:
* - announcementFinished: iOS-only event. Fires when the screen reader has finished making an announcement.
* The argument to the event handler is a dictionary with these keys:
* - announcement: The string announced by the screen reader.
* - success: A boolean indicating whether the announcement was successfully made.
* - AccessibilityEventName constants other than announcementFinished: Fires on accessibility feature change.
* The argument to the event handler is a boolean.
* The boolean is true when the related event's feature is enabled and false otherwise.
*
*/
addEventListener(
eventName: AccessibilityChangeEventName,
handler: AccessibilityChangeEventHandler,
): EmitterSubscription;
addEventListener(
eventName: AccessibilityAnnouncementEventName,
handler: AccessibilityAnnouncementFinishedEventHandler,
): EmitterSubscription;
/**
* Set accessibility focus to a react component.
*/
setAccessibilityFocus: (reactTag: number) => void;
/**
* Post a string to be announced by the screen reader.
*/
announceForAccessibility: (announcement: string) => void;
/**
* Post a string to be announced by the screen reader.
* - `announcement`: The string announced by the screen reader.
* - `options`: An object that configures the reading options.
* - `queue`: The announcement will be queued behind existing announcements. iOS only.
* - `nativeID`: The nativeID of the element to send the announcement from. win32 only.
*/
announceForAccessibilityWithOptions(
announcement: string,
options: {
queue?: boolean | undefined;
nativeID?: string | undefined; // win32
},
): void;
/**
* Gets the timeout in millisecond that the user needs.
* This value is set in "Time to take action (Accessibility timeout)" of "Accessibility" settings.
*
* @platform android
*/
getRecommendedTimeoutMillis: (originalTimeout: number) => Promise<number>;
sendAccessibilityEvent: (
handle: React.ElementRef<HostComponent<unknown>>,
eventType: AccessibilityEventTypes,
) => void;
}
export const AccessibilityInfo: AccessibilityInfoStatic;
export type AccessibilityInfo = AccessibilityInfoStatic;

Просмотреть файл

@ -17,6 +17,7 @@ import {sendAccessibilityEvent} from '../../ReactNative/RendererProxy';
import Platform from '../../Utilities/Platform';
import legacySendAccessibilityEvent from './legacySendAccessibilityEvent';
import NativeAccessibilityInfo from './NativeAccessibilityInfo';
import NativeAccessibilityInfoWin32 from './NativeAccessibilityInfoWin32';
import NativeAccessibilityManagerIOS from './NativeAccessibilityManager';
// Events that are only supported on Android.
@ -166,12 +167,18 @@ const AccessibilityInfo = {
*/
isReduceMotionEnabled(): Promise<boolean> {
return new Promise((resolve, reject) => {
if (Platform.OS === 'android' || Platform.OS === 'win32') {
if (Platform.OS === 'android') {
if (NativeAccessibilityInfo != null) {
NativeAccessibilityInfo.isReduceMotionEnabled(resolve);
} else {
reject(null);
}
} else if (Platform.OS === 'win32') {
if (NativeAccessibilityInfoWin32 != null) {
NativeAccessibilityInfoWin32.isReduceMotionEnabled(resolve);
} else {
reject(null);
}
} else {
if (NativeAccessibilityManagerIOS != null) {
NativeAccessibilityManagerIOS.getCurrentReduceMotionState(
@ -248,12 +255,18 @@ const AccessibilityInfo = {
*/
isScreenReaderEnabled(): Promise<boolean> {
return new Promise((resolve, reject) => {
if (Platform.OS === 'android' || Platform.OS === 'win32') {
if (Platform.OS === 'android') {
if (NativeAccessibilityInfo != null) {
NativeAccessibilityInfo.isTouchExplorationEnabled(resolve);
} else {
reject(null);
}
} else if (Platform.OS === 'win32') {
if (NativeAccessibilityInfoWin32 != null) {
NativeAccessibilityInfoWin32.isTouchExplorationEnabled(resolve);
} else {
reject(null);
}
} else {
if (NativeAccessibilityManagerIOS != null) {
NativeAccessibilityManagerIOS.getCurrentVoiceOverState(
@ -370,8 +383,10 @@ const AccessibilityInfo = {
* See https://reactnative.dev/docs/accessibilityinfo#announceforaccessibility
*/
announceForAccessibility(announcement: string): void {
if (Platform.OS === 'android' || Platform.OS === 'win32') {
if (Platform.OS === 'android') {
NativeAccessibilityInfo?.announceForAccessibility(announcement);
} else if (Platform.OS === 'win32') {
NativeAccessibilityInfoWin32?.announceForAccessibility(announcement);
} else {
NativeAccessibilityManagerIOS?.announceForAccessibility(announcement);
}
@ -382,19 +397,34 @@ const AccessibilityInfo = {
* - `announcement`: The string announced by the screen reader.
* - `options`: An object that configures the reading options.
* - `queue`: The announcement will be queued behind existing announcements. iOS only.
* - `nativeID`: The nativeID of the element to send the announcement from. win32 only.
*/
announceForAccessibilityWithOptions(
announcement: string,
options: {queue?: boolean},
options: {
queue?: boolean,
nativeID?: string, // win32
},
): void {
if (Platform.OS === 'android' || Platform.OS === 'win32') {
if (Platform.OS === 'android') {
NativeAccessibilityInfo?.announceForAccessibility(announcement);
} else {
if (NativeAccessibilityManagerIOS?.announceForAccessibilityWithOptions) {
NativeAccessibilityManagerIOS?.announceForAccessibilityWithOptions(
} else if (Platform.OS === 'win32') {
if (NativeAccessibilityInfoWin32?.announceForAccessibilityWithOptions) {
NativeAccessibilityInfoWin32?.announceForAccessibilityWithOptions(
announcement,
options,
);
} else {
NativeAccessibilityInfoWin32?.announceForAccessibility(announcement);
}
} else {
if (NativeAccessibilityManagerIOS?.announceForAccessibilityWithOptions) {
const {nativeID: _, ...iosOptions} = options;
// $FlowFixMe[prop-missing]
NativeAccessibilityManagerIOS?.announceForAccessibilityWithOptions(
announcement,
iosOptions,
);
} else {
NativeAccessibilityManagerIOS?.announceForAccessibility(announcement);
}
@ -407,7 +437,7 @@ const AccessibilityInfo = {
* See https://reactnative.dev/docs/accessibilityinfo#getrecommendedtimeoutmillis
*/
getRecommendedTimeoutMillis(originalTimeout: number): Promise<number> {
if (Platform.OS === 'android' || Platform.OS === 'win32') {
if (Platform.OS === 'android') {
return new Promise((resolve, reject) => {
if (NativeAccessibilityInfo?.getRecommendedTimeoutMillis) {
NativeAccessibilityInfo.getRecommendedTimeoutMillis(
@ -418,6 +448,17 @@ const AccessibilityInfo = {
resolve(originalTimeout);
}
});
} else if (Platform.OS === 'win32') {
return new Promise((resolve, reject) => {
if (NativeAccessibilityInfoWin32?.getRecommendedTimeoutMillis) {
NativeAccessibilityInfoWin32.getRecommendedTimeoutMillis(
originalTimeout,
resolve,
);
} else {
resolve(originalTimeout);
}
});
} else {
return Promise.resolve(originalTimeout);
}

Просмотреть файл

@ -0,0 +1,37 @@
/**
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*
* @format
* @flow
*/
import type {TurboModule} from '../../TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+isReduceMotionEnabled: (
onSuccess: (isReduceMotionEnabled: boolean) => void,
) => void;
+isTouchExplorationEnabled: (
onSuccess: (isScreenReaderEnabled: boolean) => void,
) => void;
+isAccessibilityServiceEnabled?: ?(
onSuccess: (isAccessibilityServiceEnabled: boolean) => void,
) => void;
+setAccessibilityFocus: (reactTag: number) => void;
+announceForAccessibility: (announcement: string) => void;
// [Win32
+announceForAccessibilityWithOptions?: (
announcement: string,
options: {queue?: boolean, nativeID?: string},
) => void;
// Win32]
+getRecommendedTimeoutMillis?: (
mSec: number,
onSuccess: (recommendedTimeoutMillis: number) => void,
) => void;
}
export default (TurboModuleRegistry.get<Spec>('AccessibilityInfo'): ?Spec);