improve color handling

This commit is contained in:
Khaleel Al-Adhami 2024-10-14 18:15:30 -07:00
parent 250b29313b
commit 6c26854e80
5 changed files with 165 additions and 11 deletions

View File

@ -644,6 +644,18 @@ class Var(Generic[VAR_TYPE]):
return self return self
@overload
def guess_type(self: Var[str]) -> StringVar: ...
@overload
def guess_type(self: Var[bool]) -> BooleanVar: ...
@overload
def guess_type(self: Var[int] | Var[float] | Var[int | float]) -> NumberVar: ...
@overload
def guess_type(self) -> Self: ...
def guess_type(self) -> Var: def guess_type(self) -> Var:
"""Guesses the type of the variable based on its `_var_type` attribute. """Guesses the type of the variable based on its `_var_type` attribute.
@ -908,16 +920,20 @@ class Var(Generic[VAR_TYPE]):
""" """
return ~self.bool() return ~self.bool()
def to_string(self): def to_string(self, use_json: bool = True) -> StringVar:
"""Convert the var to a string. """Convert the var to a string.
Returns: Returns:
The string var. The string var.
""" """
from .function import JSON_STRINGIFY from .function import JSON_STRINGIFY, OBJECT_PROTOTYPE_TO_STRING
from .sequence import StringVar from .sequence import StringVar
return JSON_STRINGIFY.call(self).to(StringVar) return (
JSON_STRINGIFY.call(self).to(StringVar)
if use_json
else OBJECT_PROTOTYPE_TO_STRING.call(self).to(StringVar)
)
def as_ref(self) -> Var: def as_ref(self) -> Var:
"""Get a reference to the var. """Get a reference to the var.
@ -1419,6 +1435,12 @@ def var_operation(
) -> Callable[P, ObjectVar[OBJECT_TYPE]]: ... ) -> Callable[P, ObjectVar[OBJECT_TYPE]]: ...
@overload
def var_operation(
func: Callable[P, CustomVarOperationReturn[T]],
) -> Callable[P, Var[T]]: ...
def var_operation( def var_operation(
func: Callable[P, CustomVarOperationReturn[T]], func: Callable[P, CustomVarOperationReturn[T]],
) -> Callable[P, Var[T]]: ) -> Callable[P, Var[T]]:

View File

@ -180,3 +180,4 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
JSON_STRINGIFY = FunctionStringVar.create("JSON.stringify") JSON_STRINGIFY = FunctionStringVar.create("JSON.stringify")
OBJECT_PROTOTYPE_TO_STRING = FunctionStringVar.create("Object.prototype.toString")

View File

@ -11,6 +11,7 @@ from typing import (
Any, Any,
Callable, Callable,
NoReturn, NoReturn,
Type,
TypeVar, TypeVar,
Union, Union,
overload, overload,
@ -1110,8 +1111,12 @@ def boolify(value: Var):
) )
T = TypeVar("T")
U = TypeVar("U")
@var_operation @var_operation
def ternary_operation(condition: BooleanVar, if_true: Var, if_false: Var): def ternary_operation(condition: BooleanVar, if_true: Var[T], if_false: Var[U]):
"""Create a ternary operation. """Create a ternary operation.
Args: Args:
@ -1122,10 +1127,14 @@ def ternary_operation(condition: BooleanVar, if_true: Var, if_false: Var):
Returns: Returns:
The ternary operation. The ternary operation.
""" """
return var_operation_return( type_value: Union[Type[T], Type[U]] = unionize(
js_expression=f"({condition} ? {if_true} : {if_false})", if_true._var_type, if_false._var_type
var_type=unionize(if_true._var_type, if_false._var_type),
) )
value: CustomVarOperationReturn[Union[T, U]] = var_operation_return(
js_expression=f"({condition} ? {if_true} : {if_false})",
var_type=type_value,
)
return value
NUMBER_TYPES = (int, float, NumberVar) NUMBER_TYPES = (int, float, NumberVar)

View File

