Skip to content

Commit

Permalink
Add ColorWithSystemEffectMacOS API to react-native-macos (microsoft#751)
Browse files Browse the repository at this point in the history
* add pull yml

* remove yml

* Getting there..

* Closer..

* Remove commented out code

* More simplification

* remove typo

* Make ColorWithSystemEffect it's own sub-object

* It works!

* Add examples of DynamicColorMacOS with a SystemEffect (currently broken)

* Add None Effect too

* Fix typo

* Essentially feature complete

* Rename API

* Missed a file

* Fix the bug where we call processColor too many times

* Replace blah with the issue number

* Change one more title

* Stub out test on other platforms

* Add ifdef macos check, some null checks, and fix up a bunch of the tags

* Fix more of the tags

* Fix lint errors

* ifdef around colorWithEffect method
  • Loading branch information
Saadnajmi committed Jun 1, 2021
1 parent 5db7d60 commit b7e23c9
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 5 deletions.
50 changes: 49 additions & 1 deletion Libraries/StyleSheet/PlatformColorValueTypes.macos.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,35 @@ export opaque type NativeColorValue = {
light: ?(ColorValue | ProcessedColorValue),
dark: ?(ColorValue | ProcessedColorValue),
},
colorWithSystemEffect?: {
baseColor: ?(ColorValue | ProcessedColorValue),
systemEffect: SystemEffectMacOSPrivate,
},
};

export const PlatformColor = (...names: Array<string>): ColorValue => {
return {semantic: names};
};

export type SystemEffectMacOSPrivate =
| 'none'
| 'pressed'
| 'deepPressed'
| 'disabled'
| 'rollover';

export const ColorWithSystemEffectMacOSPrivate = (
color: ColorValue,
effect: SystemEffectMacOSPrivate,
): ColorValue => {
return {
colorWithSystemEffect: {
baseColor: color,
systemEffect: effect,
},
};
};

export type DynamicColorMacOSTuplePrivate = {
light: ColorValue,
dark: ColorValue,
Expand Down Expand Up @@ -54,8 +77,20 @@ export const normalizeColorObject = (
},
};
return dynamicColor;
} else if (
'colorWithSystemEffect' in color &&
color.colorWithSystemEffect != null
) {
const processColor = require('./processColor');
const colorWithSystemEffect = color.colorWithSystemEffect;
const colorObject: NativeColorValue = {
colorWithSystemEffect: {
baseColor: processColor(colorWithSystemEffect.baseColor),
systemEffect: colorWithSystemEffect.systemEffect,
},
};
return colorObject;
}

return null;
};

Expand All @@ -72,6 +107,19 @@ export const processColorObject = (
},
};
return dynamicColor;
} else if (
'colorWithSystemEffect' in color &&
color.colorWithSystemEffect != null
) {
const processColor = require('./processColor');
const colorWithSystemEffect = color.colorWithSystemEffect;
const colorObject: NativeColorValue = {
colorWithSystemEffect: {
baseColor: processColor(colorWithSystemEffect.baseColor),
systemEffect: colorWithSystemEffect.systemEffect,
},
};
return colorObject;
}
return color;
};
Expand Down
16 changes: 16 additions & 0 deletions Libraries/StyleSheet/PlatformColorValueTypesMacOS.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,20 @@ export const DynamicColorMacOS = (
): ColorValue => {
throw new Error('DynamicColorMacOS is not available on this platform.');
};

export type SystemEffectMacOS =
| 'none'
| 'pressed'
| 'deepPressed'
| 'disabled'
| 'rollover';

export const ColorWithSystemEffectMacOS = (
color: ColorValue,
effect: SystemEffectMacOS,
): ColorValue => {
throw new Error(
'ColorWithSystemEffectMacOS is not available on this platform.',
);
};
// ]TODO(macOS ISS#2323203)
19 changes: 18 additions & 1 deletion Libraries/StyleSheet/PlatformColorValueTypesMacOS.macos.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
'use strict';

