reflex 0.5.3a2__py3-none-any.whl → 0.5.4a1__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.

Files changed (50) hide show
  1. reflex/.templates/apps/demo/code/webui/state.py +3 -2
  2. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +19 -20
  3. reflex/.templates/web/utils/state.js +6 -0
  4. reflex/__init__.py +7 -1
  5. reflex/__init__.pyi +2 -0
  6. reflex/app.py +2 -5
  7. reflex/compiler/compiler.py +2 -2
  8. reflex/components/component.py +19 -6
  9. reflex/components/core/client_side_routing.py +2 -2
  10. reflex/components/core/client_side_routing.pyi +1 -0
  11. reflex/components/core/upload.py +1 -1
  12. reflex/components/datadisplay/dataeditor.py +7 -2
  13. reflex/components/datadisplay/dataeditor.pyi +1 -0
  14. reflex/components/el/elements/forms.py +18 -11
  15. reflex/components/el/elements/forms.pyi +1 -0
  16. reflex/components/markdown/markdown.py +1 -1
  17. reflex/components/plotly/plotly.py +76 -12
  18. reflex/components/plotly/plotly.pyi +15 -82
  19. reflex/components/radix/themes/base.py +9 -2
  20. reflex/components/radix/themes/base.pyi +1 -0
  21. reflex/components/recharts/cartesian.py +42 -14
  22. reflex/components/recharts/cartesian.pyi +81 -17
  23. reflex/components/recharts/charts.py +12 -21
  24. reflex/components/recharts/charts.pyi +53 -14
  25. reflex/components/sonner/toast.py +30 -14
  26. reflex/components/sonner/toast.pyi +8 -4
  27. reflex/config.py +22 -14
  28. reflex/constants/__init__.py +2 -0
  29. reflex/constants/config.py +7 -0
  30. reflex/event.py +12 -6
  31. reflex/experimental/__init__.py +22 -2
  32. reflex/experimental/client_state.py +81 -23
  33. reflex/experimental/hooks.py +29 -35
  34. reflex/experimental/layout.py +8 -3
  35. reflex/experimental/layout.pyi +536 -0
  36. reflex/reflex.py +9 -5
  37. reflex/style.py +1 -0
  38. reflex/testing.py +44 -13
  39. reflex/utils/format.py +8 -1
  40. reflex/utils/processes.py +27 -0
  41. reflex/utils/pyi_generator.py +11 -4
  42. reflex/utils/serializers.py +114 -15
  43. reflex/utils/types.py +6 -2
  44. reflex/vars.py +39 -10
  45. reflex/vars.pyi +2 -2
  46. {reflex-0.5.3a2.dist-info → reflex-0.5.4a1.dist-info}/METADATA +1 -1
  47. {reflex-0.5.3a2.dist-info → reflex-0.5.4a1.dist-info}/RECORD +50 -49
  48. {reflex-0.5.3a2.dist-info → reflex-0.5.4a1.dist-info}/LICENSE +0 -0
  49. {reflex-0.5.3a2.dist-info → reflex-0.5.4a1.dist-info}/WHEEL +0 -0
  50. {reflex-0.5.3a2.dist-info → reflex-0.5.4a1.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  """Handle client side state with `useState`."""
2
+ from __future__ import annotations
2
3
 
3
4
  import dataclasses
4
5
  import sys
@@ -9,6 +10,13 @@ from reflex.event import EventChain, EventHandler, EventSpec, call_script
9
10
  from reflex.utils.imports import ImportVar
10
11
  from reflex.vars import Var, VarData
11
12
 
13
+ NoValue = object()
14
+
15
+
16
+ _refs_import = {
17
+ f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="refs")],
18
+ }
19
+
12
20
 
13
21
  def _client_state_ref(var_name: str) -> str:
