diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSAngle.h b/packages/react-native/ReactCommon/react/renderer/css/CSSAngle.h new file mode 100644 index 00000000000..8f97e351699 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSAngle.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include + +namespace facebook::react { + +/** + * Representation of CSS data type + * https://www.w3.org/TR/css-values-4/#angles + */ +struct CSSAngle { + float degrees{}; +}; + +template <> +struct CSSDataTypeParser { + static constexpr auto consumePreservedToken(const CSSPreservedToken& token) + -> std::optional { + if (token.type() == CSSTokenType::Dimension) { + if (auto unit = parseCSSAngleUnit(token.unit())) { + return CSSAngle{canonicalize(token.numericValue(), *unit)}; + } + } + return {}; + } +}; + +static_assert(CSSDataType); + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSColor.h b/packages/react-native/ReactCommon/react/renderer/css/CSSColor.h new file mode 100644 index 00000000000..5d8324f6da2 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSColor.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace facebook::react { + +/** + * Representation of CSS data type + * https://www.w3.org/TR/css-color-5/#typedef-color + */ +struct CSSColor { + uint8_t r{}; + uint8_t g{}; + uint8_t b{}; + uint8_t a{}; +}; + +template <> +struct CSSDataTypeParser { + static constexpr auto consumePreservedToken(const CSSPreservedToken& token) + -> std::optional { + switch (token.type()) { + case CSSTokenType::Ident: + return parseCSSNamedColor(token.stringValue()); + case CSSTokenType::Hash: + return parseCSSHexColor(token.stringValue()); + default: + return {}; + } + } +}; + +static_assert(CSSDataType); + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSColorUtils.h b/packages/react-native/ReactCommon/react/renderer/css/CSSColorUtils.h deleted file mode 100644 index ca384138779..00000000000 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSColorUtils.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -namespace facebook::react { - -// https://www.w3.org/TR/css-color-4/#named-colors -template -constexpr std::optional parseCSSNamedColor(std::string_view name) { - switch (fnv1aLowercase(name)) { - case fnv1a("aliceblue"): - return CSSValueT::color(240, 248, 255, 255); - case fnv1a("antiquewhite"): - return CSSValueT::color(250, 235, 215, 255); - case fnv1a("aqua"): - return CSSValueT::color(0, 255, 255, 255); - case fnv1a("aquamarine"): - return CSSValueT::color(127, 255, 212, 255); - case fnv1a("azure"): - return CSSValueT::color(240, 255, 255, 255); - case fnv1a("beige"): - return CSSValueT::color(245, 245, 220, 255); - case fnv1a("bisque"): - return CSSValueT::color(255, 228, 196, 255); - case fnv1a("black"): - return CSSValueT::color(0, 0, 0, 255); - case fnv1a("blanchedalmond"): - return CSSValueT::color(255, 235, 205, 255); - case fnv1a("blue"): - return CSSValueT::color(0, 0, 255, 255); - case fnv1a("blueviolet"): - return CSSValueT::color(138, 43, 226, 255); - case fnv1a("brown"): - return CSSValueT::color(165, 42, 42, 255); - case fnv1a("burlywood"): - return CSSValueT::color(222, 184, 135, 255); - case fnv1a("cadetblue"): - return CSSValueT::color(95, 158, 160, 255); - case fnv1a("chartreuse"): - return CSSValueT::color(127, 255, 0, 255); - case fnv1a("chocolate"): - return CSSValueT::color(210, 105, 30, 255); - case fnv1a("coral"): - return CSSValueT::color(255, 127, 80, 255); - case fnv1a("cornflowerblue"): - return CSSValueT::color(100, 149, 237, 255); - case fnv1a("cornsilk"): - return CSSValueT::color(255, 248, 220, 255); - case fnv1a("crimson"): - return CSSValueT::color(220, 20, 60, 255); - case fnv1a("cyan"): - return CSSValueT::color(0, 255, 255, 255); - case fnv1a("darkblue"): - return CSSValueT::color(0, 0, 139, 255); - case fnv1a("darkcyan"): - return CSSValueT::color(0, 139, 139, 255); - case fnv1a("darkgoldenrod"): - return CSSValueT::color(184, 134, 11, 255); - case fnv1a("darkgray"): - return CSSValueT::color(169, 169, 169, 255); - case fnv1a("darkgreen"): - return CSSValueT::color(0, 100, 0, 255); - case fnv1a("darkgrey"): - return CSSValueT::color(169, 169, 169, 255); - case fnv1a("darkkhaki"): - return CSSValueT::color(189, 183, 107, 255); - case fnv1a("darkmagenta"): - return CSSValueT::color(139, 0, 139, 255); - case fnv1a("darkolivegreen"): - return CSSValueT::color(85, 107, 47, 255); - case fnv1a("darkorange"): - return CSSValueT::color(255, 140, 0, 255); - case fnv1a("darkorchid"): - return CSSValueT::color(153, 50, 204, 255); - case fnv1a("darkred"): - return CSSValueT::color(139, 0, 0, 255); - case fnv1a("darksalmon"): - return CSSValueT::color(233, 150, 122, 255); - case fnv1a("darkseagreen"): - return CSSValueT::color(143, 188, 143, 255); - case fnv1a("darkslateblue"): - return CSSValueT::color(72, 61, 139, 255); - case fnv1a("darkslategray"): - return CSSValueT::color(47, 79, 79, 255); - case fnv1a("darkslategrey"): - return CSSValueT::color(47, 79, 79, 255); - case fnv1a("darkturquoise"): - return CSSValueT::color(0, 206, 209, 255); - case fnv1a("darkviolet"): - return CSSValueT::color(148, 0, 211, 255); - case fnv1a("deeppink"): - return CSSValueT::color(255, 20, 147, 255); - case fnv1a("deepskyblue"): - return CSSValueT::color(0, 191, 255, 255); - case fnv1a("dimgray"): - return CSSValueT::color(105, 105, 105, 255); - case fnv1a("dimgrey"): - return CSSValueT::color(105, 105, 105, 255); - case fnv1a("dodgerblue"): - return CSSValueT::color(30, 144, 255, 255); - case fnv1a("firebrick"): - return CSSValueT::color(178, 34, 34, 255); - case fnv1a("floralwhite"): - return CSSValueT::color(255, 250, 240, 255); - case fnv1a("forestgreen"): - return CSSValueT::color(34, 139, 34, 255); - case fnv1a("fuchsia"): - return CSSValueT::color(255, 0, 255, 255); - case fnv1a("gainsboro"): - return CSSValueT::color(220, 220, 220, 255); - case fnv1a("ghostwhite"): - return CSSValueT::color(248, 248, 255, 255); - case fnv1a("gold"): - return CSSValueT::color(255, 215, 0, 255); - case fnv1a("goldenrod"): - return CSSValueT::color(218, 165, 32, 255); - case fnv1a("gray"): - return CSSValueT::color(128, 128, 128, 255); - case fnv1a("green"): - return CSSValueT::color(0, 128, 0, 255); - case fnv1a("greenyellow"): - return CSSValueT::color(173, 255, 47, 255); - case fnv1a("grey"): - return CSSValueT::color(128, 128, 128, 255); - case fnv1a("honeydew"): - return CSSValueT::color(240, 255, 240, 255); - case fnv1a("hotpink"): - return CSSValueT::color(255, 105, 180, 255); - case fnv1a("indianred"): - return CSSValueT::color(205, 92, 92, 255); - case fnv1a("indigo"): - return CSSValueT::color(75, 0, 130, 255); - case fnv1a("ivory"): - return CSSValueT::color(255, 255, 240, 255); - case fnv1a("khaki"): - return CSSValueT::color(240, 230, 140, 255); - case fnv1a("lavender"): - return CSSValueT::color(230, 230, 250, 255); - case fnv1a("lavenderblush"): - return CSSValueT::color(255, 240, 245, 255); - case fnv1a("lawngreen"): - return CSSValueT::color(124, 252, 0, 255); - case fnv1a("lemonchiffon"): - return CSSValueT::color(255, 250, 205, 255); - case fnv1a("lightblue"): - return CSSValueT::color(173, 216, 230, 255); - case fnv1a("lightcoral"): - return CSSValueT::color(240, 128, 128, 255); - case fnv1a("lightcyan"): - return CSSValueT::color(224, 255, 255, 255); - case fnv1a("lightgoldenrodyellow"): - return CSSValueT::color(250, 250, 210, 255); - case fnv1a("lightgray"): - return CSSValueT::color(211, 211, 211, 255); - case fnv1a("lightgreen"): - return CSSValueT::color(144, 238, 144, 255); - case fnv1a("lightgrey"): - return CSSValueT::color(211, 211, 211, 255); - case fnv1a("lightpink"): - return CSSValueT::color(255, 182, 193, 255); - case fnv1a("lightsalmon"): - return CSSValueT::color(255, 160, 122, 255); - case fnv1a("lightseagreen"): - return CSSValueT::color(32, 178, 170, 255); - case fnv1a("lightskyblue"): - return CSSValueT::color(135, 206, 250, 255); - case fnv1a("lightslategray"): - return CSSValueT::color(119, 136, 153, 255); - case fnv1a("lightslategrey"): - return CSSValueT::color(119, 136, 153, 255); - case fnv1a("lightsteelblue"): - return CSSValueT::color(176, 196, 222, 255); - case fnv1a("lightyellow"): - return CSSValueT::color(255, 255, 224, 255); - case fnv1a("lime"): - return CSSValueT::color(0, 255, 0, 255); - case fnv1a("limegreen"): - return CSSValueT::color(50, 205, 50, 255); - case fnv1a("linen"): - return CSSValueT::color(250, 240, 230, 255); - case fnv1a("magenta"): - return CSSValueT::color(255, 0, 255, 255); - case fnv1a("maroon"): - return CSSValueT::color(128, 0, 0, 255); - case fnv1a("mediumaquamarine"): - return CSSValueT::color(102, 205, 170, 255); - case fnv1a("mediumblue"): - return CSSValueT::color(0, 0, 205, 255); - case fnv1a("mediumorchid"): - return CSSValueT::color(186, 85, 211, 255); - case fnv1a("mediumpurple"): - return CSSValueT::color(147, 112, 219, 255); - case fnv1a("mediumseagreen"): - return CSSValueT::color(60, 179, 113, 255); - case fnv1a("mediumslateblue"): - return CSSValueT::color(123, 104, 238, 255); - case fnv1a("mediumspringgreen"): - return CSSValueT::color(0, 250, 154, 255); - case fnv1a("mediumturquoise"): - return CSSValueT::color(72, 209, 204, 255); - case fnv1a("mediumvioletred"): - return CSSValueT::color(199, 21, 133, 255); - case fnv1a("midnightblue"): - return CSSValueT::color(25, 25, 112, 255); - case fnv1a("mintcream"): - return CSSValueT::color(245, 255, 250, 255); - case fnv1a("mistyrose"): - return CSSValueT::color(255, 228, 225, 255); - case fnv1a("moccasin"): - return CSSValueT::color(255, 228, 181, 255); - case fnv1a("navajowhite"): - return CSSValueT::color(255, 222, 173, 255); - case fnv1a("navy"): - return CSSValueT::color(0, 0, 128, 255); - case fnv1a("oldlace"): - return CSSValueT::color(253, 245, 230, 255); - case fnv1a("olive"): - return CSSValueT::color(128, 128, 0, 255); - case fnv1a("olivedrab"): - return CSSValueT::color(107, 142, 35, 255); - case fnv1a("orange"): - return CSSValueT::color(255, 165, 0, 255); - case fnv1a("orangered"): - return CSSValueT::color(255, 69, 0, 255); - case fnv1a("orchid"): - return CSSValueT::color(218, 112, 214, 255); - case fnv1a("palegoldenrod"): - return CSSValueT::color(238, 232, 170, 255); - case fnv1a("palegreen"): - return CSSValueT::color(152, 251, 152, 255); - case fnv1a("paleturquoise"): - return CSSValueT::color(175, 238, 238, 255); - case fnv1a("palevioletred"): - return CSSValueT::color(219, 112, 147, 255); - case fnv1a("papayawhip"): - return CSSValueT::color(255, 239, 213, 255); - case fnv1a("peachpuff"): - return CSSValueT::color(255, 218, 185, 255); - case fnv1a("peru"): - return CSSValueT::color(205, 133, 63, 255); - case fnv1a("pink"): - return CSSValueT::color(255, 192, 203, 255); - case fnv1a("plum"): - return CSSValueT::color(221, 160, 221, 255); - case fnv1a("powderblue"): - return CSSValueT::color(176, 224, 230, 255); - case fnv1a("purple"): - return CSSValueT::color(128, 0, 128, 255); - case fnv1a("rebeccapurple"): - return CSSValueT::color(102, 51, 153, 255); - case fnv1a("red"): - return CSSValueT::color(255, 0, 0, 255); - case fnv1a("rosybrown"): - return CSSValueT::color(188, 143, 143, 255); - case fnv1a("royalblue"): - return CSSValueT::color(65, 105, 225, 255); - case fnv1a("saddlebrown"): - return CSSValueT::color(139, 69, 19, 255); - case fnv1a("salmon"): - return CSSValueT::color(250, 128, 114, 255); - case fnv1a("sandybrown"): - return CSSValueT::color(244, 164, 96, 255); - case fnv1a("seagreen"): - return CSSValueT::color(46, 139, 87, 255); - case fnv1a("seashell"): - return CSSValueT::color(255, 245, 238, 255); - case fnv1a("sienna"): - return CSSValueT::color(160, 82, 45, 255); - case fnv1a("silver"): - return CSSValueT::color(192, 192, 192, 255); - case fnv1a("skyblue"): - return CSSValueT::color(135, 206, 235, 255); - case fnv1a("slateblue"): - return CSSValueT::color(106, 90, 205, 255); - case fnv1a("slategray"): - return CSSValueT::color(112, 128, 144, 255); - case fnv1a("slategrey"): - return CSSValueT::color(112, 128, 144, 255); - case fnv1a("snow"): - return CSSValueT::color(255, 250, 250, 255); - case fnv1a("springgreen"): - return CSSValueT::color(0, 255, 127, 255); - case fnv1a("steelblue"): - return CSSValueT::color(70, 130, 180, 255); - case fnv1a("tan"): - return CSSValueT::color(210, 180, 140, 255); - case fnv1a("teal"): - return CSSValueT::color(0, 128, 128, 255); - case fnv1a("thistle"): - return CSSValueT::color(216, 191, 216, 255); - case fnv1a("tomato"): - return CSSValueT::color(255, 99, 71, 255); - case fnv1a("transparent"): - return CSSValueT::color(0, 0, 0, 0); - case fnv1a("turquoise"): - return CSSValueT::color(64, 224, 208, 255); - case fnv1a("violet"): - return CSSValueT::color(238, 130, 238, 255); - case fnv1a("wheat"): - return CSSValueT::color(245, 222, 179, 255); - case fnv1a("white"): - return CSSValueT::color(255, 255, 255, 255); - case fnv1a("whitesmoke"): - return CSSValueT::color(245, 245, 245, 255); - case fnv1a("yellow"): - return CSSValueT::color(255, 255, 0, 255); - case fnv1a("yellowgreen"): - return CSSValueT::color(154, 205, 50, 255); - default: - return std::nullopt; - } -} - -enum class HexColorType { - Long, - Short, -}; - -constexpr char toLower(char c) { - if (c >= 'A' && c <= 'Z') { - return static_cast(c + 32); - } - return c; -} - -constexpr uint8_t hexToNumeric(std::string_view hex, HexColorType hexType) { - int result = 0; - for (char c : hex) { - int value = 0; - if (c >= '0' && c <= '9') { - value = c - '0'; - } else { - value = toLower(c) - 'a' + 10; - } - result *= 16; - result += value; - } - - if (hexType == HexColorType::Short) { - return result * 16 + result; - } else { - return result; - } -} - -constexpr bool isHexDigit(char c) { - return (c >= '0' && c <= '9') || (toLower(c) >= 'a' && toLower(c) <= 'f'); -} - -constexpr bool isValidHexColor(std::string_view hex) { - // The syntax of a is a token whose value consists - // of 3, 4, 6, or 8 hexadecimal digits. - if (hex.size() != 3 && hex.size() != 4 && hex.size() != 6 && - hex.size() != 8) { - return false; - } - - for (auto c : hex) { - if (!isHexDigit(c)) { - return false; - } - } - - return true; -} - -}; // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSDataType.h b/packages/react-native/ReactCommon/react/renderer/css/CSSDataType.h new file mode 100644 index 00000000000..111b208bc5d --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSDataType.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace facebook::react { + +/** + * May be specialized to instruct the CSS value parser how to parse a given data + * type, according to CSSValidDataTypeParser. + */ +template +struct CSSDataTypeParser {}; + +/** + * Accepts a CSS function block and may parse it (and future syntax) into a + * concrete representation. + */ +template +concept CSSFunctionBlockSink = + requires(const CSSFunctionBlock& func, CSSSyntaxParser& parser) { + { T::consumeFunctionBlock(func, parser) } -> std::convertible_to; + }; + +/** + * Accepts a CSS simple block and may parse it (and future syntax) into a + * concrete representation. + */ +template +concept CSSSimpleBlockSink = + requires(const CSSSimpleBlock& block, CSSSyntaxParser& parser) { + { T::consumeSimpleBlock(block, parser) } -> std::convertible_to; + }; + +/** + * Accepts a CSS preserved token and may parse it (and future syntax) into a + * concrete representation. + */ +template +concept CSSPreservedTokenSink = + requires(const CSSPreservedToken& token, CSSSyntaxParser& parser) { + { + T::consumePreservedToken(token, parser) + } -> std::convertible_to; + }; + +/** + * Accepts a CSS preserved token and may parse it into a concrete + * representation. + */ +template +concept CSSSimplePreservedTokenSink = requires(const CSSPreservedToken& token) { + { T::consumePreservedToken(token) } -> std::convertible_to; +}; + +/** + * Represents a valid specialization of CSSDataTypeParser + */ +template +concept CSSValidDataTypeParser = CSSFunctionBlockSink || + CSSSimpleBlockSink || CSSPreservedTokenSink || + CSSSimplePreservedTokenSink; + +/** + * Concrete representation for a CSS data type, or keywords + */ +template +concept CSSDataType = + CSSValidDataTypeParser, std::optional>; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSDeclaredStyle.h b/packages/react-native/ReactCommon/react/renderer/css/CSSDeclaredStyle.h deleted file mode 100644 index 92179583c56..00000000000 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSDeclaredStyle.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace facebook::react { - -namespace detail { -constexpr CSSProp kFirstCSSProp = static_cast(0); - -template -constexpr size_t maxSizeofDeclaredValue() { - if constexpr (to_underlying(Prop) < kCSSPropCount - 1) { - return std::max( - sizeof(CSSDeclaredValue), - maxSizeofDeclaredValue( - to_underlying(Prop) + 1)>()); - } else { - return sizeof(CSSDeclaredValue); - } -} -} // namespace detail - -/** - * CSSDeclaredStyle represents the set of style declarations on an element set - * by the user. Users should generally not read from CSSDeclaredStyle directly, - * and should instead use the computed style calculated on ShadowTree commit. - */ -class CSSDeclaredStyle { - public: - template - void set(const CSSDeclaredValue& value) { - using DeclaredValueT = std::remove_cvref_t>; - static_assert(sizeof(value) <= sizeof(PropMapping::value)); - static_assert(std::is_trivially_destructible_v); - - if (specifiedProperties_.test(to_underlying(Prop))) { - auto it = std::lower_bound( - properties_.begin(), properties_.end(), PropMapping{Prop, {}}); - react_native_assert(it->prop == Prop); - std::construct_at( - reinterpret_cast(it->value.data()), value); - } else { - auto it = std::upper_bound( - properties_.begin(), properties_.end(), PropMapping{Prop, {}}); - it = properties_.insert(it, {Prop, {}}); - std::construct_at( - reinterpret_cast(it->value.data()), value); - specifiedProperties_.set(to_underlying(Prop)); - } - } - - template - bool set(std::string_view value) { - auto cssProp = parseCSSProp(value); - set(cssProp); - return cssProp.hasValue(); - } - - bool set(std::string_view prop, std::string_view value) { - return setPropIfHashMatches(fnv1a(prop), value); - } - - /** - * Returns the declared value, represented as the "unset" keyword if never - * specified. Additional shorthands can be provided in order - * of precedence if Prop is unset. - */ - template - CSSDeclaredValue get() const { - if (specifiedProperties_.test(to_underlying(Prop))) { - auto it = std::lower_bound( - properties_.begin(), properties_.end(), PropMapping{Prop, {}}); - react_native_assert(it->prop == Prop); - - CSSDeclaredValue value{*std::launder( - reinterpret_cast*>(it->value.data()))}; - - if (value) { - return value; - } - } - - if constexpr (sizeof...(ShorthandsT) == 0) { - return {}; - } else { - return get(); - } - } - - bool operator==(const CSSDeclaredStyle& rhs) const = default; - - private: - struct PropMapping { - CSSProp prop; - std::array value; - - constexpr bool operator<(const PropMapping& rhs) const { - return to_underlying(prop) < to_underlying(rhs.prop); - } - }; - - template - constexpr bool setPropIfHashMatches( - size_t propNameHash, - std::string_view value) { - constexpr std::string_view currentPropName = - CSSPropDefinition::kName; - constexpr size_t currentHash = fnv1a(currentPropName); - if (currentHash == propNameHash) { - return set(value); - } else if constexpr (to_underlying(CurrentProp) < kCSSPropCount - 1) { - return setPropIfHashMatches( - to_underlying(CurrentProp) + 1)>(propNameHash, value); - } else { - return false; - } - } - - std::vector properties_; - std::bitset specifiedProperties_; -}; - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSHexColor.h b/packages/react-native/ReactCommon/react/renderer/css/CSSHexColor.h new file mode 100644 index 00000000000..ca53b90e83a --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSHexColor.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook::react { + +namespace detail { +enum class HexColorType { + Long, + Short, +}; + +constexpr char toLower(char c) { + if (c >= 'A' && c <= 'Z') { + return static_cast(c + 32); + } + return c; +} + +constexpr uint8_t hexToNumeric(std::string_view hex, HexColorType hexType) { + int result = 0; + for (char c : hex) { + int value = 0; + if (c >= '0' && c <= '9') { + value = c - '0'; + } else { + value = toLower(c) - 'a' + 10; + } + result *= 16; + result += value; + } + + if (hexType == HexColorType::Short) { + return result * 16 + result; + } else { + return result; + } +} + +constexpr bool isHexDigit(char c) { + return (c >= '0' && c <= '9') || (toLower(c) >= 'a' && toLower(c) <= 'f'); +} + +constexpr bool isValidHexColor(std::string_view hex) { + // The syntax of a is a token whose value consists + // of 3, 4, 6, or 8 hexadecimal digits. + if (hex.size() != 3 && hex.size() != 4 && hex.size() != 6 && + hex.size() != 8) { + return false; + } + + for (auto c : hex) { + if (!isHexDigit(c)) { + return false; + } + } + + return true; +} +} // namespace detail + +/** + * Parses a CSS value from hash stoken string value and returns a + * CSSColor if it is valid. + * https://www.w3.org/TR/css-color-4/#hex-color + */ +template +constexpr std::optional parseCSSHexColor( + std::string_view hexColorValue) { + if (detail::isValidHexColor(hexColorValue)) { + if (hexColorValue.length() == 3) { + return CSSColor{ + hexToNumeric(hexColorValue.substr(0, 1), detail::HexColorType::Short), + hexToNumeric(hexColorValue.substr(1, 1), detail::HexColorType::Short), + hexToNumeric(hexColorValue.substr(2, 1), detail::HexColorType::Short), + 255u}; + } else if (hexColorValue.length() == 4) { + return CSSColor{ + hexToNumeric(hexColorValue.substr(0, 1), detail::HexColorType::Short), + hexToNumeric(hexColorValue.substr(1, 1), detail::HexColorType::Short), + hexToNumeric(hexColorValue.substr(2, 1), detail::HexColorType::Short), + hexToNumeric( + hexColorValue.substr(3, 1), detail::HexColorType::Short)}; + } else if (hexColorValue.length() == 6) { + return CSSColor{ + hexToNumeric(hexColorValue.substr(0, 2), detail::HexColorType::Long), + hexToNumeric(hexColorValue.substr(2, 2), detail::HexColorType::Long), + hexToNumeric(hexColorValue.substr(4, 2), detail::HexColorType::Long), + 255u}; + } else if (hexColorValue.length() == 8) { + return CSSColor{ + hexToNumeric(hexColorValue.substr(0, 2), detail::HexColorType::Long), + hexToNumeric(hexColorValue.substr(2, 2), detail::HexColorType::Long), + hexToNumeric(hexColorValue.substr(4, 2), detail::HexColorType::Long), + hexToNumeric(hexColorValue.substr(6, 2), detail::HexColorType::Long)}; + } + } + return {}; +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSKeywords.h b/packages/react-native/ReactCommon/react/renderer/css/CSSKeyword.h similarity index 96% rename from packages/react-native/ReactCommon/react/renderer/css/CSSKeywords.h rename to packages/react-native/ReactCommon/react/renderer/css/CSSKeyword.h index 0a92769bbd7..07bca3f5e99 100644 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSKeywords.h +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSKeyword.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -453,4 +454,18 @@ constexpr std::optional parseCSSKeyword(std::string_view ident) { return std::nullopt; } +template +struct CSSDataTypeParser { + static constexpr auto consumePreservedToken(const CSSPreservedToken& token) + -> std::optional { + if (token.type() == CSSTokenType::Ident) { + return parseCSSKeyword(token.stringValue()); + } + + return {}; + } +}; + +static_assert(CSSDataType); + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSLength.h b/packages/react-native/ReactCommon/react/renderer/css/CSSLength.h new file mode 100644 index 00000000000..8b4de0213ba --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSLength.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include + +namespace facebook::react { + +/** + * Representation of CSS data type + * https://www.w3.org/TR/css-values-4/#lengths + */ +struct CSSLength { + float value{}; + CSSLengthUnit unit{CSSLengthUnit::Px}; +}; + +template <> +struct CSSDataTypeParser { + static constexpr auto consumePreservedToken(const CSSPreservedToken& token) + -> std::optional { + switch (token.type()) { + case CSSTokenType::Dimension: + if (auto unit = parseCSSLengthUnit(token.unit())) { + return CSSLength{token.numericValue(), *unit}; + } + break; + case CSSTokenType::Number: + // For zero lengths the unit identifier is optional (i.e. can be + // syntactically represented as the 0). However, if a 0 + // could be parsed as either a or a in a + // property (such as line-height), it must parse as a . + // https://www.w3.org/TR/css-values-4/#lengths + if (token.numericValue() == 0) { + return CSSLength{token.numericValue(), CSSLengthUnit::Px}; + } + break; + default: + break; + } + + return {}; + } +}; + +static_assert(CSSDataType); + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSNamedColor.h b/packages/react-native/ReactCommon/react/renderer/css/CSSNamedColor.h new file mode 100644 index 00000000000..4ed3065c96b --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSNamedColor.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include + +namespace facebook::react { + +/** + * Parse one of the given , including the "transparent" special + * keyword. + * https://www.w3.org/TR/css-color-4/#named-colors + */ +template +constexpr std::optional parseCSSNamedColor(std::string_view name) { + switch (fnv1aLowercase(name)) { + case fnv1a("aliceblue"): + return CSSColor{240, 248, 255, 255}; + case fnv1a("antiquewhite"): + return CSSColor{250, 235, 215, 255}; + case fnv1a("aqua"): + return CSSColor{0, 255, 255, 255}; + case fnv1a("aquamarine"): + return CSSColor{127, 255, 212, 255}; + case fnv1a("azure"): + return CSSColor{240, 255, 255, 255}; + case fnv1a("beige"): + return CSSColor{245, 245, 220, 255}; + case fnv1a("bisque"): + return CSSColor{255, 228, 196, 255}; + case fnv1a("black"): + return CSSColor{0, 0, 0, 255}; + case fnv1a("blanchedalmond"): + return CSSColor{255, 235, 205, 255}; + case fnv1a("blue"): + return CSSColor{0, 0, 255, 255}; + case fnv1a("blueviolet"): + return CSSColor{138, 43, 226, 255}; + case fnv1a("brown"): + return CSSColor{165, 42, 42, 255}; + case fnv1a("burlywood"): + return CSSColor{222, 184, 135, 255}; + case fnv1a("cadetblue"): + return CSSColor{95, 158, 160, 255}; + case fnv1a("chartreuse"): + return CSSColor{127, 255, 0, 255}; + case fnv1a("chocolate"): + return CSSColor{210, 105, 30, 255}; + case fnv1a("coral"): + return CSSColor{255, 127, 80, 255}; + case fnv1a("cornflowerblue"): + return CSSColor{100, 149, 237, 255}; + case fnv1a("cornsilk"): + return CSSColor{255, 248, 220, 255}; + case fnv1a("crimson"): + return CSSColor{220, 20, 60, 255}; + case fnv1a("cyan"): + return CSSColor{0, 255, 255, 255}; + case fnv1a("darkblue"): + return CSSColor{0, 0, 139, 255}; + case fnv1a("darkcyan"): + return CSSColor{0, 139, 139, 255}; + case fnv1a("darkgoldenrod"): + return CSSColor{184, 134, 11, 255}; + case fnv1a("darkgray"): + return CSSColor{169, 169, 169, 255}; + case fnv1a("darkgreen"): + return CSSColor{0, 100, 0, 255}; + case fnv1a("darkgrey"): + return CSSColor{169, 169, 169, 255}; + case fnv1a("darkkhaki"): + return CSSColor{189, 183, 107, 255}; + case fnv1a("darkmagenta"): + return CSSColor{139, 0, 139, 255}; + case fnv1a("darkolivegreen"): + return CSSColor{85, 107, 47, 255}; + case fnv1a("darkorange"): + return CSSColor{255, 140, 0, 255}; + case fnv1a("darkorchid"): + return CSSColor{153, 50, 204, 255}; + case fnv1a("darkred"): + return CSSColor{139, 0, 0, 255}; + case fnv1a("darksalmon"): + return CSSColor{233, 150, 122, 255}; + case fnv1a("darkseagreen"): + return CSSColor{143, 188, 143, 255}; + case fnv1a("darkslateblue"): + return CSSColor{72, 61, 139, 255}; + case fnv1a("darkslategray"): + return CSSColor{47, 79, 79, 255}; + case fnv1a("darkslategrey"): + return CSSColor{47, 79, 79, 255}; + case fnv1a("darkturquoise"): + return CSSColor{0, 206, 209, 255}; + case fnv1a("darkviolet"): + return CSSColor{148, 0, 211, 255}; + case fnv1a("deeppink"): + return CSSColor{255, 20, 147, 255}; + case fnv1a("deepskyblue"): + return CSSColor{0, 191, 255, 255}; + case fnv1a("dimgray"): + return CSSColor{105, 105, 105, 255}; + case fnv1a("dimgrey"): + return CSSColor{105, 105, 105, 255}; + case fnv1a("dodgerblue"): + return CSSColor{30, 144, 255, 255}; + case fnv1a("firebrick"): + return CSSColor{178, 34, 34, 255}; + case fnv1a("floralwhite"): + return CSSColor{255, 250, 240, 255}; + case fnv1a("forestgreen"): + return CSSColor{34, 139, 34, 255}; + case fnv1a("fuchsia"): + return CSSColor{255, 0, 255, 255}; + case fnv1a("gainsboro"): + return CSSColor{220, 220, 220, 255}; + case fnv1a("ghostwhite"): + return CSSColor{248, 248, 255, 255}; + case fnv1a("gold"): + return CSSColor{255, 215, 0, 255}; + case fnv1a("goldenrod"): + return CSSColor{218, 165, 32, 255}; + case fnv1a("gray"): + return CSSColor{128, 128, 128, 255}; + case fnv1a("green"): + return CSSColor{0, 128, 0, 255}; + case fnv1a("greenyellow"): + return CSSColor{173, 255, 47, 255}; + case fnv1a("grey"): + return CSSColor{128, 128, 128, 255}; + case fnv1a("honeydew"): + return CSSColor{240, 255, 240, 255}; + case fnv1a("hotpink"): + return CSSColor{255, 105, 180, 255}; + case fnv1a("indianred"): + return CSSColor{205, 92, 92, 255}; + case fnv1a("indigo"): + return CSSColor{75, 0, 130, 255}; + case fnv1a("ivory"): + return CSSColor{255, 255, 240, 255}; + case fnv1a("khaki"): + return CSSColor{240, 230, 140, 255}; + case fnv1a("lavender"): + return CSSColor{230, 230, 250, 255}; + case fnv1a("lavenderblush"): + return CSSColor{255, 240, 245, 255}; + case fnv1a("lawngreen"): + return CSSColor{124, 252, 0, 255}; + case fnv1a("lemonchiffon"): + return CSSColor{255, 250, 205, 255}; + case fnv1a("lightblue"): + return CSSColor{173, 216, 230, 255}; + case fnv1a("lightcoral"): + return CSSColor{240, 128, 128, 255}; + case fnv1a("lightcyan"): + return CSSColor{224, 255, 255, 255}; + case fnv1a("lightgoldenrodyellow"): + return CSSColor{250, 250, 210, 255}; + case fnv1a("lightgray"): + return CSSColor{211, 211, 211, 255}; + case fnv1a("lightgreen"): + return CSSColor{144, 238, 144, 255}; + case fnv1a("lightgrey"): + return CSSColor{211, 211, 211, 255}; + case fnv1a("lightpink"): + return CSSColor{255, 182, 193, 255}; + case fnv1a("lightsalmon"): + return CSSColor{255, 160, 122, 255}; + case fnv1a("lightseagreen"): + return CSSColor{32, 178, 170, 255}; + case fnv1a("lightskyblue"): + return CSSColor{135, 206, 250, 255}; + case fnv1a("lightslategray"): + return CSSColor{119, 136, 153, 255}; + case fnv1a("lightslategrey"): + return CSSColor{119, 136, 153, 255}; + case fnv1a("lightsteelblue"): + return CSSColor{176, 196, 222, 255}; + case fnv1a("lightyellow"): + return CSSColor{255, 255, 224, 255}; + case fnv1a("lime"): + return CSSColor{0, 255, 0, 255}; + case fnv1a("limegreen"): + return CSSColor{50, 205, 50, 255}; + case fnv1a("linen"): + return CSSColor{250, 240, 230, 255}; + case fnv1a("magenta"): + return CSSColor{255, 0, 255, 255}; + case fnv1a("maroon"): + return CSSColor{128, 0, 0, 255}; + case fnv1a("mediumaquamarine"): + return CSSColor{102, 205, 170, 255}; + case fnv1a("mediumblue"): + return CSSColor{0, 0, 205, 255}; + case fnv1a("mediumorchid"): + return CSSColor{186, 85, 211, 255}; + case fnv1a("mediumpurple"): + return CSSColor{147, 112, 219, 255}; + case fnv1a("mediumseagreen"): + return CSSColor{60, 179, 113, 255}; + case fnv1a("mediumslateblue"): + return CSSColor{123, 104, 238, 255}; + case fnv1a("mediumspringgreen"): + return CSSColor{0, 250, 154, 255}; + case fnv1a("mediumturquoise"): + return CSSColor{72, 209, 204, 255}; + case fnv1a("mediumvioletred"): + return CSSColor{199, 21, 133, 255}; + case fnv1a("midnightblue"): + return CSSColor{25, 25, 112, 255}; + case fnv1a("mintcream"): + return CSSColor{245, 255, 250, 255}; + case fnv1a("mistyrose"): + return CSSColor{255, 228, 225, 255}; + case fnv1a("moccasin"): + return CSSColor{255, 228, 181, 255}; + case fnv1a("navajowhite"): + return CSSColor{255, 222, 173, 255}; + case fnv1a("navy"): + return CSSColor{0, 0, 128, 255}; + case fnv1a("oldlace"): + return CSSColor{253, 245, 230, 255}; + case fnv1a("olive"): + return CSSColor{128, 128, 0, 255}; + case fnv1a("olivedrab"): + return CSSColor{107, 142, 35, 255}; + case fnv1a("orange"): + return CSSColor{255, 165, 0, 255}; + case fnv1a("orangered"): + return CSSColor{255, 69, 0, 255}; + case fnv1a("orchid"): + return CSSColor{218, 112, 214, 255}; + case fnv1a("palegoldenrod"): + return CSSColor{238, 232, 170, 255}; + case fnv1a("palegreen"): + return CSSColor{152, 251, 152, 255}; + case fnv1a("paleturquoise"): + return CSSColor{175, 238, 238, 255}; + case fnv1a("palevioletred"): + return CSSColor{219, 112, 147, 255}; + case fnv1a("papayawhip"): + return CSSColor{255, 239, 213, 255}; + case fnv1a("peachpuff"): + return CSSColor{255, 218, 185, 255}; + case fnv1a("peru"): + return CSSColor{205, 133, 63, 255}; + case fnv1a("pink"): + return CSSColor{255, 192, 203, 255}; + case fnv1a("plum"): + return CSSColor{221, 160, 221, 255}; + case fnv1a("powderblue"): + return CSSColor{176, 224, 230, 255}; + case fnv1a("purple"): + return CSSColor{128, 0, 128, 255}; + case fnv1a("rebeccapurple"): + return CSSColor{102, 51, 153, 255}; + case fnv1a("red"): + return CSSColor{255, 0, 0, 255}; + case fnv1a("rosybrown"): + return CSSColor{188, 143, 143, 255}; + case fnv1a("royalblue"): + return CSSColor{65, 105, 225, 255}; + case fnv1a("saddlebrown"): + return CSSColor{139, 69, 19, 255}; + case fnv1a("salmon"): + return CSSColor{250, 128, 114, 255}; + case fnv1a("sandybrown"): + return CSSColor{244, 164, 96, 255}; + case fnv1a("seagreen"): + return CSSColor{46, 139, 87, 255}; + case fnv1a("seashell"): + return CSSColor{255, 245, 238, 255}; + case fnv1a("sienna"): + return CSSColor{160, 82, 45, 255}; + case fnv1a("silver"): + return CSSColor{192, 192, 192, 255}; + case fnv1a("skyblue"): + return CSSColor{135, 206, 235, 255}; + case fnv1a("slateblue"): + return CSSColor{106, 90, 205, 255}; + case fnv1a("slategray"): + return CSSColor{112, 128, 144, 255}; + case fnv1a("slategrey"): + return CSSColor{112, 128, 144, 255}; + case fnv1a("snow"): + return CSSColor{255, 250, 250, 255}; + case fnv1a("springgreen"): + return CSSColor{0, 255, 127, 255}; + case fnv1a("steelblue"): + return CSSColor{70, 130, 180, 255}; + case fnv1a("tan"): + return CSSColor{210, 180, 140, 255}; + case fnv1a("teal"): + return CSSColor{0, 128, 128, 255}; + case fnv1a("thistle"): + return CSSColor{216, 191, 216, 255}; + case fnv1a("tomato"): + return CSSColor{255, 99, 71, 255}; + case fnv1a("transparent"): + return CSSColor{0, 0, 0, 0}; + case fnv1a("turquoise"): + return CSSColor{64, 224, 208, 255}; + case fnv1a("violet"): + return CSSColor{238, 130, 238, 255}; + case fnv1a("wheat"): + return CSSColor{245, 222, 179, 255}; + case fnv1a("white"): + return CSSColor{255, 255, 255, 255}; + case fnv1a("whitesmoke"): + return CSSColor{245, 245, 245, 255}; + case fnv1a("yellow"): + return CSSColor{255, 255, 0, 255}; + case fnv1a("yellowgreen"): + return CSSColor{154, 205, 50, 255}; + default: + return std::nullopt; + } +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSNumber.h b/packages/react-native/ReactCommon/react/renderer/css/CSSNumber.h new file mode 100644 index 00000000000..328ace3d2b0 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSNumber.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include + +namespace facebook::react { + +/** + * Representation of CSS data type + * https://www.w3.org/TR/css-values-4/#numbers + */ +struct CSSNumber { + float value{}; +}; + +template <> +struct CSSDataTypeParser { + static constexpr auto consumePreservedToken(const CSSPreservedToken& token) + -> std::optional { + if (token.type() == CSSTokenType::Number) { + return CSSNumber{token.numericValue()}; + } + + return {}; + } +}; + +static_assert(CSSDataType); + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSPercentage.h b/packages/react-native/ReactCommon/react/renderer/css/CSSPercentage.h new file mode 100644 index 00000000000..329c92c7154 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSPercentage.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include + +namespace facebook::react { + +/** + * Representation of CSS data type + * https://www.w3.org/TR/css-values-4/#percentages + */ +struct CSSPercentage { + float value{}; +}; + +template <> +struct CSSDataTypeParser { + static constexpr auto consumePreservedToken(const CSSPreservedToken& token) + -> std::optional { + if (token.type() == CSSTokenType::Percentage) { + return CSSPercentage{token.numericValue()}; + } + + return {}; + } +}; + +static_assert(CSSDataType); + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSProperties.h b/packages/react-native/ReactCommon/react/renderer/css/CSSProperties.h deleted file mode 100644 index 637bab85bbb..00000000000 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSProperties.h +++ /dev/null @@ -1,1287 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include - -namespace facebook::react { - -/** - * All CSS properties,including CSS,and React-Native specific shorthands - * https://www.w3.org/TR/css-cascade-4/#css-property - */ -enum class CSSProp { - AlignContent, - AlignItems, - AlignSelf, - AspectRatio, - BorderBlockEndStyle, - BorderBlockEndWidth, - BorderBlockStartStyle, - BorderBlockStartWidth, - BorderBlockStyle, - BorderBlockWidth, - BorderBottomLeftRadius, - BorderBottomRightRadius, - BorderBottomStyle, - BorderBottomWidth, - BorderEndEndRadius, - BorderEndStartRadius, - BorderEndWidth, - BorderHorizontalWidth, - BorderInlineEndStyle, - BorderInlineEndWidth, - BorderInlineStartStyle, - BorderInlineStartWidth, - BorderInlineStyle, - BorderInlineWidth, - BorderLeftStyle, - BorderLeftWidth, - BorderRadius, - BorderRightStyle, - BorderRightWidth, - BorderStartEndRadius, - BorderStartStartRadius, - BorderStartWidth, - BorderStyle, - BorderTopLeftRadius, - BorderTopRightRadius, - BorderTopStyle, - BorderTopWidth, - BorderVerticalWidth, - BorderWidth, - Bottom, - ColumnGap, - Direction, - Display, - End, - Flex, - FlexBasis, - FlexDirection, - FlexGrow, - FlexShrink, - FlexWrap, - Gap, - Height, - Inset, - InsetBlock, - InsetBlockEnd, - InsetBlockStart, - InsetInline, - InsetInlineEnd, - InsetInlineStart, - JustifyContent, - Left, - Margin, - MarginBlock, - MarginBlockEnd, - MarginBlockStart, - MarginBottom, - MarginEnd, - MarginHorizontal, - MarginInline, - MarginInlineEnd, - MarginInlineStart, - MarginLeft, - MarginRight, - MarginStart, - MarginTop, - MarginVertical, - MaxHeight, - MaxWidth, - MinHeight, - MinWidth, - Opacity, - Overflow, - Padding, - PaddingBlock, - PaddingBlockEnd, - PaddingBlockStart, - PaddingBottom, - PaddingEnd, - PaddingHorizontal, - PaddingInline, - PaddingInlineEnd, - PaddingInlineStart, - PaddingLeft, - PaddingRight, - PaddingStart, - PaddingTop, - PaddingVertical, - Position, - Right, - RowGap, - Start, - Top, - Width, - // Please update "kCSSPropCount" if adding a new prop to the end -}; - -/** - * The total number of CSS properties. - */ -constexpr auto kCSSPropCount = to_underlying(CSSProp::Width) + 1; - -/** - * CSSPropDefinition associates a CSSProp to its - * supported data types, Keyword, and other behaviors. - */ -template -struct CSSPropDefinition {}; - -template -using CSSDeclaredValue = typename CSSPropDefinition

::DeclaredValue; - -template -using CSSSpecifiedValue = typename CSSPropDefinition

::SpecifiedValue; - -template -using CSSComputedValue = typename CSSPropDefinition

::ComputedValue; - -/** - * Whether to behave in accordance with W3C specs, or to incorporate React - * Native specific tweaks to defaults and computation. - */ -enum class CSSFlavor { - W3C, - ReactNative, -}; - -/** - * CSS "align-content" property. - * https://www.w3.org/TR/css-flexbox-1/#align-content-property - * https://www.w3.org/TR/css-align-3/#align-justify-content - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "alignContent"; - - enum class Keyword : std::underlying_type_t { - Center = to_underlying(CSSKeyword::Center), - FlexEnd = to_underlying(CSSKeyword::FlexEnd), - FlexStart = to_underlying(CSSKeyword::FlexStart), - SpaceAround = to_underlying(CSSKeyword::SpaceAround), - SpaceBetween = to_underlying(CSSKeyword::SpaceBetween), - SpaceEvenly = to_underlying(CSSKeyword::SpaceEvenly), - Stretch = to_underlying(CSSKeyword::Stretch), - Start = to_underlying(CSSKeyword::Start), - End = to_underlying(CSSKeyword::End), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor flavor) { - return flavor == CSSFlavor::W3C - ? DeclaredValue::keyword(Keyword::Stretch) - : DeclaredValue::keyword(Keyword::FlexStart); - } -}; - -/** - * CSS "align-items" property. - * https://www.w3.org/TR/css-flexbox-1/#align-items-property - * https://www.w3.org/TR/css-align-3/#align-items-property - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "alignItems"; - - enum class Keyword : std::underlying_type_t { - Baseline = to_underlying(CSSKeyword::Baseline), - Center = to_underlying(CSSKeyword::Center), - FlexEnd = to_underlying(CSSKeyword::FlexEnd), - FlexStart = to_underlying(CSSKeyword::FlexStart), - Stretch = to_underlying(CSSKeyword::Stretch), - Start = to_underlying(CSSKeyword::Start), - End = to_underlying(CSSKeyword::End), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Stretch); - } -}; - -/** - * CSS "align-self" property. - * https://www.w3.org/TR/css-flexbox-1/#propdef-align-self - * https://www.w3.org/TR/css-align-3/#align-self-property - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "alignSelf"; - - enum class Keyword : std::underlying_type_t { - Auto = to_underlying(CSSKeyword::Auto), - Baseline = to_underlying(CSSKeyword::Baseline), - Center = to_underlying(CSSKeyword::Center), - FlexEnd = to_underlying(CSSKeyword::FlexEnd), - FlexStart = to_underlying(CSSKeyword::FlexStart), - Stretch = to_underlying(CSSKeyword::Stretch), - Start = to_underlying(CSSKeyword::Start), - End = to_underlying(CSSKeyword::End), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Auto); - } -}; - -/** - * CSS "aspect-ratio" property. - * https://www.w3.org/TR/css-sizing-4/#aspect-ratio - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "aspectRatio"; - - enum class Keyword : std::underlying_type_t { - Auto = to_underlying(CSSKeyword::Auto), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Auto); - } -}; - -/** - * CSS "border-radius" properties - * https://www.w3.org/TR/css-backgrounds-3/#border-radius - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "borderRadius"; - - using DeclaredValue = - CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::length(0.0f, CSSLengthUnit::Px); - } -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderTopLeftRadius"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderTopRightRadius"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBottomLeftRadius"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBottomRightRadius"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderStartStartRadius"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderStartEndRadius"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderEndStartRadius"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderEndEndRadius"; -}; - -/** - * CSS "border-style" properties - * https://www.w3.org/TR/css-backgrounds-3/#border-style - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "borderStyle"; - - enum class Keyword : std::underlying_type_t { - None = to_underlying(CSSKeyword::None), - Hidden = to_underlying(CSSKeyword::Hidden), - Dotted = to_underlying(CSSKeyword::Dotted), - Dashed = to_underlying(CSSKeyword::Dashed), - Solid = to_underlying(CSSKeyword::Solid), - Double = to_underlying(CSSKeyword::Double), - Groove = to_underlying(CSSKeyword::Groove), - Ridge = to_underlying(CSSKeyword::Ridge), - Inset = to_underlying(CSSKeyword::Inset), - Outset = to_underlying(CSSKeyword::Outset), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor flavor) { - return flavor == CSSFlavor::W3C ? DeclaredValue::keyword(Keyword::None) - : DeclaredValue::keyword(Keyword::Solid); - } -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBlockEndStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBlockStartStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBlockStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBottomStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderInlineEndStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderInlineStartStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderInlineStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderLeftStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderRightStyle"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderTopStyle"; -}; - -/** - * CSS "border-width" properties - * https://www.w3.org/TR/css-backgrounds-3/#border-width - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "borderWidth"; - - enum class Keyword : std::underlying_type_t { - Thin = to_underlying(CSSKeyword::Thin), - Medium = to_underlying(CSSKeyword::Medium), - Thick = to_underlying(CSSKeyword::Thick), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor flavor) { - return flavor == CSSFlavor::W3C - ? DeclaredValue::keyword(Keyword::Medium) - : DeclaredValue::length(0.0f, CSSLengthUnit::Px); - } -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBlockEndWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBlockStartWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBlockWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderBottomWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderEndWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderHorizontalWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderInlineEndWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderInlineStartWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderInlineWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderLeftWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderRightWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderStartWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderTopWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "borderVerticalWidth"; -}; - -/** - * CSS "direction" property. - * https://www.w3.org/TR/css-writing-modes-3/#direction - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "direction"; - - enum class Keyword : std::underlying_type_t { - Ltr = to_underlying(CSSKeyword::Ltr), - Rtl = to_underlying(CSSKeyword::Rtl), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return true; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Ltr); - } -}; - -/** - * CSS "display" property. - * https://www.w3.org/TR/css-display-3/#display-type - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "display"; - - enum class Keyword : std::underlying_type_t { - None = to_underlying(CSSKeyword::None), - Contents = to_underlying(CSSKeyword::Contents), - Inline = to_underlying(CSSKeyword::Inline), - Block = to_underlying(CSSKeyword::Block), - InlineBlock = to_underlying(CSSKeyword::InlineBlock), - Flex = to_underlying(CSSKeyword::Flex), - InlineFlex = to_underlying(CSSKeyword::InlineFlex), - Grid = to_underlying(CSSKeyword::Grid), - InlineGrid = to_underlying(CSSKeyword::InlineGrid), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor flavor) { - return flavor == CSSFlavor::W3C ? DeclaredValue::keyword(Keyword::Inline) - : DeclaredValue::keyword(Keyword::Flex); - } -}; - -/** - * CSS "flex" shorthand property. - * https://www.w3.org/TR/css-flexbox-1/#flex-property - * - * React Native's interpretation of this prop is currently different than in - * CSS. https://reactnative.dev/docs/layout-props#flex - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "flex"; - - enum class Keyword : std::underlying_type_t { - Auto = to_underlying(CSSKeyword::Auto), - None = to_underlying(CSSKeyword::None), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::number(0.0f); - } -}; - -/** - * CSS "flex-basis" property. - * https://www.w3.org/TR/css-flexbox-1/#flex-basis-property - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "flexBasis"; - - enum class Keyword : std::underlying_type_t { - Auto = to_underlying(CSSKeyword::Auto), - Content = to_underlying(CSSKeyword::Content), - }; - - using DeclaredValue = - CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Auto); - } -}; - -/** - * CSS "flex-direction" property. - * https://www.w3.org/TR/css-flexbox-1/#flex-direction-property - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "flexDirection"; - - enum class Keyword : std::underlying_type_t { - Row = to_underlying(CSSKeyword::Row), - RowReverse = to_underlying(CSSKeyword::RowReverse), - Column = to_underlying(CSSKeyword::Column), - ColumnReverse = to_underlying(CSSKeyword::ColumnReverse), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor flavor) { - return flavor == CSSFlavor::W3C ? DeclaredValue::keyword(Keyword::Row) - : DeclaredValue::keyword(Keyword::Column); - } -}; - -/** - * CSS "flex-grow" property. - * https://www.w3.org/TR/css-flexbox-1/#flex-grow-property - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "flexGrow"; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::number(0.0f); - } -}; - -/** - * CSS "flex-shrink" property. - * https://www.w3.org/TR/css-flexbox-1/#flex-shrink-property - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "flexShrink"; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor flavor) { - return flavor == CSSFlavor::W3C ? DeclaredValue::number(1.0f) - : DeclaredValue::number(0.0f); - } -}; - -/** - * CSS "flex-wrap" property. - * https://www.w3.org/TR/css-flexbox-1/#flex-wrap-property - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "flexWrap"; - - enum class Keyword : std::underlying_type_t { - NoWrap = to_underlying(CSSKeyword::NoWrap), - Wrap = to_underlying(CSSKeyword::Wrap), - WrapReverse = to_underlying(CSSKeyword::WrapReverse), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::NoWrap); - } -}; - -/** - * CSS gutter properties. - * https://www.w3.org/TR/css-align-3/#column-row-gap - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "gap"; - - enum class Keyword : std::underlying_type_t { - Normal = to_underlying(CSSKeyword::Normal), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Normal); - } -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "columnGap"; -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "rowGap"; -}; - -/** - * CSS sizing properties - * https://www.w3.org/TR/css-sizing-3/#sizing-properties - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "height"; - - enum class Keyword : std::underlying_type_t { - Auto = to_underlying(CSSKeyword::Auto), - MaxContent = to_underlying(CSSKeyword::MaxContent), - MinContent = to_underlying(CSSKeyword::MinContent), - }; - - using DeclaredValue = - CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Auto); - } -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "width"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "minWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "minHeight"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "maxWidth"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "maxHeight"; -}; - -/** - * CSS box inset properties - * https://drafts.csswg.org/css-position-3/#insets - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "inset"; - - enum class Keyword : std::underlying_type_t { - Auto = to_underlying(CSSKeyword::Auto), - }; - - using DeclaredValue = - CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Auto); - } -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "top"; -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "right"; -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "bottom"; -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "left"; -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "start"; -}; - -template <> -struct CSSPropDefinition : CSSPropDefinition { - constexpr static std::string_view kName = "end"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "insetBlock"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "insetBlockEnd"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "insetBlockStart"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "insetInline"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "insetInlineEnd"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "insetInlineStart"; -}; - -/** - * CSS "justify-content" property. - * https://www.w3.org/TR/css-flexbox-1/#justify-content-property - * https://www.w3.org/TR/css-align-3/#align-justify-content - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "justifyContent"; - - enum class Keyword : std::underlying_type_t { - Center = to_underlying(CSSKeyword::Center), - FlexEnd = to_underlying(CSSKeyword::FlexEnd), - FlexStart = to_underlying(CSSKeyword::FlexStart), - SpaceAround = to_underlying(CSSKeyword::SpaceAround), - SpaceBetween = to_underlying(CSSKeyword::SpaceBetween), - SpaceEvenly = to_underlying(CSSKeyword::SpaceEvenly), - Start = to_underlying(CSSKeyword::Start), - End = to_underlying(CSSKeyword::End), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::FlexStart); - } -}; - -/** - * CSS "margin" properties - * https://www.w3.org/TR/css-box-4/#margins - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "margin"; - - enum class Keyword : std::underlying_type_t { - Auto = to_underlying(CSSKeyword::Auto), - }; - - using DeclaredValue = - CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::length(0.0f, CSSLengthUnit::Px); - } -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginBlock"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginBlockEnd"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginBlockStart"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginBottom"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginEnd"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginHorizontal"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginInline"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginInlineEnd"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginInlineStart"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginLeft"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginRight"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginStart"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginTop"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "marginVertical"; -}; - -/** - * CSS "opacity" property - * https://www.w3.org/TR/css-color-3/#transparency - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "opacity"; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::number(1.0f); - } -}; - -/** - * CSS "overflow" property. - * https://www.w3.org/TR/css-overflow-3/#overflow-control - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "overflow"; - - enum class Keyword : std::underlying_type_t { - Auto = to_underlying(CSSKeyword::Auto), - Clip = to_underlying(CSSKeyword::Clip), - Hidden = to_underlying(CSSKeyword::Hidden), - Scroll = to_underlying(CSSKeyword::Scroll), - Visible = to_underlying(CSSKeyword::Visible), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::keyword(Keyword::Visible); - } -}; - -/** - * CSS padding properties - * https://www.w3.org/TR/css-box-4/#paddings - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "padding"; - - using DeclaredValue = - CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) { - return DeclaredValue::length(0.0f, CSSLengthUnit::Px); - } -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingBlock"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingBlockEnd"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingBlockStart"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingBottom"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingEnd"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingHorizontal"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingInline"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingInlineEnd"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingInlineStart"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingLeft"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingRight"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingStart"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingTop"; -}; - -template <> -struct CSSPropDefinition - : CSSPropDefinition { - constexpr static std::string_view kName = "paddingVertical"; -}; - -/** - * CSS "position" property. - * https://www.w3.org/TR/css-position-3/#position-property - */ -template <> -struct CSSPropDefinition { - constexpr static std::string_view kName = "position"; - - enum class Keyword : std::underlying_type_t { - Static = to_underlying(CSSKeyword::Static), - Relative = to_underlying(CSSKeyword::Relative), - Absolute = to_underlying(CSSKeyword::Absolute), - Fixed = to_underlying(CSSKeyword::Fixed), - Sticky = to_underlying(CSSKeyword::Sticky), - }; - - using DeclaredValue = CSSValueVariant; - using SpecifiedValue = CSSValueVariant; - using ComputedValue = CSSValueVariant; - - constexpr static bool isInherited() { - return false; - } - - constexpr static DeclaredValue initialValue(CSSFlavor flavor) { - return flavor == CSSFlavor::W3C ? DeclaredValue::keyword(Keyword::Static) - : DeclaredValue::keyword(Keyword::Relative); - } -}; - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSRatio.h b/packages/react-native/ReactCommon/react/renderer/css/CSSRatio.h new file mode 100644 index 00000000000..f6ed8d1ea5d --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSRatio.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace facebook::react { + +/** + * Representation of CSS data type + * https://www.w3.org/TR/css-values-4/#ratios + */ +struct CSSRatio { + float numerator{}; + float denominator{}; +}; + +template <> +struct CSSDataTypeParser { + static constexpr auto consumePreservedToken( + const CSSPreservedToken& token, + CSSSyntaxParser& parser) -> std::optional { + // = [ / ]? + // https://www.w3.org/TR/css-values-4/#ratio + if (isValidRatioPart(token.numericValue())) { + float numerator = token.numericValue(); + + CSSSyntaxParser lookaheadParser{parser}; + + auto hasSolidus = lookaheadParser.consumeComponentValue( + CSSComponentValueDelimiter::Whitespace, + [&](const CSSPreservedToken& token) { + return token.type() == CSSTokenType::Delim && + token.stringValue() == "/"; + }); + + if (!hasSolidus) { + parser = lookaheadParser; + return CSSRatio{numerator, 1.0f}; + } + + auto denominator = parseNextCSSValue( + lookaheadParser, CSSComponentValueDelimiter::Whitespace); + + if (std::holds_alternative(denominator) && + isValidRatioPart(std::get(denominator).value)) { + parser = lookaheadParser; + return CSSRatio{numerator, std::get(denominator).value}; + } + } + + return {}; + } + + private: + static constexpr bool isValidRatioPart(float value) { + // If either number in the is 0 or infinite, it represents a + // degenerate ratio (and, generally, won’t do anything). + // https://www.w3.org/TR/css-values-4/#ratios + return value > 0.0f && value != +std::numeric_limits::infinity() && + value != -std::numeric_limits::infinity(); + } +}; + +static_assert(CSSDataType); + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSSyntaxParser.h b/packages/react-native/ReactCommon/react/renderer/css/CSSSyntaxParser.h index a46e490fade..2b5eaf78020 100644 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSSyntaxParser.h +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSSyntaxParser.h @@ -251,50 +251,63 @@ struct CSSComponentValueVisitorDispatcher { return consumeComponentValue(std::forward(visitors)...); } - constexpr std::optional visitFunction(const VisitorsT&... visitors) { - for (auto visitor : {visitors...}) { - if constexpr (CSSFunctionVisitor) { - auto functionValue = - visitor({.name = parser.consumeToken().stringValue()}); - parser.consumeWhitespace(); - if (parser.peek().type() == CSSTokenType::CloseParen) { - parser.consumeToken(); - return functionValue; - } - - return {}; + constexpr std::optional visitFunction( + const CSSComponentValueVisitor auto& visitor, + const CSSComponentValueVisitor auto&... rest) { + if constexpr (CSSFunctionVisitor) { + auto functionValue = + visitor({.name = parser.consumeToken().stringValue()}); + parser.consumeWhitespace(); + if (parser.peek().type() == CSSTokenType::CloseParen) { + parser.consumeToken(); + return functionValue; } + + return {}; } + return visitFunction(rest...); + } + + constexpr std::optional visitFunction() { return {}; } + // Can be one of std::monostate (variant null-type), CSSWideKeyword, + // CSSLength, or CSSPercentage + constexpr std::optional visitSimpleBlock( CSSTokenType endToken, - const VisitorsT&... visitors) { - for (auto visitor : {visitors...}) { - if constexpr (CSSSimpleBlockVisitor) { - auto blockValue = - visitor({.openBracketType = parser.consumeToken().type()}); - parser.consumeWhitespace(); - if (parser.peek().type() == endToken) { - parser.consumeToken(); - return blockValue; - } - - return {}; + const CSSComponentValueVisitor auto& visitor, + const CSSComponentValueVisitor auto&... rest) { + if constexpr (CSSSimpleBlockVisitor) { + auto blockValue = + visitor({.openBracketType = parser.consumeToken().type()}); + parser.consumeWhitespace(); + if (parser.peek().type() == endToken) { + parser.consumeToken(); + return blockValue; } + + return {}; } + return visitSimpleBlock(endToken, rest...); + } + + constexpr std::optional visitSimpleBlock(CSSTokenType /*endToken*/) { return {}; } constexpr std::optional visitPreservedToken( - const VisitorsT&... visitors) { - for (auto visitor : {visitors...}) { - if constexpr (CSSPreservedTokenVisitor) { - return visitor(parser.consumeToken()); - } + const CSSComponentValueVisitor auto& visitor, + const CSSComponentValueVisitor auto&... rest) { + if constexpr (CSSPreservedTokenVisitor) { + return visitor(parser.consumeToken()); } + return visitPreservedToken(rest...); + } + + constexpr std::optional visitPreservedToken() { return {}; } }; diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSValue.h b/packages/react-native/ReactCommon/react/renderer/css/CSSValue.h deleted file mode 100644 index 1b39c78caf5..00000000000 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSValue.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#include -#include - -namespace facebook::react { - -/** - * Represents a CSS component value type. - * https://www.w3.org/TR/css-values-4/#component-types - */ -enum class CSSValueType : uint8_t { - CSSWideKeyword, - Keyword, - Length, - Number, - Percentage, - Ratio, - Angle, - Color, -}; - -/** - * Concrete representation for a CSS basic data type, or keywords - * https://www.w3.org/TR/css-values-4/#component-types - */ -template -concept CSSDataType = std::is_trivially_destructible_v && - std::is_copy_constructible_v && std::is_default_constructible_v; - -#pragma pack(push, 1) -/** - * Representation of CSS data type - * https://www.w3.org/TR/css-values-4/#lengths - */ -struct CSSLength { - float value{}; - CSSLengthUnit unit{CSSLengthUnit::Px}; -}; -#pragma pack(pop) - -/** - * Representation of CSS data type - * https://www.w3.org/TR/css-values-4/#percentages - */ -struct CSSPercentage { - float value{}; -}; - -/** - * Representation of CSS data type - * https://www.w3.org/TR/css-values-4/#numbers - */ -struct CSSNumber { - float value{}; -}; - -/** - * Representation of CSS data type - * https://www.w3.org/TR/css-values-4/#ratios - */ -struct CSSRatio { - float numerator{}; - float denominator{}; -}; - -/** - * Representation of CSS data type - * https://www.w3.org/TR/css-values-4/#angles - */ -struct CSSAngle { - float degrees{}; -}; - -/** - * Representation of CSS data type - * https://www.w3.org/TR/css-color-5/#typedef-color - */ -struct CSSColor { - uint8_t r{}; - uint8_t g{}; - uint8_t b{}; - uint8_t a{}; -}; - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSValueParser.h b/packages/react-native/ReactCommon/react/renderer/css/CSSValueParser.h index 7a196e2e4b2..953bceea5e9 100644 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSValueParser.h +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSValueParser.h @@ -9,83 +9,49 @@ #include #include +#include -#include -#include -#include +#include +#include #include -#include namespace facebook::react { namespace detail { -template class CSSValueParser { - using CSSValue = CSSValueVariant; - public: - explicit constexpr CSSValueParser(std::string_view css) : parser_{css} {} + explicit constexpr CSSValueParser(CSSSyntaxParser& parser) + : parser_{parser} {} /* * Attempts to parse the characters starting at the current component value - * into one of the given data types. + * into one of the given data types. Types are attempted in order, which the + * caller must consider (e.g. a number token should be preferred to be a + * before ). */ - constexpr CSSValue consumeValue( + template + constexpr std::variant consumeValue( CSSComponentValueDelimiter delimeter = CSSComponentValueDelimiter::None) { - return parser_.consumeComponentValue( - delimeter, [&](const CSSPreservedToken& token) { - // CSS-global keywords - if constexpr (hasType()) { - if (auto cssWideKeyword = consumeCSSWideKeyword(token)) { - return *cssWideKeyword; - } - } - // Property-specific keywords - if constexpr (hasType()) { - if (auto keyword = consumeKeyword(token)) { - return *keyword; - } - } - // - if constexpr (hasType()) { - if (auto ratio = consumeRatio(token)) { - return *ratio; - } - } - // - if constexpr (hasType()) { - if (auto number = consumeNumber(token)) { - return *number; - } - } - // - if constexpr (hasType()) { - if (auto length = consumeLength(token)) { - return *length; - } - } - // - if constexpr (hasType()) { - if (auto angle = consumeAngle(token)) { - return *angle; - } - } - // - if constexpr (hasType()) { - if (auto percentage = consumePercentage(token)) { - return *percentage; - } - } - // - if constexpr (hasType()) { - if (auto colorValue = consumeColorToken(token)) { - return *colorValue; - } - } - return CSSValue{}; + using ReturnT = std::variant; + + return parser_.consumeComponentValue( + delimeter, + [&](const CSSPreservedToken& token) { + return tryConsumePreservedToken< + ReturnT, + CSSDataTypeParser...>(token); + }, + [&](const CSSSimpleBlock& block) { + return tryConsumeSimpleBlock< + ReturnT, + CSSDataTypeParser...>(block); + }, + [&](const CSSFunctionBlock& func) { + return tryConsumeFunctionBlock< + ReturnT, + CSSDataTypeParser...>(func); }); - // TODO: support function component values and simple blocks } constexpr bool isFinished() const { @@ -97,221 +63,108 @@ class CSSValueParser { } private: - template - constexpr static bool hasType() { - return traits::containsType(); - } - - template - constexpr static bool hasType() { - return false; - } - - constexpr std::optional consumeKeyword( - const CSSPreservedToken& token) { - if (token.type() == CSSTokenType::Ident) { - if (auto keyword = parseCSSKeyword( - token.stringValue())) { - return CSSValue::keyword(*keyword); - } - } + template + constexpr ReturnT tryConsumePreservedToken( + const CSSPreservedToken& /*token*/) { return {}; } - constexpr std::optional consumeCSSWideKeyword( - const CSSPreservedToken& token) { - if (token.type() == CSSTokenType::Ident) { - if (auto keyword = parseCSSKeyword(token.stringValue())) { - return CSSValue::cssWideKeyword(*keyword); - } - } - return {}; - } - - constexpr std::optional consumeAngle( - const CSSPreservedToken& token) { - if (token.type() == CSSTokenType::Dimension) { - if (auto unit = parseCSSAngleUnit(token.unit())) { - return CSSValue::angle(canonicalize(token.numericValue(), *unit)); - } - } - return {}; - } - - constexpr std::optional consumePercentage( - const CSSPreservedToken& token) { - if (token.type() == CSSTokenType::Percentage) { - return CSSValue::percentage(token.numericValue()); - } - - return {}; - } - - constexpr std::optional consumeNumber( - const CSSPreservedToken& token) { - if (token.type() == CSSTokenType::Number) { - return CSSValue::number(token.numericValue()); - } - - return {}; - } - - constexpr std::optional consumeLength( - const CSSPreservedToken& token) { - switch (token.type()) { - case CSSTokenType::Dimension: - if (auto unit = parseCSSLengthUnit(token.unit())) { - return CSSValue::length(token.numericValue(), *unit); - } - break; - case CSSTokenType::Number: - // For zero lengths the unit identifier is optional (i.e. can be - // syntactically represented as the 0). However, if a 0 - // could be parsed as either a or a in a - // property (such as line-height), it must parse as a . - // https://www.w3.org/TR/css-values-4/#lengths - if (token.numericValue() == 0) { - return CSSValue::length(token.numericValue(), CSSLengthUnit::Px); - } - break; - default: - break; - } - - return {}; - } - - constexpr std::optional consumeRatio( - const CSSPreservedToken& token) { - // = [ / ]? - // https://www.w3.org/TR/css-values-4/#ratio - if (isValidRatioPart(token.numericValue())) { - float numerator = token.numericValue(); - - CSSSyntaxParser lookaheadParser{parser_}; - - auto hasSolidus = lookaheadParser.consumeComponentValue( - CSSComponentValueDelimiter::Whitespace, - [&](const CSSPreservedToken& token) { - return token.type() == CSSTokenType::Delim && - token.stringValue() == "/"; - }); - - if (!hasSolidus) { - return CSSValue::ratio(numerator, 1.0f); - } - - // TODO: support math expression substituion for - auto denominator = - lookaheadParser.consumeComponentValue>( - CSSComponentValueDelimiter::Whitespace, - [&](const CSSPreservedToken& token) { - if (token.type() == CSSTokenType::Number && - isValidRatioPart(token.numericValue())) { - return std::optional(token.numericValue()); - } - return std::optional{}; - }); - - if (denominator.has_value()) { - parser_ = lookaheadParser; - return CSSValue::ratio(numerator, *denominator); + template < + typename ReturnT, + CSSValidDataTypeParser ParserT, + CSSValidDataTypeParser... RestParserT> + constexpr ReturnT tryConsumePreservedToken(const CSSPreservedToken& token) { + if constexpr (CSSPreservedTokenSink) { + if (auto ret = ParserT::consumePreservedToken(token, parser_)) { + return *ret; } } - return {}; - } - - constexpr bool isValidRatioPart(float value) { - // If either number in the is 0 or infinite, it represents a - // degenerate ratio (and, generally, won’t do anything). - // https://www.w3.org/TR/css-values-4/#ratios - return value > 0.0f && value != +std::numeric_limits::infinity() && - value != -std::numeric_limits::infinity(); - } - - constexpr std::optional consumeColorToken( - const CSSPreservedToken& token) { - if (token.type() == CSSTokenType::Ident) { - return parseCSSNamedColor(token.stringValue()); - } else if (token.type() != CSSTokenType::Hash) { - return {}; - } - - // https://www.w3.org/TR/css-color-4/#hex-color - std::string_view hexColorValue = token.stringValue(); - if (isValidHexColor(hexColorValue)) { - if (hexColorValue.length() == 3) { - return CSSValue::color( - hexToNumeric(hexColorValue.substr(0, 1), HexColorType::Short), - hexToNumeric(hexColorValue.substr(1, 1), HexColorType::Short), - hexToNumeric(hexColorValue.substr(2, 1), HexColorType::Short), - 255u); - } else if (hexColorValue.length() == 4) { - return CSSValue::color( - hexToNumeric(hexColorValue.substr(0, 1), HexColorType::Short), - hexToNumeric(hexColorValue.substr(1, 1), HexColorType::Short), - hexToNumeric(hexColorValue.substr(2, 1), HexColorType::Short), - hexToNumeric(hexColorValue.substr(3, 1), HexColorType::Short)); - } else if (hexColorValue.length() == 6) { - return CSSValue::color( - hexToNumeric(hexColorValue.substr(0, 2), HexColorType::Long), - hexToNumeric(hexColorValue.substr(2, 2), HexColorType::Long), - hexToNumeric(hexColorValue.substr(4, 2), HexColorType::Long), - 255u); - } else if (hexColorValue.length() == 8) { - return CSSValue::color( - hexToNumeric(hexColorValue.substr(0, 2), HexColorType::Long), - hexToNumeric(hexColorValue.substr(2, 2), HexColorType::Long), - hexToNumeric(hexColorValue.substr(4, 2), HexColorType::Long), - hexToNumeric(hexColorValue.substr(6, 2), HexColorType::Long)); + if constexpr (CSSSimplePreservedTokenSink) { + if (auto ret = ParserT::consumePreservedToken(token)) { + return *ret; } } + + return tryConsumePreservedToken(token); + } + + template + constexpr ReturnT tryConsumeSimpleBlock(const CSSSimpleBlock& /*token*/) { return {}; } - CSSSyntaxParser parser_; -}; + template < + typename ReturnT, + CSSValidDataTypeParser ParserT, + CSSValidDataTypeParser... RestParserT> + constexpr ReturnT tryConsumeSimpleBlock(const CSSSimpleBlock& block) { + if constexpr (CSSSimpleBlockSink) { + if (auto ret = ParserT::consumeSimpleBlock(block, parser_)) { + return *ret; + } + } -template -constexpr void parseCSSValue( - std::string_view css, - CSSValueVariant& value) { - detail::CSSValueParser parser(css); - - parser.consumeWhitespace(); - auto componentValue = parser.consumeValue(); - parser.consumeWhitespace(); - - if (parser.isFinished()) { - value = std::move(componentValue); - } else { - value = {}; + return tryConsumeSimpleBlock(block); } + + template + constexpr ReturnT tryConsumeFunctionBlock(const CSSFunctionBlock& /*func*/) { + return {}; + } + + template < + typename ReturnT, + CSSValidDataTypeParser ParserT, + CSSValidDataTypeParser... RestParserT> + constexpr ReturnT tryConsumeFunctionBlock(const CSSFunctionBlock& func) { + if constexpr (CSSFunctionBlockSink) { + if (auto ret = ParserT::consumeFunctionBlock(func, parser_)) { + return *ret; + } + } + + return tryConsumeFunctionBlock(func); + } + + CSSSyntaxParser& parser_; }; } // namespace detail /** - * Parse a single CSS value. Returns a default-constructed - * CSSValueVariant (CSSKeyword::Unset) on syntax error. + * Parse a single CSS property value. Returns a variant holding std::monostate + * on syntax error. */ template -CSSValueVariant parseCSSValue(std::string_view css) { - CSSValueVariant value; - detail::parseCSSValue(css, value); - return value; +constexpr auto parseCSSProperty(std::string_view css) + -> std::variant { + CSSSyntaxParser syntaxParser(css); + detail::CSSValueParser parser(syntaxParser); + + parser.consumeWhitespace(); + auto value = parser.consumeValue(); + parser.consumeWhitespace(); + + if (parser.isFinished()) { + return value; + } + + return {}; }; /** - * Parses a CSS property into its declared value type. + * Attempts to parse the next CSS value of a given set of data types, at the + * current location of the syntax parser, advancing the syntax parser if + * successful. */ -template -constexpr CSSDeclaredValue parseCSSProp(std::string_view css) { - // For now we only allow parsing props composed of a single component value. - CSSDeclaredValue value; - detail::parseCSSValue(css, value); - return value; +template +constexpr auto parseNextCSSValue( + CSSSyntaxParser& syntaxParser, + CSSComponentValueDelimiter delimeter = CSSComponentValueDelimiter::None) + -> std::variant { + detail::CSSValueParser valueParser(syntaxParser); + return valueParser.consumeValue(delimeter); } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSValueVariant.h b/packages/react-native/ReactCommon/react/renderer/css/CSSValueVariant.h deleted file mode 100644 index b063c13d4e2..00000000000 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSValueVariant.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -#include -#include - -namespace facebook::react { - -/** - * CSSValueVariant represents a CSS component value: - * https://www.w3.org/TR/css-values-4/#component-types - * - * A CSSValueVariant must be constrained to the set of possible CSS types it may - * encounter. E.g. a dimension which accepts a CSS-wide keywords, "auto" or a - * would be modeled as - * `CSSValueVariant`. This - * allows for efficient storage, and customizing parsing based on the allowed - * set of values. - */ -#pragma pack(push, 1) -template -class CSSValueVariant { - template - static constexpr bool canRepresent() { - return traits::containsType(); - } - - template - static constexpr bool hasKeywordSet() { - if constexpr (CSSKeywordSet && !std::is_same_v) { - return true; - } else if constexpr (sizeof...(Rest) == 0) { - return false; - } else { - return hasKeywordSet(); - } - } - - template - struct PackedKeywordSet { - using Type = void; - }; - - template - struct PackedKeywordSet { - using Type = std::conditional_t< - hasKeywordSet(), - T, - typename PackedKeywordSet::Type>; - }; - - public: - using Keyword = typename PackedKeywordSet::Type; - - constexpr CSSValueVariant() - requires(canRepresent()) - : CSSValueVariant(CSSValueType::CSSWideKeyword, CSSWideKeyword::Unset) {} - - static constexpr CSSValueVariant cssWideKeyword(CSSWideKeyword keyword) { - return CSSValueVariant( - CSSValueType::CSSWideKeyword, CSSWideKeyword{keyword}); - } - - template - static constexpr CSSValueVariant keyword(KeywordT keyword) - requires(canRepresent()) - { - return CSSValueVariant(CSSValueType::Keyword, KeywordT{keyword}); - } - - static constexpr CSSValueVariant length(float value, CSSLengthUnit unit) - requires(canRepresent()) - { - return CSSValueVariant(CSSValueType::Length, CSSLength{value, unit}); - } - - static constexpr CSSValueVariant number(float value) - requires(canRepresent()) - { - return CSSValueVariant(CSSValueType::Number, CSSNumber{value}); - } - - static constexpr CSSValueVariant percentage(float value) - requires(canRepresent()) - { - return CSSValueVariant(CSSValueType::Percentage, CSSPercentage{value}); - } - - static constexpr CSSValueVariant ratio(float numerator, float denominator) - requires(canRepresent()) - { - return CSSValueVariant( - CSSValueType::Ratio, CSSRatio{numerator, denominator}); - } - - static constexpr CSSValueVariant angle(float degrees) - requires(canRepresent()) - { - return CSSValueVariant(CSSValueType::Angle, CSSAngle{degrees}); - } - - static constexpr CSSValueVariant - color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) - requires(canRepresent()) - { - return CSSValueVariant(CSSValueType::Color, CSSColor{r, g, b, a}); - } - - constexpr CSSValueType type() const { - return type_; - } - - constexpr CSSWideKeyword getCSSWideKeyword() const - requires(canRepresent()) - { - return getIf(); - } - - constexpr Keyword getKeyword() const - requires(hasKeywordSet()) - { - return getIf(); - } - - constexpr CSSLength getLength() const - requires(canRepresent()) - { - return getIf(); - } - - constexpr CSSNumber getNumber() const - requires(canRepresent()) - { - return getIf(); - } - - constexpr CSSPercentage getPercentage() const - requires(canRepresent()) - { - return getIf(); - } - - constexpr CSSRatio getRatio() const - requires(canRepresent()) - { - return getIf(); - } - - constexpr CSSAngle getAngle() const - requires(canRepresent()) - { - return getIf(); - } - - constexpr CSSColor getColor() const - requires(canRepresent()) - { - return getIf(); - } - - constexpr bool hasValue() const - requires(canRepresent()) - { - return type() != CSSValueType::CSSWideKeyword || - getCSSWideKeyword() != CSSWideKeyword::Unset; - } - - constexpr operator bool() const { - return hasValue(); - } - - constexpr bool operator==(const CSSValueVariant& other) const { - if (type() != other.type()) { - return false; - } - switch (type()) { - case CSSValueType::CSSWideKeyword: - return getCSSWideKeyword() == other.getCSSWideKeyword(); - case CSSValueType::Keyword: - return getKeyword() == other.getKeyword(); - case CSSValueType::Length: - return getLength() == other.getLength(); - case CSSValueType::Number: - return getNumber() == other.getNumber(); - case CSSValueType::Percentage: - return getPercentage() == other.getPercentage(); - case CSSValueType::Ratio: - return getRatio() == other.getRatio(); - case CSSValueType::Angle: - return getAngle() == other.getAngle(); - case CSSValueType::Color: - return getColor() == other.getColor(); - } - - return false; - } - - private: - template - constexpr ValueT getIf() const { - if (type_ == Type) { - return getFromUnion(data_); - } else { - return ValueT{}; - } - } - - template - union RecursiveUnion { - ValueT first; - RecursiveUnion rest; - }; - - template - union RecursiveUnion { - ValueT first; - }; - - template - constexpr const ValueT& getFromUnion(const UnionT& u) const { - if constexpr (std::is_same_v) { - return u.first; - } else { - return getFromUnion(u.rest); - } - } - - template - constexpr CSSValueVariant(CSSValueType type, DataTypeT&& value) - : type_{type}, - data_{constructIntoUnion( - std::forward(value))} {} - - template - constexpr UnionT constructIntoUnion(DataTypeT&& value) { - if constexpr (std::is_same_v) { - return UnionT{.first = std::forward(value)}; - } else { - return UnionT{ - .rest = constructIntoUnion( - std::forward(value))}; - } - } - - CSSValueType type_; - RecursiveUnion data_; -}; -#pragma pack(pop) - -static_assert(sizeof(CSSValueVariant) == 2); -static_assert(sizeof(CSSValueVariant) == 6); -static_assert( - sizeof(CSSValueVariant) == 6); -static_assert(sizeof(CSSValueVariant) == 5); -static_assert(sizeof(CSSValueVariant) == 9); - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/tests/CSSDeclaredStyleTest.cpp b/packages/react-native/ReactCommon/react/renderer/css/tests/CSSDeclaredStyleTest.cpp deleted file mode 100644 index 393d48b1618..00000000000 --- a/packages/react-native/ReactCommon/react/renderer/css/tests/CSSDeclaredStyleTest.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include - -namespace facebook::react { - -TEST(CSSDeclaredStyle, unset_keyword) { - CSSDeclaredStyle style; - auto value = style.get(); - EXPECT_EQ(value.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(value.getCSSWideKeyword(), CSSWideKeyword::Unset); -} - -TEST(CSSDeclaredStyle, unset_ratio) { - CSSDeclaredStyle style; - auto value = style.get(); - EXPECT_EQ(value.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(value.getCSSWideKeyword(), CSSWideKeyword::Unset); -} - -TEST(CSSDeclaredStyle, set_keyword) { - CSSDeclaredStyle style; - - style.set("row"); - - auto value = style.get(); - EXPECT_EQ(value.type(), CSSValueType::Keyword); - EXPECT_EQ(value.getKeyword(), CSSKeyword::Row); -} - -TEST(CSSDeclaredStyle, set_ratio) { - CSSDeclaredStyle style; - - style.set("16 / 9"); - - auto value = style.get(); - EXPECT_EQ(value.type(), CSSValueType::Ratio); - EXPECT_EQ(value.getRatio().numerator, 16.0f); - EXPECT_EQ(value.getRatio().denominator, 9.0f); -} - -TEST(CSSDeclaredStyle, overwrite_ratio) { - CSSDeclaredStyle style; - - style.set("16 / 9"); - - auto value1 = style.get(); - EXPECT_EQ(value1.type(), CSSValueType::Ratio); - EXPECT_EQ(value1.getRatio().numerator, 16.0f); - EXPECT_EQ(value1.getRatio().denominator, 9.0f); - - style.set("4/3"); - - auto value2 = style.get(); - EXPECT_EQ(value2.type(), CSSValueType::Ratio); - EXPECT_EQ(value2.getRatio().numerator, 4.0f); - EXPECT_EQ(value2.getRatio().denominator, 3.0f); -} - -TEST(CSSDeclaredStyle, set_multiple) { - CSSDeclaredStyle style; - - style.set("row"); - style.set("16 / 9"); - - auto flexDirection = style.get(); - EXPECT_EQ(flexDirection.type(), CSSValueType::Keyword); - EXPECT_EQ(flexDirection.getKeyword(), CSSKeyword::Row); - - auto aspectRatio = style.get(); - EXPECT_EQ(aspectRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(aspectRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(aspectRatio.getRatio().denominator, 9.0f); -} - -TEST(CSSDeclaredStyle, set_multiple_overwrite) { - CSSDeclaredStyle style; - - style.set("row"); - style.set("16 / 9"); - style.set("column"); - - auto flexDirection = style.get(); - EXPECT_EQ(flexDirection.type(), CSSValueType::Keyword); - EXPECT_EQ(flexDirection.getKeyword(), CSSKeyword::Column); - - auto aspectRatio = style.get(); - EXPECT_EQ(aspectRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(aspectRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(aspectRatio.getRatio().denominator, 9.0f); -} - -TEST(CSSDeclaredStyle, set_multiple_reset) { - CSSDeclaredStyle style; - - style.set("row"); - style.set("16 / 9"); - style.set(""); - - auto flexDirection = style.get(); - EXPECT_EQ(flexDirection.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(flexDirection.getCSSWideKeyword(), CSSWideKeyword::Unset); - - auto aspectRatio = style.get(); - EXPECT_EQ(aspectRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(aspectRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(aspectRatio.getRatio().denominator, 9.0f); -} - -TEST(CSSDeclaredStyle, get_with_precedence) { - CSSDeclaredStyle style; - - style.set("1px"); - - auto margin1 = style.get< - CSSProp::MarginStart, - CSSProp::MarginLeft, - CSSProp::MarginInline, - CSSProp::MarginHorizontal, - CSSProp::Margin>(); - - EXPECT_EQ(margin1.type(), CSSValueType::Length); - EXPECT_EQ(margin1.getLength().value, 1.0f); - EXPECT_EQ(margin1.getLength().unit, CSSLengthUnit::Px); - - style.set("3px"); - auto margin2 = style.get< - CSSProp::MarginStart, - CSSProp::MarginLeft, - CSSProp::MarginInline, - CSSProp::MarginHorizontal, - CSSProp::Margin>(); - - EXPECT_EQ(margin2.type(), CSSValueType::Length); - EXPECT_EQ(margin2.getLength().value, 3.0f); - EXPECT_EQ(margin2.getLength().unit, CSSLengthUnit::Px); -} - -TEST(CSSDeclaredStyle, set_from_string) { - CSSDeclaredStyle style; - - EXPECT_TRUE(style.set("flexDirection", "row")); - - EXPECT_EQ(style.get().type(), CSSValueType::Keyword); - EXPECT_EQ(style.get().getKeyword(), CSSKeyword::Row); - - EXPECT_TRUE(style.set("aspectRatio", "16 / 9")); - - EXPECT_EQ(style.get().type(), CSSValueType::Ratio); - auto ratio = style.get(); - EXPECT_FLOAT_EQ(ratio.getRatio().numerator, 16.0f); - EXPECT_FLOAT_EQ(ratio.getRatio().denominator, 9.0f); - - EXPECT_FALSE(style.set("aspectRatio", "16 / 9 / 2")); -} - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/tests/CSSValueParserTest.cpp b/packages/react-native/ReactCommon/react/renderer/css/tests/CSSValueParserTest.cpp index 5908316ba71..a229b5b9ad7 100644 --- a/packages/react-native/ReactCommon/react/renderer/css/tests/CSSValueParserTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/css/tests/CSSValueParserTest.cpp @@ -6,423 +6,292 @@ */ #include +#include +#include +#include +#include +#include +#include +#include #include namespace facebook::react { TEST(CSSValueParser, keyword_values) { - auto emptyValue = parseCSSValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto emptyValue = parseCSSProperty(""); + EXPECT_TRUE(std::holds_alternative(emptyValue)); - auto autoValue = parseCSSValue("auto"); - EXPECT_EQ(autoValue.type(), CSSValueType::Keyword); - EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto); + auto inheritValue = parseCSSProperty<>("inherit"); + EXPECT_TRUE(std::holds_alternative(inheritValue)); + EXPECT_EQ(std::get(inheritValue), CSSWideKeyword::Inherit); - auto autoCapsValue = parseCSSValue("AuTO"); - EXPECT_EQ(autoCapsValue.type(), CSSValueType::Keyword); - EXPECT_EQ(autoCapsValue.getKeyword(), CSSKeyword::Auto); + auto autoValue = parseCSSProperty("auto"); + EXPECT_TRUE(std::holds_alternative(autoValue)); + EXPECT_EQ(std::get(autoValue), CSSKeyword::Auto); - auto autoDisallowedValue = parseCSSValue("auto"); - EXPECT_EQ(autoDisallowedValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(autoDisallowedValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto autoCapsValue = parseCSSProperty("AuTO"); + EXPECT_TRUE(std::holds_alternative(autoCapsValue)); + EXPECT_EQ(std::get(autoCapsValue), CSSKeyword::Auto); - auto whitespaceValue = - parseCSSValue(" flex-start "); - EXPECT_EQ(whitespaceValue.type(), CSSValueType::Keyword); - EXPECT_EQ(whitespaceValue.getKeyword(), CSSKeyword::FlexStart); + auto autoDisallowedValue = parseCSSProperty<>("auto"); + EXPECT_TRUE(std::holds_alternative(autoDisallowedValue)); - auto badIdentValue = parseCSSValue("bad"); - EXPECT_EQ(badIdentValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(badIdentValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto whitespaceValue = parseCSSProperty(" flex-start "); + EXPECT_TRUE(std::holds_alternative(whitespaceValue)); + EXPECT_EQ(std::get(whitespaceValue), CSSKeyword::FlexStart); - auto pxValue = parseCSSValue("20px"); - EXPECT_EQ(pxValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(pxValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto badIdentValue = parseCSSProperty("bad"); + EXPECT_TRUE(std::holds_alternative(badIdentValue)); - auto multiValue = parseCSSValue("auto flex-start"); - EXPECT_EQ(multiValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(multiValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto pxValue = parseCSSProperty<>("20px"); + EXPECT_TRUE(std::holds_alternative(pxValue)); + + auto multiValue = parseCSSProperty<>("auto flex-start"); + EXPECT_TRUE(std::holds_alternative(multiValue)); } TEST(CSSValueParser, length_values) { - auto emptyValue = parseCSSValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto emptyValue = parseCSSProperty(""); + EXPECT_TRUE(std::holds_alternative(emptyValue)); - auto autoValue = parseCSSValue("auto"); - EXPECT_EQ(autoValue.type(), CSSValueType::Keyword); - EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto); + auto autoValue = parseCSSProperty("auto"); + EXPECT_TRUE(std::holds_alternative(autoValue)); + EXPECT_EQ(std::get(autoValue), CSSKeyword::Auto); - auto pxValue = parseCSSValue("20px"); - EXPECT_EQ(pxValue.type(), CSSValueType::Length); - EXPECT_EQ(pxValue.getLength().value, 20.0f); - EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px); + auto pxValue = parseCSSProperty("20px"); + EXPECT_TRUE(std::holds_alternative(pxValue)); + EXPECT_EQ(std::get(pxValue).value, 20.0f); + EXPECT_EQ(std::get(pxValue).unit, CSSLengthUnit::Px); - auto capsValue = parseCSSValue("50PX"); - EXPECT_EQ(capsValue.type(), CSSValueType::Length); - EXPECT_EQ(capsValue.getLength().value, 50.0f); - EXPECT_EQ(capsValue.getLength().unit, CSSLengthUnit::Px); + auto capsValue = parseCSSProperty("50PX"); + EXPECT_TRUE(std::holds_alternative(capsValue)); + EXPECT_EQ(std::get(capsValue).value, 50.0f); + EXPECT_EQ(std::get(capsValue).unit, CSSLengthUnit::Px); - auto cmValue = parseCSSValue("453cm"); - EXPECT_EQ(cmValue.type(), CSSValueType::Length); - EXPECT_EQ(cmValue.getLength().value, 453.0f); - EXPECT_EQ(cmValue.getLength().unit, CSSLengthUnit::Cm); + auto cmValue = parseCSSProperty("453cm"); + EXPECT_TRUE(std::holds_alternative(cmValue)); + EXPECT_TRUE(std::get(cmValue).value == 453.0f); + EXPECT_EQ(std::get(cmValue).unit, CSSLengthUnit::Cm); - auto unitlessZeroValue = parseCSSValue("0"); - EXPECT_EQ(unitlessZeroValue.type(), CSSValueType::Length); - EXPECT_EQ(unitlessZeroValue.getLength().value, 0.0f); - EXPECT_EQ(unitlessZeroValue.getLength().unit, CSSLengthUnit::Px); + auto unitlessZeroValue = parseCSSProperty("0"); + EXPECT_TRUE(std::holds_alternative(unitlessZeroValue)); + EXPECT_EQ(std::get(unitlessZeroValue).value, 0.0f); + EXPECT_EQ(std::get(unitlessZeroValue).unit, CSSLengthUnit::Px); - auto unitlessNonzeroValue = parseCSSValue("123"); - EXPECT_EQ(unitlessNonzeroValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(unitlessNonzeroValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto unitlessNonzeroValue = parseCSSProperty("123"); + EXPECT_TRUE(std::holds_alternative(unitlessNonzeroValue)); - auto pctValue = parseCSSValue("-40%"); - EXPECT_EQ(pctValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(pctValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto pctValue = parseCSSProperty("-40%"); + EXPECT_TRUE(std::holds_alternative(pctValue)); } TEST(CSSValueParser, length_percentage_values) { - auto emptyValue = parseCSSValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto emptyValue = parseCSSProperty(""); + EXPECT_TRUE(std::holds_alternative(emptyValue)); auto autoValue = - parseCSSValue( - "auto"); - EXPECT_EQ(autoValue.type(), CSSValueType::Keyword); - EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto); + parseCSSProperty("auto"); + EXPECT_TRUE(std::holds_alternative(autoValue)); + EXPECT_EQ(std::get(autoValue), CSSKeyword::Auto); - auto pxValue = - parseCSSValue("20px"); - EXPECT_EQ(pxValue.type(), CSSValueType::Length); - EXPECT_EQ(pxValue.getLength().value, 20.0f); - EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px); + auto pxValue = parseCSSProperty("20px"); + EXPECT_TRUE(std::holds_alternative(pxValue)); + EXPECT_EQ(std::get(pxValue).value, 20.0f); + EXPECT_EQ(std::get(pxValue).unit, CSSLengthUnit::Px); - auto pctValue = - parseCSSValue("-40%"); - EXPECT_EQ(pctValue.type(), CSSValueType::Percentage); - EXPECT_EQ(pctValue.getPercentage().value, -40.0f); + auto pctValue = parseCSSProperty("-40%"); + EXPECT_TRUE(std::holds_alternative(pctValue)); + EXPECT_EQ(std::get(pctValue).value, -40.0f); } TEST(CSSValueParser, number_values) { - auto emptyValue = parseCSSValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto emptyValue = parseCSSProperty(""); + EXPECT_TRUE(std::holds_alternative(emptyValue)); - auto inheritValue = parseCSSValue("inherit"); - EXPECT_EQ(inheritValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(inheritValue.getCSSWideKeyword(), CSSWideKeyword::Inherit); + auto pxValue = parseCSSProperty("20px"); + EXPECT_TRUE(std::holds_alternative(pxValue)); - auto pxValue = parseCSSValue("20px"); - EXPECT_EQ(pxValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(pxValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto numberValue = parseCSSProperty("123.456"); + EXPECT_TRUE(std::holds_alternative(numberValue)); + EXPECT_EQ(std::get(numberValue).value, 123.456f); - auto numberValue = - parseCSSValue("123.456"); - EXPECT_EQ(numberValue.type(), CSSValueType::Number); - EXPECT_EQ(numberValue.getNumber().value, 123.456f); - - auto unitlessZeroValue = - parseCSSValue("0"); - EXPECT_EQ(unitlessZeroValue.type(), CSSValueType::Number); - EXPECT_EQ(unitlessZeroValue.getNumber().value, 0.0f); + auto unitlessZeroValue = parseCSSProperty("0"); + EXPECT_TRUE(std::holds_alternative(unitlessZeroValue)); + EXPECT_EQ(std::get(unitlessZeroValue).value, 0.0f); } TEST(CSSValueParser, ratio_values) { - auto emptyValue = parseCSSValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto emptyValue = parseCSSProperty(""); + EXPECT_TRUE(std::holds_alternative(emptyValue)); - auto validRatio = parseCSSValue("16/9"); - EXPECT_EQ(validRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(validRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(validRatio.getRatio().denominator, 9.0f); + auto validRatio = parseCSSProperty("16/9"); + EXPECT_TRUE(std::holds_alternative(validRatio)); + EXPECT_EQ(std::get(validRatio).numerator, 16.0f); + EXPECT_EQ(std::get(validRatio).denominator, 9.0f); - auto validRatioWithWhitespace = - parseCSSValue("16 / 9"); - EXPECT_EQ(validRatioWithWhitespace.type(), CSSValueType::Ratio); - EXPECT_EQ(validRatioWithWhitespace.getRatio().numerator, 16.0f); - EXPECT_EQ(validRatioWithWhitespace.getRatio().denominator, 9.0f); + auto validRatioWithWhitespace = parseCSSProperty("16 / 9"); + EXPECT_TRUE(std::holds_alternative(validRatioWithWhitespace)); + EXPECT_EQ(std::get(validRatioWithWhitespace).numerator, 16.0f); + EXPECT_EQ(std::get(validRatioWithWhitespace).denominator, 9.0f); - auto singleNumberRatio = parseCSSValue("16"); - EXPECT_EQ(singleNumberRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(singleNumberRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f); + auto singleNumberRatio = parseCSSProperty("16"); + EXPECT_TRUE(std::holds_alternative(singleNumberRatio)); + EXPECT_EQ(std::get(singleNumberRatio).numerator, 16.0f); + EXPECT_EQ(std::get(singleNumberRatio).denominator, 1.0f); - auto fractionalNumber = parseCSSValue("16.5"); - EXPECT_EQ(fractionalNumber.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalNumber.getRatio().numerator, 16.5f); - EXPECT_EQ(fractionalNumber.getRatio().denominator, 1.0f); + auto fractionalNumber = parseCSSProperty("16.5"); + EXPECT_TRUE(std::holds_alternative(fractionalNumber)); + EXPECT_EQ(std::get(fractionalNumber).numerator, 16.5f); + EXPECT_EQ(std::get(fractionalNumber).denominator, 1.0f); - auto negativeNumber = parseCSSValue("-16"); - EXPECT_EQ(negativeNumber.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(negativeNumber.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto negativeNumber = parseCSSProperty("-16"); + EXPECT_TRUE(std::holds_alternative(negativeNumber)); - auto missingDenominator = parseCSSValue("16/"); - EXPECT_EQ(missingDenominator.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(missingDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto missingDenominator = parseCSSProperty("16/"); + EXPECT_TRUE(std::holds_alternative(missingDenominator)); - auto negativeNumerator = parseCSSValue("-16/9"); - EXPECT_EQ(negativeNumerator.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(negativeNumerator.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto negativeNumerator = parseCSSProperty("-16/9"); + EXPECT_TRUE(std::holds_alternative(negativeNumerator)); - auto negativeDenominator = parseCSSValue("16/-9"); - EXPECT_EQ(negativeDenominator.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(negativeDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto negativeDenominator = parseCSSProperty("16/-9"); + EXPECT_TRUE(std::holds_alternative(negativeDenominator)); - auto fractionalNumerator = parseCSSValue("16.5/9"); - EXPECT_EQ(fractionalNumerator.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalNumerator.getRatio().numerator, 16.5f); - EXPECT_EQ(fractionalNumerator.getRatio().denominator, 9.0f); + auto fractionalNumerator = parseCSSProperty("16.5/9"); + EXPECT_TRUE(std::holds_alternative(fractionalNumerator)); + EXPECT_EQ(std::get(fractionalNumerator).numerator, 16.5f); + EXPECT_EQ(std::get(fractionalNumerator).denominator, 9.0f); - auto fractionalDenominator = - parseCSSValue("16/9.5"); - EXPECT_EQ(fractionalDenominator.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalDenominator.getRatio().numerator, 16.0f); - EXPECT_EQ(fractionalDenominator.getRatio().denominator, 9.5f); + auto fractionalDenominator = parseCSSProperty("16/9.5"); + EXPECT_TRUE(std::holds_alternative(fractionalDenominator)); + EXPECT_EQ(std::get(fractionalDenominator).numerator, 16.0f); - auto degenerateRatio = parseCSSValue("0"); - EXPECT_EQ(degenerateRatio.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(degenerateRatio.getCSSWideKeyword(), CSSWideKeyword::Unset); -} - -TEST(CSSValueParser, number_ratio_values) { - auto emptyValue = parseCSSValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - - auto validRatio = parseCSSValue("16/9"); - EXPECT_EQ(validRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(validRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(validRatio.getRatio().denominator, 9.0f); - - auto validRatioWithWhitespace = - parseCSSValue("16 / 9"); - EXPECT_EQ(validRatioWithWhitespace.type(), CSSValueType::Ratio); - EXPECT_EQ(validRatioWithWhitespace.getRatio().numerator, 16.0f); - EXPECT_EQ(validRatioWithWhitespace.getRatio().denominator, 9.0f); - - auto singleNumberRatio = - parseCSSValue("16"); - EXPECT_EQ(singleNumberRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(singleNumberRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f); - - auto fractionalNumber = - parseCSSValue("16.5"); - EXPECT_EQ(fractionalNumber.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalNumber.getRatio().numerator, 16.5f); - EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f); - - auto negativeNumber = - parseCSSValue("-16"); - EXPECT_EQ(negativeNumber.type(), CSSValueType::Number); - EXPECT_EQ(negativeNumber.getNumber().value, -16.0f); - - auto missingDenominator = - parseCSSValue("16/"); - EXPECT_EQ(missingDenominator.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(missingDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset); - - auto negativeNumerator = - parseCSSValue("-16/9"); - EXPECT_EQ(negativeNumerator.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(negativeNumerator.getCSSWideKeyword(), CSSWideKeyword::Unset); - - auto negativeDenominator = - parseCSSValue("16/-9"); - EXPECT_EQ(negativeDenominator.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(negativeDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset); - - auto fractionalNumerator = - parseCSSValue("16.5/9"); - EXPECT_EQ(fractionalNumerator.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalNumerator.getRatio().numerator, 16.5f); - EXPECT_EQ(fractionalNumerator.getRatio().denominator, 9.0f); - - auto fractionalDenominator = - parseCSSValue("16/9.5"); - EXPECT_EQ(fractionalDenominator.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalDenominator.getRatio().numerator, 16.0f); - EXPECT_EQ(fractionalDenominator.getRatio().denominator, 9.5f); - - auto degenerateRatio = - parseCSSValue("0"); - EXPECT_EQ(degenerateRatio.type(), CSSValueType::Number); - EXPECT_EQ(degenerateRatio.getNumber().value, 0.0f); + auto degenerateRatio = parseCSSProperty("0"); + EXPECT_TRUE(std::holds_alternative(degenerateRatio)); } TEST(CSSValueParser, angle_values) { - auto emptyValue = parseCSSValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto emptyValue = parseCSSProperty(""); + EXPECT_TRUE(std::holds_alternative(emptyValue)); - auto degreeValue = parseCSSValue("10deg"); - EXPECT_EQ(degreeValue.type(), CSSValueType::Angle); - EXPECT_EQ(degreeValue.getAngle().degrees, 10.0f); + auto degreeValue = parseCSSProperty("10deg"); + EXPECT_TRUE(std::holds_alternative(degreeValue)); + EXPECT_EQ(std::get(degreeValue).degrees, 10.0f); - auto spongebobCaseValue = parseCSSValue("20dEg"); - EXPECT_EQ(spongebobCaseValue.type(), CSSValueType::Angle); - EXPECT_EQ(spongebobCaseValue.getAngle().degrees, 20.0f); + auto spongebobCaseValue = parseCSSProperty("20dEg"); + EXPECT_TRUE(std::holds_alternative(spongebobCaseValue)); + EXPECT_EQ(std::get(spongebobCaseValue).degrees, 20.0f); - auto radianValue = parseCSSValue("10rad"); - EXPECT_EQ(radianValue.type(), CSSValueType::Angle); - EXPECT_NEAR(radianValue.getAngle().degrees, 572.958f, 0.001f); + auto radianValue = parseCSSProperty("10rad"); + EXPECT_TRUE(std::holds_alternative(radianValue)); + ASSERT_NEAR(std::get(radianValue).degrees, 572.958f, 0.001f); - auto negativeRadianValue = parseCSSValue("-10rad"); - EXPECT_EQ(negativeRadianValue.type(), CSSValueType::Angle); - EXPECT_NEAR(negativeRadianValue.getAngle().degrees, -572.958f, 0.001f); + auto negativeRadianValue = parseCSSProperty("-10rad"); + EXPECT_TRUE(std::holds_alternative(negativeRadianValue)); + ASSERT_NEAR( + std::get(negativeRadianValue).degrees, -572.958f, 0.001f); - auto gradianValue = parseCSSValue("10grad"); - EXPECT_EQ(gradianValue.type(), CSSValueType::Angle); - ASSERT_NEAR(gradianValue.getAngle().degrees, 9.0f, 0.001f); + auto gradianValue = parseCSSProperty("10grad"); + EXPECT_TRUE(std::holds_alternative(gradianValue)); + ASSERT_NEAR(std::get(gradianValue).degrees, 9.0f, 0.001f); - auto turnValue = parseCSSValue(".25turn"); - EXPECT_EQ(turnValue.type(), CSSValueType::Angle); - EXPECT_EQ(turnValue.getAngle().degrees, 90.0f); + auto turnValue = parseCSSProperty(".25turn"); + EXPECT_TRUE(std::holds_alternative(turnValue)); + EXPECT_EQ(std::get(turnValue).degrees, 90.0f); } -TEST(CSSValueParser, parse_prop) { - auto emptyValue = parseCSSProp(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); +TEST(CSSValueParser, parse_constexpr) { + [[maybe_unused]] constexpr auto rowValue = + parseCSSProperty("row"); - auto numberWidthValue = parseCSSProp("50px"); - EXPECT_EQ(numberWidthValue.type(), CSSValueType::Length); - EXPECT_EQ(numberWidthValue.getLength().value, 50.0f); - EXPECT_EQ(numberWidthValue.getLength().unit, CSSLengthUnit::Px); - - auto percentWidthValue = parseCSSProp("50%"); - EXPECT_EQ(percentWidthValue.type(), CSSValueType::Percentage); - EXPECT_EQ(percentWidthValue.getPercentage().value, 50.0f); - - auto autoWidthValue = parseCSSProp("auto"); - EXPECT_EQ(autoWidthValue.type(), CSSValueType::Keyword); - EXPECT_EQ(autoWidthValue.getKeyword(), CSSKeyword::Auto); - - auto invalidWidthValue = parseCSSProp("50"); - EXPECT_EQ(invalidWidthValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(invalidWidthValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - - auto invalidKeywordValue = parseCSSProp("flex-start"); - EXPECT_EQ(invalidKeywordValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(invalidKeywordValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - - auto keywordlessValue = parseCSSProp("50px"); - EXPECT_EQ(keywordlessValue.type(), CSSValueType::Length); - EXPECT_EQ(keywordlessValue.getLength().value, 50.0f); - EXPECT_EQ(keywordlessValue.getLength().unit, CSSLengthUnit::Px); -} - -TEST(CSSValueParser, parse_keyword_prop_constexpr) { - constexpr auto rowValue = parseCSSProp("row"); - EXPECT_EQ(rowValue.type(), CSSValueType::Keyword); - EXPECT_EQ(rowValue.getKeyword(), CSSKeyword::Row); -} - -TEST(CSSValueParser, parse_length_prop_constexpr) { - constexpr auto pxValue = parseCSSProp("2px"); - EXPECT_EQ(pxValue.type(), CSSValueType::Length); - EXPECT_EQ(pxValue.getLength().value, 2.0f); - EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px); + [[maybe_unused]] constexpr auto pxValue = parseCSSProperty("2px"); } TEST(CSSValueParser, hex_color_values) { - auto emptyValue = parseCSSValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto emptyValue = parseCSSProperty(""); + EXPECT_TRUE(std::holds_alternative(emptyValue)); - auto hex3DigitColorValue = parseCSSValue("#fff"); - EXPECT_EQ(hex3DigitColorValue.type(), CSSValueType::Color); - EXPECT_EQ(hex3DigitColorValue.getColor().r, 255); - EXPECT_EQ(hex3DigitColorValue.getColor().g, 255); - EXPECT_EQ(hex3DigitColorValue.getColor().b, 255); - EXPECT_EQ(hex3DigitColorValue.getColor().a, 255); + auto hex3DigitColorValue = parseCSSProperty("#fff"); + EXPECT_TRUE(std::holds_alternative(hex3DigitColorValue)); + EXPECT_EQ(std::get(hex3DigitColorValue).r, 255); + EXPECT_EQ(std::get(hex3DigitColorValue).g, 255); + EXPECT_EQ(std::get(hex3DigitColorValue).b, 255); + EXPECT_EQ(std::get(hex3DigitColorValue).a, 255); - auto hex4DigitColorValue = parseCSSValue("#ffff"); - EXPECT_EQ(hex4DigitColorValue.type(), CSSValueType::Color); - EXPECT_EQ(hex4DigitColorValue.getColor().r, 255); - EXPECT_EQ(hex4DigitColorValue.getColor().g, 255); - EXPECT_EQ(hex4DigitColorValue.getColor().b, 255); - EXPECT_EQ(hex4DigitColorValue.getColor().a, 255); + auto hex4DigitColorValue = parseCSSProperty("#ffff"); + EXPECT_TRUE(std::holds_alternative(hex4DigitColorValue)); + EXPECT_EQ(std::get(hex4DigitColorValue).r, 255); + EXPECT_EQ(std::get(hex4DigitColorValue).g, 255); + EXPECT_EQ(std::get(hex4DigitColorValue).b, 255); + EXPECT_EQ(std::get(hex4DigitColorValue).a, 255); - auto hex6DigitColorValue = parseCSSValue("#ffffff"); - EXPECT_EQ(hex6DigitColorValue.type(), CSSValueType::Color); - EXPECT_EQ(hex6DigitColorValue.getColor().r, 255); - EXPECT_EQ(hex6DigitColorValue.getColor().g, 255); - EXPECT_EQ(hex6DigitColorValue.getColor().b, 255); - EXPECT_EQ(hex6DigitColorValue.getColor().a, 255); + auto hex6DigitColorValue = parseCSSProperty("#ffffff"); + EXPECT_TRUE(std::holds_alternative(hex6DigitColorValue)); + EXPECT_EQ(std::get(hex6DigitColorValue).r, 255); + EXPECT_EQ(std::get(hex6DigitColorValue).g, 255); + EXPECT_EQ(std::get(hex6DigitColorValue).b, 255); + EXPECT_EQ(std::get(hex6DigitColorValue).a, 255); - auto hex8DigitColorValue = - parseCSSValue("#ffffffff"); - EXPECT_EQ(hex8DigitColorValue.type(), CSSValueType::Color); - EXPECT_EQ(hex8DigitColorValue.getColor().r, 255); - EXPECT_EQ(hex8DigitColorValue.getColor().g, 255); - EXPECT_EQ(hex8DigitColorValue.getColor().b, 255); - EXPECT_EQ(hex8DigitColorValue.getColor().a, 255); + auto hex8DigitColorValue = parseCSSProperty("#ffffffff"); + EXPECT_TRUE(std::holds_alternative(hex8DigitColorValue)); + EXPECT_EQ(std::get(hex8DigitColorValue).r, 255); + EXPECT_EQ(std::get(hex8DigitColorValue).g, 255); + EXPECT_EQ(std::get(hex8DigitColorValue).b, 255); + EXPECT_EQ(std::get(hex8DigitColorValue).a, 255); - auto hexMixedCaseColorValue = - parseCSSValue("#FFCc99"); - EXPECT_EQ(hexMixedCaseColorValue.type(), CSSValueType::Color); - EXPECT_EQ(hexMixedCaseColorValue.getColor().r, 255); - EXPECT_EQ(hexMixedCaseColorValue.getColor().g, 204); - EXPECT_EQ(hexMixedCaseColorValue.getColor().b, 153); - EXPECT_EQ(hexMixedCaseColorValue.getColor().a, 255); + auto hexMixedCaseColorValue = parseCSSProperty("#FFCc99"); + EXPECT_TRUE(std::holds_alternative(hexMixedCaseColorValue)); + EXPECT_EQ(std::get(hexMixedCaseColorValue).r, 255); + EXPECT_EQ(std::get(hexMixedCaseColorValue).g, 204); + EXPECT_EQ(std::get(hexMixedCaseColorValue).b, 153); + EXPECT_EQ(std::get(hexMixedCaseColorValue).a, 255); - auto hexDigitOnlyColorValue = parseCSSValue("#369"); - EXPECT_EQ(hexDigitOnlyColorValue.type(), CSSValueType::Color); - EXPECT_EQ(hexDigitOnlyColorValue.getColor().r, 51); - EXPECT_EQ(hexDigitOnlyColorValue.getColor().g, 102); - EXPECT_EQ(hexDigitOnlyColorValue.getColor().b, 153); - EXPECT_EQ(hexDigitOnlyColorValue.getColor().a, 255); + auto hexDigitOnlyColorValue = parseCSSProperty("#369"); + EXPECT_TRUE(std::holds_alternative(hexDigitOnlyColorValue)); + EXPECT_EQ(std::get(hexDigitOnlyColorValue).r, 51); + EXPECT_EQ(std::get(hexDigitOnlyColorValue).g, 102); + EXPECT_EQ(std::get(hexDigitOnlyColorValue).b, 153); + EXPECT_EQ(std::get(hexDigitOnlyColorValue).a, 255); - auto hexAlphaTestValue = parseCSSValue("#FFFFFFCC"); - EXPECT_EQ(hexAlphaTestValue.type(), CSSValueType::Color); - EXPECT_EQ(hexAlphaTestValue.getColor().r, 255); - EXPECT_EQ(hexAlphaTestValue.getColor().g, 255); - EXPECT_EQ(hexAlphaTestValue.getColor().b, 255); - EXPECT_EQ(hexAlphaTestValue.getColor().a, 204); + auto hexAlphaTestValue = parseCSSProperty("#FFFFFFCC"); + EXPECT_TRUE(std::holds_alternative(hexAlphaTestValue)); + EXPECT_EQ(std::get(hexAlphaTestValue).r, 255); + EXPECT_EQ(std::get(hexAlphaTestValue).g, 255); + EXPECT_EQ(std::get(hexAlphaTestValue).b, 255); + EXPECT_EQ(std::get(hexAlphaTestValue).a, 204); } TEST(CSSValueParser, named_colors) { - auto invalidNamedColorTestValue = - parseCSSValue("redd"); - EXPECT_EQ(invalidNamedColorTestValue.type(), CSSValueType::CSSWideKeyword); - EXPECT_EQ( - invalidNamedColorTestValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + auto invalidNamedColorTestValue = parseCSSProperty("redd"); + EXPECT_TRUE( + std::holds_alternative(invalidNamedColorTestValue)); - auto namedColorTestValue1 = parseCSSValue("red"); - EXPECT_EQ(namedColorTestValue1.type(), CSSValueType::Color); - EXPECT_EQ(namedColorTestValue1.getColor().r, 255); - EXPECT_EQ(namedColorTestValue1.getColor().g, 0); - EXPECT_EQ(namedColorTestValue1.getColor().b, 0); - EXPECT_EQ(namedColorTestValue1.getColor().a, 255); + auto namedColorTestValue1 = parseCSSProperty("red"); + EXPECT_TRUE(std::holds_alternative(namedColorTestValue1)); + EXPECT_EQ(std::get(namedColorTestValue1).r, 255); + EXPECT_EQ(std::get(namedColorTestValue1).g, 0); + EXPECT_EQ(std::get(namedColorTestValue1).b, 0); + EXPECT_EQ(std::get(namedColorTestValue1).a, 255); - auto namedColorTestValue2 = - parseCSSValue("cornsilk"); - EXPECT_EQ(namedColorTestValue2.type(), CSSValueType::Color); - EXPECT_EQ(namedColorTestValue2.getColor().r, 255); - EXPECT_EQ(namedColorTestValue2.getColor().g, 248); - EXPECT_EQ(namedColorTestValue2.getColor().b, 220); - EXPECT_EQ(namedColorTestValue2.getColor().a, 255); + auto namedColorTestValue2 = parseCSSProperty("cornsilk"); + EXPECT_TRUE(std::holds_alternative(namedColorTestValue2)); + EXPECT_EQ(std::get(namedColorTestValue2).r, 255); + EXPECT_EQ(std::get(namedColorTestValue2).g, 248); + EXPECT_EQ(std::get(namedColorTestValue2).b, 220); + EXPECT_EQ(std::get(namedColorTestValue2).a, 255); - auto namedColorMixedCaseTestValue = - parseCSSValue("sPrINgGrEEn"); - EXPECT_EQ(namedColorMixedCaseTestValue.type(), CSSValueType::Color); - EXPECT_EQ(namedColorMixedCaseTestValue.getColor().r, 0); - EXPECT_EQ(namedColorMixedCaseTestValue.getColor().g, 255); - EXPECT_EQ(namedColorMixedCaseTestValue.getColor().b, 127); - EXPECT_EQ(namedColorMixedCaseTestValue.getColor().a, 255); + auto namedColorMixedCaseTestValue = parseCSSProperty("sPrINgGrEEn"); + EXPECT_TRUE(std::holds_alternative(namedColorMixedCaseTestValue)); + EXPECT_EQ(std::get(namedColorMixedCaseTestValue).r, 0); + EXPECT_EQ(std::get(namedColorMixedCaseTestValue).g, 255); + EXPECT_EQ(std::get(namedColorMixedCaseTestValue).b, 127); + EXPECT_EQ(std::get(namedColorMixedCaseTestValue).a, 255); - auto transparentColor = - parseCSSValue("transparent"); - EXPECT_EQ(transparentColor.type(), CSSValueType::Color); - EXPECT_EQ(transparentColor.getColor().r, 0); - EXPECT_EQ(transparentColor.getColor().g, 0); - EXPECT_EQ(transparentColor.getColor().b, 0); - EXPECT_EQ(transparentColor.getColor().a, 0); + auto transparentColor = parseCSSProperty("transparent"); + EXPECT_TRUE(std::holds_alternative(transparentColor)); + EXPECT_EQ(std::get(transparentColor).r, 0); + EXPECT_EQ(std::get(transparentColor).g, 0); + EXPECT_EQ(std::get(transparentColor).b, 0); + EXPECT_EQ(std::get(transparentColor).a, 0); } } // namespace facebook::react