import type {ColorValue} from './StyleSheetTypes';
import {DynamicColorMacOSPrivate} from './PlatformColorValueTypes';
import {
DynamicColorMacOSPrivate,
ColorWithSystemEffectMacOSPrivate,
} from './PlatformColorValueTypes';

export type DynamicColorMacOSTuple = {
light: ColorValue,
Expand All @@ -23,4 +26,18 @@ export const DynamicColorMacOS = (
): ColorValue => {
return DynamicColorMacOSPrivate({light: tuple.light, dark: tuple.dark});
};

export type SystemEffectMacOS =
| 'none'
| 'pressed'
| 'deepPressed'
| 'disabled'
| 'rollover';

export const ColorWithSystemEffectMacOS = (
color: ColorValue,
effect: SystemEffectMacOS,
): ColorValue => {
return ColorWithSystemEffectMacOSPrivate(color, effect);
};
// ]TODO(macOS ISS#2323203)
146 changes: 146 additions & 0 deletions RNTester/js/examples/PlatformColor/PlatformColorExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const ReactNative = require('react-native');
import Platform from '../../../../Libraries/Utilities/Platform';
const {
ColorAndroid,
ColorWithSystemEffectMacOS, // TODO(macOS GH#750)
DynamicColorIOS,
DynamicColorMacOS,
PlatformColor,
Expand Down Expand Up @@ -352,6 +353,144 @@ function VariantColorsExample() {
);
}

// [TODO(macOS GH#750)
function ColorWithSystemEffectMacOSExample() {
function createTable() {
let colors = [
{label: 'gray', color: 'gray'},
{
label: "ColorWithSystemEffectMacOS('gray', 'none')",
color: ColorWithSystemEffectMacOS('gray', 'none'),
},
{
label: "ColorWithSystemEffectMacOS('gray', 'pressed')",
color: ColorWithSystemEffectMacOS('gray', 'pressed'),
},
{
label: "ColorWithSystemEffectMacOS('gray', 'deepPressed')",
color: ColorWithSystemEffectMacOS('gray', 'deepPressed'),
},
{
label: "ColorWithSystemEffectMacOS('gray', 'disabled')",
color: ColorWithSystemEffectMacOS('gray', 'disabled'),
},
{
label: "ColorWithSystemEffectMacOS('gray', 'rollover')",
color: ColorWithSystemEffectMacOS('gray', 'rollover'),
},
{
label: "PlatformColor('systemBlueColor')",
color: PlatformColor('systemBlueColor'),
},
{
label:
"ColorWithSystemEffectMacOS(PlatformColor('systemBlueColor'), 'none')",
color: ColorWithSystemEffectMacOS(
PlatformColor('systemBlueColor'),
'none',
),
},
{
label:
"ColorWithSystemEffectMacOS(PlatformColor('systemBlueColor'), 'pressed')",
color: ColorWithSystemEffectMacOS(
PlatformColor('systemBlueColor'),
'pressed',
),
},
{
label:
"ColorWithSystemEffectMacOS(PlatformColor('systemBlueColor'), 'deepPressed')",
color: ColorWithSystemEffectMacOS(
PlatformColor('systemBlueColor'),
'deepPressed',
),
},
{
label:
"ColorWithSystemEffectMacOS(PlatformColor('systemBlueColor'), 'disabled')",
color: ColorWithSystemEffectMacOS(
PlatformColor('systemBlueColor'),
'disabled',
),
},
{
label:
"ColorWithSystemEffectMacOS(PlatformColor('systemBlueColor'), 'rollover')",
color: ColorWithSystemEffectMacOS(
PlatformColor('systemBlueColor'),
'rollover',
),
},
{
label: "DynamicColorMacOS({light: 'red', dark: 'blue'})",
color: DynamicColorMacOS({light: 'red', dark: 'blue'}),
},
{
label:
"ColorWithSystemEffectMacOS(DynamicColorMacOS({light: 'red', dark: 'blue'}), 'none')",
color: ColorWithSystemEffectMacOS(
DynamicColorMacOS({light: 'red', dark: 'blue'}),
'none',
),
},
{
label:
"ColorWithSystemEffectMacOS(DynamicColorMacOS({light: 'red', dark: 'blue'}), 'pressed')",
color: ColorWithSystemEffectMacOS(
DynamicColorMacOS({light: 'red', dark: 'blue'}),
'pressed',
),
},
{
label:
"ColorWithSystemEffectMacOS(DynamicColorMacOS({light: 'red', dark: 'blue'}), 'deepPressed')",
color: ColorWithSystemEffectMacOS(
DynamicColorMacOS({light: 'red', dark: 'blue'}),
'deepPressed',
),
},
{
label:
"ColorWithSystemEffectMacOS(DynamicColorMacOS({light: 'red', dark: 'blue'}), 'disabled')",
color: ColorWithSystemEffectMacOS(
DynamicColorMacOS({light: 'red', dark: 'blue'}),
'disabled',
),
},
{
label:
"ColorWithSystemEffectMacOS(DynamicColorMacOS({light: 'red', dark: 'blue'}), 'rollover')",
color: ColorWithSystemEffectMacOS(
DynamicColorMacOS({light: 'red', dark: 'blue'}),
'rollover',
),
},
];

let table = [];
for (let color of colors) {
table.push(
<View style={styles.row} key={color.label}>
<Text style={styles.labelCell}>{color.label}</Text>
<View
style={{
...styles.colorCell,
backgroundColor: color.color,
}}
/>
</View>,
);
}
return table;
}
return Platform.OS === 'macos' ? (
<View style={styles.column}>{createTable()}</View>
) : (
<Text style={styles.labelCell}>Not applicable on this platform</Text>
);
} // ]TODO(macOS GH#750)

const styles = StyleSheet.create({
column: {flex: 1, flexDirection: 'column'},
row: {flex: 0.75, flexDirection: 'row'},
Expand Down Expand Up @@ -398,4 +537,11 @@ exports.examples = [
return <VariantColorsExample />;
},
},
// [TODO(macOS GH#750)
{
title: 'Color With System Effect macOS',
render(): React.Element<any> {
return <ColorWithSystemEffectMacOSExample />;
},
}, // ]TODO(macOS GH#750)
];
40 changes: 39 additions & 1 deletion React/Base/RCTConvert.m
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,28 @@ + (RCTUIColor *)NSColor:(id)json
}
// ]TODO(macOS ISS#2323203)

// [TODO(macOS GH#750)
#if TARGET_OS_OSX
static NSColor *RCTColorWithSystemEffect(NSColor* color, NSString *systemEffectString) {
NSColor *colorWithEffect = color;
if (systemEffectString != nil) {
if ([systemEffectString isEqualToString:@"none"]) {
colorWithEffect = [color colorWithSystemEffect:NSColorSystemEffectNone];
} else if ([systemEffectString isEqualToString:@"pressed"]) {
colorWithEffect = [color colorWithSystemEffect:NSColorSystemEffectPressed];
} else if ([systemEffectString isEqualToString:@"deepPressed"]) {
colorWithEffect = [color colorWithSystemEffect:NSColorSystemEffectDeepPressed];
} else if ([systemEffectString isEqualToString:@"disabled"]) {
colorWithEffect = [color colorWithSystemEffect:NSColorSystemEffectDisabled];
} else if ([systemEffectString isEqualToString:@"rollover"]) {
colorWithEffect = [color colorWithSystemEffect:NSColorSystemEffectRollover];
}
}
return colorWithEffect;
}
#endif //TARGET_OS_OSX
// ]TODO(macOS GH#750)

+ (RCTUIColor *)UIColor:(id)json // TODO(OSS Candidate ISS#2710739)
{
if (!json) {
Expand Down Expand Up @@ -1030,8 +1052,24 @@ + (RCTUIColor *)UIColor:(id)json // TODO(OSS Candidate ISS#2710739)
RCTLogConvertError(json, @"a UIColor. Expected a dynamic appearance aware color.");
return nil;
}
// [TODO(macOS GH#750)
#if TARGET_OS_OSX
} else if((value = [dictionary objectForKey:@"colorWithSystemEffect"])) {
NSDictionary *colorWithSystemEffect = value;
id base = [colorWithSystemEffect objectForKey:@"baseColor"];
NSColor *baseColor = [RCTConvert UIColor:base];
NSString * systemEffectString = [colorWithSystemEffect objectForKey:@"systemEffect"];
if (baseColor != nil && systemEffectString != nil) {
return RCTColorWithSystemEffect(baseColor, systemEffectString);
} else {
RCTLogConvertError(
json, @"a UIColor. Expected a color with a system effect string, but got something else");
return nil;
}
#endif //TARGET_OS_OSX
// ]TODO(macOS GH#750)
} else {
RCTLogConvertError(json, @"a UIColor. Expected a semantic color or dynamic appearance aware color.");
RCTLogConvertError(json, @"a UIColor. Expected a semantic color, dynamic appearance aware color, or color with system effect"); //TODO(macOS GH#750)
return nil;
}
// ]TODO(macOS ISS#2323203)
Expand Down
4 changes: 3 additions & 1 deletion React/Base/macOS/RCTDynamicColor.m
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ - (nullable NSColor *)blendedColorWithFraction:(CGFloat)fraction ofColor:(NSColo

- (NSColor *)colorWithSystemEffect:(NSColorSystemEffect)systemEffect NS_AVAILABLE_MAC(10_14)
{
return [[self effectiveColor] colorWithSystemEffect:systemEffect];
NSColor *aquaColorWithSystemEffect = [_aquaColor colorWithSystemEffect:systemEffect];
NSColor *darkAquaColorWithSystemEffect = [_darkAquaColor colorWithSystemEffect:systemEffect];
return [[RCTDynamicColor alloc] initWithAquaColor:aquaColorWithSystemEffect darkAquaColor:darkAquaColorWithSystemEffect];
}

- (NSUInteger)hash
Expand Down
9 changes: 8 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ import typeof processColor from './Libraries/StyleSheet/processColor';
import typeof {PlatformColor} from './Libraries/StyleSheet/PlatformColorValueTypes';
import typeof {DynamicColorIOS} from './Libraries/StyleSheet/PlatformColorValueTypesIOS';
import typeof {DynamicColorMacOS} from './Libraries/StyleSheet/PlatformColorValueTypesMacOS'; // TODO(macOS ISS#2323203)
import typeof {ColorWithSystemEffectMacOS} from './Libraries/StyleSheet/PlatformColorValueTypesMacOS'; // TODO(macOS GH#750)
import typeof {ColorAndroid} from './Libraries/StyleSheet/PlatformColorValueTypesAndroid';
import typeof RootTagContext from './Libraries/ReactNative/RootTagContext';
import typeof DeprecatedColorPropType from './Libraries/DeprecatedPropTypes/DeprecatedColorPropType';
Expand Down Expand Up @@ -496,10 +497,16 @@ module.exports = {
return require('./Libraries/StyleSheet/PlatformColorValueTypesIOS')
.DynamicColorIOS;
},
// [TODO(macOS ISS#2323203)
get DynamicColorMacOS(): DynamicColorMacOS {
return require('./Libraries/StyleSheet/PlatformColorValueTypesMacOS')
.DynamicColorMacOS;
},
}, // [TODO(macOS ISS#2323203)
// [TODO(macOS GH#750)
get ColorWithSystemEffectMacOS(): ColorWithSystemEffectMacOS {
return require('./Libraries/StyleSheet/PlatformColorValueTypesMacOS')
.ColorWithSystemEffectMacOS;
}, // ]TODO(macOS GH#750)
get ColorAndroid(): ColorAndroid {
return require('./Libraries/StyleSheet/PlatformColorValueTypesAndroid')
.ColorAndroid;
Expand Down

0 comments on commit b7e23c9

Please sign in to comment.