@ -18,13 +18,15 @@ from typing import (
Set, Set,
Tuple, Tuple,
Type, Type,
TypeVar,
Union, Union,
overload, overload,
) )
from typing_extensions import TypeVar
from reflex import constants from reflex import constants
from reflex.constants.base import REFLEX_VAR_OPENING_TAG from reflex.constants.base import REFLEX_VAR_OPENING_TAG
from reflex.constants.colors import Color
from reflex.utils.exceptions import VarTypeError from reflex.utils.exceptions import VarTypeError
from reflex.utils.types import GenericType, get_origin from reflex.utils.types import GenericType, get_origin
@ -44,16 +46,20 @@ from .base import (
) )
from .number import ( from .number import (
BooleanVar, BooleanVar,
LiteralBooleanVar,
LiteralNumberVar, LiteralNumberVar,
NumberVar, NumberVar,
raise_unsupported_operand_types, raise_unsupported_operand_types,
ternary_operation,
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from .object import ObjectVar from .object import ObjectVar
STRING_TYPE = TypeVar("STRING_TYPE", default=str)
class StringVar(Var[str], python_types=str):
class StringVar(Var[STRING_TYPE], python_types=str):
"""Base class for immutable string vars.""" """Base class for immutable string vars."""
@overload @overload
@ -1625,3 +1631,119 @@ def array_concat_operation(
js_expression=f"[...{lhs}, ...{rhs}]", js_expression=f"[...{lhs}, ...{rhs}]",
var_type=Union[lhs._var_type, rhs._var_type], var_type=Union[lhs._var_type, rhs._var_type],
) )
class ColorVar(StringVar[Color], python_types=Color):
"""Base class for immutable color vars."""
@dataclasses.dataclass(
eq=False,
frozen=True,
**{"slots": True} if sys.version_info >= (3, 10) else {},
)
class LiteralColorVar(CachedVarOperation, LiteralVar, ColorVar):
"""Base class for immutable literal color vars."""
_var_value: Color = dataclasses.field(default_factory=lambda: Color(color="black"))
@classmethod
def create(
cls,
value: Color,
_var_type: Type[Color] | None = None,
_var_data: VarData | None = None,
) -> ColorVar:
"""Create a var from a string value.
Args:
value: The value to create the var from.
_var_type: The type of the var.
_var_data: Additional hooks and imports associated with the Var.
Returns:
The var.
"""
return cls(
_js_expr="",
_var_type=_var_type or Color,
_var_data=_var_data,
_var_value=value,
)
def __hash__(self) -> int:
"""Get the hash of the var.
Returns:
The hash of the var.
"""
return hash(
(
self.__class__.__name__,
self._var_value.color,
self._var_value.alpha,
self._var_value.shade,
)
)
@cached_property_no_lock
def _cached_var_name(self) -> str:
"""The name of the var.
Returns:
The name of the var.
"""
alpha = self._var_value.alpha
alpha = (
ternary_operation(
LiteralBooleanVar.create(alpha),
LiteralStringVar.create("a"),
LiteralStringVar.create("False"),
)
if isinstance(alpha, Var)
else LiteralStringVar.create("a" if alpha else "")
)
shade = self._var_value.shade
shade = (
shade.to_string(use_json=False)
if isinstance(shade, Var)
else LiteralStringVar.create(str(shade))
)
return str(
ConcatVarOperation.create(
LiteralStringVar.create("var(--"),
self._var_value.color,
LiteralStringVar.create("-"),
alpha,
shade,
LiteralStringVar.create(")"),
)
)
@cached_property_no_lock
def _cached_get_all_var_data(self) -> VarData | None:
"""Get all the var data.
Returns:
The var data.
"""
return VarData.merge(
*[
LiteralVar.create(var)._get_all_var_data()
for var in (
self._var_value.color,
self._var_value.alpha,
self._var_value.shade,
)
],
self._var_data,
)
def json(self) -> str:
"""Get the JSON representation of the var.
Returns:
The JSON representation of the var.
"""
return json.dumps(f"{self._var_value}")

View File

@ -31,7 +31,7 @@ def create_color_var(color):
(create_color_var(rx.color("mint", 3, True)), '"var(--mint-a3)"', Color), (create_color_var(rx.color("mint", 3, True)), '"var(--mint-a3)"', Color),
( (
create_color_var(rx.color(ColorState.color, ColorState.shade)), # type: ignore create_color_var(rx.color(ColorState.color, ColorState.shade)), # type: ignore
f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")', f'("var(--"+{str(color_state_name)}.color+"-"+(Object.prototype.toString({str(color_state_name)}.shade))+")")',
Color, Color,
), ),
( (
@ -43,7 +43,7 @@ def create_color_var(color):
create_color_var( create_color_var(
rx.color(f"{ColorState.color_part}ato", f"{ColorState.shade}") # type: ignore rx.color(f"{ColorState.color_part}ato", f"{ColorState.shade}") # type: ignore
), ),
f'("var(--"+{str(color_state_name)}.color_part+"ato-"+{str(color_state_name)}.shade+")")', f'("var(--"+({str(color_state_name)}.color_part+"ato")+"-"+{str(color_state_name)}.shade+")")',
Color, Color,
), ),
( (