reflex 0.7.14a5__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 +103 -152
- 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.14a5.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-0.7.14a5.dist-info/RECORD +0 -407
- {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/WHEEL +0 -0
- {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/licenses/LICENSE +0 -0
reflex/components/props.py
CHANGED
|
@@ -2,17 +2,280 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from dataclasses import _MISSING_TYPE, MISSING
|
|
7
|
+
from typing import Any, TypeVar, get_args, get_origin
|
|
6
8
|
|
|
7
|
-
from
|
|
9
|
+
from typing_extensions import dataclass_transform
|
|
10
|
+
|
|
11
|
+
from reflex.components.field import BaseField, FieldBasedMeta
|
|
8
12
|
from reflex.utils import format
|
|
9
13
|
from reflex.utils.exceptions import InvalidPropValueError
|
|
14
|
+
from reflex.utils.serializers import serializer
|
|
15
|
+
from reflex.utils.types import is_union
|
|
10
16
|
from reflex.vars.object import LiteralObjectVar
|
|
11
17
|
|
|
18
|
+
PROPS_FIELD_TYPE = TypeVar("PROPS_FIELD_TYPE")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_props_subclass(field_type: Any) -> type | None:
|
|
22
|
+
"""Extract the Props subclass from a field type annotation.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
field_type: The type annotation to check.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
The Props subclass if found, None otherwise.
|
|
29
|
+
"""
|
|
30
|
+
from reflex.utils.types import typehint_issubclass
|
|
31
|
+
|
|
32
|
+
# For direct class types, we can return them directly if they're Props subclasses
|
|
33
|
+
if isinstance(field_type, type):
|
|
34
|
+
return field_type if typehint_issubclass(field_type, PropsBase) else None
|
|
35
|
+
|
|
36
|
+
# For Union types, check each union member
|
|
37
|
+
if is_union(field_type):
|
|
38
|
+
for arg in get_args(field_type):
|
|
39
|
+
result = _get_props_subclass(arg)
|
|
40
|
+
if result is not None:
|
|
41
|
+
return result
|
|
42
|
+
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _find_props_in_list_annotation(field_type: Any) -> type | None:
|
|
47
|
+
"""Find Props subclass within a list type annotation.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
field_type: The type annotation to check (e.g., list[SomeProps] or list[SomeProps] | None).
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
The Props subclass if found in a list annotation, None otherwise.
|
|
54
|
+
"""
|
|
55
|
+
origin = get_origin(field_type)
|
|
56
|
+
if origin is list:
|
|
57
|
+
args = get_args(field_type)
|
|
58
|
+
if args:
|
|
59
|
+
return _get_props_subclass(args[0])
|
|
60
|
+
|
|
61
|
+
# Handle Union types - check if any union member is a list
|
|
62
|
+
if is_union(field_type):
|
|
63
|
+
for arg in get_args(field_type):
|
|
64
|
+
if arg is not type(None): # Skip None from Optional
|
|
65
|
+
list_element = _find_props_in_list_annotation(arg)
|
|
66
|
+
if list_element is not None:
|
|
67
|
+
return list_element
|
|
68
|
+
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class PropsField(BaseField[PROPS_FIELD_TYPE]):
|
|
73
|
+
"""A field for a props class."""
|
|
74
|
+
|
|
75
|
+
def __init__(
|
|
76
|
+
self,
|
|
77
|
+
default: PROPS_FIELD_TYPE | _MISSING_TYPE = MISSING,
|
|
78
|
+
default_factory: Callable[[], PROPS_FIELD_TYPE] | None = None,
|
|
79
|
+
annotated_type: type[Any] | _MISSING_TYPE = MISSING,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Initialize the field.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
default: The default value for the field.
|
|
85
|
+
default_factory: The default factory for the field.
|
|
86
|
+
annotated_type: The annotated type for the field.
|
|
87
|
+
"""
|
|
88
|
+
super().__init__(default, default_factory, annotated_type)
|
|
89
|
+
self._name: str = "" # Will be set by metaclass
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def required(self) -> bool:
|
|
93
|
+
"""Check if the field is required (for Pydantic compatibility).
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
True if the field has no default value or factory.
|
|
97
|
+
"""
|
|
98
|
+
return self.default is MISSING and self.default_factory is None
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def name(self) -> str | None:
|
|
102
|
+
"""Field name (for Pydantic compatibility).
|
|
103
|
+
|
|
104
|
+
Note: This is set by the metaclass when processing fields.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
The field name if set, None otherwise.
|
|
108
|
+
"""
|
|
109
|
+
return getattr(self, "_name", None)
|
|
110
|
+
|
|
111
|
+
def get_default(self) -> Any:
|
|
112
|
+
"""Get the default value (for Pydantic compatibility).
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
The default value for the field, or None if required.
|
|
116
|
+
"""
|
|
117
|
+
try:
|
|
118
|
+
return self.default_value()
|
|
119
|
+
except ValueError:
|
|
120
|
+
# Field is required (no default)
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
def __repr__(self) -> str:
|
|
124
|
+
"""Represent the field in a readable format.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
The string representation of the field.
|
|
128
|
+
"""
|
|
129
|
+
annotated_type_str = (
|
|
130
|
+
f", annotated_type={self.annotated_type!r}"
|
|
131
|
+
if self.annotated_type is not MISSING
|
|
132
|
+
else ""
|
|
133
|
+
)
|
|
134
|
+
if self.default is not MISSING:
|
|
135
|
+
return f"PropsField(default={self.default!r}{annotated_type_str})"
|
|
136
|
+
return (
|
|
137
|
+
f"PropsField(default_factory={self.default_factory!r}{annotated_type_str})"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def props_field(
|
|
142
|
+
default: PROPS_FIELD_TYPE | _MISSING_TYPE = MISSING,
|
|
143
|
+
default_factory: Callable[[], PROPS_FIELD_TYPE] | None = None,
|
|
144
|
+
) -> PROPS_FIELD_TYPE:
|
|
145
|
+
"""Create a field for a props class.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
default: The default value for the field.
|
|
149
|
+
default_factory: The default factory for the field.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
The field for the props class.
|
|
153
|
+
|
|
154
|
+
Raises:
|
|
155
|
+
ValueError: If both default and default_factory are specified.
|
|
156
|
+
"""
|
|
157
|
+
if default is not MISSING and default_factory is not None:
|
|
158
|
+
msg = "cannot specify both default and default_factory"
|
|
159
|
+
raise ValueError(msg)
|
|
160
|
+
return PropsField( # pyright: ignore [reportReturnType]
|
|
161
|
+
default=default,
|
|
162
|
+
default_factory=default_factory,
|
|
163
|
+
annotated_type=MISSING,
|
|
164
|
+
)
|
|
165
|
+
|
|
12
166
|
|
|
13
|
-
|
|
167
|
+
@dataclass_transform(field_specifiers=(props_field,))
|
|
168
|
+
class PropsBaseMeta(FieldBasedMeta):
|
|
169
|
+
"""Meta class for PropsBase."""
|
|
170
|
+
|
|
171
|
+
@classmethod
|
|
172
|
+
def _process_annotated_fields(
|
|
173
|
+
cls,
|
|
174
|
+
namespace: dict[str, Any],
|
|
175
|
+
annotations: dict[str, Any],
|
|
176
|
+
inherited_fields: dict[str, PropsField],
|
|
177
|
+
) -> dict[str, PropsField]:
|
|
178
|
+
own_fields: dict[str, PropsField] = {}
|
|
179
|
+
|
|
180
|
+
for key, annotation in annotations.items():
|
|
181
|
+
value = namespace.get(key, MISSING)
|
|
182
|
+
|
|
183
|
+
if value is MISSING:
|
|
184
|
+
# Field with only annotation, no default value
|
|
185
|
+
field = PropsField(annotated_type=annotation, default=None)
|
|
186
|
+
elif not isinstance(value, PropsField):
|
|
187
|
+
# Field with default value
|
|
188
|
+
field = PropsField(annotated_type=annotation, default=value)
|
|
189
|
+
else:
|
|
190
|
+
# Field is already a PropsField, update annotation
|
|
191
|
+
field = PropsField(
|
|
192
|
+
annotated_type=annotation,
|
|
193
|
+
default=value.default,
|
|
194
|
+
default_factory=value.default_factory,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
own_fields[key] = field
|
|
198
|
+
|
|
199
|
+
return own_fields
|
|
200
|
+
|
|
201
|
+
@classmethod
|
|
202
|
+
def _create_field(
|
|
203
|
+
cls,
|
|
204
|
+
annotated_type: Any,
|
|
205
|
+
default: Any = MISSING,
|
|
206
|
+
default_factory: Callable[[], Any] | None = None,
|
|
207
|
+
) -> PropsField:
|
|
208
|
+
return PropsField(
|
|
209
|
+
annotated_type=annotated_type,
|
|
210
|
+
default=default,
|
|
211
|
+
default_factory=default_factory,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
@classmethod
|
|
215
|
+
def _finalize_fields(
|
|
216
|
+
cls,
|
|
217
|
+
namespace: dict[str, Any],
|
|
218
|
+
inherited_fields: dict[str, PropsField],
|
|
219
|
+
own_fields: dict[str, PropsField],
|
|
220
|
+
) -> None:
|
|
221
|
+
# Call parent implementation
|
|
222
|
+
super()._finalize_fields(namespace, inherited_fields, own_fields)
|
|
223
|
+
|
|
224
|
+
# Add Pydantic compatibility
|
|
225
|
+
namespace["__fields__"] = namespace["_fields"]
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class PropsBase(metaclass=PropsBaseMeta):
|
|
14
229
|
"""Base for a class containing props that can be serialized as a JS object."""
|
|
15
230
|
|
|
231
|
+
def __init__(self, **kwargs):
|
|
232
|
+
"""Initialize the props with field values.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
**kwargs: The field values to set.
|
|
236
|
+
"""
|
|
237
|
+
# Set field values from kwargs with nested object instantiation
|
|
238
|
+
for key, value in kwargs.items():
|
|
239
|
+
field_info = self.get_fields().get(key)
|
|
240
|
+
if field_info:
|
|
241
|
+
field_type = field_info.annotated_type
|
|
242
|
+
|
|
243
|
+
# Check if this field expects a specific Props type and we got a dict
|
|
244
|
+
if isinstance(value, dict):
|
|
245
|
+
props_class = _get_props_subclass(field_type)
|
|
246
|
+
if props_class is not None:
|
|
247
|
+
value = props_class(**value)
|
|
248
|
+
|
|
249
|
+
# Check if this field expects a list of Props and we got a list of dicts
|
|
250
|
+
elif isinstance(value, list):
|
|
251
|
+
element_type = _find_props_in_list_annotation(field_type)
|
|
252
|
+
if element_type is not None:
|
|
253
|
+
# Convert each dict in the list to the appropriate Props class
|
|
254
|
+
value = [
|
|
255
|
+
element_type(**item) if isinstance(item, dict) else item
|
|
256
|
+
for item in value
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
setattr(self, key, value)
|
|
260
|
+
|
|
261
|
+
# Set default values for fields not provided
|
|
262
|
+
for field_name, field in self.get_fields().items():
|
|
263
|
+
if field_name not in kwargs:
|
|
264
|
+
if field.default is not MISSING:
|
|
265
|
+
setattr(self, field_name, field.default)
|
|
266
|
+
elif field.default_factory is not None:
|
|
267
|
+
setattr(self, field_name, field.default_factory())
|
|
268
|
+
# Note: Fields with no default and no factory remain unset (required fields)
|
|
269
|
+
|
|
270
|
+
@classmethod
|
|
271
|
+
def get_fields(cls) -> dict[str, Any]:
|
|
272
|
+
"""Get the fields of the object.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
The fields of the object.
|
|
276
|
+
"""
|
|
277
|
+
return getattr(cls, "_fields", {})
|
|
278
|
+
|
|
16
279
|
def json(self) -> str:
|
|
17
280
|
"""Convert the object to a json-like string.
|
|
18
281
|
|
|
@@ -27,31 +290,117 @@ class PropsBase(Base):
|
|
|
27
290
|
{format.to_camel_case(key): value for key, value in self.dict().items()}
|
|
28
291
|
).json()
|
|
29
292
|
|
|
30
|
-
def dict(
|
|
293
|
+
def dict(
|
|
294
|
+
self,
|
|
295
|
+
exclude_none: bool = True,
|
|
296
|
+
include: set[str] | None = None,
|
|
297
|
+
exclude: set[str] | None = None,
|
|
298
|
+
**kwargs,
|
|
299
|
+
):
|
|
31
300
|
"""Convert the object to a dictionary.
|
|
32
301
|
|
|
33
302
|
Keys will be converted to camelCase.
|
|
34
303
|
By default, None values are excluded (exclude_none=True).
|
|
35
304
|
|
|
36
305
|
Args:
|
|
37
|
-
|
|
38
|
-
|
|
306
|
+
exclude_none: Whether to exclude None values.
|
|
307
|
+
include: Fields to include in the output.
|
|
308
|
+
exclude: Fields to exclude from the output.
|
|
309
|
+
**kwargs: Additional keyword arguments (for compatibility).
|
|
39
310
|
|
|
40
311
|
Returns:
|
|
41
312
|
The object as a dictionary.
|
|
42
313
|
"""
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
format.to_camel_case(key): value
|
|
46
|
-
for key, value in super().dict(*args, **kwargs).items()
|
|
47
|
-
}
|
|
314
|
+
result = {}
|
|
48
315
|
|
|
316
|
+
for field_name in self.get_fields():
|
|
317
|
+
if hasattr(self, field_name):
|
|
318
|
+
value = getattr(self, field_name)
|
|
49
319
|
|
|
50
|
-
|
|
320
|
+
# Apply include/exclude filters
|
|
321
|
+
if include is not None and field_name not in include:
|
|
322
|
+
continue
|
|
323
|
+
if exclude is not None and field_name in exclude:
|
|
324
|
+
continue
|
|
325
|
+
|
|
326
|
+
# Apply exclude_none logic
|
|
327
|
+
if exclude_none and value is None:
|
|
328
|
+
continue
|
|
329
|
+
|
|
330
|
+
# Recursively convert nested structures
|
|
331
|
+
value = self._convert_to_camel_case(
|
|
332
|
+
value, exclude_none, include, exclude
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# Convert key to camelCase
|
|
336
|
+
camel_key = format.to_camel_case(field_name)
|
|
337
|
+
result[camel_key] = value
|
|
338
|
+
|
|
339
|
+
return result
|
|
340
|
+
|
|
341
|
+
def _convert_to_camel_case(
|
|
342
|
+
self,
|
|
343
|
+
value: Any,
|
|
344
|
+
exclude_none: bool = True,
|
|
345
|
+
include: set[str] | None = None,
|
|
346
|
+
exclude: set[str] | None = None,
|
|
347
|
+
) -> Any:
|
|
348
|
+
"""Recursively convert nested dictionaries and lists to camelCase.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
value: The value to convert.
|
|
352
|
+
exclude_none: Whether to exclude None values.
|
|
353
|
+
include: Fields to include in the output.
|
|
354
|
+
exclude: Fields to exclude from the output.
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
The converted value with camelCase keys.
|
|
358
|
+
"""
|
|
359
|
+
if isinstance(value, PropsBase):
|
|
360
|
+
# Convert nested PropsBase objects
|
|
361
|
+
return value.dict(
|
|
362
|
+
exclude_none=exclude_none, include=include, exclude=exclude
|
|
363
|
+
)
|
|
364
|
+
if isinstance(value, dict):
|
|
365
|
+
# Convert dictionary keys to camelCase
|
|
366
|
+
return {
|
|
367
|
+
format.to_camel_case(k): self._convert_to_camel_case(
|
|
368
|
+
v, exclude_none, include, exclude
|
|
369
|
+
)
|
|
370
|
+
for k, v in value.items()
|
|
371
|
+
if not (exclude_none and v is None)
|
|
372
|
+
}
|
|
373
|
+
if isinstance(value, (list, tuple)):
|
|
374
|
+
# Convert list/tuple items recursively
|
|
375
|
+
return [
|
|
376
|
+
self._convert_to_camel_case(item, exclude_none, include, exclude)
|
|
377
|
+
for item in value
|
|
378
|
+
]
|
|
379
|
+
# Return primitive values as-is
|
|
380
|
+
return value
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
@serializer(to=dict)
|
|
384
|
+
def serialize_props_base(value: PropsBase) -> dict:
|
|
385
|
+
"""Serialize a PropsBase instance.
|
|
386
|
+
|
|
387
|
+
Unlike serialize_base, this preserves callables (lambdas) since they're
|
|
388
|
+
needed for AG Grid and other components that process them on the frontend.
|
|
389
|
+
|
|
390
|
+
Args:
|
|
391
|
+
value: The PropsBase instance to serialize.
|
|
392
|
+
|
|
393
|
+
Returns:
|
|
394
|
+
Dictionary representation of the PropsBase instance.
|
|
395
|
+
"""
|
|
396
|
+
return value.dict()
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class NoExtrasAllowedProps(PropsBase):
|
|
51
400
|
"""A class that holds props to be passed or applied to a component with no extra props allowed."""
|
|
52
401
|
|
|
53
402
|
def __init__(self, component_name: str | None = None, **kwargs):
|
|
54
|
-
"""Initialize the props.
|
|
403
|
+
"""Initialize the props with validation.
|
|
55
404
|
|
|
56
405
|
Args:
|
|
57
406
|
component_name: The custom name of the component.
|
|
@@ -61,17 +410,17 @@ class NoExtrasAllowedProps(Base):
|
|
|
61
410
|
InvalidPropValueError: If invalid props are passed on instantiation.
|
|
62
411
|
"""
|
|
63
412
|
component_name = component_name or type(self).__name__
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
413
|
+
|
|
414
|
+
# Validate fields BEFORE setting them
|
|
415
|
+
known_fields = set(self.__class__.get_fields().keys())
|
|
416
|
+
provided_fields = set(kwargs.keys())
|
|
417
|
+
invalid_fields = provided_fields - known_fields
|
|
418
|
+
|
|
419
|
+
if invalid_fields:
|
|
420
|
+
invalid_fields_str = ", ".join(invalid_fields)
|
|
421
|
+
supported_props_str = ", ".join(f'"{field}"' for field in known_fields)
|
|
422
|
+
msg = f"Invalid prop(s) {invalid_fields_str} for {component_name!r}. Supported props are {supported_props_str}"
|
|
423
|
+
raise InvalidPropValueError(msg)
|
|
424
|
+
|
|
425
|
+
# Use parent class initialization after validation
|
|
426
|
+
super().__init__(**kwargs)
|
|
@@ -3,68 +3,126 @@
|
|
|
3
3
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
|
4
4
|
# ------------------------------------------------------
|
|
5
5
|
|
|
6
|
-
from . import primitives
|
|
7
|
-
from . import
|
|
8
|
-
from .primitives.
|
|
9
|
-
from .primitives.
|
|
10
|
-
from .
|
|
11
|
-
from .themes.
|
|
12
|
-
from .themes.
|
|
13
|
-
from .themes.
|
|
14
|
-
from .themes.components.
|
|
15
|
-
from .themes.components.
|
|
16
|
-
from .themes.components.
|
|
17
|
-
from .themes.components.
|
|
18
|
-
from .themes.components.
|
|
19
|
-
from .themes.components.
|
|
20
|
-
from .themes.components.
|
|
21
|
-
from .themes.components.
|
|
22
|
-
from .themes.components.
|
|
23
|
-
from .themes.components.
|
|
24
|
-
from .themes.components.
|
|
25
|
-
from .themes.components.
|
|
26
|
-
from .themes.components.
|
|
27
|
-
from .themes.components.
|
|
28
|
-
from .themes.components.
|
|
29
|
-
from .themes.components.
|
|
30
|
-
from .themes.components.
|
|
31
|
-
from .themes.components.
|
|
32
|
-
from .themes.components.
|
|
33
|
-
from .themes.components.
|
|
34
|
-
from .themes.components.
|
|
35
|
-
from .themes.components.
|
|
36
|
-
from .themes.components.
|
|
37
|
-
from .themes.components.
|
|
38
|
-
from .themes.components.
|
|
39
|
-
from .themes.components.
|
|
40
|
-
from .themes.components.
|
|
41
|
-
from .themes.components.
|
|
42
|
-
from .themes.components.
|
|
43
|
-
from .themes.components.
|
|
44
|
-
from .themes.components.
|
|
45
|
-
from .themes.components.
|
|
46
|
-
from .themes.
|
|
47
|
-
from .themes.
|
|
48
|
-
from .themes.
|
|
49
|
-
from .themes.
|
|
50
|
-
from .themes.
|
|
51
|
-
from .themes.
|
|
52
|
-
from .themes.layout.
|
|
53
|
-
from .themes.layout.
|
|
54
|
-
from .themes.layout.
|
|
55
|
-
from .themes.layout.
|
|
56
|
-
from .themes.
|
|
57
|
-
from .themes.
|
|
58
|
-
from .themes.
|
|
59
|
-
from .themes.
|
|
60
|
-
from .themes.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
6
|
+
from . import primitives, themes
|
|
7
|
+
from .primitives.accordion import accordion
|
|
8
|
+
from .primitives.drawer import drawer
|
|
9
|
+
from .primitives.form import form
|
|
10
|
+
from .themes.base import theme, theme_panel
|
|
11
|
+
from .themes.color_mode import color_mode
|
|
12
|
+
from .themes.components.alert_dialog import alert_dialog
|
|
13
|
+
from .themes.components.aspect_ratio import aspect_ratio
|
|
14
|
+
from .themes.components.avatar import avatar
|
|
15
|
+
from .themes.components.badge import badge
|
|
16
|
+
from .themes.components.button import button
|
|
17
|
+
from .themes.components.callout import callout
|
|
18
|
+
from .themes.components.card import card
|
|
19
|
+
from .themes.components.checkbox import checkbox
|
|
20
|
+
from .themes.components.checkbox_cards import checkbox_cards
|
|
21
|
+
from .themes.components.checkbox_group import checkbox_group
|
|
22
|
+
from .themes.components.context_menu import context_menu
|
|
23
|
+
from .themes.components.data_list import data_list
|
|
24
|
+
from .themes.components.dialog import dialog
|
|
25
|
+
from .themes.components.dropdown_menu import dropdown_menu, menu
|
|
26
|
+
from .themes.components.hover_card import hover_card
|
|
27
|
+
from .themes.components.icon_button import icon_button
|
|
28
|
+
from .themes.components.inset import inset
|
|
29
|
+
from .themes.components.popover import popover
|
|
30
|
+
from .themes.components.progress import progress
|
|
31
|
+
from .themes.components.radio_cards import radio_cards
|
|
32
|
+
from .themes.components.radio_group import radio, radio_group
|
|
33
|
+
from .themes.components.scroll_area import scroll_area
|
|
34
|
+
from .themes.components.segmented_control import segmented_control
|
|
35
|
+
from .themes.components.select import select
|
|
36
|
+
from .themes.components.separator import divider, separator
|
|
37
|
+
from .themes.components.skeleton import skeleton
|
|
38
|
+
from .themes.components.slider import slider
|
|
39
|
+
from .themes.components.spinner import spinner
|
|
40
|
+
from .themes.components.switch import switch
|
|
41
|
+
from .themes.components.table import table
|
|
42
|
+
from .themes.components.tabs import tabs
|
|
43
|
+
from .themes.components.text_area import text_area
|
|
44
|
+
from .themes.components.text_field import input, text_field
|
|
45
|
+
from .themes.components.tooltip import tooltip
|
|
46
|
+
from .themes.layout.box import box
|
|
47
|
+
from .themes.layout.center import center
|
|
48
|
+
from .themes.layout.container import container
|
|
49
|
+
from .themes.layout.flex import flex
|
|
50
|
+
from .themes.layout.grid import grid
|
|
51
|
+
from .themes.layout.list import list_item, ordered_list, unordered_list
|
|
52
|
+
from .themes.layout.list import list_ns as list
|
|
53
|
+
from .themes.layout.section import section
|
|
54
|
+
from .themes.layout.spacer import spacer
|
|
55
|
+
from .themes.layout.stack import hstack, stack, vstack
|
|
56
|
+
from .themes.typography.blockquote import blockquote
|
|
57
|
+
from .themes.typography.code import code
|
|
58
|
+
from .themes.typography.heading import heading
|
|
59
|
+
from .themes.typography.link import link
|
|
60
|
+
from .themes.typography.text import text
|
|
61
|
+
|
|
62
|
+
__all__ = [
|
|
63
|
+
"accordion",
|
|
64
|
+
"alert_dialog",
|
|
65
|
+
"aspect_ratio",
|
|
66
|
+
"avatar",
|
|
67
|
+
"badge",
|
|
68
|
+
"blockquote",
|
|
69
|
+
"box",
|
|
70
|
+
"button",
|
|
71
|
+
"callout",
|
|
72
|
+
"card",
|
|
73
|
+
"center",
|
|
74
|
+
"checkbox",
|
|
75
|
+
"checkbox_cards",
|
|
76
|
+
"checkbox_group",
|
|
77
|
+
"code",
|
|
78
|
+
"color_mode",
|
|
79
|
+
"container",
|
|
80
|
+
"context_menu",
|
|
81
|
+
"data_list",
|
|
82
|
+
"dialog",
|
|
83
|
+
"divider",
|
|
84
|
+
"drawer",
|
|
85
|
+
"dropdown_menu",
|
|
86
|
+
"flex",
|
|
87
|
+
"form",
|
|
88
|
+
"grid",
|
|
89
|
+
"heading",
|
|
90
|
+
"hover_card",
|
|
91
|
+
"hstack",
|
|
92
|
+
"icon_button",
|
|
93
|
+
"input",
|
|
94
|
+
"inset",
|
|
95
|
+
"link",
|
|
96
|
+
"list",
|
|
97
|
+
"list_item",
|
|
98
|
+
"menu",
|
|
99
|
+
"ordered_list",
|
|
100
|
+
"popover",
|
|
101
|
+
"primitives",
|
|
102
|
+
"progress",
|
|
103
|
+
"radio",
|
|
104
|
+
"radio_cards",
|
|
105
|
+
"radio_group",
|
|
106
|
+
"scroll_area",
|
|
107
|
+
"section",
|
|
108
|
+
"segmented_control",
|
|
109
|
+
"select",
|
|
110
|
+
"separator",
|
|
111
|
+
"skeleton",
|
|
112
|
+
"slider",
|
|
113
|
+
"spacer",
|
|
114
|
+
"spinner",
|
|
115
|
+
"stack",
|
|
116
|
+
"switch",
|
|
117
|
+
"table",
|
|
118
|
+
"tabs",
|
|
119
|
+
"text",
|
|
120
|
+
"text_area",
|
|
121
|
+
"text_field",
|
|
122
|
+
"theme",
|
|
123
|
+
"theme_panel",
|
|
124
|
+
"themes",
|
|
125
|
+
"tooltip",
|
|
126
|
+
"unordered_list",
|
|
127
|
+
"vstack",
|
|
128
|
+
]
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
|
4
4
|
# ------------------------------------------------------
|
|
5
5
|
|
|
6
|
-
from .accordion import accordion
|
|
7
|
-
from .drawer import drawer
|
|
8
|
-
from .form import form
|
|
9
|
-
from .progress import progress
|
|
6
|
+
from .accordion import accordion
|
|
7
|
+
from .drawer import drawer
|
|
8
|
+
from .form import form
|
|
9
|
+
from .progress import progress
|
|
10
|
+
|
|
11
|
+
__all__ = ["accordion", "drawer", "form", "progress"]
|
|
@@ -334,7 +334,11 @@ class AccordionHeader(AccordionComponent):
|
|
|
334
334
|
Returns:
|
|
335
335
|
The style of the component.
|
|
336
336
|
"""
|
|
337
|
-
return {
|
|
337
|
+
return {
|
|
338
|
+
"display": "flex",
|
|
339
|
+
# Reset some values to ensure consistent styling without tailwind reset.
|
|
340
|
+
"margin": "0",
|
|
341
|
+
}
|
|
338
342
|
|
|
339
343
|
|
|
340
344
|
class AccordionTrigger(AccordionComponent):
|
|
@@ -399,6 +403,9 @@ class AccordionTrigger(AccordionComponent):
|
|
|
399
403
|
"color": "var(--accent-contrast)",
|
|
400
404
|
},
|
|
401
405
|
},
|
|
406
|
+
# Reset some values to ensure consistent styling without tailwind reset.
|
|
407
|
+
"background": "none",
|
|
408
|
+
"border": "none",
|
|
402
409
|
}
|
|
403
410
|
|
|
404
411
|
|