Skip to content

Commit 9faa30c

Browse files
committed
Merge remote-tracking branch 'origin/main' into masenf/background-never-resets-event-processing
2 parents d1284bf + e53b65d commit 9faa30c

File tree

21 files changed

+409
-254
lines changed

21 files changed

+409
-254
lines changed

README.md

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,50 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu
3939

4040
## ⚙️ Installation
4141

42-
Open a terminal and run (Requires Python 3.10+):
43-
44-
```bash
45-
pip install reflex
46-
```
42+
**Important:** We strongly recommend using a virtual environment to ensure the `reflex` command is available in your PATH.
4743

4844
## 🥳 Create your first app
4945

50-
Installing `reflex` also installs the `reflex` command line tool.
46+
### 1. Create the project directory
5147

52-
Test that the install was successful by creating a new project. (Replace `my_app_name` with your project name):
48+
Replace `my_app_name` with your project name:
5349

5450
```bash
5551
mkdir my_app_name
5652
cd my_app_name
53+
```
54+
55+
### 2. Set up a virtual environment
56+
57+
Create and activate virtual environment
58+
59+
```bash
60+
# On Windows:
61+
python -m venv .venv
62+
.venv\Scripts\activate
63+
64+
# On macOS/Linux:
65+
python3 -m venv .venv
66+
source .venv/bin/activate
67+
```
68+
69+
### 3. Install Reflex
70+
71+
Reflex is available as a pip package (Requires Python 3.10+):
72+
73+
```bash
74+
pip install reflex
75+
```
76+
77+
### 4. Initialize the project
78+
79+
This command initializes a template app in your new directory:
80+
81+
```bash
5782
reflex init
5883
```
5984

60-
This command initializes a template app in your new directory.
85+
### 5. Run the app
6186

6287
You can run this app in development mode:
6388

@@ -69,6 +94,10 @@ You should see your app running at http://localhost:3000.
6994

7095
Now you can modify the source code in `my_app_name/my_app_name.py`. Reflex has fast refreshes so you can see your changes instantly when you save your code.
7196

97+
### Troubleshooting
98+
99+
If you installed Reflex without a virtual environment and the `reflex` command is not found, you can run commands using: `python3 -m reflex init` and `python3 -m reflex run`
100+
72101
## 🫧 Example App
73102

74103
Let's go over an example: creating an image generation UI around [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). For simplicity, we just call the [OpenAI API](https://platform.openai.com/docs/api-reference/authentication), but you could replace this with an ML model run locally.

