reflex 0.6.8a1__py3-none-any.whl → 0.7.0a1__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/.templates/jinja/custom_components/pyproject.toml.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +7 -7
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +1 -4
- reflex/.templates/web/utils/state.js +65 -36
- reflex/__init__.py +4 -17
- reflex/__init__.pyi +1 -2
- reflex/app.py +244 -115
- reflex/app_mixins/lifespan.py +9 -9
- reflex/app_mixins/middleware.py +6 -6
- reflex/app_module_for_backend.py +3 -7
- reflex/base.py +7 -7
- reflex/compiler/compiler.py +8 -0
- reflex/compiler/utils.py +35 -6
- reflex/components/base/bare.py +1 -1
- reflex/components/base/error_boundary.py +2 -1
- reflex/components/base/error_boundary.pyi +2 -1
- reflex/components/base/meta.py +2 -2
- reflex/components/base/strict_mode.py +10 -0
- reflex/components/base/strict_mode.pyi +57 -0
- reflex/components/component.py +38 -77
- reflex/components/core/banner.py +83 -4
- reflex/components/core/banner.pyi +86 -0
- reflex/components/core/breakpoints.py +3 -1
- reflex/components/core/client_side_routing.py +1 -1
- reflex/components/core/client_side_routing.pyi +1 -1
- reflex/components/core/cond.py +9 -10
- reflex/components/core/debounce.py +1 -1
- reflex/components/core/foreach.py +23 -3
- reflex/components/core/html.py +1 -1
- reflex/components/core/match.py +5 -5
- reflex/components/core/sticky.py +160 -0
- reflex/components/core/sticky.pyi +449 -0
- reflex/components/core/upload.py +2 -2
- reflex/components/datadisplay/code.py +5 -14
- reflex/components/datadisplay/dataeditor.py +7 -4
- reflex/components/datadisplay/logo.py +13 -8
- reflex/components/datadisplay/shiki_code_block.py +14 -9
- reflex/components/dynamic.py +22 -3
- reflex/components/el/constants/reflex.py +1 -1
- reflex/components/el/element.py +1 -1
- reflex/components/el/elements/forms.py +4 -4
- reflex/components/el/elements/forms.pyi +4 -4
- reflex/components/lucide/icon.py +46 -8
- reflex/components/lucide/icon.pyi +54 -0
- reflex/components/markdown/markdown.py +10 -8
- reflex/components/moment/moment.py +2 -2
- reflex/components/next/image.py +16 -4
- reflex/components/next/image.pyi +4 -2
- reflex/components/next/link.py +1 -1
- reflex/components/plotly/plotly.py +5 -5
- reflex/components/props.py +3 -3
- reflex/components/radix/__init__.pyi +1 -1
- reflex/components/radix/primitives/accordion.py +9 -5
- reflex/components/radix/primitives/accordion.pyi +3 -1
- reflex/components/radix/primitives/drawer.py +5 -2
- reflex/components/radix/primitives/drawer.pyi +4 -4
- reflex/components/radix/primitives/form.pyi +6 -6
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/themes/color_mode.py +11 -9
- reflex/components/radix/themes/components/alert_dialog.py +3 -0
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +1 -1
- reflex/components/radix/themes/components/context_menu.py +5 -0
- reflex/components/radix/themes/components/dialog.py +3 -0
- reflex/components/radix/themes/components/dropdown_menu.py +5 -0
- reflex/components/radix/themes/components/hover_card.py +3 -0
- reflex/components/radix/themes/components/icon_button.py +2 -2
- reflex/components/radix/themes/components/icon_button.pyi +1 -0
- reflex/components/radix/themes/components/popover.py +3 -0
- reflex/components/radix/themes/components/radio_cards.py +2 -0
- reflex/components/radix/themes/components/radio_group.py +1 -1
- reflex/components/radix/themes/components/select.py +3 -0
- reflex/components/radix/themes/components/tabs.py +3 -0
- reflex/components/radix/themes/components/text_area.py +12 -0
- reflex/components/radix/themes/components/text_area.pyi +2 -0
- reflex/components/radix/themes/components/text_field.py +1 -1
- reflex/components/radix/themes/components/tooltip.py +3 -1
- reflex/components/radix/themes/components/tooltip.pyi +1 -0
- reflex/components/radix/themes/layout/__init__.pyi +1 -1
- reflex/components/radix/themes/layout/list.py +2 -2
- reflex/components/radix/themes/layout/stack.py +2 -2
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/text.py +2 -2
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/recharts/__init__.py +2 -0
- reflex/components/recharts/__init__.pyi +2 -0
- reflex/components/recharts/charts.py +15 -15
- reflex/components/recharts/general.py +19 -4
- reflex/components/recharts/general.pyi +55 -4
- reflex/components/recharts/polar.py +2 -2
- reflex/components/recharts/recharts.py +4 -4
- reflex/components/sonner/toast.py +15 -13
- reflex/components/sonner/toast.pyi +6 -6
- reflex/components/suneditor/editor.py +6 -4
- reflex/components/suneditor/editor.pyi +2 -2
- reflex/components/tags/iter_tag.py +3 -3
- reflex/components/tags/tag.py +25 -3
- reflex/config.py +48 -20
- reflex/constants/__init__.py +1 -0
- reflex/constants/base.py +4 -1
- reflex/constants/compiler.py +5 -2
- reflex/constants/config.py +8 -1
- reflex/constants/installer.py +9 -9
- reflex/constants/style.py +1 -1
- reflex/custom_components/custom_components.py +9 -7
- reflex/event.py +137 -163
- reflex/experimental/__init__.py +19 -11
- reflex/experimental/client_state.py +53 -28
- reflex/experimental/hooks.py +5 -5
- reflex/experimental/layout.py +8 -5
- reflex/experimental/layout.pyi +1 -1
- reflex/experimental/misc.py +3 -3
- reflex/istate/wrappers.py +1 -1
- reflex/middleware/hydrate_middleware.py +2 -2
- reflex/model.py +11 -6
- reflex/page.py +3 -3
- reflex/reflex.py +90 -19
- reflex/route.py +1 -1
- reflex/state.py +358 -401
- reflex/style.py +27 -3
- reflex/testing.py +34 -39
- reflex/utils/build.py +6 -2
- reflex/utils/codespaces.py +1 -4
- reflex/utils/compat.py +6 -5
- reflex/utils/console.py +52 -21
- reflex/utils/exceptions.py +76 -26
- reflex/utils/exec.py +69 -74
- reflex/utils/export.py +6 -1
- reflex/utils/format.py +7 -39
- reflex/utils/imports.py +2 -2
- reflex/utils/lazy_loader.py +7 -1
- reflex/utils/path_ops.py +28 -14
- reflex/utils/prerequisites.py +324 -65
- reflex/utils/processes.py +45 -32
- reflex/utils/pyi_generator.py +30 -25
- reflex/utils/registry.py +4 -4
- reflex/utils/serializers.py +1 -1
- reflex/utils/telemetry.py +5 -4
- reflex/utils/types.py +42 -18
- reflex/vars/base.py +650 -333
- reflex/vars/datetime.py +6 -7
- reflex/vars/dep_tracking.py +344 -0
- reflex/vars/function.py +11 -5
- reflex/vars/number.py +31 -43
- reflex/vars/object.py +63 -62
- reflex/vars/sequence.py +79 -67
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/METADATA +7 -10
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/RECORD +153 -150
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/WHEEL +1 -1
- reflex/experimental/assets.py +0 -37
- reflex/proxy.py +0 -119
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/LICENSE +0 -0
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/entry_points.txt +0 -0
reflex/components/component.py
CHANGED
|
@@ -23,8 +23,6 @@ from typing import (
|
|
|
23
23
|
Union,
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
-
from typing_extensions import deprecated
|
|
27
|
-
|
|
28
26
|
import reflex.state
|
|
29
27
|
from reflex.base import Base
|
|
30
28
|
from reflex.compiler.templates import STATEFUL_COMPONENT
|
|
@@ -47,11 +45,10 @@ from reflex.event import (
|
|
|
47
45
|
EventChain,
|
|
48
46
|
EventHandler,
|
|
49
47
|
EventSpec,
|
|
50
|
-
EventVar,
|
|
51
48
|
no_args_event_spec,
|
|
52
49
|
)
|
|
53
50
|
from reflex.style import Style, format_as_emotion
|
|
54
|
-
from reflex.utils import
|
|
51
|
+
from reflex.utils import format, imports, types
|
|
55
52
|
from reflex.utils.imports import (
|
|
56
53
|
ImmutableParsedImportDict,
|
|
57
54
|
ImportDict,
|
|
@@ -153,7 +150,7 @@ class BaseComponent(Base, ABC):
|
|
|
153
150
|
class ComponentNamespace(SimpleNamespace):
|
|
154
151
|
"""A namespace to manage components with subcomponents."""
|
|
155
152
|
|
|
156
|
-
def __hash__(self) -> int:
|
|
153
|
+
def __hash__(self) -> int: # pyright: ignore [reportIncompatibleVariableOverride]
|
|
157
154
|
"""Get the hash of the namespace.
|
|
158
155
|
|
|
159
156
|
Returns:
|
|
@@ -429,20 +426,22 @@ class Component(BaseComponent, ABC):
|
|
|
429
426
|
else:
|
|
430
427
|
continue
|
|
431
428
|
|
|
429
|
+
def determine_key(value: Any):
|
|
430
|
+
# Try to create a var from the value
|
|
431
|
+
key = value if isinstance(value, Var) else LiteralVar.create(value)
|
|
432
|
+
|
|
433
|
+
# Check that the var type is not None.
|
|
434
|
+
if key is None:
|
|
435
|
+
raise TypeError
|
|
436
|
+
|
|
437
|
+
return key
|
|
438
|
+
|
|
432
439
|
# Check whether the key is a component prop.
|
|
433
440
|
if types._issubclass(field_type, Var):
|
|
434
441
|
# Used to store the passed types if var type is a union.
|
|
435
442
|
passed_types = None
|
|
436
443
|
try:
|
|
437
|
-
|
|
438
|
-
if isinstance(value, Var):
|
|
439
|
-
kwargs[key] = value
|
|
440
|
-
else:
|
|
441
|
-
kwargs[key] = LiteralVar.create(value)
|
|
442
|
-
|
|
443
|
-
# Check that the var type is not None.
|
|
444
|
-
if kwargs[key] is None:
|
|
445
|
-
raise TypeError
|
|
444
|
+
kwargs[key] = determine_key(value)
|
|
446
445
|
|
|
447
446
|
expected_type = fields[key].outer_type_.__args__[0]
|
|
448
447
|
# validate literal fields.
|
|
@@ -463,9 +462,7 @@ class Component(BaseComponent, ABC):
|
|
|
463
462
|
if types.is_union(passed_type):
|
|
464
463
|
# We need to check all possible types in the union.
|
|
465
464
|
passed_types = (
|
|
466
|
-
arg
|
|
467
|
-
for arg in passed_type.__args__ # type: ignore
|
|
468
|
-
if arg is not type(None)
|
|
465
|
+
arg for arg in passed_type.__args__ if arg is not type(None)
|
|
469
466
|
)
|
|
470
467
|
if (
|
|
471
468
|
# If the passed var is a union, check if all possible types are valid.
|
|
@@ -492,7 +489,7 @@ class Component(BaseComponent, ABC):
|
|
|
492
489
|
# Check if the key is an event trigger.
|
|
493
490
|
if key in component_specific_triggers:
|
|
494
491
|
kwargs["event_triggers"][key] = EventChain.create(
|
|
495
|
-
value=value,
|
|
492
|
+
value=value,
|
|
496
493
|
args_spec=component_specific_triggers[key],
|
|
497
494
|
key=key,
|
|
498
495
|
)
|
|
@@ -545,41 +542,6 @@ class Component(BaseComponent, ABC):
|
|
|
545
542
|
# Construct the component.
|
|
546
543
|
super().__init__(*args, **kwargs)
|
|
547
544
|
|
|
548
|
-
@deprecated("Use rx.EventChain.create instead.")
|
|
549
|
-
def _create_event_chain(
|
|
550
|
-
self,
|
|
551
|
-
args_spec: types.ArgsSpec | Sequence[types.ArgsSpec],
|
|
552
|
-
value: Union[
|
|
553
|
-
Var,
|
|
554
|
-
EventHandler,
|
|
555
|
-
EventSpec,
|
|
556
|
-
List[Union[EventHandler, EventSpec, EventVar]],
|
|
557
|
-
Callable,
|
|
558
|
-
],
|
|
559
|
-
key: Optional[str] = None,
|
|
560
|
-
) -> Union[EventChain, Var]:
|
|
561
|
-
"""Create an event chain from a variety of input types.
|
|
562
|
-
|
|
563
|
-
Args:
|
|
564
|
-
args_spec: The args_spec of the event trigger being bound.
|
|
565
|
-
value: The value to create the event chain from.
|
|
566
|
-
key: The key of the event trigger being bound.
|
|
567
|
-
|
|
568
|
-
Returns:
|
|
569
|
-
The event chain.
|
|
570
|
-
"""
|
|
571
|
-
console.deprecate(
|
|
572
|
-
"Component._create_event_chain",
|
|
573
|
-
"Use rx.EventChain.create instead.",
|
|
574
|
-
deprecation_version="0.6.8",
|
|
575
|
-
removal_version="0.7.0",
|
|
576
|
-
)
|
|
577
|
-
return EventChain.create(
|
|
578
|
-
value=value, # type: ignore
|
|
579
|
-
args_spec=args_spec,
|
|
580
|
-
key=key,
|
|
581
|
-
)
|
|
582
|
-
|
|
583
545
|
def get_event_triggers(
|
|
584
546
|
self,
|
|
585
547
|
) -> Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]:
|
|
@@ -614,7 +576,7 @@ class Component(BaseComponent, ABC):
|
|
|
614
576
|
annotation = field.annotation
|
|
615
577
|
if (metadata := getattr(annotation, "__metadata__", None)) is not None:
|
|
616
578
|
args_spec = metadata[0]
|
|
617
|
-
default_triggers[field.name] = args_spec or (no_args_event_spec)
|
|
579
|
+
default_triggers[field.name] = args_spec or (no_args_event_spec)
|
|
618
580
|
return default_triggers
|
|
619
581
|
|
|
620
582
|
def __repr__(self) -> str:
|
|
@@ -661,8 +623,7 @@ class Component(BaseComponent, ABC):
|
|
|
661
623
|
if props is None:
|
|
662
624
|
# Add component props to the tag.
|
|
663
625
|
props = {
|
|
664
|
-
attr
|
|
665
|
-
for attr in self.get_props()
|
|
626
|
+
attr.removesuffix("_"): getattr(self, attr) for attr in self.get_props()
|
|
666
627
|
}
|
|
667
628
|
|
|
668
629
|
# Add ref to element if `id` is not None.
|
|
@@ -740,22 +701,21 @@ class Component(BaseComponent, ABC):
|
|
|
740
701
|
# Import here to avoid circular imports.
|
|
741
702
|
from reflex.components.base.bare import Bare
|
|
742
703
|
from reflex.components.base.fragment import Fragment
|
|
743
|
-
from reflex.utils.exceptions import
|
|
704
|
+
from reflex.utils.exceptions import ChildrenTypeError
|
|
744
705
|
|
|
745
706
|
# Filter out None props
|
|
746
707
|
props = {key: value for key, value in props.items() if value is not None}
|
|
747
708
|
|
|
748
|
-
def validate_children(children):
|
|
709
|
+
def validate_children(children: tuple | list):
|
|
749
710
|
for child in children:
|
|
750
|
-
if isinstance(child, tuple):
|
|
711
|
+
if isinstance(child, (tuple, list)):
|
|
751
712
|
validate_children(child)
|
|
713
|
+
|
|
752
714
|
# Make sure the child is a valid type.
|
|
753
|
-
if not types._isinstance(
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
f"Got child {child} of type {type(child)}.",
|
|
758
|
-
)
|
|
715
|
+
if isinstance(child, dict) or not types._isinstance(
|
|
716
|
+
child, ComponentChild
|
|
717
|
+
):
|
|
718
|
+
raise ChildrenTypeError(component=cls.__name__, child=child)
|
|
759
719
|
|
|
760
720
|
# Validate all the children.
|
|
761
721
|
validate_children(children)
|
|
@@ -798,7 +758,7 @@ class Component(BaseComponent, ABC):
|
|
|
798
758
|
|
|
799
759
|
# Walk the MRO to call all `add_style` methods.
|
|
800
760
|
for base in self._iter_parent_classes_with_method("add_style"):
|
|
801
|
-
s = base.add_style(self)
|
|
761
|
+
s = base.add_style(self)
|
|
802
762
|
if s is not None:
|
|
803
763
|
styles.append(s)
|
|
804
764
|
|
|
@@ -890,7 +850,7 @@ class Component(BaseComponent, ABC):
|
|
|
890
850
|
else {}
|
|
891
851
|
)
|
|
892
852
|
|
|
893
|
-
def render(self) ->
|
|
853
|
+
def render(self) -> dict:
|
|
894
854
|
"""Render the component.
|
|
895
855
|
|
|
896
856
|
Returns:
|
|
@@ -908,7 +868,7 @@ class Component(BaseComponent, ABC):
|
|
|
908
868
|
self._replace_prop_names(rendered_dict)
|
|
909
869
|
return rendered_dict
|
|
910
870
|
|
|
911
|
-
def _replace_prop_names(self, rendered_dict) -> None:
|
|
871
|
+
def _replace_prop_names(self, rendered_dict: dict) -> None:
|
|
912
872
|
"""Replace the prop names in the render dictionary.
|
|
913
873
|
|
|
914
874
|
Args:
|
|
@@ -948,7 +908,7 @@ class Component(BaseComponent, ABC):
|
|
|
948
908
|
comp.__name__ for comp in (Fragment, Foreach, Cond, Match)
|
|
949
909
|
]
|
|
950
910
|
|
|
951
|
-
def validate_child(child):
|
|
911
|
+
def validate_child(child: Any):
|
|
952
912
|
child_name = type(child).__name__
|
|
953
913
|
|
|
954
914
|
# Iterate through the immediate children of fragment
|
|
@@ -1711,7 +1671,7 @@ class CustomComponent(Component):
|
|
|
1711
1671
|
if base_value is not None and isinstance(value, Component):
|
|
1712
1672
|
self.component_props[key] = value
|
|
1713
1673
|
value = base_value._replace(
|
|
1714
|
-
merge_var_data=VarData(
|
|
1674
|
+
merge_var_data=VarData(
|
|
1715
1675
|
imports=value._get_all_imports(),
|
|
1716
1676
|
hooks=value._get_all_hooks(),
|
|
1717
1677
|
)
|
|
@@ -1744,7 +1704,7 @@ class CustomComponent(Component):
|
|
|
1744
1704
|
return hash(self.tag)
|
|
1745
1705
|
|
|
1746
1706
|
@classmethod
|
|
1747
|
-
def get_props(cls) -> Set[str]:
|
|
1707
|
+
def get_props(cls) -> Set[str]: # pyright: ignore [reportIncompatibleVariableOverride]
|
|
1748
1708
|
"""Get the props for the component.
|
|
1749
1709
|
|
|
1750
1710
|
Returns:
|
|
@@ -1839,7 +1799,7 @@ class CustomComponent(Component):
|
|
|
1839
1799
|
include_children=include_children, ignore_ids=ignore_ids
|
|
1840
1800
|
)
|
|
1841
1801
|
|
|
1842
|
-
@lru_cache(maxsize=None) # noqa
|
|
1802
|
+
@lru_cache(maxsize=None) # noqa: B019
|
|
1843
1803
|
def get_component(self) -> Component:
|
|
1844
1804
|
"""Render the component.
|
|
1845
1805
|
|
|
@@ -1983,7 +1943,7 @@ class StatefulComponent(BaseComponent):
|
|
|
1983
1943
|
|
|
1984
1944
|
if not should_memoize:
|
|
1985
1945
|
# Determine if any Vars have associated data.
|
|
1986
|
-
for prop_var in component._get_vars():
|
|
1946
|
+
for prop_var in component._get_vars(include_children=True):
|
|
1987
1947
|
if prop_var._get_all_var_data():
|
|
1988
1948
|
should_memoize = True
|
|
1989
1949
|
break
|
|
@@ -2366,8 +2326,8 @@ class MemoizationLeaf(Component):
|
|
|
2366
2326
|
"""
|
|
2367
2327
|
comp = super().create(*children, **props)
|
|
2368
2328
|
if comp._get_all_hooks():
|
|
2369
|
-
comp._memoization_mode =
|
|
2370
|
-
|
|
2329
|
+
comp._memoization_mode = dataclasses.replace(
|
|
2330
|
+
comp._memoization_mode, disposition=MemoizationDisposition.ALWAYS
|
|
2371
2331
|
)
|
|
2372
2332
|
return comp
|
|
2373
2333
|
|
|
@@ -2428,7 +2388,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
|
|
|
2428
2388
|
if tag["name"] == "match":
|
|
2429
2389
|
element = tag["cond"]
|
|
2430
2390
|
|
|
2431
|
-
conditionals = tag["default"]
|
|
2391
|
+
conditionals = render_dict_to_var(tag["default"], imported_names)
|
|
2432
2392
|
|
|
2433
2393
|
for case in tag["match_cases"][::-1]:
|
|
2434
2394
|
condition = case[0].to_string() == element.to_string()
|
|
@@ -2437,7 +2397,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
|
|
|
2437
2397
|
|
|
2438
2398
|
conditionals = ternary_operation(
|
|
2439
2399
|
condition,
|
|
2440
|
-
case[-1],
|
|
2400
|
+
render_dict_to_var(case[-1], imported_names),
|
|
2441
2401
|
conditionals,
|
|
2442
2402
|
)
|
|
2443
2403
|
|
|
@@ -2496,6 +2456,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
|
|
|
2496
2456
|
@dataclasses.dataclass(
|
|
2497
2457
|
eq=False,
|
|
2498
2458
|
frozen=True,
|
|
2459
|
+
slots=True,
|
|
2499
2460
|
)
|
|
2500
2461
|
class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
|
|
2501
2462
|
"""A Var that represents a Component."""
|
reflex/components/core/banner.py
CHANGED
|
@@ -4,8 +4,10 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Optional
|
|
6
6
|
|
|
7
|
+
from reflex import constants
|
|
7
8
|
from reflex.components.component import Component
|
|
8
9
|
from reflex.components.core.cond import cond
|
|
10
|
+
from reflex.components.datadisplay.logo import svg_logo
|
|
9
11
|
from reflex.components.el.elements.typography import Div
|
|
10
12
|
from reflex.components.lucide.icon import Icon
|
|
11
13
|
from reflex.components.radix.themes.components.dialog import (
|
|
@@ -25,7 +27,7 @@ from reflex.vars.function import FunctionStringVar
|
|
|
25
27
|
from reflex.vars.number import BooleanVar
|
|
26
28
|
from reflex.vars.sequence import LiteralArrayVar
|
|
27
29
|
|
|
28
|
-
connect_error_var_data: VarData = VarData(
|
|
30
|
+
connect_error_var_data: VarData = VarData(
|
|
29
31
|
imports=Imports.EVENTS,
|
|
30
32
|
hooks={Hooks.EVENTS: None},
|
|
31
33
|
)
|
|
@@ -99,14 +101,14 @@ class ConnectionToaster(Toaster):
|
|
|
99
101
|
"""
|
|
100
102
|
toast_id = "websocket-error"
|
|
101
103
|
target_url = WebsocketTargetURL.create()
|
|
102
|
-
props = ToastProps(
|
|
104
|
+
props = ToastProps(
|
|
103
105
|
description=LiteralVar.create(
|
|
104
106
|
f"Check if server is reachable at {target_url}",
|
|
105
107
|
),
|
|
106
108
|
close_button=True,
|
|
107
109
|
duration=120000,
|
|
108
110
|
id=toast_id,
|
|
109
|
-
)
|
|
111
|
+
) # pyright: ignore [reportCallIssue]
|
|
110
112
|
|
|
111
113
|
individual_hooks = [
|
|
112
114
|
f"const toast_props = {LiteralVar.create(props)!s};",
|
|
@@ -116,7 +118,7 @@ class ConnectionToaster(Toaster):
|
|
|
116
118
|
_var_data=VarData(
|
|
117
119
|
imports={
|
|
118
120
|
"react": ["useEffect", "useState"],
|
|
119
|
-
**dict(target_url._get_all_var_data().imports), #
|
|
121
|
+
**dict(target_url._get_all_var_data().imports), # pyright: ignore [reportArgumentType, reportOptionalMemberAccess]
|
|
120
122
|
}
|
|
121
123
|
),
|
|
122
124
|
).call(
|
|
@@ -293,7 +295,84 @@ class ConnectionPulser(Div):
|
|
|
293
295
|
)
|
|
294
296
|
|
|
295
297
|
|
|
298
|
+
class BackendDisabled(Div):
|
|
299
|
+
"""A component that displays a message when the backend is disabled."""
|
|
300
|
+
|
|
301
|
+
@classmethod
|
|
302
|
+
def create(cls, **props) -> Component:
|
|
303
|
+
"""Create a backend disabled component.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
**props: The properties of the component.
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
The backend disabled component.
|
|
310
|
+
"""
|
|
311
|
+
import reflex as rx
|
|
312
|
+
|
|
313
|
+
is_backend_disabled = Var(
|
|
314
|
+
"backendDisabled",
|
|
315
|
+
_var_type=bool,
|
|
316
|
+
_var_data=VarData(
|
|
317
|
+
hooks={
|
|
318
|
+
"const [backendDisabled, setBackendDisabled] = useState(false);": None,
|
|
319
|
+
"useEffect(() => { setBackendDisabled(isBackendDisabled()); }, []);": None,
|
|
320
|
+
},
|
|
321
|
+
imports={
|
|
322
|
+
f"$/{constants.Dirs.STATE_PATH}": [
|
|
323
|
+
ImportVar(tag="isBackendDisabled")
|
|
324
|
+
],
|
|
325
|
+
},
|
|
326
|
+
),
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
return super().create(
|
|
330
|
+
rx.cond(
|
|
331
|
+
is_backend_disabled,
|
|
332
|
+
rx.box(
|
|
333
|
+
rx.box(
|
|
334
|
+
rx.card(
|
|
335
|
+
rx.vstack(
|
|
336
|
+
svg_logo(),
|
|
337
|
+
rx.text(
|
|
338
|
+
"You ran out of compute credits.",
|
|
339
|
+
),
|
|
340
|
+
rx.callout(
|
|
341
|
+
rx.fragment(
|
|
342
|
+
"Please upgrade your plan or raise your compute credits at ",
|
|
343
|
+
rx.link(
|
|
344
|
+
"Reflex Cloud.",
|
|
345
|
+
href="https://cloud.reflex.dev/",
|
|
346
|
+
),
|
|
347
|
+
),
|
|
348
|
+
width="100%",
|
|
349
|
+
icon="info",
|
|
350
|
+
variant="surface",
|
|
351
|
+
),
|
|
352
|
+
),
|
|
353
|
+
font_size="20px",
|
|
354
|
+
font_family='"Inter", "Helvetica", "Arial", sans-serif',
|
|
355
|
+
variant="classic",
|
|
356
|
+
),
|
|
357
|
+
position="fixed",
|
|
358
|
+
top="50%",
|
|
359
|
+
left="50%",
|
|
360
|
+
transform="translate(-50%, -50%)",
|
|
361
|
+
width="40ch",
|
|
362
|
+
max_width="90vw",
|
|
363
|
+
),
|
|
364
|
+
position="fixed",
|
|
365
|
+
z_index=9999,
|
|
366
|
+
backdrop_filter="grayscale(1) blur(5px)",
|
|
367
|
+
width="100dvw",
|
|
368
|
+
height="100dvh",
|
|
369
|
+
),
|
|
370
|
+
)
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
|
|
296
374
|
connection_banner = ConnectionBanner.create
|
|
297
375
|
connection_modal = ConnectionModal.create
|
|
298
376
|
connection_toaster = ConnectionToaster.create
|
|
299
377
|
connection_pulser = ConnectionPulser.create
|
|
378
|
+
backend_disabled = BackendDisabled.create
|
|
@@ -350,7 +350,93 @@ class ConnectionPulser(Div):
|
|
|
350
350
|
"""
|
|
351
351
|
...
|
|
352
352
|
|
|
353
|
+
class BackendDisabled(Div):
|
|
354
|
+
@overload
|
|
355
|
+
@classmethod
|
|
356
|
+
def create( # type: ignore
|
|
357
|
+
cls,
|
|
358
|
+
*children,
|
|
359
|
+
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
360
|
+
auto_capitalize: Optional[
|
|
361
|
+
Union[Var[Union[bool, int, str]], bool, int, str]
|
|
362
|
+
] = None,
|
|
363
|
+
content_editable: Optional[
|
|
364
|
+
Union[Var[Union[bool, int, str]], bool, int, str]
|
|
365
|
+
] = None,
|
|
366
|
+
context_menu: Optional[
|
|
367
|
+
Union[Var[Union[bool, int, str]], bool, int, str]
|
|
368
|
+
] = None,
|
|
369
|
+
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
370
|
+
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
371
|
+
enter_key_hint: Optional[
|
|
372
|
+
Union[Var[Union[bool, int, str]], bool, int, str]
|
|
373
|
+
] = None,
|
|
374
|
+
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
375
|
+
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
376
|
+
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
377
|
+
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
378
|
+
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
379
|
+
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
380
|
+
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
381
|
+
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
382
|
+
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
|
383
|
+
style: Optional[Style] = None,
|
|
384
|
+
key: Optional[Any] = None,
|
|
385
|
+
id: Optional[Any] = None,
|
|
386
|
+
class_name: Optional[Any] = None,
|
|
387
|
+
autofocus: Optional[bool] = None,
|
|
388
|
+
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
|
|
389
|
+
on_blur: Optional[EventType[[], BASE_STATE]] = None,
|
|
390
|
+
on_click: Optional[EventType[[], BASE_STATE]] = None,
|
|
391
|
+
on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
|
|
392
|
+
on_double_click: Optional[EventType[[], BASE_STATE]] = None,
|
|
393
|
+
on_focus: Optional[EventType[[], BASE_STATE]] = None,
|
|
394
|
+
on_mount: Optional[EventType[[], BASE_STATE]] = None,
|
|
395
|
+
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
|
|
396
|
+
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
|
|
397
|
+
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
|
|
398
|
+
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
|
|
399
|
+
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
|
|
400
|
+
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
|
|
401
|
+
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
|
|
402
|
+
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
|
|
403
|
+
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
|
|
404
|
+
**props,
|
|
405
|
+
) -> "BackendDisabled":
|
|
406
|
+
"""Create a backend disabled component.
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
410
|
+
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
411
|
+
content_editable: Indicates whether the element's content is editable.
|
|
412
|
+
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
413
|
+
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
|
414
|
+
draggable: Defines whether the element can be dragged.
|
|
415
|
+
enter_key_hint: Hints what media types the media element is able to play.
|
|
416
|
+
hidden: Defines whether the element is hidden.
|
|
417
|
+
input_mode: Defines the type of the element.
|
|
418
|
+
item_prop: Defines the name of the element for metadata purposes.
|
|
419
|
+
lang: Defines the language used in the element.
|
|
420
|
+
role: Defines the role of the element.
|
|
421
|
+
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
|
422
|
+
spell_check: Defines whether the element may be checked for spelling errors.
|
|
423
|
+
tab_index: Defines the position of the current element in the tabbing order.
|
|
424
|
+
title: Defines a tooltip for the element.
|
|
425
|
+
style: The style of the component.
|
|
426
|
+
key: A unique key for the component.
|
|
427
|
+
id: The id for the component.
|
|
428
|
+
class_name: The class name for the component.
|
|
429
|
+
autofocus: Whether the component should take the focus once the page is loaded
|
|
430
|
+
custom_attrs: custom attribute
|
|
431
|
+
**props: The properties of the component.
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
The backend disabled component.
|
|
435
|
+
"""
|
|
436
|
+
...
|
|
437
|
+
|
|
353
438
|
connection_banner = ConnectionBanner.create
|
|
354
439
|
connection_modal = ConnectionModal.create
|
|
355
440
|
connection_toaster = ConnectionToaster.create
|
|
356
441
|
connection_pulser = ConnectionPulser.create
|
|
442
|
+
backend_disabled = BackendDisabled.create
|
|
@@ -41,7 +41,7 @@ class ClientSideRouting(Component):
|
|
|
41
41
|
return ""
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def wait_for_client_redirect(component) -> Component:
|
|
44
|
+
def wait_for_client_redirect(component: Component) -> Component:
|
|
45
45
|
"""Wait for a redirect to occur before rendering a component.
|
|
46
46
|
|
|
47
47
|
This prevents the 404 page from flashing while the redirect is happening.
|
reflex/components/core/cond.py
CHANGED
|
@@ -26,10 +26,9 @@ class Cond(MemoizationLeaf):
|
|
|
26
26
|
cond: Var[Any]
|
|
27
27
|
|
|
28
28
|
# The component to render if the cond is true.
|
|
29
|
-
comp1: BaseComponent
|
|
30
|
-
|
|
29
|
+
comp1: BaseComponent | None = None
|
|
31
30
|
# The component to render if the cond is false.
|
|
32
|
-
comp2: BaseComponent
|
|
31
|
+
comp2: BaseComponent | None = None
|
|
33
32
|
|
|
34
33
|
@classmethod
|
|
35
34
|
def create(
|
|
@@ -73,8 +72,8 @@ class Cond(MemoizationLeaf):
|
|
|
73
72
|
def _render(self) -> Tag:
|
|
74
73
|
return CondTag(
|
|
75
74
|
cond=self.cond,
|
|
76
|
-
true_value=self.comp1.render(),
|
|
77
|
-
false_value=self.comp2.render(),
|
|
75
|
+
true_value=self.comp1.render(), # pyright: ignore [reportOptionalMemberAccess]
|
|
76
|
+
false_value=self.comp2.render(), # pyright: ignore [reportOptionalMemberAccess]
|
|
78
77
|
)
|
|
79
78
|
|
|
80
79
|
def render(self) -> Dict:
|
|
@@ -111,7 +110,7 @@ class Cond(MemoizationLeaf):
|
|
|
111
110
|
|
|
112
111
|
|
|
113
112
|
@overload
|
|
114
|
-
def cond(condition: Any, c1: Component, c2: Any) -> Component: ...
|
|
113
|
+
def cond(condition: Any, c1: Component, c2: Any) -> Component: ... # pyright: ignore [reportOverlappingOverload]
|
|
115
114
|
|
|
116
115
|
|
|
117
116
|
@overload
|
|
@@ -154,7 +153,7 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
|
|
|
154
153
|
if c2 is None:
|
|
155
154
|
raise ValueError("For conditional vars, the second argument must be set.")
|
|
156
155
|
|
|
157
|
-
def create_var(cond_part):
|
|
156
|
+
def create_var(cond_part: Any) -> Var[Any]:
|
|
158
157
|
return LiteralVar.create(cond_part)
|
|
159
158
|
|
|
160
159
|
# convert the truth and false cond parts into vars so the _var_data can be obtained.
|
|
@@ -163,16 +162,16 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
|
|
|
163
162
|
|
|
164
163
|
# Create the conditional var.
|
|
165
164
|
return ternary_operation(
|
|
166
|
-
cond_var.bool()._replace(
|
|
165
|
+
cond_var.bool()._replace(
|
|
167
166
|
merge_var_data=VarData(imports=_IS_TRUE_IMPORT),
|
|
168
|
-
),
|
|
167
|
+
),
|
|
169
168
|
c1,
|
|
170
169
|
c2,
|
|
171
170
|
)
|
|
172
171
|
|
|
173
172
|
|
|
174
173
|
@overload
|
|
175
|
-
def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... #
|
|
174
|
+
def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... # pyright: ignore [reportOverlappingOverload]
|
|
176
175
|
|
|
177
176
|
|
|
178
177
|
@overload
|
|
@@ -28,7 +28,7 @@ class DebounceInput(Component):
|
|
|
28
28
|
min_length: Var[int]
|
|
29
29
|
|
|
30
30
|
# Time to wait between end of input and triggering on_change
|
|
31
|
-
debounce_timeout: Var[int] = DEFAULT_DEBOUNCE_TIMEOUT
|
|
31
|
+
debounce_timeout: Var[int] = Var.create(DEFAULT_DEBOUNCE_TIMEOUT)
|
|
32
32
|
|
|
33
33
|
# If true, notify when Enter key is pressed
|
|
34
34
|
force_notify_by_enter: Var[bool]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import functools
|
|
5
6
|
import inspect
|
|
6
7
|
from typing import Any, Callable, Iterable
|
|
7
8
|
|
|
@@ -10,6 +11,7 @@ from reflex.components.component import Component
|
|
|
10
11
|
from reflex.components.tags import IterTag
|
|
11
12
|
from reflex.constants import MemoizationMode
|
|
12
13
|
from reflex.state import ComponentState
|
|
14
|
+
from reflex.utils.exceptions import UntypedVarError
|
|
13
15
|
from reflex.vars.base import LiteralVar, Var
|
|
14
16
|
|
|
15
17
|
|
|
@@ -50,6 +52,7 @@ class Foreach(Component):
|
|
|
50
52
|
Raises:
|
|
51
53
|
ForeachVarError: If the iterable is of type Any.
|
|
52
54
|
TypeError: If the render function is a ComponentState.
|
|
55
|
+
UntypedVarError: If the iterable is of type Any without a type annotation.
|
|
53
56
|
"""
|
|
54
57
|
iterable = LiteralVar.create(iterable)
|
|
55
58
|
if iterable._var_type == Any:
|
|
@@ -71,8 +74,14 @@ class Foreach(Component):
|
|
|
71
74
|
iterable=iterable,
|
|
72
75
|
render_fn=render_fn,
|
|
73
76
|
)
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
try:
|
|
78
|
+
# Keep a ref to a rendered component to determine correct imports/hooks/styles.
|
|
79
|
+
component.children = [component._render().render_component()]
|
|
80
|
+
except UntypedVarError as e:
|
|
81
|
+
raise UntypedVarError(
|
|
82
|
+
f"Could not foreach over var `{iterable!s}` without a type annotation. "
|
|
83
|
+
"See https://reflex.dev/docs/library/dynamic-rendering/foreach/"
|
|
84
|
+
) from e
|
|
76
85
|
return component
|
|
77
86
|
|
|
78
87
|
def _render(self) -> IterTag:
|
|
@@ -97,9 +106,20 @@ class Foreach(Component):
|
|
|
97
106
|
# Determine the index var name based on the params accepted by render_fn.
|
|
98
107
|
props["index_var_name"] = params[1].name
|
|
99
108
|
else:
|
|
109
|
+
render_fn = self.render_fn
|
|
100
110
|
# Otherwise, use a deterministic index, based on the render function bytecode.
|
|
101
111
|
code_hash = (
|
|
102
|
-
hash(
|
|
112
|
+
hash(
|
|
113
|
+
getattr(
|
|
114
|
+
render_fn,
|
|
115
|
+
"__code__",
|
|
116
|
+
(
|
|
117
|
+
repr(self.render_fn)
|
|
118
|
+
if not isinstance(render_fn, functools.partial)
|
|
119
|
+
else render_fn.func.__code__
|
|
120
|
+
),
|
|
121
|
+
)
|
|
122
|
+
)
|
|
103
123
|
.to_bytes(
|
|
104
124
|
length=8,
|
|
105
125
|
byteorder="big",
|