Skip to content

Commit 36afb32

Browse files
committed
Change color passed to CPP from number or string to object
1 parent d2f2ed5 commit 36afb32

File tree

16 files changed

+182
-99
lines changed

16 files changed

+182
-99
lines changed

packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSColor.cpp

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#include <reanimated/CSS/common/values/CSSColor.h>
22
#include <reanimated/CSS/svg/values/SVGBrush.h>
33

4-
#include <utility>
5-
64
namespace reanimated::css {
75

86
// CSSColorBase template implementations
@@ -49,6 +47,23 @@ template <ColorTypeEnum TColorType, typename TDerived>
4947
CSSColorBase<TColorType, TDerived>::CSSColorBase(ColorChannels colorChannels)
5048
: channels{std::move(colorChannels)}, colorType(TColorType::Rgba) {}
5149

50+
template <ColorTypeEnum TColorType, typename TDerived>
51+
bool CSSColorBase<TColorType, TDerived>::canConstruct(
52+
jsi::Runtime &rt,
53+
const jsi::Value &jsiValue) {
54+
if (!jsiValue.isObject()) {
55+
return false;
56+
}
57+
const auto &jsiObject = jsiValue.asObject(rt);
58+
return jsiObject.hasProperty(rt, "colorType");
59+
}
60+
61+
template <ColorTypeEnum TColorType, typename TDerived>
62+
bool CSSColorBase<TColorType, TDerived>::canConstruct(
63+
const folly::dynamic &value) {
64+
return value.isObject() && value.count("colorType") > 0;
65+
}
66+
5267
template <ColorTypeEnum TColorType, typename TDerived>
5368
TDerived CSSColorBase<TColorType, TDerived>::interpolate(
5469
double progress,
@@ -83,38 +98,57 @@ bool CSSColorBase<TColorType, TDerived>::operator==(
8398
return colorType == other.colorType && channels == other.channels;
8499
}
85100

101+
template <ColorTypeEnum TColorType, typename TDerived>
102+
std::pair<TColorType, jsi::Value>
103+
CSSColorBase<TColorType, TDerived>::parseJSIValue(
104+
jsi::Runtime &rt,
105+
const jsi::Value &jsiValue) const {
106+
const auto jsiObject = jsiValue.asObject(rt);
107+
const auto colorType = static_cast<TColorType>(
108+
jsiObject.getProperty(rt, "colorType").asNumber());
109+
110+
if (colorType == TColorType::Rgba) {
111+
return {colorType, jsiObject.getProperty(rt, "value")};
112+
}
113+
return {colorType, jsi::Value::undefined()};
114+
}
115+
116+
template <ColorTypeEnum TColorType, typename TDerived>
117+
std::pair<TColorType, folly::dynamic>
118+
CSSColorBase<TColorType, TDerived>::parseDynamicValue(
119+
const folly::dynamic &value) const {
120+
const auto colorType = static_cast<TColorType>(value.at("colorType").asInt());
121+
122+
if (colorType == TColorType::Rgba) {
123+
return {colorType, value.at("value")};
124+
}
125+
return {colorType, folly::dynamic::object()};
126+
}
127+
86128
// CSSColor implementations
87129

88130
CSSColor::CSSColor(jsi::Runtime &rt, const jsi::Value &jsiValue)
89131
: CSSColorBase<CSSColorType, CSSColor>(CSSColorType::Transparent) {
90-
if (jsiValue.isNumber()) {
91-
*this = CSSColor(jsiValue.getNumber());
132+
const auto [colorType, value] = parseJSIValue(rt, jsiValue);
133+
if (colorType == CSSColorType::Rgba) {
134+
*this = CSSColor(value.asNumber());
92135
}
93136
}
94137

95-
CSSColor::CSSColor(const folly::dynamic &value)
138+
CSSColor::CSSColor(const folly::dynamic &dynamicValue)
96139
: CSSColorBase<CSSColorType, CSSColor>(CSSColorType::Transparent) {
97-
if (value.isNumber()) {
140+
const auto [colorType, value] = parseDynamicValue(dynamicValue);
141+
if (colorType == CSSColorType::Rgba) {
98142
*this = CSSColor(value.asInt());
99143
}
100144
}
101145

102-
bool CSSColor::canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue) {
103-
return jsiValue.isNumber() || jsiValue.isUndefined() ||
104-
(jsiValue.isString() && jsiValue.getString(rt).utf8(rt) == "transparent");
105-
}
106-
107-
bool CSSColor::canConstruct(const folly::dynamic &value) {
108-
return value.isNumber() || value.empty() ||
109-
(value.isString() && value.getString() == "transparent");
110-
}
111-
112146
folly::dynamic CSSColor::toDynamic() const {
113-
if (colorType == CSSColorType::Rgba) {
114-
return (channels[3] << 24) | (channels[0] << 16) | (channels[1] << 8) |
115-
channels[2];
147+
if (colorType == CSSColorType::Transparent) {
148+
return 0;
116149
}
117-
return 0;
150+
return (channels[3] << 24) | (channels[0] << 16) | (channels[1] << 8) |
151+
channels[2];
118152
}
119153

120154
std::string CSSColor::toString() const {

packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSColor.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,20 @@ struct CSSColorBase : public CSSSimpleValue<TDerived> {
2727
explicit CSSColorBase(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
2828
explicit CSSColorBase(ColorChannels colorChannels);
2929

30+
static bool canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue);
31+
static bool canConstruct(const folly::dynamic &value);
32+
3033
TDerived interpolate(double progress, const TDerived &to) const override;
3134

3235
bool operator==(const TDerived &other) const;
33-
};
3436

35-
// Enum class for color type
37+
protected:
38+
virtual std::pair<TColorType, jsi::Value> parseJSIValue(
39+
jsi::Runtime &rt,
40+
const jsi::Value &jsiValue) const;
41+
virtual std::pair<TColorType, folly::dynamic> parseDynamicValue(
42+
const folly::dynamic &value) const;
43+
};
3644

3745
enum class CSSColorType {
3846
Rgba,
@@ -41,13 +49,12 @@ enum class CSSColorType {
4149

4250
struct CSSColor : public CSSColorBase<CSSColorType, CSSColor> {
4351
using CSSColorBase<CSSColorType, CSSColor>::CSSColorBase;
52+
using CSSColorBase<CSSColorType, CSSColor>::operator==;
53+
using CSSColorBase<CSSColorType, CSSColor>::canConstruct;
4454

4555
explicit CSSColor(jsi::Runtime &rt, const jsi::Value &jsiValue);
4656
explicit CSSColor(const folly::dynamic &value);
4757

48-
static bool canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue);
49-
static bool canConstruct(const folly::dynamic &value);
50-
5158
folly::dynamic toDynamic() const override;
5259
std::string toString() const override;
5360

packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGBrush.cpp

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,60 @@
22

33
namespace reanimated::css {
44

5-
SVGBrush::SVGBrush(jsi::Runtime &rt, const jsi::Value &value)
5+
SVGBrush::SVGBrush(jsi::Runtime &rt, const jsi::Value &jsiValue)
66
: CSSColorBase<SVGBrushType, SVGBrush>(SVGBrushType::Transparent) {
7-
if (value.isNumber()) {
8-
*this = SVGBrush(value.getNumber());
9-
} else if (
10-
value.isString() && value.getString(rt).utf8(rt) == "currentColor") {
11-
colorType = SVGBrushType::CurrentColor;
7+
const auto [type, value] = parseJSIValue(rt, jsiValue);
8+
if (type == SVGBrushType::Rgba) {
9+
*this = SVGBrush(value.asNumber());
10+
return;
1211
}
12+
13+
if (type == SVGBrushType::UrlId) {
14+
// TODO - handle brush
15+
}
16+
17+
colorType = type;
1318
}
1419

15-
SVGBrush::SVGBrush(const folly::dynamic &value)
20+
SVGBrush::SVGBrush(const folly::dynamic &dynamicValue)
1621
: CSSColorBase<SVGBrushType, SVGBrush>(SVGBrushType::Transparent) {
17-
if (value.isNumber()) {
18-
*this = SVGBrush(value.getDouble());
19-
} else if (value.isString() && value.getString() == "currentColor") {
20-
colorType = SVGBrushType::CurrentColor;
22+
const auto [type, value] = parseDynamicValue(dynamicValue);
23+
if (type == SVGBrushType::Rgba) {
24+
*this = SVGBrush(value.asInt());
25+
return;
2126
}
22-
}
2327

24-
bool SVGBrush::canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue) {
25-
return jsiValue.isNumber() || jsiValue.isUndefined() ||
26-
(jsiValue.isString() &&
27-
isValidColorString(jsiValue.getString(rt).utf8(rt)));
28-
}
28+
if (type == SVGBrushType::UrlId) {
29+
// TODO - handle brush
30+
}
2931

30-
bool SVGBrush::canConstruct(const folly::dynamic &value) {
31-
return value.isNumber() || value.empty() ||
32-
isValidColorString(value.asString());
32+
colorType = type;
3333
}
3434

3535
folly::dynamic SVGBrush::toDynamic() const {
36+
// if (colorType == SVGBrushType::Rgba) {
37+
// return (channels[3] << 24) | (channels[0] << 16) | (channels[1] << 8) |
38+
// channels[2];
39+
// }
40+
// if (colorType == SVGBrushType::CurrentColor) {
41+
// return nullptr; // CurrentColor is not a valid dynamic value
42+
// }
43+
// return 0; // Transparent
3644
switch (colorType) {
3745
case SVGBrushType::Rgba:
3846
return (channels[3] << 24) | (channels[0] << 16) | (channels[1] << 8) |
3947
channels[2];
4048
case SVGBrushType::CurrentColor:
4149
return nullptr; // currentColor is represented as nullptr in SVG
50+
// TODO - add support for urlId
51+
// case SVGBrushType::UrlId:
52+
// return "url(" + value + ")";
53+
case SVGBrushType::ContextFill:
54+
// TODO - return correct value
55+
return 0;
56+
case SVGBrushType::ContextStroke:
57+
// TODO - return correct value
58+
return 0;
4259
default:
4360
return 0; // Transparent
4461
}
@@ -52,6 +69,13 @@ std::string SVGBrush::toString() const {
5269
"," + std::to_string(channels[3]) + ")";
5370
case SVGBrushType::CurrentColor:
5471
return "currentColor";
72+
// TODO - add support for urlId
73+
// case SVGBrushType::UrlId:
74+
// return "url(" + value + ")";
75+
case SVGBrushType::ContextFill:
76+
return "context-fill";
77+
case SVGBrushType::ContextStroke:
78+
return "context-stroke";
5579
default:
5680
return "transparent";
5781
}
@@ -78,8 +102,4 @@ std::ostream &operator<<(std::ostream &os, const SVGBrush &colorValue) {
78102

79103
#endif // NDEBUG
80104

81-
bool SVGBrush::isValidColorString(const std::string &value) {
82-
return value == "transparent" || value == "currentColor";
83-
}
84-
85105
} // namespace reanimated::css

packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGBrush.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,25 @@
22

33
#include <reanimated/CSS/common/values/CSSColor.h>
44

5-
#include <string>
6-
75
namespace reanimated::css {
86

97
enum class SVGBrushType {
10-
Rgba,
11-
Transparent,
12-
CurrentColor,
8+
Rgba = 0,
9+
Transparent = 1,
10+
CurrentColor = 2,
11+
UrlId = 3,
12+
ContextFill = 4,
13+
ContextStroke = 5,
1314
};
1415

1516
struct SVGBrush : public CSSColorBase<SVGBrushType, SVGBrush> {
1617
using CSSColorBase<SVGBrushType, SVGBrush>::CSSColorBase;
18+
using CSSColorBase<SVGBrushType, SVGBrush>::operator==;
19+
using CSSColorBase<SVGBrushType, SVGBrush>::canConstruct;
1720

1821
explicit SVGBrush(jsi::Runtime &rt, const jsi::Value &jsiValue);
1922
explicit SVGBrush(const folly::dynamic &value);
2023

21-
static bool canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue);
22-
static bool canConstruct(const folly::dynamic &value);
23-
2424
folly::dynamic toDynamic() const override;
2525
std::string toString() const override;
2626

@@ -30,9 +30,6 @@ struct SVGBrush : public CSSColorBase<SVGBrushType, SVGBrush> {
3030
#ifndef NDEBUG
3131
friend std::ostream &operator<<(std::ostream &os, const SVGBrush &colorValue);
3232
#endif // NDEBUG
33-
34-
private:
35-
static bool isValidColorString(const std::string &value);
3633
};
3734

3835
} // namespace reanimated::css

packages/react-native-reanimated/src/common/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export type AnyRecord = Record<string, any>;
1717

1818
export type ValueProcessor<V, R = V> = (
1919
value: NonMutable<V>
20-
) => Maybe<R> | Record<string, R>;
20+
) => Maybe<R> | (() => Record<string, R>);
2121

2222
export type TransformOrigin = string | Array<string | number>;
2323

packages/react-native-reanimated/src/css/native/style/createStyleBuilder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
import type { AnyRecord } from '../../../common';
4-
import { isConfigPropertyAlias, isDefined, isRecord } from '../../utils';
4+
import { isConfigPropertyAlias, isDefined } from '../../utils';
55
import type {
66
StyleBuilder,
77
StyleBuilderConfig,
@@ -50,8 +50,8 @@ class StyleBuilderImpl<P extends AnyRecord> implements StyleBuilder<P> {
5050
return;
5151
}
5252

53-
if (isRecord<P>(processedValue)) {
54-
this.maybeAssignProps(processedValue);
53+
if (typeof processedValue === 'function') {
54+
this.maybeAssignProps(processedValue());
5555
} else {
5656
this.maybeAssignProp(property, processedValue);
5757
}
Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22
import type { ColorValue } from 'react-native';
33

4-
import type { Maybe, ValueProcessor } from '../../../../common';
4+
import type { ValueProcessor } from '../../../../common';
55
import {
66
processColor as processColorInternal,
77
ReanimatedError,
@@ -12,21 +12,29 @@ export const ERROR_MESSAGES = {
1212
`Invalid color value: ${String(color)}`,
1313
};
1414

15+
enum CSSColorType {
16+
Rgba = 0,
17+
Transparent = 1,
18+
}
19+
20+
export type CSSColorValue = {
21+
colorType: number;
22+
value?: number | string;
23+
};
24+
1525
export const processColor: ValueProcessor<
1626
ColorValue | number,
17-
number | string
27+
CSSColorValue
1828
> = (value) => {
19-
let normalizedColor: Maybe<number | string> = null;
29+
const normalizedColor = processColorInternal(value);
2030

21-
if (typeof value === 'string' && value === 'transparent') {
22-
normalizedColor = 'transparent';
23-
} else {
24-
normalizedColor = processColorInternal(value);
31+
if (typeof normalizedColor === 'number') {
32+
return { colorType: CSSColorType.Rgba, value: normalizedColor };
2533
}
2634

27-
if (!normalizedColor && normalizedColor !== 0) {
35+
if (normalizedColor === null) {
2836
throw new ReanimatedError(ERROR_MESSAGES.invalidColor(value));
2937
}
3038

31-
return normalizedColor;
39+
return { colorType: CSSColorType.Transparent };
3240
};

packages/react-native-reanimated/src/css/native/style/processors/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use strict';
2+
export type { CSSColorValue } from './colors';
23
export { processColor } from './colors';
34
export { processFontWeight } from './font';
45
export { processInset, processInsetBlock, processInsetInline } from './insets';

packages/react-native-reanimated/src/css/native/style/processors/others.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const processAspectRatio: ValueProcessor<number | string> = (value) => {
2424
throw new ReanimatedError(ERROR_MESSAGES.unsupportedAspectRatio(value));
2525
};
2626

27-
export const processGap: ValueProcessor<number | string> = (value) => ({
27+
export const processGap: ValueProcessor<number | string> = (value) => () => ({
2828
rowGap: value,
2929
columnGap: value,
3030
});

0 commit comments

Comments
 (0)