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.

Files changed (155) hide show
  1. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +1 -1
  2. reflex/.templates/jinja/web/pages/_app.js.jinja2 +7 -7
  3. reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
  4. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +1 -4
  5. reflex/.templates/web/utils/state.js +65 -36
  6. reflex/__init__.py +4 -17
  7. reflex/__init__.pyi +1 -2
  8. reflex/app.py +244 -115
  9. reflex/app_mixins/lifespan.py +9 -9
  10. reflex/app_mixins/middleware.py +6 -6
  11. reflex/app_module_for_backend.py +3 -7
  12. reflex/base.py +7 -7
  13. reflex/compiler/compiler.py +8 -0
  14. reflex/compiler/utils.py +35 -6
  15. reflex/components/base/bare.py +1 -1
  16. reflex/components/base/error_boundary.py +2 -1
  17. reflex/components/base/error_boundary.pyi +2 -1
  18. reflex/components/base/meta.py +2 -2
  19. reflex/components/base/strict_mode.py +10 -0
  20. reflex/components/base/strict_mode.pyi +57 -0
  21. reflex/components/component.py +38 -77
  22. reflex/components/core/banner.py +83 -4
  23. reflex/components/core/banner.pyi +86 -0
  24. reflex/components/core/breakpoints.py +3 -1
  25. reflex/components/core/client_side_routing.py +1 -1
  26. reflex/components/core/client_side_routing.pyi +1 -1
  27. reflex/components/core/cond.py +9 -10
  28. reflex/components/core/debounce.py +1 -1
  29. reflex/components/core/foreach.py +23 -3
  30. reflex/components/core/html.py +1 -1
  31. reflex/components/core/match.py +5 -5
  32. reflex/components/core/sticky.py +160 -0
  33. reflex/components/core/sticky.pyi +449 -0
  34. reflex/components/core/upload.py +2 -2
  35. reflex/components/datadisplay/code.py +5 -14
  36. reflex/components/datadisplay/dataeditor.py +7 -4
  37. reflex/components/datadisplay/logo.py +13 -8
  38. reflex/components/datadisplay/shiki_code_block.py +14 -9
  39. reflex/components/dynamic.py +22 -3
  40. reflex/components/el/constants/reflex.py +1 -1
  41. reflex/components/el/element.py +1 -1
  42. reflex/components/el/elements/forms.py +4 -4
  43. reflex/components/el/elements/forms.pyi +4 -4
  44. reflex/components/lucide/icon.py +46 -8
  45. reflex/components/lucide/icon.pyi +54 -0
  46. reflex/components/markdown/markdown.py +10 -8
  47. reflex/components/moment/moment.py +2 -2
  48. reflex/components/next/image.py +16 -4
  49. reflex/components/next/image.pyi +4 -2
  50. reflex/components/next/link.py +1 -1
  51. reflex/components/plotly/plotly.py +5 -5
  52. reflex/components/props.py +3 -3
  53. reflex/components/radix/__init__.pyi +1 -1
  54. reflex/components/radix/primitives/accordion.py +9 -5
  55. reflex/components/radix/primitives/accordion.pyi +3 -1
  56. reflex/components/radix/primitives/drawer.py +5 -2
  57. reflex/components/radix/primitives/drawer.pyi +4 -4
  58. reflex/components/radix/primitives/form.pyi +6 -6
  59. reflex/components/radix/primitives/progress.py +1 -1
  60. reflex/components/radix/primitives/slider.py +1 -1
  61. reflex/components/radix/themes/color_mode.py +11 -9
  62. reflex/components/radix/themes/components/alert_dialog.py +3 -0
  63. reflex/components/radix/themes/components/card.py +1 -1
  64. reflex/components/radix/themes/components/card.pyi +1 -1
  65. reflex/components/radix/themes/components/context_menu.py +5 -0
  66. reflex/components/radix/themes/components/dialog.py +3 -0
  67. reflex/components/radix/themes/components/dropdown_menu.py +5 -0
  68. reflex/components/radix/themes/components/hover_card.py +3 -0
  69. reflex/components/radix/themes/components/icon_button.py +2 -2
  70. reflex/components/radix/themes/components/icon_button.pyi +1 -0
  71. reflex/components/radix/themes/components/popover.py +3 -0
  72. reflex/components/radix/themes/components/radio_cards.py +2 -0
  73. reflex/components/radix/themes/components/radio_group.py +1 -1
  74. reflex/components/radix/themes/components/select.py +3 -0
  75. reflex/components/radix/themes/components/tabs.py +3 -0
  76. reflex/components/radix/themes/components/text_area.py +12 -0
  77. reflex/components/radix/themes/components/text_area.pyi +2 -0
  78. reflex/components/radix/themes/components/text_field.py +1 -1
  79. reflex/components/radix/themes/components/tooltip.py +3 -1
  80. reflex/components/radix/themes/components/tooltip.pyi +1 -0
  81. reflex/components/radix/themes/layout/__init__.pyi +1 -1
  82. reflex/components/radix/themes/layout/list.py +2 -2
  83. reflex/components/radix/themes/layout/stack.py +2 -2
  84. reflex/components/radix/themes/typography/link.py +1 -1
  85. reflex/components/radix/themes/typography/text.py +2 -2
  86. reflex/components/react_player/react_player.py +1 -1
  87. reflex/components/recharts/__init__.py +2 -0
  88. reflex/components/recharts/__init__.pyi +2 -0
  89. reflex/components/recharts/charts.py +15 -15
  90. reflex/components/recharts/general.py +19 -4
  91. reflex/components/recharts/general.pyi +55 -4
  92. reflex/components/recharts/polar.py +2 -2
  93. reflex/components/recharts/recharts.py +4 -4
  94. reflex/components/sonner/toast.py +15 -13
  95. reflex/components/sonner/toast.pyi +6 -6
  96. reflex/components/suneditor/editor.py +6 -4
  97. reflex/components/suneditor/editor.pyi +2 -2
  98. reflex/components/tags/iter_tag.py +3 -3
  99. reflex/components/tags/tag.py +25 -3
  100. reflex/config.py +48 -20
  101. reflex/constants/__init__.py +1 -0
  102. reflex/constants/base.py +4 -1
  103. reflex/constants/compiler.py +5 -2
  104. reflex/constants/config.py +8 -1
  105. reflex/constants/installer.py +9 -9
  106. reflex/constants/style.py +1 -1
  107. reflex/custom_components/custom_components.py +9 -7
  108. reflex/event.py +137 -163
  109. reflex/experimental/__init__.py +19 -11
  110. reflex/experimental/client_state.py +53 -28
  111. reflex/experimental/hooks.py +5 -5
  112. reflex/experimental/layout.py +8 -5
  113. reflex/experimental/layout.pyi +1 -1
  114. reflex/experimental/misc.py +3 -3
  115. reflex/istate/wrappers.py +1 -1
  116. reflex/middleware/hydrate_middleware.py +2 -2
  117. reflex/model.py +11 -6
  118. reflex/page.py +3 -3
  119. reflex/reflex.py +90 -19
  120. reflex/route.py +1 -1
  121. reflex/state.py +358 -401
  122. reflex/style.py +27 -3
  123. reflex/testing.py +34 -39
  124. reflex/utils/build.py +6 -2
  125. reflex/utils/codespaces.py +1 -4
  126. reflex/utils/compat.py +6 -5
  127. reflex/utils/console.py +52 -21
  128. reflex/utils/exceptions.py +76 -26
  129. reflex/utils/exec.py +69 -74
  130. reflex/utils/export.py +6 -1
  131. reflex/utils/format.py +7 -39
  132. reflex/utils/imports.py +2 -2
  133. reflex/utils/lazy_loader.py +7 -1
  134. reflex/utils/path_ops.py +28 -14
  135. reflex/utils/prerequisites.py +324 -65
  136. reflex/utils/processes.py +45 -32
  137. reflex/utils/pyi_generator.py +30 -25
  138. reflex/utils/registry.py +4 -4
  139. reflex/utils/serializers.py +1 -1
  140. reflex/utils/telemetry.py +5 -4
  141. reflex/utils/types.py +42 -18
  142. reflex/vars/base.py +650 -333
  143. reflex/vars/datetime.py +6 -7
  144. reflex/vars/dep_tracking.py +344 -0
  145. reflex/vars/function.py +11 -5
  146. reflex/vars/number.py +31 -43
  147. reflex/vars/object.py +63 -62
  148. reflex/vars/sequence.py +79 -67
  149. {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/METADATA +7 -10
  150. {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/RECORD +153 -150
  151. {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/WHEEL +1 -1
  152. reflex/experimental/assets.py +0 -37
  153. reflex/proxy.py +0 -119
  154. {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/LICENSE +0 -0
  155. {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/entry_points.txt +0 -0
@@ -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 console, format, imports, types
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
- # Try to create a var from the value.
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, # type: ignore
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) # type: ignore
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[:-1] if attr.endswith("_") else attr: getattr(self, 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 ComponentTypeError
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(child, ComponentChild):
754
- raise ComponentTypeError(
755
- "Children of Reflex components must be other components, "
756
- "state vars, or primitive Python types. "
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) # type: ignore
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) -> Dict:
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( # type: ignore
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 = cls._memoization_mode.copy(
2370
- update={"disposition": MemoizationDisposition.ALWAYS}
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."""
@@ -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( # type: ignore
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( # type: ignore
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), # type: ignore
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
@@ -82,7 +82,9 @@ class Breakpoints(Dict[K, V]):
82
82
  return Breakpoints(
83
83
  {
84
84
  k: v
85
- for k, v in zip(["initial", *breakpoint_names], thresholds)
85
+ for k, v in zip(
86
+ ["initial", *breakpoint_names], thresholds, strict=True
87
+ )
86
88
  if v is not None
87
89
  }
88
90
  )
@@ -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.
@@ -60,7 +60,7 @@ class ClientSideRouting(Component):
60
60
  """
61
61
  ...
62
62
 
63
- def wait_for_client_redirect(component) -> Component: ...
63
+ def wait_for_client_redirect(component: Component) -> Component: ...
64
64
 
65
65
  class Default404Page(Component):
66
66
  @overload
@@ -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 = None # type: ignore
30
-
29
+ comp1: BaseComponent | None = None
31
30
  # The component to render if the cond is false.
32
- comp2: BaseComponent = None # type: ignore
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( # type: ignore
165
+ cond_var.bool()._replace(
167
166
  merge_var_data=VarData(imports=_IS_TRUE_IMPORT),
168
- ), # type: ignore
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: ... # type: ignore
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 # type: ignore
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
- # Keep a ref to a rendered component to determine correct imports/hooks/styles.
75
- component.children = [component._render().render_component()]
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(self.render_fn.__code__)
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",
@@ -14,7 +14,7 @@ class Html(Div):
14
14
  """
15
15
 
16
16
  # The HTML to render.
17
- dangerouslySetInnerHTML: Var[Dict[str, str]]
17
+ dangerouslySetInnerHTML: Var[Dict[str, str]] # noqa: N815
18
18
 
19
19
  @classmethod
20
20
  def create(cls, *children, **props):