14
22
  """Get the ref path for a ClientStateVar.
@@ -36,6 +44,9 @@ class ClientStateVar(Var):
36
44
  _setter_name: str = dataclasses.field()
37
45
  _getter_name: str = dataclasses.field()
38
46
 
47
+ # Whether to add the var and setter to the global `refs` object for use in any Component.
48
+ _global_ref: bool = dataclasses.field(default=True)
49
+
39
50
  # The type of the var.
40
51
  _var_type: Type = dataclasses.field(default=Any)
41
52
 
@@ -62,7 +73,9 @@ class ClientStateVar(Var):
62
73
  )
63
74
 
64
75
  @classmethod
65
- def create(cls, var_name, default=None) -> "ClientStateVar":
76
+ def create(
77
+ cls, var_name: str, default: Any = NoValue, global_ref: bool = True
78
+ ) -> "ClientStateVar":
66
79
  """Create a local_state Var that can be accessed and updated on the client.
67
80
 
68
81
  The `ClientStateVar` should be included in the highest parent component
@@ -72,7 +85,7 @@ class ClientStateVar(Var):
72
85
 
73
86
  To render the var in a component, use the `value` property.
74
87
 
75
- To update the var in a component, use the `set` property.
88
+ To update the var in a component, use the `set` property or `set_value` method.
76
89
 
77
90
  To access the var in an event handler, use the `retrieve` method with
78
91
  `callback` set to the event handler which should receive the value.
@@ -83,36 +96,45 @@ class ClientStateVar(Var):
83
96
  Args:
84
97
  var_name: The name of the variable.
85
98
  default: The default value of the variable.
99
+ global_ref: Whether the state should be accessible in any Component and on the backend.
86
100
 
87
101
  Returns:
88
102
  ClientStateVar
89
103
  """
90
- if default is None:
104
+ assert isinstance(var_name, str), "var_name must be a string."
105
+ if default is NoValue:
91
106
  default_var = Var.create_safe("", _var_is_local=False, _var_is_string=False)
92
107
  elif not isinstance(default, Var):
93
- default_var = Var.create_safe(default)
108
+ default_var = Var.create_safe(
109
+ default,
110
+ _var_is_string=isinstance(default, str),
111
+ )
94
112
  else:
95
113
  default_var = default
96
114
  setter_name = f"set{var_name.capitalize()}"
115
+ hooks = {
116
+ f"const [{var_name}, {setter_name}] = useState({default_var._var_name_unwrapped})": None,
117
+ }
118
+ imports = {
119
+ "react": [ImportVar(tag="useState")],
120
+ }
121
+ if global_ref:
122
+ hooks[f"{_client_state_ref(var_name)} = {var_name}"] = None
123
+ hooks[f"{_client_state_ref(setter_name)} = {setter_name}"] = None
124
+ imports.update(_refs_import)
97
125
  return cls(
98
126
  _var_name="",
99
127
  _setter_name=setter_name,
100
128
  _getter_name=var_name,
129
+ _global_ref=global_ref,
101
130
  _var_is_local=False,
102
131
  _var_is_string=False,
103
132
  _var_type=default_var._var_type,
104
133
  _var_data=VarData.merge(
105
134
  default_var._var_data,
106
135
  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
- },
136
+ hooks=hooks,
137
+ imports=imports,
116
138
  ),
117
139
  ),
118
140
  )
@@ -130,47 +152,73 @@ class ClientStateVar(Var):
130
152
  """
131
153
  return (
132
154
  Var.create_safe(
133
- _client_state_ref(self._getter_name),
155
+ _client_state_ref(self._getter_name)
156
+ if self._global_ref
157
+ else self._getter_name,
134
158
  _var_is_local=False,
135
159
  _var_is_string=False,
136
160
  )
137
161
  .to(self._var_type)
138
162
  ._replace(
139
163
  merge_var_data=VarData( # type: ignore
140
- imports={
141
- f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="refs")],
142
- }
164
+ imports=_refs_import if self._global_ref else {}
143
165
  )
144
166
  )
145
167
  )
146
168
 
147
- @property
148
- def set(self) -> Var:
169
+ def set_value(self, value: Any = NoValue) -> Var:
149
170
  """Set the value of the client state variable.
150
171
 
151
172
  This property can only be attached to a frontend event trigger.
152
173
 
153
174
  To set a value from a backend event handler, see `push`.
154
175
 
176
+ Args:
177
+ value: The value to set.
178
+
155
179
  Returns:
156
180
  A special EventChain Var which will set the value when triggered.
157
181
  """
