diff --git a/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts b/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts index bad75fca1346b6..e74482135c032d 100644 --- a/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts +++ b/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts @@ -13,6 +13,7 @@ import {EmitterSubscription} from '../../vendor/emitter/EventEmitter'; type AccessibilityChangeEventName = | 'change' // deprecated, maps to screenReaderChanged | 'boldTextChanged' // iOS-only Event + | 'differentiateWithoutColorChanged' // iOS-only Event | 'grayscaleChanged' // iOS-only Event | 'invertColorsChanged' // iOS-only Event | 'reduceMotionChanged' @@ -51,6 +52,13 @@ export interface AccessibilityInfoStatic { */ isBoldTextEnabled: () => Promise; + /** + * Query whether Differentiate Without Color is currently enabled. + * + * @platform ios + */ + isDifferentiateWithoutColorEnabled: () => Promise; + /** * Query whether grayscale is currently enabled. * diff --git a/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js b/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js index 9e1d236c92883c..2d5a5d5cad17f0 100644 --- a/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +++ b/packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js @@ -109,6 +109,31 @@ const AccessibilityInfo = { } }, + /** + * Query whether Differentiate Without Color is currently enabled. iOS only. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when the Differentiate Without Color setting is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#isDifferentiateWithoutColorEnabled + */ + isDifferentiateWithoutColorEnabled(): Promise { + if (Platform.OS === 'android') { + return Promise.resolve(false); + } else { + return new Promise((resolve, reject) => { + if (NativeAccessibilityManagerIOS != null) { + NativeAccessibilityManagerIOS.getCurrentDifferentiateWithoutColorState( + resolve, + reject, + ); + } else { + reject(new Error('NativeAccessibilityManagerIOS is not available')); + } + }); + } + }, + /** * Query whether grayscale is currently enabled. * diff --git a/packages/react-native/React/CoreModules/RCTAccessibilityManager.h b/packages/react-native/React/CoreModules/RCTAccessibilityManager.h index e8ea831b931b0d..c70334b7cdd2a4 100644 --- a/packages/react-native/React/CoreModules/RCTAccessibilityManager.h +++ b/packages/react-native/React/CoreModules/RCTAccessibilityManager.h @@ -21,6 +21,7 @@ extern NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification; / @property (nonatomic, copy) NSDictionary *multipliers; @property (nonatomic, assign) BOOL isBoldTextEnabled; +@property (nonatomic, assign) BOOL isDifferentiateWithoutColorEnabled; @property (nonatomic, assign) BOOL isGrayscaleEnabled; @property (nonatomic, assign) BOOL isInvertColorsEnabled; @property (nonatomic, assign) BOOL isReduceMotionEnabled; diff --git a/packages/react-native/React/CoreModules/RCTAccessibilityManager.mm b/packages/react-native/React/CoreModules/RCTAccessibilityManager.mm index 19895271f14104..fc8ae1cd1b37f6 100644 --- a/packages/react-native/React/CoreModules/RCTAccessibilityManager.mm +++ b/packages/react-native/React/CoreModules/RCTAccessibilityManager.mm @@ -61,6 +61,11 @@ - (instancetype)init name:UIAccessibilityBoldTextStatusDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(differentiateWithoutColorStatusDidChange:) + name:UIAccessibilityDifferentiateWithoutColorStatusDidChangeNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(grayscaleStatusDidChange:) name:UIAccessibilityGrayscaleStatusDidChangeNotification @@ -93,6 +98,7 @@ - (instancetype)init self.contentSizeCategory = RCTSharedApplication().preferredContentSizeCategory; _isBoldTextEnabled = UIAccessibilityIsBoldTextEnabled(); + _isDifferentiateWithoutColorEnabled = UIAccessibilityIsDifferentiateWithoutColorEnabled(); _isGrayscaleEnabled = UIAccessibilityIsGrayscaleEnabled(); _isInvertColorsEnabled = UIAccessibilityIsInvertColorsEnabled(); _isReduceMotionEnabled = UIAccessibilityIsReduceMotionEnabled(); @@ -136,6 +142,19 @@ - (void)boldTextStatusDidChange:(__unused NSNotification *)notification } } +- (void)differentiateWithoutColorStatusDidChange:(__unused NSNotification *)notification +{ + BOOL newDifferentiateWithoutColorEnabled = UIAccessibilityIsDifferentiateWithoutColorEnabled(); + if (_isDifferentiateWithoutColorEnabled != newDifferentiateWithoutColorEnabled) { + _isDifferentiateWithoutColorEnabled = newDifferentiateWithoutColorEnabled; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"differentiateWithoutColorChanged" + body:@(_isDifferentiateWithoutColorEnabled)]; +#pragma clang diagnostic pop + } +} + - (void)grayscaleStatusDidChange:(__unused NSNotification *)notification { BOOL newGrayscaleEnabled = UIAccessibilityIsGrayscaleEnabled(); @@ -369,6 +388,12 @@ static void setMultipliers( onSuccess(@[ @(_isBoldTextEnabled) ]); } +RCT_EXPORT_METHOD( + getCurrentDifferentiateWithoutColorState : (RCTResponseSenderBlock)onSuccess onError : (__unused RCTResponseSenderBlock)onError) +{ + onSuccess(@[ @(_isDifferentiateWithoutColorEnabled) ]); +} + RCT_EXPORT_METHOD( getCurrentGrayscaleState : (RCTResponseSenderBlock)onSuccess onError : (__unused RCTResponseSenderBlock)onError) { diff --git a/packages/react-native/jest/mocks/AccessibilityInfo.js b/packages/react-native/jest/mocks/AccessibilityInfo.js index 4dc215bcabd7f4..297e7d02f41c35 100644 --- a/packages/react-native/jest/mocks/AccessibilityInfo.js +++ b/packages/react-native/jest/mocks/AccessibilityInfo.js @@ -24,6 +24,10 @@ const AccessibilityInfo = { $FlowFixMe, $FlowFixMe, >, + isDifferentiateWithoutColorEnabled: jest.fn(() => Promise.resolve(false)) as JestMockFn< + $FlowFixMe, + $FlowFixMe, + >, isGrayscaleEnabled: jest.fn(() => Promise.resolve(false)) as JestMockFn< $FlowFixMe, $FlowFixMe, diff --git a/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAccessibilityManager.js b/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAccessibilityManager.js index de79663d418b39..cef9b4df6b1e2f 100644 --- a/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAccessibilityManager.js +++ b/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAccessibilityManager.js @@ -17,6 +17,10 @@ export interface Spec extends TurboModule { onSuccess: (isBoldTextEnabled: boolean) => void, onError: (error: Object) => void, ) => void; + +getCurrentDifferentiateWithoutColorState?: ( + onSuccess: (isDifferentiateWithoutColorEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; +getCurrentGrayscaleState: ( onSuccess: (isGrayscaleEnabled: boolean) => void, onError: (error: Object) => void, diff --git a/packages/react-native/types/__typetests__/index.tsx b/packages/react-native/types/__typetests__/index.tsx index 47f720b21946a7..2a24cb8c939d43 100644 --- a/packages/react-native/types/__typetests__/index.tsx +++ b/packages/react-native/types/__typetests__/index.tsx @@ -1473,6 +1473,9 @@ class AccessibilityTest extends React.Component { AccessibilityInfo.isBoldTextEnabled().then(isEnabled => console.log(`AccessibilityInfo.isBoldTextEnabled => ${isEnabled}`), ); +AccessibilityInfo.isDifferentiateWithoutColorEnabled().then(isEnabled => + console.log(`AccessibilityInfo.isDifferentiateWithoutColorEnabled => ${isEnabled}`), +); AccessibilityInfo.isGrayscaleEnabled().then(isEnabled => console.log(`AccessibilityInfo.isGrayscaleEnabled => ${isEnabled}`), ); @@ -1504,6 +1507,9 @@ AccessibilityInfo.addEventListener( AccessibilityInfo.addEventListener('boldTextChanged', isEnabled => console.log(`AccessibilityInfo.isBoldTextEnabled => ${isEnabled}`), ); +AccessibilityInfo.addEventListener('differentiateWithoutColorChanged', isEnabled => + console.log(`AccessibilityInfo.isDifferentiateWithoutColorEnabled => ${isEnabled}`), +); AccessibilityInfo.addEventListener('grayscaleChanged', isEnabled => console.log(`AccessibilityInfo.isGrayscaleEnabled => ${isEnabled}`), );