reflex 0.8.7a1__py3-none-any.whl → 0.8.8__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 (71) hide show
  1. reflex/.templates/web/utils/state.js +5 -5
  2. reflex/app.py +15 -7
  3. reflex/app_mixins/lifespan.py +8 -2
  4. reflex/compiler/compiler.py +14 -14
  5. reflex/compiler/templates.py +629 -102
  6. reflex/compiler/utils.py +30 -21
  7. reflex/components/base/bare.py +17 -0
  8. reflex/components/component.py +38 -34
  9. reflex/components/core/cond.py +6 -12
  10. reflex/components/core/foreach.py +1 -1
  11. reflex/components/core/match.py +83 -60
  12. reflex/components/dynamic.py +3 -3
  13. reflex/components/el/elements/forms.py +31 -14
  14. reflex/components/el/elements/forms.pyi +0 -5
  15. reflex/components/lucide/icon.py +2 -1
  16. reflex/components/lucide/icon.pyi +2 -1
  17. reflex/components/markdown/markdown.py +2 -2
  18. reflex/components/radix/primitives/accordion.py +1 -1
  19. reflex/components/radix/primitives/drawer.py +10 -22
  20. reflex/components/radix/primitives/drawer.pyi +4 -0
  21. reflex/components/radix/primitives/form.py +1 -1
  22. reflex/components/radix/primitives/slider.py +1 -1
  23. reflex/components/tags/cond_tag.py +14 -5
  24. reflex/components/tags/iter_tag.py +0 -26
  25. reflex/components/tags/match_tag.py +15 -6
  26. reflex/components/tags/tag.py +3 -6
  27. reflex/components/tags/tagless.py +14 -0
  28. reflex/constants/base.py +0 -2
  29. reflex/constants/compiler.py +1 -1
  30. reflex/constants/installer.py +4 -4
  31. reflex/custom_components/custom_components.py +202 -15
  32. reflex/event.py +1 -1
  33. reflex/experimental/client_state.py +1 -1
  34. reflex/istate/manager.py +2 -1
  35. reflex/plugins/shared_tailwind.py +87 -62
  36. reflex/plugins/tailwind_v3.py +2 -2
  37. reflex/plugins/tailwind_v4.py +4 -4
  38. reflex/state.py +5 -1
  39. reflex/utils/format.py +3 -4
  40. reflex/utils/frontend_skeleton.py +2 -2
  41. reflex/utils/imports.py +18 -0
  42. reflex/utils/pyi_generator.py +10 -2
  43. reflex/utils/telemetry.py +4 -1
  44. reflex/utils/templates.py +1 -6
  45. {reflex-0.8.7a1.dist-info → reflex-0.8.8.dist-info}/METADATA +3 -4
  46. {reflex-0.8.7a1.dist-info → reflex-0.8.8.dist-info}/RECORD +49 -71
  47. reflex/.templates/jinja/app/rxconfig.py.jinja2 +0 -9
  48. reflex/.templates/jinja/custom_components/README.md.jinja2 +0 -9
  49. reflex/.templates/jinja/custom_components/__init__.py.jinja2 +0 -1
  50. reflex/.templates/jinja/custom_components/demo_app.py.jinja2 +0 -39
  51. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +0 -25
  52. reflex/.templates/jinja/custom_components/src.py.jinja2 +0 -57
  53. reflex/.templates/jinja/web/package.json.jinja2 +0 -27
  54. reflex/.templates/jinja/web/pages/_app.js.jinja2 +0 -62
  55. reflex/.templates/jinja/web/pages/_document.js.jinja2 +0 -9
  56. reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -21
  57. reflex/.templates/jinja/web/pages/component.js.jinja2 +0 -2
  58. reflex/.templates/jinja/web/pages/custom_component.js.jinja2 +0 -22
  59. reflex/.templates/jinja/web/pages/index.js.jinja2 +0 -18
  60. reflex/.templates/jinja/web/pages/macros.js.jinja2 +0 -38
  61. reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +0 -15
  62. reflex/.templates/jinja/web/pages/stateful_components.js.jinja2 +0 -5
  63. reflex/.templates/jinja/web/pages/utils.js.jinja2 +0 -93
  64. reflex/.templates/jinja/web/styles/styles.css.jinja2 +0 -6
  65. reflex/.templates/jinja/web/utils/context.js.jinja2 +0 -129
  66. reflex/.templates/jinja/web/utils/theme.js.jinja2 +0 -1
  67. reflex/.templates/jinja/web/vite.config.js.jinja2 +0 -74
  68. reflex/components/core/client_side_routing.pyi +0 -68
  69. {reflex-0.8.7a1.dist-info → reflex-0.8.8.dist-info}/WHEEL +0 -0
  70. {reflex-0.8.7a1.dist-info → reflex-0.8.8.dist-info}/entry_points.txt +0 -0
  71. {reflex-0.8.7a1.dist-info → reflex-0.8.8.dist-info}/licenses/LICENSE +0 -0
