diff --git a/reflex/components/component.py b/reflex/components/component.py index af583a735..0a9da1adc 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -509,7 +509,9 @@ class Component(BaseComponent, ABC): # If it's an event chain var, return it. if isinstance(value, Var): if value._var_type is not EventChain: - raise ValueError(f"Invalid event chain: {value}") + raise ValueError( + f"Invalid event chain: {repr(value)} of type {type(value)}" + ) return value elif isinstance(value, EventChain): # Trust that the caller knows what they're doing passing an EventChain directly diff --git a/reflex/components/datadisplay/code.py b/reflex/components/datadisplay/code.py index c8106062f..878e5ac12 100644 --- a/reflex/components/datadisplay/code.py +++ b/reflex/components/datadisplay/code.py @@ -423,13 +423,14 @@ class CodeBlock(Component): if ( self.language is not None - and self.language._var_name in LiteralCodeLanguage.__args__ # type: ignore + and (language_without_quotes := str(self.language).replace('"', "")) + in LiteralCodeLanguage.__args__ # type: ignore ): imports_[ - f"react-syntax-highlighter/dist/cjs/languages/prism/{self.language._var_name}" + f"react-syntax-highlighter/dist/cjs/languages/prism/{language_without_quotes}" ] = [ ImportVar( - tag=format.to_camel_case(self.language._var_name), + tag=format.to_camel_case(language_without_quotes), is_default=True, install=False, ) diff --git a/reflex/experimental/client_state.py b/reflex/experimental/client_state.py index 3033b94dd..c36b47e54 100644 --- a/reflex/experimental/client_state.py +++ b/reflex/experimental/client_state.py @@ -8,6 +8,8 @@ from typing import Any, Callable, Optional, Type, Union from reflex import constants from reflex.event import EventChain, EventHandler, EventSpec, call_script +from reflex.ivars.base import ImmutableVar, LiteralVar +from reflex.ivars.function import FunctionVar from reflex.utils.imports import ImportVar from reflex.vars import Var, VarData, get_unique_variable_name @@ -109,12 +111,11 @@ class ClientStateVar(Var): var_name = get_unique_variable_name() assert isinstance(var_name, str), "var_name must be a string." if default is NoValue: - default_var = Var.create_safe("", _var_is_local=False, _var_is_string=False) - elif not isinstance(default, Var): - default_var = Var.create_safe( - default, - _var_is_string=isinstance(default, str), + default_var = ImmutableVar.create_safe( + "", _var_is_local=False, _var_is_string=False ) + elif not isinstance(default, Var): + default_var = LiteralVar.create(default) else: default_var = default setter_name = f"set{var_name.capitalize()}" @@ -157,12 +158,10 @@ class ClientStateVar(Var): an accessor for the client state variable. """ return ( - Var.create_safe( + ImmutableVar.create_safe( _client_state_ref(self._getter_name) if self._global_ref - else self._getter_name, - _var_is_local=False, - _var_is_string=False, + else self._getter_name ) .to(self._var_type) ._replace( @@ -192,19 +191,15 @@ class ClientStateVar(Var): ) if value is not NoValue: # This is a hack to make it work like an EventSpec taking an arg - value = Var.create_safe(value, _var_is_string=isinstance(value, str)) + value = LiteralVar.create(value) if not value._var_is_string and value._var_full_name.startswith("_"): arg = value._var_name_unwrapped.partition(".")[0] else: arg = "" setter = f"({arg}) => {setter}({value._var_name_unwrapped})" return ( - Var.create_safe( - setter, - _var_is_local=False, - _var_is_string=False, - ) - .to(EventChain) + ImmutableVar.create_safe(setter) + .to(FunctionVar, EventChain) ._replace( merge_var_data=VarData( # type: ignore imports=_refs_import if self._global_ref else {} diff --git a/reflex/ivars/base.py b/reflex/ivars/base.py index 6e8982c38..004b3464d 100644 --- a/reflex/ivars/base.py +++ b/reflex/ivars/base.py @@ -761,11 +761,33 @@ class LiteralVar(ImmutableVar): Raises: TypeError: If the value is not a supported type for LiteralVar. """ + from .number import LiteralBooleanVar, LiteralNumberVar + from .object import LiteralObjectVar + from .sequence import LiteralArrayVar, LiteralStringVar + if isinstance(value, Var): if _var_data is None: return value return value._replace(merge_var_data=_var_data) + if isinstance(value, str): + return LiteralStringVar.create(value, _var_data=_var_data) + + if isinstance(value, bool): + return LiteralBooleanVar.create(value, _var_data=_var_data) + + if isinstance(value, (int, float)): + return LiteralNumberVar.create(value, _var_data=_var_data) + + if isinstance(value, dict): + return LiteralObjectVar.create(value, _var_data=_var_data) + + if isinstance(value, Color): + return LiteralStringVar.create(f"{value}", _var_data=_var_data) + + if isinstance(value, (list, tuple, set)): + return LiteralArrayVar.create(value, _var_data=_var_data) + if value is None: return ImmutableVar.create_safe("null", _var_data=_var_data) @@ -836,8 +858,6 @@ class LiteralVar(ImmutableVar): except ImportError: pass - from .sequence import LiteralArrayVar, LiteralStringVar - try: import base64 import io @@ -876,26 +896,6 @@ class LiteralVar(ImmutableVar): _var_data=_var_data, ) - if isinstance(value, dict): - return LiteralObjectVar.create(value, _var_data=_var_data) - - if isinstance(value, str): - return LiteralStringVar.create(value, _var_data=_var_data) - - if isinstance(value, Color): - return LiteralStringVar.create(f"{value}", _var_data=_var_data) - - from .number import LiteralBooleanVar, LiteralNumberVar - - if isinstance(value, bool): - return LiteralBooleanVar.create(value, _var_data=_var_data) - - if isinstance(value, (int, float)): - return LiteralNumberVar.create(value, _var_data=_var_data) - - if isinstance(value, (list, tuple, set)): - return LiteralArrayVar.create(value, _var_data=_var_data) - raise TypeError( f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}." ) diff --git a/reflex/style.py b/reflex/style.py index a844764e9..89bedd03b 100644 --- a/reflex/style.py +++ b/reflex/style.py @@ -6,6 +6,7 @@ from typing import Any, Literal, Tuple, Type from reflex import constants from reflex.components.core.breakpoints import Breakpoints, breakpoints_values +from reflex.constants.base import REFLEX_VAR_OPENING_TAG from reflex.event import EventChain from reflex.ivars.base import ImmutableCallableVar, ImmutableVar, LiteralVar from reflex.ivars.function import FunctionVar @@ -115,8 +116,8 @@ def media_query(breakpoint_expr: str): def convert_item( - style_item: str | Var, -) -> tuple[Var, VarData | ImmutableVarData | None]: + style_item: int | str | Var, +) -> tuple[str | Var, VarData | ImmutableVarData | None]: """Format a single value in a style dictionary. Args: @@ -128,6 +129,9 @@ def convert_item( if isinstance(style_item, Var): return style_item, style_item._get_all_var_data() + if isinstance(style_item, str) and REFLEX_VAR_OPENING_TAG not in style_item: + return style_item, None + # Otherwise, convert to Var to collapse VarData encoded in f-string. new_var = LiteralVar.create(style_item) var_data = new_var._get_all_var_data() if new_var is not None else None @@ -136,7 +140,7 @@ def convert_item( def convert_list( responsive_list: list[str | dict | Var], -) -> tuple[list[Var | dict[str, Var | list | dict]], VarData | None]: +) -> tuple[list[str | dict[str, Var | list | dict]], VarData | None]: """Format a responsive value list. Args: @@ -160,7 +164,7 @@ def convert_list( def convert( style_dict: dict[str, Var | dict | list | str], -) -> tuple[dict[str, Var | list | dict], VarData | None]: +) -> tuple[dict[str, str | list | dict], VarData | None]: """Format a style dictionary. Args: