reflex 0.6.5a2__py3-none-any.whl → 0.6.6__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 (52) hide show
  1. reflex/.templates/web/utils/state.js +39 -14
  2. reflex/__init__.py +3 -1
  3. reflex/__init__.pyi +3 -0
  4. reflex/app.py +24 -4
  5. reflex/assets.py +95 -0
  6. reflex/base.py +2 -2
  7. reflex/components/base/error_boundary.py +99 -36
  8. reflex/components/base/error_boundary.pyi +3 -4
  9. reflex/components/component.py +29 -7
  10. reflex/components/core/cond.py +8 -0
  11. reflex/components/core/upload.py +8 -5
  12. reflex/components/datadisplay/code.py +1 -1
  13. reflex/components/datadisplay/logo.py +26 -13
  14. reflex/components/el/__init__.pyi +2 -0
  15. reflex/components/el/elements/__init__.py +1 -0
  16. reflex/components/el/elements/__init__.pyi +3 -0
  17. reflex/components/el/elements/forms.py +1 -0
  18. reflex/components/el/elements/forms.pyi +1 -0
  19. reflex/components/moment/moment.py +4 -3
  20. reflex/components/moment/moment.pyi +12 -2
  21. reflex/components/plotly/plotly.py +1 -1
  22. reflex/components/radix/primitives/drawer.py +5 -23
  23. reflex/components/radix/themes/base.py +3 -0
  24. reflex/components/radix/themes/components/segmented_control.py +3 -1
  25. reflex/components/radix/themes/components/segmented_control.pyi +7 -2
  26. reflex/components/radix/themes/components/text_field.py +3 -0
  27. reflex/components/radix/themes/components/text_field.pyi +4 -0
  28. reflex/components/recharts/recharts.py +2 -14
  29. reflex/components/recharts/recharts.pyi +0 -1
  30. reflex/components/sonner/toast.py +23 -12
  31. reflex/components/sonner/toast.pyi +6 -6
  32. reflex/config.py +60 -9
  33. reflex/constants/base.py +12 -0
  34. reflex/constants/installer.py +3 -3
  35. reflex/constants/style.py +1 -1
  36. reflex/event.py +22 -5
  37. reflex/experimental/assets.py +14 -36
  38. reflex/reflex.py +16 -35
  39. reflex/state.py +99 -28
  40. reflex/utils/exceptions.py +4 -0
  41. reflex/utils/prerequisites.py +174 -40
  42. reflex/utils/redir.py +13 -4
  43. reflex/utils/serializers.py +52 -1
  44. reflex/utils/telemetry.py +2 -1
  45. reflex/utils/types.py +52 -1
  46. reflex/vars/base.py +18 -4
  47. reflex/vars/function.py +283 -37
  48. {reflex-0.6.5a2.dist-info → reflex-0.6.6.dist-info}/METADATA +3 -2
  49. {reflex-0.6.5a2.dist-info → reflex-0.6.6.dist-info}/RECORD +52 -51
  50. {reflex-0.6.5a2.dist-info → reflex-0.6.6.dist-info}/LICENSE +0 -0
  51. {reflex-0.6.5a2.dist-info → reflex-0.6.6.dist-info}/WHEEL +0 -0
  52. {reflex-0.6.5a2.dist-info → reflex-0.6.6.dist-info}/entry_points.txt +0 -0
@@ -1,22 +1,23 @@
1
1
  """A Reflex logo component."""
2
2
 
3
+ from typing import Union
4
+
3
5
  import reflex as rx
4
6
 
5
7
 
6
- def logo(**props):
7
- """A Reflex logo.
8
+ def svg_logo(color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "white")):
9
+ """A Reflex logo SVG.
8
10
 
9
11
  Args:
10
- **props: The props to pass to the component.
12
+ color: The color of the logo.
11
13
 
12
14
  Returns:
13
- The logo component.
15
+ The Reflex logo SVG.
14
16
  """
15
17
 
16
18
  def logo_path(d):
17
19
  return rx.el.svg.path(
18
20
  d=d,
19
- fill=rx.color_mode_cond("#110F1F", "white"),
20
21
  )
21
22
 
22
23
  paths = [
@@ -28,18 +29,30 @@ def logo(**props):
28
29
  "M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z",
29
30
  ]
30
31
 
32
+ return rx.el.svg(
33
+ *[logo_path(d) for d in paths],
34
+ width="56",
35
+ height="12",
36
+ viewBox="0 0 56 12",
37
+ fill=color,
38
+ xmlns="http://www.w3.org/2000/svg",
39
+ )
40
+
41
+
42
+ def logo(**props):
43
+ """A Reflex logo.
44
+
45
+ Args:
46
+ **props: The props to pass to the component.
47
+
48
+ Returns:
49
+ The logo component.
50
+ """
31
51
  return rx.center(
32
52
  rx.link(
33
53
  rx.hstack(
34
54
  "Built with ",
35
- rx.el.svg(
36
- *[logo_path(d) for d in paths],
37
- width="56",
38
- height="12",
39
- viewBox="0 0 56 12",
40
- fill="none",
41
- xmlns="http://www.w3.org/2000/svg",
42
- ),
55
+ svg_logo(),
43
56
  text_align="center",
44
57
  align="center",
45
58
  padding="1em",
@@ -5,6 +5,7 @@
5
5
 
6
6
  from . import elements as elements
7
7
  from .elements.forms import Button as Button
8
+ from .elements.forms import Datalist as Datalist
8
9
  from .elements.forms import Fieldset as Fieldset
9
10
  from .elements.forms import Form as Form
10
11
  from .elements.forms import Input as Input
@@ -18,6 +19,7 @@ from .elements.forms import Progress as Progress
18
19
  from .elements.forms import Select as Select
19
20
  from .elements.forms import Textarea as Textarea
20
21
  from .elements.forms import button as button
22
+ from .elements.forms import datalist as datalist
21
23
  from .elements.forms import fieldset as fieldset
22
24
  from .elements.forms import form as form
23
25
  from .elements.forms import input as input
@@ -7,6 +7,7 @@ from reflex.utils import lazy_loader
7
7
  _MAPPING = {
8
8
  "forms": [
9
9
  "button",
10
+ "datalist",
10
11
  "fieldset",
11
12
  "form",
12
13
  "input",
@@ -4,6 +4,7 @@
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from .forms import Button as Button
7
+ from .forms import Datalist as Datalist
7
8
  from .forms import Fieldset as Fieldset
8
9
  from .forms import Form as Form
9
10
  from .forms import Input as Input
@@ -17,6 +18,7 @@ from .forms import Progress as Progress
17
18
  from .forms import Select as Select
18
19
  from .forms import Textarea as Textarea
19
20
  from .forms import button as button
21
+ from .forms import datalist as datalist
20
22
  from .forms import fieldset as fieldset
21
23
  from .forms import form as form
22
24
  from .forms import input as input
@@ -226,6 +228,7 @@ from .typography import ul as ul
226
228
  _MAPPING = {
227
229
  "forms": [
228
230
  "button",
231
+ "datalist",
229
232
  "fieldset",
230
233
  "form",
231
234
  "input",
@@ -681,6 +681,7 @@ class Textarea(BaseHTML):
681
681
 
682
682
 
683
683
  button = Button.create
684
+ datalist = Datalist.create
684
685
  fieldset = Fieldset.create
685
686
  form = Form.create
686
687
  input = Input.create
@@ -1490,6 +1490,7 @@ class Textarea(BaseHTML):
1490
1490
  ...
1491
1491
 
1492
1492
  button = Button.create
1493
+ datalist = Datalist.create
1493
1494
  fieldset = Fieldset.create
1494
1495
  form = Form.create
1495
1496
  input = Input.create
@@ -1,7 +1,8 @@
1
1
  """Moment component for humanized date rendering."""
2
2
 
3
3
  import dataclasses
4
- from typing import List, Optional
4
+ from datetime import date, datetime, time, timedelta
5
+ from typing import List, Optional, Union
5
6
 
6
7
  from reflex.components.component import NoSSRComponent
7
8
  from reflex.event import EventHandler, passthrough_event_spec
@@ -19,7 +20,7 @@ class MomentDelta:
19
20
  weeks: Optional[int] = dataclasses.field(default=None)
20
21
  days: Optional[int] = dataclasses.field(default=None)
21
22
  hours: Optional[int] = dataclasses.field(default=None)
22
- minutess: Optional[int] = dataclasses.field(default=None)
23
+ minutes: Optional[int] = dataclasses.field(default=None)
23
24
  seconds: Optional[int] = dataclasses.field(default=None)
24
25
  milliseconds: Optional[int] = dataclasses.field(default=None)
25
26
 
@@ -78,7 +79,7 @@ class Moment(NoSSRComponent):
78
79
  duration: Var[str]
79
80
 
80
81
  # The date to display (also work if passed as children).
81
- date: Var[str]
82
+ date: Var[Union[str, datetime, date, time, timedelta]]
82
83
 
83
84
  # Shows the duration (elapsed time) between now and the provided datetime.
84
85
  duration_from_now: Var[bool]
@@ -4,6 +4,7 @@
4
4
  # This file was generated by `reflex/utils/pyi_generator.py`!
5
5
  # ------------------------------------------------------
6
6
  import dataclasses
7
+ from datetime import date, datetime, time, timedelta
7
8
  from typing import Any, Dict, Optional, Union, overload
8
9
 
9
10
  from reflex.components.component import NoSSRComponent
@@ -20,7 +21,7 @@ class MomentDelta:
20
21
  weeks: Optional[int]
21
22
  days: Optional[int]
22
23
  hours: Optional[int]
23
- minutess: Optional[int]
24
+ minutes: Optional[int]
24
25
  seconds: Optional[int]
25
26
  milliseconds: Optional[int]
26
27
 
@@ -46,7 +47,16 @@ class Moment(NoSSRComponent):
46
47
  decimal: Optional[Union[Var[bool], bool]] = None,
47
48
  unit: Optional[Union[Var[str], str]] = None,
48
49
  duration: Optional[Union[Var[str], str]] = None,
49
- date: Optional[Union[Var[str], str]] = None,
50
+ date: Optional[
51
+ Union[
52
+ Var[Union[date, datetime, str, time, timedelta]],
53
+ date,
54
+ datetime,
55
+ str,
56
+ time,
57
+ timedelta,
58
+ ]
59
+ ] = None,
50
60
  duration_from_now: Optional[Union[Var[bool], bool]] = None,
51
61
  unix: Optional[Union[Var[bool], bool]] = None,
52
62
  local: Optional[Union[Var[bool], bool]] = None,
@@ -255,7 +255,7 @@ const extractPoints = (points) => {
255
255
 
256
256
  def _render(self):
257
257
  tag = super()._render()
258
- figure = self.data.to(dict)
258
+ figure = self.data.to(dict) if self.data is not None else Var.create({})
259
259
  merge_dicts = [] # Data will be merged and spread from these dict Vars
260
260
  if self.layout is not None:
261
261
  # Why is this not a literal dict? Great question... it didn't work
@@ -11,7 +11,6 @@ from reflex.components.radix.primitives.base import RadixPrimitiveComponent
11
11
  from reflex.components.radix.themes.base import Theme
12
12
  from reflex.components.radix.themes.layout.flex import Flex
13
13
  from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
14
- from reflex.utils import console
15
14
  from reflex.vars.base import Var
16
15
 
17
16
 
@@ -140,19 +139,19 @@ class DrawerContent(DrawerComponent):
140
139
  base_style.update(style)
141
140
  return {"css": base_style}
142
141
 
143
- # Fired when the drawer content is opened. Deprecated.
142
+ # Fired when the drawer content is opened.
144
143
  on_open_auto_focus: EventHandler[no_args_event_spec]
145
144
 
146
- # Fired when the drawer content is closed. Deprecated.
145
+ # Fired when the drawer content is closed.
147
146
  on_close_auto_focus: EventHandler[no_args_event_spec]
148
147
 
149
- # Fired when the escape key is pressed. Deprecated.
148
+ # Fired when the escape key is pressed.
150
149
  on_escape_key_down: EventHandler[no_args_event_spec]
151
150
 
152
- # Fired when the pointer is down outside the drawer content. Deprecated.
151
+ # Fired when the pointer is down outside the drawer content.
153
152
  on_pointer_down_outside: EventHandler[no_args_event_spec]
154
153
 
155
- # Fired when interacting outside the drawer content. Deprecated.
154
+ # Fired when interacting outside the drawer content.
156
155
  on_interact_outside: EventHandler[no_args_event_spec]
157
156
 
158
157
  @classmethod
@@ -170,23 +169,6 @@ class DrawerContent(DrawerComponent):
170
169
  Returns:
171
170
  The drawer content.
172
171
  """
173
- deprecated_properties = [
174
- "on_open_auto_focus",
175
- "on_close_auto_focus",
176
- "on_escape_key_down",
177
- "on_pointer_down_outside",
178
- "on_interact_outside",
179
- ]
180
-
181
- for prop in deprecated_properties:
182
- if prop in props:
183
- console.deprecate(
184
- feature_name="drawer content events",
185
- reason=f"The `{prop}` event is deprecated and will be removed in 0.7.0.",
186
- deprecation_version="0.6.3",
187
- removal_version="0.7.0",
188
- )
189
-
190
172
  comp = super().create(*children, **props)
191
173
 
192
174
  return Theme.create(comp)
@@ -112,6 +112,9 @@ class RadixThemesComponent(Component):
112
112
 
113
113
  library = "@radix-ui/themes@^3.0.0"
114
114
 
115
+ # Temporary pin < 3.1.5 until radix-ui/themes#627 is resolved.
116
+ library = library + " && <3.1.5"
117
+
115
118
  # "Fake" prop color_scheme is used to avoid shadowing CSS prop "color".
116
119
  _rename_props: Dict[str, str] = {"colorScheme": "color"}
117
120
 
@@ -12,7 +12,9 @@ from reflex.vars.base import Var
12
12
  from ..base import LiteralAccentColor, RadixThemesComponent
13
13
 
14
14
 
15
- def on_value_change(value: Var[str | List[str]]) -> Tuple[Var[str | List[str]]]:
15
+ def on_value_change(
16
+ value: Var[Union[str, List[str]]],
17
+ ) -> Tuple[Var[Union[str, List[str]]]]:
16
18
  """Handle the on_value_change event.
17
19
 
18
20
  Args:
@@ -13,7 +13,9 @@ from reflex.vars.base import Var
13
13
 
14
14
  from ..base import RadixThemesComponent
15
15
 
16
- def on_value_change(value: Var[str | List[str]]) -> Tuple[Var[str | List[str]]]: ...
16
+ def on_value_change(
17
+ value: Var[Union[str, List[str]]],
18
+ ) -> Tuple[Var[Union[str, List[str]]]]: ...
17
19
 
18
20
  class SegmentedControlRoot(RadixThemesComponent):
19
21
  @overload
@@ -118,7 +120,10 @@ class SegmentedControlRoot(RadixThemesComponent):
118
120
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
119
121
  on_blur: Optional[EventType[[], BASE_STATE]] = None,
120
122
  on_change: Optional[
121
- Union[EventType[[], BASE_STATE], EventType[[str | List[str]], BASE_STATE]]
123
+ Union[
124
+ EventType[[], BASE_STATE],
125
+ EventType[[Union[str, List[str]]], BASE_STATE],
126
+ ]
122
127
  ] = None,
123
128
  on_click: Optional[EventType[[], BASE_STATE]] = None,
124
129
  on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
@@ -67,6 +67,9 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
67
67
  # Value of the input
68
68
  value: Var[Union[str, int, float]]
69
69
 
70
+ # References a datalist for suggested options
71
+ list: Var[Union[str, int, bool]]
72
+
70
73
  # Fired when the value of the textarea changes.
71
74
  on_change: EventHandler[input_event]
72
75
 
@@ -119,6 +119,7 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
119
119
  required: Optional[Union[Var[bool], bool]] = None,
120
120
  type: Optional[Union[Var[str], str]] = None,
121
121
  value: Optional[Union[Var[Union[float, int, str]], float, int, str]] = None,
122
+ list: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
122
123
  access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
123
124
  auto_capitalize: Optional[
124
125
  Union[Var[Union[bool, int, str]], bool, int, str]
@@ -206,6 +207,7 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
206
207
  required: Indicates that the input is required
207
208
  type: Specifies the type of input
208
209
  value: Value of the input
210
+ list: References a datalist for suggested options
209
211
  on_change: Fired when the value of the textarea changes.
210
212
  on_focus: Fired when the textarea is focused.
211
213
  on_blur: Fired when the textarea is blurred.
@@ -454,6 +456,7 @@ class TextField(ComponentNamespace):
454
456
  required: Optional[Union[Var[bool], bool]] = None,
455
457
  type: Optional[Union[Var[str], str]] = None,
456
458
  value: Optional[Union[Var[Union[float, int, str]], float, int, str]] = None,
459
+ list: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
457
460
  access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
458
461
  auto_capitalize: Optional[
459
462
  Union[Var[Union[bool, int, str]], bool, int, str]
@@ -541,6 +544,7 @@ class TextField(ComponentNamespace):
541
544
  required: Indicates that the input is required
542
545
  type: Specifies the type of input
543
546
  value: Value of the input
547
+ list: References a datalist for suggested options
544
548
  on_change: Fired when the value of the textarea changes.
545
549
  on_focus: Fired when the textarea is focused.
546
550
  on_blur: Fired when the textarea is blurred.
@@ -3,7 +3,6 @@
3
3
  from typing import Dict, Literal
4
4
 
5
5
  from reflex.components.component import Component, MemoizationLeaf, NoSSRComponent
6
- from reflex.utils import console
7
6
 
8
7
 
9
8
  class Recharts(Component):
@@ -11,19 +10,8 @@ class Recharts(Component):
11
10
 
12
11
  library = "recharts@2.13.0"
13
12
 
14
- def render(self) -> Dict:
15
- """Render the tag.
16
-
17
- Returns:
18
- The rendered tag.
19
- """
20
- tag = super().render()
21
- if any(p.startswith("css") for p in tag["props"]):
22
- console.warn(
23
- f"CSS props do not work for {self.__class__.__name__}. Consult docs to style it with its own prop."
24
- )
25
- tag["props"] = [p for p in tag["props"] if not p.startswith("css")]
26
- return tag
13
+ def _get_style(self) -> Dict:
14
+ return {"wrapperStyle": self.style}
27
15
 
28
16
 
29
17
  class RechartsCharts(NoSSRComponent, MemoizationLeaf):
@@ -11,7 +11,6 @@ from reflex.style import Style
11
11
  from reflex.vars.base import Var
12
12
 
13
13
  class Recharts(Component):
14
- def render(self) -> Dict: ...
15
14
  @overload
16
15
  @classmethod
17
16
  def create( # type: ignore
@@ -15,6 +15,8 @@ from reflex.utils.imports import ImportVar
15
15
  from reflex.utils.serializers import serializer
16
16
  from reflex.vars import VarData
17
17
  from reflex.vars.base import LiteralVar, Var
18
+ from reflex.vars.function import FunctionVar
19
+ from reflex.vars.object import ObjectVar
18
20
 
19
21
  LiteralPosition = Literal[
20
22
  "top-left",
@@ -232,7 +234,9 @@ class Toaster(Component):
232
234
  return [hook]
233
235
 
234
236
  @staticmethod
235
- def send_toast(message: str = "", level: str | None = None, **props) -> EventSpec:
237
+ def send_toast(
238
+ message: str | Var = "", level: str | None = None, **props
239
+ ) -> EventSpec:
236
240
  """Send a toast message.
237
241
 
238
242
  Args:
@@ -250,20 +254,27 @@ class Toaster(Component):
250
254
  raise ValueError(
251
255
  "Toaster component must be created before sending a toast. (use `rx.toast.provider()`)"
252
256
  )
253
- toast_command = f"{toast_ref}.{level}" if level is not None else toast_ref
254
- if message == "" and ("title" not in props or "description" not in props):
257
+
258
+ toast_command = (
259
+ ObjectVar.__getattr__(toast_ref.to(dict), level) if level else toast_ref
260
+ ).to(FunctionVar)
261
+
262
+ if isinstance(message, Var):
263
+ props.setdefault("title", message)
264
+ message = ""
265
+ elif message == "" and "title" not in props and "description" not in props:
255
266
  raise ValueError("Toast message or title or description must be provided.")
267
+
256
268
  if props:
257
- args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # type: ignore
258
- toast = f"{toast_command}(`{message}`, {str(args)})"
269
+ args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # pyright: ignore [reportCallIssue, reportGeneralTypeIssues]
270
+ toast = toast_command.call(message, args)
259
271
  else:
260
- toast = f"{toast_command}(`{message}`)"
272
+ toast = toast_command.call(message)
261
273
 
262
- toast_action = Var(_js_expr=toast)
263
- return run_script(toast_action)
274
+ return run_script(toast)
264
275
 
265
276
  @staticmethod
266
- def toast_info(message: str = "", **kwargs):
277
+ def toast_info(message: str | Var = "", **kwargs):
267
278
  """Display an info toast message.
268
279
 
269
280
  Args:
@@ -276,7 +287,7 @@ class Toaster(Component):
276
287
  return Toaster.send_toast(message, level="info", **kwargs)
277
288
 
278
289
  @staticmethod
279
- def toast_warning(message: str = "", **kwargs):
290
+ def toast_warning(message: str | Var = "", **kwargs):
280
291
  """Display a warning toast message.
