reflex 0.5.0a3__py3-none-any.whl → 0.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/web/utils/state.js +7 -2
- reflex/app.py +68 -50
- reflex/app_module_for_backend.py +3 -0
- reflex/base.py +5 -2
- reflex/components/component.py +49 -13
- reflex/components/core/__init__.py +7 -1
- reflex/components/core/banner.py +79 -6
- reflex/components/core/banner.pyi +130 -0
- reflex/components/core/cond.py +10 -4
- reflex/components/core/debounce.py +2 -4
- reflex/components/core/foreach.py +11 -0
- reflex/components/core/upload.py +9 -10
- reflex/components/el/elements/forms.py +12 -6
- reflex/components/el/elements/media.py +19 -0
- reflex/components/el/elements/media.pyi +3 -1
- reflex/components/gridjs/datatable.py +4 -2
- reflex/components/props.py +30 -0
- reflex/components/radix/themes/components/tabs.py +1 -1
- reflex/components/sonner/toast.py +102 -35
- reflex/components/sonner/toast.pyi +27 -14
- reflex/config.py +5 -3
- reflex/constants/compiler.py +3 -3
- reflex/constants/installer.py +1 -1
- reflex/event.py +38 -24
- reflex/experimental/__init__.py +4 -0
- reflex/experimental/client_state.py +198 -0
- reflex/state.py +59 -21
- reflex/style.py +3 -3
- reflex/testing.py +28 -9
- reflex/utils/exceptions.py +64 -8
- reflex/utils/format.py +73 -2
- reflex/utils/prerequisites.py +68 -23
- reflex/utils/processes.py +34 -4
- reflex/utils/telemetry.py +42 -16
- reflex/utils/types.py +16 -0
- reflex/vars.py +104 -61
- reflex/vars.pyi +7 -6
- {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/METADATA +1 -1
- {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/RECORD +42 -40
- {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/LICENSE +0 -0
- {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/WHEEL +0 -0
- {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/entry_points.txt +0 -0
|
@@ -7,15 +7,16 @@ from typing import Any, Dict, Literal, Optional, Union, overload
|
|
|
7
7
|
from reflex.vars import Var, BaseVar, ComputedVar
|
|
8
8
|
from reflex.event import EventChain, EventHandler, EventSpec
|
|
9
9
|
from reflex.style import Style
|
|
10
|
-
from typing import Literal
|
|
10
|
+
from typing import Any, Literal, Optional, Union
|
|
11
11
|
from reflex.base import Base
|
|
12
12
|
from reflex.components.component import Component, ComponentNamespace
|
|
13
13
|
from reflex.components.lucide.icon import Icon
|
|
14
|
+
from reflex.components.props import PropsBase
|
|
14
15
|
from reflex.event import EventSpec, call_script
|
|
15
16
|
from reflex.style import Style, color_mode
|
|
16
17
|
from reflex.utils import format
|
|
17
18
|
from reflex.utils.imports import ImportVar
|
|
18
|
-
from reflex.utils.serializers import serialize
|
|
19
|
+
from reflex.utils.serializers import serialize, serializer
|
|
19
20
|
from reflex.vars import Var, VarData
|
|
20
21
|
|
|
21
22
|
LiteralPosition = Literal[
|
|
@@ -28,20 +29,32 @@ LiteralPosition = Literal[
|
|
|
28
29
|
]
|
|
29
30
|
toast_ref = Var.create_safe("refs['__toast']")
|
|
30
31
|
|
|
31
|
-
class
|
|
32
|
-
|
|
32
|
+
class ToastAction(Base):
|
|
33
|
+
label: str
|
|
34
|
+
on_click: Any
|
|
35
|
+
|
|
36
|
+
@serializer
|
|
37
|
+
def serialize_action(action: ToastAction) -> dict: ...
|
|
33
38
|
|
|
34
39
|
class ToastProps(PropsBase):
|
|
35
|
-
description: str
|
|
36
|
-
close_button: bool
|
|
37
|
-
invert: bool
|
|
38
|
-
important: bool
|
|
39
|
-
duration: int
|
|
40
|
-
position: LiteralPosition
|
|
41
|
-
dismissible: bool
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
description: Optional[Union[str, Var]]
|
|
41
|
+
close_button: Optional[bool]
|
|
42
|
+
invert: Optional[bool]
|
|
43
|
+
important: Optional[bool]
|
|
44
|
+
duration: Optional[int]
|
|
45
|
+
position: Optional[LiteralPosition]
|
|
46
|
+
dismissible: Optional[bool]
|
|
47
|
+
action: Optional[ToastAction]
|
|
48
|
+
cancel: Optional[ToastAction]
|
|
49
|
+
id: Optional[str]
|
|
50
|
+
unstyled: Optional[bool]
|
|
51
|
+
style: Optional[Style]
|
|
52
|
+
action_button_styles: Optional[Style]
|
|
53
|
+
cancel_button_styles: Optional[Style]
|
|
54
|
+
on_dismiss: Optional[Any]
|
|
55
|
+
on_auto_close: Optional[Any]
|
|
56
|
+
|
|
57
|
+
def dict(self, *args, **kwargs) -> dict: ...
|
|
45
58
|
|
|
46
59
|
class Toaster(Component):
|
|
47
60
|
@staticmethod
|
reflex/config.py
CHANGED
|
@@ -251,8 +251,10 @@ class Config(Base):
|
|
|
251
251
|
The updated config values.
|
|
252
252
|
|
|
253
253
|
Raises:
|
|
254
|
-
|
|
254
|
+
EnvVarValueError: If an environment variable is set to an invalid type.
|
|
255
255
|
"""
|
|
256
|
+
from reflex.utils.exceptions import EnvVarValueError
|
|
257
|
+
|
|
256
258
|
updated_values = {}
|
|
257
259
|
# Iterate over the fields.
|
|
258
260
|
for key, field in self.__fields__.items():
|
|
@@ -273,11 +275,11 @@ class Config(Base):
|
|
|
273
275
|
env_var = env_var.lower() in ["true", "1", "yes"]
|
|
274
276
|
else:
|
|
275
277
|
env_var = field.type_(env_var)
|
|
276
|
-
except ValueError:
|
|
278
|
+
except ValueError as ve:
|
|
277
279
|
console.error(
|
|
278
280
|
f"Could not convert {key.upper()}={env_var} to type {field.type_}"
|
|
279
281
|
)
|
|
280
|
-
raise
|
|
282
|
+
raise EnvVarValueError from ve
|
|
281
283
|
|
|
282
284
|
# Set the value.
|
|
283
285
|
updated_values[key] = env_var
|
reflex/constants/compiler.py
CHANGED
|
@@ -103,9 +103,9 @@ class Imports(SimpleNamespace):
|
|
|
103
103
|
"""Common sets of import vars."""
|
|
104
104
|
|
|
105
105
|
EVENTS = {
|
|
106
|
-
"react":
|
|
107
|
-
f"/{Dirs.CONTEXTS_PATH}":
|
|
108
|
-
f"/{Dirs.STATE_PATH}":
|
|
106
|
+
"react": [ImportVar(tag="useContext")],
|
|
107
|
+
f"/{Dirs.CONTEXTS_PATH}": [ImportVar(tag="EventLoopContext")],
|
|
108
|
+
f"/{Dirs.STATE_PATH}": [ImportVar(tag=CompileVars.TO_EVENT)],
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
|
reflex/constants/installer.py
CHANGED
reflex/event.py
CHANGED
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import inspect
|
|
6
6
|
from base64 import b64encode
|
|
7
|
-
from types import FunctionType
|
|
8
7
|
from typing import (
|
|
9
8
|
Any,
|
|
10
9
|
Callable,
|
|
@@ -180,8 +179,10 @@ class EventHandler(EventActionsMixin):
|
|
|
180
179
|
The event spec, containing both the function and args.
|
|
181
180
|
|
|
182
181
|
Raises:
|
|
183
|
-
|
|
182
|
+
EventHandlerTypeError: If the arguments are invalid.
|
|
184
183
|
"""
|
|
184
|
+
from reflex.utils.exceptions import EventHandlerTypeError
|
|
185
|
+
|
|
185
186
|
# Get the function args.
|
|
186
187
|
fn_args = inspect.getfullargspec(self.fn).args[1:]
|
|
187
188
|
fn_args = (Var.create_safe(arg) for arg in fn_args)
|
|
@@ -197,7 +198,7 @@ class EventHandler(EventActionsMixin):
|
|
|
197
198
|
try:
|
|
198
199
|
values.append(Var.create(arg, _var_is_string=isinstance(arg, str)))
|
|
199
200
|
except TypeError as e:
|
|
200
|
-
raise
|
|
201
|
+
raise EventHandlerTypeError(
|
|
201
202
|
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
|
202
203
|
) from e
|
|
203
204
|
payload = tuple(zip(fn_args, values))
|
|
@@ -256,8 +257,10 @@ class EventSpec(EventActionsMixin):
|
|
|
256
257
|
The event spec with the new arguments.
|
|
257
258
|
|
|
258
259
|
Raises:
|
|
259
|
-
|
|
260
|
+
EventHandlerTypeError: If the arguments are invalid.
|
|
260
261
|
"""
|
|
262
|
+
from reflex.utils.exceptions import EventHandlerTypeError
|
|
263
|
+
|
|
261
264
|
# Get the remaining unfilled function args.
|
|
262
265
|
fn_args = inspect.getfullargspec(self.handler.fn).args[1 + len(self.args) :]
|
|
263
266
|
fn_args = (Var.create_safe(arg) for arg in fn_args)
|
|
@@ -268,7 +271,7 @@ class EventSpec(EventActionsMixin):
|
|
|
268
271
|
try:
|
|
269
272
|
values.append(Var.create(arg, _var_is_string=isinstance(arg, str)))
|
|
270
273
|
except TypeError as e:
|
|
271
|
-
raise
|
|
274
|
+
raise EventHandlerTypeError(
|
|
272
275
|
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
|
273
276
|
) from e
|
|
274
277
|
new_payload = tuple(zip(fn_args, values))
|
|
@@ -312,10 +315,12 @@ class CallableEventSpec(EventSpec):
|
|
|
312
315
|
The EventSpec returned from calling the function.
|
|
313
316
|
|
|
314
317
|
Raises:
|
|
315
|
-
|
|
318
|
+
EventHandlerTypeError: If the CallableEventSpec has no associated function.
|
|
316
319
|
"""
|
|
320
|
+
from reflex.utils.exceptions import EventHandlerTypeError
|
|
321
|
+
|
|
317
322
|
if self.fn is None:
|
|
318
|
-
raise
|
|
323
|
+
raise EventHandlerTypeError("CallableEventSpec has no associated function.")
|
|
319
324
|
return self.fn(*args, **kwargs)
|
|
320
325
|
|
|
321
326
|
|
|
@@ -462,18 +467,27 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
|
|
|
462
467
|
)
|
|
463
468
|
|
|
464
469
|
|
|
465
|
-
def redirect(
|
|
470
|
+
def redirect(
|
|
471
|
+
path: str | Var[str],
|
|
472
|
+
external: Optional[bool] = False,
|
|
473
|
+
replace: Optional[bool] = False,
|
|
474
|
+
) -> EventSpec:
|
|
466
475
|
"""Redirect to a new path.
|
|
467
476
|
|
|
468
477
|
Args:
|
|
469
478
|
path: The path to redirect to.
|
|
470
479
|
external: Whether to open in new tab or not.
|
|
480
|
+
replace: If True, the current page will not create a new history entry.
|
|
471
481
|
|
|
472
482
|
Returns:
|
|
473
483
|
An event to redirect to the path.
|
|
474
484
|
"""
|
|
475
485
|
return server_side(
|
|
476
|
-
"_redirect",
|
|
486
|
+
"_redirect",
|
|
487
|
+
get_fn_signature(redirect),
|
|
488
|
+
path=path,
|
|
489
|
+
external=external,
|
|
490
|
+
replace=replace,
|
|
477
491
|
)
|
|
478
492
|
|
|
479
493
|
|
|
@@ -700,7 +714,11 @@ def _callback_arg_spec(eval_result):
|
|
|
700
714
|
|
|
701
715
|
def call_script(
|
|
702
716
|
javascript_code: str,
|
|
703
|
-
callback:
|
|
717
|
+
callback: EventSpec
|
|
718
|
+
| EventHandler
|
|
719
|
+
| Callable
|
|
720
|
+
| List[EventSpec | EventHandler | Callable]
|
|
721
|
+
| None = None,
|
|
704
722
|
) -> EventSpec:
|
|
705
723
|
"""Create an event handler that executes arbitrary javascript code.
|
|
706
724
|
|
|
@@ -710,21 +728,14 @@ def call_script(
|
|
|
710
728
|
|
|
711
729
|
Returns:
|
|
712
730
|
EventSpec: An event that will execute the client side javascript.
|
|
713
|
-
|
|
714
|
-
Raises:
|
|
715
|
-
ValueError: If the callback is not a valid event handler.
|
|
716
731
|
"""
|
|
717
732
|
callback_kwargs = {}
|
|
718
733
|
if callback is not None:
|
|
719
|
-
arg_name = parse_args_spec(_callback_arg_spec)[0]._var_name
|
|
720
|
-
if isinstance(callback, EventHandler):
|
|
721
|
-
event_spec = call_event_handler(callback, _callback_arg_spec)
|
|
722
|
-
elif isinstance(callback, FunctionType):
|
|
723
|
-
event_spec = call_event_fn(callback, _callback_arg_spec)[0]
|
|
724
|
-
else:
|
|
725
|
-
raise ValueError("Cannot use {callback!r} as a call_script callback.")
|
|
726
734
|
callback_kwargs = {
|
|
727
|
-
"callback":
|
|
735
|
+
"callback": format.format_queue_events(
|
|
736
|
+
callback,
|
|
737
|
+
args_spec=lambda result: [result],
|
|
738
|
+
)
|
|
728
739
|
}
|
|
729
740
|
return server_side(
|
|
730
741
|
"_call_script",
|
|
@@ -834,10 +845,11 @@ def call_event_fn(fn: Callable, arg: Union[Var, ArgsSpec]) -> list[EventSpec]:
|
|
|
834
845
|
The event specs from calling the function.
|
|
835
846
|
|
|
836
847
|
Raises:
|
|
837
|
-
|
|
848
|
+
EventHandlerValueError: If the lambda has an invalid signature.
|
|
838
849
|
"""
|
|
839
850
|
# Import here to avoid circular imports.
|
|
840
851
|
from reflex.event import EventHandler, EventSpec
|
|
852
|
+
from reflex.utils.exceptions import EventHandlerValueError
|
|
841
853
|
|
|
842
854
|
# Get the args of the lambda.
|
|
843
855
|
args = inspect.getfullargspec(fn).args
|
|
@@ -851,7 +863,7 @@ def call_event_fn(fn: Callable, arg: Union[Var, ArgsSpec]) -> list[EventSpec]:
|
|
|
851
863
|
elif len(args) == 1:
|
|
852
864
|
out = fn(arg)
|
|
853
865
|
else:
|
|
854
|
-
raise
|
|
866
|
+
raise EventHandlerValueError(f"Lambda {fn} must have 0 or 1 arguments.")
|
|
855
867
|
|
|
856
868
|
# Convert the output to a list.
|
|
857
869
|
if not isinstance(out, List):
|
|
@@ -869,7 +881,9 @@ def call_event_fn(fn: Callable, arg: Union[Var, ArgsSpec]) -> list[EventSpec]:
|
|
|
869
881
|
|
|
870
882
|
# Make sure the event spec is valid.
|
|
871
883
|
if not isinstance(e, EventSpec):
|
|
872
|
-
raise
|
|
884
|
+
raise EventHandlerValueError(
|
|
885
|
+
f"Lambda {fn} returned an invalid event spec: {e}."
|
|
886
|
+
)
|
|
873
887
|
|
|
874
888
|
# Add the event spec to the chain.
|
|
875
889
|
events.append(e)
|
reflex/experimental/__init__.py
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from types import SimpleNamespace
|
|
4
4
|
|
|
5
|
+
from reflex.components.props import PropsBase
|
|
5
6
|
from reflex.components.radix.themes.components.progress import progress as progress
|
|
6
7
|
from reflex.components.sonner.toast import toast as toast
|
|
7
8
|
|
|
8
9
|
from ..utils.console import warn
|
|
9
10
|
from . import hooks as hooks
|
|
11
|
+
from .client_state import ClientStateVar as ClientStateVar
|
|
10
12
|
from .layout import layout as layout
|
|
11
13
|
from .misc import run_in_thread as run_in_thread
|
|
12
14
|
|
|
@@ -15,9 +17,11 @@ warn(
|
|
|
15
17
|
)
|
|
16
18
|
|
|
17
19
|
_x = SimpleNamespace(
|
|
20
|
+
client_state=ClientStateVar.create,
|
|
18
21
|
hooks=hooks,
|
|
19
22
|
layout=layout,
|
|
20
23
|
progress=progress,
|
|
24
|
+
PropsBase=PropsBase,
|
|
21
25
|
run_in_thread=run_in_thread,
|
|
22
26
|
toast=toast,
|
|
23
27
|
)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""Handle client side state with `useState`."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Any, Callable, Optional, Type
|
|
6
|
+
|
|
7
|
+
from reflex import constants
|
|
8
|
+
from reflex.event import EventChain, EventHandler, EventSpec, call_script
|
|
9
|
+
from reflex.utils.imports import ImportVar
|
|
10
|
+
from reflex.vars import Var, VarData
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _client_state_ref(var_name: str) -> str:
|
|
14
|
+
"""Get the ref path for a ClientStateVar.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
var_name: The name of the variable.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
An accessor for ClientStateVar ref as a string.
|
|
21
|
+
"""
|
|
22
|
+
return f"refs['_client_state_{var_name}']"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclasses.dataclass(
|
|
26
|
+
eq=False,
|
|
27
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
28
|
+
)
|
|
29
|
+
class ClientStateVar(Var):
|
|
30
|
+
"""A Var that exists on the client via useState."""
|
|
31
|
+
|
|
32
|
+
# The name of the var.
|
|
33
|
+
_var_name: str = dataclasses.field()
|
|
34
|
+
|
|
35
|
+
# Track the names of the getters and setters
|
|
36
|
+
_setter_name: str = dataclasses.field()
|
|
37
|
+
_getter_name: str = dataclasses.field()
|
|
38
|
+
|
|
39
|
+
# The type of the var.
|
|
40
|
+
_var_type: Type = dataclasses.field(default=Any)
|
|
41
|
+
|
|
42
|
+
# Whether this is a local javascript variable.
|
|
43
|
+
_var_is_local: bool = dataclasses.field(default=False)
|
|
44
|
+
|
|
45
|
+
# Whether the var is a string literal.
|
|
46
|
+
_var_is_string: bool = dataclasses.field(default=False)
|
|
47
|
+
|
|
48
|
+
# _var_full_name should be prefixed with _var_state
|
|
49
|
+
_var_full_name_needs_state_prefix: bool = dataclasses.field(default=False)
|
|
50
|
+
|
|
51
|
+
# Extra metadata associated with the Var
|
|
52
|
+
_var_data: Optional[VarData] = dataclasses.field(default=None)
|
|
53
|
+
|
|
54
|
+
def __hash__(self) -> int:
|
|
55
|
+
"""Define a hash function for a var.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
The hash of the var.
|
|
59
|
+
"""
|
|
60
|
+
return hash(
|
|
61
|
+
(self._var_name, str(self._var_type), self._getter_name, self._setter_name)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def create(cls, var_name, default=None) -> "ClientStateVar":
|
|
66
|
+
"""Create a local_state Var that can be accessed and updated on the client.
|
|
67
|
+
|
|
68
|
+
The `ClientStateVar` should be included in the highest parent component
|
|
69
|
+
that contains the components which will access and manipulate the client
|
|
70
|
+
state. It has no visual rendering, including it ensures that the
|
|
71
|
+
`useState` hook is called in the correct scope.
|
|
72
|
+
|
|
73
|
+
To render the var in a component, use the `value` property.
|
|
74
|
+
|
|
75
|
+
To update the var in a component, use the `set` property.
|
|
76
|
+
|
|
77
|
+
To access the var in an event handler, use the `retrieve` method with
|
|
78
|
+
`callback` set to the event handler which should receive the value.
|
|
79
|
+
|
|
80
|
+
To update the var in an event handler, use the `push` method with the
|
|
81
|
+
value to update.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
var_name: The name of the variable.
|
|
85
|
+
default: The default value of the variable.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
ClientStateVar
|
|
89
|
+
"""
|
|
90
|
+
if default is None:
|
|
91
|
+
default_var = Var.create_safe("", _var_is_local=False, _var_is_string=False)
|
|
92
|
+
elif not isinstance(default, Var):
|
|
93
|
+
default_var = Var.create_safe(default)
|
|
94
|
+
else:
|
|
95
|
+
default_var = default
|
|
96
|
+
setter_name = f"set{var_name.capitalize()}"
|
|
97
|
+
return cls(
|
|
98
|
+
_var_name="",
|
|
99
|
+
_setter_name=setter_name,
|
|
100
|
+
_getter_name=var_name,
|
|
101
|
+
_var_is_local=False,
|
|
102
|
+
_var_is_string=False,
|
|
103
|
+
_var_type=default_var._var_type,
|
|
104
|
+
_var_data=VarData.merge(
|
|
105
|
+
default_var._var_data,
|
|
106
|
+
VarData( # type: ignore
|
|
107
|
+
hooks={
|
|
108
|
+
f"const [{var_name}, {setter_name}] = useState({default_var._var_name_unwrapped})": None,
|
|
109
|
+
f"{_client_state_ref(var_name)} = {var_name}": None,
|
|
110
|
+
f"{_client_state_ref(setter_name)} = {setter_name}": None,
|
|
111
|
+
},
|
|
112
|
+
imports={
|
|
113
|
+
"react": [ImportVar(tag="useState", install=False)],
|
|
114
|
+
f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="refs")],
|
|
115
|
+
},
|
|
116
|
+
),
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def value(self) -> Var:
|
|
122
|
+
"""Get a placeholder for the Var.
|
|
123
|
+
|
|
124
|
+
This property can only be rendered on the frontend.
|
|
125
|
+
|
|
126
|
+
To access the value in a backend event handler, see `retrieve`.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
an accessor for the client state variable.
|
|
130
|
+
"""
|
|
131
|
+
return (
|
|
132
|
+
Var.create_safe(
|
|
133
|
+
_client_state_ref(self._getter_name),
|
|
134
|
+
_var_is_local=False,
|
|
135
|
+
_var_is_string=False,
|
|
136
|
+
)
|
|
137
|
+
.to(self._var_type)
|
|
138
|
+
._replace(
|
|
139
|
+
merge_var_data=VarData( # type: ignore
|
|
140
|
+
imports={
|
|
141
|
+
f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="refs")],
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def set(self) -> Var:
|
|
149
|
+
"""Set the value of the client state variable.
|
|
150
|
+
|
|
151
|
+
This property can only be attached to a frontend event trigger.
|
|
152
|
+
|
|
153
|
+
To set a value from a backend event handler, see `push`.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
A special EventChain Var which will set the value when triggered.
|
|
157
|
+
"""
|
|
158
|
+
return (
|
|
159
|
+
Var.create_safe(
|
|
160
|
+
_client_state_ref(self._setter_name),
|
|
161
|
+
_var_is_local=False,
|
|
162
|
+
_var_is_string=False,
|
|
163
|
+
)
|
|
164
|
+
.to(EventChain)
|
|
165
|
+
._replace(
|
|
166
|
+
merge_var_data=VarData( # type: ignore
|
|
167
|
+
imports={
|
|
168
|
+
f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="refs")],
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def retrieve(self, callback: EventHandler | Callable | None = None) -> EventSpec:
|
|
175
|
+
"""Pass the value of the client state variable to a backend EventHandler.
|
|
176
|
+
|
|
177
|
+
The event handler must `yield` or `return` the EventSpec to trigger the event.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
callback: The callback to pass the value to.
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
An EventSpec which will retrieve the value when triggered.
|
|
184
|
+
"""
|
|
185
|
+
return call_script(_client_state_ref(self._getter_name), callback=callback)
|
|
186
|
+
|
|
187
|
+
def push(self, value: Any) -> EventSpec:
|
|
188
|
+
"""Push a value to the client state variable from the backend.
|
|
189
|
+
|
|
190
|
+
The event handler must `yield` or `return` the EventSpec to trigger the event.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
value: The value to update.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
An EventSpec which will push the value when triggered.
|
|
197
|
+
"""
|
|
198
|
+
return call_script(f"{_client_state_ref(self._setter_name)}({value})")
|