reflex 0.8.9a2__py3-none-any.whl → 0.8.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of reflex might be problematic. Click here for more details.

@@ -1,5 +1,5 @@
1
1
  import { useTheme } from "$/utils/react-theme";
2
- import { createElement } from "react";
2
+ import { createElement, useEffect } from "react";
3
3
  import { ColorModeContext, defaultColorMode } from "$/utils/context";
4
4
 
5
5
  export default function RadixThemesColorModeProvider({ children }) {
@@ -20,6 +20,16 @@ export default function RadixThemesColorModeProvider({ children }) {
20
20
  setTheme(mode);
21
21
  };
22
22
 
23
+ useEffect(() => {
24
+ const radixRoot = document.querySelector(
25
+ '.radix-themes[data-is-root-theme="true"]',
26
+ );
27
+ if (radixRoot) {
28
+ radixRoot.classList.remove("light", "dark");
29
+ radixRoot.classList.add(resolvedTheme);
30
+ }
31
+ }, [resolvedTheme]);
32
+
23
33
  return createElement(
24
34
  ColorModeContext.Provider,
25
35
  {
@@ -0,0 +1,170 @@
1
+ import JSON5 from "json5";
2
+ import env from "$/env.json";
3
+
4
+ /**
5
+ * Upload files to the server.
6
+ *
7
+ * @param state The state to apply the delta to.
8
+ * @param handler The handler to use.
9
+ * @param upload_id The upload id to use.
10
+ * @param on_upload_progress The function to call on upload progress.
11
+ * @param socket the websocket connection
12
+ * @param extra_headers Extra headers to send with the request.
13
+ * @param refs The refs object to store the abort controller in.
14
+ * @param getBackendURL Function to get the backend URL.
15
+ * @param getToken Function to get the Reflex token.
16
+ *
17
+ * @returns The response from posting to the UPLOADURL endpoint.
18
+ */
19
+ export const uploadFiles = async (
20
+ handler,
21
+ files,
22
+ upload_id,
23
+ on_upload_progress,
24
+ extra_headers,
25
+ socket,
26
+ refs,
27
+ getBackendURL,
28
+ getToken,
29
+ ) => {
30
+ // return if there's no file to upload
31
+ if (files === undefined || files.length === 0) {
32
+ return false;
33
+ }
34
+
35
+ const upload_ref_name = `__upload_controllers_${upload_id}`;
36
+
37
+ if (refs[upload_ref_name]) {
38
+ console.log("Upload already in progress for ", upload_id);
39
+ return false;
40
+ }
41
+
42
+ // Track how many partial updates have been processed for this upload.
43
+ let resp_idx = 0;
44
+ const eventHandler = (progressEvent) => {
45
+ const event_callbacks = socket._callbacks.$event;
46
+ // Whenever called, responseText will contain the entire response so far.
47
+ const chunks = progressEvent.event.target.responseText.trim().split("\n");
48
+ // So only process _new_ chunks beyond resp_idx.
49
+ chunks.slice(resp_idx).map((chunk_json) => {
50
+ try {
51
+ const chunk = JSON5.parse(chunk_json);
52
+ event_callbacks.map((f, ix) => {
53
+ f(chunk)
54
+ .then(() => {
55
+ if (ix === event_callbacks.length - 1) {
56
+ // Mark this chunk as processed.
57
+ resp_idx += 1;
58
+ }
59
+ })
60
+ .catch((e) => {
61
+ if (progressEvent.progress === 1) {
62
+ // Chunk may be incomplete, so only report errors when full response is available.
63
+ console.log("Error processing chunk", chunk, e);
64
+ }
65
+ return;
66
+ });
67
+ });
68
+ } catch (e) {
69
+ if (progressEvent.progress === 1) {
70
+ console.log("Error parsing chunk", chunk_json, e);
71
+ }
72
+ return;
73
+ }
74
+ });
75
+ };
76
+
77
+ const controller = new AbortController();
78
+ const formdata = new FormData();
79
+
80
+ // Add the token and handler to the file name.
81
+ files.forEach((file) => {
82
+ formdata.append("files", file, file.path || file.name);
83
+ });
84
+
85
+ // Send the file to the server.
86
+ refs[upload_ref_name] = controller;
87
+
88
+ return new Promise((resolve, reject) => {
89
+ const xhr = new XMLHttpRequest();
90
+
91
+ // Set up event handlers
92
+ xhr.onload = function () {
93
+ if (xhr.status >= 200 && xhr.status < 300) {
94
+ resolve({
95
+ data: xhr.responseText,
96
+ status: xhr.status,
97
+ statusText: xhr.statusText,
98
+ headers: {
99
+ get: (name) => xhr.getResponseHeader(name),
100
+ },
101
+ });
102
+ } else {
103
+ reject(new Error(`HTTP error! status: ${xhr.status}`));
104
+ }
105
+ };
106
+
107
+ xhr.onerror = function () {
108
+ reject(new Error("Network error"));
109
+ };
110
+
111
+ xhr.onabort = function () {
112
+ reject(new Error("Upload aborted"));
113
+ };
114
+
115
+ // Handle upload progress
116
+ if (on_upload_progress) {
117
+ xhr.upload.onprogress = function (event) {
118
+ if (event.lengthComputable) {
119
+ const progressEvent = {
120
+ loaded: event.loaded,
121
+ total: event.total,
122
+ progress: event.loaded / event.total,
123
+ };
124
+ on_upload_progress(progressEvent);
125
+ }
126
+ };
127
+ }
128
+
129
+ // Handle download progress with streaming response parsing
130
+ xhr.onprogress = function (event) {
131
+ if (eventHandler) {
132
+ const progressEvent = {
133
+ event: {
134
+ target: {
135
+ responseText: xhr.responseText,
136
+ },
137
+ },
138
+ progress: event.lengthComputable ? event.loaded / event.total : 0,
139
+ };
140
+ eventHandler(progressEvent);
141
+ }
142
+ };
143
+
144
+ // Handle abort controller
145
+ controller.signal.addEventListener("abort", () => {
146
+ xhr.abort();
147
+ });
148
+
149
+ // Configure and send request
150
+ xhr.open("POST", getBackendURL(env.UPLOAD));
151
+ xhr.setRequestHeader("Reflex-Client-Token", getToken());
152
+ xhr.setRequestHeader("Reflex-Event-Handler", handler);
153
+ for (const [key, value] of Object.entries(extra_headers || {})) {
154
+ xhr.setRequestHeader(key, value);
155
+ }
156
+
157
+ try {
158
+ xhr.send(formdata);
159
+ } catch (error) {
160
+ reject(error);
161
+ }
162
+ })
163
+ .catch((error) => {
164
+ console.log("Upload error:", error.message);
165
+ return false;
166
+ })
167
+ .finally(() => {
168
+ delete refs[upload_ref_name];
169
+ });
170
+ };
@@ -20,10 +20,10 @@ import {
20
20
  } from "$/utils/context";
21
21
  import debounce from "$/utils/helpers/debounce";
22
22
  import throttle from "$/utils/helpers/throttle";
23
+ import { uploadFiles } from "$/utils/helpers/upload";
23
24
 
24
25
  // Endpoint URLs.
25
26
  const EVENTURL = env.EVENT;
26
- const UPLOADURL = env.UPLOAD;
27
27
 
28
28
  // These hostnames indicate that the backend and frontend are reachable via the same domain.
29
29
  const SAME_DOMAIN_HOSTNAMES = ["localhost", "0.0.0.0", "::", "0:0:0:0:0:0:0:0"];
@@ -210,7 +210,11 @@ export const applyEvent = async (event, socket, navigate, params) => {
210
210
  return false;
211
211
  }
212
212
  if (event.payload.external) {
213
- window.open(event.payload.path, "_blank", "noopener");
213
+ window.open(
214
+ event.payload.path,
215
+ "_blank",
216
+ "noopener" + (event.payload.popup ? ",popup" : ""),
217
+ );
214
218
  return false;
215
219
  }
216
220
  const url = urlFrom(event.payload.path);
@@ -428,7 +432,11 @@ export const applyRestEvent = async (event, socket, navigate, params) => {
428
432
  event.payload.files,
429
433
  event.payload.upload_id,
430
434
  event.payload.on_upload_progress,
435
+ event.payload.extra_headers,
431
436
  socket,
437
+ refs,
438
+ getBackendURL,
439
+ getToken,
432
440
  );
433
441
  return false;
434
442
  }
@@ -610,163 +618,6 @@ export const connect = async (
610
618
  document.addEventListener("visibilitychange", checkVisibility);
611
619
  };
612
620
 
613
- /**
614
- * Upload files to the server.
615
- *
616
- * @param state The state to apply the delta to.
617
- * @param handler The handler to use.
618
- * @param upload_id The upload id to use.
619
- * @param on_upload_progress The function to call on upload progress.
620
- * @param socket the websocket connection
621
- *
622
- * @returns The response from posting to the UPLOADURL endpoint.
623
- */
624
- export const uploadFiles = async (
625
- handler,
626
- files,
627
- upload_id,
628
- on_upload_progress,
629
- socket,
630
- ) => {
631
- // return if there's no file to upload
632
- if (files === undefined || files.length === 0) {
633
- return false;
634
- }
635
-
636
- const upload_ref_name = `__upload_controllers_${upload_id}`;
637
-
638
- if (refs[upload_ref_name]) {
639
- console.log("Upload already in progress for ", upload_id);
640
- return false;
641
- }
642
-
643
- // Track how many partial updates have been processed for this upload.
644
- let resp_idx = 0;
645
- const eventHandler = (progressEvent) => {
646
- const event_callbacks = socket._callbacks.$event;
647
- // Whenever called, responseText will contain the entire response so far.
648
- const chunks = progressEvent.event.target.responseText.trim().split("\n");
649
- // So only process _new_ chunks beyond resp_idx.
650
- chunks.slice(resp_idx).map((chunk_json) => {
651
- try {
652
- const chunk = JSON5.parse(chunk_json);
653
- event_callbacks.map((f, ix) => {
654
- f(chunk)
655
- .then(() => {
656
- if (ix === event_callbacks.length - 1) {
657
- // Mark this chunk as processed.
658
- resp_idx += 1;
659
- }
660
- })
661
- .catch((e) => {
662
- if (progressEvent.progress === 1) {
663
- // Chunk may be incomplete, so only report errors when full response is available.
664
- console.log("Error processing chunk", chunk, e);
665
- }
666
- return;
667
- });
668
- });
669
- } catch (e) {
670
- if (progressEvent.progress === 1) {
671
- console.log("Error parsing chunk", chunk_json, e);
672
- }
673
- return;
674
- }
675
- });
676
- };
677
-
678
- const controller = new AbortController();
679
- const formdata = new FormData();
680
-
681
- // Add the token and handler to the file name.
682
- files.forEach((file) => {
683
- formdata.append("files", file, file.path || file.name);
684
- });
685
-
686
- // Send the file to the server.
687
- refs[upload_ref_name] = controller;
688
-
689
- return new Promise((resolve, reject) => {
690
- const xhr = new XMLHttpRequest();
691
-
692
- // Set up event handlers
693
- xhr.onload = function () {
694
- if (xhr.status >= 200 && xhr.status < 300) {
695
- resolve({
696
- data: xhr.responseText,
697
- status: xhr.status,
698
- statusText: xhr.statusText,
699
- headers: {
700
- get: (name) => xhr.getResponseHeader(name),
701
- },
702
- });
703
- } else {
704
- reject(new Error(`HTTP error! status: ${xhr.status}`));
705
- }
706
- };
707
-
708
- xhr.onerror = function () {
709
- reject(new Error("Network error"));
710
- };
711
-
712
- xhr.onabort = function () {
713
- reject(new Error("Upload aborted"));
714
- };
715
-
716
- // Handle upload progress
717
- if (on_upload_progress) {
718
- xhr.upload.onprogress = function (event) {
719
- if (event.lengthComputable) {
720
- const progressEvent = {
721
- loaded: event.loaded,
722
- total: event.total,
723
- progress: event.loaded / event.total,
724
- };
725
- on_upload_progress(progressEvent);
726
- }
727
- };
728
- }
729
-
730
- // Handle download progress with streaming response parsing
731
- xhr.onprogress = function (event) {
732
- if (eventHandler) {
733
- const progressEvent = {
734
- event: {
735
- target: {
736
- responseText: xhr.responseText,
737
- },
738
- },
739
- progress: event.lengthComputable ? event.loaded / event.total : 0,
740
- };
741
- eventHandler(progressEvent);
742
- }
743
- };
744
-
745
- // Handle abort controller
746
- controller.signal.addEventListener("abort", () => {
747
- xhr.abort();
748
- });
749
-
750
- // Configure and send request
751
- xhr.open("POST", getBackendURL(UPLOADURL));
752
- xhr.setRequestHeader("Reflex-Client-Token", getToken());
753
- xhr.setRequestHeader("Reflex-Event-Handler", handler);
754
-
755
- try {
756
- xhr.send(formdata);
757
- } catch (error) {
758
- reject(error);
759
- }
760
- })
761
- .catch((error) => {
762
- console.log("Upload error:", error.message);
763
- return false;
764
- })
765
- .finally(() => {
766
- delete refs[upload_ref_name];
767
- });
768
- };
769
-
770
621
  /**
771
622
  * Create an event object.
772
623
  * @param {string} name The name of the event.
reflex/app.py CHANGED
@@ -258,6 +258,15 @@ class UploadFile(StarletteUploadFile):
258
258
 
259
259
  headers: Headers = dataclasses.field(default_factory=Headers)
260
260
 
261
+ @property
262
+ def filename(self) -> str | None:
263
+ """Get the name of the uploaded file.
264
+
265
+ Returns:
266
+ The name of the uploaded file.
267
+ """
268
+ return self.name
269
+
261
270
  @property
262
271
  def name(self) -> str | None:
263
272
  """Get the name of the uploaded file.
@@ -161,7 +161,7 @@ def _compile_page(component: BaseComponent) -> str:
161
161
  # Compile the code to render the component.
162
162
  return templates.page_template(
163
163
  imports=imports,
164
- dynamic_imports=component._get_all_dynamic_imports(),
164
+ dynamic_imports=sorted(component._get_all_dynamic_imports()),
165
165
  custom_codes=component._get_all_custom_code(),
166
166
  hooks=component._get_all_hooks(),
167
167
  render=component.render(),
@@ -379,7 +379,7 @@ def _compile_components(
379
379
  templates.custom_component_template(
380
380
  imports=utils.compile_imports(imports),
381
381
  components=component_renders,
382
- dynamic_imports=dynamic_imports,
382
+ dynamic_imports=sorted(dynamic_imports),
383
383
  custom_codes=custom_codes,
384
384
  ),
385
385
  imports,
@@ -435,9 +435,7 @@ def _compile_stateful_components(
435
435
  rendered_components.update(dict.fromkeys(dynamic_imports))
436
436
 
437
437
  # Include custom code in the shared component.
438
- rendered_components.update(
439
- dict.fromkeys(component._get_all_custom_code(export=True)),
440
- )
438
+ rendered_components.update(component._get_all_custom_code(export=True))
441
439
 
442
440
  # Include all imports in the shared component.
443
441
  all_import_dicts.append(component._get_all_imports())
@@ -164,7 +164,7 @@ export function Layout({{children}}) {{
164
164
  def app_root_template(
165
165
  *,
166
166
  imports: list[_ImportDict],
167
- custom_codes: set[str],
167
+ custom_codes: Iterable[str],
168
168
  hooks: dict[str, VarData | None],
169
169
  window_libraries: list[tuple[str, str]],
170
170
  render: dict[str, Any],
@@ -200,7 +200,6 @@ def app_root_template(
200
200
  )
201
201
 
202
202
  return f"""
203
- import reflexGlobalStyles from '$/styles/__reflex_global_styles.css?url';
204
203
  {imports_str}
205
204
  {dynamic_imports_str}
206
205
  import {{ EventLoopProvider, StateProvider, defaultColorMode }} from "$/utils/context";
@@ -211,10 +210,6 @@ import {{ Outlet }} from 'react-router';
211
210
 
212
211
  {custom_code_str}
213
212
 
214
- export const links = () => [
215
- {{ rel: 'stylesheet', href: reflexGlobalStyles, type: 'text/css' }}
216
- ];
217
-
218
213
  function AppWrap({{children}}) {{
219
214
  {_render_hooks(hooks)}
220
215
  return ({_RenderUtils.render(render)})
reflex/compiler/utils.py CHANGED
@@ -16,7 +16,7 @@ from reflex.components.base import Description, Image, Scripts
16
16
  from reflex.components.base.document import Links, ScrollRestoration
17
17
  from reflex.components.base.document import Meta as ReactMeta
18
18
  from reflex.components.component import Component, ComponentStyle, CustomComponent
19
- from reflex.components.el.elements.metadata import Head, Meta, Title
19
+ from reflex.components.el.elements.metadata import Head, Link, Meta, Title
20
20
  from reflex.components.el.elements.other import Html
21
21
  from reflex.components.el.elements.sectioning import Body
22
22
  from reflex.constants.state import FIELD_MARKER
@@ -26,7 +26,7 @@ from reflex.style import Style
26
26
  from reflex.utils import format, imports, path_ops
27
27
  from reflex.utils.imports import ImportVar, ParsedImportDict
28
28
  from reflex.utils.prerequisites import get_web_dir
29
- from reflex.vars.base import Field, Var
29
+ from reflex.vars.base import Field, Var, VarData
30
30
 
31
31
  # To re-export this function.
32
32
  merge_imports = imports.merge_imports
@@ -382,6 +382,20 @@ def create_document_root(
382
382
  # Always include the framework meta and link tags.
383
383
  always_head_components = [
384
384
  ReactMeta.create(),
385
+ Link.create(
386
+ rel="stylesheet",
387
+ type="text/css",
388
+ href=Var(
389
+ "reflexGlobalStyles",
390
+ _var_data=VarData(
391
+ imports={
392
+ "$/styles/__reflex_global_styles.css?url": [
393
+ ImportVar(tag="reflexGlobalStyles", is_default=True)
394
+ ]
395
+ }
396
+ ),
397
+ ),
398
+ ),
385
399
  Links.create(),
386
400
  ]
387
401
  maybe_head_components = []
@@ -129,7 +129,7 @@ class Bare(Component):
129
129
  dynamic_imports |= component._get_all_dynamic_imports()
130
130
  return dynamic_imports
131
131
 
132
- def _get_all_custom_code(self) -> set[str]:
132
+ def _get_all_custom_code(self) -> dict[str, None]:
133
133
  """Get custom code for the component.
134
134
 
135
135
  Returns:
@@ -166,7 +166,7 @@ class Bare(Component):
166
166
  )
167
167
  return app_wrap_components
168
168
 
169
- def _get_all_refs(self) -> set[str]:
169
+ def _get_all_refs(self) -> dict[str, None]:
170
170
  """Get the refs for the children of the component.
171
171
 
172
172
  Returns:
@@ -10,7 +10,7 @@ import functools
10
10
  import inspect
11
11
  import typing
12
12
  from abc import ABC, ABCMeta, abstractmethod
13
- from collections.abc import Callable, Iterator, Mapping, Sequence
13
+ from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
14
14
  from dataclasses import _MISSING_TYPE, MISSING
15
15
  from functools import wraps
16
16
  from hashlib import md5
@@ -374,7 +374,7 @@ class BaseComponent(metaclass=BaseComponentMeta):
374
374
  """
375
375
 
376
376
  @abstractmethod
377
- def _get_all_custom_code(self) -> set[str]:
377
+ def _get_all_custom_code(self) -> dict[str, None]:
378
378
  """Get custom code for the component.
379
379
 
380
380
  Returns:
@@ -382,7 +382,7 @@ class BaseComponent(metaclass=BaseComponentMeta):
382
382
  """
383
383
 
384
384
  @abstractmethod
385
- def _get_all_refs(self) -> set[str]:
385
+ def _get_all_refs(self) -> dict[str, None]:
386
386
  """Get the refs for the children of the component.
387
387
 
388
388
  Returns:
@@ -1003,13 +1003,13 @@ class Component(BaseComponent, ABC):
1003
1003
 
1004
1004
  @classmethod
1005
1005
  @functools.cache
1006
- def get_props(cls) -> set[str]:
1006
+ def get_props(cls) -> Iterable[str]:
1007
1007
  """Get the unique fields for the component.
1008
1008
 
1009
1009
  Returns:
1010
1010
  The unique fields.
1011
1011
  """
1012
- return set(cls.get_js_fields())
1012
+ return cls.get_js_fields()
1013
1013
 
1014
1014
  @classmethod
1015
1015
  @functools.cache
@@ -1509,19 +1509,19 @@ class Component(BaseComponent, ABC):
1509
1509
  """
1510
1510
  return None
1511
1511
 
1512
- def _get_all_custom_code(self) -> set[str]:
1512
+ def _get_all_custom_code(self) -> dict[str, None]:
1513
1513
  """Get custom code for the component and its children.
1514
1514
 
1515
1515
  Returns:
1516
1516
  The custom code.
1517
1517
  """
1518
1518
  # Store the code in a set to avoid duplicates.
1519
- code = set()
1519
+ code: dict[str, None] = {}
1520
1520
 
1521
1521
  # Add the custom code for this component.
1522
1522
  custom_code = self._get_custom_code()
1523
1523
  if custom_code is not None:
1524
- code.add(custom_code)
1524
+ code[custom_code] = None
1525
1525
 
1526
1526
  for component in self._get_components_in_props():
1527
1527
  code |= component._get_all_custom_code()
@@ -1529,7 +1529,7 @@ class Component(BaseComponent, ABC):
1529
1529
  # Add the custom code from add_custom_code method.
1530
1530
  for clz in self._iter_parent_classes_with_method("add_custom_code"):
1531
1531
  for item in clz.add_custom_code(self):
1532
- code.add(item)
1532
+ code[item] = None
1533
1533
 
1534
1534
  # Add the custom code for the children.
1535
1535
  for child in self.children:
@@ -1814,7 +1814,7 @@ class Component(BaseComponent, ABC):
1814
1814
 
1815
1815
  # Add the hook code for the children.
1816
1816
  for child in self.children:
1817
- code = {**code, **child._get_all_hooks_internal()}
1817
+ code.update(child._get_all_hooks_internal())
1818
1818
 
1819
1819
  return code
1820
1820
 
@@ -1838,7 +1838,7 @@ class Component(BaseComponent, ABC):
1838
1838
 
1839
1839
  # Add the hook code for the children.
1840
1840
  for child in self.children:
1841
- code = {**code, **child._get_all_hooks()}
1841
+ code.update(child._get_all_hooks())
1842
1842
 
1843
1843
  return code
1844
1844
 
@@ -1853,16 +1853,16 @@ class Component(BaseComponent, ABC):
1853
1853
  return None
1854
1854
  return format.format_ref(self.id)
1855
1855
 
1856
- def _get_all_refs(self) -> set[str]:
1856
+ def _get_all_refs(self) -> dict[str, None]:
1857
1857
  """Get the refs for the children of the component.
1858
1858
 
1859
1859
  Returns:
1860
1860
  The refs for the children.
1861
1861
  """
1862
- refs = set()
1862
+ refs = {}
1863
1863
  ref = self.get_ref()
1864
1864
  if ref is not None:
1865
- refs.add(ref)
1865
+ refs[ref] = None
1866
1866
  for child in self.children:
1867
1867
  refs |= child._get_all_refs()
1868
1868
  for component in self._get_components_in_props():
@@ -1994,7 +1994,7 @@ class CustomComponent(Component):
1994
1994
  )
1995
1995
 
1996
1996
  to_camel_cased_props = {
1997
- format.to_camel_case(key + MEMO_MARKER)
1997
+ format.to_camel_case(key + MEMO_MARKER): None
1998
1998
  for key in props
1999
1999
  if key not in event_types
2000
2000
  }
@@ -2048,13 +2048,13 @@ class CustomComponent(Component):
2048
2048
  return hash(self.tag)
2049
2049
 
2050
2050
  @classmethod
2051
- def get_props(cls) -> set[str]:
2051
+ def get_props(cls) -> Iterable[str]:
2052
2052
  """Get the props for the component.
2053
2053
 
2054
2054
  Returns:
2055
2055
  The set of component props.
2056
2056
  """
2057
- return set()
2057
+ return ()
2058
2058
 
2059
2059
  @staticmethod
2060
2060
  def _get_event_spec_from_args_spec(name: str, event: EventChain) -> Callable:
@@ -2656,7 +2656,7 @@ class StatefulComponent(BaseComponent):
2656
2656
  return set()
2657
2657
  return self.component._get_all_dynamic_imports()
2658
2658
 
2659
- def _get_all_custom_code(self, export: bool = False) -> set[str]:
2659
+ def _get_all_custom_code(self, export: bool = False) -> dict[str, None]:
2660
2660
  """Get custom code for the component.
2661
2661
 
2662
2662
  Args:
@@ -2666,19 +2666,19 @@ class StatefulComponent(BaseComponent):
2666
2666
  The custom code.
2667
2667
  """
2668
2668
  if self.rendered_as_shared:
2669
- return set()
2670
- return self.component._get_all_custom_code().union(
2671
- {self._render_stateful_code(export=export)}
2669
+ return {}
2670
+ return self.component._get_all_custom_code() | (
2671
+ {self._render_stateful_code(export=export): None}
2672
2672
  )
2673
2673
 
2674
- def _get_all_refs(self) -> set[str]:
2674
+ def _get_all_refs(self) -> dict[str, None]:
2675
2675
  """Get the refs for the children of the component.
2676
2676
 
2677
2677
  Returns:
2678
2678
  The refs for the children.
2679
2679
  """
2680
2680
  if self.rendered_as_shared:
2681
- return set()
2681
+ return {}
2682
2682
  return self.component._get_all_refs()
2683
2683
 
2684
2684
  def render(self) -> dict:
@@ -132,7 +132,7 @@ class DebounceInput(Component):
132
132
  component.children = child.children
133
133
  component._rename_props = child._rename_props # pyright: ignore[reportAttributeAccessIssue]
134
134
  outer_get_all_custom_code = component._get_all_custom_code
135
- component._get_all_custom_code = lambda: outer_get_all_custom_code().union(
135
+ component._get_all_custom_code = lambda: outer_get_all_custom_code() | (
136
136
  child._get_all_custom_code()
137
137
  )
138
138
  return component
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import functools
6
6
  import inspect
7
7
  from collections.abc import Callable, Iterable
8
+ from hashlib import md5
8
9
  from typing import Any
9
10
 
10
11
  from reflex.components.base.fragment import Fragment
@@ -141,25 +142,12 @@ class Foreach(Component):
141
142
  else:
142
143
  render_fn = self.render_fn
143
144
  # Otherwise, use a deterministic index, based on the render function bytecode.
144
- code_hash = (
145
- hash(
146
- getattr(
147
- render_fn,
148
- "__code__",
149
- (
150
- repr(self.render_fn)
151
- if not isinstance(render_fn, functools.partial)
152
- else render_fn.func.__code__
153
- ),
154
- )
155
- )
156
- .to_bytes(
157
- length=8,
158
- byteorder="big",
159
- signed=True,
160
- )
161
- .hex()
162
- )
145
+ if (render_fn_code := getattr(render_fn, "__code__", None)) is not None:
146
+ code_hash = md5(render_fn_code.co_code).hexdigest()
147
+ elif isinstance(render_fn, functools.partial):
148
+ code_hash = md5(render_fn.func.__code__.co_code).hexdigest()
149
+ else:
150
+ code_hash = md5(repr(render_fn).encode()).hexdigest()
163
151
  props["index_var_name"] = f"index_{code_hash}"
164
152
 
165
153
  return IterTag(
@@ -260,7 +260,7 @@ class Upload(MemoizationLeaf):
260
260
  props["class_name"] = ["rx-Upload", *given_class_name]
261
261
 
262
262
  # get only upload component props
263
- supported_props = cls.get_props().union({"on_drop"})
263
+ supported_props = set(cls.get_props()) | {"on_drop"}
264
264
  upload_props = {
265
265
  key: value for key, value in props.items() if key in supported_props
266
266
  }
@@ -81,9 +81,7 @@ def load_dynamic_serializer():
81
81
  rendered_components.update(dict.fromkeys(dynamic_imports))
82
82
 
83
83
  # Include custom code in the shared component.
84
- rendered_components.update(
85
- dict.fromkeys(component._get_all_custom_code()),
86
- )
84
+ rendered_components.update(component._get_all_custom_code())
87
85
 
88
86
  rendered_components[
89
87
  templates.stateful_component_template(
@@ -770,7 +770,7 @@ class Textarea(BaseHTML):
770
770
  "enter_key_submit",
771
771
  ]
772
772
 
773
- def _get_all_custom_code(self) -> set[str]:
773
+ def _get_all_custom_code(self) -> dict[str, None]:
774
774
  """Include the custom code for auto_height and enter_key_submit functionality.
775
775
 
776
776
  Returns:
@@ -778,9 +778,9 @@ class Textarea(BaseHTML):
778
778
  """
779
779
  custom_code = super()._get_all_custom_code()
780
780
  if self.auto_height is not None:
781
- custom_code.add(AUTO_HEIGHT_JS)
781
+ custom_code[AUTO_HEIGHT_JS] = None
782
782
  if self.enter_key_submit is not None:
783
- custom_code.add(ENTER_KEY_SUBMIT_JS)
783
+ custom_code[ENTER_KEY_SUBMIT_JS] = None
784
784
  return custom_code
785
785
 
786
786
 
@@ -6,7 +6,7 @@ from reflex.utils.imports import ImportVar
6
6
  from reflex.vars.base import LiteralVar, Var
7
7
  from reflex.vars.sequence import LiteralStringVar, StringVar
8
8
 
9
- LUCIDE_LIBRARY = "lucide-react@0.541.0"
9
+ LUCIDE_LIBRARY = "lucide-react@0.542.0"
10
10
 
11
11
 
12
12
  class LucideIconComponent(Component):
@@ -1002,6 +1002,7 @@ LUCIDE_ICON_LIST = [
1002
1002
  "linkedin",
1003
1003
  "list_check",
1004
1004
  "list_checks",
1005
+ "list_chevrons_down_up",
1005
1006
  "list_collapse",
1006
1007
  "list_end",
1007
1008
  "list_filter_plus",
@@ -11,7 +11,7 @@ from reflex.components.core.breakpoints import Breakpoints
11
11
  from reflex.event import EventType, PointerEventInfo
12
12
  from reflex.vars.base import Var
13
13
 
14
- LUCIDE_LIBRARY = "lucide-react@0.541.0"
14
+ LUCIDE_LIBRARY = "lucide-react@0.542.0"
15
15
 
16
16
  class LucideIconComponent(Component):
17
17
  @classmethod
@@ -1067,6 +1067,7 @@ LUCIDE_ICON_LIST = [
1067
1067
  "linkedin",
1068
1068
  "list_check",
1069
1069
  "list_checks",
1070
+ "list_chevrons_down_up",
1070
1071
  "list_collapse",
1071
1072
  "list_end",
1072
1073
  "list_filter_plus",
reflex/environment.py CHANGED
@@ -204,7 +204,7 @@ def interpret_env_var_value(
204
204
  The interpreted value.
205
205
 
206
206
  Raises:
207
- ValueError: If the value is invalid.
207
+ ValueError: If the environment variable type is invalid.
208
208
  """
209
209
  field_type = value_inside_optional(field_type)
210
210
 
@@ -556,6 +556,18 @@ class EnvironmentVariables:
556
556
  # Whether to check db connections before using them.
557
557
  SQLALCHEMY_POOL_PRE_PING: EnvVar[bool] = env_var(True)
558
558
 
559
+ # The size of the database connection pool.
560
+ SQLALCHEMY_POOL_SIZE: EnvVar[int] = env_var(5)
561
+
562
+ # The maximum overflow size of the database connection pool.
563
+ SQLALCHEMY_MAX_OVERFLOW: EnvVar[int] = env_var(10)
564
+
565
+ # Recycle connections after this many seconds.
566
+ SQLALCHEMY_POOL_RECYCLE: EnvVar[int] = env_var(-1)
567
+
568
+ # The timeout for acquiring a connection from the pool.
569
+ SQLALCHEMY_POOL_TIMEOUT: EnvVar[int] = env_var(30)
570
+
559
571
  # Whether to ignore the redis config error. Some redis servers only allow out-of-band configuration.
560
572
  REFLEX_IGNORE_REDIS_CONFIG_ERROR: EnvVar[bool] = env_var(False)
561
573
 
reflex/event.py CHANGED
@@ -13,6 +13,7 @@ from typing import (
13
13
  Annotated,
14
14
  Any,
15
15
  Generic,
16
+ Literal,
16
17
  NoReturn,
17
18
  Protocol,
18
19
  TypeVar,
@@ -845,6 +846,7 @@ class FileUpload:
845
846
 
846
847
  upload_id: str | None = None
847
848
  on_upload_progress: EventHandler | Callable | None = None
849
+ extra_headers: dict[str, str] | None = None
848
850
 
849
851
  @staticmethod
850
852
  def on_upload_progress_args_spec(_prog: Var[dict[str, int | float | bool]]):
@@ -886,6 +888,12 @@ class FileUpload:
886
888
  Var(_js_expr="upload_id"),
887
889
  LiteralVar.create(upload_id),
888
890
  ),
891
+ (
892
+ Var(_js_expr="extra_headers"),
893
+ LiteralVar.create(
894
+ self.extra_headers if self.extra_headers is not None else {}
895
+ ),
896
+ ),
889
897
  ]
890
898
  if self.on_upload_progress is not None:
891
899
  on_upload_progress = self.on_upload_progress
@@ -962,9 +970,29 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
962
970
  )
963
971
 
964
972
 
973
+ @overload
974
+ def redirect(
975
+ path: str | Var[str],
976
+ *,
977
+ is_external: Literal[False] = False,
978
+ replace: bool = False,
979
+ ) -> EventSpec: ...
980
+
981
+
982
+ @overload
983
+ def redirect(
984
+ path: str | Var[str],
985
+ *,
986
+ is_external: Literal[True],
987
+ popup: bool = False,
988
+ ) -> EventSpec: ...
989
+
990
+
965
991
  def redirect(
966
992
  path: str | Var[str],
993
+ *,
967
994
  is_external: bool = False,
995
+ popup: bool = False,
968
996
  replace: bool = False,
969
997
  ) -> EventSpec:
970
998
  """Redirect to a new path.
@@ -972,6 +1000,7 @@ def redirect(
972
1000
  Args:
973
1001
  path: The path to redirect to.
974
1002
  is_external: Whether to open in new tab or not.
1003
+ popup: Whether to open in a new window or not.
975
1004
  replace: If True, the current page will not create a new history entry.
976
1005
 
977
1006
  Returns:
@@ -982,6 +1011,7 @@ def redirect(
982
1011
  get_fn_signature(redirect),
983
1012
  path=path,
984
1013
  external=is_external,
1014
+ popup=popup,
985
1015
  replace=replace,
986
1016
  )
987
1017
 
reflex/model.py CHANGED
@@ -96,6 +96,10 @@ def get_engine_args(url: str | None = None) -> dict[str, Any]:
96
96
  "echo": environment.SQLALCHEMY_ECHO.get(),
97
97
  # Check connections before returning them.
98
98
  "pool_pre_ping": environment.SQLALCHEMY_POOL_PRE_PING.get(),
99
+ "pool_size": environment.SQLALCHEMY_POOL_SIZE.get(),
100
+ "max_overflow": environment.SQLALCHEMY_MAX_OVERFLOW.get(),
101
+ "pool_recycle": environment.SQLALCHEMY_POOL_RECYCLE.get(),
102
+ "pool_timeout": environment.SQLALCHEMY_POOL_TIMEOUT.get(),
99
103
  }
100
104
  conf = get_config()
101
105
  url = url or conf.db_url
reflex/vars/base.py CHANGED
@@ -9,7 +9,6 @@ import datetime
9
9
  import functools
10
10
  import inspect
11
11
  import json
12
- import random
13
12
  import re
14
13
  import string
15
14
  import uuid
@@ -50,6 +49,7 @@ from reflex.base import Base
50
49
  from reflex.constants.compiler import Hooks
51
50
  from reflex.constants.state import FIELD_MARKER
52
51
  from reflex.utils import console, exceptions, imports, serializers, types
52
+ from reflex.utils.decorator import once
53
53
  from reflex.utils.exceptions import (
54
54
  ComputedVarSignatureError,
55
55
  UntypedComputedVarError,
@@ -3033,13 +3033,20 @@ def get_uuid_string_var() -> Var:
3033
3033
  USED_VARIABLES = set()
3034
3034
 
3035
3035
 
3036
+ @once
3037
+ def _rng():
3038
+ import random
3039
+
3040
+ return random.Random(42)
3041
+
3042
+
3036
3043
  def get_unique_variable_name() -> str:
3037
3044
  """Get a unique variable name.
3038
3045
 
3039
3046
  Returns:
3040
3047
  The unique variable name.
3041
3048
  """
3042
- name = "".join([random.choice(string.ascii_lowercase) for _ in range(8)])
3049
+ name = "".join([_rng().choice(string.ascii_lowercase) for _ in range(8)])
3043
3050
  if name not in USED_VARIABLES:
3044
3051
  USED_VARIABLES.add(name)
3045
3052
  return name
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reflex
3
- Version: 0.8.9a2
3
+ Version: 0.8.10
4
4
  Summary: Web apps in pure Python.
5
5
  Project-URL: homepage, https://reflex.dev
6
6
  Project-URL: repository, https://github.com/reflex-dev/reflex
7
7
  Project-URL: documentation, https://reflex.dev/docs/getting-started/introduction
8
- Author-email: Nikhil Rao <nikhil@reflex.dev>, Alek Petuskey <alek@reflex.dev>, Masen Furer <masen@reflex.dev>, Elijah Ahianyo <elijahahianyo@gmail.com>, Thomas Brandeho <thomas@reflex.dev>, Khaleel Al-Adhami <khaleel@reflex.dev>
9
- Maintainer-email: Masen Furer <masen@reflex.dev>, Thomas Brandeho <thomas@reflex.dev>, Khaleel Al-Adhami <khaleel@reflex.dev>
8
+ Author: Nikhil Rao, Alek Petuskey, Masen Furer, Elijah Ahianyo, Thomas Brandeho, Khaleel Al-Adhami
9
+ Maintainer: Masen Furer, Khaleel Al-Adhami
10
+ Maintainer-email: maintainers@reflex.dev
10
11
  License: Apache-2.0
11
12
  License-File: LICENSE
12
13
  Keywords: framework,web
@@ -2,13 +2,13 @@ reflex/__init__.py,sha256=_1PVYjDeA6_JyfXvL6OuKjjO6AX2oMiNcAq8AEHf6xw,10161
2
2
  reflex/__init__.pyi,sha256=0D46kHVUJPE_kgYL-BjraERu-MXNCPsQTZQShrijmeQ,10148
3
3
  reflex/__main__.py,sha256=6cVrGEyT3j3tEvlEVUatpaYfbB5EF3UVY-6vc_Z7-hw,108
4
4
  reflex/admin.py,sha256=Nbc38y-M8iaRBvh1W6DQu_D3kEhO8JFvxrog4q2cB_E,434
5
- reflex/app.py,sha256=PaoBHbIRPHAf5_nfEcRKDmANi77LTJfq5xuJZIUBCCU,77932
5
+ reflex/app.py,sha256=3J6VYfArjPXikkv1HEHyLVAuG2tJpbJHDFVYQvvK1C0,78129
6
6
  reflex/assets.py,sha256=l5O_mlrTprC0lF7Rc_McOe3a0OtSLnRdNl_PqCpDCBA,3431
7
7
  reflex/base.py,sha256=Oh664QL3fZEHErhUasFqP7fE4olYf1y-9Oj6uZI2FCU,1173
8
8
  reflex/config.py,sha256=LsHAtdH4nkSn3q_Ie-KNdOGdflLXrFICUQov29oFjVk,21229
9
- reflex/environment.py,sha256=7tfEPpUbelmOZ2B9zlqk0rgfHNkvz_HspGRIpod_AIQ,23126
10
- reflex/event.py,sha256=0VHquGHwqfvsEFExJn8m1YFSaE__pg1j58Q8hOgiVmA,74797
11
- reflex/model.py,sha256=l1-6fm7NHRFWH-xK9oV9UzAVfvKeUXG1f-tCrF7vmfI,19403
9
+ reflex/environment.py,sha256=BRIePrhFKTZajYlyl-KhjGsqR4_hc7KxfNCoape6Jjw,23590
10
+ reflex/event.py,sha256=WfM9jNCFaTpHPRVKXJVjBbwx2lgJ9GwidyWd9cS-G1I,75460
11
+ reflex/model.py,sha256=2QhU1TJlcDeRA23pv8usLjyDaA6FhbQRYdzsjOHzvUI,19665
12
12
  reflex/page.py,sha256=ssCbMVFuIy60vH-YhJUzN0OxzUwXFCCD3ej56dVjp3g,3525
13
13
  reflex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  reflex/reflex.py,sha256=qKpWvXuA55y519MWckr6oxKSf3pCQfRCrvzsyXSuAqk,22729
@@ -26,28 +26,29 @@ reflex/.templates/web/react-router.config.js,sha256=5K1FBryYdPusn1nE513GwB5_5UdP
26
26
  reflex/.templates/web/vite-plugin-safari-cachebust.js,sha256=FcyppYYBxUlZtQ-D_iyVaQIT6TBVisBH7DMzWxYm-zA,5300
27
27
  reflex/.templates/web/app/entry.client.js,sha256=2Jv-5SQWHhHmA07BP50f1ew1V-LOsX5VoLtSInnFDj8,264
28
28
  reflex/.templates/web/app/routes.js,sha256=-16AwZFzrVSR7DBPYZbGx3lBA5hBFJ_XF2Y-6ilharo,254
29
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js,sha256=dnDHW49imtdalZJQqj7J_u7cj2z8Sve7OlhtOO0FbKE,916
29
+ reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js,sha256=H8F1bUUuIU8VOtbaHRStQQwlqSwrCwFF-orklp3xKiE,1198
30
30
  reflex/.templates/web/components/shiki/code.js,sha256=4Es1pxsr-lX4hTQ5mglrwwC6O_SI-z-O60k03z8VFzQ,1144
31
31
  reflex/.templates/web/styles/__reflex_style_reset.css,sha256=qbC6JIT643YEsvSQ0D7xBmWE5vXy94JGrKNihRuEjnA,8913
32
32
  reflex/.templates/web/utils/react-theme.js,sha256=Aa-RND3ooGCXW6Zavzitc-v0ciKlcQDTFlDtE4mPkFI,2713
33
- reflex/.templates/web/utils/state.js,sha256=-K0bu2X2wxUpfeieCuw14HQz3W1jvx1s7JK69S8b4R0,36060
33
+ reflex/.templates/web/utils/state.js,sha256=sf8v15y5FXGeuQg1spDRe88pl3Kdv7n4_338tqu_xkY,31894
34
34
  reflex/.templates/web/utils/helpers/dataeditor.js,sha256=pG6MgsHuStDR7-qPipzfiK32j9bKDBa-4hZ0JSUo4JM,1623
35
35
  reflex/.templates/web/utils/helpers/debounce.js,sha256=xGhtTRtS_xIcaeqnYVvYJNseLgQVk-DW-eFiHJYO9As,528
36
36
  reflex/.templates/web/utils/helpers/paste.js,sha256=ef30HsR83jRzzvZnl8yV79yqFP8TC_u8SlN99cCS_OM,1799
37
37
  reflex/.templates/web/utils/helpers/range.js,sha256=Bjr7Ex1Mghpsopjfrcp__IVFw8F8AsMiP-0nE20ZZwk,1091
38
38
  reflex/.templates/web/utils/helpers/throttle.js,sha256=qxeyaEojaTeX36FPGftzVWrzDsRQU4iqg3U9RJz9Vj4,566
39
+ reflex/.templates/web/utils/helpers/upload.js,sha256=YiAv-KC-LijTsEmzG_o6YxUprgSN7Pbyd__xu8HTX6s,4814
39
40
  reflex/app_mixins/__init__.py,sha256=Oegz3-gZLP9p2OAN5ALNbsgxuNQfS6lGZgQA8cc-9mQ,137
40
41
  reflex/app_mixins/lifespan.py,sha256=a156ZUYVo2bN1Tv-4WmWSjojo90PP_2-V12BX0q8YNw,3543
41
42
  reflex/app_mixins/middleware.py,sha256=BKhe0jUFO1_TylEC48LUZyaeYyPmAYW-NV4H5Rw221k,2848
42
43
  reflex/app_mixins/mixin.py,sha256=R1YncalqDrbdPZvpKVbm72ZKmQZxYAWfuFq9JknzTqQ,305
43
44
  reflex/compiler/__init__.py,sha256=r8jqmDSFf09iV2lHlNhfc9XrTLjNxfDNwPYlxS4cmHE,27
44
- reflex/compiler/compiler.py,sha256=MQ5SW5pcSeDL6Nsfvrcu0jWW26xaEXrR4EsSybzuW7k,29130
45
- reflex/compiler/templates.py,sha256=91LCzfwCG_VdqZEEG9vXoYA7SVZvTYTXVlkBuL-zEa8,20579
46
- reflex/compiler/utils.py,sha256=FM1KCuFMfcjveLmQAmwNMp6dTtaqhG3m2opo7rZs_iA,19158
45
+ reflex/compiler/compiler.py,sha256=KmkR33gbkYXPxlwBgsCFS5Hn7Fjpj_yFLuu6L5CYmQA,29100
46
+ reflex/compiler/templates.py,sha256=QATHSjsmMbH40kYpArPEIfKdmnWkBIkzGIC8JgRK9nM,20407
47
+ reflex/compiler/utils.py,sha256=RmeUoZMHdIfnqPl-p0ToPgwd0FEFO5u0Xbb-J20UYdQ,19621
47
48
  reflex/components/__init__.py,sha256=eWpgWFbSQDj2TpGp6StEbxU7roQgzY7ZM0XIcIc5RE8,588
48
49
  reflex/components/__init__.pyi,sha256=7VFHtJGIjvGtD3IiPk848IPWYSCcPRT1EyPGljLhYlU,736
49
- reflex/components/component.py,sha256=64p7eWhFg6Q9ZikvPX9pOYNjQk9GUElwXaf2qUAJACc,98103
50
- reflex/components/dynamic.py,sha256=WfN1waxtRuuZ3-8MvooDi4SkFxem4R8wAHOLXx_9rCo,7422
50
+ reflex/components/component.py,sha256=ToY6NmFGcDumWylgemkb7t4nhsnlc4QWdqiBeMbuCe4,98168
51
+ reflex/components/dynamic.py,sha256=M3Waonox1lMCs9db_0iz4VtmBLuETpzZvvJ8m4iNAhE,7384
51
52
  reflex/components/field.py,sha256=j5JZFzNlET3GAIW91m1L31RypXylMAxJNm0-CJbtykM,5745
52
53
  reflex/components/literals.py,sha256=hogLnwTJxFJODIvqihg-GD9kFZVsEBDoYzaRit56Nuk,501
53
54
  reflex/components/props.py,sha256=BH7RiRu_EI2BRkB1PyBVp6tLeFTTV4FzGEdDIXXQ9Bk,14378
@@ -55,7 +56,7 @@ reflex/components/base/__init__.py,sha256=6DzVn2oVZqmsXYq3r9AN8Q40R0NAsyRpSyVzBD
55
56
  reflex/components/base/__init__.pyi,sha256=CoM0dGGkZSKLNHe6KBS4Zgc6sRpRGM5dZ_EuVmZ2qkA,883
56
57
  reflex/components/base/app_wrap.py,sha256=5K_myvYvHPeAJbm3BdEX17tKvdNEj6SV9RYahbIQBAQ,514
57
58
  reflex/components/base/app_wrap.pyi,sha256=opdrLSp-IGFibjM4bPLZPxLsyhc1H6nev2F9XhPfOSg,1996
58
- reflex/components/base/bare.py,sha256=yALgxs1OhssQVcrcJwWtprw_DKKeXjVMLMZpTzn0Isc,8271
59
+ reflex/components/base/bare.py,sha256=_k1tx7nymFCNAmhRtT89PKBjLRldQZWxW0xPAkeZfuA,8285
59
60
  reflex/components/base/body.py,sha256=KLPOhxVsKyjPwrY9AziCOOG_c9ckOqIhI4n2i3_Q3NU,129
60
61
  reflex/components/base/body.pyi,sha256=VG8N-0ocwgFOJR9mXfu6a5BtIY_jR7mK9lX3Y22g9GQ,8655
61
62
  reflex/components/base/document.py,sha256=Fr7y22NbeKeiz8kWPH2q5BpFjKdq-AmY-sxZilee_H8,636
@@ -83,9 +84,9 @@ reflex/components/core/clipboard.py,sha256=lrM4KpbioSqBclhvtrgawgeg9Vq2dKsv40xP4
83
84
  reflex/components/core/clipboard.pyi,sha256=Wt84ce1rd5vje-KuzAIkn_0riAD91_VtnZcRiRBsFLs,3230
84
85
  reflex/components/core/colors.py,sha256=gkT5o5OqI_BR5fGMcCmBUpaz99XRNol9zAis46WktI4,1564
85
86
  reflex/components/core/cond.py,sha256=zjDM7Elf0iYpA1MtnUjXvEbD5XvYbluWDTaQ96uxZSI,5531
86
- reflex/components/core/debounce.py,sha256=P0rj23JKVsx_dzPMVI4HTOyrXhhacxh-QkI4Z9K6KNQ,5022
87
+ reflex/components/core/debounce.py,sha256=mLttJ1HkrHN3pJWVpV6KNeQBJBkcPQA4yNt4vWLXZU4,5019
87
88
  reflex/components/core/debounce.pyi,sha256=-vEa4eIS2VlHwoL1jMmAey_dMGzz0h4VbDhzC6JT6vI,3105
88
- reflex/components/core/foreach.py,sha256=HCAoDfdyumK8FvgNrfnQeNRaf6Cngn_6U02640M8ofI,6264
89
+ reflex/components/core/foreach.py,sha256=A33CPPBhd2IZ3-54Tv-MhMVlNoGh99IhuQ1Z-_vQj-E,6060
89
90
  reflex/components/core/helmet.py,sha256=9Fr2Tz_J2v8r5t1xeZClL0V5-fEWTiFAXTcJ6bECvAw,220
90
91
  reflex/components/core/helmet.pyi,sha256=dp5AOEPQYM77-_ylpsbgbsZkUqu37RblgUGw7Y0BGcI,2391
91
92
  reflex/components/core/html.py,sha256=JKK3MsbuzxtcVXbzvW_Q4TZuF9yk3WwiC9LmQl34rzA,1303
@@ -94,7 +95,7 @@ reflex/components/core/match.py,sha256=xBB9vtWgVlotPHq6ssng8lzxwXDDQLp9k6Ew5RPPd
94
95
  reflex/components/core/responsive.py,sha256=ACZdtJ4a4F8B3dm1k8h6J2_UJx0Z5LDB7XHQ2ty4wAc,1911
95
96
  reflex/components/core/sticky.py,sha256=2B3TxrwG2Rtp_lv1VkMOIF2bqSiT7qYGbqbiZiMKxKY,3856
96
97
  reflex/components/core/sticky.pyi,sha256=5D-yT0LYs0ewOlUlInU7KCpuz49yKK7dirysUs1C2VI,32908
97
- reflex/components/core/upload.py,sha256=b4-ubt4dznL5LDA7UCKNdWcdCX9aLOX2vNFdv4GlRdg,13544
98
+ reflex/components/core/upload.py,sha256=Zxni0-cG3B8qx2eSFV7CSZ38gHN9r8YtosowNBHceoI,13544
98
99
  reflex/components/core/upload.pyi,sha256=UqfcPGUs8xmnKHKuvqYV7CtOXeF_D1s9ooRe49w6C3E,15757
99
100
  reflex/components/core/window_events.py,sha256=opbuO20zVxt252kQLk49V7cltb_Um2oh7iePeGNJ538,3355
100
101
  reflex/components/core/window_events.pyi,sha256=aTkBiAy-e9LqkQm6_apRsXXfJRdawA11cE1tQQSIy3c,3206
@@ -116,7 +117,7 @@ reflex/components/el/elements/__init__.py,sha256=_uZaPHSQSDZBqo-v_hRZECJbWBY3Srq
116
117
  reflex/components/el/elements/__init__.pyi,sha256=LCaxINN6BUqHsxgpDITjOUqJnF3x5rRI8y2fj62ZT14,8680
117
118
  reflex/components/el/elements/base.py,sha256=4jnwyCQUHvWcIfwiIWVCiIC_jbwZlkAiOgx73t7tdw8,3075
118
119
  reflex/components/el/elements/base.pyi,sha256=RPdq_8Z1gkV-5n2qeEVQWpPCwVSTzY4eYb6iIJVU-ig,10074
119
- reflex/components/el/elements/forms.py,sha256=75RJqmw4vBEUeYFNZwza91BpiXnEVSSK3HVPqyZcK44,22004
120
+ reflex/components/el/elements/forms.py,sha256=_WleBOQniadFc0lqDM_CoBbnDoLw0LfWJD6wyr3_bQw,22017
120
121
  reflex/components/el/elements/forms.pyi,sha256=NSmo68oksZkzOoSGA5XKNVzqU0K3WIzkFN82EDLC-f8,168115
121
122
  reflex/components/el/elements/inline.py,sha256=q3Ku_x8L9NaXrYQovCfkWwZ5AfXG0VyhGN_OT73kA0Y,4126
122
123
  reflex/components/el/elements/inline.pyi,sha256=0pjqiHH8DmFfghbM8MK5tqgiZGSnfT-o055GINU8xrA,231760
@@ -138,8 +139,8 @@ reflex/components/gridjs/__init__.py,sha256=xJwDm1AZ70L5-t9LLqZwGUtDpijbf1KuMYDT
138
139
  reflex/components/gridjs/datatable.py,sha256=7JKrRw1zkpFB0_wwoaIhrVrldsm7-dyi3PASgqLq8Hc,4224
139
140
  reflex/components/gridjs/datatable.pyi,sha256=kFgv82vCgfdWZaUq4bZ73G8X3mkw6ecvSRkZ9G9-28E,5185
140
141
  reflex/components/lucide/__init__.py,sha256=EggTK2MuQKQeOBLKW-mF0VaDK9zdWBImu1HO2dvHZbE,73
141
- reflex/components/lucide/icon.py,sha256=GiNlTfoXE36J9ZAY9Kh7DogxM5jVliFi5VjZZ_8YObM,35292
142
- reflex/components/lucide/icon.pyi,sha256=PtN6ysOxDRtwlpt-YsXAKZpKipXmZBtbAt-FaGI6i4Q,38086
142
+ reflex/components/lucide/icon.py,sha256=wetRyx6HB5tAZ4ntAV5fbf3VuhkEj7zosoLStGYGjBA,35321
143
+ reflex/components/lucide/icon.pyi,sha256=7HEqYp0fGgNyi_nTrpCZNQSuEBnFEzJRb9pWTQKJ-dM,38115
143
144
  reflex/components/markdown/__init__.py,sha256=Dfl1At5uYoY7H4ufZU_RY2KOGQDLtj75dsZ2BTqqAns,87
144
145
  reflex/components/markdown/markdown.py,sha256=kzvO2VnfCbxV7AcIMBJbxLtAlQ6U5T_QB_JTh8l-HJ4,15450
145
146
  reflex/components/markdown/markdown.pyi,sha256=oOlXZItHB0TPWsFz1Qjvr3KzG8sssthBp40UO_KkRIA,4322
@@ -372,7 +373,7 @@ reflex/utils/templates.py,sha256=tWo3jO6laQX8b0gUsqHkio_hUQGIvFbmXC-lxiGcdRo,142
372
373
  reflex/utils/token_manager.py,sha256=o_HGbqT9WfYRmek2iY9nem4vDZMz8Q4Dra-eW1lKmuA,6999
373
374
  reflex/utils/types.py,sha256=Xh9jXSMBgwrR-Whn_5qAnjqQWzHiIJbm1b8qwMG4QmY,38511
374
375
  reflex/vars/__init__.py,sha256=85eXMt32bFoKtMdH3KxYRMD8mtnKyYiQcThPxJLoW1k,1359
375
- reflex/vars/base.py,sha256=hfcJ3x-BSFLgN85oBS0dPJb2IaoKJqQjguP1sy50NRY,113256
376
+ reflex/vars/base.py,sha256=CJT6SVtFDcBBpOtLw6jtszgZYifqeS3UJVsZ5y-BJQQ,113350
376
377
  reflex/vars/datetime.py,sha256=F2Jv_bfydipFSkIQ1F6x5MnSgFEyES9Vq5RG_uGH81E,5118
377
378
  reflex/vars/dep_tracking.py,sha256=LfDGgAGlqfC0DeiVcitRBcA1uCe1C3fNRARRekLgCz4,13738
378
379
  reflex/vars/function.py,sha256=0i-VkxHkDJmZtfQUwUfaF0rlS6WM8azjwQ8k7rEOkyk,13944
@@ -380,8 +381,8 @@ reflex/vars/number.py,sha256=tO7pnvFaBsedq1HWT4skytnSqHWMluGEhUbjAUMx8XQ,28190
380
381
  reflex/vars/object.py,sha256=YblDxQYMajR19a7qjavXcM7-9A6MweAH1giw5fjPci4,17349
381
382
  reflex/vars/sequence.py,sha256=1kBrqihspyjyQ1XDqFPC8OpVGtZs_EVkOdIKBro5ilA,55249
382
383
  scripts/hatch_build.py,sha256=-4pxcLSFmirmujGpQX9UUxjhIC03tQ_fIQwVbHu9kc0,1861
383
- reflex-0.8.9a2.dist-info/METADATA,sha256=xOp7-o3Rakin_ji0pTLZieiQ50RC99Xh0sf-Fy8pdj8,12507
384
- reflex-0.8.9a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
385
- reflex-0.8.9a2.dist-info/entry_points.txt,sha256=Rxt4dXc7MLBNt5CSHTehVPuSe9Xqow4HLX55nD9tQQ0,45
386
- reflex-0.8.9a2.dist-info/licenses/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
387
- reflex-0.8.9a2.dist-info/RECORD,,
384
+ reflex-0.8.10.dist-info/METADATA,sha256=3ska8-7YBaAwHA5LP77s80KPxvnbPsKt_NgPr6YEoFs,12334
385
+ reflex-0.8.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
386
+ reflex-0.8.10.dist-info/entry_points.txt,sha256=Rxt4dXc7MLBNt5CSHTehVPuSe9Xqow4HLX55nD9tQQ0,45
387
+ reflex-0.8.10.dist-info/licenses/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
388
+ reflex-0.8.10.dist-info/RECORD,,