reflex 0.4.9a2__py3-none-any.whl → 0.5.0__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 (133) hide show
  1. reflex/.templates/apps/blank/code/blank.py +19 -16
  2. reflex/.templates/apps/demo/code/demo.py +1 -1
  3. reflex/.templates/apps/demo/code/pages/datatable.py +4 -4
  4. reflex/.templates/apps/demo/code/pages/forms.py +2 -2
  5. reflex/.templates/jinja/web/tailwind.config.js.jinja2 +12 -0
  6. reflex/.templates/web/utils/helpers/debounce.js +17 -0
  7. reflex/.templates/web/utils/helpers/throttle.js +22 -0
  8. reflex/.templates/web/utils/state.js +21 -3
  9. reflex/__init__.py +6 -1
  10. reflex/__init__.pyi +4 -1
  11. reflex/app.py +157 -140
  12. reflex/app_module_for_backend.py +1 -1
  13. reflex/base.py +13 -15
  14. reflex/compiler/compiler.py +10 -1
  15. reflex/compiler/utils.py +3 -30
  16. reflex/components/__init__.py +1 -0
  17. reflex/components/chakra/datadisplay/list.py +1 -3
  18. reflex/components/chakra/datadisplay/list.pyi +3 -3
  19. reflex/components/chakra/disclosure/accordion.py +1 -1
  20. reflex/components/chakra/forms/pininput.pyi +1 -1
  21. reflex/components/chakra/media/icon.py +2 -2
  22. reflex/components/component.py +275 -32
  23. reflex/components/core/__init__.py +2 -2
  24. reflex/components/core/cond.py +1 -10
  25. reflex/components/core/debounce.py +5 -2
  26. reflex/components/core/debounce.pyi +4 -2
  27. reflex/components/core/foreach.py +60 -49
  28. reflex/components/core/html.py +6 -0
  29. reflex/components/core/match.py +2 -17
  30. reflex/components/core/upload.py +42 -1
  31. reflex/components/core/upload.pyi +199 -1
  32. reflex/components/datadisplay/code.py +7 -3
  33. reflex/components/datadisplay/code.pyi +3 -1
  34. reflex/components/el/elements/forms.py +1 -1
  35. reflex/components/el/elements/forms.pyi +1 -1
  36. reflex/components/lucide/icon.py +5 -13
  37. reflex/components/lucide/icon.pyi +0 -1
  38. reflex/components/markdown/markdown.py +5 -23
  39. reflex/components/markdown/markdown.pyi +1 -4
  40. reflex/components/radix/primitives/accordion.py +265 -410
  41. reflex/components/radix/primitives/accordion.pyi +390 -36
  42. reflex/components/radix/primitives/form.py +33 -29
  43. reflex/components/radix/primitives/form.pyi +7 -2
  44. reflex/components/radix/primitives/progress.py +17 -9
  45. reflex/components/radix/primitives/progress.pyi +2 -0
  46. reflex/components/radix/primitives/slider.py +30 -18
  47. reflex/components/radix/primitives/slider.pyi +4 -0
  48. reflex/components/radix/themes/base.py +8 -1
  49. reflex/components/radix/themes/base.pyi +79 -1
  50. reflex/components/radix/themes/color_mode.py +88 -20
  51. reflex/components/radix/themes/color_mode.pyi +157 -139
  52. reflex/components/radix/themes/components/__init__.py +17 -0
  53. reflex/components/radix/themes/components/badge.py +2 -1
  54. reflex/components/radix/themes/components/badge.pyi +3 -1
  55. reflex/components/radix/themes/components/button.py +3 -1
  56. reflex/components/radix/themes/components/button.pyi +4 -1
  57. reflex/components/radix/themes/components/checkbox_cards.py +48 -0
  58. reflex/components/radix/themes/components/checkbox_cards.pyi +264 -0
  59. reflex/components/radix/themes/components/checkbox_group.py +42 -0
  60. reflex/components/radix/themes/components/checkbox_group.pyi +253 -0
  61. reflex/components/radix/themes/components/data_list.py +63 -0
  62. reflex/components/radix/themes/components/data_list.pyi +426 -0
  63. reflex/components/radix/themes/components/icon_button.py +20 -17
  64. reflex/components/radix/themes/components/icon_button.pyi +5 -1
  65. reflex/components/radix/themes/components/progress.py +55 -0
  66. reflex/components/radix/themes/components/progress.pyi +180 -0
  67. reflex/components/radix/themes/components/radio.py +31 -0
  68. reflex/components/radix/themes/components/radio.pyi +169 -0
  69. reflex/components/radix/themes/components/radio_cards.py +48 -0
  70. reflex/components/radix/themes/components/radio_cards.pyi +264 -0
  71. reflex/components/radix/themes/components/radio_group.py +2 -4
  72. reflex/components/radix/themes/components/segmented_control.py +48 -0
  73. reflex/components/radix/themes/components/segmented_control.pyi +262 -0
  74. reflex/components/radix/themes/components/skeleton.py +32 -0
  75. reflex/components/radix/themes/components/skeleton.pyi +106 -0
  76. reflex/components/radix/themes/components/spinner.py +26 -0
  77. reflex/components/radix/themes/components/spinner.pyi +101 -0
  78. reflex/components/radix/themes/components/tabs.py +26 -1
  79. reflex/components/radix/themes/components/tabs.pyi +69 -9
  80. reflex/components/radix/themes/components/text_field.py +101 -71
  81. reflex/components/radix/themes/components/text_field.pyi +81 -499
  82. reflex/components/radix/themes/layout/base.py +2 -2
  83. reflex/components/radix/themes/layout/base.pyi +4 -4
  84. reflex/components/radix/themes/layout/center.py +8 -3
  85. reflex/components/radix/themes/layout/center.pyi +2 -1
  86. reflex/components/radix/themes/layout/container.py +30 -2
  87. reflex/components/radix/themes/layout/container.pyi +9 -30
  88. reflex/components/radix/themes/layout/list.py +10 -5
  89. reflex/components/radix/themes/layout/list.pyi +5 -21
  90. reflex/components/radix/themes/layout/spacer.py +8 -3
  91. reflex/components/radix/themes/layout/spacer.pyi +2 -1
  92. reflex/components/radix/themes/layout/stack.py +7 -1
  93. reflex/components/radix/themes/layout/stack.pyi +3 -3
  94. reflex/components/radix/themes/typography/link.py +10 -2
  95. reflex/components/radix/themes/typography/link.pyi +5 -4
  96. reflex/components/sonner/__init__.py +3 -0
  97. reflex/components/sonner/toast.py +267 -0
  98. reflex/components/sonner/toast.pyi +205 -0
  99. reflex/components/tags/iter_tag.py +9 -6
  100. reflex/config.py +30 -54
  101. reflex/constants/__init__.py +0 -2
  102. reflex/constants/base.py +0 -5
  103. reflex/constants/colors.py +2 -0
  104. reflex/constants/installer.py +5 -1
  105. reflex/constants/route.py +4 -0
  106. reflex/custom_components/custom_components.py +24 -2
  107. reflex/event.py +75 -30
  108. reflex/experimental/__init__.py +5 -0
  109. reflex/experimental/layout.py +24 -6
  110. reflex/model.py +2 -1
  111. reflex/page.py +7 -4
  112. reflex/reflex.py +8 -3
  113. reflex/route.py +39 -0
  114. reflex/state.py +128 -131
  115. reflex/style.py +25 -3
  116. reflex/testing.py +10 -6
  117. reflex/utils/console.py +3 -1
  118. reflex/utils/exec.py +20 -7
  119. reflex/utils/format.py +1 -1
  120. reflex/utils/imports.py +3 -1
  121. reflex/utils/prerequisites.py +141 -20
  122. reflex/utils/processes.py +21 -1
  123. reflex/utils/pyi_generator.py +95 -5
  124. reflex/utils/serializers.py +1 -1
  125. reflex/utils/telemetry.py +26 -4
  126. reflex/utils/types.py +62 -18
  127. reflex/vars.py +11 -5
  128. {reflex-0.4.9a2.dist-info → reflex-0.5.0.dist-info}/METADATA +16 -4
  129. {reflex-0.4.9a2.dist-info → reflex-0.5.0.dist-info}/RECORD +132 -110
  130. {reflex-0.4.9a2.dist-info → reflex-0.5.0.dist-info}/WHEEL +1 -1
  131. reflex/app.pyi +0 -149
  132. {reflex-0.4.9a2.dist-info → reflex-0.5.0.dist-info}/LICENSE +0 -0
  133. {reflex-0.4.9a2.dist-info → reflex-0.5.0.dist-info}/entry_points.txt +0 -0
