Accessible colors for DynamicColorIOS (#31651)

Summary:
Allow you to harvest the `UIAccessibilityContrastHigh` trait from iOS to show accessible colors when high contrast mode is enabled.

```jsx
// usage

PlatformColorIOS({
  light: '#eeeeee',
  dark: '#333333',
  highContrastLight: '#ffffff',
  highContrastDark: '#000000',
});

// {
//   "dynamic": {
//     "light": "#eeeeee",
//     "dark": "#333333",
//     "highContrastLight": "#ffffff",
//     "highContrastDark": "#000000",
//   }
// }
```

This is how apple's own dynamic system colors work under the hood (https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color/#dynamic-system-colors)

 ---

The react native docs mention that more keys may become available in the future, which this PR is adding:

> In the future, more keys might become available for different user preferences, like high contrast.

https://reactnative.dev/docs/dynamiccolorios

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Added] - High contrast dynamic color options for dark and light mode.

Pull Request resolved: https://github.com/facebook/react-native/pull/31651

Test Plan: Added unit tests for `normalizeColor` to pass the high contrast colors downstream to RCTConvert

Reviewed By: lunaleaps

Differential Revision: D28922536

Pulled By: p-sun

fbshipit-source-id: f81417f003c3adefac50e994e62b9be14ffa91a1
This commit is contained in:
Birkir Gudjonsson
2021-06-16 16:40:42 +01:00
committed by Lorenzo Sciandra
parent 6b5b72c4c3
commit 6287c447d6
6 changed files with 65 additions and 7 deletions
@@ -16,6 +16,8 @@ export opaque type NativeColorValue = {
dynamic?: {
light: ?(ColorValue | ProcessedColorValue),
dark: ?(ColorValue | ProcessedColorValue),
highContrastLight?: ?(ColorValue | ProcessedColorValue),
highContrastDark?: ?(ColorValue | ProcessedColorValue),
},
};
@@ -26,12 +28,21 @@ export const PlatformColor = (...names: Array<string>): ColorValue => {
export type DynamicColorIOSTuplePrivate = {
light: ColorValue,
dark: ColorValue,
highContrastLight?: ColorValue,
highContrastDark?: ColorValue,
};
export const DynamicColorIOSPrivate = (
tuple: DynamicColorIOSTuplePrivate,
): ColorValue => {
return {dynamic: {light: tuple.light, dark: tuple.dark}};
return {
dynamic: {
light: tuple.light,
dark: tuple.dark,
highContrastLight: tuple.highContrastLight,
highContrastDark: tuple.highContrastDark,
},
};
};
export const normalizeColorObject = (
@@ -49,6 +60,8 @@ export const normalizeColorObject = (
dynamic: {
light: normalizeColor(dynamic.light),
dark: normalizeColor(dynamic.dark),
highContrastLight: normalizeColor(dynamic.highContrastLight),
highContrastDark: normalizeColor(dynamic.highContrastDark),
},
};
return dynamicColor;
@@ -67,6 +80,8 @@ export const processColorObject = (
dynamic: {
light: processColor(dynamic.light),
dark: processColor(dynamic.dark),
highContrastLight: processColor(dynamic.highContrastLight),
highContrastDark: processColor(dynamic.highContrastDark),
},
};
return dynamicColor;
@@ -14,8 +14,15 @@ import {DynamicColorIOSPrivate} from './PlatformColorValueTypes';
export type DynamicColorIOSTuple = {
light: ColorValue,
dark: ColorValue,
highContrastLight?: ColorValue,
highContrastDark?: ColorValue,
};
export const DynamicColorIOS = (tuple: DynamicColorIOSTuple): ColorValue => {
return DynamicColorIOSPrivate({light: tuple.light, dark: tuple.dark});
return DynamicColorIOSPrivate({
light: tuple.light,
dark: tuple.dark,
highContrastLight: tuple.highContrastLight,
highContrastDark: tuple.highContrastDark,
});
};
@@ -13,6 +13,8 @@ import type {ColorValue} from './StyleSheet';
export type DynamicColorIOSTuple = {
light: ColorValue,
dark: ColorValue,
highContrastLight?: ColorValue,
highContrastDark?: ColorValue,
};
export const DynamicColorIOS = (tuple: DynamicColorIOSTuple): ColorValue => {
@@ -43,6 +43,25 @@ describe('iOS', () => {
expect(normalizedColor).toEqual(expectedColor);
});
it('should normalize iOS Dynamic colors with accessible colors', () => {
const color = DynamicColorIOS({
light: 'black',
dark: 'white',
highContrastLight: 'red',
highContrastDark: 'blue',
});
const normalizedColor = normalizeColor(color);
const expectedColor = {
dynamic: {
light: 'black',
dark: 'white',
highContrastLight: 'red',
highContrastDark: 'blue',
},
};
expect(normalizedColor).toEqual(expectedColor);
});
it('should normalize iOS Dynamic colors with PlatformColor colors', () => {
const color = DynamicColorIOS({
light: PlatformColor('systemBlackColor'),