pyi_hashes.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"reflex/components/core/html.pyi": "86eb9d4c1bb4807547b2950d9a32e9fd",
2121
"reflex/components/core/sticky.pyi": "cb763b986a9b0654d1a3f33440dfcf60",
2222
"reflex/components/core/upload.pyi": "6dc28804a6dddf903e31162e87c1b023",
23-
"reflex/components/core/window_events.pyi": "76bf03a273a1fbbb3b333e10d5d08c30",
23+
"reflex/components/core/window_events.pyi": "af33ccec866b9540ee7fbec6dbfbd151",
2424
"reflex/components/datadisplay/__init__.pyi": "52755871369acbfd3a96b46b9a11d32e",
2525
"reflex/components/datadisplay/code.pyi": "b86769987ef4d1cbdddb461be88539fd",
2626
"reflex/components/datadisplay/dataeditor.pyi": "35391d4ba147cf20ce4ac7a782066d61",
@@ -39,7 +39,7 @@
3939
"reflex/components/el/elements/tables.pyi": "686eb70ea7d8c4dafb0cc5c284e76184",
4040
"reflex/components/el/elements/typography.pyi": "684e83dde887dba12badd0fb75c87c04",
4141
"reflex/components/gridjs/datatable.pyi": "98a7e1b3f3b60cafcdfcd8879750ee42",
42-
"reflex/components/lucide/icon.pyi": "ecaa40d72315ff4b8577f22c1537c0f3",
42+
"reflex/components/lucide/icon.pyi": "cc0bbb10e53b339b8c8f10c00996768c",
4343
"reflex/components/markdown/markdown.pyi": "2f84254a548e908020949564fc289339",
4444
"reflex/components/moment/moment.pyi": "e1952f1c2c82cef85d91e970d1be64ab",
4545
"reflex/components/plotly/plotly.pyi": "4311a0aae2abcc9226abb6a273f96372",

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "reflex"
3-
version = "0.8.16dev1"
3+
version = "0.8.17dev1"
44
description = "Web apps in pure Python."
55
license.text = "Apache-2.0"
66
authors = [
@@ -31,12 +31,12 @@ dependencies = [
3131
"python-multipart >=0.0.20,<1.0",
3232
"python-socketio >=5.12.0,<6.0",
3333
"redis >=5.2.1,<7.0",
34-
"reflex-hosting-cli >=0.1.55",
34+
"reflex-hosting-cli >=0.1.57",
3535
"rich >=13,<15",
3636
"sqlmodel >=0.0.27,<0.1",
3737
"starlette >=0.47.0",
3838
"typing_extensions >=4.13.0",
39-
"wrapt >=1.17.0,<2.0",
39+
"wrapt >=1.17.0,<3.0",
4040
]
4141

4242
classifiers = [
@@ -243,7 +243,7 @@ fail_fast = true
243243

244244
[[tool.pre-commit.repos]]
245245
repo = "https://github.com/astral-sh/ruff-pre-commit"
246-
rev = "v0.14.0"
246+
rev = "v0.14.1"
247247
hooks = [
248248
{ id = "ruff-format", args = [
249249
"reflex",

reflex/app.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1764,7 +1764,9 @@ async def process(
17641764
constants.RouteVar.CLIENT_IP: client_ip,
17651765
})
17661766
# Get the state for the session exclusively.
1767-
async with app.state_manager.modify_state(event.substate_token) as state:
1767+
async with app.state_manager.modify_state(
1768+
event.substate_token, event=event
1769+
) as state:
17681770
# When this is a brand new instance of the state, signal the
17691771
# frontend to reload before processing it.
17701772
if (

reflex/components/core/window_events.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
"""Window event listener component for Reflex."""
22

3+
from __future__ import annotations
4+
5+
from typing import Any, cast
6+
37
import reflex as rx
48
from reflex.components.base.fragment import Fragment
9+
from reflex.components.component import StatefulComponent, field
510
from reflex.constants.compiler import Hooks
611
from reflex.event import key_event, no_args_event_spec
712
from reflex.vars.base import Var, VarData
@@ -61,6 +66,23 @@ class WindowEventListener(Fragment):
6166
on_popstate: rx.EventHandler[no_args_event_spec]
6267
on_storage: rx.EventHandler[_on_storage_spec]
6368

69+
hooks: list[str] = field(default_factory=list, is_javascript_property=False)
70+
71+
@classmethod
72+
def create(cls, **props) -> WindowEventListener:
73+
"""Create a WindowEventListener component.
74+
75+
Args:
76+
**props: The props to set on the component.
77+
78+
Returns:
79+
The created component.
80+
"""
81+
real_component = cast("WindowEventListener", super().create(**props))
82+
hooks = StatefulComponent._fix_event_triggers(real_component)
83+
real_component.hooks = hooks
84+
return real_component
85+
6486
def _exclude_props(self) -> list[str]:
6587
"""Exclude event handler props from being passed to Fragment.
6688
@@ -69,31 +91,30 @@ def _exclude_props(self) -> list[str]:
6991
"""
7092
return [*super()._exclude_props(), *self.event_triggers.keys()]
7193

72-
def add_hooks(self) -> list[str | Var[str]]:
94+
def add_hooks(self) -> list[str | Var[Any]]:
7395
"""Add hooks to register window event listeners.
7496
7597
Returns:
7698
The hooks to add to the component.
7799
"""
78-
hooks = []
100+
hooks: list[str | Var[Any]] = [*self.hooks]
79101

80102
for prop_name, event_trigger in self.event_triggers.items():
81103
# Get JS event name: remove on_ prefix and underscores
82104
event_name = prop_name.removeprefix("on_").replace("_", "")
83105

84106
hook_expr = f"""
85-
useEffect(() => {{
86-
if (typeof window === 'undefined') return;
87-
88-
window.addEventListener('{event_name}', {event_trigger});
89-
return () => window.removeEventListener('{event_name}', {event_trigger});
90-
}}, []);
107+
useEffect(() => {{
108+
if (typeof window === 'undefined') return;
109+
const fn = {Var.create(event_trigger)};
110+
window.addEventListener('{event_name}', fn);
111+
return () => window.removeEventListener('{event_name}', fn);
112+
}}, []);
91113
"""
92114

93115
hooks.append(
94116
Var(
95117
hook_expr,
96-
_var_type="str",
97118
_var_data=VarData(position=Hooks.HookPosition.POST_TRIGGER),
98119
)
99120
)

reflex/components/lucide/icon.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from reflex.vars.base import LiteralVar, Var
77
from reflex.vars.sequence import LiteralStringVar, StringVar
88

9-
LUCIDE_LIBRARY = "lucide-react@0.545.0"
9+
LUCIDE_LIBRARY = "lucide-react@0.546.0"
1010

1111

1212
class LucideIconComponent(Component):
@@ -1115,6 +1115,7 @@ def _get_imports(self):
11151115
"minimize",
11161116
"minus",
11171117
"monitor_check",
1118+
"monitor_cloud",
11181119
"monitor_cog",
11191120
"monitor_dot",
11201121
"monitor_down",

reflex/components/plotly/plotly.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class Plotly(NoSSRComponent):
7272

7373
library = "[email protected]"
7474

75-
lib_dependencies: list[str] = ["[email protected].1"]
75+
lib_dependencies: list[str] = ["[email protected].2"]
7676

7777
tag = "Plot"
7878

@@ -303,7 +303,7 @@ class PlotlyBasic(Plotly):
303303

304304
library = "[email protected]"
305305

306-
lib_dependencies: list[str] = ["[email protected].1"]
306+
lib_dependencies: list[str] = ["[email protected].2"]
307307

308308
def add_imports(self) -> ImportDict | list[ImportDict]:
309309
"""Add imports for the plotly basic component.
@@ -329,7 +329,7 @@ class PlotlyCartesian(Plotly):
329329

330330
library = "[email protected]"
331331

332-
lib_dependencies: list[str] = ["[email protected].1"]
332+
lib_dependencies: list[str] = ["[email protected].2"]
333333

334334
def add_imports(self) -> ImportDict | list[ImportDict]:
335335
"""Add imports for the plotly cartesian component.
@@ -355,7 +355,7 @@ class PlotlyGeo(Plotly):
355355

356356
library = "[email protected]"
357357

358-
lib_dependencies: list[str] = ["[email protected].1"]
358+
lib_dependencies: list[str] = ["[email protected].2"]
359359

360360
def add_imports(self) -> ImportDict | list[ImportDict]:
361361
"""Add imports for the plotly geo component.
@@ -381,7 +381,7 @@ class PlotlyGl3d(Plotly):
381381

382382
library = "[email protected]"
383383

384-
lib_dependencies: list[str] = ["[email protected].1"]
384+
lib_dependencies: list[str] = ["[email protected].2"]
385385

386386
def add_imports(self) -> ImportDict | list[ImportDict]:
387387
"""Add imports for the plotly 3d component.
@@ -407,7 +407,7 @@ class PlotlyGl2d(Plotly):
407407

408408
library = "[email protected]"
409409

410-
lib_dependencies: list[str] = ["[email protected].1"]
410+
lib_dependencies: list[str] = ["[email protected].2"]
411411

412412
def add_imports(self) -> ImportDict | list[ImportDict]:
413413
"""Add imports for the plotly 2d component.
@@ -433,7 +433,7 @@ class PlotlyMapbox(Plotly):
433433

434434
library = "[email protected]"
435435

436-
lib_dependencies: list[str] = ["[email protected].1"]
436+
lib_dependencies: list[str] = ["[email protected].2"]
437437

438438
def add_imports(self) -> ImportDict | list[ImportDict]:
439439
"""Add imports for the plotly mapbox component.
@@ -459,7 +459,7 @@ class PlotlyFinance(Plotly):
459459

460460
library = "[email protected]"
461461

462-
lib_dependencies: list[str] = ["[email protected].1"]
462+
lib_dependencies: list[str] = ["[email protected].2"]
463463

464464
def add_imports(self) -> ImportDict | list[ImportDict]:
465465
"""Add imports for the plotly finance component.
@@ -485,7 +485,7 @@ class PlotlyStrict(Plotly):
485485

486486
library = "[email protected]"
487487

488-
lib_dependencies: list[str] = ["[email protected].1"]
488+
lib_dependencies: list[str] = ["[email protected].2"]
489489

490490
def add_imports(self) -> ImportDict | list[ImportDict]:
491491
"""Add imports for the plotly strict component.

reflex/components/radix/primitives/dialog.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ class DialogTrigger(DialogElement, RadixPrimitiveTriggerComponent):
7373

7474
_memoization_mode = MemoizationMode(recursive=False)
7575

76+
_valid_parents = ["DialogRoot"]
77+
7678

7779
class DialogContent(elements.Div, DialogElement):
7880
"""Content component to display inside a Dialog modal."""

reflex/components/recharts/recharts.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class Recharts(Component):
99
"""A component that wraps a recharts lib."""
1010

11-
library = "recharts@3.2.1"
11+
library = "recharts@3.3.0"
1212

1313
def _get_style(self) -> dict:
1414
return {"wrapperStyle": self.style}
@@ -17,7 +17,7 @@ def _get_style(self) -> dict:
1717
class RechartsCharts(NoSSRComponent, MemoizationLeaf):
1818
"""A component that wraps a recharts lib."""
1919

20-
library = "recharts@3.2.1"
20+
library = "recharts@3.3.0"
2121

2222

2323
LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"]

reflex/constants/installer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,11 @@ def DEPENDENCIES(cls) -> dict[str, str]:
143143
"postcss-import": "16.1.1",
144144
"@react-router/dev": _react_router_version,
145145
"@react-router/fs-routes": _react_router_version,
146-
"vite": "npm:[email protected].17",
146+
"vite": "npm:[email protected].18",
147147
}
148148
OVERRIDES = {
149149
# This should always match the `react` version in DEPENDENCIES for recharts compatibility.
150150
"react-is": _react_version,
151151
"cookie": "1.0.2",
152-
"vite": "npm:[email protected].17",
152+
"vite": "npm:[email protected].18",
153153
}

0 commit comments

Comments
 (0)