@@ -4,10 +4,11 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Any, Dict, Literal
6
6
 
7
- from reflex.components.component import Component, ComponentNamespace
7
+ from reflex.components.component import ComponentNamespace
8
8
  from reflex.components.el.elements.forms import Form as HTMLForm
9
- from reflex.components.radix.themes.components.text_field import TextFieldInput
9
+ from reflex.components.radix.themes.components.text_field import TextFieldRoot
10
10
  from reflex.constants.event import EventTriggers
11
+ from reflex.style import Style
11
12
  from reflex.vars import Var
12
13
 
13
14
  from .base import RadixPrimitiveComponentWithClassName
@@ -37,11 +38,13 @@ class FormRoot(FormComponent, HTMLForm):
37
38
  EventTriggers.ON_CLEAR_SERVER_ERRORS: lambda: [],
38
39
  }
39
40
 
40
- def _apply_theme(self, theme: Component):
41
- return {
42
- "width": "260px",
43
- **self.style,
44
- }
41
+ def add_style(self) -> Style | None:
42
+ """Add style to the component.
43
+
44
+ Returns:
45
+ The style of the component.
46
+ """
47
+ return Style({"width": "100%"})
45
48
 
46
49
 
47
50
  class FormField(FormComponent):
@@ -57,12 +60,13 @@ class FormField(FormComponent):
57
60
  # Flag to mark the form field as invalid, for server side validation.
58
61
  server_invalid: Var[bool]
59
62
 
60
- def _apply_theme(self, theme: Component):
61
- return {
62
- "display": "grid",
63
- "margin_bottom": "10px",
64
- **self.style,
65
- }
63
+ def add_style(self) -> Style | None:
64
+ """Add style to the component.
65
+
66
+ Returns:
67
+ The style of the component.
68
+ """
69
+ return Style({"display": "grid", "margin_bottom": "10px"})
66
70
 
67
71
 
68
72
  class FormLabel(FormComponent):
@@ -72,13 +76,13 @@ class FormLabel(FormComponent):
72
76
 
73
77
  alias = "RadixFormLabel"
74
78
 
75
- def _apply_theme(self, theme: Component):
76
- return {
77
- "font_size": "15px",
78
- "font_weight": "500",
79
- "line_height": "35px",
80
- **self.style,
81
- }
79
+ def add_style(self) -> Style | None:
80
+ """Add style to the component.
81
+
82
+ Returns:
83
+ The style of the component.
84
+ """
85
+ return Style({"font_size": "15px", "font_weight": "500", "line_height": "35px"})
82
86
 
83
87
 
84
88
  class FormControl(FormComponent):
@@ -108,9 +112,9 @@ class FormControl(FormComponent):
108
112
  f"FormControl can only have at most one child, got {len(children)} children"
109
113
  )
110
114
  for child in children:
111
- if not isinstance(child, TextFieldInput):
115
+ if not isinstance(child, TextFieldRoot):
112
116
  raise TypeError(
113
- "Only Radix TextFieldInput is allowed as child of FormControl"
117
+ "Only Radix TextFieldRoot is allowed as child of FormControl"
114
118
  )
115
119
  return super().create(*children, **props)
116
120
 
@@ -145,13 +149,13 @@ class FormMessage(FormComponent):
145
149
  # Forces the message to be shown. This is useful when using server-side validation.
146
150
  force_match: Var[bool]
147
151
 
148
- def _apply_theme(self, theme: Component):
149
- return {
150
- "font_size": "13px",
151
- "opacity": "0.8",
152
- "color": "white",
153
- **self.style,
154
- }
152
+ def add_style(self) -> Style | None:
153
+ """Add style to the component.
154
+
155
+ Returns:
156
+ The style of the component.
157
+ """
158
+ return Style({"font_size": "13px", "opacity": "0.8", "color": "white"})
155
159
 
