reflex 0.7.9a2__py3-none-any.whl → 0.7.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/app.py +12 -4
- reflex/components/component.py +38 -11
- reflex/components/core/upload.py +48 -16
- reflex/components/core/upload.pyi +7 -0
- reflex/components/react_player/audio.pyi +0 -4
- reflex/components/react_player/react_player.py +21 -7
- reflex/components/react_player/react_player.pyi +0 -4
- reflex/components/react_player/video.pyi +0 -4
- reflex/config.py +2 -2
- reflex/constants/__init__.py +2 -0
- reflex/constants/base.py +1 -1
- reflex/constants/config.py +7 -0
- reflex/constants/installer.py +19 -5
- reflex/event.py +24 -0
- reflex/istate/manager.py +858 -0
- reflex/istate/proxy.py +726 -2
- reflex/reflex.py +15 -9
- reflex/state.py +91 -1622
- reflex/testing.py +20 -13
- reflex/utils/prerequisites.py +33 -40
- reflex/utils/pyi_generator.py +5 -4
- reflex/utils/redir.py +7 -0
- reflex/utils/serializers.py +14 -0
- reflex/vars/base.py +13 -1
- reflex/vars/number.py +16 -8
- reflex/vars/sequence.py +2 -1
- {reflex-0.7.9a2.dist-info → reflex-0.7.10.dist-info}/METADATA +2 -2
- {reflex-0.7.9a2.dist-info → reflex-0.7.10.dist-info}/RECORD +31 -30
- {reflex-0.7.9a2.dist-info → reflex-0.7.10.dist-info}/WHEEL +0 -0
- {reflex-0.7.9a2.dist-info → reflex-0.7.10.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.9a2.dist-info → reflex-0.7.10.dist-info}/licenses/LICENSE +0 -0
reflex/app.py
CHANGED
|
@@ -29,7 +29,7 @@ from starlette.datastructures import Headers
|
|
|
29
29
|
from starlette.datastructures import UploadFile as StarletteUploadFile
|
|
30
30
|
from starlette.exceptions import HTTPException
|
|
31
31
|
from starlette.middleware import cors
|
|
32
|
-
from starlette.requests import Request
|
|
32
|
+
from starlette.requests import ClientDisconnect, Request
|
|
33
33
|
from starlette.responses import JSONResponse, Response, StreamingResponse
|
|
34
34
|
from starlette.staticfiles import StaticFiles
|
|
35
35
|
from typing_extensions import deprecated
|
|
@@ -488,7 +488,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
488
488
|
set_breakpoints(self.style.pop("breakpoints"))
|
|
489
489
|
|
|
490
490
|
# Set up the API.
|
|
491
|
-
self._api = Starlette(
|
|
491
|
+
self._api = Starlette()
|
|
492
492
|
App._add_cors(self._api)
|
|
493
493
|
self._add_default_endpoints()
|
|
494
494
|
|
|
@@ -629,6 +629,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
629
629
|
|
|
630
630
|
if not self._api:
|
|
631
631
|
raise ValueError("The app has not been initialized.")
|
|
632
|
+
|
|
632
633
|
if self._cached_fastapi_app is not None:
|
|
633
634
|
asgi_app = self._cached_fastapi_app
|
|
634
635
|
asgi_app.mount("", self._api)
|
|
@@ -653,7 +654,11 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
653
654
|
# Transform the asgi app.
|
|
654
655
|
asgi_app = api_transformer(asgi_app)
|
|
655
656
|
|
|
656
|
-
|
|
657
|
+
top_asgi_app = Starlette(lifespan=self._run_lifespan_tasks)
|
|
658
|
+
top_asgi_app.mount("", asgi_app)
|
|
659
|
+
App._add_cors(top_asgi_app)
|
|
660
|
+
|
|
661
|
+
return top_asgi_app
|
|
657
662
|
|
|
658
663
|
def _add_default_endpoints(self):
|
|
659
664
|
"""Add default api endpoints (ping)."""
|
|
@@ -1828,7 +1833,10 @@ def upload(app: App):
|
|
|
1828
1833
|
from reflex.utils.exceptions import UploadTypeError, UploadValueError
|
|
1829
1834
|
|
|
1830
1835
|
# Get the files from the request.
|
|
1831
|
-
|
|
1836
|
+
try:
|
|
1837
|
+
files = await request.form()
|
|
1838
|
+
except ClientDisconnect:
|
|
1839
|
+
return Response() # user cancelled
|
|
1832
1840
|
files = files.getlist("files")
|
|
1833
1841
|
if not files:
|
|
1834
1842
|
raise UploadValueError("No files were uploaded.")
|
reflex/components/component.py
CHANGED
|
@@ -43,6 +43,7 @@ from reflex.event import (
|
|
|
43
43
|
no_args_event_spec,
|
|
44
44
|
parse_args_spec,
|
|
45
45
|
run_script,
|
|
46
|
+
unwrap_var_annotation,
|
|
46
47
|
)
|
|
47
48
|
from reflex.style import Style, format_as_emotion
|
|
48
49
|
from reflex.utils import console, format, imports, types
|
|
@@ -50,14 +51,15 @@ from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_
|
|
|
50
51
|
from reflex.vars import VarData
|
|
51
52
|
from reflex.vars.base import (
|
|
52
53
|
CachedVarOperation,
|
|
54
|
+
LiteralNoneVar,
|
|
53
55
|
LiteralVar,
|
|
54
56
|
Var,
|
|
55
57
|
cached_property_no_lock,
|
|
56
58
|
)
|
|
57
59
|
from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar, FunctionVar
|
|
58
60
|
from reflex.vars.number import ternary_operation
|
|
59
|
-
from reflex.vars.object import ObjectVar
|
|
60
|
-
from reflex.vars.sequence import LiteralArrayVar
|
|
61
|
+
from reflex.vars.object import LiteralObjectVar, ObjectVar
|
|
62
|
+
from reflex.vars.sequence import LiteralArrayVar, LiteralStringVar, StringVar
|
|
61
63
|
|
|
62
64
|
|
|
63
65
|
class BaseComponent(Base, ABC):
|
|
@@ -598,13 +600,36 @@ class Component(BaseComponent, ABC):
|
|
|
598
600
|
# Convert class_name to str if it's list
|
|
599
601
|
class_name = kwargs.get("class_name", "")
|
|
600
602
|
if isinstance(class_name, (list, tuple)):
|
|
601
|
-
|
|
603
|
+
has_var = False
|
|
604
|
+
for c in class_name:
|
|
605
|
+
if isinstance(c, str):
|
|
606
|
+
continue
|
|
607
|
+
if isinstance(c, Var):
|
|
608
|
+
if not isinstance(c, StringVar) and not issubclass(
|
|
609
|
+
c._var_type, str
|
|
610
|
+
):
|
|
611
|
+
raise TypeError(
|
|
612
|
+
f"Invalid class_name passed for prop {type(self).__name__}.class_name, expected type str, got value {c._js_expr} of type {c._var_type}."
|
|
613
|
+
)
|
|
614
|
+
has_var = True
|
|
615
|
+
else:
|
|
616
|
+
raise TypeError(
|
|
617
|
+
f"Invalid class_name passed for prop {type(self).__name__}.class_name, expected type str, got value {c} of type {type(c)}."
|
|
618
|
+
)
|
|
619
|
+
if has_var:
|
|
602
620
|
kwargs["class_name"] = LiteralArrayVar.create(
|
|
603
621
|
class_name, _var_type=list[str]
|
|
604
622
|
).join(" ")
|
|
605
623
|
else:
|
|
606
624
|
kwargs["class_name"] = " ".join(class_name)
|
|
607
|
-
|
|
625
|
+
elif (
|
|
626
|
+
isinstance(class_name, Var)
|
|
627
|
+
and not isinstance(class_name, StringVar)
|
|
628
|
+
and not issubclass(class_name._var_type, str)
|
|
629
|
+
):
|
|
630
|
+
raise TypeError(
|
|
631
|
+
f"Invalid class_name passed for prop {type(self).__name__}.class_name, expected type str, got value {class_name._js_expr} of type {class_name._var_type}."
|
|
632
|
+
)
|
|
608
633
|
# Construct the component.
|
|
609
634
|
for key, value in kwargs.items():
|
|
610
635
|
setattr(self, key, value)
|
|
@@ -1146,7 +1171,7 @@ class Component(BaseComponent, ABC):
|
|
|
1146
1171
|
vars.append(comp_prop)
|
|
1147
1172
|
elif isinstance(comp_prop, str):
|
|
1148
1173
|
# Collapse VarData encoded in f-strings.
|
|
1149
|
-
var =
|
|
1174
|
+
var = LiteralStringVar.create(comp_prop)
|
|
1150
1175
|
if var._get_all_var_data() is not None:
|
|
1151
1176
|
vars.append(var)
|
|
1152
1177
|
|
|
@@ -1912,8 +1937,8 @@ def _register_custom_component(
|
|
|
1912
1937
|
prop: (
|
|
1913
1938
|
Var(
|
|
1914
1939
|
"",
|
|
1915
|
-
_var_type=annotation,
|
|
1916
|
-
)
|
|
1940
|
+
_var_type=unwrap_var_annotation(annotation),
|
|
1941
|
+
).guess_type()
|
|
1917
1942
|
if not types.safe_issubclass(annotation, EventHandler)
|
|
1918
1943
|
else EventSpec(handler=EventHandler(fn=lambda: []))
|
|
1919
1944
|
)
|
|
@@ -2494,7 +2519,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
|
|
|
2494
2519
|
return Var.create(tag)
|
|
2495
2520
|
|
|
2496
2521
|
if "iterable" in tag:
|
|
2497
|
-
function_return =
|
|
2522
|
+
function_return = LiteralArrayVar.create(
|
|
2498
2523
|
[
|
|
2499
2524
|
render_dict_to_var(child.render(), imported_names)
|
|
2500
2525
|
for child in tag["children"]
|
|
@@ -2537,7 +2562,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
|
|
|
2537
2562
|
render_dict_to_var(tag["true_value"], imported_names),
|
|
2538
2563
|
render_dict_to_var(tag["false_value"], imported_names)
|
|
2539
2564
|
if tag["false_value"] is not None
|
|
2540
|
-
else
|
|
2565
|
+
else LiteralNoneVar.create(),
|
|
2541
2566
|
)
|
|
2542
2567
|
|
|
2543
2568
|
props = {}
|
|
@@ -2553,7 +2578,9 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
|
|
|
2553
2578
|
value = prop_str[prop + 2 : -1]
|
|
2554
2579
|
props[key] = value
|
|
2555
2580
|
|
|
2556
|
-
props =
|
|
2581
|
+
props = LiteralObjectVar.create(
|
|
2582
|
+
{LiteralStringVar.create(k): Var(v) for k, v in props.items()}
|
|
2583
|
+
)
|
|
2557
2584
|
|
|
2558
2585
|
for prop in special_props:
|
|
2559
2586
|
props = props.merge(prop)
|
|
@@ -2564,7 +2591,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
|
|
|
2564
2591
|
tag_name = Var(raw_tag_name or "Fragment")
|
|
2565
2592
|
|
|
2566
2593
|
tag_name = (
|
|
2567
|
-
|
|
2594
|
+
LiteralStringVar.create(raw_tag_name)
|
|
2568
2595
|
if raw_tag_name
|
|
2569
2596
|
and raw_tag_name.split(".")[0] not in imported_names
|
|
2570
2597
|
and raw_tag_name.lower() == raw_tag_name
|
reflex/components/core/upload.py
CHANGED
|
@@ -13,6 +13,7 @@ from reflex.components.component import (
|
|
|
13
13
|
MemoizationLeaf,
|
|
14
14
|
StatefulComponent,
|
|
15
15
|
)
|
|
16
|
+
from reflex.components.core.cond import cond
|
|
16
17
|
from reflex.components.el.elements.forms import Input
|
|
17
18
|
from reflex.components.radix.themes.layout.box import Box
|
|
18
19
|
from reflex.config import environment
|
|
@@ -28,6 +29,7 @@ from reflex.event import (
|
|
|
28
29
|
parse_args_spec,
|
|
29
30
|
run_script,
|
|
30
31
|
)
|
|
32
|
+
from reflex.style import Style
|
|
31
33
|
from reflex.utils import format
|
|
32
34
|
from reflex.utils.imports import ImportVar
|
|
33
35
|
from reflex.vars import VarData
|
|
@@ -231,6 +233,9 @@ class Upload(MemoizationLeaf):
|
|
|
231
233
|
# Fired when files are dropped.
|
|
232
234
|
on_drop: EventHandler[_on_drop_spec]
|
|
233
235
|
|
|
236
|
+
# Style rules to apply when actively dragging.
|
|
237
|
+
drag_active_style: Style | None = None
|
|
238
|
+
|
|
234
239
|
@classmethod
|
|
235
240
|
def create(cls, *children, **props) -> Component:
|
|
236
241
|
"""Create an upload component.
|
|
@@ -266,25 +271,46 @@ class Upload(MemoizationLeaf):
|
|
|
266
271
|
# If on_drop is not provided, save files to be uploaded later.
|
|
267
272
|
upload_props["on_drop"] = upload_file(upload_props["id"])
|
|
268
273
|
else:
|
|
269
|
-
on_drop =
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
274
|
+
on_drop = (
|
|
275
|
+
[on_drop_prop]
|
|
276
|
+
if not isinstance(on_drop_prop := upload_props["on_drop"], Sequence)
|
|
277
|
+
else list(on_drop_prop)
|
|
278
|
+
)
|
|
279
|
+
for ix, event in enumerate(on_drop):
|
|
280
|
+
if isinstance(event, (EventHandler, EventSpec)):
|
|
281
|
+
# Call the lambda to get the event chain.
|
|
282
|
+
event = call_event_handler(event, _on_drop_spec)
|
|
283
|
+
elif isinstance(event, Callable):
|
|
284
|
+
# Call the lambda to get the event chain.
|
|
285
|
+
event = call_event_fn(event, _on_drop_spec)
|
|
286
|
+
if isinstance(event, EventSpec):
|
|
287
|
+
# Update the provided args for direct use with on_drop.
|
|
288
|
+
event = event.with_args(
|
|
289
|
+
args=tuple(
|
|
290
|
+
cls._update_arg_tuple_for_on_drop(arg_value)
|
|
291
|
+
for arg_value in event.args
|
|
292
|
+
),
|
|
293
|
+
)
|
|
294
|
+
on_drop[ix] = event
|
|
284
295
|
upload_props["on_drop"] = on_drop
|
|
285
296
|
|
|
286
297
|
input_props_unique_name = get_unique_variable_name()
|
|
287
298
|
root_props_unique_name = get_unique_variable_name()
|
|
299
|
+
is_drag_active_unique_name = get_unique_variable_name()
|
|
300
|
+
drag_active_css_class_unique_name = get_unique_variable_name() + "-drag-active"
|
|
301
|
+
|
|
302
|
+
# Handle special style when dragging over the drop zone.
|
|
303
|
+
if "drag_active_style" in props:
|
|
304
|
+
props.setdefault("style", Style())[
|
|
305
|
+
f"&:where(.{drag_active_css_class_unique_name})"
|
|
306
|
+
] = props.pop("drag_active_style")
|
|
307
|
+
props["class_name"].append(
|
|
308
|
+
cond(
|
|
309
|
+
Var(is_drag_active_unique_name),
|
|
310
|
+
drag_active_css_class_unique_name,
|
|
311
|
+
"",
|
|
312
|
+
),
|
|
313
|
+
)
|
|
288
314
|
|
|
289
315
|
event_var, callback_str = StatefulComponent._get_memoized_event_triggers(
|
|
290
316
|
GhostUpload.create(on_drop=upload_props["on_drop"])
|
|
@@ -303,7 +329,13 @@ class Upload(MemoizationLeaf):
|
|
|
303
329
|
}
|
|
304
330
|
)
|
|
305
331
|
|
|
306
|
-
left_side =
|
|
332
|
+
left_side = (
|
|
333
|
+
"const { "
|
|
334
|
+
f"getRootProps: {root_props_unique_name}, "
|
|
335
|
+
f"getInputProps: {input_props_unique_name}, "
|
|
336
|
+
f"isDragActive: {is_drag_active_unique_name}"
|
|
337
|
+
"}"
|
|
338
|
+
)
|
|
307
339
|
right_side = f"useDropzone({use_dropzone_arguments!s})"
|
|
308
340
|
|
|
309
341
|
var_data = VarData.merge(
|
|
@@ -12,6 +12,7 @@ from reflex.components.component import Component, ComponentNamespace, Memoizati
|
|
|
12
12
|
from reflex.components.core.breakpoints import Breakpoints
|
|
13
13
|
from reflex.constants import Dirs
|
|
14
14
|
from reflex.event import CallableEventSpec, EventSpec, EventType
|
|
15
|
+
from reflex.style import Style
|
|
15
16
|
from reflex.utils.imports import ImportVar
|
|
16
17
|
from reflex.vars import VarData
|
|
17
18
|
from reflex.vars.base import Var
|
|
@@ -157,6 +158,7 @@ class Upload(MemoizationLeaf):
|
|
|
157
158
|
no_click: Var[bool] | bool | None = None,
|
|
158
159
|
no_drag: Var[bool] | bool | None = None,
|
|
159
160
|
no_keyboard: Var[bool] | bool | None = None,
|
|
161
|
+
drag_active_style: Style | None = None,
|
|
160
162
|
style: Sequence[Mapping[str, Any]]
|
|
161
163
|
| Mapping[str, Any]
|
|
162
164
|
| Var[Mapping[str, Any]]
|
|
@@ -199,6 +201,7 @@ class Upload(MemoizationLeaf):
|
|
|
199
201
|
no_drag: Whether to disable drag and drop.
|
|
200
202
|
no_keyboard: Whether to disable using the space/enter keys to upload.
|
|
201
203
|
on_drop: Fired when files are dropped.
|
|
204
|
+
drag_active_style: Style rules to apply when actively dragging.
|
|
202
205
|
style: The style of the component.
|
|
203
206
|
key: A unique key for the component.
|
|
204
207
|
id: The id for the component.
|
|
@@ -227,6 +230,7 @@ class StyledUpload(Upload):
|
|
|
227
230
|
no_click: Var[bool] | bool | None = None,
|
|
228
231
|
no_drag: Var[bool] | bool | None = None,
|
|
229
232
|
no_keyboard: Var[bool] | bool | None = None,
|
|
233
|
+
drag_active_style: Style | None = None,
|
|
230
234
|
style: Sequence[Mapping[str, Any]]
|
|
231
235
|
| Mapping[str, Any]
|
|
232
236
|
| Var[Mapping[str, Any]]
|
|
@@ -269,6 +273,7 @@ class StyledUpload(Upload):
|
|
|
269
273
|
no_drag: Whether to disable drag and drop.
|
|
270
274
|
no_keyboard: Whether to disable using the space/enter keys to upload.
|
|
271
275
|
on_drop: Fired when files are dropped.
|
|
276
|
+
drag_active_style: Style rules to apply when actively dragging.
|
|
272
277
|
style: The style of the component.
|
|
273
278
|
key: A unique key for the component.
|
|
274
279
|
id: The id for the component.
|
|
@@ -297,6 +302,7 @@ class UploadNamespace(ComponentNamespace):
|
|
|
297
302
|
no_click: Var[bool] | bool | None = None,
|
|
298
303
|
no_drag: Var[bool] | bool | None = None,
|
|
299
304
|
no_keyboard: Var[bool] | bool | None = None,
|
|
305
|
+
drag_active_style: Style | None = None,
|
|
300
306
|
style: Sequence[Mapping[str, Any]]
|
|
301
307
|
| Mapping[str, Any]
|
|
302
308
|
| Var[Mapping[str, Any]]
|
|
@@ -339,6 +345,7 @@ class UploadNamespace(ComponentNamespace):
|
|
|
339
345
|
no_drag: Whether to disable drag and drop.
|
|
340
346
|
no_keyboard: Whether to disable using the space/enter keys to upload.
|
|
341
347
|
on_drop: Fired when files are dropped.
|
|
348
|
+
drag_active_style: Style rules to apply when actively dragging.
|
|
342
349
|
style: The style of the component.
|
|
343
350
|
key: A unique key for the component.
|
|
344
351
|
id: The id for the component.
|
|
@@ -27,8 +27,6 @@ class Audio(ReactPlayer):
|
|
|
27
27
|
light: Var[bool] | bool | None = None,
|
|
28
28
|
volume: Var[float] | float | None = None,
|
|
29
29
|
muted: Var[bool] | bool | None = None,
|
|
30
|
-
width: Var[str] | str | None = None,
|
|
31
|
-
height: Var[str] | str | None = None,
|
|
32
30
|
style: Sequence[Mapping[str, Any]]
|
|
33
31
|
| Mapping[str, Any]
|
|
34
32
|
| Var[Mapping[str, Any]]
|
|
@@ -83,8 +81,6 @@ class Audio(ReactPlayer):
|
|
|
83
81
|
light: Set to true to show just the video thumbnail, which loads the full player on click
|
|
84
82
|
volume: Set the volume of the player, between 0 and 1
|
|
85
83
|
muted: Mutes the player
|
|
86
|
-
width: Set the width of the player: ex:640px
|
|
87
|
-
height: Set the height of the player: ex:640px
|
|
88
84
|
on_ready: Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
|
|
89
85
|
on_start: Called when media starts playing.
|
|
90
86
|
on_play: Called when media starts or resumes playing after pausing or buffering.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import TypedDict
|
|
5
|
+
from typing import Any, TypedDict
|
|
6
6
|
|
|
7
7
|
from reflex.components.component import NoSSRComponent
|
|
8
8
|
from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
|
|
@@ -50,12 +50,6 @@ class ReactPlayer(NoSSRComponent):
|
|
|
50
50
|
# Mutes the player
|
|
51
51
|
muted: Var[bool]
|
|
52
52
|
|
|
53
|
-
# Set the width of the player: ex:640px
|
|
54
|
-
width: Var[str]
|
|
55
|
-
|
|
56
|
-
# Set the height of the player: ex:640px
|
|
57
|
-
height: Var[str]
|
|
58
|
-
|
|
59
53
|
# Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
|
|
60
54
|
on_ready: EventHandler[no_args_event_spec]
|
|
61
55
|
|
|
@@ -103,3 +97,23 @@ class ReactPlayer(NoSSRComponent):
|
|
|
103
97
|
|
|
104
98
|
# Called when picture-in-picture mode is disabled.
|
|
105
99
|
on_disable_pip: EventHandler[no_args_event_spec]
|
|
100
|
+
|
|
101
|
+
def _render(self, props: dict[str, Any] | None = None):
|
|
102
|
+
"""Render the component. Adds width and height set to None because
|
|
103
|
+
react-player will set them to some random value that overrides the
|
|
104
|
+
css width and height.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
props: The props to pass to the component.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
The rendered component.
|
|
111
|
+
"""
|
|
112
|
+
return (
|
|
113
|
+
super()
|
|
114
|
+
._render(props)
|
|
115
|
+
.add_props(
|
|
116
|
+
width=Var.create(None),
|
|
117
|
+
height=Var.create(None),
|
|
118
|
+
)
|
|
119
|
+
)
|
|
@@ -30,8 +30,6 @@ class ReactPlayer(NoSSRComponent):
|
|
|
30
30
|
light: Var[bool] | bool | None = None,
|
|
31
31
|
volume: Var[float] | float | None = None,
|
|
32
32
|
muted: Var[bool] | bool | None = None,
|
|
33
|
-
width: Var[str] | str | None = None,
|
|
34
|
-
height: Var[str] | str | None = None,
|
|
35
33
|
style: Sequence[Mapping[str, Any]]
|
|
36
34
|
| Mapping[str, Any]
|
|
37
35
|
| Var[Mapping[str, Any]]
|
|
@@ -86,8 +84,6 @@ class ReactPlayer(NoSSRComponent):
|
|
|
86
84
|
light: Set to true to show just the video thumbnail, which loads the full player on click
|
|
87
85
|
volume: Set the volume of the player, between 0 and 1
|
|
88
86
|
muted: Mutes the player
|
|
89
|
-
width: Set the width of the player: ex:640px
|
|
90
|
-
height: Set the height of the player: ex:640px
|
|
91
87
|
on_ready: Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
|
|
92
88
|
on_start: Called when media starts playing.
|
|
93
89
|
on_play: Called when media starts or resumes playing after pausing or buffering.
|
|
@@ -27,8 +27,6 @@ class Video(ReactPlayer):
|
|
|
27
27
|
light: Var[bool] | bool | None = None,
|
|
28
28
|
volume: Var[float] | float | None = None,
|
|
29
29
|
muted: Var[bool] | bool | None = None,
|
|
30
|
-
width: Var[str] | str | None = None,
|
|
31
|
-
height: Var[str] | str | None = None,
|
|
32
30
|
style: Sequence[Mapping[str, Any]]
|
|
33
31
|
| Mapping[str, Any]
|
|
34
32
|
| Var[Mapping[str, Any]]
|
|
@@ -83,8 +81,6 @@ class Video(ReactPlayer):
|
|
|
83
81
|
light: Set to true to show just the video thumbnail, which loads the full player on click
|
|
84
82
|
volume: Set the volume of the player, between 0 and 1
|
|
85
83
|
muted: Mutes the player
|
|
86
|
-
width: Set the width of the player: ex:640px
|
|
87
|
-
height: Set the height of the player: ex:640px
|
|
88
84
|
on_ready: Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
|
|
89
85
|
on_start: Called when media starts playing.
|
|
90
86
|
on_play: Called when media starts or resumes playing after pausing or buffering.
|
reflex/config.py
CHANGED
|
@@ -55,7 +55,7 @@ def _load_dotenv_from_str(env_files: str) -> None:
|
|
|
55
55
|
|
|
56
56
|
if load_dotenv is None:
|
|
57
57
|
console.error(
|
|
58
|
-
"""The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.0
|
|
58
|
+
"""The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.1.0"`."""
|
|
59
59
|
)
|
|
60
60
|
return
|
|
61
61
|
|
|
@@ -68,7 +68,7 @@ def _load_dotenv_from_str(env_files: str) -> None:
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
# Load the env files at import time if they are set in the ENV_FILE environment variable.
|
|
71
|
-
if
|
|
71
|
+
if env_files := os.getenv("ENV_FILE"):
|
|
72
72
|
_load_dotenv_from_str(env_files)
|
|
73
73
|
|
|
74
74
|
|
reflex/constants/__init__.py
CHANGED
|
@@ -41,6 +41,7 @@ from .config import (
|
|
|
41
41
|
DefaultPorts,
|
|
42
42
|
Expiration,
|
|
43
43
|
GitIgnore,
|
|
44
|
+
PyprojectToml,
|
|
44
45
|
RequirementsTxt,
|
|
45
46
|
)
|
|
46
47
|
from .custom_components import CustomComponents
|
|
@@ -106,6 +107,7 @@ __all__ = [
|
|
|
106
107
|
"Page404",
|
|
107
108
|
"PageNames",
|
|
108
109
|
"Ping",
|
|
110
|
+
"PyprojectToml",
|
|
109
111
|
"Reflex",
|
|
110
112
|
"RequirementsTxt",
|
|
111
113
|
"RouteArgType",
|
reflex/constants/base.py
CHANGED
|
@@ -134,7 +134,7 @@ class Templates(SimpleNamespace):
|
|
|
134
134
|
DEFAULT_TEMPLATE_URL = "https://blank-template.reflex.run"
|
|
135
135
|
|
|
136
136
|
# The reflex.build frontend host
|
|
137
|
-
REFLEX_BUILD_FRONTEND = "https://
|
|
137
|
+
REFLEX_BUILD_FRONTEND = "https://reflex.build"
|
|
138
138
|
|
|
139
139
|
# The reflex.build backend host
|
|
140
140
|
REFLEX_BUILD_BACKEND = "https://flexgen-prod-flexgen.fly.dev"
|
reflex/constants/config.py
CHANGED
|
@@ -49,6 +49,13 @@ class GitIgnore(SimpleNamespace):
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
class PyprojectToml(SimpleNamespace):
|
|
53
|
+
"""Pyproject.toml constants."""
|
|
54
|
+
|
|
55
|
+
# The pyproject.toml file.
|
|
56
|
+
FILE = "pyproject.toml"
|
|
57
|
+
|
|
58
|
+
|
|
52
59
|
class RequirementsTxt(SimpleNamespace):
|
|
53
60
|
"""Requirements.txt constants."""
|
|
54
61
|
|
reflex/constants/installer.py
CHANGED
|
@@ -14,7 +14,7 @@ class Bun(SimpleNamespace):
|
|
|
14
14
|
"""Bun constants."""
|
|
15
15
|
|
|
16
16
|
# The Bun version.
|
|
17
|
-
VERSION = "1.2.
|
|
17
|
+
VERSION = "1.2.11"
|
|
18
18
|
|
|
19
19
|
# Min Bun Version
|
|
20
20
|
MIN_VERSION = "1.2.8"
|
|
@@ -86,6 +86,18 @@ def _determine_nextjs_version() -> str:
|
|
|
86
86
|
return default_version
|
|
87
87
|
|
|
88
88
|
|
|
89
|
+
def _determine_react_version() -> str:
|
|
90
|
+
default_version = "19.1.0"
|
|
91
|
+
if (version := os.getenv("REACT_VERSION")) and version != default_version:
|
|
92
|
+
from reflex.utils import console
|
|
93
|
+
|
|
94
|
+
console.warn(
|
|
95
|
+
f"You have requested react@{version} but the supported version is {default_version}, abandon all hope ye who enter here."
|
|
96
|
+
)
|
|
97
|
+
return version
|
|
98
|
+
return default_version
|
|
99
|
+
|
|
100
|
+
|
|
89
101
|
class PackageJson(SimpleNamespace):
|
|
90
102
|
"""Constants used to build the package.json file."""
|
|
91
103
|
|
|
@@ -99,15 +111,17 @@ class PackageJson(SimpleNamespace):
|
|
|
99
111
|
|
|
100
112
|
PATH = "package.json"
|
|
101
113
|
|
|
114
|
+
_react_version = _determine_react_version()
|
|
115
|
+
|
|
102
116
|
DEPENDENCIES = {
|
|
103
117
|
"@emotion/react": "11.14.0",
|
|
104
|
-
"axios": "1.
|
|
118
|
+
"axios": "1.9.0",
|
|
105
119
|
"json5": "2.2.3",
|
|
106
120
|
"next": _determine_nextjs_version(),
|
|
107
121
|
"next-sitemap": "4.2.3",
|
|
108
122
|
"next-themes": "0.4.6",
|
|
109
|
-
"react":
|
|
110
|
-
"react-dom":
|
|
123
|
+
"react": _react_version,
|
|
124
|
+
"react-dom": _react_version,
|
|
111
125
|
"react-focus-lock": "2.13.6",
|
|
112
126
|
"socket.io-client": "4.8.1",
|
|
113
127
|
"universal-cookie": "7.2.2",
|
|
@@ -119,5 +133,5 @@ class PackageJson(SimpleNamespace):
|
|
|
119
133
|
}
|
|
120
134
|
OVERRIDES = {
|
|
121
135
|
# This should always match the `react` version in DEPENDENCIES for recharts compatibility.
|
|
122
|
-
"react-is":
|
|
136
|
+
"react-is": _react_version
|
|
123
137
|
}
|
reflex/event.py
CHANGED
|
@@ -2066,6 +2066,30 @@ class EventNamespace:
|
|
|
2066
2066
|
setattr(func, BACKGROUND_TASK_MARKER, True)
|
|
2067
2067
|
if getattr(func, "__name__", "").startswith("_"):
|
|
2068
2068
|
raise ValueError("Event handlers cannot be private.")
|
|
2069
|
+
|
|
2070
|
+
qualname: str | None = getattr(func, "__qualname__", None)
|
|
2071
|
+
|
|
2072
|
+
if qualname and (
|
|
2073
|
+
len(func_path := qualname.split(".")) == 1
|
|
2074
|
+
or func_path[-2] == "<locals>"
|
|
2075
|
+
):
|
|
2076
|
+
from reflex.state import BaseState
|
|
2077
|
+
|
|
2078
|
+
types = get_type_hints(func)
|
|
2079
|
+
state_arg_name = next(iter(inspect.signature(func).parameters), None)
|
|
2080
|
+
state_cls = state_arg_name and types.get(state_arg_name)
|
|
2081
|
+
if state_cls and issubclass(state_cls, BaseState):
|
|
2082
|
+
name = (
|
|
2083
|
+
(func.__module__ + "." + qualname)
|
|
2084
|
+
.replace(".", "_")
|
|
2085
|
+
.replace("<locals>", "_")
|
|
2086
|
+
.removeprefix("_")
|
|
2087
|
+
)
|
|
2088
|
+
object.__setattr__(func, "__name__", name)
|
|
2089
|
+
object.__setattr__(func, "__qualname__", name)
|
|
2090
|
+
state_cls._add_event_handler(name, func)
|
|
2091
|
+
return getattr(state_cls, name)
|
|
2092
|
+
|
|
2069
2093
|
return func # pyright: ignore [reportReturnType]
|
|
2070
2094
|
|
|
2071
2095
|
if func is not None:
|