Procházet zdrojové kódy

rx.color to work with conditional vars (#2546)

Elijah Ahianyo před 1 rokem
rodič
revize
601dd34792

+ 3 - 2
reflex/components/core/colors.py

@@ -2,10 +2,11 @@
 
 from reflex.constants.colors import Color, ColorType, ShadeType
 from reflex.utils.types import validate_parameter_literals
+from reflex.vars import Var
 
 
 @validate_parameter_literals
-def color(color: ColorType, shade: ShadeType = 7, alpha: bool = False) -> Color:
+def color(color: ColorType, shade: ShadeType = 7, alpha: bool = False) -> Var:
     """Create a color object.
 
     Args:
@@ -16,4 +17,4 @@ def color(color: ColorType, shade: ShadeType = 7, alpha: bool = False) -> Color:
     Returns:
         The color object.
     """
-    return Color(color, shade, alpha)
+    return Var.create(Color(color, shade, alpha))._replace(_var_is_string=True)  # type: ignore

+ 8 - 12
reflex/utils/format.py

@@ -253,24 +253,20 @@ def format_cond(
     # Use Python truthiness.
     cond = f"isTrue({cond})"
 
+    def create_var(cond_part):
+        return Var.create_safe(cond_part, _var_is_string=type(cond_part) is str)
+
     # Format prop conds.
     if is_prop:
-        if not isinstance(true_value, Var):
-            true_value = Var.create_safe(
-                true_value,
-                _var_is_string=type(true_value) is str,
-            )
+        true_value = create_var(true_value)
         prop1 = true_value._replace(
             _var_is_local=True,
         )
-        if not isinstance(false_value, Var):
-            false_value = Var.create_safe(
-                false_value,
-                _var_is_string=type(false_value) is str,
-            )
+
+        false_value = create_var(false_value)
         prop2 = false_value._replace(_var_is_local=True)
-        prop1, prop2 = str(prop1), str(prop2)  # avoid f-string semantics for Var
-        return f"{cond} ? {prop1} : {prop2}".replace("{", "").replace("}", "")
+        # unwrap '{}' to avoid f-string semantics for Var
+        return f"{cond} ? {prop1._var_name_unwrapped} : {prop2._var_name_unwrapped}"
 
     # Format component conds.
     return wrap(f"{cond} ? {true_value} : {false_value}", "{")

+ 3 - 3
reflex/vars.py

@@ -1612,13 +1612,13 @@ class Var:
             if types.is_generic_alias(self._var_type)
             else self._var_type
         )
-
         wrapped_var = str(self)
+
         return (
             wrapped_var
             if not self._var_state
-            and issubclass(type_, dict)
-            or issubclass(type_, Style)
+            and types._issubclass(type_, dict)
+            or types._issubclass(type_, Style)
             else wrapped_var.strip("{}")
         )
 

+ 0 - 0
tests/components/core/__init__.py


+ 66 - 0
tests/components/core/test_colors.py

@@ -0,0 +1,66 @@
+import pytest
+
+import reflex as rx
+
+
+class ColorState(rx.State):
+    """Test color state."""
+
+    color: str = "mint"
+    shade: int = 4
+
+
+@pytest.mark.parametrize(
+    "color, expected",
+    [
+        (rx.color("mint"), "{`var(--mint-7)`}"),
+        (rx.color("mint", 3), "{`var(--mint-3)`}"),
+        (rx.color("mint", 3, True), "{`var(--mint-a3)`}"),
+        (
+            rx.color(ColorState.color, ColorState.shade),  # type: ignore
+            "{`var(--${state__color_state.color}-${state__color_state.shade})`}",
+        ),
+    ],
+)
+def test_color(color, expected):
+    assert str(color) == expected
+
+
+@pytest.mark.parametrize(
+    "cond_var, expected",
+    [
+        (
+            rx.cond(True, rx.color("mint"), rx.color("tomato", 5)),
+            "{isTrue(true) ? `var(--mint-7)` : `var(--tomato-5)`}",
+        ),
+        (
+            rx.cond(True, rx.color(ColorState.color), rx.color(ColorState.color, 5)),  # type: ignore
+            "{isTrue(true) ? `var(--${state__color_state.color}-7)` : `var(--${state__color_state.color}-5)`}",
+        ),
+        (
+            rx.match(
+                "condition",
+                ("first", rx.color("mint")),
+                ("second", rx.color("tomato", 5)),
+                rx.color(ColorState.color, 2),  # type: ignore
+            ),
+            "{(() => { switch (JSON.stringify(`condition`)) {case JSON.stringify(`first`):  return (`var(--mint-7)`);"
+            "  break;case JSON.stringify(`second`):  return (`var(--tomato-5)`);  break;default:  "
+            "return (`var(--${state__color_state.color}-2)`);  break;};})()}",
+        ),
+        (
+            rx.match(
+                "condition",
+                ("first", rx.color(ColorState.color)),  # type: ignore
+                ("second", rx.color(ColorState.color, 5)),  # type: ignore
+                rx.color(ColorState.color, 2),  # type: ignore
+            ),
+            "{(() => { switch (JSON.stringify(`condition`)) {case JSON.stringify(`first`):  "
+            "return (`var(--${state__color_state.color}-7)`);  break;case JSON.stringify(`second`):  "
+            "return (`var(--${state__color_state.color}-5)`);  break;default:  "
+            "return (`var(--${state__color_state.color}-2)`);  break;};})()}",
+        ),
+    ],
+)
+def test_color_with_conditionals(cond_var, expected):
+    assert str(cond_var) == expected

+ 3 - 3
tests/utils/test_serializers.py

@@ -5,7 +5,7 @@ from typing import Any, Dict, List, Type
 import pytest
 
 from reflex.base import Base
-from reflex.components.core.colors import color
+from reflex.components.core.colors import Color
 from reflex.utils import serializers
 from reflex.vars import Var
 
@@ -170,8 +170,8 @@ class BaseSubclass(Base):
             [datetime.timedelta(1, 1, 1), datetime.timedelta(1, 1, 2)],
             '["1 day, 0:00:01.000001", "1 day, 0:00:01.000002"]',
         ),
-        (color("slate", shade=1), "var(--slate-1)"),
-        (color("orange", shade=1, alpha=True), "var(--orange-a1)"),
+        (Color(color="slate", shade=1), "var(--slate-1)"),
+        (Color(color="orange", shade=1, alpha=True), "var(--orange-a1)"),
     ],
 )
 def test_serialize(value: Any, expected: str):