182
+ setter = (
183
+ _client_state_ref(self._setter_name)
184
+ if self._global_ref
185
+ else self._setter_name
186
+ )
187
+ if value is not NoValue:
188
+ # This is a hack to make it work like an EventSpec taking an arg
189
+ value = Var.create_safe(value, _var_is_string=isinstance(value, str))
190
+ if not value._var_is_string and value._var_full_name.startswith("_"):
191
+ arg = value._var_name_unwrapped
192
+ else:
193
+ arg = ""
194
+ setter = f"({arg}) => {setter}({value._var_name_unwrapped})"
158
195
  return (
159
196
  Var.create_safe(
160
- _client_state_ref(self._setter_name),
197
+ setter,
161
198
  _var_is_local=False,
162
199
  _var_is_string=False,
163
200
  )
164
201
  .to(EventChain)
165
202
  ._replace(
166
203
  merge_var_data=VarData( # type: ignore
167
- imports={
168
- f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="refs")],
169
- }
204
+ imports=_refs_import if self._global_ref else {}
170
205
  )
171
206
  )
172
207
  )
173
208
 
209
+ @property
210
+ def set(self) -> Var:
211
+ """Set the value of the client state variable.
212
+
213
+ This property can only be attached to a frontend event trigger.
214
+
215
+ To set a value from a backend event handler, see `push`.
216
+
217
+ Returns:
218
+ A special EventChain Var which will set the value when triggered.
219
+ """
220
+ return self.set_value()
221
+
174
222
  def retrieve(
175
223
  self, callback: Union[EventHandler, Callable, None] = None
176
224
  ) -> EventSpec:
@@ -183,7 +231,12 @@ class ClientStateVar(Var):
183
231
 
184
232
  Returns:
185
233
  An EventSpec which will retrieve the value when triggered.
234
+
235
+ Raises:
236
+ ValueError: If the ClientStateVar is not global.
186
237
  """
238
+ if not self._global_ref:
239
+ raise ValueError("ClientStateVar must be global to retrieve the value.")
187
240
  return call_script(_client_state_ref(self._getter_name), callback=callback)
188
241
 
189
242
  def push(self, value: Any) -> EventSpec:
@@ -196,5 +249,10 @@ class ClientStateVar(Var):
196
249
 
197
250
  Returns:
198
251
  An EventSpec which will push the value when triggered.
252
+
253
+ Raises:
254
+ ValueError: If the ClientStateVar is not global.
199
255
  """
256
+ if not self._global_ref:
257
+ raise ValueError("ClientStateVar must be global to push the value.")
200
258
  return call_script(f"{_client_state_ref(self._setter_name)}({value})")
@@ -1,24 +1,15 @@
1
1
  """Add standard Hooks wrapper for React."""
2
-
3
- from typing import Optional, Union
2
+ from __future__ import annotations
4
3
 
5
4
  from reflex.utils.imports import ImportVar
6
5
  from reflex.vars import Var, VarData
7
6
 
8
7
 
9
- def _add_react_import(v: Optional[Var], tags: Union[str, list]):
10
- if v is None:
11
- return
12
-
13
- if isinstance(tags, str):
14
- tags = [tags]
15
-
16
- v._var_data = VarData( # type: ignore
17
- imports={"react": [ImportVar(tag=tag, install=False) for tag in tags]},
18
- )
8
+ def _compose_react_imports(tags: list[str]) -> dict[str, list[ImportVar]]:
9
+ return {"react": [ImportVar(tag=tag, install=False) for tag in tags]}
19
10
 
20
11
 
21
- def const(name, value) -> Optional[Var]:
12
+ def const(name, value) -> Var:
22
13
  """Create a constant Var.
23
14
 
24
15
  Args:
@@ -29,11 +20,11 @@ def const(name, value) -> Optional[Var]:
29
20
  The constant Var.
30
21
  """