156
160
 
157
161
  class FormValidityState(FormComponent):
@@ -8,10 +8,11 @@ from reflex.vars import Var, BaseVar, ComputedVar
8
8
  from reflex.event import EventChain, EventHandler, EventSpec
9
9
  from reflex.style import Style
10
10
  from typing import Any, Dict, Literal
11
- from reflex.components.component import Component, ComponentNamespace
11
+ from reflex.components.component import ComponentNamespace
12
12
  from reflex.components.el.elements.forms import Form as HTMLForm
13
- from reflex.components.radix.themes.components.text_field import TextFieldInput
13
+ from reflex.components.radix.themes.components.text_field import TextFieldRoot
14
14
  from reflex.constants.event import EventTriggers
15
+ from reflex.style import Style
15
16
  from reflex.vars import Var
16
17
  from .base import RadixPrimitiveComponentWithClassName
17
18
 
@@ -95,6 +96,7 @@ class FormComponent(RadixPrimitiveComponentWithClassName):
95
96
 
96
97
  class FormRoot(FormComponent, HTMLForm):
97
98
  def get_event_triggers(self) -> Dict[str, Any]: ...
99
+ def add_style(self) -> Style | None: ...
98
100
  @overload
99
101
  @classmethod
100
102
  def create( # type: ignore
@@ -273,6 +275,7 @@ class FormRoot(FormComponent, HTMLForm):
273
275
  ...
274
276
 
275
277
  class FormField(FormComponent):
278
+ def add_style(self) -> Style | None: ...
276
279
  @overload
277
280
  @classmethod
278
281
  def create( # type: ignore
@@ -355,6 +358,7 @@ class FormField(FormComponent):
355
358
  ...
356
359
 
357
360
  class FormLabel(FormComponent):
361
+ def add_style(self) -> Style | None: ...
358
362
  @overload
359
363
  @classmethod
360
364
  def create( # type: ignore
@@ -528,6 +532,7 @@ LiteralMatcher = Literal[
528
532
  ]
529
533
 
530
534
  class FormMessage(FormComponent):
535
+ def add_style(self) -> Style | None: ...
531
536
  @overload
532
537
  @classmethod
533
538
  def create( # type: ignore
@@ -28,20 +28,24 @@ class ProgressRoot(ProgressComponent):
28
28
  # Override theme radius for progress bar: "none" | "small" | "medium" | "large" | "full"
29
29
  radius: Var[LiteralRadius]
30
30
 
31
- def _apply_theme(self, theme: Component):
31
+ def add_style(self) -> Style | None:
32
+ """Add style to the component.
33
+
34
+ Returns:
35
+ The style of the component.
36
+ """
32
37
  if self.radius is not None:
33
38
  self.custom_attrs["data-radius"] = self.radius
34
39
 
35
- self.style = Style(
40
+ return Style(
36
41
  {
37
42
  "position": "relative",
38
43
  "overflow": "hidden",
39
- "background": "var(--gray-a3)",
44
+ "background": color("gray", 3, alpha=True),
40
45
  "border_radius": "max(var(--radius-2), var(--radius-full))",
41
46
  "width": "100%",
42
47
  "height": "20px",
43
- "boxShadow": "inset 0 0 0 1px var(--gray-a5)",
44
- **self.style,
48
+ "boxShadow": f"inset 0 0 0 1px {color('gray', 5, alpha=True)}",
45
49
  }
46
50
  )
47
51
 
@@ -65,22 +69,26 @@ class ProgressIndicator(ProgressComponent):
65
69
  # The color scheme of the progress indicator.
66
70
  color_scheme: Var[LiteralAccentColor]
67
71
 
68
- def _apply_theme(self, theme: Component):
72
+ def add_style(self) -> Style | None:
73
+ """Add style to the component.
74
+
75
+ Returns:
76
+ The style of the component.
77
+ """
69
78
  if self.color_scheme is not None:
70
79
  self.custom_attrs["data-accent-color"] = self.color_scheme
71
80
 
72
- self.style = Style(
81
+ return Style(
73
82
  {
74
83
  "background_color": color("accent", 9),
75
84
  "width": "100%",
76
85
  "height": "100%",
77
- f"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms linear",
86
+ "transition": f"transform {DEFAULT_ANIMATION_DURATION}ms linear",
78
87
  "&[data_state='loading']": {
79
88
  "transition": f"transform {DEFAULT_ANIMATION_DURATION}ms linear",
80
89
  },
81
90
  "transform": f"translateX(calc(-100% + ({self.value} / {self.max} * 100%)))", # type: ignore
82
91
  "boxShadow": "inset 0 0 0 1px var(--gray-a5)",
83
- **self.style,
84
92
  }
85
93
  )
86
94
 
@@ -95,6 +95,7 @@ class ProgressComponent(RadixPrimitiveComponentWithClassName):
95
95
  ...
96
96
 
97
97
  class ProgressRoot(ProgressComponent):
98
+ def add_style(self) -> Style | None: ...
98
99
  @overload
99
100
  @classmethod
100
101
  def create( # type: ignore
@@ -180,6 +181,7 @@ class ProgressRoot(ProgressComponent):
180
181
  ...
181
182
 
182
183
  class ProgressIndicator(ProgressComponent):
184
+ def add_style(self) -> Style | None: ...
183
185
  @overload
184
186
  @classmethod
185
187
  def create( # type: ignore
@@ -59,8 +59,13 @@ class SliderRoot(SliderComponent):
59
59
  "on_value_commit": lambda e0: [e0], # trigger when thumb is released
60
60
  }
61
61
 
62
- def _apply_theme(self, theme: Component):
63
- self.style = Style(
62
+ def add_style(self) -> Style | None:
63
+ """Add style to the component.
64
+
65
+ Returns:
66
+ The style of the component.
67
+ """
68
+ return Style(
64
69
  {
65
70
  "position": "relative",
66
71
  "display": "flex",
@@ -74,7 +79,6 @@ class SliderRoot(SliderComponent):
74
79
  "width": "20px",
75
80
  "height": "100px",
76
81
  },
77
- **self.style,
78
82
  }
79
83
  )
80
84
 
@@ -85,18 +89,20 @@ class SliderTrack(SliderComponent):
85
89
  tag = "Track"
86
90
  alias = "RadixSliderTrack"
87
91
 
88
- def _apply_theme(self, theme: Component):
89
- self.style = Style(
92
+ def add_style(self) -> Style | None:
93
+ """Add style to the component.
94
+
95
+ Returns:
96
+ The style of the component.
97
+ """
98
+ return Style(
90
99
  {
91
100
  "position": "relative",
92
101
  "flex_grow": "1",
93
102
  "background_color": "black",
94
103
  "border_radius": "9999px",
95
104
  "height": "3px",
96
- "&[data-orientation='vertical']": {
97
- "width": "3px",
98
- },
99
- **self.style,
105
+ "&[data-orientation='vertical']": {"width": "3px"},
100
106
  }
101
107
  )
102
108
 
@@ -107,16 +113,18 @@ class SliderRange(SliderComponent):
107
113
  tag = "Range"
108
114
  alias = "RadixSliderRange"
109
115
 
110
- def _apply_theme(self, theme: Component):
111
- self.style = Style(
116
+ def add_style(self) -> Style | None:
117
+ """Add style to the component.
118
+
119
+ Returns:
120
+ The style of the component.
121
+ """
122
+ return Style(
112
123
  {
113
124
  "position": "absolute",
114
125
  "background_color": "white",
115
126
  "height": "100%",
116
- "&[data-orientation='vertical']": {
117
- "width": "100%",
118
- },
119
- **self.style,
127
+ "&[data-orientation='vertical']": {"width": "100%"},
120
128
  }
121
129
  )
122
130
 
@@ -127,8 +135,13 @@ class SliderThumb(SliderComponent):
127
135
  tag = "Thumb"
128
136
  alias = "RadixSliderThumb"
129
137
 
130
- def _apply_theme(self, theme: Component):
131
- self.style = Style(
138
+ def add_style(self) -> Style | None:
139
+ """Add style to the component.
140
+
141
+ Returns:
142
+ The style of the component.
143
+ """
144
+ return Style(
132
145
  {
133
146
  "display": "block",
134
147
  "width": "20px",
@@ -143,7 +156,6 @@ class SliderThumb(SliderComponent):
143
156
  "outline": "none",
144
157
  "box_shadow": "0 0 0 4px gray",
145
158
  },
146
- **self.style,
147
159
  }
148
160
  )
149
161
 
@@ -96,6 +96,7 @@ class SliderComponent(RadixPrimitiveComponentWithClassName):
96
96
 
97
97
  class SliderRoot(SliderComponent):
98
98
  def get_event_triggers(self) -> Dict[str, Any]: ...
99
+ def add_style(self) -> Style | None: ...
99
100
  @overload
100
101
  @classmethod
101
102
  def create( # type: ignore
@@ -196,6 +197,7 @@ class SliderRoot(SliderComponent):
196
197
  ...
197
198
 
198
199
  class SliderTrack(SliderComponent):
200
+ def add_style(self) -> Style | None: ...
199
201
  @overload
200
202
  @classmethod
201
203
  def create( # type: ignore
@@ -274,6 +276,7 @@ class SliderTrack(SliderComponent):
274
276
  ...
275
277
 
276
278
  class SliderRange(SliderComponent):
279
+ def add_style(self) -> Style | None: ...
277
280
  @overload
278
281
  @classmethod
279
282
  def create( # type: ignore
@@ -352,6 +355,7 @@ class SliderRange(SliderComponent):
352
355
  ...
353
356
 
354
357
  class SliderThumb(SliderComponent):
358
+ def add_style(self) -> Style | None: ...
355
359
  @overload
356
360
  @classmethod
357
361
  def create( # type: ignore
@@ -73,10 +73,17 @@ class CommonMarginProps(Component):
73
73
  ml: Var[LiteralSpacing]
74
74
 
75
75
 
76
+ class RadixLoadingProp(Component):
77
+ """Base class for components that can be in a loading state."""
78
+
79
+ # If set, show an rx.spinner instead of the component children.
80
+ loading: Var[bool]
81
+
82
+
76
83
  class RadixThemesComponent(Component):
77
84
  """Base class for all @radix-ui/themes components."""
78
85
 
79
- library = "@radix-ui/themes@^2.0.0"
86
+ library = "@radix-ui/themes@^3.0.0"
80
87
 
81
88
  # "Fake" prop color_scheme is used to avoid shadowing CSS prop "color".
82
89
  _rename_props: Dict[str, str] = {"colorScheme": "color"}
@@ -176,6 +176,84 @@ class CommonMarginProps(Component):
176
176
  """
177
177
  ...
178
178
 
179
+ class RadixLoadingProp(Component):
180
+ @overload
181
+ @classmethod
182
+ def create( # type: ignore
183
+ cls,
184
+ *children,
185
+ loading: Optional[Union[Var[bool], bool]] = None,
186
+ style: Optional[Style] = None,
187
+ key: Optional[Any] = None,
188
+ id: Optional[Any] = None,
189
+ class_name: Optional[Any] = None,
190
+ autofocus: Optional[bool] = None,
191
+ custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
192
+ on_blur: Optional[
193
+ Union[EventHandler, EventSpec, list, function, BaseVar]
194
+ ] = None,
195
+ on_click: Optional[
196
+ Union[EventHandler, EventSpec, list, function, BaseVar]
197
+ ] = None,
198
+ on_context_menu: Optional[
199
+ Union[EventHandler, EventSpec, list, function, BaseVar]
200
+ ] = None,
201
+ on_double_click: Optional[
202
+ Union[EventHandler, EventSpec, list, function, BaseVar]
203
+ ] = None,
204
+ on_focus: Optional[
205
+ Union[EventHandler, EventSpec, list, function, BaseVar]
206
+ ] = None,
207
+ on_mount: Optional[
208
+ Union[EventHandler, EventSpec, list, function, BaseVar]
209
+ ] = None,
210
+ on_mouse_down: Optional[
211
+ Union[EventHandler, EventSpec, list, function, BaseVar]
212
+ ] = None,
213
+ on_mouse_enter: Optional[
214
+ Union[EventHandler, EventSpec, list, function, BaseVar]
215
+ ] = None,
216
+ on_mouse_leave: Optional[
217
+ Union[EventHandler, EventSpec, list, function, BaseVar]
218
+ ] = None,
219
+ on_mouse_move: Optional[
220
+ Union[EventHandler, EventSpec, list, function, BaseVar]
221
+ ] = None,
222
+ on_mouse_out: Optional[
223
+ Union[EventHandler, EventSpec, list, function, BaseVar]
224
+ ] = None,
225
+ on_mouse_over: Optional[
226
+ Union[EventHandler, EventSpec, list, function, BaseVar]
227
+ ] = None,
228
+ on_mouse_up: Optional[
229
+ Union[EventHandler, EventSpec, list, function, BaseVar]
230
+ ] = None,
231
+ on_scroll: Optional[
232
+ Union[EventHandler, EventSpec, list, function, BaseVar]
233
+ ] = None,
234
+ on_unmount: Optional[
235
+ Union[EventHandler, EventSpec, list, function, BaseVar]
236
+ ] = None,
237
+ **props
238
+ ) -> "RadixLoadingProp":
239
+ """Create the component.
240
+
241
+ Args:
242
+ *children: The children of the component.
243
+ loading: If set, show an rx.spinner instead of the component children.
244
+ style: The style of the component.
245
+ key: A unique key for the component.
246
+ id: The id for the component.
247
+ class_name: The class name for the component.
248
+ autofocus: Whether the component should take the focus once the page is loaded
249
+ custom_attrs: custom attribute
250
+ **props: The props of the component.
251
+
252
+ Returns:
253
+ The component.
254
+ """
255
+ ...
256
+
179
257
  class RadixThemesComponent(Component):
180
258
  @overload
181
259
  @classmethod
@@ -331,7 +409,7 @@ class Theme(RadixThemesComponent):
331
409
  def create( # type: ignore
332
410
  cls,
333
411
  *children,
334
- color_mode: Optional[LiteralAppearance | None] = None,
412
+ color_mode: Optional[Literal["inherit", "light", "dark"]] = None,
335
413
  theme_panel: Optional[bool] = False,
336
414
  has_background: Optional[Union[Var[bool], bool]] = None,
337
415
  appearance: Optional[
@@ -14,18 +14,21 @@ rx.text(
14
14
  )
15
15
  ```
16
16
  """
17
+
17
18
  from __future__ import annotations
18
19
 
19
20
  import dataclasses
21
+ from typing import Literal, get_args
20
22
 
21
23
  from reflex.components.component import BaseComponent
22
- from reflex.components.core.cond import Cond, color_mode_cond
24
+ from reflex.components.core.cond import Cond, color_mode_cond, cond
23
25
  from reflex.components.lucide.icon import Icon
26
+ from reflex.components.radix.themes.components.switch import Switch
24
27
  from reflex.style import LIGHT_COLOR_MODE, color_mode, toggle_color_mode
25
- from reflex.vars import BaseVar
28
+ from reflex.utils import console
29
+ from reflex.vars import BaseVar, Var
26
30
 
27
- from .components.button import Button
28
- from .components.switch import Switch
31
+ from .components.icon_button import IconButton
29
32
 
30
33
  DEFAULT_LIGHT_ICON: Icon = Icon.create(tag="sun")
31
34
  DEFAULT_DARK_ICON: Icon = Icon.create(tag="moon")
@@ -55,45 +58,110 @@ class ColorModeIcon(Cond):
55
58
  )
56
59
 
57
60
 
58
- class ColorModeSwitch(Switch):
59
- """Switch for toggling light / dark mode via toggle_color_mode."""
61
+ LiteralPosition = Literal["top-left", "top-right", "bottom-left", "bottom-right"]
62
+
63
+ position_values = get_args(LiteralPosition)
64
+
65
+ position_map = {
66
+ "position": position_values,
67
+ "left": ["top-left", "bottom-left"],
68
+ "right": ["top-right", "bottom-right"],
69
+ "top": ["top-left", "top-right"],
70
+ "bottom": ["bottom-left", "bottom-right"],
71
+ }
72
+
73
+
74
+ # needed to inverse contains for find
75
+ def _find(const, var):
76
+ return Var.create_safe(const).contains(var)
77
+
78
+
79
+ def _set_var_default(props, position, prop, default1, default2=""):
80
+ props.setdefault(
81
+ prop, cond(_find(position_map[prop], position), default1, default2)
82
+ )
83
+
84
+
85
+ def _set_static_default(props, position, prop, default):
86
+ if prop in position:
87
+ props.setdefault(prop, default)
88
+
89
+
90
+ class ColorModeIconButton(IconButton):
91
+ """Icon Button for toggling light / dark mode via toggle_color_mode."""
60
92
 
61
93
  @classmethod
62
- def create(cls, *children, **props):
63
- """Create a switch component bound to color_mode.
94
+ def create(
95
+ cls,
96
+ *children,
97
+ position: LiteralPosition | None = None,
98
+ **props,
99
+ ):
100
+ """Create a icon button component that calls toggle_color_mode on click.
64
101
 
65
102
  Args:
66
103
  *children: The children of the component.
104
+ position: The position of the icon button. Follow document flow if None.
67
105
  **props: The props to pass to the component.
68
106
 
69
107
  Returns:
70
- The switch component.
108
+ The button component.
71
109
  """
72
- return Switch.create(
73
- *children,
74
- checked=color_mode != LIGHT_COLOR_MODE,
75
- on_change=toggle_color_mode,
110
+ if children:
111
+ console.deprecate(
112
+ feature_name="passing children to color_mode.button",
113
+ reason=", use color_mode_cond and toggle_color_mode instead to build a custom color_mode component",
114
+ deprecation_version="0.5.0",
115
+ removal_version="0.6.0",
116
+ )
117
+
118
+ # position is used to set nice defaults for positioning the icon button
119
+ if isinstance(position, Var):
120
+ _set_var_default(props, position, "position", "fixed", position)
121
+ _set_var_default(props, position, "bottom", "2rem")
122
+ _set_var_default(props, position, "top", "2rem")
123
+ _set_var_default(props, position, "left", "2rem")
124
+ _set_var_default(props, position, "right", "2rem")
125
+ elif position is not None:
126
+ if position in position_values:
127
+ props.setdefault("position", "fixed")
128
+ _set_static_default(props, position, "bottom", "2rem")
129
+ _set_static_default(props, position, "top", "2rem")
130
+ _set_static_default(props, position, "left", "2rem")
131
+ _set_static_default(props, position, "right", "2rem")
132
+ else:
133
+ props["position"] = position
134
+
135
+ props.setdefault("background", "transparent")
136
+ props.setdefault("color", "inherit")
137
+ props.setdefault("z_index", "20")
138
+ props.setdefault(":hover", {"cursor": "pointer"})
139
+
140
+ return super().create(
141
+ ColorModeIcon.create(),
142
+ on_click=toggle_color_mode,
76
143
  **props,
77
144
  )
78
145
 
79
146
 
80
- class ColorModeButton(Button):
81
- """Button for toggling chakra light / dark mode via toggle_color_mode."""
147
+ class ColorModeSwitch(Switch):
148
+ """Switch for toggling light / dark mode via toggle_color_mode."""
82
149
 
83
150
  @classmethod
84
151
  def create(cls, *children, **props):
85
- """Create a button component that calls toggle_color_mode on click.
152
+ """Create a switch component bound to color_mode.
86
153
 
87
154
  Args:
88
155
  *children: The children of the component.
89
156
  **props: The props to pass to the component.
90
157
 
91
158
  Returns:
92
- The button component.
159
+ The switch component.
93
160
  """
94
- return Button.create(
161
+ return Switch.create(
95
162
  *children,
96
- on_click=toggle_color_mode,
163
+ checked=color_mode != LIGHT_COLOR_MODE,
164
+ on_change=toggle_color_mode,
97
165
  **props,
98
166
  )
99
167
 
@@ -102,8 +170,8 @@ class ColorModeNamespace(BaseVar):
102
170
  """Namespace for color mode components."""
103
171
 
104
172
  icon = staticmethod(ColorModeIcon.create)
173
+ button = staticmethod(ColorModeIconButton.create)
105
174
  switch = staticmethod(ColorModeSwitch.create)
106
- button = staticmethod(ColorModeButton.create)
107
175
 
108
176
 
109
177
  color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode))