reflex 0.8.7__py3-none-any.whl → 0.8.8a1__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/app.py +13 -5
- reflex/app_mixins/lifespan.py +8 -2
- reflex/compiler/compiler.py +12 -12
- reflex/compiler/templates.py +629 -102
- reflex/compiler/utils.py +29 -20
- reflex/components/base/bare.py +17 -0
- reflex/components/component.py +37 -33
- reflex/components/core/cond.py +6 -12
- reflex/components/core/foreach.py +1 -1
- reflex/components/core/match.py +83 -60
- reflex/components/dynamic.py +3 -3
- reflex/components/el/elements/forms.py +31 -14
- reflex/components/el/elements/forms.pyi +0 -5
- reflex/components/lucide/icon.py +2 -1
- reflex/components/lucide/icon.pyi +2 -1
- reflex/components/markdown/markdown.py +2 -2
- reflex/components/radix/primitives/accordion.py +1 -1
- reflex/components/radix/primitives/drawer.py +1 -1
- reflex/components/radix/primitives/form.py +1 -1
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/tags/cond_tag.py +14 -5
- reflex/components/tags/iter_tag.py +0 -26
- reflex/components/tags/match_tag.py +15 -6
- reflex/components/tags/tag.py +3 -6
- reflex/components/tags/tagless.py +14 -0
- reflex/constants/base.py +0 -2
- reflex/constants/installer.py +4 -4
- reflex/custom_components/custom_components.py +202 -15
- reflex/experimental/client_state.py +1 -1
- reflex/istate/manager.py +2 -1
- reflex/plugins/shared_tailwind.py +87 -62
- reflex/plugins/tailwind_v3.py +2 -2
- reflex/plugins/tailwind_v4.py +4 -4
- reflex/state.py +5 -1
- reflex/utils/format.py +2 -3
- reflex/utils/frontend_skeleton.py +2 -2
- reflex/utils/imports.py +18 -0
- reflex/utils/pyi_generator.py +10 -2
- reflex/utils/telemetry.py +4 -1
- reflex/utils/templates.py +1 -6
- {reflex-0.8.7.dist-info → reflex-0.8.8a1.dist-info}/METADATA +3 -4
- {reflex-0.8.7.dist-info → reflex-0.8.8a1.dist-info}/RECORD +45 -66
- reflex/.templates/jinja/app/rxconfig.py.jinja2 +0 -9
- reflex/.templates/jinja/custom_components/README.md.jinja2 +0 -9
- reflex/.templates/jinja/custom_components/__init__.py.jinja2 +0 -1
- reflex/.templates/jinja/custom_components/demo_app.py.jinja2 +0 -39
- reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +0 -25
- reflex/.templates/jinja/custom_components/src.py.jinja2 +0 -57
- reflex/.templates/jinja/web/package.json.jinja2 +0 -27
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +0 -62
- reflex/.templates/jinja/web/pages/_document.js.jinja2 +0 -9
- reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -21
- reflex/.templates/jinja/web/pages/component.js.jinja2 +0 -2
- reflex/.templates/jinja/web/pages/custom_component.js.jinja2 +0 -22
- reflex/.templates/jinja/web/pages/index.js.jinja2 +0 -18
- reflex/.templates/jinja/web/pages/macros.js.jinja2 +0 -38
- reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +0 -15
- reflex/.templates/jinja/web/pages/stateful_components.js.jinja2 +0 -5
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +0 -93
- reflex/.templates/jinja/web/styles/styles.css.jinja2 +0 -6
- reflex/.templates/jinja/web/utils/context.js.jinja2 +0 -129
- reflex/.templates/jinja/web/utils/theme.js.jinja2 +0 -1
- reflex/.templates/jinja/web/vite.config.js.jinja2 +0 -74
- {reflex-0.8.7.dist-info → reflex-0.8.8a1.dist-info}/WHEEL +0 -0
- {reflex-0.8.7.dist-info → reflex-0.8.8a1.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.7.dist-info → reflex-0.8.8a1.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,8 +6,6 @@ from collections.abc import Iterator
|
|
|
6
6
|
from hashlib import md5
|
|
7
7
|
from typing import Any, ClassVar, Literal
|
|
8
8
|
|
|
9
|
-
from jinja2 import Environment
|
|
10
|
-
|
|
11
9
|
from reflex.components.el.element import Element
|
|
12
10
|
from reflex.components.tags.tag import Tag
|
|
13
11
|
from reflex.constants import Dirs, EventTriggers
|
|
@@ -31,21 +29,40 @@ from reflex.vars.number import ternary_operation
|
|
|
31
29
|
|
|
32
30
|
from .base import BaseHTML
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
|
|
33
|
+
def _handle_submit_js_template(
|
|
34
|
+
handle_submit_unique_name: str,
|
|
35
|
+
form_data: str,
|
|
36
|
+
field_ref_mapping: str,
|
|
37
|
+
on_submit_event_chain: str,
|
|
38
|
+
reset_on_submit: str,
|
|
39
|
+
) -> str:
|
|
40
|
+
"""Generate handle submit JS using f-string formatting.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
handle_submit_unique_name: Unique name for the handle submit function.
|
|
44
|
+
form_data: Name of the form data variable.
|
|
45
|
+
field_ref_mapping: JSON string of field reference mappings.
|
|
46
|
+
on_submit_event_chain: Event chain for the submit handler.
|
|
47
|
+
reset_on_submit: Boolean string indicating if form should reset after submit.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
JavaScript code for the form submit handler.
|
|
35
51
|
"""
|
|
36
|
-
|
|
52
|
+
return f"""
|
|
53
|
+
const handleSubmit_{handle_submit_unique_name} = useCallback((ev) => {{
|
|
37
54
|
const $form = ev.target
|
|
38
55
|
ev.preventDefault()
|
|
39
|
-
const {
|
|
56
|
+
const {form_data} = {{...Object.fromEntries(new FormData($form).entries()), ...{field_ref_mapping}}};
|
|
40
57
|
|
|
41
|
-
({
|
|
58
|
+
({on_submit_event_chain}(ev));
|
|
42
59
|
|
|
43
|
-
if ({
|
|
60
|
+
if ({reset_on_submit}) {{
|
|
44
61
|
$form.reset()
|
|
45
|
-
}
|
|
46
|
-
})
|
|
62
|
+
}}
|
|
63
|
+
}})
|
|
47
64
|
"""
|
|
48
|
-
|
|
65
|
+
|
|
49
66
|
|
|
50
67
|
ButtonType = Literal["submit", "reset", "button"]
|
|
51
68
|
|
|
@@ -198,14 +215,14 @@ class Form(BaseHTML):
|
|
|
198
215
|
if EventTriggers.ON_SUBMIT not in self.event_triggers:
|
|
199
216
|
return []
|
|
200
217
|
return [
|
|
201
|
-
|
|
202
|
-
handle_submit_unique_name=self.handle_submit_unique_name,
|
|
203
|
-
form_data=FORM_DATA,
|
|
218
|
+
_handle_submit_js_template(
|
|
219
|
+
handle_submit_unique_name=str(self.handle_submit_unique_name),
|
|
220
|
+
form_data=str(FORM_DATA),
|
|
204
221
|
field_ref_mapping=str(LiteralVar.create(self._get_form_refs())),
|
|
205
222
|
on_submit_event_chain=str(
|
|
206
223
|
LiteralVar.create(self.event_triggers[EventTriggers.ON_SUBMIT])
|
|
207
224
|
),
|
|
208
|
-
reset_on_submit=self.reset_on_submit,
|
|
225
|
+
reset_on_submit=str(self.reset_on_submit).lower(),
|
|
209
226
|
)
|
|
210
227
|
]
|
|
211
228
|
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
from collections.abc import Mapping, Sequence
|
|
7
7
|
from typing import Any, Literal
|
|
8
8
|
|
|
9
|
-
from jinja2 import Environment
|
|
10
|
-
|
|
11
9
|
from reflex.components.core.breakpoints import Breakpoints
|
|
12
10
|
from reflex.components.el.element import Element
|
|
13
11
|
from reflex.event import EventType, KeyInputInfo, PointerEventInfo
|
|
@@ -16,9 +14,6 @@ from reflex.vars.base import Var
|
|
|
16
14
|
|
|
17
15
|
from .base import BaseHTML
|
|
18
16
|
|
|
19
|
-
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
|
20
|
-
"\n const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {\n const $form = ev.target\n ev.preventDefault()\n const {{ form_data }} = {...Object.fromEntries(new FormData($form).entries()), ...{{ field_ref_mapping }}};\n\n ({{ on_submit_event_chain }}(ev));\n\n if ({{ reset_on_submit }}) {\n $form.reset()\n }\n })\n "
|
|
21
|
-
)
|
|
22
17
|
ButtonType = Literal["submit", "reset", "button"]
|
|
23
18
|
|
|
24
19
|
class Button(BaseHTML):
|
reflex/components/lucide/icon.py
CHANGED
|
@@ -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.
|
|
9
|
+
LUCIDE_LIBRARY = "lucide-react@0.540.0"
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class LucideIconComponent(Component):
|
|
@@ -1330,6 +1330,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1330
1330
|
"rocket",
|
|
1331
1331
|
"rocking_chair",
|
|
1332
1332
|
"roller_coaster",
|
|
1333
|
+
"rose",
|
|
1333
1334
|
"rotate_3d",
|
|
1334
1335
|
"rotate_ccw_key",
|
|
1335
1336
|
"rotate_ccw_square",
|
|
@@ -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.
|
|
14
|
+
LUCIDE_LIBRARY = "lucide-react@0.540.0"
|
|
15
15
|
|
|
16
16
|
class LucideIconComponent(Component):
|
|
17
17
|
@classmethod
|
|
@@ -1395,6 +1395,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1395
1395
|
"rocket",
|
|
1396
1396
|
"rocking_chair",
|
|
1397
1397
|
"roller_coaster",
|
|
1398
|
+
"rose",
|
|
1398
1399
|
"rotate_3d",
|
|
1399
1400
|
"rotate_ccw_key",
|
|
1400
1401
|
"rotate_ccw_square",
|
|
@@ -422,12 +422,12 @@ let {_LANGUAGE!s} = match ? match[1] : '';
|
|
|
422
422
|
|
|
423
423
|
def _get_custom_code(self) -> str | None:
|
|
424
424
|
hooks = {}
|
|
425
|
-
from reflex.compiler.templates import
|
|
425
|
+
from reflex.compiler.templates import _render_hooks
|
|
426
426
|
|
|
427
427
|
for _component in self.component_map.values():
|
|
428
428
|
comp = _component(_MOCK_ARG)
|
|
429
429
|
hooks.update(comp._get_all_hooks())
|
|
430
|
-
formatted_hooks =
|
|
430
|
+
formatted_hooks = _render_hooks(hooks)
|
|
431
431
|
return f"""
|
|
432
432
|
function {self._get_component_map_name()} () {{
|
|
433
433
|
{formatted_hooks}
|
|
@@ -54,7 +54,7 @@ def _inherited_variant_selector(
|
|
|
54
54
|
class AccordionComponent(RadixPrimitiveComponent):
|
|
55
55
|
"""Base class for all @radix-ui/accordion components."""
|
|
56
56
|
|
|
57
|
-
library = "@radix-ui/react-accordion@1.2.
|
|
57
|
+
library = "@radix-ui/react-accordion@1.2.12"
|
|
58
58
|
|
|
59
59
|
# The color scheme of the component.
|
|
60
60
|
color_scheme: Var[LiteralAccentColor]
|
|
@@ -21,7 +21,7 @@ class DrawerComponent(RadixPrimitiveComponent):
|
|
|
21
21
|
|
|
22
22
|
library = "vaul@1.1.2"
|
|
23
23
|
|
|
24
|
-
lib_dependencies: list[str] = ["@radix-ui/react-dialog@1.1.
|
|
24
|
+
lib_dependencies: list[str] = ["@radix-ui/react-dialog@1.1.15"]
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
LiteralDirectionType = Literal["top", "bottom", "left", "right"]
|
|
@@ -17,7 +17,7 @@ from .base import RadixPrimitiveComponentWithClassName
|
|
|
17
17
|
class FormComponent(RadixPrimitiveComponentWithClassName):
|
|
18
18
|
"""Base class for all @radix-ui/react-form components."""
|
|
19
19
|
|
|
20
|
-
library = "@radix-ui/react-form@0.1.
|
|
20
|
+
library = "@radix-ui/react-form@0.1.8"
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class FormRoot(FormComponent, HTMLForm):
|
|
@@ -17,7 +17,7 @@ LiteralSliderDir = Literal["ltr", "rtl"]
|
|
|
17
17
|
class SliderComponent(RadixPrimitiveComponentWithClassName):
|
|
18
18
|
"""Base class for all @radix-ui/react-slider components."""
|
|
19
19
|
|
|
20
|
-
library = "@radix-ui/react-slider@1.3.
|
|
20
|
+
library = "@radix-ui/react-slider@1.3.6"
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def on_value_event_spec(
|
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
"""Tag to conditionally render components."""
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
from collections.abc import Mapping
|
|
4
|
+
from collections.abc import Iterator, Mapping
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
from reflex.components.tags.tag import Tag
|
|
8
|
-
from reflex.vars.base import Var
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
@dataclasses.dataclass(frozen=True)
|
|
10
|
+
@dataclasses.dataclass(frozen=True, kw_only=True)
|
|
12
11
|
class CondTag(Tag):
|
|
13
12
|
"""A conditional tag."""
|
|
14
13
|
|
|
15
14
|
# The condition to determine which component to render.
|
|
16
|
-
|
|
15
|
+
cond_state: str
|
|
17
16
|
|
|
18
17
|
# The code to render if the condition is true.
|
|
19
|
-
true_value: Mapping
|
|
18
|
+
true_value: Mapping
|
|
20
19
|
|
|
21
20
|
# The code to render if the condition is false.
|
|
22
21
|
false_value: Mapping | None = None
|
|
22
|
+
|
|
23
|
+
def __iter__(self) -> Iterator[tuple[str, Any]]:
|
|
24
|
+
"""Iterate over the tag's attributes.
|
|
25
|
+
|
|
26
|
+
Yields:
|
|
27
|
+
An iterator over the tag's attributes.
|
|
28
|
+
"""
|
|
29
|
+
yield ("cond_state", self.cond_state)
|
|
30
|
+
yield ("true_value", self.true_value)
|
|
31
|
+
yield ("false_value", self.false_value)
|
|
@@ -68,32 +68,6 @@ class IterTag(Tag):
|
|
|
68
68
|
_var_type=self.get_iterable_var_type(),
|
|
69
69
|
).guess_type()
|
|
70
70
|
|
|
71
|
-
def get_index_var_arg(self) -> Var:
|
|
72
|
-
"""Get the index var for the tag (without curly braces).
|
|
73
|
-
|
|
74
|
-
This is used to render the index var in the .map() function.
|
|
75
|
-
|
|
76
|
-
Returns:
|
|
77
|
-
The index var.
|
|
78
|
-
"""
|
|
79
|
-
return Var(
|
|
80
|
-
_js_expr=self.index_var_name,
|
|
81
|
-
_var_type=int,
|
|
82
|
-
).guess_type()
|
|
83
|
-
|
|
84
|
-
def get_arg_var_arg(self) -> Var:
|
|
85
|
-
"""Get the arg var for the tag (without curly braces).
|
|
86
|
-
|
|
87
|
-
This is used to render the arg var in the .map() function.
|
|
88
|
-
|
|
89
|
-
Returns:
|
|
90
|
-
The arg var.
|
|
91
|
-
"""
|
|
92
|
-
return Var(
|
|
93
|
-
_js_expr=self.arg_var_name,
|
|
94
|
-
_var_type=self.get_iterable_var_type(),
|
|
95
|
-
).guess_type()
|
|
96
|
-
|
|
97
71
|
def render_component(self) -> Component:
|
|
98
72
|
"""Render the component.
|
|
99
73
|
|
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
"""Tag to conditionally match cases."""
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
from collections.abc import Sequence
|
|
4
|
+
from collections.abc import Iterator, Mapping, Sequence
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
from reflex.components.tags.tag import Tag
|
|
8
|
-
from reflex.vars.base import Var
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
@dataclasses.dataclass(frozen=True)
|
|
10
|
+
@dataclasses.dataclass(frozen=True, kw_only=True)
|
|
12
11
|
class MatchTag(Tag):
|
|
13
12
|
"""A match tag."""
|
|
14
13
|
|
|
15
14
|
# The condition to determine which case to match.
|
|
16
|
-
cond:
|
|
15
|
+
cond: str
|
|
17
16
|
|
|
18
17
|
# The list of match cases to be matched.
|
|
19
|
-
match_cases: Sequence[
|
|
18
|
+
match_cases: Sequence[tuple[Sequence[str], Mapping]]
|
|
20
19
|
|
|
21
20
|
# The catchall case to match.
|
|
22
|
-
default: Any
|
|
21
|
+
default: Any
|
|
22
|
+
|
|
23
|
+
def __iter__(self) -> Iterator[tuple[str, Any]]:
|
|
24
|
+
"""Iterate over the tag's attributes.
|
|
25
|
+
|
|
26
|
+
Yields:
|
|
27
|
+
An iterator over the tag's attributes.
|
|
28
|
+
"""
|
|
29
|
+
yield ("cond", self.cond)
|
|
30
|
+
yield ("match_cases", self.match_cases)
|
|
31
|
+
yield ("default", self.default)
|
reflex/components/tags/tag.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import dataclasses
|
|
6
|
-
from collections.abc import Mapping, Sequence
|
|
6
|
+
from collections.abc import Iterator, Mapping, Sequence
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
9
|
from reflex.event import EventChain
|
|
@@ -41,16 +41,13 @@ class Tag:
|
|
|
41
41
|
# The props of the tag.
|
|
42
42
|
props: Mapping[str, Any] = dataclasses.field(default_factory=dict)
|
|
43
43
|
|
|
44
|
-
# The inner contents of the tag.
|
|
45
|
-
contents: str = ""
|
|
46
|
-
|
|
47
44
|
# Special props that aren't key value pairs.
|
|
48
45
|
special_props: Sequence[Var] = dataclasses.field(default_factory=list)
|
|
49
46
|
|
|
50
47
|
# The children components.
|
|
51
48
|
children: Sequence[Any] = dataclasses.field(default_factory=list)
|
|
52
49
|
|
|
53
|
-
def format_props(self) -> list:
|
|
50
|
+
def format_props(self) -> list[str]:
|
|
54
51
|
"""Format the tag's props.
|
|
55
52
|
|
|
56
53
|
Returns:
|
|
@@ -69,7 +66,7 @@ class Tag:
|
|
|
69
66
|
"""
|
|
70
67
|
return dataclasses.replace(self, **kwargs)
|
|
71
68
|
|
|
72
|
-
def __iter__(self):
|
|
69
|
+
def __iter__(self) -> Iterator[tuple[str, Any]]:
|
|
73
70
|
"""Iterate over the tag's fields.
|
|
74
71
|
|
|
75
72
|
Yields:
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
"""A tag with no tag."""
|
|
2
2
|
|
|
3
|
+
import dataclasses
|
|
4
|
+
|
|
3
5
|
from reflex.components.tags import Tag
|
|
4
6
|
from reflex.utils import format
|
|
5
7
|
|
|
6
8
|
|
|
9
|
+
@dataclasses.dataclass(frozen=True, kw_only=True)
|
|
7
10
|
class Tagless(Tag):
|
|
8
11
|
"""A tag with no tag."""
|
|
9
12
|
|
|
13
|
+
# The inner contents of the tag.
|
|
14
|
+
contents: str
|
|
15
|
+
|
|
10
16
|
def __str__(self) -> str:
|
|
11
17
|
"""Return the string representation of the tag.
|
|
12
18
|
|
|
@@ -20,3 +26,11 @@ class Tagless(Tag):
|
|
|
20
26
|
if len(self.contents) > 0 and self.contents[-1] == " ":
|
|
21
27
|
out = out + space
|
|
22
28
|
return out
|
|
29
|
+
|
|
30
|
+
def __iter__(self):
|
|
31
|
+
"""Iterate over the tag's fields.
|
|
32
|
+
|
|
33
|
+
Yields:
|
|
34
|
+
tuple[str, Any]: The field name and value.
|
|
35
|
+
"""
|
|
36
|
+
yield "contents", self.contents
|
reflex/constants/base.py
CHANGED
|
@@ -141,8 +141,6 @@ class Templates(SimpleNamespace):
|
|
|
141
141
|
BASE = Reflex.ROOT_DIR / Reflex.MODULE_NAME / ".templates"
|
|
142
142
|
# The web subdirectory of the template directory.
|
|
143
143
|
WEB_TEMPLATE = BASE / "web"
|
|
144
|
-
# The jinja template directory.
|
|
145
|
-
JINJA_TEMPLATE = BASE / "jinja"
|
|
146
144
|
# Where the code for the templates is stored.
|
|
147
145
|
CODE = "code"
|
|
148
146
|
|
reflex/constants/installer.py
CHANGED
|
@@ -75,7 +75,7 @@ fetch-retries=0
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
def _determine_react_router_version() -> str:
|
|
78
|
-
default_version = "7.8.
|
|
78
|
+
default_version = "7.8.1"
|
|
79
79
|
if (version := os.getenv("REACT_ROUTER_VERSION")) and version != default_version:
|
|
80
80
|
from reflex.utils import console
|
|
81
81
|
|
|
@@ -131,7 +131,7 @@ class PackageJson(SimpleNamespace):
|
|
|
131
131
|
"react": cls._react_version,
|
|
132
132
|
"react-helmet": "6.1.0",
|
|
133
133
|
"react-dom": cls._react_version,
|
|
134
|
-
"isbot": "5.1.
|
|
134
|
+
"isbot": "5.1.30",
|
|
135
135
|
"socket.io-client": "4.8.1",
|
|
136
136
|
"universal-cookie": "7.2.2",
|
|
137
137
|
}
|
|
@@ -143,11 +143,11 @@ class PackageJson(SimpleNamespace):
|
|
|
143
143
|
"postcss-import": "16.1.1",
|
|
144
144
|
"@react-router/dev": _react_router_version,
|
|
145
145
|
"@react-router/fs-routes": _react_router_version,
|
|
146
|
-
"vite": "npm:rolldown-vite@7.1.
|
|
146
|
+
"vite": "npm:rolldown-vite@7.1.3",
|
|
147
147
|
}
|
|
148
148
|
OVERRIDES = {
|
|
149
149
|
# This should always match the `react` version in DEPENDENCIES for recharts compatibility.
|
|
150
150
|
"react-is": _react_version,
|
|
151
151
|
"cookie": "1.0.2",
|
|
152
|
-
"vite": "npm:rolldown-vite@7.1.
|
|
152
|
+
"vite": "npm:rolldown-vite@7.1.3",
|
|
153
153
|
}
|
|
@@ -18,6 +18,202 @@ from reflex.constants import CustomComponents
|
|
|
18
18
|
from reflex.utils import console, frontend_skeleton
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
def _pyproject_toml_template(
|
|
22
|
+
package_name: str, module_name: str, reflex_version: str
|
|
23
|
+
) -> str:
|
|
24
|
+
"""Template for custom components pyproject.toml.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
package_name: The name of the package.
|
|
28
|
+
module_name: The name of the module.
|
|
29
|
+
reflex_version: The version of Reflex.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Rendered pyproject.toml content as string.
|
|
33
|
+
"""
|
|
34
|
+
return f"""[build-system]
|
|
35
|
+
requires = ["setuptools", "wheel"]
|
|
36
|
+
build-backend = "setuptools.build_meta"
|
|
37
|
+
|
|
38
|
+
[project]
|
|
39
|
+
name = "{package_name}"
|
|
40
|
+
version = "0.0.1"
|
|
41
|
+
description = "Reflex custom component {module_name}"
|
|
42
|
+
readme = "README.md"
|
|
43
|
+
license = {{ text = "Apache-2.0" }}
|
|
44
|
+
requires-python = ">=3.10"
|
|
45
|
+
authors = [{{ name = "", email = "YOUREMAIL@domain.com" }}]
|
|
46
|
+
keywords = ["reflex","reflex-custom-components"]
|
|
47
|
+
|
|
48
|
+
dependencies = ["reflex>={reflex_version}"]
|
|
49
|
+
|
|
50
|
+
classifiers = ["Development Status :: 4 - Beta"]
|
|
51
|
+
|
|
52
|
+
[project.urls]
|
|
53
|
+
|
|
54
|
+
[project.optional-dependencies]
|
|
55
|
+
dev = ["build", "twine"]
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.packages.find]
|
|
58
|
+
where = ["custom_components"]
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _readme_template(module_name: str, package_name: str) -> str:
|
|
63
|
+
"""Template for custom components README.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
module_name: The name of the module.
|
|
67
|
+
package_name: The name of the package.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
Rendered README.md content as string.
|
|
71
|
+
"""
|
|
72
|
+
return f"""# {module_name}
|
|
73
|
+
|
|
74
|
+
A Reflex custom component {module_name}.
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install {package_name}
|
|
80
|
+
```
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _source_template(component_class_name: str, module_name: str) -> str:
|
|
85
|
+
"""Template for custom components source.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
component_class_name: The name of the component class.
|
|
89
|
+
module_name: The name of the module.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Rendered custom component source code as string.
|
|
93
|
+
"""
|
|
94
|
+
return rf'''
|
|
95
|
+
"""Reflex custom component {component_class_name}."""
|
|
96
|
+
|
|
97
|
+
# For wrapping react guide, visit https://reflex.dev/docs/wrapping-react/overview/
|
|
98
|
+
|
|
99
|
+
import reflex as rx
|
|
100
|
+
|
|
101
|
+
# Some libraries you want to wrap may require dynamic imports.
|
|
102
|
+
# This is because they they may not be compatible with Server-Side Rendering (SSR).
|
|
103
|
+
# To handle this in Reflex, all you need to do is subclass `NoSSRComponent` instead.
|
|
104
|
+
# For example:
|
|
105
|
+
# from reflex.components.component import NoSSRComponent
|
|
106
|
+
# class {component_class_name}(NoSSRComponent):
|
|
107
|
+
# pass
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class {component_class_name}(rx.Component):
|
|
111
|
+
"""{component_class_name} component."""
|
|
112
|
+
|
|
113
|
+
# The React library to wrap.
|
|
114
|
+
library = "Fill-Me"
|
|
115
|
+
|
|
116
|
+
# The React component tag.
|
|
117
|
+
tag = "Fill-Me"
|
|
118
|
+
|
|
119
|
+
# If the tag is the default export from the module, you must set is_default = True.
|
|
120
|
+
# This is normally used when components don't have curly braces around them when importing.
|
|
121
|
+
# is_default = True
|
|
122
|
+
|
|
123
|
+
# If you are wrapping another components with the same tag as a component in your project
|
|
124
|
+
# you can use aliases to differentiate between them and avoid naming conflicts.
|
|
125
|
+
# alias = "Other{component_class_name}"
|
|
126
|
+
|
|
127
|
+
# The props of the React component.
|
|
128
|
+
# Note: when Reflex compiles the component to Javascript,
|
|
129
|
+
# `snake_case` property names are automatically formatted as `camelCase`.
|
|
130
|
+
# The prop names may be defined in `camelCase` as well.
|
|
131
|
+
# some_prop: rx.Var[str] = "some default value"
|
|
132
|
+
# some_other_prop: rx.Var[int] = 1
|
|
133
|
+
|
|
134
|
+
# By default Reflex will install the library you have specified in the library property.
|
|
135
|
+
# However, sometimes you may need to install other libraries to use a component.
|
|
136
|
+
# In this case you can use the lib_dependencies property to specify other libraries to install.
|
|
137
|
+
# lib_dependencies: list[str] = []
|
|
138
|
+
|
|
139
|
+
# Event triggers declaration if any.
|
|
140
|
+
# Below is equivalent to merging `{{ "on_change": lambda e: [e] }}`
|
|
141
|
+
# onto the default event triggers of parent/base Component.
|
|
142
|
+
# The function defined for the `on_change` trigger maps event for the javascript
|
|
143
|
+
# trigger to what will be passed to the backend event handler function.
|
|
144
|
+
# on_change: rx.EventHandler[lambda e: [e]]
|
|
145
|
+
|
|
146
|
+
# To add custom code to your component
|
|
147
|
+
# def _get_custom_code(self) -> str:
|
|
148
|
+
# return "const customCode = 'customCode';"
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
{module_name} = {component_class_name}.create
|
|
152
|
+
'''
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _init_template(module_name: str) -> str:
|
|
156
|
+
"""Template for custom components __init__.py.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
module_name: The name of the module.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Rendered __init__.py content as string.
|
|
163
|
+
"""
|
|
164
|
+
return f"from .{module_name} import *"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _demo_app_template(custom_component_module_dir: str, module_name: str) -> str:
|
|
168
|
+
"""Template for custom components demo app.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
custom_component_module_dir: The directory of the custom component module.
|
|
172
|
+
module_name: The name of the module.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Rendered demo app source code as string.
|
|
176
|
+
"""
|
|
177
|
+
return rf'''
|
|
178
|
+
"""Welcome to Reflex! This file showcases the custom component in a basic app."""
|
|
179
|
+
|
|
180
|
+
from rxconfig import config
|
|
181
|
+
|
|
182
|
+
import reflex as rx
|
|
183
|
+
|
|
184
|
+
from {custom_component_module_dir} import {module_name}
|
|
185
|
+
|
|
186
|
+
filename = f"{{config.app_name}}/{{config.app_name}}.py"
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class State(rx.State):
|
|
190
|
+
"""The app state."""
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
def index() -> rx.Component:
|
|
194
|
+
return rx.center(
|
|
195
|
+
rx.theme_panel(),
|
|
196
|
+
rx.vstack(
|
|
197
|
+
rx.heading("Welcome to Reflex!", size="9"),
|
|
198
|
+
rx.text(
|
|
199
|
+
"Test your custom component by editing ",
|
|
200
|
+
rx.code(filename),
|
|
201
|
+
font_size="2em",
|
|
202
|
+
),
|
|
203
|
+
{module_name}(),
|
|
204
|
+
align="center",
|
|
205
|
+
spacing="7",
|
|
206
|
+
),
|
|
207
|
+
height="100vh",
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# Add state and page to the app.
|
|
212
|
+
app = rx.App()
|
|
213
|
+
app.add_page(index)
|
|
214
|
+
'''
|
|
215
|
+
|
|
216
|
+
|
|
21
217
|
def set_loglevel(ctx: Any, self: Any, value: str | None):
|
|
22
218
|
"""Set the log level.
|
|
23
219
|
|
|
@@ -77,11 +273,9 @@ def _create_package_config(module_name: str, package_name: str):
|
|
|
77
273
|
module_name: The name of the module.
|
|
78
274
|
package_name: The name of the package typically constructed with `reflex-` prefix and a meaningful library name.
|
|
79
275
|
"""
|
|
80
|
-
from reflex.compiler import templates
|
|
81
|
-
|
|
82
276
|
pyproject = Path(CustomComponents.PYPROJECT_TOML)
|
|
83
277
|
pyproject.write_text(
|
|
84
|
-
|
|
278
|
+
_pyproject_toml_template(
|
|
85
279
|
module_name=module_name,
|
|
86
280
|
package_name=package_name,
|
|
87
281
|
reflex_version=constants.Reflex.VERSION,
|
|
@@ -96,11 +290,9 @@ def _create_readme(module_name: str, package_name: str):
|
|
|
96
290
|
module_name: The name of the module.
|
|
97
291
|
package_name: The name of the python package to be published.
|
|
98
292
|
"""
|
|
99
|
-
from reflex.compiler import templates
|
|
100
|
-
|
|
101
293
|
readme = Path(CustomComponents.PACKAGE_README)
|
|
102
294
|
readme.write_text(
|
|
103
|
-
|
|
295
|
+
_readme_template(
|
|
104
296
|
module_name=module_name,
|
|
105
297
|
package_name=package_name,
|
|
106
298
|
)
|
|
@@ -119,19 +311,15 @@ def _write_source_and_init_py(
|
|
|
119
311
|
component_class_name: The name of the component class.
|
|
120
312
|
module_name: The name of the module.
|
|
121
313
|
"""
|
|
122
|
-
from reflex.compiler import templates
|
|
123
|
-
|
|
124
314
|
module_path = custom_component_src_dir / f"{module_name}.py"
|
|
125
315
|
module_path.write_text(
|
|
126
|
-
|
|
316
|
+
_source_template(
|
|
127
317
|
component_class_name=component_class_name, module_name=module_name
|
|
128
318
|
)
|
|
129
319
|
)
|
|
130
320
|
|
|
131
321
|
init_path = custom_component_src_dir / CustomComponents.INIT_FILE
|
|
132
|
-
init_path.write_text(
|
|
133
|
-
templates.CUSTOM_COMPONENTS_INIT_FILE.render(module_name=module_name)
|
|
134
|
-
)
|
|
322
|
+
init_path.write_text(_init_template(module_name=module_name))
|
|
135
323
|
|
|
136
324
|
|
|
137
325
|
def _populate_demo_app(name_variants: NameVariants):
|
|
@@ -141,7 +329,6 @@ def _populate_demo_app(name_variants: NameVariants):
|
|
|
141
329
|
name_variants: the tuple including various names such as package name, class name needed for the project.
|
|
142
330
|
"""
|
|
143
331
|
from reflex import constants
|
|
144
|
-
from reflex.compiler import templates
|
|
145
332
|
from reflex.reflex import _init
|
|
146
333
|
|
|
147
334
|
demo_app_dir = Path(name_variants.demo_app_dir)
|
|
@@ -155,10 +342,10 @@ def _populate_demo_app(name_variants: NameVariants):
|
|
|
155
342
|
# We start with the blank template as basis.
|
|
156
343
|
_init(name=demo_app_name, template=constants.Templates.DEFAULT)
|
|
157
344
|
# Then overwrite the app source file with the one we want for testing custom components.
|
|
158
|
-
# This source file is rendered using
|
|
345
|
+
# This source file is rendered using template file.
|
|
159
346
|
demo_file = Path(f"{demo_app_name}/{demo_app_name}.py")
|
|
160
347
|
demo_file.write_text(
|
|
161
|
-
|
|
348
|
+
_demo_app_template(
|
|
162
349
|
custom_component_module_dir=name_variants.custom_component_module_dir,
|
|
163
350
|
module_name=name_variants.module_name,
|
|
164
351
|
)
|