reflex 0.4.2a1__py3-none-any.whl → 0.4.3a2__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.
- reflex/.templates/apps/blank/code/blank.py +1 -1
- reflex/.templates/apps/sidebar/README.md +3 -2
- reflex/.templates/apps/sidebar/assets/reflex_white.svg +8 -0
- reflex/.templates/apps/sidebar/code/components/sidebar.py +26 -22
- reflex/.templates/apps/sidebar/code/pages/dashboard.py +6 -5
- reflex/.templates/apps/sidebar/code/pages/settings.py +45 -6
- reflex/.templates/apps/sidebar/code/styles.py +15 -17
- reflex/.templates/apps/sidebar/code/templates/__init__.py +1 -1
- reflex/.templates/apps/sidebar/code/templates/template.py +54 -40
- reflex/.templates/jinja/custom_components/README.md.jinja2 +9 -0
- reflex/.templates/jinja/custom_components/__init__.py.jinja2 +1 -0
- reflex/.templates/jinja/custom_components/demo_app.py.jinja2 +36 -0
- reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +35 -0
- reflex/.templates/jinja/custom_components/src.py.jinja2 +57 -0
- reflex/.templates/jinja/web/utils/context.js.jinja2 +26 -6
- reflex/.templates/web/utils/state.js +206 -146
- reflex/app.py +21 -18
- reflex/compiler/compiler.py +6 -2
- reflex/compiler/templates.py +17 -0
- reflex/compiler/utils.py +2 -2
- reflex/components/core/__init__.py +2 -1
- reflex/components/core/banner.py +99 -11
- reflex/components/core/banner.pyi +215 -2
- reflex/components/el/elements/__init__.py +1 -0
- reflex/components/el/elements/forms.py +6 -0
- reflex/components/el/elements/forms.pyi +4 -0
- reflex/components/markdown/markdown.py +13 -25
- reflex/components/markdown/markdown.pyi +5 -5
- reflex/components/plotly/plotly.py +3 -0
- reflex/components/plotly/plotly.pyi +2 -0
- reflex/components/radix/primitives/drawer.py +3 -7
- reflex/components/radix/themes/components/select.py +4 -4
- reflex/components/radix/themes/components/text_field.pyi +4 -0
- reflex/constants/__init__.py +4 -0
- reflex/constants/colors.py +1 -0
- reflex/constants/compiler.py +4 -3
- reflex/constants/custom_components.py +30 -0
- reflex/custom_components/__init__.py +1 -0
- reflex/custom_components/custom_components.py +565 -0
- reflex/reflex.py +11 -2
- reflex/route.py +4 -0
- reflex/state.py +594 -124
- reflex/testing.py +6 -0
- reflex/utils/exec.py +9 -0
- reflex/utils/prerequisites.py +28 -2
- reflex/utils/telemetry.py +3 -1
- reflex/utils/types.py +23 -0
- reflex/vars.py +48 -17
- reflex/vars.pyi +8 -3
- {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/METADATA +4 -2
- {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/RECORD +55 -51
- {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/WHEEL +1 -1
- reflex/components/base/bare.pyi +0 -84
- reflex/constants/base.pyi +0 -94
- reflex/constants/event.pyi +0 -59
- reflex/constants/route.pyi +0 -50
- reflex/constants/style.pyi +0 -20
- /reflex/.templates/apps/sidebar/assets/{icon.svg → reflex_black.svg} +0 -0
- {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/LICENSE +0 -0
- {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/entry_points.txt +0 -0
|
@@ -41,7 +41,7 @@ See the [Project Structure docs](https://reflex.dev/docs/getting-started/project
|
|
|
41
41
|
In this template, the pages in your app are defined in `{your_app}/pages/`.
|
|
42
42
|
Each page is a function that returns a Reflex component.
|
|
43
43
|
For example, to edit this page you can modify `{your_app}/pages/index.py`.
|
|
44
|
-
See the [pages docs](https://reflex.dev/docs/
|
|
44
|
+
See the [pages docs](https://reflex.dev/docs/pages/routes/) for more information on pages.
|
|
45
45
|
|
|
46
46
|
In this template, instead of using `rx.add_page` or the `@rx.page` decorator,
|
|
47
47
|
we use the `@template` decorator from `{your_app}/templates/template.py`.
|
|
@@ -62,7 +62,8 @@ In this template, we have a sidebar component in `{your_app}/components/sidebar.
|
|
|
62
62
|
|
|
63
63
|
### Adding State
|
|
64
64
|
|
|
65
|
-
As your app grows, we recommend using [substates](https://reflex.dev/docs/
|
|
65
|
+
As your app grows, we recommend using [substates](https://reflex.dev/docs/substates/overview/)
|
|
66
66
|
to organize your state.
|
|
67
|
+
|
|
67
68
|
You can either define substates in their own files, or if the state is
|
|
68
69
|
specific to a page, you can define it in the page file itself.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg width="56" height="12" viewBox="0 0 56 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z" fill="white"/>
|
|
3
|
+
<path d="M11.2 11.5999V0.399902H17.92V2.6399H13.44V4.8799H17.92V7.1199H13.44V9.3599H17.92V11.5999H11.2Z" fill="white"/>
|
|
4
|
+
<path d="M20.16 11.5999V0.399902H26.88V2.6399H22.4V4.8799H26.88V7.1199H22.4V11.5999H20.16Z" fill="white"/>
|
|
5
|
+
<path d="M29.12 11.5999V0.399902H31.36V9.3599H35.84V11.5999H29.12Z" fill="white"/>
|
|
6
|
+
<path d="M38.08 11.5999V0.399902H44.8V2.6399H40.32V4.8799H44.8V7.1199H40.32V9.3599H44.8V11.5999H38.08Z" fill="white"/>
|
|
7
|
+
<path d="M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z" fill="white"/>
|
|
8
|
+
</svg>
|
|
@@ -11,17 +11,17 @@ def sidebar_header() -> rx.Component:
|
|
|
11
11
|
Returns:
|
|
12
12
|
The sidebar header component.
|
|
13
13
|
"""
|
|
14
|
-
return rx.
|
|
14
|
+
return rx.hstack(
|
|
15
15
|
# The logo.
|
|
16
|
-
rx.
|
|
17
|
-
src="/
|
|
18
|
-
height="2em",
|
|
16
|
+
rx.color_mode_cond(
|
|
17
|
+
rx.image(src="/reflex_black.svg", height="2em"),
|
|
18
|
+
rx.image(src="/reflex_white.svg", height="2em"),
|
|
19
19
|
),
|
|
20
|
-
rx.
|
|
20
|
+
rx.spacer(),
|
|
21
21
|
# Link to Reflex GitHub repo.
|
|
22
|
-
rx.
|
|
23
|
-
rx.
|
|
24
|
-
rx.
|
|
22
|
+
rx.link(
|
|
23
|
+
rx.center(
|
|
24
|
+
rx.image(
|
|
25
25
|
src="/github.svg",
|
|
26
26
|
height="3em",
|
|
27
27
|
padding="0.5em",
|
|
@@ -35,6 +35,7 @@ def sidebar_header() -> rx.Component:
|
|
|
35
35
|
),
|
|
36
36
|
href="https://github.com/reflex-dev/reflex",
|
|
37
37
|
),
|
|
38
|
+
align="center",
|
|
38
39
|
width="100%",
|
|
39
40
|
border_bottom=styles.border,
|
|
40
41
|
padding="1em",
|
|
@@ -47,15 +48,17 @@ def sidebar_footer() -> rx.Component:
|
|
|
47
48
|
Returns:
|
|
48
49
|
The sidebar footer component.
|
|
49
50
|
"""
|
|
50
|
-
return rx.
|
|
51
|
-
rx.
|
|
52
|
-
rx.
|
|
53
|
-
rx.
|
|
51
|
+
return rx.hstack(
|
|
52
|
+
rx.spacer(),
|
|
53
|
+
rx.link(
|
|
54
|
+
rx.text("Docs"),
|
|
54
55
|
href="https://reflex.dev/docs/getting-started/introduction/",
|
|
56
|
+
style=styles.link_style,
|
|
55
57
|
),
|
|
56
|
-
rx.
|
|
57
|
-
rx.
|
|
58
|
+
rx.link(
|
|
59
|
+
rx.text("Blog"),
|
|
58
60
|
href="https://reflex.dev/blog/",
|
|
61
|
+
style=styles.link_style,
|
|
59
62
|
),
|
|
60
63
|
width="100%",
|
|
61
64
|
border_top=styles.border,
|
|
@@ -79,14 +82,14 @@ def sidebar_item(text: str, icon: str, url: str) -> rx.Component:
|
|
|
79
82
|
(rx.State.router.page.path == "/") & text == "Home"
|
|
80
83
|
)
|
|
81
84
|
|
|
82
|
-
return rx.
|
|
83
|
-
rx.
|
|
84
|
-
rx.
|
|
85
|
+
return rx.link(
|
|
86
|
+
rx.hstack(
|
|
87
|
+
rx.image(
|
|
85
88
|
src=icon,
|
|
86
89
|
height="2.5em",
|
|
87
90
|
padding="0.5em",
|
|
88
91
|
),
|
|
89
|
-
rx.
|
|
92
|
+
rx.text(
|
|
90
93
|
text,
|
|
91
94
|
),
|
|
92
95
|
bg=rx.cond(
|
|
@@ -99,6 +102,7 @@ def sidebar_item(text: str, icon: str, url: str) -> rx.Component:
|
|
|
99
102
|
styles.accent_text_color,
|
|
100
103
|
styles.text_color,
|
|
101
104
|
),
|
|
105
|
+
align="center",
|
|
102
106
|
border_radius=styles.border_radius,
|
|
103
107
|
box_shadow=styles.box_shadow,
|
|
104
108
|
width="100%",
|
|
@@ -118,10 +122,10 @@ def sidebar() -> rx.Component:
|
|
|
118
122
|
# Get all the decorated pages and add them to the sidebar.
|
|
119
123
|
from reflex.page import get_decorated_pages
|
|
120
124
|
|
|
121
|
-
return rx.
|
|
122
|
-
rx.
|
|
125
|
+
return rx.box(
|
|
126
|
+
rx.vstack(
|
|
123
127
|
sidebar_header(),
|
|
124
|
-
rx.
|
|
128
|
+
rx.vstack(
|
|
125
129
|
*[
|
|
126
130
|
sidebar_item(
|
|
127
131
|
text=page.get("title", page["route"].strip("/").capitalize()),
|
|
@@ -135,7 +139,7 @@ def sidebar() -> rx.Component:
|
|
|
135
139
|
align_items="flex-start",
|
|
136
140
|
padding="1em",
|
|
137
141
|
),
|
|
138
|
-
rx.
|
|
142
|
+
rx.spacer(),
|
|
139
143
|
sidebar_footer(),
|
|
140
144
|
height="100dvh",
|
|
141
145
|
),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""The dashboard page."""
|
|
2
|
+
|
|
2
3
|
from code.templates import template
|
|
3
4
|
|
|
4
5
|
import reflex as rx
|
|
@@ -11,11 +12,11 @@ def dashboard() -> rx.Component:
|
|
|
11
12
|
Returns:
|
|
12
13
|
The UI for the dashboard page.
|
|
13
14
|
"""
|
|
14
|
-
return rx.
|
|
15
|
-
rx.
|
|
16
|
-
rx.
|
|
17
|
-
rx.
|
|
15
|
+
return rx.vstack(
|
|
16
|
+
rx.heading("Dashboard", size="8"),
|
|
17
|
+
rx.text("Welcome to Reflex!"),
|
|
18
|
+
rx.text(
|
|
18
19
|
"You can edit this page in ",
|
|
19
|
-
rx.
|
|
20
|
+
rx.code("{your_app}/pages/dashboard.py"),
|
|
20
21
|
),
|
|
21
22
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""The settings page."""
|
|
2
2
|
|
|
3
|
-
from code.templates import template
|
|
3
|
+
from code.templates import ThemeState, template
|
|
4
4
|
|
|
5
5
|
import reflex as rx
|
|
6
6
|
|
|
@@ -12,11 +12,50 @@ def settings() -> rx.Component:
|
|
|
12
12
|
Returns:
|
|
13
13
|
The UI for the settings page.
|
|
14
14
|
"""
|
|
15
|
-
return rx.
|
|
16
|
-
rx.
|
|
17
|
-
rx.
|
|
18
|
-
|
|
15
|
+
return rx.vstack(
|
|
16
|
+
rx.heading("Settings", size="8"),
|
|
17
|
+
rx.hstack(
|
|
18
|
+
rx.text("Dark mode: "),
|
|
19
|
+
rx.color_mode.switch(),
|
|
20
|
+
),
|
|
21
|
+
rx.hstack(
|
|
22
|
+
rx.text("Theme color: "),
|
|
23
|
+
rx.select(
|
|
24
|
+
[
|
|
25
|
+
"tomato",
|
|
26
|
+
"red",
|
|
27
|
+
"ruby",
|
|
28
|
+
"crimson",
|
|
29
|
+
"pink",
|
|
30
|
+
"plum",
|
|
31
|
+
"purple",
|
|
32
|
+
"violet",
|
|
33
|
+
"iris",
|
|
34
|
+
"indigo",
|
|
35
|
+
"blue",
|
|
36
|
+
"cyan",
|
|
37
|
+
"teal",
|
|
38
|
+
"jade",
|
|
39
|
+
"green",
|
|
40
|
+
"grass",
|
|
41
|
+
"brown",
|
|
42
|
+
"orange",
|
|
43
|
+
"sky",
|
|
44
|
+
"mint",
|
|
45
|
+
"lime",
|
|
46
|
+
"yellow",
|
|
47
|
+
"amber",
|
|
48
|
+
"gold",
|
|
49
|
+
"bronze",
|
|
50
|
+
"gray",
|
|
51
|
+
],
|
|
52
|
+
value=ThemeState.accent_color,
|
|
53
|
+
on_change=ThemeState.set_accent_color,
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
rx.text(
|
|
19
57
|
"You can edit this page in ",
|
|
20
|
-
rx.
|
|
58
|
+
rx.code("{your_app}/pages/settings.py"),
|
|
59
|
+
size="1",
|
|
21
60
|
),
|
|
22
61
|
)
|
|
@@ -4,12 +4,12 @@ import reflex as rx
|
|
|
4
4
|
|
|
5
5
|
border_radius = "0.375rem"
|
|
6
6
|
box_shadow = "0px 0px 0px 1px rgba(84, 82, 95, 0.14)"
|
|
7
|
-
border = "1px solid
|
|
8
|
-
text_color = "
|
|
9
|
-
accent_text_color = "
|
|
10
|
-
accent_color = "
|
|
11
|
-
hover_accent_color = {"_hover": {"color":
|
|
12
|
-
hover_accent_bg = {"_hover": {"
|
|
7
|
+
border = f"1px solid {rx.color('accent', 12)}"
|
|
8
|
+
text_color = rx.color("gray", 11)
|
|
9
|
+
accent_text_color = rx.color("accent", 10)
|
|
10
|
+
accent_color = rx.color("accent", 1)
|
|
11
|
+
hover_accent_color = {"_hover": {"color": accent_text_color}}
|
|
12
|
+
hover_accent_bg = {"_hover": {"background_color": accent_color}}
|
|
13
13
|
content_width_vw = "90vw"
|
|
14
14
|
sidebar_width = "20em"
|
|
15
15
|
|
|
@@ -24,7 +24,7 @@ template_content_style = {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
link_style = {
|
|
27
|
-
"color":
|
|
27
|
+
"color": accent_text_color,
|
|
28
28
|
"text_decoration": "none",
|
|
29
29
|
**hover_accent_color,
|
|
30
30
|
}
|
|
@@ -36,27 +36,25 @@ overlapping_button_style = {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
base_style = {
|
|
39
|
-
rx.
|
|
40
|
-
"width": "3em",
|
|
41
|
-
"height": "3em",
|
|
39
|
+
rx.menu.trigger: {
|
|
42
40
|
**overlapping_button_style,
|
|
43
41
|
},
|
|
44
|
-
rx.
|
|
42
|
+
rx.menu.item: hover_accent_bg,
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
markdown_style = {
|
|
48
|
-
"code": lambda text: rx.
|
|
49
|
-
"a": lambda text, **props: rx.
|
|
46
|
+
"code": lambda text: rx.code(text, color=accent_text_color, bg=accent_color),
|
|
47
|
+
"a": lambda text, **props: rx.link(
|
|
50
48
|
text,
|
|
51
49
|
**props,
|
|
52
50
|
font_weight="bold",
|
|
53
|
-
color=
|
|
51
|
+
color=accent_text_color,
|
|
54
52
|
text_decoration="underline",
|
|
55
|
-
text_decoration_color=
|
|
53
|
+
text_decoration_color=accent_text_color,
|
|
56
54
|
_hover={
|
|
57
|
-
"color":
|
|
55
|
+
"color": accent_color,
|
|
58
56
|
"text_decoration": "underline",
|
|
59
|
-
"text_decoration_color":
|
|
57
|
+
"text_decoration_color": accent_color,
|
|
60
58
|
},
|
|
61
59
|
),
|
|
62
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
from .template import template
|
|
1
|
+
from .template import ThemeState, template
|
|
@@ -17,6 +17,21 @@ default_meta = [
|
|
|
17
17
|
]
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
def menu_item_link(text, href):
|
|
21
|
+
return rx.menu.item(
|
|
22
|
+
rx.link(
|
|
23
|
+
text,
|
|
24
|
+
href=href,
|
|
25
|
+
width="100%",
|
|
26
|
+
color="inherit",
|
|
27
|
+
),
|
|
28
|
+
_hover={
|
|
29
|
+
"color": styles.accent_color,
|
|
30
|
+
"background_color": styles.accent_text_color,
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
20
35
|
def menu_button() -> rx.Component:
|
|
21
36
|
"""The menu button on the top right of the page.
|
|
22
37
|
|
|
@@ -25,37 +40,24 @@ def menu_button() -> rx.Component:
|
|
|
25
40
|
"""
|
|
26
41
|
from reflex.page import get_decorated_pages
|
|
27
42
|
|
|
28
|
-
return rx.
|
|
29
|
-
rx.
|
|
30
|
-
rx.
|
|
31
|
-
rx.
|
|
32
|
-
|
|
33
|
-
size=
|
|
34
|
-
color=styles.
|
|
43
|
+
return rx.box(
|
|
44
|
+
rx.menu.root(
|
|
45
|
+
rx.menu.trigger(
|
|
46
|
+
rx.icon(
|
|
47
|
+
"menu",
|
|
48
|
+
size=36,
|
|
49
|
+
color=styles.accent_text_color,
|
|
35
50
|
),
|
|
51
|
+
background_color=styles.accent_color,
|
|
36
52
|
),
|
|
37
|
-
rx.
|
|
53
|
+
rx.menu.content(
|
|
38
54
|
*[
|
|
39
|
-
|
|
40
|
-
rx.chakra.link(
|
|
41
|
-
page["title"],
|
|
42
|
-
href=page["route"],
|
|
43
|
-
width="100%",
|
|
44
|
-
)
|
|
45
|
-
)
|
|
55
|
+
menu_item_link(page["title"], page["route"])
|
|
46
56
|
for page in get_decorated_pages()
|
|
47
57
|
],
|
|
48
|
-
rx.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"About", href="https://github.com/reflex-dev", width="100%"
|
|
52
|
-
)
|
|
53
|
-
),
|
|
54
|
-
rx.chakra.menu_item(
|
|
55
|
-
rx.chakra.link(
|
|
56
|
-
"Contact", href="mailto:founders@=reflex.dev", width="100%"
|
|
57
|
-
)
|
|
58
|
-
),
|
|
58
|
+
rx.menu.separator(),
|
|
59
|
+
menu_item_link("About", "https://github.com/reflex-dev"),
|
|
60
|
+
menu_item_link("Contact", "mailto:founders@=reflex.dev"),
|
|
59
61
|
),
|
|
60
62
|
),
|
|
61
63
|
position="fixed",
|
|
@@ -65,6 +67,12 @@ def menu_button() -> rx.Component:
|
|
|
65
67
|
)
|
|
66
68
|
|
|
67
69
|
|
|
70
|
+
class ThemeState(rx.State):
|
|
71
|
+
"""The state for the theme of the app."""
|
|
72
|
+
|
|
73
|
+
accent_color: str = "crimson"
|
|
74
|
+
|
|
75
|
+
|
|
68
76
|
def template(
|
|
69
77
|
route: str | None = None,
|
|
70
78
|
title: str | None = None,
|
|
@@ -101,31 +109,37 @@ def template(
|
|
|
101
109
|
# Get the meta tags for the page.
|
|
102
110
|
all_meta = [*default_meta, *(meta or [])]
|
|
103
111
|
|
|
104
|
-
@rx.page(
|
|
105
|
-
route=route,
|
|
106
|
-
title=title,
|
|
107
|
-
image=image,
|
|
108
|
-
description=description,
|
|
109
|
-
meta=all_meta,
|
|
110
|
-
script_tags=script_tags,
|
|
111
|
-
on_load=on_load,
|
|
112
|
-
)
|
|
113
112
|
def templated_page():
|
|
114
|
-
return rx.
|
|
113
|
+
return rx.hstack(
|
|
115
114
|
sidebar(),
|
|
116
|
-
rx.
|
|
117
|
-
rx.
|
|
115
|
+
rx.box(
|
|
116
|
+
rx.box(
|
|
118
117
|
page_content(),
|
|
119
118
|
**styles.template_content_style,
|
|
120
119
|
),
|
|
121
120
|
**styles.template_page_style,
|
|
122
121
|
),
|
|
123
122
|
menu_button(),
|
|
124
|
-
|
|
123
|
+
align="start",
|
|
125
124
|
transition="left 0.5s, width 0.5s",
|
|
126
125
|
position="relative",
|
|
127
126
|
)
|
|
128
127
|
|
|
129
|
-
|
|
128
|
+
@rx.page(
|
|
129
|
+
route=route,
|
|
130
|
+
title=title,
|
|
131
|
+
image=image,
|
|
132
|
+
description=description,
|
|
133
|
+
meta=all_meta,
|
|
134
|
+
script_tags=script_tags,
|
|
135
|
+
on_load=on_load,
|
|
136
|
+
)
|
|
137
|
+
def theme_wrap():
|
|
138
|
+
return rx.theme(
|
|
139
|
+
templated_page(),
|
|
140
|
+
accent_color=ThemeState.accent_color,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return theme_wrap
|
|
130
144
|
|
|
131
145
|
return decorator
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .{{ module_name }} import *
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Welcome to Reflex! This file showcases the custom component in a basic app."""
|
|
2
|
+
|
|
3
|
+
from rxconfig import config
|
|
4
|
+
|
|
5
|
+
import reflex as rx
|
|
6
|
+
|
|
7
|
+
from {{ custom_component_module_dir }} import {{ module_name }}
|
|
8
|
+
|
|
9
|
+
filename = f"{config.app_name}/{config.app_name}.py"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class State(rx.State):
|
|
13
|
+
"""The app state."""
|
|
14
|
+
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def index() -> rx.Component:
|
|
19
|
+
return rx.center(
|
|
20
|
+
rx.theme_panel(),
|
|
21
|
+
rx.vstack(
|
|
22
|
+
rx.heading("Welcome to Reflex!", size="9"),
|
|
23
|
+
rx.text("Test your custom component by editing ", rx.code(filename)),
|
|
24
|
+
{{ module_name }}(),
|
|
25
|
+
align="center",
|
|
26
|
+
spacing="7",
|
|
27
|
+
font_size="2em",
|
|
28
|
+
),
|
|
29
|
+
height="100vh",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Add state and page to the app.
|
|
34
|
+
app = rx.App()
|
|
35
|
+
app.add_page(index)
|
|
36
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [
|
|
3
|
+
"setuptools",
|
|
4
|
+
"wheel",
|
|
5
|
+
]
|
|
6
|
+
build-backend = "setuptools.build_meta"
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "{{ package_name }}"
|
|
10
|
+
version = "0.0.1"
|
|
11
|
+
description = "Reflex custom component {{ module_name }}"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = { text = "Apache-2.0" }
|
|
14
|
+
requires-python = ">=3.8"
|
|
15
|
+
authors = [{ name = "Your Name", email = "YOUREMAIL@domain.com" }]
|
|
16
|
+
keywords = [
|
|
17
|
+
"reflex",
|
|
18
|
+
"reflex-custom-components"]
|
|
19
|
+
|
|
20
|
+
dependencies = [
|
|
21
|
+
"reflex>=0.4.2"
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Development Status :: 4 - Beta",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com"
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
dev = ["build", "twine"]
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
where = ["custom_components"]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Reflex custom component {{ component_class_name }}."""
|
|
2
|
+
|
|
3
|
+
# For wrapping react guide, visit https://reflex.dev/docs/wrapping-react/overview/
|
|
4
|
+
|
|
5
|
+
import reflex as rx
|
|
6
|
+
|
|
7
|
+
# Some libraries you may want to wrap may require dynamic imports.
|
|
8
|
+
# This is because they they may not be compatible with Server-Side Rendering (SSR).
|
|
9
|
+
# To handle this in Reflex all you need to do is subclass NoSSRComponent instead.
|
|
10
|
+
# For example:
|
|
11
|
+
# from reflex.components.component import NoSSRComponent
|
|
12
|
+
# class {{ component_class_name }}(NoSSRComponent):
|
|
13
|
+
# pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class {{ component_class_name }}(rx.Component):
|
|
17
|
+
"""{{ component_class_name }} component."""
|
|
18
|
+
|
|
19
|
+
# The React library to wrap.
|
|
20
|
+
library = "Fill-Me"
|
|
21
|
+
|
|
22
|
+
# The React component tag.
|
|
23
|
+
tag = "Fill-Me"
|
|
24
|
+
|
|
25
|
+
# If the tag is the default export from the module, you must set is_default = True.
|
|
26
|
+
# This is normally used when components don't have curly braces around them when importing.
|
|
27
|
+
# is_default = True
|
|
28
|
+
|
|
29
|
+
# If you are wrapping another components with the same tag as a component in your project
|
|
30
|
+
# you can use aliases to differentiate between them and avoid naming conflicts.
|
|
31
|
+
# alias = "Other{{ component_class_name }}"
|
|
32
|
+
|
|
33
|
+
# The props of the React component.
|
|
34
|
+
# Note: when Reflex compiles the component to Javascript,
|
|
35
|
+
# `snake_case` property names are automatically formatted as `camelCase`.
|
|
36
|
+
# The prop names may be defined in `camelCase` as well.
|
|
37
|
+
# some_prop: rx.Var[str] = "some default value"
|
|
38
|
+
# some_other_prop: rx.Var[int] = 1
|
|
39
|
+
|
|
40
|
+
# By default Reflex will install the library you have specified in the library property.
|
|
41
|
+
# However, sometimes you may need to install other libraries to use a component.
|
|
42
|
+
# In this case you can use the lib_dependencies property to specify other libraries to install.
|
|
43
|
+
# lib_dependencies: list[str] = []
|
|
44
|
+
|
|
45
|
+
# Event triggers, I did not understand the wording of the doc.
|
|
46
|
+
# def get_event_triggers(self) -> dict[str, Any]:
|
|
47
|
+
# return {
|
|
48
|
+
# **super().get_event_triggers(),
|
|
49
|
+
# "on_change": lambda e0: [e0],
|
|
50
|
+
# }
|
|
51
|
+
|
|
52
|
+
# To add custom code to your component
|
|
53
|
+
# def _get_custom_code(self) -> str:
|
|
54
|
+
# return "const customCode = 'customCode';"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
{{ module_name }} = {{ component_class_name }}.create
|
|
@@ -25,11 +25,31 @@ export const clientStorage = {}
|
|
|
25
25
|
|
|
26
26
|
{% if state_name %}
|
|
27
27
|
export const state_name = "{{state_name}}"
|
|
28
|
-
export const onLoadInternalEvent = () => [
|
|
29
|
-
Event('{{state_name}}.{{const.update_vars_internal}}', {vars: hydrateClientStorage(clientStorage)}),
|
|
30
|
-
Event('{{state_name}}.{{const.on_load_internal}}')
|
|
31
|
-
]
|
|
32
28
|
|
|
29
|
+
// Theses events are triggered on initial load and each page navigation.
|
|
30
|
+
export const onLoadInternalEvent = () => {
|
|
31
|
+
const internal_events = [];
|
|
32
|
+
|
|
33
|
+
// Get tracked cookie and local storage vars to send to the backend.
|
|
34
|
+
const client_storage_vars = hydrateClientStorage(clientStorage);
|
|
35
|
+
// But only send the vars if any are actually set in the browser.
|
|
36
|
+
if (client_storage_vars && Object.keys(client_storage_vars).length !== 0) {
|
|
37
|
+
internal_events.push(
|
|
38
|
+
Event(
|
|
39
|
+
'{{state_name}}.{{const.update_vars_internal}}',
|
|
40
|
+
{vars: client_storage_vars},
|
|
41
|
+
),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// `on_load_internal` triggers the correct on_load event(s) for the current page.
|
|
46
|
+
// If the page does not define any on_load event, this will just set `is_hydrated = true`.
|
|
47
|
+
internal_events.push(Event('{{state_name}}.{{const.on_load_internal}}'));
|
|
48
|
+
|
|
49
|
+
return internal_events;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The following events are sent when the websocket connects or reconnects.
|
|
33
53
|
export const initialEvents = () => [
|
|
34
54
|
Event('{{state_name}}.{{const.hydrate}}'),
|
|
35
55
|
...onLoadInternalEvent()
|
|
@@ -60,13 +80,13 @@ export function UploadFilesProvider({ children }) {
|
|
|
60
80
|
|
|
61
81
|
export function EventLoopProvider({ children }) {
|
|
62
82
|
const dispatch = useContext(DispatchContext)
|
|
63
|
-
const [addEvents,
|
|
83
|
+
const [addEvents, connectErrors] = useEventLoop(
|
|
64
84
|
dispatch,
|
|
65
85
|
initialEvents,
|
|
66
86
|
clientStorage,
|
|
67
87
|
)
|
|
68
88
|
return (
|
|
69
|
-
<EventLoopContext.Provider value={[addEvents,
|
|
89
|
+
<EventLoopContext.Provider value={[addEvents, connectErrors]}>
|
|
70
90
|
{children}
|
|
71
91
|
</EventLoopContext.Provider>
|
|
72
92
|
)
|