31
22
  if isinstance(name, list):
32
- return Var.create(f"const [{', '.join(name)}] = {value}")
33
- return Var.create(f"const {name} = {value}")
23
+ return Var.create_safe(f"const [{', '.join(name)}] = {value}")
24
+ return Var.create_safe(f"const {name} = {value}")
34
25
 
35
26
 
36
- def useCallback(func, deps) -> Optional[Var]:
27
+ def useCallback(func, deps) -> Var:
37
28
  """Create a useCallback hook with a function and dependencies.
38
29
 
39
30
  Args:
@@ -43,15 +34,13 @@ def useCallback(func, deps) -> Optional[Var]:
43
34
  Returns:
44
35
  The useCallback hook.
45
36
  """
46
- if deps:
47
- v = Var.create(f"useCallback({func}, {deps})")
48
- else:
49
- v = Var.create(f"useCallback({func})")
50
- _add_react_import(v, "useCallback")
51
- return v
37
+ return Var.create_safe(
38
+ f"useCallback({func}, {deps})" if deps else f"useCallback({func})",
39
+ _var_data=VarData(imports=_compose_react_imports(["useCallback"])),
40
+ )
52
41
 
53
42
 
54
- def useContext(context) -> Optional[Var]:
43
+ def useContext(context) -> Var:
55
44
  """Create a useContext hook with a context.
56
45
 
57
46
  Args:
@@ -60,12 +49,13 @@ def useContext(context) -> Optional[Var]:
60
49
  Returns:
61
50
  The useContext hook.
62
51
  """
63
- v = Var.create(f"useContext({context})")
64
- _add_react_import(v, "useContext")
65
- return v
52
+ return Var.create_safe(
53
+ f"useContext({context})",
54
+ _var_data=VarData(imports=_compose_react_imports(["useContext"])),
55
+ )
66
56
 
67
57
 
68
- def useRef(default) -> Optional[Var]:
58
+ def useRef(default) -> Var:
69
59
  """Create a useRef hook with a default value.
70
60
 
71
61
  Args:
@@ -74,12 +64,13 @@ def useRef(default) -> Optional[Var]:
74
64
  Returns:
75
65
  The useRef hook.
76
66
  """
77
- v = Var.create(f"useRef({default})")
78
- _add_react_import(v, "useRef")
79
- return v
67
+ return Var.create_safe(
68
+ f"useRef({default})",
69
+ _var_data=VarData(imports=_compose_react_imports(["useRef"])),
70
+ )
80
71
 
81
72
 
82
- def useState(var_name, default=None) -> Optional[Var]:
73
+ def useState(var_name, default=None) -> Var:
83
74
  """Create a useState hook with a variable name and setter name.
84
75
 
85
76
  Args:
@@ -89,7 +80,10 @@ def useState(var_name, default=None) -> Optional[Var]:
89
80
  Returns:
90
81
  A useState hook.
91
82
  """
92
- setter_name = f"set{var_name.capitalize()}"
93
- v = const([var_name, setter_name], f"useState({default})")
94
- _add_react_import(v, "useState")
95
- return v
83
+ return const(
84
+ [var_name, f"set{var_name.capitalize()}"],
85
+ Var.create_safe(
86
+ f"useState({default})",
87
+ _var_data=VarData(imports=_compose_react_imports(["useState"])),
88
+ ),
89
+ )
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any
5
+ from typing import Any, List
6
6
 
7
7
  from reflex import color, cond
8
8
  from reflex.components.base.fragment import Fragment
@@ -65,8 +65,13 @@ class Sidebar(Box, MemoizationLeaf):
65
65
  }
66
66
  )
67
67
 
68
- def _get_hooks(self) -> Var | None:
69
- return hooks.useState("open", "true") if not self.State else None
68
+ def add_hooks(self) -> List[Var]:
69
+ """Get the hooks to render.
70
+
71
+ Returns:
72
+ The hooks for the sidebar.
73
+ """
74
+ return [hooks.useState("open", "true")] if not self.State else []
70
75
 
71
76
 
72
77
  class StatefulSidebar(ComponentState):