@@ -415,7 +415,7 @@ export const applyRestEvent = async (event, socket, navigate, params) => {
415
415
  if (event.payload.files === undefined || event.payload.files.length === 0) {
416
416
  // Submit the event over the websocket to trigger the event handler.
417
417
  return await applyEvent(
418
- Event(event.name, { files: [] }),
418
+ ReflexEvent(event.name, { files: [] }),
419
419
  socket,
420
420
  navigate,
421
421
  params,
@@ -775,7 +775,7 @@ export const uploadFiles = async (
775
775
  * @param {string} handler The client handler to process event.
776
776
  * @returns The event object.
777
777
  */
778
- export const Event = (
778
+ export const ReflexEvent = (
779
779
  name,
780
780
  payload = {},
781
781
  event_actions = {},
@@ -987,7 +987,7 @@ export const useEventLoop = (
987
987
 
988
988
  window.onerror = function (msg, url, lineNo, columnNo, error) {
989
989
  addEvents([
990
- Event(`${exception_state_name}.handle_frontend_exception`, {
990
+ ReflexEvent(`${exception_state_name}.handle_frontend_exception`, {
991
991
  info: error.name + ": " + error.message + "\n" + error.stack,
992
992
  component_stack: "",
993
993
  }),
@@ -999,7 +999,7 @@ export const useEventLoop = (
999
999
  //https://github.com/mknichel/javascript-errors?tab=readme-ov-file#promise-rejection-events
1000
1000
  window.onunhandledrejection = function (event) {
1001
1001
  addEvents([
1002
- Event(`${exception_state_name}.handle_frontend_exception`, {
1002
+ ReflexEvent(`${exception_state_name}.handle_frontend_exception`, {
1003
1003
  info:
1004
1004
  event.reason?.name +
1005
1005
  ": " +
@@ -1072,7 +1072,7 @@ export const useEventLoop = (
1072
1072
  if (storage_to_state_map[e.key]) {
1073
1073
  const vars = {};
1074
1074
  vars[storage_to_state_map[e.key]] = e.newValue;
1075
- const event = Event(
1075
+ const event = ReflexEvent(
1076
1076
  `${state_name}.reflex___state____update_vars_internal_state.update_vars_internal`,
1077
1077
  { vars: vars },
1078
1078
  );
reflex/app.py CHANGED
@@ -12,6 +12,7 @@ import inspect
12
12
  import io
13
13
  import json
14
14
  import sys
15
+ import time
15
16
  import traceback
16
17
  import urllib.parse
17
18
  from collections.abc import (
@@ -1310,9 +1311,9 @@ class App(MiddlewareMixin, LifespanMixin):
1310
1311
  self.head_components,
1311
1312
  html_lang=self.html_lang,
1312
1313
  html_custom_attrs=(
1313
- {"suppressHydrationWarning": "true", **self.html_custom_attrs}
1314
+ {"suppressHydrationWarning": True, **self.html_custom_attrs}
1314
1315
  if self.html_custom_attrs
1315
- else {"suppressHydrationWarning": "true"}
1316
+ else {"suppressHydrationWarning": True}
1316
1317
  ),
1317
1318
  )
1318
1319
  )
@@ -1582,7 +1583,10 @@ class App(MiddlewareMixin, LifespanMixin):
1582
1583
  sid=state.router.session.session_id,
1583
1584
  )
1584
1585
 
1585
- task = asyncio.create_task(_coro())
1586
+ task = asyncio.create_task(
1587
+ _coro(),
1588
+ name=f"reflex_background_task|{event.name}|{time.time()}|{event.token}",
1589
+ )
1586
1590
  self._background_tasks.add(task)
1587
1591
  # Clean up task from background_tasks set when complete.
1588
1592
  task.add_done_callback(self._background_tasks.discard)
@@ -1727,7 +1731,8 @@ async def process(
1727
1731
  "reload",
1728
1732
  data=event,
1729
1733
  to=sid,
1730
- )
1734
+ ),
1735
+ name=f"reflex_emit_reload|{event.name}|{time.time()}|{event.token}",
1731
1736
  )
1732
1737
  return
1733
1738
  # re-assign only when the value is different
@@ -2028,7 +2033,8 @@ class EventNamespace(AsyncNamespace):
2028
2033
  if disconnect_token:
2029
2034
  # Use async cleanup through token manager
2030
2035
  task = asyncio.create_task(
2031
- self._token_manager.disconnect_token(disconnect_token, sid)
2036
+ self._token_manager.disconnect_token(disconnect_token, sid),
2037
+ name=f"reflex_disconnect_token|{disconnect_token}|{time.time()}",
2032
2038
  )
2033
2039
  # Don't await to avoid blocking disconnect, but handle potential errors
2034
2040
  task.add_done_callback(
@@ -2047,12 +2053,14 @@ class EventNamespace(AsyncNamespace):
2047
2053
  # If the sid is None, we are not connected to a client. Prevent sending
2048
2054
  # updates to all clients.
2049
2055
  return
2050
- if sid not in self.sid_to_token:
2056
+ token = self.sid_to_token.get(sid)
2057
+ if token is None:
2051
2058
  console.warn(f"Attempting to send delta to disconnected websocket {sid}")
2052
2059
  return
2053
2060
  # Creating a task prevents the update from being blocked behind other coroutines.
2054
2061
  await asyncio.create_task(
2055
- self.emit(str(constants.SocketEvent.EVENT), update, to=sid)
2062
+ self.emit(str(constants.SocketEvent.EVENT), update, to=sid),
2063
+ name=f"reflex_emit_event|{token}|{sid}|{time.time()}",
2056
2064
  )
2057
2065
 
2058
2066
  async def on_event(self, sid: str, data: Any):
@@ -7,6 +7,7 @@ import contextlib
7
7
  import dataclasses
8
8
  import functools
9
9
  import inspect
10
+ import time
10
11
  from collections.abc import Callable, Coroutine
11
12
 
12
13
  from starlette.applications import Starlette
@@ -36,6 +37,7 @@ class LifespanMixin(AppMixin):
36
37
  if isinstance(task, asyncio.Task):
37
38
  running_tasks.append(task)
38
39
  else:
40
+ task_name = task.__name__
39
41
  signature = inspect.signature(task)
40
42
  if "app" in signature.parameters:
41
43
  task = functools.partial(task, app=app)
@@ -44,7 +46,10 @@ class LifespanMixin(AppMixin):
44
46
  await stack.enter_async_context(_t)
45
47
  console.debug(run_msg.format(type="asynccontextmanager"))
46
48
  elif isinstance(_t, Coroutine):
47
- task_ = asyncio.create_task(_t)
49
+ task_ = asyncio.create_task(
50
+ _t,
51
+ name=f"reflex_lifespan_task|{task_name}|{time.time()}",
52
+ )
48
53
  task_.add_done_callback(lambda t: t.result())
49
54
  running_tasks.append(task_)
50
55
  console.debug(run_msg.format(type="coroutine"))
@@ -70,9 +75,10 @@ class LifespanMixin(AppMixin):
70
75
  msg = f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager."
71
76
  raise InvalidLifespanTaskTypeError(msg)
72
77
 
78
+ task_name = task.__name__ # pyright: ignore [reportAttributeAccessIssue]
73
79
  if task_kwargs:
74
80
  original_task = task
75
81
  task = functools.partial(task, **task_kwargs) # pyright: ignore [reportArgumentType]
76
82
  functools.update_wrapper(task, original_task) # pyright: ignore [reportArgumentType]
77
83
  self.lifespan_tasks.add(task)
78
- console.debug(f"Registered lifespan task: {task.__name__}") # pyright: ignore [reportAttributeAccessIssue]
84
+ console.debug(f"Registered lifespan task: {task_name}")
@@ -6,7 +6,7 @@ import sys
6
6
  from collections.abc import Callable, Iterable, Sequence
7
7
  from inspect import getmodule
8
8
  from pathlib import Path
9
- from typing import TYPE_CHECKING
9
+ from typing import TYPE_CHECKING, Any
10
10
 
11
11
  from reflex import constants
12
12
  from reflex.compiler import templates, utils
@@ -53,7 +53,7 @@ def _compile_document_root(root: Component) -> str:
53
53
  """
54
54
  document_root_imports = root._get_all_imports()
55
55
  _apply_common_imports(document_root_imports)
56
- return templates.DOCUMENT_ROOT.render(
56
+ return templates.document_root_template(
57
57
  imports=utils.compile_imports(document_root_imports),
58
58
  document=root.render(),
59
59
  )
@@ -93,7 +93,7 @@ def _compile_app(app_root: Component) -> str:
93
93
  app_root_imports = app_root._get_all_imports()
94
94
  _apply_common_imports(app_root_imports)
95
95
 
96
- return templates.APP_ROOT.render(
96
+ return templates.app_root_template(
97
97
  imports=utils.compile_imports(app_root_imports),
98
98
  custom_codes=app_root._get_all_custom_code(),
99
99
  hooks=app_root._get_all_hooks(),
@@ -112,7 +112,7 @@ def _compile_theme(theme: str) -> str:
112
112
  Returns:
113
113
  The compiled theme.
114
114
  """
115
- return templates.THEME.render(theme=theme)
115
+ return templates.theme_template(theme=theme)
116
116
 
117
117
 
118
118
  def _compile_contexts(state: type[BaseState] | None, theme: Component | None) -> str:
@@ -130,17 +130,17 @@ def _compile_contexts(state: type[BaseState] | None, theme: Component | None) ->
130
130
  appearance = LiteralVar.create(SYSTEM_COLOR_MODE)
131
131
 
132
132
  return (
133
- templates.CONTEXT.render(
133
+ templates.context_template(
134
134
  initial_state=utils.compile_state(state),
135
135
  state_name=state.get_name(),
136
136
  client_storage=utils.compile_client_storage(state),
137
137
  is_dev_mode=not is_prod_mode(),
138
- default_color_mode=appearance,
138
+ default_color_mode=str(appearance),
139
139
  )
140
140
  if state
141
- else templates.CONTEXT.render(
141
+ else templates.context_template(
142
142
  is_dev_mode=not is_prod_mode(),
143
- default_color_mode=appearance,
143
+ default_color_mode=str(appearance),
144
144
  )
145
145
  )
146
146
 
@@ -159,7 +159,7 @@ def _compile_page(component: BaseComponent) -> str:
159
159
  imports = utils.compile_imports(imports)
160
160
 
161
161
  # Compile the code to render the component.
162
- return templates.PAGE.render(
162
+ return templates.page_template(
163
163
  imports=imports,
164
164
  dynamic_imports=component._get_all_dynamic_imports(),
165
165
  custom_codes=component._get_all_custom_code(),
@@ -321,7 +321,7 @@ def _compile_root_stylesheet(stylesheets: list[str], reset_style: bool = True) -
321
321
  'The `libsass` package is required to compile sass/scss stylesheet files. Run `pip install "libsass>=0.23.0"`.'
322
322
  )
323
323
 
324
- return templates.STYLE.render(stylesheets=sheets)
324
+ return templates.styles_template(stylesheets=sheets)
325
325
 
326
326
 
327
327
  def _compile_component(component: Component | StatefulComponent) -> str:
@@ -333,7 +333,7 @@ def _compile_component(component: Component | StatefulComponent) -> str:
333
333
  Returns:
334
334
  The compiled component.
335
335
  """
336
- return templates.COMPONENT.render(component=component)
336
+ return templates.component_template(component=component)
337
337
 
338
338
 
339
339
  def _compile_components(
@@ -376,7 +376,7 @@ def _compile_components(
376
376
 
377
377
  # Compile the components page.
378
378
  return (
379
- templates.COMPONENTS.render(
379
+ templates.custom_component_template(
380
380
  imports=utils.compile_imports(imports),
381
381
  components=component_renders,
382
382
  dynamic_imports=dynamic_imports,
@@ -456,7 +456,7 @@ def _compile_stateful_components(
456
456
  if rendered_components:
457
457
  _apply_common_imports(all_imports)
458
458
 
459
- return templates.STATEFUL_COMPONENTS.render(
459
+ return templates.stateful_components_template(
460
460
  imports=utils.compile_imports(all_imports),
461
461
  memoized_code="\n".join(rendered_components),
462
462
  )
@@ -465,7 +465,7 @@ def _compile_stateful_components(
465
465
  def compile_document_root(
466
466
  head_components: list[Component],
467
467
  html_lang: str | None = None,
468
- html_custom_attrs: dict[str, Var | str] | None = None,
468
+ html_custom_attrs: dict[str, Var | Any] | None = None,
469
469
  ) -> tuple[str, str]:
470
470
  """Compile the document root.
471
471