reflex 0.7.14a5__py3-none-any.whl → 0.8.0a1__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 +16 -10
- 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/utils/context.js.jinja2 +25 -6
- 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 -32
- reflex/.templates/web/postcss.config.js +1 -1
- reflex/.templates/web/react-router.config.js +6 -0
- reflex/.templates/web/utils/client_side_routing.js +21 -19
- reflex/.templates/web/utils/react-theme.js +89 -0
- reflex/.templates/web/utils/state.js +155 -67
- reflex/.templates/web/vite.config.js +32 -0
- reflex/__init__.py +1 -6
- reflex/__init__.pyi +0 -4
- reflex/app.py +69 -132
- reflex/base.py +1 -87
- reflex/compiler/compiler.py +40 -3
- reflex/compiler/utils.py +54 -28
- reflex/components/__init__.py +0 -2
- reflex/components/__init__.pyi +0 -3
- reflex/components/base/__init__.py +1 -5
- reflex/components/base/__init__.pyi +4 -6
- reflex/components/base/app_wrap.pyi +5 -4
- reflex/components/base/body.pyi +5 -4
- reflex/components/base/document.py +18 -14
- reflex/components/base/document.pyi +83 -27
- reflex/components/base/error_boundary.pyi +5 -4
- reflex/components/base/fragment.pyi +5 -4
- reflex/components/base/link.pyi +9 -7
- reflex/components/base/meta.pyi +17 -13
- reflex/components/base/script.py +60 -58
- reflex/components/base/script.pyi +246 -31
- reflex/components/base/strict_mode.pyi +5 -4
- reflex/components/component.py +109 -194
- reflex/components/core/__init__.py +1 -0
- reflex/components/core/__init__.pyi +1 -0
- reflex/components/core/auto_scroll.pyi +5 -4
- reflex/components/core/banner.pyi +25 -19
- reflex/components/core/client_side_routing.py +7 -6
- reflex/components/core/client_side_routing.pyi +6 -56
- reflex/components/core/clipboard.pyi +5 -4
- reflex/components/core/debounce.py +1 -0
- reflex/components/core/debounce.pyi +5 -4
- reflex/components/core/foreach.py +3 -2
- reflex/components/core/helmet.py +14 -0
- reflex/components/{next/base.pyi → core/helmet.pyi} +10 -7
- reflex/components/core/html.pyi +5 -4
- reflex/components/core/sticky.pyi +17 -13
- reflex/components/core/upload.py +2 -1
- reflex/components/core/upload.pyi +21 -16
- reflex/components/datadisplay/code.pyi +9 -7
- reflex/components/datadisplay/dataeditor.pyi +5 -4
- reflex/components/datadisplay/shiki_code_block.pyi +13 -10
- reflex/components/dynamic.py +4 -5
- reflex/components/el/element.pyi +5 -4
- reflex/components/el/elements/base.pyi +5 -4
- reflex/components/el/elements/forms.pyi +69 -52
- reflex/components/el/elements/inline.pyi +113 -85
- reflex/components/el/elements/media.pyi +105 -79
- reflex/components/el/elements/metadata.pyi +25 -19
- reflex/components/el/elements/other.pyi +29 -22
- reflex/components/el/elements/scripts.pyi +13 -10
- reflex/components/el/elements/sectioning.pyi +61 -46
- reflex/components/el/elements/tables.pyi +41 -31
- reflex/components/el/elements/typography.pyi +61 -46
- reflex/components/field.py +175 -0
- reflex/components/gridjs/datatable.py +2 -2
- reflex/components/gridjs/datatable.pyi +11 -9
- reflex/components/lucide/icon.py +6 -2
- reflex/components/lucide/icon.pyi +15 -10
- reflex/components/markdown/markdown.pyi +5 -4
- reflex/components/moment/moment.pyi +5 -4
- reflex/components/plotly/plotly.pyi +19 -10
- reflex/components/props.py +376 -27
- reflex/components/radix/primitives/accordion.py +8 -1
- reflex/components/radix/primitives/accordion.pyi +29 -22
- reflex/components/radix/primitives/base.pyi +9 -7
- reflex/components/radix/primitives/drawer.pyi +45 -34
- reflex/components/radix/primitives/form.pyi +41 -31
- reflex/components/radix/primitives/progress.pyi +21 -16
- reflex/components/radix/primitives/slider.pyi +21 -16
- reflex/components/radix/themes/base.py +3 -3
- reflex/components/radix/themes/base.pyi +33 -25
- reflex/components/radix/themes/color_mode.pyi +13 -10
- reflex/components/radix/themes/components/alert_dialog.pyi +29 -22
- reflex/components/radix/themes/components/aspect_ratio.pyi +5 -4
- reflex/components/radix/themes/components/avatar.pyi +5 -4
- reflex/components/radix/themes/components/badge.pyi +5 -4
- reflex/components/radix/themes/components/button.pyi +5 -4
- reflex/components/radix/themes/components/callout.pyi +21 -16
- reflex/components/radix/themes/components/card.pyi +5 -4
- reflex/components/radix/themes/components/checkbox.pyi +13 -10
- reflex/components/radix/themes/components/checkbox_cards.pyi +9 -7
- reflex/components/radix/themes/components/checkbox_group.pyi +9 -7
- reflex/components/radix/themes/components/context_menu.pyi +53 -40
- reflex/components/radix/themes/components/data_list.pyi +17 -13
- reflex/components/radix/themes/components/dialog.pyi +29 -22
- reflex/components/radix/themes/components/dropdown_menu.pyi +33 -25
- reflex/components/radix/themes/components/hover_card.pyi +17 -13
- reflex/components/radix/themes/components/icon_button.pyi +5 -4
- reflex/components/radix/themes/components/inset.pyi +5 -4
- reflex/components/radix/themes/components/popover.pyi +17 -13
- reflex/components/radix/themes/components/progress.pyi +5 -4
- reflex/components/radix/themes/components/radio.pyi +5 -4
- reflex/components/radix/themes/components/radio_cards.pyi +9 -7
- reflex/components/radix/themes/components/radio_group.pyi +17 -13
- reflex/components/radix/themes/components/scroll_area.pyi +5 -4
- reflex/components/radix/themes/components/segmented_control.pyi +9 -7
- reflex/components/radix/themes/components/select.pyi +37 -28
- reflex/components/radix/themes/components/separator.pyi +5 -4
- reflex/components/radix/themes/components/skeleton.pyi +5 -4
- reflex/components/radix/themes/components/slider.pyi +5 -4
- reflex/components/radix/themes/components/spinner.pyi +5 -4
- reflex/components/radix/themes/components/switch.pyi +5 -4
- reflex/components/radix/themes/components/table.pyi +29 -22
- reflex/components/radix/themes/components/tabs.pyi +21 -16
- reflex/components/radix/themes/components/text_area.pyi +5 -4
- reflex/components/radix/themes/components/text_field.pyi +13 -10
- reflex/components/radix/themes/components/tooltip.pyi +5 -4
- reflex/components/radix/themes/layout/base.pyi +5 -4
- reflex/components/radix/themes/layout/box.pyi +5 -4
- reflex/components/radix/themes/layout/center.pyi +5 -4
- reflex/components/radix/themes/layout/container.pyi +5 -4
- reflex/components/radix/themes/layout/flex.pyi +5 -4
- reflex/components/radix/themes/layout/grid.pyi +5 -4
- reflex/components/radix/themes/layout/list.pyi +21 -16
- reflex/components/radix/themes/layout/section.pyi +5 -4
- reflex/components/radix/themes/layout/spacer.pyi +5 -4
- reflex/components/radix/themes/layout/stack.pyi +13 -10
- reflex/components/radix/themes/typography/blockquote.pyi +5 -4
- reflex/components/radix/themes/typography/code.pyi +5 -4
- reflex/components/radix/themes/typography/heading.pyi +5 -4
- reflex/components/radix/themes/typography/link.py +42 -9
- reflex/components/radix/themes/typography/link.pyi +311 -6
- reflex/components/radix/themes/typography/text.pyi +29 -22
- reflex/components/react_player/audio.pyi +5 -4
- reflex/components/react_player/react_player.pyi +5 -4
- reflex/components/react_player/video.pyi +5 -4
- reflex/components/recharts/cartesian.py +2 -1
- reflex/components/recharts/cartesian.pyi +65 -46
- reflex/components/recharts/charts.py +4 -2
- reflex/components/recharts/charts.pyi +36 -24
- reflex/components/recharts/general.pyi +24 -18
- reflex/components/recharts/polar.py +8 -4
- reflex/components/recharts/polar.pyi +16 -10
- reflex/components/recharts/recharts.pyi +9 -7
- reflex/components/sonner/toast.py +2 -2
- reflex/components/sonner/toast.pyi +7 -6
- reflex/config.py +3 -77
- reflex/constants/__init__.py +1 -0
- reflex/constants/base.py +38 -8
- reflex/constants/compiler.py +4 -2
- reflex/constants/event.py +1 -0
- reflex/constants/installer.py +23 -16
- reflex/constants/state.py +2 -0
- reflex/custom_components/custom_components.py +0 -14
- reflex/environment.py +1 -1
- reflex/event.py +178 -81
- reflex/experimental/__init__.py +0 -30
- 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 +158 -0
- reflex/plugins/sitemap.py +206 -0
- reflex/plugins/tailwind_v3.py +13 -106
- reflex/plugins/tailwind_v4.py +15 -108
- reflex/reflex.py +1 -0
- reflex/state.py +134 -140
- reflex/testing.py +57 -9
- reflex/utils/build.py +9 -69
- reflex/utils/exec.py +59 -161
- reflex/utils/export.py +1 -1
- reflex/utils/imports.py +0 -4
- reflex/utils/misc.py +28 -0
- reflex/utils/prerequisites.py +62 -59
- reflex/utils/processes.py +6 -6
- reflex/utils/pyi_generator.py +21 -9
- reflex/utils/serializers.py +14 -1
- reflex/utils/types.py +196 -61
- reflex/vars/__init__.py +2 -0
- reflex/vars/base.py +367 -134
- {reflex-0.7.14a5.dist-info → reflex-0.8.0a1.dist-info}/METADATA +12 -5
- {reflex-0.7.14a5.dist-info → reflex-0.8.0a1.dist-info}/RECORD +190 -196
- 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 → reflex-0.8.0a1.dist-info}/WHEEL +0 -0
- {reflex-0.7.14a5.dist-info → reflex-0.8.0a1.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.14a5.dist-info → reflex-0.8.0a1.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)
|
|
@@ -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
|
|
|
@@ -10,7 +10,7 @@ from reflex.components.component import Component, ComponentNamespace
|
|
|
10
10
|
from reflex.components.core.breakpoints import Breakpoints
|
|
11
11
|
from reflex.components.lucide.icon import Icon
|
|
12
12
|
from reflex.components.radix.primitives.base import RadixPrimitiveComponent
|
|
13
|
-
from reflex.event import EventType
|
|
13
|
+
from reflex.event import EventType, PointerEventInfo
|
|
14
14
|
from reflex.vars.base import Var
|
|
15
15
|
|
|
16
16
|
LiteralAccordionType = Literal["single", "multiple"]
|
|
@@ -102,9 +102,9 @@ class AccordionComponent(RadixPrimitiveComponent):
|
|
|
102
102
|
autofocus: bool | None = None,
|
|
103
103
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
104
104
|
on_blur: EventType[()] | None = None,
|
|
105
|
-
on_click: EventType[()] | None = None,
|
|
106
|
-
on_context_menu: EventType[()] | None = None,
|
|
107
|
-
on_double_click: EventType[()] | None = None,
|
|
105
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
106
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
107
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
108
108
|
on_focus: EventType[()] | None = None,
|
|
109
109
|
on_mount: EventType[()] | None = None,
|
|
110
110
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -115,6 +115,7 @@ class AccordionComponent(RadixPrimitiveComponent):
|
|
|
115
115
|
on_mouse_over: EventType[()] | None = None,
|
|
116
116
|
on_mouse_up: EventType[()] | None = None,
|
|
117
117
|
on_scroll: EventType[()] | None = None,
|
|
118
|
+
on_scroll_end: EventType[()] | None = None,
|
|
118
119
|
on_unmount: EventType[()] | None = None,
|
|
119
120
|
**props,
|
|
120
121
|
) -> AccordionComponent:
|
|
@@ -239,9 +240,9 @@ class AccordionRoot(AccordionComponent):
|
|
|
239
240
|
autofocus: bool | None = None,
|
|
240
241
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
241
242
|
on_blur: EventType[()] | None = None,
|
|
242
|
-
on_click: EventType[()] | None = None,
|
|
243
|
-
on_context_menu: EventType[()] | None = None,
|
|
244
|
-
on_double_click: EventType[()] | None = None,
|
|
243
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
244
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
245
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
245
246
|
on_focus: EventType[()] | None = None,
|
|
246
247
|
on_mount: EventType[()] | None = None,
|
|
247
248
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -252,6 +253,7 @@ class AccordionRoot(AccordionComponent):
|
|
|
252
253
|
on_mouse_over: EventType[()] | None = None,
|
|
253
254
|
on_mouse_up: EventType[()] | None = None,
|
|
254
255
|
on_scroll: EventType[()] | None = None,
|
|
256
|
+
on_scroll_end: EventType[()] | None = None,
|
|
255
257
|
on_unmount: EventType[()] | None = None,
|
|
256
258
|
on_value_change: EventType[()] | EventType[str | list[str]] | None = None,
|
|
257
259
|
**props,
|
|
@@ -373,9 +375,9 @@ class AccordionItem(AccordionComponent):
|
|
|
373
375
|
autofocus: bool | None = None,
|
|
374
376
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
375
377
|
on_blur: EventType[()] | None = None,
|
|
376
|
-
on_click: EventType[()] | None = None,
|
|
377
|
-
on_context_menu: EventType[()] | None = None,
|
|
378
|
-
on_double_click: EventType[()] | None = None,
|
|
378
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
379
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
380
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
379
381
|
on_focus: EventType[()] | None = None,
|
|
380
382
|
on_mount: EventType[()] | None = None,
|
|
381
383
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -386,6 +388,7 @@ class AccordionItem(AccordionComponent):
|
|
|
386
388
|
on_mouse_over: EventType[()] | None = None,
|
|
387
389
|
on_mouse_up: EventType[()] | None = None,
|
|
388
390
|
on_scroll: EventType[()] | None = None,
|
|
391
|
+
on_scroll_end: EventType[()] | None = None,
|
|
389
392
|
on_unmount: EventType[()] | None = None,
|
|
390
393
|
**props,
|
|
391
394
|
) -> AccordionItem:
|
|
@@ -496,9 +499,9 @@ class AccordionHeader(AccordionComponent):
|
|
|
496
499
|
autofocus: bool | None = None,
|
|
497
500
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
498
501
|
on_blur: EventType[()] | None = None,
|
|
499
|
-
on_click: EventType[()] | None = None,
|
|
500
|
-
on_context_menu: EventType[()] | None = None,
|
|
501
|
-
on_double_click: EventType[()] | None = None,
|
|
502
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
503
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
504
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
502
505
|
on_focus: EventType[()] | None = None,
|
|
503
506
|
on_mount: EventType[()] | None = None,
|
|
504
507
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -509,6 +512,7 @@ class AccordionHeader(AccordionComponent):
|
|
|
509
512
|
on_mouse_over: EventType[()] | None = None,
|
|
510
513
|
on_mouse_up: EventType[()] | None = None,
|
|
511
514
|
on_scroll: EventType[()] | None = None,
|
|
515
|
+
on_scroll_end: EventType[()] | None = None,
|
|
512
516
|
on_unmount: EventType[()] | None = None,
|
|
513
517
|
**props,
|
|
514
518
|
) -> AccordionHeader:
|
|
@@ -615,9 +619,9 @@ class AccordionTrigger(AccordionComponent):
|
|
|
615
619
|
autofocus: bool | None = None,
|
|
616
620
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
617
621
|
on_blur: EventType[()] | None = None,
|
|
618
|
-
on_click: EventType[()] | None = None,
|
|
619
|
-
on_context_menu: EventType[()] | None = None,
|
|
620
|
-
on_double_click: EventType[()] | None = None,
|
|
622
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
623
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
624
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
621
625
|
on_focus: EventType[()] | None = None,
|
|
622
626
|
on_mount: EventType[()] | None = None,
|
|
623
627
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -628,6 +632,7 @@ class AccordionTrigger(AccordionComponent):
|
|
|
628
632
|
on_mouse_over: EventType[()] | None = None,
|
|
629
633
|
on_mouse_up: EventType[()] | None = None,
|
|
630
634
|
on_scroll: EventType[()] | None = None,
|
|
635
|
+
on_scroll_end: EventType[()] | None = None,
|
|
631
636
|
on_unmount: EventType[()] | None = None,
|
|
632
637
|
**props,
|
|
633
638
|
) -> AccordionTrigger:
|
|
@@ -672,9 +677,9 @@ class AccordionIcon(Icon):
|
|
|
672
677
|
autofocus: bool | None = None,
|
|
673
678
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
674
679
|
on_blur: EventType[()] | None = None,
|
|
675
|
-
on_click: EventType[()] | None = None,
|
|
676
|
-
on_context_menu: EventType[()] | None = None,
|
|
677
|
-
on_double_click: EventType[()] | None = None,
|
|
680
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
681
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
682
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
678
683
|
on_focus: EventType[()] | None = None,
|
|
679
684
|
on_mount: EventType[()] | None = None,
|
|
680
685
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -685,6 +690,7 @@ class AccordionIcon(Icon):
|
|
|
685
690
|
on_mouse_over: EventType[()] | None = None,
|
|
686
691
|
on_mouse_up: EventType[()] | None = None,
|
|
687
692
|
on_scroll: EventType[()] | None = None,
|
|
693
|
+
on_scroll_end: EventType[()] | None = None,
|
|
688
694
|
on_unmount: EventType[()] | None = None,
|
|
689
695
|
**props,
|
|
690
696
|
) -> AccordionIcon:
|
|
@@ -788,9 +794,9 @@ class AccordionContent(AccordionComponent):
|
|
|
788
794
|
autofocus: bool | None = None,
|
|
789
795
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
790
796
|
on_blur: EventType[()] | None = None,
|
|
791
|
-
on_click: EventType[()] | None = None,
|
|
792
|
-
on_context_menu: EventType[()] | None = None,
|
|
793
|
-
on_double_click: EventType[()] | None = None,
|
|
797
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
798
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
799
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
794
800
|
on_focus: EventType[()] | None = None,
|
|
795
801
|
on_mount: EventType[()] | None = None,
|
|
796
802
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -801,6 +807,7 @@ class AccordionContent(AccordionComponent):
|
|
|
801
807
|
on_mouse_over: EventType[()] | None = None,
|
|
802
808
|
on_mouse_up: EventType[()] | None = None,
|
|
803
809
|
on_scroll: EventType[()] | None = None,
|
|
810
|
+
on_scroll_end: EventType[()] | None = None,
|
|
804
811
|
on_unmount: EventType[()] | None = None,
|
|
805
812
|
**props,
|
|
806
813
|
) -> AccordionContent:
|
|
@@ -8,7 +8,7 @@ from typing import Any, overload
|
|
|
8
8
|
|
|
9
9
|
from reflex.components.component import Component
|
|
10
10
|
from reflex.components.core.breakpoints import Breakpoints
|
|
11
|
-
from reflex.event import EventType
|
|
11
|
+
from reflex.event import EventType, PointerEventInfo
|
|
12
12
|
from reflex.vars.base import Var
|
|
13
13
|
|
|
14
14
|
class RadixPrimitiveComponent(Component):
|
|
@@ -30,9 +30,9 @@ class RadixPrimitiveComponent(Component):
|
|
|
30
30
|
autofocus: bool | None = None,
|
|
31
31
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
32
32
|
on_blur: EventType[()] | None = None,
|
|
33
|
-
on_click: EventType[()] | None = None,
|
|
34
|
-
on_context_menu: EventType[()] | None = None,
|
|
35
|
-
on_double_click: EventType[()] | None = None,
|
|
33
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
34
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
35
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
36
36
|
on_focus: EventType[()] | None = None,
|
|
37
37
|
on_mount: EventType[()] | None = None,
|
|
38
38
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -43,6 +43,7 @@ class RadixPrimitiveComponent(Component):
|
|
|
43
43
|
on_mouse_over: EventType[()] | None = None,
|
|
44
44
|
on_mouse_up: EventType[()] | None = None,
|
|
45
45
|
on_scroll: EventType[()] | None = None,
|
|
46
|
+
on_scroll_end: EventType[()] | None = None,
|
|
46
47
|
on_unmount: EventType[()] | None = None,
|
|
47
48
|
**props,
|
|
48
49
|
) -> RadixPrimitiveComponent:
|
|
@@ -83,9 +84,9 @@ class RadixPrimitiveComponentWithClassName(RadixPrimitiveComponent):
|
|
|
83
84
|
autofocus: bool | None = None,
|
|
84
85
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
85
86
|
on_blur: EventType[()] | None = None,
|
|
86
|
-
on_click: EventType[()] | None = None,
|
|
87
|
-
on_context_menu: EventType[()] | None = None,
|
|
88
|
-
on_double_click: EventType[()] | None = None,
|
|
87
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
88
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
89
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
89
90
|
on_focus: EventType[()] | None = None,
|
|
90
91
|
on_mount: EventType[()] | None = None,
|
|
91
92
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -96,6 +97,7 @@ class RadixPrimitiveComponentWithClassName(RadixPrimitiveComponent):
|
|
|
96
97
|
on_mouse_over: EventType[()] | None = None,
|
|
97
98
|
on_mouse_up: EventType[()] | None = None,
|
|
98
99
|
on_scroll: EventType[()] | None = None,
|
|
100
|
+
on_scroll_end: EventType[()] | None = None,
|
|
99
101
|
on_unmount: EventType[()] | None = None,
|
|
100
102
|
**props,
|
|
101
103
|
) -> RadixPrimitiveComponentWithClassName:
|