Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support PlatformColor #1561

Merged
merged 2 commits into from
Feb 23, 2022
Merged

Conversation

oblador
Copy link
Contributor

@oblador oblador commented Apr 1, 2021

Summary

Since version 0.63 React Native has supported PlatformColor structs that among other features has dark mode support built in. Using those values with RNSVG today throws a warning "[Object object]" is not a valid color or brush and makes the path have a clear color.

This PR adds support for PlatformColor by utilizing the color parsing code shipped with React Native itself. In order to support the dynamic properties I had to retain the reference as a UIColor and convert it to CGColorRef as it's read. This might have a performance penalty.

The Android implementation doesn't yet have support for dynamic values (EDIT: react-native itself doesn't support it, so we're good there I think). Since it relies on the ColorPropConverter class, I think it means minimum supported version of RN will be raised to 0.63.

Fixes #1391

Test Plan

I couldn't find an example project in the repo, so I used my own example project, see video:

2021-04-01 15-54-57 2021-04-01 15_56_47

Compatibility

OS Implemented
iOS
Android

Checklist

  • I have tested this on a device and a simulator
  • I added documentation in README.md
  • I updated the typed files (typescript)
  • I added a test for the API in the __tests__ folder

src/index.d.ts Outdated
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as ReactNative from 'react-native';
import { GestureResponderEvent } from 'react-native';
import { GestureResponderEvent, OpaqueColorValue } from 'react-native';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this just be "ColorValue"?

@@ -101,7 +101,7 @@ export type rgbaArray = ReadonlyArray<number>;
// int32ARGBColor = 0xaarrggbb
export type int32ARGBColor = number;

export type Color = int32ARGBColor | rgbaArray | string;
export type Color = int32ARGBColor | rgbaArray | OpaqueColorValue | string;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we just replace the "Color" type altogether with "ColorValue" from react native? It should represent the same set of types of colors

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not the same, from the type it's string | OpaqueColorValue so we could replace the string with this one, but not the whole type. I prefer to use OpaqueColorValue here as I'm not sure what types will be added to ColorValue in the future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was under the impression that ColorValue is just the standard Color type in React Native 0.63+, and that OpaqueColorValue will include all the extra types of colors that can be passed to native. In react-native-macos (which we recently added support for in react-native-svg), I extended ColorValue/OpaqueColorValue to include a new API ColorWithSystemEffectMacOS (microsoft/react-native-macos#751).

But also, I thought the idea of OpaqueColorValue is that we do not need to know the specifics of the type, as long as it gets passed over the bridge to RCTConvert UIColor:] (or whatever the equivalent on Android is), React Native will make sure it's a valid native color. Is there a reason we need to know the specifics of the types of colors now? I was under the impression we could abstract most of that away to React Native and would need less processing on this repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can find the definition here:

export type ColorValue = string | OpaqueColorValue;

So it's not the same, and it can't be replaced as the way this library deals with colors is quite custom. I'm not the author of this library, but i guess it's partly due to color inheritance. If it was not dealing with colors in a custom way then this PR wouldn't be necessary.

Comment on lines +43 to +51
// iOS PlatformColor
if ('semantic' in color) {
return [0, color];
}

// Android PlatformColor
if ('resource_paths' in color) {
return [0, color];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least on iOS, "semantic" isn't enough, because a color might be a DynamicColor instead. Could we instead do something like a type check? if (typeof color === ColorValue) ....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DynamicColorIOS isn't supported in this PR, and I don't really see that API surviving long term as it's iOS only.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surviving in react-native, or surviving in this repo? I don't think it's going anywhere as long as PlatformColor exists. We also have a react-native-macos equivalent DynacmicColorMacOS that won't go anywhere as long as DynamicColor exists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant in react-native. DynamicColorIOS predates PlaformColor, and while it's not able to fully replace it just yet, I don't see that API as useful without cross platform support. I guess is possible to add however.

@oblador
Copy link
Contributor Author

oblador commented Oct 22, 2021

@Saadnajmi How can we make this PR progress?

@gaodeng
Copy link

gaodeng commented Jan 12, 2022

@oblador @Saadnajmi @brentvatne @msand
Based on oblador's code, I added DynamicColorIOS support. Can someone please help to review and merge it?
oblador#1

@Gregoirevda
Copy link

Any update to support PlatformColor?

@Gregoirevda
Copy link

@oblador I've installed your PR branch through npm, but it doesn't compile with Babel:
The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
for
if ('semantic' in color) { and if ('resource_paths' in color) {

Copy link
Member

@WoLewicki WoLewicki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some suggestions regarding the code, which we can fix in a follow-up PR. Other from that, it looks like it's ready to be merged 🎉

@@ -13,48 +13,49 @@

@implementation RNSVGSolidColorBrush
{
CGColorRef _color;
UIColor *_color;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should use RNSVGColor so it compiles on macOS.

return CGColorCreateCopyWithAlpha(_color, opacity * CGColorGetAlpha(_color));
CGColorRef baseColor = _color.CGColor;
CGColorRef color = CGColorCreateCopyWithAlpha(baseColor, opacity * CGColorGetAlpha(baseColor));
CGColorRelease(baseColor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not release it since it will release CGColor prop of _color, so trying to use _color.CGColor again will lead to crash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure about that? Why would releasing _baseColor affect _color?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, now I see, good catch 👍

@@ -40,6 +40,16 @@ export default function extractBrush(color?: Color) {
return int32ARGBColor;
}

// iOS PlatformColor
if ('semantic' in color) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WoLewicki
Copy link
Member

One more thing about Android, I tried to set color prop with PlatformColor on Svg and it throws error unless we add changes in android folder from this PR: https://github.com/oblador/react-native-svg/pull/1/files. We can also do it in a follow-up PR so it is OK for now.

@WoLewicki WoLewicki merged commit d35878b into software-mansion:develop Feb 23, 2022
WoLewicki added a commit that referenced this pull request Feb 24, 2022
Follow-up PR to #1561 fixing the problems mentioned there. Also fixing the wrong releasing introduced in 027b8c1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

PlatformColor and DynamicColorIOS don't work
5 participants