reflex 0.8.0a6__py3-none-any.whl → 0.8.1__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 (38) hide show
  1. reflex/.templates/web/utils/state.js +18 -1
  2. reflex/.templates/web/vite-plugin-safari-cachebust.js +160 -0
  3. reflex/.templates/web/vite.config.js +28 -6
  4. reflex/app.py +1 -1
  5. reflex/components/__init__.py +1 -0
  6. reflex/components/__init__.pyi +2 -0
  7. reflex/components/component.py +53 -1
  8. reflex/components/core/banner.py +3 -13
  9. reflex/components/core/upload.py +5 -5
  10. reflex/components/core/upload.pyi +2 -2
  11. reflex/components/el/__init__.py +7 -1
  12. reflex/components/el/__init__.pyi +2 -1
  13. reflex/components/radix/primitives/accordion.py +10 -29
  14. reflex/components/radix/primitives/accordion.pyi +7 -1
  15. reflex/components/radix/themes/typography/link.py +1 -30
  16. reflex/components/radix/themes/typography/link.pyi +1 -304
  17. reflex/components/react_router/__init__.py +5 -0
  18. reflex/components/react_router/dom.py +69 -0
  19. reflex/components/react_router/dom.pyi +321 -0
  20. reflex/components/recharts/recharts.py +2 -2
  21. reflex/config.py +7 -36
  22. reflex/constants/compiler.py +1 -1
  23. reflex/constants/installer.py +2 -2
  24. reflex/environment.py +116 -0
  25. reflex/event.py +18 -1
  26. reflex/istate/data.py +142 -69
  27. reflex/plugins/tailwind_v4.py +2 -2
  28. reflex/state.py +3 -3
  29. reflex/utils/exec.py +35 -8
  30. reflex/utils/lazy_loader.py +7 -1
  31. reflex/utils/misc.py +1 -2
  32. reflex/utils/processes.py +27 -3
  33. reflex/utils/pyi_generator.py +17 -2
  34. {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/METADATA +3 -3
  35. {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/RECORD +38 -34
  36. {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/WHEEL +0 -0
  37. {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/entry_points.txt +0 -0
  38. {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,321 @@
1
+ """Stub file for reflex/components/react_router/dom.py"""
2
+
3
+ # ------------------- DO NOT EDIT ----------------------
4
+ # This file was generated by `reflex/utils/pyi_generator.py`!
5
+ # ------------------------------------------------------
6
+ from collections.abc import Mapping, Sequence
7
+ from typing import Any, Literal, TypedDict
8
+
9
+ from reflex.components.core.breakpoints import Breakpoints
10
+ from reflex.components.el.elements.inline import A
11
+ from reflex.event import EventType, PointerEventInfo
12
+ from reflex.vars.base import Var
13
+
14
+ LiteralLinkDiscover = Literal["none", "render"]
15
+
16
+ class To(TypedDict):
17
+ pathname: str
18
+ search: str
19
+ hash: str
20
+
21
+ class ReactRouterLink(A):
22
+ @classmethod
23
+ def create(
24
+ cls,
25
+ *children,
26
+ to: To | Var[To | str] | str | None = None,
27
+ replace: Var[bool] | bool | None = None,
28
+ reload_document: Var[bool] | bool | None = None,
29
+ prevent_scroll_reset: Var[bool] | bool | None = None,
30
+ discover: Literal["none", "render"]
31
+ | Var[Literal["none", "render"]]
32
+ | None = None,
33
+ view_transition: Var[bool] | bool | None = None,
34
+ download: Var[bool | str] | bool | str | None = None,
35
+ href: Var[str] | str | None = None,
36
+ href_lang: Var[str] | str | None = None,
37
+ media: Var[str] | str | None = None,
38
+ ping: Var[str] | str | None = None,
39
+ referrer_policy: Literal[
40
+ "",
41
+ "no-referrer",
42
+ "no-referrer-when-downgrade",
43
+ "origin",
44
+ "origin-when-cross-origin",
45
+ "same-origin",
46
+ "strict-origin",
47
+ "strict-origin-when-cross-origin",
48
+ "unsafe-url",
49
+ ]
50
+ | Var[
51
+ Literal[
52
+ "",
53
+ "no-referrer",
54
+ "no-referrer-when-downgrade",
55
+ "origin",
56
+ "origin-when-cross-origin",
57
+ "same-origin",
58
+ "strict-origin",
59
+ "strict-origin-when-cross-origin",
60
+ "unsafe-url",
61
+ ]
62
+ ]
63
+ | None = None,
64
+ rel: Var[str] | str | None = None,
65
+ target: Literal["_blank", "_parent", "_self", "_top"]
66
+ | Var[Literal["_blank", "_parent", "_self", "_top"] | str]
67
+ | str
68
+ | None = None,
69
+ access_key: Var[str] | str | None = None,
70
+ auto_capitalize: Literal[
71
+ "characters", "none", "off", "on", "sentences", "words"
72
+ ]
73
+ | Var[Literal["characters", "none", "off", "on", "sentences", "words"]]
74
+ | None = None,
75
+ content_editable: Literal["inherit", "plaintext-only", False, True]
76
+ | Var[Literal["inherit", "plaintext-only", False, True]]
77
+ | None = None,
78
+ context_menu: Var[str] | str | None = None,
79
+ dir: Var[str] | str | None = None,
80
+ draggable: Var[bool] | bool | None = None,
81
+ enter_key_hint: Literal[
82
+ "done", "enter", "go", "next", "previous", "search", "send"
83
+ ]
84
+ | Var[Literal["done", "enter", "go", "next", "previous", "search", "send"]]
85
+ | None = None,
86
+ hidden: Var[bool] | bool | None = None,
87
+ input_mode: Literal[
88
+ "decimal", "email", "none", "numeric", "search", "tel", "text", "url"
89
+ ]
90
+ | Var[
91
+ Literal[
92
+ "decimal", "email", "none", "numeric", "search", "tel", "text", "url"
93
+ ]
94
+ ]
95
+ | None = None,
96
+ item_prop: Var[str] | str | None = None,
97
+ lang: Var[str] | str | None = None,
98
+ role: Literal[
99
+ "alert",
100
+ "alertdialog",
101
+ "application",
102
+ "article",
103
+ "banner",
104
+ "button",
105
+ "cell",
106
+ "checkbox",
107
+ "columnheader",
108
+ "combobox",
109
+ "complementary",
110
+ "contentinfo",
111
+ "definition",
112
+ "dialog",
113
+ "directory",
114
+ "document",
115
+ "feed",
116
+ "figure",
117
+ "form",
118
+ "grid",
119
+ "gridcell",
120
+ "group",
121
+ "heading",
122
+ "img",
123
+ "link",
124
+ "list",
125
+ "listbox",
126
+ "listitem",
127
+ "log",
128
+ "main",
129
+ "marquee",
130
+ "math",
131
+ "menu",
132
+ "menubar",
133
+ "menuitem",
134
+ "menuitemcheckbox",
135
+ "menuitemradio",
136
+ "navigation",
137
+ "none",
138
+ "note",
139
+ "option",
140
+ "presentation",
141
+ "progressbar",
142
+ "radio",
143
+ "radiogroup",
144
+ "region",
145
+ "row",
146
+ "rowgroup",
147
+ "rowheader",
148
+ "scrollbar",
149
+ "search",
150
+ "searchbox",
151
+ "separator",
152
+ "slider",
153
+ "spinbutton",
154
+ "status",
155
+ "switch",
156
+ "tab",
157
+ "table",
158
+ "tablist",
159
+ "tabpanel",
160
+ "term",
161
+ "textbox",
162
+ "timer",
163
+ "toolbar",
164
+ "tooltip",
165
+ "tree",
166
+ "treegrid",
167
+ "treeitem",
168
+ ]
169
+ | Var[
170
+ Literal[
171
+ "alert",
172
+ "alertdialog",
173
+ "application",
174
+ "article",
175
+ "banner",
176
+ "button",
177
+ "cell",
178
+ "checkbox",
179
+ "columnheader",
180
+ "combobox",
181
+ "complementary",
182
+ "contentinfo",
183
+ "definition",
184
+ "dialog",
185
+ "directory",
186
+ "document",
187
+ "feed",
188
+ "figure",
189
+ "form",
190
+ "grid",
191
+ "gridcell",
192
+ "group",
193
+ "heading",
194
+ "img",
195
+ "link",
196
+ "list",
197
+ "listbox",
198
+ "listitem",
199
+ "log",
200
+ "main",
201
+ "marquee",
202
+ "math",
203
+ "menu",
204
+ "menubar",
205
+ "menuitem",
206
+ "menuitemcheckbox",
207
+ "menuitemradio",
208
+ "navigation",
209
+ "none",
210
+ "note",
211
+ "option",
212
+ "presentation",
213
+ "progressbar",
214
+ "radio",
215
+ "radiogroup",
216
+ "region",
217
+ "row",
218
+ "rowgroup",
219
+ "rowheader",
220
+ "scrollbar",
221
+ "search",
222
+ "searchbox",
223
+ "separator",
224
+ "slider",
225
+ "spinbutton",
226
+ "status",
227
+ "switch",
228
+ "tab",
229
+ "table",
230
+ "tablist",
231
+ "tabpanel",
232
+ "term",
233
+ "textbox",
234
+ "timer",
235
+ "toolbar",
236
+ "tooltip",
237
+ "tree",
238
+ "treegrid",
239
+ "treeitem",
240
+ ]
241
+ ]
242
+ | None = None,
243
+ slot: Var[str] | str | None = None,
244
+ spell_check: Var[bool] | bool | None = None,
245
+ tab_index: Var[int] | int | None = None,
246
+ title: Var[str] | str | None = None,
247
+ style: Sequence[Mapping[str, Any]]
248
+ | Mapping[str, Any]
249
+ | Var[Mapping[str, Any]]
250
+ | Breakpoints
251
+ | None = None,
252
+ key: Any | None = None,
253
+ id: Any | None = None,
254
+ ref: Var | None = None,
255
+ class_name: Any | None = None,
256
+ autofocus: bool | None = None,
257
+ custom_attrs: dict[str, Var | Any] | None = None,
258
+ on_blur: EventType[()] | None = None,
259
+ on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
260
+ on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
261
+ on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
262
+ on_focus: EventType[()] | None = None,
263
+ on_mount: EventType[()] | None = None,
264
+ on_mouse_down: EventType[()] | None = None,
265
+ on_mouse_enter: EventType[()] | None = None,
266
+ on_mouse_leave: EventType[()] | None = None,
267
+ on_mouse_move: EventType[()] | None = None,
268
+ on_mouse_out: EventType[()] | None = None,
269
+ on_mouse_over: EventType[()] | None = None,
270
+ on_mouse_up: EventType[()] | None = None,
271
+ on_scroll: EventType[()] | None = None,
272
+ on_scroll_end: EventType[()] | None = None,
273
+ on_unmount: EventType[()] | None = None,
274
+ **props,
275
+ ) -> ReactRouterLink:
276
+ """Create a ReactRouterLink component for client-side navigation.
277
+
278
+ Args:
279
+ *children: The children of the component.
280
+ to: The page to link to.
281
+ replace: Replaces the current entry in the history stack instead of pushing a new one onto it.
282
+ reload_document: Will use document navigation instead of client side routing when the link is clicked: the browser will handle the transition normally (as if it were an <a href>).
283
+ prevent_scroll_reset: Prevents the scroll position from being reset to the top of the window when the link is clicked and the app is using ScrollRestoration. This only prevents new locations resetting scroll to the top, scroll position will be restored for back/forward button navigation.
284
+ discover: Defines the link discovery behavior
285
+ view_transition: Enables a View Transition for this navigation.
286
+ download: Specifies that the target (the file specified in the href attribute) will be downloaded when a user clicks on the hyperlink.
287
+ href: Specifies the URL of the page the link goes to
288
+ href_lang: Specifies the language of the linked document
289
+ media: Specifies what media/device the linked document is optimized for
290
+ ping: Specifies which referrer is sent when fetching the resource
291
+ referrer_policy: Specifies the relationship between the current document and the linked document
292
+ rel: Specifies the relationship between the linked document and the current document
293
+ target: Specifies where to open the linked document
294
+ access_key: Provides a hint for generating a keyboard shortcut for the current element.
295
+ auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
296
+ content_editable: Indicates whether the element's content is editable.
297
+ context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
298
+ dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
299
+ draggable: Defines whether the element can be dragged.
300
+ enter_key_hint: Hints what media types the media element is able to play.
301
+ hidden: Defines whether the element is hidden.
302
+ input_mode: Defines the type of the element.
303
+ item_prop: Defines the name of the element for metadata purposes.
304
+ lang: Defines the language used in the element.
305
+ role: Defines the role of the element.
306
+ slot: Assigns a slot in a shadow DOM shadow tree to an element.
307
+ spell_check: Defines whether the element may be checked for spelling errors.
308
+ tab_index: Defines the position of the current element in the tabbing order.
309
+ title: Defines a tooltip for the element.
310
+ style: The style of the component.
311
+ key: A unique key for the component.
312
+ id: The id for the component.
313
+ ref: The Var to pass as the ref to the component.
314
+ class_name: The class name for the component.
315
+ autofocus: Whether the component should take the focus once the page is loaded
316
+ custom_attrs: custom attribute
317
+ **props: The props of the component.
318
+
319
+ Returns:
320
+ The ReactRouterLink component.
321
+ """
@@ -8,7 +8,7 @@ from reflex.components.component import Component, MemoizationLeaf, NoSSRCompone
8
8
  class Recharts(Component):
9
9
  """A component that wraps a recharts lib."""
10
10
 
11
- library = "recharts@3.0.0"
11
+ library = "recharts@3.0.2"
12
12
 
13
13
  def _get_style(self) -> dict:
14
14
  return {"wrapperStyle": self.style}
@@ -17,7 +17,7 @@ class Recharts(Component):
17
17
  class RechartsCharts(NoSSRComponent, MemoizationLeaf):
18
18
  """A component that wraps a recharts lib."""
19
19
 
20
- library = "recharts@3.0.0"
20
+ library = "recharts@3.0.2"
21
21
 
22
22
 
23
23
  LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"]
reflex/config.py CHANGED
@@ -19,7 +19,12 @@ from reflex.base import Base
19
19
  from reflex.constants.base import LogLevel
20
20
  from reflex.environment import EnvironmentVariables as EnvironmentVariables
21
21
  from reflex.environment import EnvVar as EnvVar
22
- from reflex.environment import ExistingPath, interpret_env_var_value
22
+ from reflex.environment import (
23
+ ExistingPath,
24
+ _load_dotenv_from_files,
25
+ _paths_from_env_files,
26
+ interpret_env_var_value,
27
+ )
23
28
  from reflex.environment import env_var as env_var
24
29
  from reflex.environment import environment as environment
25
30
  from reflex.plugins import Plugin
@@ -27,40 +32,6 @@ from reflex.utils import console
27
32
  from reflex.utils.exceptions import ConfigError
28
33
  from reflex.utils.types import true_type_for_pydantic_field
29
34
 
30
- try:
31
- from dotenv import load_dotenv
32
- except ImportError:
33
- load_dotenv = None
34
-
35
-
36
- def _load_dotenv_from_str(env_files: str) -> None:
37
- if not env_files:
38
- return
39
-
40
- if load_dotenv is None:
41
- console.error(
42
- """The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.1.0"`."""
43
- )
44
- return
45
-
46
- # load env files in reverse order if they exist
47
- for env_file_path in [
48
- Path(p) for s in reversed(env_files.split(os.pathsep)) if (p := s.strip())
49
- ]:
50
- if env_file_path.exists():
51
- load_dotenv(env_file_path, override=True)
52
-
53
-
54
- def _load_dotenv_from_env():
55
- """Load environment variables from paths specified in REFLEX_ENV_FILE."""
56
- env_env_file = os.environ.get("REFLEX_ENV_FILE")
57
- if env_env_file:
58
- _load_dotenv_from_str(env_env_file)
59
-
60
-
61
- # Load the env files at import time if they are set in the ENV_FILE environment variable.
62
- _load_dotenv_from_env()
63
-
64
35
 
65
36
  class DBConfig(Base):
66
37
  """Database config."""
@@ -358,7 +329,7 @@ class Config(Base):
358
329
  The updated config values.
359
330
  """
360
331
  if self.env_file:
361
- _load_dotenv_from_str(self.env_file)
332
+ _load_dotenv_from_files(_paths_from_env_files(self.env_file))
362
333
 
363
334
  updated_values = {}
364
335
  # Iterate over the fields.
@@ -85,7 +85,7 @@ class PageNames(SimpleNamespace):
85
85
  # The name of the index page.
86
86
  INDEX_ROUTE = "index"
87
87
  # The name of the app root page.
88
- APP_ROOT = "root.js"
88
+ APP_ROOT = "root.jsx"
89
89
  # The root stylesheet filename.
90
90
  STYLESHEET_ROOT = "__reflex_global_styles"
91
91
  # The name of the document root page.
@@ -75,7 +75,7 @@ fetch-retries=0
75
75
 
76
76
 
77
77
  def _determine_react_router_version() -> str:
78
- default_version = "7.6.2"
78
+ default_version = "7.6.3"
79
79
  if (version := os.getenv("REACT_ROUTER_VERSION")) and version != default_version:
80
80
  from reflex.utils import console
81
81
 
@@ -143,7 +143,7 @@ class PackageJson(SimpleNamespace):
143
143
  "postcss-import": "16.1.1",
144
144
  "@react-router/dev": _react_router_version,
145
145
  "@react-router/fs-routes": _react_router_version,
146
- "rolldown-vite": "7.0.1",
146
+ "rolldown-vite": "7.0.5",
147
147
  }
148
148
  OVERRIDES = {
149
149
  # This should always match the `react` version in DEPENDENCIES for recharts compatibility.
reflex/environment.py CHANGED
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import concurrent.futures
6
6
  import dataclasses
7
7
  import enum
8
+ import importlib
8
9
  import inspect
9
10
  import multiprocessing
10
11
  import os
@@ -24,6 +25,7 @@ from typing import (
24
25
  )
25
26
 
26
27
  from reflex import constants
28
+ from reflex.plugins import Plugin
27
29
  from reflex.utils.exceptions import EnvironmentVarValueError
28
30
  from reflex.utils.types import GenericType, is_union, value_inside_optional
29
31
 
@@ -126,6 +128,48 @@ def interpret_path_env(value: str, field_name: str) -> Path:
126
128
  return Path(value)
127
129
 
128
130
 
131
+ def interpret_plugin_env(value: str, field_name: str) -> Plugin:
132
+ """Interpret a plugin environment variable value.
133
+
134
+ Args:
135
+ value: The environment variable value.
136
+ field_name: The field name.
137
+
138
+ Returns:
139
+ The interpreted value.
140
+
141
+ Raises:
142
+ EnvironmentVarValueError: If the value is invalid.
143
+ """
144
+ if "." not in value:
145
+ msg = f"Invalid plugin value: {value!r} for {field_name}. Plugin name must be in the format 'package.module.PluginName'."
146
+ raise EnvironmentVarValueError(msg)
147
+
148
+ import_path, plugin_name = value.rsplit(".", 1)
149
+
150
+ try:
151
+ module = importlib.import_module(import_path)
152
+ except ImportError as e:
153
+ msg = f"Failed to import module {import_path!r} for {field_name}: {e}"
154
+ raise EnvironmentVarValueError(msg) from e
155
+
156
+ try:
157
+ plugin_class = getattr(module, plugin_name, None)
158
+ except Exception as e:
159
+ msg = f"Failed to get plugin class {plugin_name!r} from module {import_path!r} for {field_name}: {e}"
160
+ raise EnvironmentVarValueError(msg) from e
161
+
162
+ if not inspect.isclass(plugin_class) or not issubclass(plugin_class, Plugin):
163
+ msg = f"Invalid plugin class: {plugin_name!r} for {field_name}. Must be a subclass of Plugin."
164
+ raise EnvironmentVarValueError(msg)
165
+
166
+ try:
167
+ return plugin_class()
168
+ except Exception as e:
169
+ msg = f"Failed to instantiate plugin {plugin_name!r} for {field_name}: {e}"
170
+ raise EnvironmentVarValueError(msg) from e
171
+
172
+
129
173
  def interpret_enum_env(value: str, field_type: GenericType, field_name: str) -> Any:
130
174
  """Interpret an enum environment variable value.
131
175
 
@@ -181,6 +225,8 @@ def interpret_env_var_value(
181
225
  return interpret_path_env(value, field_name)
182
226
  if field_type is ExistingPath:
183
227
  return interpret_existing_path_env(value, field_name)
228
+ if field_type is Plugin:
229
+ return interpret_plugin_env(value, field_name)
184
230
  if get_origin(field_type) is list:
185
231
  return [
186
232
  interpret_env_var_value(
@@ -606,3 +652,73 @@ class EnvironmentVariables:
606
652
 
607
653
 
608
654
  environment = EnvironmentVariables()
655
+
656
+ try:
657
+ from dotenv import load_dotenv
658
+ except ImportError:
659
+ load_dotenv = None
660
+
661
+
662
+ def _paths_from_env_files(env_files: str) -> list[Path]:
663
+ """Convert a string of paths separated by os.pathsep into a list of Path objects.
664
+
665
+ Args:
666
+ env_files: The string of paths.
667
+
668
+ Returns:
669
+ A list of Path objects.
670
+ """
671
+ # load env files in reverse order
672
+ return list(
673
+ reversed(
674
+ [
675
+ Path(path)
676
+ for path_element in env_files.split(os.pathsep)
677
+ if (path := path_element.strip())
678
+ ]
679
+ )
680
+ )
681
+
682
+
683
+ def _load_dotenv_from_files(files: list[Path]):
684
+ """Load environment variables from a list of files.
685
+
686
+ Args:
687
+ files: A list of Path objects representing the environment variable files.
688
+ """
689
+ from reflex.utils import console
690
+
691
+ if not files:
692
+ return
693
+
694
+ if load_dotenv is None:
695
+ console.error(
696
+ """The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.1.0"`."""
697
+ )
698
+ return
699
+
700
+ for env_file in files:
701
+ if env_file.exists():
702
+ load_dotenv(env_file, override=True)
703
+
704
+
705
+ def _paths_from_environment() -> list[Path]:
706
+ """Get the paths from the REFLEX_ENV_FILE environment variable.
707
+
708
+ Returns:
709
+ A list of Path objects.
710
+ """
711
+ env_files = os.environ.get("REFLEX_ENV_FILE")
712
+ if not env_files:
713
+ return []
714
+
715
+ return _paths_from_env_files(env_files)
716
+
717
+
718
+ def _load_dotenv_from_env():
719
+ """Load environment variables from paths specified in REFLEX_ENV_FILE."""
720
+ _load_dotenv_from_files(_paths_from_environment())
721
+
722
+
723
+ # Load the env files at import time if they are set in the ENV_FILE environment variable.
724
+ _load_dotenv_from_env()
reflex/event.py CHANGED
@@ -570,7 +570,7 @@ class JavascriptHTMLInputElement:
570
570
  class JavascriptInputEvent:
571
571
  """Interface for a Javascript InputEvent https://developer.mozilla.org/en-US/docs/Web/API/InputEvent."""
572
572
 
573
- target: JavascriptHTMLInputElement = JavascriptHTMLInputElement() # noqa: RUF009
573
+ target: JavascriptHTMLInputElement = JavascriptHTMLInputElement()
574
574
 
575
575
 
576
576
  @dataclasses.dataclass(
@@ -1025,6 +1025,22 @@ def set_focus(ref: str) -> EventSpec:
1025
1025
  )
1026
1026
 
1027
1027
 
1028
+ def blur_focus(ref: str) -> EventSpec:
1029
+ """Blur focus of specified ref.
1030
+
1031
+ Args:
1032
+ ref: The ref.
1033
+
1034
+ Returns:
1035
+ An event to blur focus on the ref
1036
+ """
1037
+ return server_side(
1038
+ "_blur_focus",
1039
+ get_fn_signature(blur_focus),
1040
+ ref=LiteralVar.create(format.format_ref(ref)),
1041
+ )
1042
+
1043
+
1028
1044
  def scroll_to(elem_id: str, align_to_top: bool | Var[bool] = True) -> EventSpec:
1029
1045
  """Select the id of a html element for scrolling into view.
1030
1046
 
@@ -2293,6 +2309,7 @@ class EventNamespace:
2293
2309
  back = staticmethod(back)
2294
2310
  window_alert = staticmethod(window_alert)
2295
2311
  set_focus = staticmethod(set_focus)
2312
+ blur_focus = staticmethod(blur_focus)
2296
2313
  scroll_to = staticmethod(scroll_to)
2297
2314
  set_value = staticmethod(set_value)
2298
2315
  remove_cookie = staticmethod(remove_cookie)