reflex 0.6.7a2__py3-none-any.whl → 0.6.8__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 (62) hide show
  1. reflex/.templates/jinja/web/pages/_app.js.jinja2 +2 -4
  2. reflex/.templates/jinja/web/pages/custom_component.js.jinja2 +3 -4
  3. reflex/.templates/jinja/web/pages/index.js.jinja2 +2 -3
  4. reflex/.templates/jinja/web/pages/macros.js.jinja2 +38 -0
  5. reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +4 -16
  6. reflex/.templates/jinja/web/utils/context.js.jinja2 +1 -1
  7. reflex/.templates/web/utils/state.js +9 -4
  8. reflex/app.py +12 -10
  9. reflex/compiler/compiler.py +2 -2
  10. reflex/compiler/templates.py +41 -0
  11. reflex/compiler/utils.py +1 -1
  12. reflex/components/base/bare.py +7 -3
  13. reflex/components/component.py +78 -116
  14. reflex/components/core/banner.py +1 -1
  15. reflex/components/core/breakpoints.py +1 -1
  16. reflex/components/datadisplay/code.py +14 -10
  17. reflex/components/datadisplay/dataeditor.py +1 -1
  18. reflex/components/datadisplay/dataeditor.pyi +1 -1
  19. reflex/components/el/elements/forms.py +7 -5
  20. reflex/components/el/elements/metadata.py +1 -1
  21. reflex/components/lucide/icon.py +142 -19
  22. reflex/components/lucide/icon.pyi +141 -18
  23. reflex/components/markdown/markdown.py +3 -2
  24. reflex/components/plotly/plotly.py +3 -3
  25. reflex/components/plotly/plotly.pyi +3 -3
  26. reflex/components/radix/primitives/slider.py +1 -1
  27. reflex/components/radix/themes/layout/center.pyi +1 -1
  28. reflex/components/radix/themes/layout/flex.py +1 -1
  29. reflex/components/radix/themes/layout/flex.pyi +1 -1
  30. reflex/components/radix/themes/layout/grid.py +1 -1
  31. reflex/components/radix/themes/layout/grid.pyi +1 -1
  32. reflex/components/radix/themes/layout/spacer.pyi +1 -1
  33. reflex/components/radix/themes/layout/stack.pyi +3 -3
  34. reflex/components/radix/themes/typography/link.py +1 -1
  35. reflex/components/recharts/cartesian.py +2 -2
  36. reflex/components/recharts/cartesian.pyi +6 -6
  37. reflex/components/recharts/charts.py +2 -2
  38. reflex/components/recharts/polar.py +2 -2
  39. reflex/components/recharts/polar.pyi +2 -2
  40. reflex/components/sonner/toast.py +1 -1
  41. reflex/constants/base.py +1 -1
  42. reflex/constants/compiler.py +1 -0
  43. reflex/event.py +96 -1
  44. reflex/experimental/client_state.py +42 -20
  45. reflex/istate/data.py +3 -3
  46. reflex/model.py +4 -5
  47. reflex/page.py +1 -1
  48. reflex/reflex.py +8 -1
  49. reflex/state.py +116 -9
  50. reflex/testing.py +3 -3
  51. reflex/utils/exceptions.py +4 -0
  52. reflex/utils/prerequisites.py +37 -20
  53. reflex/utils/processes.py +2 -2
  54. reflex/utils/pyi_generator.py +2 -2
  55. reflex/utils/telemetry.py +6 -4
  56. reflex/vars/base.py +15 -4
  57. reflex/vars/sequence.py +37 -0
  58. {reflex-0.6.7a2.dist-info → reflex-0.6.8.dist-info}/METADATA +2 -2
  59. {reflex-0.6.7a2.dist-info → reflex-0.6.8.dist-info}/RECORD +62 -61
  60. {reflex-0.6.7a2.dist-info → reflex-0.6.8.dist-info}/LICENSE +0 -0
  61. {reflex-0.6.7a2.dist-info → reflex-0.6.8.dist-info}/WHEEL +0 -0
  62. {reflex-0.6.7a2.dist-info → reflex-0.6.8.dist-info}/entry_points.txt +0 -0
@@ -150,7 +150,7 @@ class Center(Flex):
150
150
  Args:
151
151
  *children: Child components.
152
152
  as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
153
- direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse"
153
+ direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse"
154
154
  align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
155
155
  justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between"
156
156
  wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse"
