reflex 0.7.14a6__py3-none-any.whl → 0.8.0__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/jinja/app/rxconfig.py.jinja2 +4 -1
- reflex/.templates/jinja/web/package.json.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +21 -11
- reflex/.templates/jinja/web/pages/_document.js.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -1
- reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +4 -0
- reflex/.templates/jinja/web/styles/styles.css.jinja2 +1 -0
- reflex/.templates/jinja/web/utils/context.js.jinja2 +25 -8
- reflex/.templates/web/app/entry.client.js +8 -0
- reflex/.templates/web/app/routes.js +10 -0
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +12 -37
- reflex/.templates/web/postcss.config.js +1 -1
- reflex/.templates/web/react-router.config.js +6 -0
- reflex/.templates/web/styles/__reflex_style_reset.css +399 -0
- reflex/.templates/web/utils/client_side_routing.js +21 -19
- reflex/.templates/web/utils/react-theme.js +92 -0
- reflex/.templates/web/utils/state.js +251 -100
- reflex/.templates/web/vite-plugin-safari-cachebust.js +160 -0
- reflex/.templates/web/vite.config.js +39 -0
- reflex/__init__.py +1 -6
- reflex/__init__.pyi +327 -192
- reflex/app.py +86 -135
- reflex/base.py +1 -87
- reflex/compiler/compiler.py +70 -19
- reflex/compiler/templates.py +3 -3
- reflex/compiler/utils.py +91 -33
- reflex/components/__init__.py +0 -2
- reflex/components/__init__.pyi +34 -18
- reflex/components/base/__init__.py +1 -5
- reflex/components/base/__init__.pyi +30 -21
- reflex/components/base/app_wrap.pyi +7 -7
- reflex/components/base/body.pyi +7 -7
- reflex/components/base/document.py +18 -14
- reflex/components/base/document.pyi +88 -38
- reflex/components/base/error_boundary.pyi +7 -7
- reflex/components/base/fragment.pyi +7 -7
- reflex/components/base/link.pyi +12 -12
- reflex/components/base/meta.py +4 -15
- reflex/components/base/meta.pyi +31 -31
- reflex/components/base/script.py +60 -58
- reflex/components/base/script.pyi +248 -34
- reflex/components/base/strict_mode.pyi +7 -7
- reflex/components/component.py +146 -217
- reflex/components/core/__init__.py +1 -0
- reflex/components/core/__init__.pyi +77 -37
- reflex/components/core/auto_scroll.pyi +7 -7
- reflex/components/core/banner.pyi +33 -33
- reflex/components/core/client_side_routing.py +7 -6
- reflex/components/core/client_side_routing.pyi +8 -59
- reflex/components/core/clipboard.pyi +7 -7
- reflex/components/core/debounce.py +1 -0
- reflex/components/core/debounce.pyi +7 -7
- reflex/components/core/foreach.py +5 -4
- reflex/components/core/helmet.py +14 -0
- reflex/components/{next/base.pyi → core/helmet.pyi} +12 -10
- reflex/components/core/html.pyi +7 -7
- reflex/components/core/match.py +3 -3
- reflex/components/core/sticky.pyi +21 -20
- reflex/components/core/upload.py +4 -2
- reflex/components/core/upload.pyi +26 -25
- reflex/components/datadisplay/__init__.pyi +13 -7
- reflex/components/datadisplay/code.py +14 -79
- reflex/components/datadisplay/code.pyi +11 -13
- reflex/components/datadisplay/dataeditor.pyi +38 -15
- reflex/components/datadisplay/shiki_code_block.py +5 -3
- reflex/components/datadisplay/shiki_code_block.pyi +16 -15
- reflex/components/dynamic.py +5 -5
- reflex/components/el/__init__.pyi +506 -246
- reflex/components/el/element.pyi +7 -7
- reflex/components/el/elements/__init__.pyi +504 -245
- reflex/components/el/elements/base.pyi +7 -7
- reflex/components/el/elements/forms.pyi +146 -101
- reflex/components/el/elements/inline.pyi +142 -142
- reflex/components/el/elements/media.pyi +131 -130
- reflex/components/el/elements/metadata.pyi +32 -32
- reflex/components/el/elements/other.pyi +37 -37
- reflex/components/el/elements/scripts.pyi +17 -17
- reflex/components/el/elements/sectioning.pyi +77 -77
- reflex/components/el/elements/tables.pyi +52 -52
- reflex/components/el/elements/typography.pyi +77 -77
- reflex/components/field.py +175 -0
- reflex/components/gridjs/datatable.py +2 -2
- reflex/components/gridjs/datatable.pyi +14 -14
- reflex/components/lucide/icon.py +6 -2
- reflex/components/lucide/icon.pyi +19 -17
- reflex/components/markdown/markdown.py +5 -3
- reflex/components/markdown/markdown.pyi +7 -7
- reflex/components/moment/moment.py +1 -1
- reflex/components/moment/moment.pyi +7 -7
- reflex/components/plotly/plotly.py +12 -6
- reflex/components/plotly/plotly.pyi +50 -49
- reflex/components/props.py +376 -27
- reflex/components/radix/__init__.pyi +123 -65
- reflex/components/radix/primitives/__init__.pyi +6 -4
- reflex/components/radix/primitives/accordion.py +8 -1
- reflex/components/radix/primitives/accordion.pyi +37 -37
- reflex/components/radix/primitives/base.pyi +12 -12
- reflex/components/radix/primitives/drawer.pyi +56 -55
- reflex/components/radix/primitives/form.pyi +63 -53
- reflex/components/radix/primitives/progress.pyi +26 -25
- reflex/components/radix/primitives/slider.pyi +27 -27
- reflex/components/radix/themes/__init__.pyi +5 -6
- reflex/components/radix/themes/base.py +3 -3
- reflex/components/radix/themes/base.pyi +42 -42
- reflex/components/radix/themes/color_mode.py +5 -6
- reflex/components/radix/themes/color_mode.pyi +17 -17
- reflex/components/radix/themes/components/__init__.pyi +75 -38
- reflex/components/radix/themes/components/alert_dialog.pyi +37 -37
- reflex/components/radix/themes/components/aspect_ratio.pyi +7 -7
- reflex/components/radix/themes/components/avatar.pyi +7 -7
- reflex/components/radix/themes/components/badge.pyi +7 -7
- reflex/components/radix/themes/components/button.pyi +7 -7
- reflex/components/radix/themes/components/callout.pyi +26 -25
- reflex/components/radix/themes/components/card.pyi +7 -7
- reflex/components/radix/themes/components/checkbox.pyi +16 -15
- reflex/components/radix/themes/components/checkbox_cards.pyi +12 -12
- reflex/components/radix/themes/components/checkbox_group.pyi +12 -12
- reflex/components/radix/themes/components/context_menu.pyi +67 -67
- reflex/components/radix/themes/components/data_list.pyi +22 -22
- reflex/components/radix/themes/components/dialog.pyi +36 -35
- reflex/components/radix/themes/components/dropdown_menu.pyi +42 -42
- reflex/components/radix/themes/components/hover_card.pyi +21 -20
- reflex/components/radix/themes/components/icon_button.pyi +7 -7
- reflex/components/radix/themes/components/inset.pyi +7 -7
- reflex/components/radix/themes/components/popover.pyi +22 -22
- reflex/components/radix/themes/components/progress.pyi +7 -7
- reflex/components/radix/themes/components/radio.pyi +7 -7
- reflex/components/radix/themes/components/radio_cards.pyi +12 -12
- reflex/components/radix/themes/components/radio_group.pyi +21 -20
- reflex/components/radix/themes/components/scroll_area.pyi +7 -7
- reflex/components/radix/themes/components/segmented_control.pyi +12 -12
- reflex/components/radix/themes/components/select.pyi +46 -45
- reflex/components/radix/themes/components/separator.pyi +7 -7
- reflex/components/radix/themes/components/skeleton.pyi +7 -7
- reflex/components/radix/themes/components/slider.pyi +17 -9
- reflex/components/radix/themes/components/spinner.pyi +7 -7
- reflex/components/radix/themes/components/switch.pyi +7 -7
- reflex/components/radix/themes/components/table.pyi +37 -37
- reflex/components/radix/themes/components/tabs.pyi +26 -25
- reflex/components/radix/themes/components/text_area.pyi +15 -9
- reflex/components/radix/themes/components/text_field.pyi +32 -19
- reflex/components/radix/themes/components/tooltip.pyi +7 -7
- reflex/components/radix/themes/layout/__init__.pyi +27 -14
- reflex/components/radix/themes/layout/base.pyi +7 -7
- reflex/components/radix/themes/layout/box.pyi +7 -7
- reflex/components/radix/themes/layout/center.pyi +7 -7
- reflex/components/radix/themes/layout/container.pyi +7 -7
- reflex/components/radix/themes/layout/flex.pyi +7 -7
- reflex/components/radix/themes/layout/grid.pyi +7 -7
- reflex/components/radix/themes/layout/list.pyi +26 -25
- reflex/components/radix/themes/layout/section.pyi +7 -7
- reflex/components/radix/themes/layout/spacer.pyi +7 -7
- reflex/components/radix/themes/layout/stack.pyi +17 -17
- reflex/components/radix/themes/typography/__init__.pyi +7 -5
- reflex/components/radix/themes/typography/blockquote.pyi +7 -7
- reflex/components/radix/themes/typography/code.pyi +7 -7
- reflex/components/radix/themes/typography/heading.pyi +7 -7
- reflex/components/radix/themes/typography/link.py +46 -11
- reflex/components/radix/themes/typography/link.pyi +312 -9
- reflex/components/radix/themes/typography/text.pyi +36 -35
- reflex/components/react_player/audio.pyi +10 -8
- reflex/components/react_player/react_player.pyi +7 -7
- reflex/components/react_player/video.pyi +10 -8
- reflex/components/recharts/__init__.pyi +208 -100
- reflex/components/recharts/cartesian.py +10 -8
- reflex/components/recharts/cartesian.pyi +90 -94
- reflex/components/recharts/charts.py +4 -2
- reflex/components/recharts/charts.pyi +49 -49
- reflex/components/recharts/general.pyi +31 -31
- reflex/components/recharts/polar.py +8 -4
- reflex/components/recharts/polar.pyi +23 -23
- reflex/components/recharts/recharts.py +2 -2
- reflex/components/recharts/recharts.pyi +12 -12
- reflex/components/sonner/toast.py +3 -3
- reflex/components/sonner/toast.pyi +9 -9
- reflex/config.py +10 -113
- reflex/constants/__init__.py +2 -2
- reflex/constants/base.py +28 -11
- reflex/constants/compiler.py +12 -3
- reflex/constants/event.py +1 -0
- reflex/constants/installer.py +26 -20
- reflex/constants/route.py +27 -8
- reflex/constants/state.py +2 -0
- reflex/custom_components/custom_components.py +0 -14
- reflex/environment.py +77 -5
- reflex/event.py +178 -81
- reflex/experimental/__init__.py +0 -30
- reflex/istate/__init__.py +69 -0
- reflex/istate/manager.py +1 -0
- reflex/istate/proxy.py +5 -3
- reflex/page.py +0 -27
- reflex/plugins/__init__.py +3 -2
- reflex/plugins/base.py +5 -1
- reflex/plugins/shared_tailwind.py +215 -0
- reflex/plugins/sitemap.py +206 -0
- reflex/plugins/tailwind_v3.py +15 -108
- reflex/plugins/tailwind_v4.py +18 -110
- reflex/reflex.py +1 -0
- reflex/route.py +157 -75
- reflex/state.py +171 -155
- reflex/testing.py +86 -16
- reflex/utils/build.py +38 -82
- reflex/utils/exec.py +83 -175
- reflex/utils/export.py +2 -2
- reflex/utils/format.py +1 -5
- reflex/utils/imports.py +5 -16
- reflex/utils/misc.py +67 -0
- reflex/utils/prerequisites.py +66 -68
- reflex/utils/processes.py +24 -47
- reflex/utils/pyi_generator.py +44 -49
- reflex/utils/serializers.py +14 -1
- reflex/utils/telemetry.py +0 -15
- reflex/utils/types.py +197 -62
- reflex/vars/__init__.py +2 -0
- reflex/vars/base.py +367 -134
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/METADATA +15 -8
- reflex-0.8.0.dist-info/RECORD +403 -0
- reflex/.templates/web/next.config.js +0 -7
- reflex/components/base/head.py +0 -20
- reflex/components/base/head.pyi +0 -116
- reflex/components/next/__init__.py +0 -10
- reflex/components/next/base.py +0 -7
- reflex/components/next/image.py +0 -117
- reflex/components/next/image.pyi +0 -94
- reflex/components/next/link.py +0 -20
- reflex/components/next/link.pyi +0 -67
- reflex/components/next/video.py +0 -38
- reflex/components/next/video.pyi +0 -68
- reflex/components/suneditor/__init__.py +0 -5
- reflex/components/suneditor/editor.py +0 -269
- reflex/components/suneditor/editor.pyi +0 -199
- reflex/experimental/layout.py +0 -254
- reflex/experimental/layout.pyi +0 -814
- reflex-0.7.14a6.dist-info/RECORD +0 -408
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/WHEEL +0 -0
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/licenses/LICENSE +0 -0
reflex/components/component.py
CHANGED
|
@@ -7,7 +7,6 @@ import copy
|
|
|
7
7
|
import dataclasses
|
|
8
8
|
import functools
|
|
9
9
|
import inspect
|
|
10
|
-
import sys
|
|
11
10
|
import typing
|
|
12
11
|
from abc import ABC, ABCMeta, abstractmethod
|
|
13
12
|
from collections.abc import Callable, Iterator, Mapping, Sequence
|
|
@@ -15,27 +14,17 @@ from dataclasses import _MISSING_TYPE, MISSING
|
|
|
15
14
|
from functools import wraps
|
|
16
15
|
from hashlib import md5
|
|
17
16
|
from types import SimpleNamespace
|
|
18
|
-
from typing import
|
|
19
|
-
TYPE_CHECKING,
|
|
20
|
-
Annotated,
|
|
21
|
-
Any,
|
|
22
|
-
ClassVar,
|
|
23
|
-
ForwardRef,
|
|
24
|
-
Generic,
|
|
25
|
-
TypeVar,
|
|
26
|
-
_eval_type, # pyright: ignore [reportAttributeAccessIssue]
|
|
27
|
-
cast,
|
|
28
|
-
get_args,
|
|
29
|
-
get_origin,
|
|
30
|
-
)
|
|
17
|
+
from typing import TYPE_CHECKING, Any, ClassVar, TypeVar, cast, get_args, get_origin
|
|
31
18
|
|
|
32
19
|
from rich.markup import escape
|
|
33
20
|
from typing_extensions import dataclass_transform
|
|
34
21
|
|
|
35
22
|
import reflex.state
|
|
23
|
+
from reflex import constants
|
|
36
24
|
from reflex.compiler.templates import STATEFUL_COMPONENT
|
|
37
25
|
from reflex.components.core.breakpoints import Breakpoints
|
|
38
26
|
from reflex.components.dynamic import load_dynamic_serializer
|
|
27
|
+
from reflex.components.field import BaseField, FieldBasedMeta
|
|
39
28
|
from reflex.components.tags import Tag
|
|
40
29
|
from reflex.constants import (
|
|
41
30
|
Dirs,
|
|
@@ -55,6 +44,7 @@ from reflex.event import (
|
|
|
55
44
|
EventSpec,
|
|
56
45
|
no_args_event_spec,
|
|
57
46
|
parse_args_spec,
|
|
47
|
+
pointer_event_spec,
|
|
58
48
|
run_script,
|
|
59
49
|
unwrap_var_annotation,
|
|
60
50
|
)
|
|
@@ -74,50 +64,10 @@ from reflex.vars.number import ternary_operation
|
|
|
74
64
|
from reflex.vars.object import ObjectVar
|
|
75
65
|
from reflex.vars.sequence import LiteralArrayVar, LiteralStringVar, StringVar
|
|
76
66
|
|
|
77
|
-
|
|
78
|
-
def resolve_annotations(
|
|
79
|
-
raw_annotations: Mapping[str, type[Any]], module_name: str | None
|
|
80
|
-
) -> dict[str, type[Any]]:
|
|
81
|
-
"""Partially taken from typing.get_type_hints.
|
|
82
|
-
|
|
83
|
-
Resolve string or ForwardRef annotations into type objects if possible.
|
|
84
|
-
|
|
85
|
-
Args:
|
|
86
|
-
raw_annotations: The raw annotations to resolve.
|
|
87
|
-
module_name: The name of the module.
|
|
88
|
-
|
|
89
|
-
Returns:
|
|
90
|
-
The resolved annotations.
|
|
91
|
-
"""
|
|
92
|
-
module = sys.modules.get(module_name, None) if module_name is not None else None
|
|
93
|
-
|
|
94
|
-
base_globals: dict[str, Any] | None = (
|
|
95
|
-
module.__dict__ if module is not None else None
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
annotations = {}
|
|
99
|
-
for name, value in raw_annotations.items():
|
|
100
|
-
if isinstance(value, str):
|
|
101
|
-
if sys.version_info == (3, 10, 0):
|
|
102
|
-
value = ForwardRef(value, is_argument=False)
|
|
103
|
-
else:
|
|
104
|
-
value = ForwardRef(value, is_argument=False, is_class=True)
|
|
105
|
-
try:
|
|
106
|
-
if sys.version_info >= (3, 13):
|
|
107
|
-
value = _eval_type(value, base_globals, None, type_params=())
|
|
108
|
-
else:
|
|
109
|
-
value = _eval_type(value, base_globals, None)
|
|
110
|
-
except NameError:
|
|
111
|
-
# this is ok, it can be fixed with update_forward_refs
|
|
112
|
-
pass
|
|
113
|
-
annotations[name] = value
|
|
114
|
-
return annotations
|
|
115
|
-
|
|
116
|
-
|
|
117
67
|
FIELD_TYPE = TypeVar("FIELD_TYPE")
|
|
118
68
|
|
|
119
69
|
|
|
120
|
-
class ComponentField(
|
|
70
|
+
class ComponentField(BaseField[FIELD_TYPE]):
|
|
121
71
|
"""A field for a component."""
|
|
122
72
|
|
|
123
73
|
def __init__(
|
|
@@ -135,30 +85,8 @@ class ComponentField(Generic[FIELD_TYPE]):
|
|
|
135
85
|
is_javascript: Whether the field is a javascript property.
|
|
136
86
|
annotated_type: The annotated type for the field.
|
|
137
87
|
"""
|
|
138
|
-
|
|
139
|
-
self.default_factory = default_factory
|
|
88
|
+
super().__init__(default, default_factory, annotated_type)
|
|
140
89
|
self.is_javascript = is_javascript
|
|
141
|
-
self.outer_type_ = self.annotated_type = annotated_type
|
|
142
|
-
type_origin = get_origin(annotated_type) or annotated_type
|
|
143
|
-
if type_origin is Annotated:
|
|
144
|
-
type_origin = annotated_type.__origin__ # pyright: ignore [reportAttributeAccessIssue]
|
|
145
|
-
self.type_ = self.type_origin = type_origin
|
|
146
|
-
|
|
147
|
-
def default_value(self) -> FIELD_TYPE:
|
|
148
|
-
"""Get the default value for the field.
|
|
149
|
-
|
|
150
|
-
Returns:
|
|
151
|
-
The default value for the field.
|
|
152
|
-
|
|
153
|
-
Raises:
|
|
154
|
-
ValueError: If no default value or factory is provided.
|
|
155
|
-
"""
|
|
156
|
-
if self.default is not MISSING:
|
|
157
|
-
return self.default
|
|
158
|
-
if self.default_factory is not None:
|
|
159
|
-
return self.default_factory()
|
|
160
|
-
msg = "No default value or factory provided."
|
|
161
|
-
raise ValueError(msg)
|
|
162
90
|
|
|
163
91
|
def __repr__(self) -> str:
|
|
164
92
|
"""Represent the field in a readable format.
|
|
@@ -205,7 +133,7 @@ def field(
|
|
|
205
133
|
|
|
206
134
|
|
|
207
135
|
@dataclass_transform(kw_only_default=True, field_specifiers=(field,))
|
|
208
|
-
class BaseComponentMeta(ABCMeta):
|
|
136
|
+
class BaseComponentMeta(FieldBasedMeta, ABCMeta):
|
|
209
137
|
"""Meta class for BaseComponent."""
|
|
210
138
|
|
|
211
139
|
if TYPE_CHECKING:
|
|
@@ -214,46 +142,24 @@ class BaseComponentMeta(ABCMeta):
|
|
|
214
142
|
_fields: Mapping[str, ComponentField]
|
|
215
143
|
_js_fields: Mapping[str, ComponentField]
|
|
216
144
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
bases: The bases of the class.
|
|
223
|
-
namespace: The namespace of the class.
|
|
224
|
-
|
|
225
|
-
Returns:
|
|
226
|
-
The new class.
|
|
227
|
-
"""
|
|
228
|
-
# Add the field to the class
|
|
229
|
-
inherited_fields: dict[str, ComponentField] = {}
|
|
230
|
-
own_fields: dict[str, ComponentField] = {}
|
|
231
|
-
resolved_annotations = resolve_annotations(
|
|
145
|
+
@classmethod
|
|
146
|
+
def _resolve_annotations(
|
|
147
|
+
cls, namespace: dict[str, Any], name: str
|
|
148
|
+
) -> dict[str, Any]:
|
|
149
|
+
return types.resolve_annotations(
|
|
232
150
|
namespace.get("__annotations__", {}), namespace["__module__"]
|
|
233
151
|
)
|
|
234
152
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
(key, value, inherited_field)
|
|
244
|
-
for key, value in namespace.items()
|
|
245
|
-
if key not in resolved_annotations
|
|
246
|
-
and ((inherited_field := inherited_fields.get(key)) is not None)
|
|
247
|
-
]:
|
|
248
|
-
new_value = ComponentField(
|
|
249
|
-
default=value,
|
|
250
|
-
is_javascript=inherited_field.is_javascript,
|
|
251
|
-
annotated_type=inherited_field.annotated_type,
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
own_fields[key] = new_value
|
|
153
|
+
@classmethod
|
|
154
|
+
def _process_annotated_fields(
|
|
155
|
+
cls,
|
|
156
|
+
namespace: dict[str, Any],
|
|
157
|
+
annotations: dict[str, Any],
|
|
158
|
+
inherited_fields: dict[str, ComponentField],
|
|
159
|
+
) -> dict[str, ComponentField]:
|
|
160
|
+
own_fields: dict[str, ComponentField] = {}
|
|
255
161
|
|
|
256
|
-
for key, annotation in
|
|
162
|
+
for key, annotation in annotations.items():
|
|
257
163
|
value = namespace.get(key, MISSING)
|
|
258
164
|
|
|
259
165
|
if types.is_classvar(annotation):
|
|
@@ -286,16 +192,63 @@ class BaseComponentMeta(ABCMeta):
|
|
|
286
192
|
|
|
287
193
|
own_fields[key] = value
|
|
288
194
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
195
|
+
return own_fields
|
|
196
|
+
|
|
197
|
+
@classmethod
|
|
198
|
+
def _create_field(
|
|
199
|
+
cls,
|
|
200
|
+
annotated_type: Any,
|
|
201
|
+
default: Any = MISSING,
|
|
202
|
+
default_factory: Callable[[], Any] | None = None,
|
|
203
|
+
) -> ComponentField:
|
|
204
|
+
return ComponentField(
|
|
205
|
+
annotated_type=annotated_type,
|
|
206
|
+
default=default,
|
|
207
|
+
default_factory=default_factory,
|
|
208
|
+
is_javascript=True, # Default for components
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
@classmethod
|
|
212
|
+
def _process_field_overrides(
|
|
213
|
+
cls,
|
|
214
|
+
namespace: dict[str, Any],
|
|
215
|
+
annotations: dict[str, Any],
|
|
216
|
+
inherited_fields: dict[str, Any],
|
|
217
|
+
) -> dict[str, ComponentField]:
|
|
218
|
+
own_fields: dict[str, ComponentField] = {}
|
|
219
|
+
|
|
220
|
+
for key, value, inherited_field in [
|
|
221
|
+
(key, value, inherited_field)
|
|
222
|
+
for key, value in namespace.items()
|
|
223
|
+
if key not in annotations
|
|
224
|
+
and ((inherited_field := inherited_fields.get(key)) is not None)
|
|
225
|
+
]:
|
|
226
|
+
new_field = ComponentField(
|
|
227
|
+
default=value,
|
|
228
|
+
is_javascript=inherited_field.is_javascript,
|
|
229
|
+
annotated_type=inherited_field.annotated_type,
|
|
230
|
+
)
|
|
231
|
+
own_fields[key] = new_field
|
|
232
|
+
|
|
233
|
+
return own_fields
|
|
234
|
+
|
|
235
|
+
@classmethod
|
|
236
|
+
def _finalize_fields(
|
|
237
|
+
cls,
|
|
238
|
+
namespace: dict[str, Any],
|
|
239
|
+
inherited_fields: dict[str, ComponentField],
|
|
240
|
+
own_fields: dict[str, ComponentField],
|
|
241
|
+
) -> None:
|
|
242
|
+
# Call parent implementation
|
|
243
|
+
super()._finalize_fields(namespace, inherited_fields, own_fields)
|
|
244
|
+
|
|
245
|
+
# Add JavaScript fields mapping
|
|
246
|
+
all_fields = namespace["_fields"]
|
|
293
247
|
namespace["_js_fields"] = {
|
|
294
248
|
key: value
|
|
295
249
|
for key, value in all_fields.items()
|
|
296
250
|
if value.is_javascript is True
|
|
297
251
|
}
|
|
298
|
-
return super().__new__(cls, name, bases, namespace)
|
|
299
252
|
|
|
300
253
|
|
|
301
254
|
class BaseComponent(metaclass=BaseComponentMeta):
|
|
@@ -317,11 +270,6 @@ class BaseComponent(metaclass=BaseComponentMeta):
|
|
|
317
270
|
default_factory=list, is_javascript_property=False
|
|
318
271
|
)
|
|
319
272
|
|
|
320
|
-
# List here the dependencies that need to be transpiled by Next.js
|
|
321
|
-
transpile_packages: list[str] = field(
|
|
322
|
-
default_factory=list, is_javascript_property=False
|
|
323
|
-
)
|
|
324
|
-
|
|
325
273
|
# The tag to use when rendering the component.
|
|
326
274
|
tag: str | None = field(default=None, is_javascript_property=False)
|
|
327
275
|
|
|
@@ -504,12 +452,9 @@ def satisfies_type_hint(obj: Any, type_hint: Any) -> bool:
|
|
|
504
452
|
if not isinstance(obj, Var)
|
|
505
453
|
else (obj._var_value if isinstance(obj, LiteralVar) else obj)
|
|
506
454
|
)
|
|
507
|
-
console.
|
|
508
|
-
"
|
|
509
|
-
|
|
510
|
-
+ f"Passed {obj!s} of type {escape(str(type(obj) if not isinstance(obj, Var) else obj._var_type))} to {escape(str(type_hint))}.",
|
|
511
|
-
deprecation_version="0.7.2",
|
|
512
|
-
removal_version="0.8.0",
|
|
455
|
+
console.warn(
|
|
456
|
+
"Passing None to a Var that is not explicitly marked as Optional (| None) is deprecated. "
|
|
457
|
+
f"Passed {obj!s} of type {escape(str(type(obj) if not isinstance(obj, Var) else obj._var_type))} to {escape(str(type_hint))}."
|
|
513
458
|
)
|
|
514
459
|
return True
|
|
515
460
|
return False
|
|
@@ -534,12 +479,12 @@ def _components_from(
|
|
|
534
479
|
return ()
|
|
535
480
|
|
|
536
481
|
|
|
537
|
-
DEFAULT_TRIGGERS:
|
|
482
|
+
DEFAULT_TRIGGERS: Mapping[str, types.ArgsSpec | Sequence[types.ArgsSpec]] = {
|
|
538
483
|
EventTriggers.ON_FOCUS: no_args_event_spec,
|
|
539
484
|
EventTriggers.ON_BLUR: no_args_event_spec,
|
|
540
|
-
EventTriggers.ON_CLICK:
|
|
541
|
-
EventTriggers.ON_CONTEXT_MENU:
|
|
542
|
-
EventTriggers.ON_DOUBLE_CLICK:
|
|
485
|
+
EventTriggers.ON_CLICK: pointer_event_spec, # pyright: ignore [reportAssignmentType]
|
|
486
|
+
EventTriggers.ON_CONTEXT_MENU: pointer_event_spec, # pyright: ignore [reportAssignmentType]
|
|
487
|
+
EventTriggers.ON_DOUBLE_CLICK: pointer_event_spec, # pyright: ignore [reportAssignmentType]
|
|
543
488
|
EventTriggers.ON_MOUSE_DOWN: no_args_event_spec,
|
|
544
489
|
EventTriggers.ON_MOUSE_ENTER: no_args_event_spec,
|
|
545
490
|
EventTriggers.ON_MOUSE_LEAVE: no_args_event_spec,
|
|
@@ -548,6 +493,7 @@ DEFAULT_TRIGGERS: dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]] = {
|
|
|
548
493
|
EventTriggers.ON_MOUSE_OVER: no_args_event_spec,
|
|
549
494
|
EventTriggers.ON_MOUSE_UP: no_args_event_spec,
|
|
550
495
|
EventTriggers.ON_SCROLL: no_args_event_spec,
|
|
496
|
+
EventTriggers.ON_SCROLL_END: no_args_event_spec,
|
|
551
497
|
EventTriggers.ON_MOUNT: no_args_event_spec,
|
|
552
498
|
EventTriggers.ON_UNMOUNT: no_args_event_spec,
|
|
553
499
|
}
|
|
@@ -728,16 +674,10 @@ class Component(BaseComponent, ABC):
|
|
|
728
674
|
Args:
|
|
729
675
|
**kwargs: The kwargs to pass to the component.
|
|
730
676
|
"""
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
console.deprecate(
|
|
735
|
-
"component-direct-instantiation",
|
|
736
|
-
reason="Use the `create` method instead.",
|
|
737
|
-
deprecation_version="0.7.2",
|
|
738
|
-
removal_version="0.8.0",
|
|
677
|
+
console.error(
|
|
678
|
+
"Instantiating components directly is not supported."
|
|
679
|
+
f" Use `{self.__class__.__name__}.create` method instead."
|
|
739
680
|
)
|
|
740
|
-
self._post_init(**kwargs)
|
|
741
681
|
|
|
742
682
|
def _post_init(self, *args, **kwargs):
|
|
743
683
|
"""Initialize the component.
|
|
@@ -907,9 +847,8 @@ class Component(BaseComponent, ABC):
|
|
|
907
847
|
for key, value in kwargs.items():
|
|
908
848
|
setattr(self, key, value)
|
|
909
849
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
) -> dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]:
|
|
850
|
+
@classmethod
|
|
851
|
+
def get_event_triggers(cls) -> dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]:
|
|
913
852
|
"""Get the event triggers for the component.
|
|
914
853
|
|
|
915
854
|
Returns:
|
|
@@ -926,9 +865,9 @@ class Component(BaseComponent, ABC):
|
|
|
926
865
|
)
|
|
927
866
|
else no_args_event_spec
|
|
928
867
|
)
|
|
929
|
-
for name, field in
|
|
868
|
+
for name, field in cls.get_fields().items()
|
|
930
869
|
if field.type_origin is EventHandler
|
|
931
|
-
}
|
|
870
|
+
} # pyright: ignore [reportOperatorIssue]
|
|
932
871
|
|
|
933
872
|
def __repr__(self) -> str:
|
|
934
873
|
"""Represent the component in React.
|
|
@@ -1607,20 +1546,6 @@ class Component(BaseComponent, ABC):
|
|
|
1607
1546
|
# Return the dynamic imports
|
|
1608
1547
|
return dynamic_imports
|
|
1609
1548
|
|
|
1610
|
-
def _should_transpile(self, dep: str | None) -> bool:
|
|
1611
|
-
"""Check if a dependency should be transpiled.
|
|
1612
|
-
|
|
1613
|
-
Args:
|
|
1614
|
-
dep: The dependency to check.
|
|
1615
|
-
|
|
1616
|
-
Returns:
|
|
1617
|
-
True if the dependency should be transpiled.
|
|
1618
|
-
"""
|
|
1619
|
-
return bool(self.transpile_packages) and (
|
|
1620
|
-
dep in self.transpile_packages
|
|
1621
|
-
or format.format_library_name(dep or "") in self.transpile_packages
|
|
1622
|
-
)
|
|
1623
|
-
|
|
1624
1549
|
def _get_dependencies_imports(self) -> ParsedImportDict:
|
|
1625
1550
|
"""Get the imports from lib_dependencies for installing.
|
|
1626
1551
|
|
|
@@ -1628,14 +1553,7 @@ class Component(BaseComponent, ABC):
|
|
|
1628
1553
|
The dependencies imports of the component.
|
|
1629
1554
|
"""
|
|
1630
1555
|
return {
|
|
1631
|
-
dep: [
|
|
1632
|
-
ImportVar(
|
|
1633
|
-
tag=None,
|
|
1634
|
-
render=False,
|
|
1635
|
-
transpile=self._should_transpile(dep),
|
|
1636
|
-
)
|
|
1637
|
-
]
|
|
1638
|
-
for dep in self.lib_dependencies
|
|
1556
|
+
dep: [ImportVar(tag=None, render=False)] for dep in self.lib_dependencies
|
|
1639
1557
|
}
|
|
1640
1558
|
|
|
1641
1559
|
def _get_hooks_imports(self) -> ParsedImportDict:
|
|
@@ -1693,7 +1611,7 @@ class Component(BaseComponent, ABC):
|
|
|
1693
1611
|
|
|
1694
1612
|
# Import this component's tag from the main library.
|
|
1695
1613
|
if self.library is not None and self.tag is not None:
|
|
1696
|
-
_imports[self.library] =
|
|
1614
|
+
_imports[self.library] = self.import_var
|
|
1697
1615
|
|
|
1698
1616
|
# Get static imports required for event processing.
|
|
1699
1617
|
event_imports = Imports.EVENTS if self.event_triggers else {}
|
|
@@ -1719,7 +1637,7 @@ class Component(BaseComponent, ABC):
|
|
|
1719
1637
|
return imports.merge_imports(
|
|
1720
1638
|
self._get_dependencies_imports(),
|
|
1721
1639
|
self._get_hooks_imports(),
|
|
1722
|
-
_imports,
|
|
1640
|
+
{**_imports},
|
|
1723
1641
|
event_imports,
|
|
1724
1642
|
*var_imports,
|
|
1725
1643
|
*added_import_dicts,
|
|
@@ -1960,12 +1878,7 @@ class Component(BaseComponent, ABC):
|
|
|
1960
1878
|
# If the tag is dot-qualified, only import the left-most name.
|
|
1961
1879
|
tag = self.tag.partition(".")[0] if self.tag else None
|
|
1962
1880
|
alias = self.alias.partition(".")[0] if self.alias else None
|
|
1963
|
-
return ImportVar(
|
|
1964
|
-
tag=tag,
|
|
1965
|
-
is_default=self.is_default,
|
|
1966
|
-
alias=alias,
|
|
1967
|
-
transpile=self._should_transpile(self.library),
|
|
1968
|
-
)
|
|
1881
|
+
return ImportVar(tag=tag, is_default=self.is_default, alias=alias)
|
|
1969
1882
|
|
|
1970
1883
|
@staticmethod
|
|
1971
1884
|
def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
|
|
@@ -2178,7 +2091,7 @@ class CustomComponent(Component):
|
|
|
2178
2091
|
annotation=arg._var_type,
|
|
2179
2092
|
)
|
|
2180
2093
|
for name, arg in zip(
|
|
2181
|
-
names, parse_args_spec(event.args_spec), strict=True
|
|
2094
|
+
names, parse_args_spec(event.args_spec)[0], strict=True
|
|
2182
2095
|
)
|
|
2183
2096
|
]
|
|
2184
2097
|
)
|
|
@@ -2320,8 +2233,11 @@ class NoSSRComponent(Component):
|
|
|
2320
2233
|
Returns:
|
|
2321
2234
|
The imports for dynamically importing the component at module load time.
|
|
2322
2235
|
"""
|
|
2323
|
-
#
|
|
2324
|
-
dynamic_import = {
|
|
2236
|
+
# React lazy import mechanism.
|
|
2237
|
+
dynamic_import = {
|
|
2238
|
+
"react": [ImportVar(tag="lazy")],
|
|
2239
|
+
f"$/{constants.Dirs.UTILS}/context": [ImportVar(tag="ClientSide")],
|
|
2240
|
+
}
|
|
2325
2241
|
|
|
2326
2242
|
# The normal imports for this component.
|
|
2327
2243
|
_imports = super()._get_imports()
|
|
@@ -2331,13 +2247,7 @@ class NoSSRComponent(Component):
|
|
|
2331
2247
|
if import_name is not None:
|
|
2332
2248
|
with contextlib.suppress(ValueError):
|
|
2333
2249
|
_imports[import_name].remove(self.import_var)
|
|
2334
|
-
_imports[import_name].append(
|
|
2335
|
-
imports.ImportVar(
|
|
2336
|
-
tag=None,
|
|
2337
|
-
render=False,
|
|
2338
|
-
transpile=self._should_transpile(self.library),
|
|
2339
|
-
)
|
|
2340
|
-
)
|
|
2250
|
+
_imports[import_name].append(ImportVar(tag=None, render=False))
|
|
2341
2251
|
|
|
2342
2252
|
return imports.merge_imports(
|
|
2343
2253
|
dynamic_import,
|
|
@@ -2346,8 +2256,6 @@ class NoSSRComponent(Component):
|
|
|
2346
2256
|
)
|
|
2347
2257
|
|
|
2348
2258
|
def _get_dynamic_imports(self) -> str:
|
|
2349
|
-
opts_fragment = ", { ssr: false });"
|
|
2350
|
-
|
|
2351
2259
|
# extract the correct import name from library name
|
|
2352
2260
|
base_import_name = self._get_import_name()
|
|
2353
2261
|
if base_import_name is None:
|
|
@@ -2355,12 +2263,19 @@ class NoSSRComponent(Component):
|
|
|
2355
2263
|
raise ValueError(msg)
|
|
2356
2264
|
import_name = format.format_library_name(base_import_name)
|
|
2357
2265
|
|
|
2358
|
-
library_import = f"
|
|
2266
|
+
library_import = f"import('{import_name}')"
|
|
2359
2267
|
mod_import = (
|
|
2360
2268
|
# https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#with-named-exports
|
|
2361
|
-
f".then((mod) => mod.{self.tag})"
|
|
2269
|
+
f".then((mod) => ({{default: mod.{self.tag}}}))"
|
|
2270
|
+
if not self.is_default
|
|
2271
|
+
else ""
|
|
2272
|
+
)
|
|
2273
|
+
return (
|
|
2274
|
+
f"const {self.alias if self.alias else self.tag} = ClientSide(lazy(() => "
|
|
2275
|
+
+ library_import
|
|
2276
|
+
+ mod_import
|
|
2277
|
+
+ "))"
|
|
2362
2278
|
)
|
|
2363
|
-
return library_import + mod_import + opts_fragment
|
|
2364
2279
|
|
|
2365
2280
|
|
|
2366
2281
|
class StatefulComponent(BaseComponent):
|
|
@@ -2378,16 +2293,19 @@ class StatefulComponent(BaseComponent):
|
|
|
2378
2293
|
tag_to_stateful_component: ClassVar[dict[str, StatefulComponent]] = {}
|
|
2379
2294
|
|
|
2380
2295
|
# Reference to the original component that was memoized into this component.
|
|
2381
|
-
component: Component
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
code: str
|
|
2296
|
+
component: Component = field(
|
|
2297
|
+
default_factory=Component, is_javascript_property=False
|
|
2298
|
+
)
|
|
2385
2299
|
|
|
2386
2300
|
# How many times this component is referenced in the app.
|
|
2387
|
-
references: int = 0
|
|
2301
|
+
references: int = field(default=0, is_javascript_property=False)
|
|
2388
2302
|
|
|
2389
2303
|
# Whether the component has already been rendered to a shared file.
|
|
2390
|
-
rendered_as_shared: bool = False
|
|
2304
|
+
rendered_as_shared: bool = field(default=False, is_javascript_property=False)
|
|
2305
|
+
|
|
2306
|
+
memo_trigger_hooks: list[str] = field(
|
|
2307
|
+
default_factory=list, is_javascript_property=False
|
|
2308
|
+
)
|
|
2391
2309
|
|
|
2392
2310
|
@classmethod
|
|
2393
2311
|
def create(cls, component: Component) -> StatefulComponent | None:
|
|
@@ -2447,8 +2365,7 @@ class StatefulComponent(BaseComponent):
|
|
|
2447
2365
|
# Look up the tag in the cache
|
|
2448
2366
|
stateful_component = cls.tag_to_stateful_component.get(tag_name)
|
|
2449
2367
|
if stateful_component is None:
|
|
2450
|
-
|
|
2451
|
-
code = cls._render_stateful_code(component, tag_name=tag_name)
|
|
2368
|
+
memo_trigger_hooks = cls._fix_event_triggers(component)
|
|
2452
2369
|
# Set the stateful component in the cache for the given tag.
|
|
2453
2370
|
stateful_component = cls.tag_to_stateful_component.setdefault(
|
|
2454
2371
|
tag_name,
|
|
@@ -2456,7 +2373,7 @@ class StatefulComponent(BaseComponent):
|
|
|
2456
2373
|
children=component.children,
|
|
2457
2374
|
component=component,
|
|
2458
2375
|
tag=tag_name,
|
|
2459
|
-
|
|
2376
|
+
memo_trigger_hooks=memo_trigger_hooks,
|
|
2460
2377
|
),
|
|
2461
2378
|
)
|
|
2462
2379
|
# Bump the reference count -- multiple pages referencing the same component
|
|
@@ -2520,26 +2437,38 @@ class StatefulComponent(BaseComponent):
|
|
|
2520
2437
|
f"{component.tag or 'Comp'}_{code_hash}"
|
|
2521
2438
|
).capitalize()
|
|
2522
2439
|
|
|
2523
|
-
@classmethod
|
|
2524
2440
|
def _render_stateful_code(
|
|
2441
|
+
self,
|
|
2442
|
+
export: bool = False,
|
|
2443
|
+
) -> str:
|
|
2444
|
+
if not self.tag:
|
|
2445
|
+
return ""
|
|
2446
|
+
# Render the code for this component and hooks.
|
|
2447
|
+
return STATEFUL_COMPONENT.render(
|
|
2448
|
+
tag_name=self.tag,
|
|
2449
|
+
memo_trigger_hooks=self.memo_trigger_hooks,
|
|
2450
|
+
component=self.component,
|
|
2451
|
+
export=export,
|
|
2452
|
+
)
|
|
2453
|
+
|
|
2454
|
+
@classmethod
|
|
2455
|
+
def _fix_event_triggers(
|
|
2525
2456
|
cls,
|
|
2526
2457
|
component: Component,
|
|
2527
|
-
|
|
2528
|
-
) -> str:
|
|
2458
|
+
) -> list[str]:
|
|
2529
2459
|
"""Render the code for a stateful component.
|
|
2530
2460
|
|
|
2531
2461
|
Args:
|
|
2532
2462
|
component: The component to render.
|
|
2533
|
-
tag_name: The tag name for the stateful component (see _get_tag_name).
|
|
2534
2463
|
|
|
2535
2464
|
Returns:
|
|
2536
|
-
The
|
|
2465
|
+
The memoized event trigger hooks for the component.
|
|
2537
2466
|
"""
|
|
2538
2467
|
# Memoize event triggers useCallback to avoid unnecessary re-renders.
|
|
2539
2468
|
memo_event_triggers = tuple(cls._get_memoized_event_triggers(component).items())
|
|
2540
2469
|
|
|
2541
2470
|
# Trigger hooks stored separately to write after the normal hooks (see stateful_component.js.jinja2)
|
|
2542
|
-
memo_trigger_hooks = []
|
|
2471
|
+
memo_trigger_hooks: list[str] = []
|
|
2543
2472
|
|
|
2544
2473
|
if memo_event_triggers:
|
|
2545
2474
|
# Copy the component to avoid mutating the original.
|
|
@@ -2553,12 +2482,7 @@ class StatefulComponent(BaseComponent):
|
|
|
2553
2482
|
memo_trigger_hooks.append(memo_trigger_hook)
|
|
2554
2483
|
component.event_triggers[event_trigger] = memo_trigger
|
|
2555
2484
|
|
|
2556
|
-
|
|
2557
|
-
return STATEFUL_COMPONENT.render(
|
|
2558
|
-
tag_name=tag_name,
|
|
2559
|
-
memo_trigger_hooks=memo_trigger_hooks,
|
|
2560
|
-
component=component,
|
|
2561
|
-
)
|
|
2485
|
+
return memo_trigger_hooks
|
|
2562
2486
|
|
|
2563
2487
|
@staticmethod
|
|
2564
2488
|
def _get_hook_deps(hook: str) -> list[str]:
|
|
@@ -2716,15 +2640,20 @@ class StatefulComponent(BaseComponent):
|
|
|
2716
2640
|
return set()
|
|
2717
2641
|
return self.component._get_all_dynamic_imports()
|
|
2718
2642
|
|
|
2719
|
-
def _get_all_custom_code(self) -> set[str]:
|
|
2643
|
+
def _get_all_custom_code(self, export: bool = False) -> set[str]:
|
|
2720
2644
|
"""Get custom code for the component.
|
|
2721
2645
|
|
|
2646
|
+
Args:
|
|
2647
|
+
export: Whether to export the component.
|
|
2648
|
+
|
|
2722
2649
|
Returns:
|
|
2723
2650
|
The custom code.
|
|
2724
2651
|
"""
|
|
2725
2652
|
if self.rendered_as_shared:
|
|
2726
2653
|
return set()
|
|
2727
|
-
return self.component._get_all_custom_code().union(
|
|
2654
|
+
return self.component._get_all_custom_code().union(
|
|
2655
|
+
{self._render_stateful_code(export=export)}
|
|
2656
|
+
)
|
|
2728
2657
|
|
|
2729
2658
|
def _get_all_refs(self) -> set[str]:
|
|
2730
2659
|
"""Get the refs for the children of the component.
|