reflex 0.3.5a4__py3-none-any.whl → 0.3.7__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 (138) hide show
  1. reflex/.templates/jinja/web/pages/base_page.js.jinja2 +2 -0
  2. reflex/.templates/web/utils/state.js +1 -1
  3. reflex/__init__.py +29 -6
  4. reflex/__init__.pyi +2 -0
  5. reflex/app.py +3 -0
  6. reflex/components/__init__.py +2 -0
  7. reflex/components/chakra/__init__.py +23 -0
  8. reflex/components/{media → chakra/media}/image.py +1 -28
  9. reflex/components/chakra/media/image.pyi +120 -0
  10. reflex/components/component.py +32 -4
  11. reflex/components/datadisplay/datatable.py +1 -37
  12. reflex/components/datadisplay/datatable.pyi +1 -11
  13. reflex/components/el/elements/forms.py +43 -1
  14. reflex/components/el/elements/forms.pyi +26 -1
  15. reflex/components/graphing/plotly.py +0 -22
  16. reflex/components/graphing/plotly.pyi +0 -12
  17. reflex/components/media/__init__.py +0 -1
  18. reflex/components/media/image.pyi +0 -9
  19. reflex/components/next/__init__.py +8 -0
  20. reflex/components/next/base.py +8 -0
  21. reflex/components/next/base.pyi +91 -0
  22. reflex/components/next/image.py +114 -0
  23. reflex/components/next/image.pyi +122 -0
  24. reflex/components/next/video.py +33 -0
  25. reflex/components/next/video.pyi +92 -0
  26. reflex/components/radix/primitives/__init__.py +3 -0
  27. reflex/components/radix/primitives/accordion.py +279 -0
  28. reflex/components/radix/primitives/accordion.pyi +619 -0
  29. reflex/components/radix/themes/__init__.py +4 -73
  30. reflex/components/radix/themes/base.py +7 -7
  31. reflex/components/radix/themes/base.pyi +21 -21
  32. reflex/components/radix/themes/components/__init__.py +193 -0
  33. reflex/components/radix/themes/components/alertdialog.py +72 -0
  34. reflex/components/radix/themes/components/alertdialog.pyi +733 -0
  35. reflex/components/radix/themes/components/aspectratio.py +20 -0
  36. reflex/components/radix/themes/components/aspectratio.pyi +144 -0
  37. reflex/components/radix/themes/components/avatar.py +38 -0
  38. reflex/components/radix/themes/components/avatar.pyi +233 -0
  39. reflex/components/radix/themes/components/badge.py +38 -0
  40. reflex/components/radix/themes/components/badge.pyi +291 -0
  41. reflex/components/radix/themes/components/button.py +39 -0
  42. reflex/components/radix/themes/components/button.pyi +330 -0
  43. reflex/components/radix/themes/components/callout.py +49 -0
  44. reflex/components/radix/themes/components/callout.pyi +668 -0
  45. reflex/components/radix/themes/components/card.py +25 -0
  46. reflex/components/radix/themes/components/card.pyi +214 -0
  47. reflex/components/radix/themes/components/checkbox.py +67 -0
  48. reflex/components/radix/themes/components/checkbox.pyi +249 -0
  49. reflex/components/radix/themes/components/contextmenu.py +134 -0
  50. reflex/components/radix/themes/{typography.pyi → components/contextmenu.pyi} +182 -602
  51. reflex/components/radix/themes/components/dialog.py +75 -0
  52. reflex/components/radix/themes/components/dialog.pyi +739 -0
  53. reflex/components/radix/themes/components/dropdownmenu.py +101 -0
  54. reflex/components/radix/themes/components/dropdownmenu.pyi +1065 -0
  55. reflex/components/radix/themes/components/hovercard.py +63 -0
  56. reflex/components/radix/themes/components/hovercard.pyi +487 -0
  57. reflex/components/radix/themes/components/iconbutton.py +39 -0
  58. reflex/components/radix/themes/components/iconbutton.pyi +332 -0
  59. reflex/components/radix/themes/components/icons.py +400 -0
  60. reflex/components/radix/themes/components/icons.pyi +185 -0
  61. reflex/components/radix/themes/components/inset.py +44 -0
  62. reflex/components/radix/themes/components/inset.pyi +230 -0
  63. reflex/components/radix/themes/components/popover.py +85 -0
  64. reflex/components/radix/themes/components/popover.pyi +634 -0
  65. reflex/components/radix/themes/components/radiogroup.py +72 -0
  66. reflex/components/radix/themes/components/radiogroup.pyi +369 -0
  67. reflex/components/radix/themes/components/scrollarea.py +31 -0
  68. reflex/components/radix/themes/components/scrollarea.pyi +165 -0
  69. reflex/components/radix/themes/components/select.py +137 -0
  70. reflex/components/radix/themes/{layout.pyi → components/select.pyi} +422 -418
  71. reflex/components/radix/themes/components/separator.py +30 -0
  72. reflex/components/radix/themes/components/separator.pyi +218 -0
  73. reflex/components/radix/themes/components/slider.py +68 -0
  74. reflex/components/radix/themes/components/slider.pyi +254 -0
  75. reflex/components/radix/themes/components/switch.py +68 -0
  76. reflex/components/radix/themes/components/switch.pyi +250 -0
  77. reflex/components/radix/themes/components/table.py +79 -0
  78. reflex/components/radix/themes/components/table.pyi +1485 -0
  79. reflex/components/radix/themes/components/tabs.py +65 -0
  80. reflex/components/radix/themes/components/tabs.pyi +549 -0
  81. reflex/components/radix/themes/components/textarea.py +68 -0
  82. reflex/components/radix/themes/components/textarea.pyi +333 -0
  83. reflex/components/radix/themes/{components.py → components/textfield.py} +3 -87
  84. reflex/components/radix/themes/{components.pyi → components/textfield.pyi} +202 -591
  85. reflex/components/radix/themes/layout/__init__.py +13 -0
  86. reflex/components/radix/themes/layout/base.py +48 -0
  87. reflex/components/radix/themes/layout/base.pyi +195 -0
  88. reflex/components/radix/themes/layout/box.py +12 -0
  89. reflex/components/radix/themes/layout/box.pyi +252 -0
  90. reflex/components/radix/themes/layout/container.py +23 -0
  91. reflex/components/radix/themes/layout/container.pyi +260 -0
  92. reflex/components/radix/themes/layout/flex.py +45 -0
  93. reflex/components/radix/themes/layout/flex.pyi +303 -0
  94. reflex/components/radix/themes/layout/grid.py +53 -0
  95. reflex/components/radix/themes/layout/grid.pyi +203 -0
  96. reflex/components/radix/themes/layout/section.py +20 -0
  97. reflex/components/radix/themes/layout/section.pyi +260 -0
  98. reflex/components/radix/themes/typography/__init__.py +21 -0
  99. reflex/components/radix/themes/typography/base.py +12 -0
  100. reflex/components/radix/themes/typography/blockquote.py +36 -0
  101. reflex/components/radix/themes/typography/blockquote.pyi +282 -0
  102. reflex/components/radix/themes/typography/code.py +40 -0
  103. reflex/components/radix/themes/typography/code.pyi +292 -0
  104. reflex/components/radix/themes/typography/em.py +18 -0
  105. reflex/components/radix/themes/typography/em.pyi +199 -0
  106. reflex/components/radix/themes/typography/heading.py +50 -0
  107. reflex/components/radix/themes/typography/heading.pyi +298 -0
  108. reflex/components/radix/themes/typography/kbd.py +25 -0
  109. reflex/components/radix/themes/typography/kbd.pyi +208 -0
  110. reflex/components/radix/themes/typography/link.py +49 -0
  111. reflex/components/radix/themes/typography/link.pyi +238 -0
  112. reflex/components/radix/themes/typography/quote.py +18 -0
  113. reflex/components/radix/themes/typography/quote.pyi +200 -0
  114. reflex/components/radix/themes/typography/strong.py +18 -0
  115. reflex/components/radix/themes/typography/strong.pyi +199 -0
  116. reflex/components/radix/themes/typography/text.py +50 -0
  117. reflex/components/radix/themes/typography/text.pyi +298 -0
  118. reflex/components/radix/themes/typography.py +1 -1
  119. reflex/constants/__init__.py +1 -0
  120. reflex/constants/base.py +7 -0
  121. reflex/constants/config.py +1 -1
  122. reflex/model.py +2 -1
  123. reflex/reflex.py +8 -1
  124. reflex/state.py +11 -0
  125. reflex/style.py +120 -10
  126. reflex/testing.py +4 -4
  127. reflex/utils/format.py +9 -5
  128. reflex/utils/prerequisites.py +49 -6
  129. reflex/utils/processes.py +8 -1
  130. reflex/utils/serializers.py +83 -0
  131. reflex/utils/types.py +22 -1
  132. reflex/vars.py +24 -1
  133. {reflex-0.3.5a4.dist-info → reflex-0.3.7.dist-info}/METADATA +3 -2
  134. {reflex-0.3.5a4.dist-info → reflex-0.3.7.dist-info}/RECORD +137 -44
  135. reflex/components/radix/themes/layout.py +0 -155
  136. {reflex-0.3.5a4.dist-info → reflex-0.3.7.dist-info}/LICENSE +0 -0
  137. {reflex-0.3.5a4.dist-info → reflex-0.3.7.dist-info}/WHEEL +0 -0
  138. {reflex-0.3.5a4.dist-info → reflex-0.3.7.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,298 @@
1
+ """Stub file for reflex/components/radix/themes/typography/text.py"""
2
+ # ------------------- DO NOT EDIT ----------------------
3
+ # This file was generated by `scripts/pyi_generator.py`!
4
+ # ------------------------------------------------------
5
+
6
+ from typing import Any, Dict, Literal, Optional, Union, overload
7
+ from reflex.vars import Var, BaseVar, ComputedVar
8
+ from reflex.event import EventChain, EventHandler, EventSpec
9
+ from reflex.style import Style
10
+ from reflex import el
11
+ from reflex.vars import Var
12
+ from ..base import CommonMarginProps, LiteralAccentColor, RadixThemesComponent
13
+ from .base import LiteralTextAlign, LiteralTextSize, LiteralTextTrim, LiteralTextWeight
14
+
15
+ class Text(el.Span, CommonMarginProps, RadixThemesComponent):
16
+ @overload
17
+ @classmethod
18
+ def create( # type: ignore
19
+ cls,
20
+ *children,
21
+ as_child: Optional[Union[Var[bool], bool]] = None,
22
+ as_: Optional[Union[Var[str], str]] = None,
23
+ size: Optional[
24
+ Union[
25
+ Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
26
+ Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
27
+ ]
28
+ ] = None,
29
+ weight: Optional[
30
+ Union[
31
+ Var[Literal["light", "regular", "medium", "bold"]],
32
+ Literal["light", "regular", "medium", "bold"],
33
+ ]
34
+ ] = None,
35
+ align: Optional[
36
+ Union[
37
+ Var[Literal["left", "center", "right"]],
38
+ Literal["left", "center", "right"],
39
+ ]
40
+ ] = None,
41
+ trim: Optional[
42
+ Union[
43
+ Var[Literal["normal", "start", "end", "both"]],
44
+ Literal["normal", "start", "end", "both"],
45
+ ]
46
+ ] = None,
47
+ color: Optional[
48
+ Union[
49
+ Var[
50
+ Literal[
51
+ "tomato",
52
+ "red",
53
+ "ruby",
54
+ "crimson",
55
+ "pink",
56
+ "plum",
57
+ "purple",
58
+ "violet",
59
+ "iris",
60
+ "indigo",
61
+ "blue",
62
+ "cyan",
63
+ "teal",
64
+ "jade",
65
+ "green",
66
+ "grass",
67
+ "brown",
68
+ "orange",
69
+ "sky",
70
+ "mint",
71
+ "lime",
72
+ "yellow",
73
+ "amber",
74
+ "gold",
75
+ "bronze",
76
+ "gray",
77
+ ]
78
+ ],
79
+ Literal[
80
+ "tomato",
81
+ "red",
82
+ "ruby",
83
+ "crimson",
84
+ "pink",
85
+ "plum",
86
+ "purple",
87
+ "violet",
88
+ "iris",
89
+ "indigo",
90
+ "blue",
91
+ "cyan",
92
+ "teal",
93
+ "jade",
94
+ "green",
95
+ "grass",
96
+ "brown",
97
+ "orange",
98
+ "sky",
99
+ "mint",
100
+ "lime",
101
+ "yellow",
102
+ "amber",
103
+ "gold",
104
+ "bronze",
105
+ "gray",
106
+ ],
107
+ ]
108
+ ] = None,
109
+ high_contrast: Optional[Union[Var[bool], bool]] = None,
110
+ access_key: Optional[
111
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
112
+ ] = None,
113
+ auto_capitalize: Optional[
114
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
115
+ ] = None,
116
+ content_editable: Optional[
117
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
118
+ ] = None,
119
+ context_menu: Optional[
120
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
121
+ ] = None,
122
+ dir: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
123
+ draggable: Optional[
124
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
125
+ ] = None,
126
+ enter_key_hint: Optional[
127
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
128
+ ] = None,
129
+ hidden: Optional[
130
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
131
+ ] = None,
132
+ input_mode: Optional[
133
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
134
+ ] = None,
135
+ item_prop: Optional[
136
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
137
+ ] = None,
138
+ lang: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
139
+ role: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
140
+ slot: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
141
+ spell_check: Optional[
142
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
143
+ ] = None,
144
+ tab_index: Optional[
145
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
146
+ ] = None,
147
+ title: Optional[
148
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
149
+ ] = None,
150
+ translate: Optional[
151
+ Union[Var[Union[str, int, bool]], Union[str, int, bool]]
152
+ ] = None,
153
+ m: Optional[
154
+ Union[
155
+ Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
156
+ Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
157
+ ]
158
+ ] = None,
159
+ mx: Optional[
160
+ Union[
161
+ Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
162
+ Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
163
+ ]
164
+ ] = None,
165
+ my: Optional[
166
+ Union[
167
+ Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
168
+ Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
169
+ ]
170
+ ] = None,
171
+ mt: Optional[
172
+ Union[
173
+ Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
174
+ Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
175
+ ]
176
+ ] = None,
177
+ mr: Optional[
178
+ Union[
179
+ Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
180
+ Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
181
+ ]
182
+ ] = None,
183
+ mb: Optional[
184
+ Union[
185
+ Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
186
+ Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
187
+ ]
188
+ ] = None,
189
+ ml: Optional[
190
+ Union[
191
+ Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
192
+ Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
193
+ ]
194
+ ] = None,
195
+ style: Optional[Style] = None,
196
+ key: Optional[Any] = None,
197
+ id: Optional[Any] = None,
198
+ class_name: Optional[Any] = None,
199
+ autofocus: Optional[bool] = None,
200
+ custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
201
+ on_blur: Optional[
202
+ Union[EventHandler, EventSpec, list, function, BaseVar]
203
+ ] = None,
204
+ on_click: Optional[
205
+ Union[EventHandler, EventSpec, list, function, BaseVar]
206
+ ] = None,
207
+ on_context_menu: Optional[
208
+ Union[EventHandler, EventSpec, list, function, BaseVar]
209
+ ] = None,
210
+ on_double_click: Optional[
211
+ Union[EventHandler, EventSpec, list, function, BaseVar]
212
+ ] = None,
213
+ on_focus: Optional[
214
+ Union[EventHandler, EventSpec, list, function, BaseVar]
215
+ ] = None,
216
+ on_mount: Optional[
217
+ Union[EventHandler, EventSpec, list, function, BaseVar]
218
+ ] = None,
219
+ on_mouse_down: Optional[
220
+ Union[EventHandler, EventSpec, list, function, BaseVar]
221
+ ] = None,
222
+ on_mouse_enter: Optional[
223
+ Union[EventHandler, EventSpec, list, function, BaseVar]
224
+ ] = None,
225
+ on_mouse_leave: Optional[
226
+ Union[EventHandler, EventSpec, list, function, BaseVar]
227
+ ] = None,
228
+ on_mouse_move: Optional[
229
+ Union[EventHandler, EventSpec, list, function, BaseVar]
230
+ ] = None,
231
+ on_mouse_out: Optional[
232
+ Union[EventHandler, EventSpec, list, function, BaseVar]
233
+ ] = None,
234
+ on_mouse_over: Optional[
235
+ Union[EventHandler, EventSpec, list, function, BaseVar]
236
+ ] = None,
237
+ on_mouse_up: Optional[
238
+ Union[EventHandler, EventSpec, list, function, BaseVar]
239
+ ] = None,
240
+ on_scroll: Optional[
241
+ Union[EventHandler, EventSpec, list, function, BaseVar]
242
+ ] = None,
243
+ on_unmount: Optional[
244
+ Union[EventHandler, EventSpec, list, function, BaseVar]
245
+ ] = None,
246
+ **props
247
+ ) -> "Text":
248
+ """Create a new component instance.
249
+
250
+ Will prepend "RadixThemes" to the component tag to avoid conflicts with
251
+ other UI libraries for common names, like Text and Button.
252
+
253
+ Args:
254
+ *children: Child components.
255
+ as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
256
+ as_: Change the default rendered element into a semantically appropriate alternative (cannot be used with asChild)
257
+ size: Text size: "1" - "9"
258
+ weight: Thickness of text: "light" | "regular" | "medium" | "bold"
259
+ align: Alignment of text in element: "left" | "center" | "right"
260
+ trim: Removes the leading trim space: "normal" | "start" | "end" | "both"
261
+ color: Overrides the accent color inherited from the Theme.
262
+ high_contrast: Whether to render the text with higher contrast color
263
+ access_key: Provides a hint for generating a keyboard shortcut for the current element.
264
+ auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
265
+ content_editable: Indicates whether the element's content is editable.
266
+ context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
267
+ dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
268
+ draggable: Defines whether the element can be dragged.
269
+ enter_key_hint: Hints what media types the media element is able to play.
270
+ hidden: Defines whether the element is hidden.
271
+ input_mode: Defines the type of the element.
272
+ item_prop: Defines the name of the element for metadata purposes.
273
+ lang: Defines the language used in the element.
274
+ role: Defines the role of the element.
275
+ slot: Assigns a slot in a shadow DOM shadow tree to an element.
276
+ spell_check: Defines whether the element may be checked for spelling errors.
277
+ tab_index: Defines the position of the current element in the tabbing order.
278
+ title: Defines a tooltip for the element.
279
+ translate: Specifies whether the content of an element should be translated or not.
280
+ m: Margin: "0" - "9"
281
+ mx: Margin horizontal: "0" - "9"
282
+ my: Margin vertical: "0" - "9"
283
+ mt: Margin top: "0" - "9"
284
+ mr: Margin right: "0" - "9"
285
+ mb: Margin bottom: "0" - "9"
286
+ ml: Margin left: "0" - "9"
287
+ style: The style of the component.
288
+ key: A unique key for the component.
289
+ id: The id for the component.
290
+ class_name: The class name for the component.
291
+ autofocus: Whether the component should take the focus once the page is loaded
292
+ custom_attrs: custom attribute
293
+ **props: Component properties.
294
+
295
+ Returns:
296
+ A new component instance.
297
+ """
298
+ ...
@@ -33,7 +33,7 @@ class Text(CommonMarginProps, RadixThemesComponent):
33
33
  as_: Var[str]
34
34
 
35
35
  # Text size: "1" - "9"
36
- size: Var[LiteralTextSize | dict]
36
+ size: Var[LiteralTextSize]
37
37
 
38
38
  # Thickness of text: "light" | "regular" | "medium" | "bold"
39
39
  weight: Var[LiteralTextWeight]
@@ -15,6 +15,7 @@ from .base import (
15
15
  Next,
16
16
  Ping,
17
17
  Reflex,
18
+ ReflexHostingCLI,
18
19
  Templates,
19
20
  )
20
21
  from .compiler import (
reflex/constants/base.py CHANGED
@@ -72,6 +72,13 @@ class Reflex(SimpleNamespace):
72
72
  )
73
73
 
74
74
 
75
+ class ReflexHostingCLI(SimpleNamespace):
76
+ """Base constants concerning Reflex Hosting CLI."""
77
+
78
+ # The name of the Reflex Hosting CLI package.
79
+ MODULE_NAME = "reflex-hosting-cli"
80
+
81
+
75
82
  class Templates(SimpleNamespace):
76
83
  """Constants related to Templates."""
77
84
 
@@ -47,7 +47,7 @@ class RequirementsTxt(SimpleNamespace):
47
47
  # The requirements.txt file.
48
48
  FILE = "requirements.txt"
49
49
  # The partial text used to form requirement that pins a reflex version
50
- DEFAULTS_STUB = f"{Reflex.MODULE_NAME}>="
50
+ DEFAULTS_STUB = f"{Reflex.MODULE_NAME}=="
51
51
 
52
52
 
53
53
  # The deployment URL.
reflex/model.py CHANGED
@@ -62,7 +62,8 @@ class Model(Base, sqlmodel.SQLModel):
62
62
  non_default_primary_key_fields = [
63
63
  field_name
64
64
  for field_name, field in cls.__fields__.items()
65
- if field_name != "id" and getattr(field.field_info, "primary_key", None)
65
+ if field_name != "id"
66
+ and getattr(field.field_info, "primary_key", None) is True
66
67
  ]
67
68
  if non_default_primary_key_fields:
68
69
  cls.__fields__.pop("id", None)
reflex/reflex.py CHANGED
@@ -78,6 +78,8 @@ def _init(
78
78
  app_name = prerequisites.get_default_app_name() if name is None else name
79
79
  console.rule(f"[bold]Initializing {app_name}")
80
80
 
81
+ prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
82
+
81
83
  # Set up the web project.
82
84
  prerequisites.initialize_frontend_dependencies()
83
85
 
@@ -171,6 +173,8 @@ def _run(
171
173
 
172
174
  console.rule("[bold]Starting Reflex App")
173
175
 
176
+ prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
177
+
174
178
  if frontend:
175
179
  prerequisites.update_next_config()
176
180
  # Get the app module.
@@ -483,10 +487,13 @@ def deploy(
483
487
  # Set the log level.
484
488
  console.set_log_level(loglevel)
485
489
 
486
- dependency.check_requirements()
490
+ # Only check requirements if interactive. There is user interaction for requirements update.
491
+ if interactive:
492
+ dependency.check_requirements()
487
493
 
488
494
  # Check if we are set up.
489
495
  prerequisites.check_initialized(frontend=True)
496
+ prerequisites.check_latest_package_version(constants.ReflexHostingCLI.MODULE_NAME)
490
497
 
491
498
  hosting_cli.deploy(
492
499
  app_name=app_name,
reflex/state.py CHANGED
@@ -1788,6 +1788,17 @@ class StateManagerRedis(StateManager):
1788
1788
  # only delete our lock
1789
1789
  await self.redis.delete(lock_key)
1790
1790
 
1791
+ async def close(self):
1792
+ """Explicitly close the redis connection and connection_pool.
1793
+
1794
+ It is necessary in testing scenarios to close between asyncio test cases
1795
+ to avoid having lingering redis connections associated with event loops
1796
+ that will be closed (each test case uses its own event loop).
1797
+
1798
+ Note: Connections will be automatically reopened when needed.
1799
+ """
1800
+ await self.redis.close(close_connection_pool=True)
1801
+
1791
1802
 
1792
1803
  class ClientStorageBase:
1793
1804
  """Base class for client-side storage."""
reflex/style.py CHANGED
@@ -35,6 +35,66 @@ toggle_color_mode = BaseVar(
35
35
  _var_data=color_mode_var_data,
36
36
  )
37
37
 
38
+ breakpoints = ["0", "30em", "48em", "62em", "80em", "96em"]
39
+
40
+
41
+ def media_query(breakpoint_index: int):
42
+ """Create a media query selector.
43
+
44
+ Args:
45
+ breakpoint_index: The index of the breakpoint to use.
46
+
47
+ Returns:
48
+ The media query selector used as a key in emotion css dict.
49
+ """
50
+ return f"@media screen and (min-width: {breakpoints[breakpoint_index]})"
51
+
52
+
53
+ def convert_item(style_item: str | Var) -> tuple[str, VarData | None]:
54
+ """Format a single value in a style dictionary.
55
+
56
+ Args:
57
+ style_item: The style item to format.
58
+
59
+ Returns:
60
+ The formatted style item and any associated VarData.
61
+ """
62
+ if isinstance(style_item, Var):
63
+ # If the value is a Var, extract the var_data and cast as str.
64
+ return str(style_item), style_item._var_data
65
+
66
+ # Otherwise, convert to Var to collapse VarData encoded in f-string.
67
+ new_var = Var.create(style_item)
68
+ if new_var is not None and new_var._var_data:
69
+ # The wrapped backtick is used to identify the Var for interpolation.
70
+ return f"`{str(new_var)}`", new_var._var_data
71
+
72
+ return style_item, None
73
+
74
+
75
+ def convert_list(
76
+ responsive_list: list[str | dict | Var],
77
+ ) -> tuple[list[str | dict], VarData | None]:
78
+ """Format a responsive value list.
79
+
80
+ Args:
81
+ responsive_list: The raw responsive value list (one value per breakpoint).
82
+
83
+ Returns:
84
+ The recursively converted responsive value list and any associated VarData.
85
+ """
86
+ converted_value = []
87
+ item_var_datas = []
88
+ for responsive_item in responsive_list:
89
+ if isinstance(responsive_item, dict):
90
+ # Recursively format nested style dictionaries.
91
+ item, item_var_data = convert(responsive_item)
92
+ else:
93
+ item, item_var_data = convert_item(responsive_item)
94
+ converted_value.append(item)
95
+ item_var_datas.append(item_var_data)
96
+ return converted_value, VarData.merge(*item_var_datas)
97
+
38
98
 
39
99
  def convert(style_dict):
40
100
  """Format a style dictionary.
@@ -49,20 +109,14 @@ def convert(style_dict):
49
109
  out = {}
50
110
  for key, value in style_dict.items():
51
111
  key = format.to_camel_case(key)
52
- new_var_data = None
53
112
  if isinstance(value, dict):
54
113
  # Recursively format nested style dictionaries.
55
114
  out[key], new_var_data = convert(value)
56
- elif isinstance(value, Var):
57
- # If the value is a Var, extract the var_data and cast as str.
58
- new_var_data = value._var_data
59
- out[key] = str(value)
115
+ elif isinstance(value, list):
116
+ # Responsive value is a list of dict or value
117
+ out[key], new_var_data = convert_list(value)
60
118
  else:
61
- # Otherwise, convert to Var to collapse VarData encoded in f-string.
62
- new_var = Var.create(value)
63
- if new_var is not None:
64
- new_var_data = new_var._var_data
65
- out[key] = value
119
+ out[key], new_var_data = convert_item(value)
66
120
  # Combine all the collected VarData instances.
67
121
  var_data = VarData.merge(var_data, new_var_data)
68
122
  return out, var_data
@@ -110,3 +164,59 @@ class Style(dict):
110
164
  # Carry the imports/hooks when setting a Var as a value.
111
165
  self._var_data = VarData.merge(self._var_data, _var._var_data)
112
166
  super().__setitem__(key, value)
167
+
168
+
169
+ def _format_emotion_style_pseudo_selector(key: str) -> str:
170
+ """Format a pseudo selector for emotion CSS-in-JS.
171
+
172
+ Args:
173
+ key: Underscore-prefixed or colon-prefixed pseudo selector key (_hover).
174
+
175
+ Returns:
176
+ A self-referential pseudo selector key (&:hover).
177
+ """
178
+ prefix = None
179
+ if key.startswith("_"):
180
+ # Handle pseudo selectors in chakra style format.
181
+ prefix = "&:"
182
+ key = key[1:]
183
+ if key.startswith(":"):
184
+ # Handle pseudo selectors and elements in native format.
185
+ prefix = "&"
186
+ if prefix is not None:
187
+ return prefix + format.to_kebab_case(key)
188
+ return key
189
+
190
+
191
+ def format_as_emotion(style_dict: dict[str, Any]) -> dict[str, Any] | None:
192
+ """Convert the style to an emotion-compatible CSS-in-JS dict.
193
+
194
+ Args:
195
+ style_dict: The style dict to convert.
196
+
197
+ Returns:
198
+ The emotion dict.
199
+ """
200
+ emotion_style = {}
201
+ for orig_key, value in style_dict.items():
202
+ key = _format_emotion_style_pseudo_selector(orig_key)
203
+ if isinstance(value, list):
204
+ # Apply media queries from responsive value list.
205
+ mbps = {
206
+ media_query(bp): bp_value
207
+ if isinstance(bp_value, dict)
208
+ else {key: bp_value}
209
+ for bp, bp_value in enumerate(value)
210
+ }
211
+ if key.startswith("&:"):
212
+ emotion_style[key] = mbps
213
+ else:
214
+ for mq, style_sub_dict in mbps.items():
215
+ emotion_style.setdefault(mq, {}).update(style_sub_dict)
216
+ elif isinstance(value, dict):
217
+ # Recursively format nested style dictionaries.
218
+ emotion_style[key] = format_as_emotion(value)
219
+ else:
220
+ emotion_style[key] = value
221
+ if emotion_style:
222
+ return emotion_style
reflex/testing.py CHANGED
@@ -184,7 +184,7 @@ class AppHarness:
184
184
  if self.app_instance is not None and isinstance(
185
185
  self.app_instance.state_manager, StateManagerRedis
186
186
  ):
187
- await self.app_instance.state_manager.redis.close()
187
+ await self.app_instance.state_manager.close()
188
188
  await original_shutdown(*args, **kwargs)
189
189
 
190
190
  return _shutdown_redis
@@ -455,7 +455,7 @@ class AppHarness:
455
455
  return await self.state_manager.get_state(token)
456
456
  finally:
457
457
  if isinstance(self.state_manager, StateManagerRedis):
458
- await self.state_manager.redis.close()
458
+ await self.state_manager.close()
459
459
 
460
460
  async def set_state(self, token: str, **kwargs) -> None:
461
461
  """Set the state associated with the given token.
@@ -476,7 +476,7 @@ class AppHarness:
476
476
  await self.state_manager.set_state(token, state)
477
477
  finally:
478
478
  if isinstance(self.state_manager, StateManagerRedis):
479
- await self.state_manager.redis.close()
479
+ await self.state_manager.close()
480
480
 
481
481
  @contextlib.asynccontextmanager
482
482
  async def modify_state(self, token: str) -> AsyncIterator[State]:
@@ -506,7 +506,7 @@ class AppHarness:
506
506
  finally:
507
507
  if isinstance(self.state_manager, StateManagerRedis):
508
508
  self.app_instance._state_manager = app_state_manager
509
- await self.state_manager.redis.close()
509
+ await self.state_manager.close()
510
510
 
511
511
  def poll_for_content(
512
512
  self,
reflex/utils/format.py CHANGED
@@ -625,17 +625,21 @@ def unwrap_vars(value: str) -> str:
625
625
  return prefix + re.sub('\\\\"', '"', m.group(2))
626
626
 
627
627
  # This substitution is necessary to unwrap var values.
628
- return re.sub(
629
- pattern=r"""
628
+ return (
629
+ re.sub(
630
+ pattern=r"""
630
631
  (?<!\\) # must NOT start with a backslash
631
632
  " # match opening double quote of JSON value
632
633
  (<reflex.Var>.*?</reflex.Var>)? # Optional encoded VarData (non-greedy)
633
634
  {(.*?)} # extract the value between curly braces (non-greedy)
634
635
  " # match must end with an unescaped double quote
635
636
  """,
636
- repl=unescape_double_quotes_in_var,
637
- string=value,
638
- flags=re.VERBOSE,
637
+ repl=unescape_double_quotes_in_var,
638
+ string=value,
639
+ flags=re.VERBOSE,
640
+ )
641
+ .replace('"`', "`")
642
+ .replace('`"', "`")
639
643
  )
640
644
 
641
645