281
292
 
282
293
  Args:
@@ -289,7 +300,7 @@ class Toaster(Component):
289
300
  return Toaster.send_toast(message, level="warning", **kwargs)
290
301
 
291
302
  @staticmethod
292
- def toast_error(message: str = "", **kwargs):
303
+ def toast_error(message: str | Var = "", **kwargs):
293
304
  """Display an error toast message.
294
305
 
295
306
  Args:
@@ -302,7 +313,7 @@ class Toaster(Component):
302
313
  return Toaster.send_toast(message, level="error", **kwargs)
303
314
 
304
315
  @staticmethod
305
- def toast_success(message: str = "", **kwargs):
316
+ def toast_success(message: str | Var = "", **kwargs):
306
317
  """Display a success toast message.
307
318
 
308
319
  Args:
@@ -59,16 +59,16 @@ class Toaster(Component):
59
59
  def add_hooks(self) -> list[Var | str]: ...
60
60
  @staticmethod
61
61
  def send_toast(
62
- message: str = "", level: str | None = None, **props
62
+ message: str | Var = "", level: str | None = None, **props
63
63
  ) -> EventSpec: ...
64
64
  @staticmethod
65
- def toast_info(message: str = "", **kwargs): ...
65
+ def toast_info(message: str | Var = "", **kwargs): ...
66
66
  @staticmethod
67
- def toast_warning(message: str = "", **kwargs): ...
67
+ def toast_warning(message: str | Var = "", **kwargs): ...
68
68
  @staticmethod
69
- def toast_error(message: str = "", **kwargs): ...
69
+ def toast_error(message: str | Var = "", **kwargs): ...
70
70
  @staticmethod
71
- def toast_success(message: str = "", **kwargs): ...
71
+ def toast_success(message: str | Var = "", **kwargs): ...
72
72
  @staticmethod
73
73
  def toast_dismiss(id: Var | str | None = None): ...
74
74
  @overload
@@ -176,7 +176,7 @@ class ToastNamespace(ComponentNamespace):
176
176
 
177
177
  @staticmethod
178
178
  def __call__(
179
- message: str = "", level: Optional[str] = None, **props
179
+ message: Union[str, Var] = "", level: Optional[str] = None, **props
180
180
  ) -> "Optional[EventSpec]":
181
181
  """Send a toast message.
182
182
 
reflex/config.py CHANGED
@@ -8,7 +8,9 @@ import importlib
8
8
  import inspect
9
9
  import os
10
10
  import sys
11
+ import threading
11
12
  import urllib.parse
13
+ from importlib.util import find_spec
12
14
  from pathlib import Path
13
15
  from typing import (
14
16
  TYPE_CHECKING,
@@ -452,6 +454,14 @@ class PathExistsFlag:
452
454
  ExistingPath = Annotated[Path, PathExistsFlag]
453
455
 
454
456
 
457
+ class PerformanceMode(enum.Enum):
458
+ """Performance mode for the app."""
459
+
460
+ WARN = "warn"
461
+ RAISE = "raise"
462
+ OFF = "off"
463
+
464
+
455
465
  class EnvironmentVariables:
456
466
  """Environment variables class to instantiate environment variables."""
457
467
 
@@ -545,6 +555,15 @@ class EnvironmentVariables:
545
555
  # Where to save screenshots when tests fail.
546
556
  SCREENSHOT_DIR: EnvVar[Optional[Path]] = env_var(None)
547
557
 
558
+ # Whether to check for outdated package versions.
559
+ REFLEX_CHECK_LATEST_VERSION: EnvVar[bool] = env_var(True)
560
+
561
+ # In which performance mode to run the app.
562
+ REFLEX_PERF_MODE: EnvVar[Optional[PerformanceMode]] = env_var(PerformanceMode.WARN)
563
+
564
+ # The maximum size of the reflex state in kilobytes.
565
+ REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000)
566
+
548
567
 
549
568
  environment = EnvironmentVariables()
550
569
 
@@ -798,24 +817,56 @@ class Config(Base):
798
817
  self._replace_defaults(**kwargs)
799
818
 
800
819
 
801
- def get_config(reload: bool = False) -> Config:
820
+ def _get_config() -> Config:
802
821
  """Get the app config.