@@ -22,7 +22,7 @@ class Flex(elements.Div, RadixThemesComponent):
22
22
  # Change the default rendered element for the one passed as a child, merging their props and behavior.
23
23
  as_child: Var[bool]
24
24
 
25
- # How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse"
25
+ # How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse"
26
26
  direction: Var[Responsive[LiteralFlexDirection]]
27
27
 
28
28
  # Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
@@ -153,7 +153,7 @@ class Flex(elements.Div, RadixThemesComponent):
153
153
  Args:
154
154
  *children: Child components.
155
155
  as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
156
- direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse"
156
+ direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse"
157
157
  align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
158
158
  justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between"
159
159
  wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse"
@@ -27,7 +27,7 @@ class Grid(elements.Div, RadixThemesComponent):
27
27
  # Number of rows
28
28
  rows: Var[Responsive[str]]
29
29
 
30
- # How the grid items are layed out: "row" | "column" | "dense" | "row-dense" | "column-dense"
30
+ # How the grid items are laid out: "row" | "column" | "dense" | "row-dense" | "column-dense"
31
31
  flow: Var[Responsive[LiteralGridFlow]]
32
32
 
33
33
  # Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
@@ -184,7 +184,7 @@ class Grid(elements.Div, RadixThemesComponent):
184
184
  as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
185
185
  columns: Number of columns
186
186
  rows: Number of rows
187
- flow: How the grid items are layed out: "row" | "column" | "dense" | "row-dense" | "column-dense"
187
+ flow: How the grid items are laid out: "row" | "column" | "dense" | "row-dense" | "column-dense"
188
188
  align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
189
189
  justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between"
190
190
  spacing: Gap between children: "0" - "9"
@@ -150,7 +150,7 @@ class Spacer(Flex):
150
150
  Args:
151
151
  *children: Child components.
152
152
  as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
153
- direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse"
153
+ direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse"
154
154
  align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
155
155
  justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between"
156
156
  wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse"
@@ -126,7 +126,7 @@ class Stack(Flex):
126
126
  spacing: Gap between children: "0" - "9"
127
127
  align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
128
128
  as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
129
- direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse"
129
+ direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse"
130
130
  justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between"
131
131
  wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse"
132
132
  access_key: Provides a hint for generating a keyboard shortcut for the current element.
@@ -258,7 +258,7 @@ class VStack(Stack):
258
258
 
259
259
  Args:
260
260
  *children: The children of the stack.
261
- direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse"
261
+ direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse"
262
262
  spacing: Gap between children: "0" - "9"
263
263
  align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
264
264
  as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
@@ -393,7 +393,7 @@ class HStack(Stack):
393
393
 
394
394
  Args:
395
395
  *children: The children of the stack.
396
- direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse"
396
+ direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse"
397
397
  spacing: Gap between children: "0" - "9"
398
398
  align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch"
399
399
  as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
@@ -76,7 +76,7 @@ class Link(RadixThemesComponent, A, MemoizationLeaf, MarkdownComponentMap):
76
76
  Returns:
77
77
  Component: The link component
78
78
  """
79
- props.setdefault(":hover", {"color": color("accent", 8)})
79
+ props.setdefault("_hover", {"color": color("accent", 8)})
80
80
  href = props.get("href")
81
81
 
82
82
  is_external = props.pop("is_external", None)
@@ -42,7 +42,7 @@ class Axis(Recharts):
42
42
  # The width of axis which is usually calculated internally.
43
43
  width: Var[Union[str, int]]
44
44
 
45
- # The height of axis, which can be setted by user.
45
+ # The height of axis, which can be set by user.
46
46
  height: Var[Union[str, int]]
47
47
 
48
48
  # The type of axis 'number' | 'category'
@@ -60,7 +60,7 @@ class Axis(Recharts):
60
60
  # Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True
61
61
  allow_duplicated_category: Var[bool]
62
62
 
63
- # The range of the axis. Work best in conjuction with allow_data_overflow. Default: [0, "auto"]
63
+ # The range of the axis. Work best in conjunction with allow_data_overflow. Default: [0, "auto"]
64
64
  domain: Var[List]
65
65
 
66
66
  # If set false, no axis line will be drawn. Default: True
@@ -144,13 +144,13 @@ class Axis(Recharts):
144
144
  data_key: The key of data displayed in the axis.
145
145
  hide: If set true, the axis do not display in the chart. Default: False
146
146
  width: The width of axis which is usually calculated internally.
147
- height: The height of axis, which can be setted by user.
147
+ height: The height of axis, which can be set by user.
148
148
  type_: The type of axis 'number' | 'category'
149
149
  interval: If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. Default: "preserveEnd"
150
150
  allow_decimals: Allow the ticks of Axis to be decimals or not. Default: True
151
151
  allow_data_overflow: When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. Default: False
152
152
  allow_duplicated_category: Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True
153
- domain: The range of the axis. Work best in conjuction with allow_data_overflow. Default: [0, "auto"]
153
+ domain: The range of the axis. Work best in conjunction with allow_data_overflow. Default: [0, "auto"]
154
154
  axis_line: If set false, no axis line will be drawn. Default: True
155
155
  mirror: If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. Default: False
156
156
  reversed: Reverse the ticks or not. Default: False
@@ -330,13 +330,13 @@ class XAxis(Axis):
330
330
  data_key: The key of data displayed in the axis.
331
331
  hide: If set true, the axis do not display in the chart. Default: False
332
332
  width: The width of axis which is usually calculated internally.
333
- height: The height of axis, which can be setted by user.
333
+ height: The height of axis, which can be set by user.
334
334
  type_: The type of axis 'number' | 'category'
335
335
  interval: If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. Default: "preserveEnd"
336
336
  allow_decimals: Allow the ticks of Axis to be decimals or not. Default: True
337
337
  allow_data_overflow: When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. Default: False
338
338
  allow_duplicated_category: Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True
339
- domain: The range of the axis. Work best in conjuction with allow_data_overflow. Default: [0, "auto"]
339
+ domain: The range of the axis. Work best in conjunction with allow_data_overflow. Default: [0, "auto"]
340
340
  axis_line: If set false, no axis line will be drawn. Default: True
341
341
  mirror: If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. Default: False
342
342
  reversed: Reverse the ticks or not. Default: False
@@ -512,13 +512,13 @@ class YAxis(Axis):
512
512
  data_key: The key of data displayed in the axis.
513
513
  hide: If set true, the axis do not display in the chart. Default: False
514
514
  width: The width of axis which is usually calculated internally.
515
- height: The height of axis, which can be setted by user.
515
+ height: The height of axis, which can be set by user.
516
516
  type_: The type of axis 'number' | 'category'
517
517
  interval: If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. Default: "preserveEnd"
518
518
  allow_decimals: Allow the ticks of Axis to be decimals or not. Default: True
519
519
  allow_data_overflow: When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. Default: False
520
520
  allow_duplicated_category: Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True
521
- domain: The range of the axis. Work best in conjuction with allow_data_overflow. Default: [0, "auto"]
521
+ domain: The range of the axis. Work best in conjunction with allow_data_overflow. Default: [0, "auto"]
522
522
  axis_line: If set false, no axis line will be drawn. Default: True
523
523
  mirror: If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. Default: False
524
524
  reversed: Reverse the ticks or not. Default: False
@@ -85,8 +85,8 @@ class ChartBase(RechartsCharts):
85
85
  cls._ensure_valid_dimension("height", height)
86
86
 
87
87
  dim_props = {
88
- "width": width or "100%",
89
- "height": height or "100%",
88
+ "width": width if width is not None else "100%",
89
+ "height": height if height is not None else "100%",
90
90
  }
91
91
  # Provide min dimensions so the graph always appears, even if the outer container is zero-size.
92
92
  if width is None:
@@ -124,7 +124,7 @@ class Radar(Recharts):
124
124
  # The key of a group of data which should be unique in a radar chart.
125
125
  data_key: Var[Union[str, int]]
126
126
 
127
- # The coordinates of all the vertexes of the radar shape, like [{ x, y }].
127
+ # The coordinates of all the vertices of the radar shape, like [{ x, y }].
128
128
  points: Var[List[Dict[str, Any]]]
129
129
 
130
130
  # If false set, dots will not be drawn. Default: True
@@ -373,7 +373,7 @@ class PolarRadiusAxis(Recharts):
373
373
  # The count of axis ticks. Not used if 'type' is 'category'. Default: 5
374
374
  tick_count: Var[int]
375
375
 
376
- # If 'auto' set, the scale funtion is linear scale. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold'. Default: "auto"
376
+ # If 'auto' set, the scale function is linear scale. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold'. Default: "auto"
377
377
  scale: Var[LiteralScale]
378
378
 
379
379
  # Valid children components
@@ -200,7 +200,7 @@ class Radar(Recharts):
200
200
  Args:
201
201
  *children: The children of the component.
202
202
  data_key: The key of a group of data which should be unique in a radar chart.
203
- points: The coordinates of all the vertexes of the radar shape, like [{ x, y }].
203
+ points: The coordinates of all the vertices of the radar shape, like [{ x, y }].
204
204
  dot: If false set, dots will not be drawn. Default: True
205
205
  stroke: Stoke color. Default: rx.color("accent", 9)
206
206
  fill: Fill color. Default: rx.color("accent", 3)
@@ -574,7 +574,7 @@ class PolarRadiusAxis(Recharts):
574
574
  axis_line: If false set, axis line will not be drawn. If true set, axis line will be drawn which have the props calculated internally. If object set, axis line will be drawn which have the props mergered by the internal calculated props and the option. Default: True
575
575
  tick: If false set, ticks will not be drawn. If true set, ticks will be drawn which have the props calculated internally. If object set, ticks will be drawn which have the props mergered by the internal calculated props and the option. Default: True
576
576
  tick_count: The count of axis ticks. Not used if 'type' is 'category'. Default: 5
577
- scale: If 'auto' set, the scale funtion is linear scale. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold'. Default: "auto"
577
+ scale: If 'auto' set, the scale function is linear scale. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold'. Default: "auto"
578
578
  domain: The domain of the polar radius axis, specifying the minimum and maximum values. Default: [0, "auto"]
579
579
  stroke: The stroke color of axis. Default: rx.color("gray", 10)
580
580
  style: The style of the component.
@@ -167,7 +167,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
167
167
  class Toaster(Component):
168
168
  """A Toaster Component for displaying toast notifications."""
169
169
 
170
- library: str = "sonner@1.5.0"
170
+ library: str = "sonner@1.7.1"
171
171
 
172
172
  tag = "Toaster"
173
173
 
reflex/constants/base.py CHANGED
@@ -27,7 +27,7 @@ class Dirs(SimpleNamespace):
27
27
  UPLOADED_FILES = "uploaded_files"
28
28
  # The name of the assets directory.
29
29
  APP_ASSETS = "assets"
30
- # The name of the assets directory for external ressource (a subfolder of APP_ASSETS).
30
+ # The name of the assets directory for external resources (a subfolder of APP_ASSETS).
31
31
  EXTERNAL_APP_ASSETS = "external"
32
32
  # The name of the utils file.
33
33
  UTILS = "utils"
@@ -135,6 +135,7 @@ class Hooks(SimpleNamespace):
135
135
  class HookPosition(enum.Enum):
136
136
  """The position of the hook in the component."""
137
137
 
138
+ INTERNAL = "internal"
138
139
  PRE_TRIGGER = "pre_trigger"
139
140
  POST_TRIGGER = "post_trigger"
140
141
 
reflex/event.py CHANGED
@@ -431,6 +431,101 @@ class EventChain(EventActionsMixin):
431
431
 
432
432
  invocation: Optional[Var] = dataclasses.field(default=None)
433
433
 
434
+ @classmethod
435
+ def create(
436
+ cls,
437
+ value: EventType,
438
+ args_spec: ArgsSpec | Sequence[ArgsSpec],
439
+ key: Optional[str] = None,
440
+ **event_chain_kwargs,
441
+ ) -> Union[EventChain, Var]:
442
+ """Create an event chain from a variety of input types.
443
+
444
+ Args:
445
+ value: The value to create the event chain from.
446
+ args_spec: The args_spec of the event trigger being bound.
447
+ key: The key of the event trigger being bound.
448
+ **event_chain_kwargs: Additional kwargs to pass to the EventChain constructor.
449
+
450
+ Returns:
451
+ The event chain.
452
+
453
+ Raises:
454
+ ValueError: If the value is not a valid event chain.
455
+ """
456
+ # If it's an event chain var, return it.
457
+ if isinstance(value, Var):
458
+ if isinstance(value, EventChainVar):
459
+ return value
460
+ elif isinstance(value, EventVar):
461
+ value = [value]
462
+ elif issubclass(value._var_type, (EventChain, EventSpec)):
463
+ return cls.create(
464
+ value=value.guess_type(),
465
+ args_spec=args_spec,
466
+ key=key,
467
+ **event_chain_kwargs,
468
+ )
469
+ else:
470
+ raise ValueError(
471
+ f"Invalid event chain: {value!s} of type {value._var_type}"
472
+ )
473
+ elif isinstance(value, EventChain):
474
+ # Trust that the caller knows what they're doing passing an EventChain directly
475
+ return value
476
+
477
+ # If the input is a single event handler, wrap it in a list.
478
+ if isinstance(value, (EventHandler, EventSpec)):
479
+ value = [value]
480
+
481
+ # If the input is a list of event handlers, create an event chain.
482
+ if isinstance(value, List):
483
+ events: List[Union[EventSpec, EventVar]] = []
484
+ for v in value:
485
+ if isinstance(v, (EventHandler, EventSpec)):
486
+ # Call the event handler to get the event.
487
+ events.append(call_event_handler(v, args_spec, key=key))
488
+ elif isinstance(v, Callable):
489
+ # Call the lambda to get the event chain.
490
+ result = call_event_fn(v, args_spec, key=key)
491
+ if isinstance(result, Var):
492
+ raise ValueError(
493
+ f"Invalid event chain: {v}. Cannot use a Var-returning "
494
+ "lambda inside an EventChain list."
495
+ )
496
+ events.extend(result)
497
+ elif isinstance(v, EventVar):
498
+ events.append(v)
499
+ else:
500
+ raise ValueError(f"Invalid event: {v}")
501
+
502
+ # If the input is a callable, create an event chain.
503
+ elif isinstance(value, Callable):
504
+ result = call_event_fn(value, args_spec, key=key)
505
+ if isinstance(result, Var):
506
+ # Recursively call this function if the lambda returned an EventChain Var.
507
+ return cls.create(
508
+ value=result, args_spec=args_spec, key=key, **event_chain_kwargs
509
+ )
510
+ events = [*result]
511
+
512
+ # Otherwise, raise an error.
513
+ else:
514
+ raise ValueError(f"Invalid event chain: {value}")
515
+
516
+ # Add args to the event specs if necessary.
517
+ events = [
518
+ (e.with_args(get_handler_args(e)) if isinstance(e, EventSpec) else e)
519
+ for e in events
520
+ ]
521
+
522
+ # Return the event chain.
523
+ return cls(
524
+ events=events,
525
+ args_spec=args_spec,
526
+ **event_chain_kwargs,
527
+ )
528
+
434
529
 
435
530
  @dataclasses.dataclass(
436
531
  init=True,
@@ -1100,7 +1195,7 @@ def call_function(
1100
1195
  Returns:
1101
1196
  EventSpec: An event that will execute the client side javascript.
1102
1197
  """
1103
- callback_kwargs = {}
1198
+ callback_kwargs = {"callback": None}
1104
1199
  if callback is not None:
1105
1200
  callback_kwargs = {
1106
1201
  "callback": format.format_queue_events(
@@ -12,7 +12,7 @@ from reflex.event import EventChain, EventHandler, EventSpec, run_script
12
12
  from reflex.utils.imports import ImportVar
13
13
  from reflex.vars import VarData, get_unique_variable_name
14
14
  from reflex.vars.base import LiteralVar, Var
15
- from reflex.vars.function import FunctionVar
15
+ from reflex.vars.function import ArgsFunctionOperationBuilder, FunctionVar
16
16
 
17
17
  NoValue = object()
18
18
 
@@ -45,6 +45,7 @@ class ClientStateVar(Var):
45
45
  # Track the names of the getters and setters
46
46
  _setter_name: str = dataclasses.field(default="")
47
47
  _getter_name: str = dataclasses.field(default="")
48
+ _id_name: str = dataclasses.field(default="")
48
49
 
49
50
  # Whether to add the var and setter to the global `refs` object for use in any Component.
50
51
  _global_ref: bool = dataclasses.field(default=True)
@@ -96,6 +97,7 @@ class ClientStateVar(Var):
96
97
  """
97
98
  if var_name is None:
98
99
  var_name = get_unique_variable_name()
100
+ id_name = "id_" + get_unique_variable_name()
99
101
  if not isinstance(var_name, str):
100
102
  raise ValueError("var_name must be a string.")
101
103
  if default is NoValue:
@@ -105,20 +107,24 @@ class ClientStateVar(Var):
105
107
  else:
106
108
  default_var = default
107
109
  setter_name = f"set{var_name.capitalize()}"
108
- hooks = {
110
+ hooks: dict[str, VarData | None] = {
111
+ f"const {id_name} = useId()": None,
109
112
  f"const [{var_name}, {setter_name}] = useState({default_var!s})": None,
110
113
  }
111
114
  imports = {
112
- "react": [ImportVar(tag="useState")],
115
+ "react": [ImportVar(tag="useState"), ImportVar(tag="useId")],
113
116
  }
114
117
  if global_ref:
115
- hooks[f"{_client_state_ref(var_name)} = {var_name}"] = None
116
- hooks[f"{_client_state_ref(setter_name)} = {setter_name}"] = None
118
+ hooks[f"{_client_state_ref(var_name)} ??= {{}}"] = None
119
+ hooks[f"{_client_state_ref(setter_name)} ??= {{}}"] = None
120
+ hooks[f"{_client_state_ref(var_name)}[{id_name}] = {var_name}"] = None
121
+ hooks[f"{_client_state_ref(setter_name)}[{id_name}] = {setter_name}"] = None
117
122
  imports.update(_refs_import)
118
123
  return cls(
119
124
  _js_expr="",
120
125
  _setter_name=setter_name,
121
126
  _getter_name=var_name,
127
+ _id_name=id_name,
122
128
  _global_ref=global_ref,
123
129
  _var_type=default_var._var_type,
124
130
  _var_data=VarData.merge(
@@ -144,10 +150,11 @@ class ClientStateVar(Var):
144
150
  return (
145
151
  Var(
146
152
  _js_expr=(
147
- _client_state_ref(self._getter_name)
153
+ _client_state_ref(self._getter_name) + f"[{self._id_name}]"
148
154
  if self._global_ref
149
155
  else self._getter_name
150
- )
156
+ ),
157
+ _var_data=self._var_data,
151
158
  )
152
159
  .to(self._var_type)
153
160
  ._replace(
@@ -170,28 +177,43 @@ class ClientStateVar(Var):
170
177
  Returns:
171
178
  A special EventChain Var which will set the value when triggered.
172
179
  """
180
+ _var_data = VarData(imports=_refs_import if self._global_ref else {})
181
+
182
+ arg_name = get_unique_variable_name()
173
183
  setter = (
174
- _client_state_ref(self._setter_name)
184
+ ArgsFunctionOperationBuilder.create(
185
+ args_names=(arg_name,),
186
+ return_expr=Var("Array.prototype.forEach.call")
187
+ .to(FunctionVar)
188
+ .call(
189
+ Var("Object.values")
190
+ .to(FunctionVar)
191
+ .call(Var(_client_state_ref(self._setter_name))),
192
+ ArgsFunctionOperationBuilder.create(
193
+ args_names=("setter",),
194
+ return_expr=Var("setter").to(FunctionVar).call(Var(arg_name)),
195
+ ),
196
+ ),
197
+ _var_data=_var_data,
198
+ )
175
199
  if self._global_ref
176
- else self._setter_name
200
+ else Var(self._setter_name, _var_data=_var_data).to(FunctionVar)
177
201
  )
178
- _var_data = VarData(imports=_refs_import if self._global_ref else {})
202
+
179
203
  if value is not NoValue:
180
204
  # This is a hack to make it work like an EventSpec taking an arg
181
205
  value_var = LiteralVar.create(value)
182
- _var_data = VarData.merge(_var_data, value_var._get_all_var_data())
183
206
  value_str = str(value_var)
184
207
 
185
- if value_str.startswith("_"):
208
+ setter = ArgsFunctionOperationBuilder.create(
186
209
  # remove patterns of ["*"] from the value_str using regex
187
- arg = re.sub(r"\[\".*\"\]", "", value_str)
188
- setter = f"(({arg}) => {setter}({value_str}))"
189
- else:
190
- setter = f"(() => {setter}({value_str}))"
191
- return Var(
192
- _js_expr=setter,
193
- _var_data=_var_data,
194
- ).to(FunctionVar, EventChain)
210
+ args_names=(re.sub(r"\[\".*\"\]", "", value_str),)
211
+ if value_str.startswith("_")
212
+ else (),
213
+ return_expr=setter.call(value_var),
214
+ )
215
+
216
+ return setter.to(FunctionVar, EventChain)
195
217
 
196
218
  @property
197
219
  def set(self) -> Var:
reflex/istate/data.py CHANGED
@@ -26,7 +26,7 @@ class HeaderData:
26
26
  accept_language: str = ""
27
27
 
28
28
  def __init__(self, router_data: Optional[dict] = None):
29
- """Initalize the HeaderData object based on router_data.
29
+ """Initialize the HeaderData object based on router_data.
30
30
 
31
31
  Args:
32
32
  router_data: the router_data dict.
@@ -51,7 +51,7 @@ class PageData:
51
51
  params: dict = dataclasses.field(default_factory=dict)
52
52
 
53
53
  def __init__(self, router_data: Optional[dict] = None):
54
- """Initalize the PageData object based on router_data.
54
+ """Initialize the PageData object based on router_data.
55
55
 
56
56
  Args:
57
57
  router_data: the router_data dict.
@@ -91,7 +91,7 @@ class SessionData:
91
91
  session_id: str = ""
92
92
 
93
93
  def __init__(self, router_data: Optional[dict] = None):
94
- """Initalize the SessionData object based on router_data.
94
+ """Initialize the SessionData object based on router_data.
95
95
 
96
96
  Args:
97
97
  router_data: the router_data dict.
reflex/model.py CHANGED
@@ -141,15 +141,13 @@ def get_async_engine(url: str | None) -> sqlalchemy.ext.asyncio.AsyncEngine:
141
141
  return _ASYNC_ENGINE[url]
142
142
 
143
143
 
144
- async def get_db_status() -> bool:
144
+ async def get_db_status() -> dict[str, bool]:
145
145
  """Checks the status of the database connection.
146
146
 
147
147
  Attempts to connect to the database and execute a simple query to verify connectivity.
148
148
 
149
149
  Returns:
150
- bool: The status of the database connection:
151
- - True: The database is accessible.
152
- - False: The database is not accessible.
150
+ The status of the database connection.
153
151
  """
154
152
  status = True
155
153
  try:
@@ -159,7 +157,7 @@ async def get_db_status() -> bool:
159
157
  except sqlalchemy.exc.OperationalError:
160
158
  status = False
161
159
 
162
- return status
160
+ return {"db": status}
163
161
 
164
162
 
165
163
  SQLModelOrSqlAlchemy = Union[
@@ -535,6 +533,7 @@ def asession(url: str | None = None) -> AsyncSession:
535
533
  _AsyncSessionLocal[url] = sqlalchemy.ext.asyncio.async_sessionmaker(
536
534
  bind=get_async_engine(url),
537
535
  class_=AsyncSession,
536
+ expire_on_commit=False,
538
537
  autocommit=False,
539
538
  autoflush=False,
540
539
  )
reflex/page.py CHANGED
@@ -70,7 +70,7 @@ def get_decorated_pages(omit_implicit_routes=True) -> list[dict[str, Any]]:
70
70
  """Get the decorated pages.
71
71
 
72
72
  Args:
73
- omit_implicit_routes: Whether to omit pages where the route will be implicitely guessed later.
73
+ omit_implicit_routes: Whether to omit pages where the route will be implicitly guessed later.
74
74
 
75
75
  Returns:
76
76
  The decorated pages.
reflex/reflex.py CHANGED
@@ -329,13 +329,14 @@ def export(
329
329
 
330
330
  @cli.command()
331
331
  def login(loglevel: constants.LogLevel = typer.Option(config.loglevel)):
332
- """Authenicate with experimental Reflex hosting service."""
332
+ """Authenticate with experimental Reflex hosting service."""
333
333
  from reflex_cli.v2 import cli as hosting_cli
334
334
 
335
335
  check_version()
336
336
 
337
337
  validated_info = hosting_cli.login()
338
338
  if validated_info is not None:
339
+ _skip_compile() # Allow running outside of an app dir
339
340
  telemetry.send("login", user_uuid=validated_info.get("user_id"))
340
341
 
341
342
 
@@ -484,6 +485,11 @@ def deploy(
484
485
  "--token",
485
486
  help="token to use for auth",
486
487
  ),
488
+ config_path: Optional[str] = typer.Option(
489
+ None,
490
+ "--config",
491
+ help="path to the config file",
492
+ ),
487
493
  ):
488
494
  """Deploy the app to the Reflex hosting service."""
489
495
  from reflex_cli.utils import dependency
@@ -539,6 +545,7 @@ def deploy(
539
545
  loglevel=type(loglevel).INFO, # type: ignore
540
546
  token=token,
541
547
  project=project,
548
+ config_path=config_path,
542
549
  )
543
550
 
544
551