803
822
 
804
- Args:
805
- reload: Re-import the rxconfig module from disk
806
-
807
823
  Returns:
808
824
  The app config.
809
825
  """
810
- sys.path.insert(0, os.getcwd())
811
826
  # only import the module if it exists. If a module spec exists then
812
827
  # the module exists.
813
- spec = importlib.util.find_spec(constants.Config.MODULE) # type: ignore
828
+ spec = find_spec(constants.Config.MODULE)
814
829
  if not spec:
815
830
  # we need this condition to ensure that a ModuleNotFound error is not thrown when
816
- # running unit/integration tests.
831
+ # running unit/integration tests or during `reflex init`.
817
832
  return Config(app_name="")
818
833
  rxconfig = importlib.import_module(constants.Config.MODULE)
819
- if reload:
820
- importlib.reload(rxconfig)
821
834
  return rxconfig.config
835
+
836
+
837
+ # Protect sys.path from concurrent modification
838
+ _config_lock = threading.RLock()
839
+
840
+
841
+ def get_config(reload: bool = False) -> Config:
842
+ """Get the app config.
843
+
844
+ Args:
845
+ reload: Re-import the rxconfig module from disk
846
+
847
+ Returns:
848
+ The app config.
849
+ """
850
+ cached_rxconfig = sys.modules.get(constants.Config.MODULE, None)
851
+ if cached_rxconfig is not None:
852
+ if reload:
853
+ # Remove any cached module when `reload` is requested.
854
+ del sys.modules[constants.Config.MODULE]
855
+ else:
856
+ return cached_rxconfig.config
857
+
858
+ with _config_lock:
859
+ sys_path = sys.path.copy()
860
+ sys.path.clear()
861
+ sys.path.append(os.getcwd())
862
+ try:
863
+ # Try to import the module with only the current directory in the path.
864
+ return _get_config()
865
+ except Exception:
866
+ # If the module import fails, try to import with the original sys.path.
867
+ sys.path.extend(sys_path)
868
+ return _get_config()
869
+ finally:
870
+ # Restore the original sys.path.
871
+ sys.path.clear()
872
+ sys.path.extend(sys_path)
reflex/constants/base.py CHANGED
@@ -97,6 +97,18 @@ class Templates(SimpleNamespace):
97
97
  # The default template
98
98
  DEFAULT = "blank"
99
99
 
100
+ # The AI template
101
+ AI = "ai"
102
+
103
+ # The option for the user to choose a remote template.
104
+ CHOOSE_TEMPLATES = "choose-templates"
105
+
106
+ # The URL to find reflex templates.
107
+ REFLEX_TEMPLATES_URL = "https://reflex.dev/templates"
108
+
109
+ # Demo url for the default template.
110
+ DEFAULT_TEMPLATE_URL = "https://blank-template.reflex.run"
111
+
100
112
  # The reflex.build frontend host
101
113
  REFLEX_BUILD_FRONTEND = "https://flexgen.reflex.run"
102
114
 
@@ -184,15 +184,15 @@ class PackageJson(SimpleNamespace):
184
184
  "json5": "2.2.3",
185
185
  "next": "14.2.16",
186
186
  "next-sitemap": "4.2.3",
187
- "next-themes": "0.3.0",
187
+ "next-themes": "0.4.3",
188
188
  "react": "18.3.1",
189
189
  "react-dom": "18.3.1",
190
190
  "react-focus-lock": "2.13.2",
191
191
  "socket.io-client": "4.8.1",
192
- "universal-cookie": "7.2.1",
192
+ "universal-cookie": "7.2.2",
193
193
  }
194
194
  DEV_DEPENDENCIES = {
195
195
  "autoprefixer": "10.4.20",
196
- "postcss": "8.4.47",
196
+ "postcss": "8.4.49",
197
197
  "postcss-import": "16.1.0",
198
198
  }
reflex/constants/style.py CHANGED
@@ -7,7 +7,7 @@ class Tailwind(SimpleNamespace):
7
7
  """Tailwind constants."""
8
8
 
9
9
  # The Tailwindcss version
10
- VERSION = "tailwindcss@3.4.14"
10
+ VERSION = "tailwindcss@3.4.15"
11
11
  # The Tailwind config.
12
12
  CONFIG = "tailwind.config.js"
13
13
  # Default Tailwind content paths