reflex 0.6.8a2__py3-none-any.whl → 0.7.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/custom_components/pyproject.toml.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +7 -7
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +1 -4
- reflex/.templates/web/utils/state.js +65 -36
- reflex/__init__.py +4 -17
- reflex/__init__.pyi +1 -2
- reflex/app.py +244 -109
- reflex/app_mixins/lifespan.py +9 -9
- reflex/app_mixins/middleware.py +6 -6
- reflex/app_module_for_backend.py +3 -7
- reflex/base.py +7 -7
- reflex/compiler/compiler.py +8 -0
- reflex/compiler/utils.py +35 -6
- reflex/components/base/bare.py +1 -1
- reflex/components/base/error_boundary.py +2 -1
- reflex/components/base/error_boundary.pyi +2 -1
- reflex/components/base/meta.py +2 -2
- reflex/components/base/strict_mode.py +10 -0
- reflex/components/base/strict_mode.pyi +57 -0
- reflex/components/component.py +38 -77
- reflex/components/core/banner.py +83 -4
- reflex/components/core/banner.pyi +86 -0
- reflex/components/core/breakpoints.py +3 -1
- reflex/components/core/client_side_routing.py +1 -1
- reflex/components/core/client_side_routing.pyi +1 -1
- reflex/components/core/cond.py +9 -10
- reflex/components/core/debounce.py +1 -1
- reflex/components/core/foreach.py +23 -3
- reflex/components/core/html.py +1 -1
- reflex/components/core/match.py +5 -5
- reflex/components/core/sticky.py +160 -0
- reflex/components/core/sticky.pyi +449 -0
- reflex/components/core/upload.py +2 -2
- reflex/components/datadisplay/code.py +5 -14
- reflex/components/datadisplay/dataeditor.py +7 -4
- reflex/components/datadisplay/logo.py +13 -8
- reflex/components/datadisplay/shiki_code_block.py +14 -9
- reflex/components/dynamic.py +22 -3
- reflex/components/el/constants/reflex.py +1 -1
- reflex/components/el/element.py +1 -1
- reflex/components/el/elements/forms.py +4 -4
- reflex/components/el/elements/forms.pyi +4 -4
- reflex/components/lucide/icon.py +46 -8
- reflex/components/lucide/icon.pyi +54 -0
- reflex/components/markdown/markdown.py +10 -8
- reflex/components/moment/moment.py +2 -2
- reflex/components/next/image.py +16 -4
- reflex/components/next/image.pyi +4 -2
- reflex/components/next/link.py +1 -1
- reflex/components/plotly/plotly.py +5 -5
- reflex/components/props.py +3 -3
- reflex/components/radix/__init__.pyi +1 -1
- reflex/components/radix/primitives/accordion.py +9 -5
- reflex/components/radix/primitives/accordion.pyi +3 -1
- reflex/components/radix/primitives/drawer.py +5 -2
- reflex/components/radix/primitives/drawer.pyi +4 -4
- reflex/components/radix/primitives/form.pyi +6 -6
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/themes/color_mode.py +11 -9
- reflex/components/radix/themes/components/alert_dialog.py +3 -0
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +1 -1
- reflex/components/radix/themes/components/context_menu.py +5 -0
- reflex/components/radix/themes/components/dialog.py +3 -0
- reflex/components/radix/themes/components/dropdown_menu.py +5 -0
- reflex/components/radix/themes/components/hover_card.py +3 -0
- reflex/components/radix/themes/components/icon_button.py +2 -2
- reflex/components/radix/themes/components/icon_button.pyi +1 -0
- reflex/components/radix/themes/components/popover.py +3 -0
- reflex/components/radix/themes/components/radio_cards.py +2 -0
- reflex/components/radix/themes/components/radio_group.py +1 -1
- reflex/components/radix/themes/components/select.py +3 -0
- reflex/components/radix/themes/components/tabs.py +3 -0
- reflex/components/radix/themes/components/text_area.py +12 -0
- reflex/components/radix/themes/components/text_area.pyi +2 -0
- reflex/components/radix/themes/components/text_field.py +1 -1
- reflex/components/radix/themes/components/tooltip.py +3 -1
- reflex/components/radix/themes/components/tooltip.pyi +1 -0
- reflex/components/radix/themes/layout/__init__.pyi +1 -1
- reflex/components/radix/themes/layout/list.py +2 -2
- reflex/components/radix/themes/layout/stack.py +2 -2
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/text.py +2 -2
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/recharts/__init__.py +2 -0
- reflex/components/recharts/__init__.pyi +2 -0
- reflex/components/recharts/charts.py +15 -15
- reflex/components/recharts/general.py +19 -4
- reflex/components/recharts/general.pyi +55 -4
- reflex/components/recharts/polar.py +2 -2
- reflex/components/recharts/recharts.py +4 -4
- reflex/components/sonner/toast.py +15 -13
- reflex/components/sonner/toast.pyi +6 -6
- reflex/components/suneditor/editor.py +6 -4
- reflex/components/suneditor/editor.pyi +2 -2
- reflex/components/tags/iter_tag.py +3 -3
- reflex/components/tags/tag.py +25 -3
- reflex/config.py +48 -15
- reflex/constants/__init__.py +1 -0
- reflex/constants/base.py +4 -1
- reflex/constants/compiler.py +5 -2
- reflex/constants/config.py +8 -1
- reflex/constants/installer.py +9 -9
- reflex/constants/style.py +1 -1
- reflex/custom_components/custom_components.py +9 -7
- reflex/event.py +130 -161
- reflex/experimental/__init__.py +19 -11
- reflex/experimental/client_state.py +53 -28
- reflex/experimental/hooks.py +5 -5
- reflex/experimental/layout.py +8 -5
- reflex/experimental/layout.pyi +1 -1
- reflex/experimental/misc.py +3 -3
- reflex/istate/wrappers.py +1 -1
- reflex/middleware/hydrate_middleware.py +2 -2
- reflex/model.py +11 -6
- reflex/page.py +3 -3
- reflex/reflex.py +90 -19
- reflex/route.py +1 -1
- reflex/state.py +358 -401
- reflex/style.py +27 -3
- reflex/testing.py +29 -23
- reflex/utils/build.py +6 -2
- reflex/utils/codespaces.py +1 -4
- reflex/utils/compat.py +6 -5
- reflex/utils/console.py +52 -16
- reflex/utils/exceptions.py +76 -26
- reflex/utils/exec.py +69 -74
- reflex/utils/export.py +6 -1
- reflex/utils/format.py +7 -39
- reflex/utils/imports.py +2 -2
- reflex/utils/lazy_loader.py +7 -1
- reflex/utils/path_ops.py +28 -14
- reflex/utils/prerequisites.py +324 -65
- reflex/utils/processes.py +45 -32
- reflex/utils/pyi_generator.py +30 -25
- reflex/utils/registry.py +4 -4
- reflex/utils/serializers.py +1 -1
- reflex/utils/telemetry.py +5 -4
- reflex/utils/types.py +42 -18
- reflex/vars/base.py +650 -333
- reflex/vars/datetime.py +6 -7
- reflex/vars/dep_tracking.py +344 -0
- reflex/vars/function.py +11 -5
- reflex/vars/number.py +31 -43
- reflex/vars/object.py +63 -62
- reflex/vars/sequence.py +79 -67
- {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/METADATA +7 -8
- {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/RECORD +153 -149
- {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/WHEEL +1 -1
- reflex/experimental/assets.py +0 -37
- {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/LICENSE +0 -0
- {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/entry_points.txt +0 -0
|
@@ -14,7 +14,7 @@ from reflex.components.radix.themes.layout.box import Box
|
|
|
14
14
|
from reflex.constants.colors import Color
|
|
15
15
|
from reflex.event import set_clipboard
|
|
16
16
|
from reflex.style import Style
|
|
17
|
-
from reflex.utils import
|
|
17
|
+
from reflex.utils import format
|
|
18
18
|
from reflex.utils.imports import ImportVar
|
|
19
19
|
from reflex.vars.base import LiteralVar, Var, VarData
|
|
20
20
|
|
|
@@ -382,7 +382,7 @@ for theme_name in dir(Theme):
|
|
|
382
382
|
class CodeBlock(Component, MarkdownComponentMap):
|
|
383
383
|
"""A code block."""
|
|
384
384
|
|
|
385
|
-
library = "react-syntax-highlighter@15.6.
|
|
385
|
+
library = "react-syntax-highlighter@15.6.1"
|
|
386
386
|
|
|
387
387
|
tag = "PrismAsyncLight"
|
|
388
388
|
|
|
@@ -438,6 +438,8 @@ class CodeBlock(Component, MarkdownComponentMap):
|
|
|
438
438
|
can_copy = props.pop("can_copy", False)
|
|
439
439
|
copy_button = props.pop("copy_button", None)
|
|
440
440
|
|
|
441
|
+
# react-syntax-highlighter doesn't have an explicit "light" or "dark" theme so we use one-light and one-dark
|
|
442
|
+
# themes respectively to ensure code compatibility.
|
|
441
443
|
if "theme" not in props:
|
|
442
444
|
# Default color scheme responds to global color mode.
|
|
443
445
|
props["theme"] = color_mode_cond(
|
|
@@ -445,20 +447,9 @@ class CodeBlock(Component, MarkdownComponentMap):
|
|
|
445
447
|
dark=Theme.one_dark,
|
|
446
448
|
)
|
|
447
449
|
|
|
448
|
-
# react-syntax-highlighter doesn't have an explicit "light" or "dark" theme so we use one-light and one-dark
|
|
449
|
-
# themes respectively to ensure code compatibility.
|
|
450
|
-
if "theme" in props and not isinstance(props["theme"], Var):
|
|
451
|
-
props["theme"] = getattr(Theme, format.to_snake_case(props["theme"])) # type: ignore
|
|
452
|
-
console.deprecate(
|
|
453
|
-
feature_name="theme prop as string",
|
|
454
|
-
reason="Use code_block.themes instead.",
|
|
455
|
-
deprecation_version="0.6.0",
|
|
456
|
-
removal_version="0.7.0",
|
|
457
|
-
)
|
|
458
|
-
|
|
459
450
|
if can_copy:
|
|
460
451
|
code = children[0]
|
|
461
|
-
copy_button = (
|
|
452
|
+
copy_button = (
|
|
462
453
|
copy_button
|
|
463
454
|
if copy_button is not None
|
|
464
455
|
else Button.create(
|
|
@@ -165,7 +165,7 @@ class DataEditor(NoSSRComponent):
|
|
|
165
165
|
|
|
166
166
|
tag = "DataEditor"
|
|
167
167
|
is_default = True
|
|
168
|
-
library: str = "@glideapps/glide-data-grid@^6.0.3"
|
|
168
|
+
library: str | None = "@glideapps/glide-data-grid@^6.0.3"
|
|
169
169
|
lib_dependencies: List[str] = [
|
|
170
170
|
"lodash@^4.17.21",
|
|
171
171
|
"react-responsive-carousel@^3.2.7",
|
|
@@ -321,6 +321,8 @@ class DataEditor(NoSSRComponent):
|
|
|
321
321
|
Returns:
|
|
322
322
|
The import dict.
|
|
323
323
|
"""
|
|
324
|
+
if self.library is None:
|
|
325
|
+
return {}
|
|
324
326
|
return {
|
|
325
327
|
"": f"{format.format_library_name(self.library)}/dist/index.css",
|
|
326
328
|
self.library: "GridCellKind",
|
|
@@ -343,9 +345,9 @@ class DataEditor(NoSSRComponent):
|
|
|
343
345
|
data_callback = self.get_cell_content._js_expr
|
|
344
346
|
else:
|
|
345
347
|
data_callback = f"getData_{editor_id}"
|
|
346
|
-
self.get_cell_content = Var(_js_expr=data_callback)
|
|
348
|
+
self.get_cell_content = Var(_js_expr=data_callback)
|
|
347
349
|
|
|
348
|
-
code = [f"function {data_callback}([col, row])
|
|
350
|
+
code = [f"function {data_callback}([col, row]){{"]
|
|
349
351
|
|
|
350
352
|
columns_path = str(self.columns)
|
|
351
353
|
data_path = str(self.data)
|
|
@@ -385,7 +387,8 @@ class DataEditor(NoSSRComponent):
|
|
|
385
387
|
raise ValueError(
|
|
386
388
|
"DataEditor data must be an ArrayVar if rows is not provided."
|
|
387
389
|
)
|
|
388
|
-
|
|
390
|
+
|
|
391
|
+
props["rows"] = data.length() if isinstance(data, ArrayVar) else len(data)
|
|
389
392
|
|
|
390
393
|
if not isinstance(columns, Var) and len(columns):
|
|
391
394
|
if types.is_dataframe(type(data)) or (
|
|
@@ -5,20 +5,22 @@ from typing import Union
|
|
|
5
5
|
import reflex as rx
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def svg_logo(
|
|
8
|
+
def svg_logo(
|
|
9
|
+
color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "white"),
|
|
10
|
+
**props,
|
|
11
|
+
):
|
|
9
12
|
"""A Reflex logo SVG.
|
|
10
13
|
|
|
11
14
|
Args:
|
|
12
15
|
color: The color of the logo.
|
|
16
|
+
props: Extra props to pass to the svg component.
|
|
13
17
|
|
|
14
18
|
Returns:
|
|
15
19
|
The Reflex logo SVG.
|
|
16
20
|
"""
|
|
17
21
|
|
|
18
|
-
def logo_path(d):
|
|
19
|
-
return rx.el.svg.path(
|
|
20
|
-
d=d,
|
|
21
|
-
)
|
|
22
|
+
def logo_path(d: str):
|
|
23
|
+
return rx.el.svg.path(d=d)
|
|
22
24
|
|
|
23
25
|
paths = [
|
|
24
26
|
"M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z",
|
|
@@ -31,11 +33,14 @@ def svg_logo(color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "whi
|
|
|
31
33
|
|
|
32
34
|
return rx.el.svg(
|
|
33
35
|
*[logo_path(d) for d in paths],
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
rx.el.title("Reflex"),
|
|
37
|
+
aria_label="Reflex",
|
|
38
|
+
role="img",
|
|
39
|
+
width=props.pop("width", "56"),
|
|
40
|
+
height=props.pop("height", "12"),
|
|
37
41
|
fill=color,
|
|
38
42
|
xmlns="http://www.w3.org/2000/svg",
|
|
43
|
+
**props,
|
|
39
44
|
)
|
|
40
45
|
|
|
41
46
|
|
|
@@ -602,7 +602,7 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
|
|
|
602
602
|
|
|
603
603
|
transformer_styles = {}
|
|
604
604
|
# Collect styles from transformers and wrapper
|
|
605
|
-
for transformer in code_block.transformers._var_value: #
|
|
605
|
+
for transformer in code_block.transformers._var_value: # pyright: ignore [reportAttributeAccessIssue]
|
|
606
606
|
if isinstance(transformer, ShikiBaseTransformers) and transformer.style:
|
|
607
607
|
transformer_styles.update(transformer.style)
|
|
608
608
|
transformer_styles.update(code_wrapper_props.pop("style", {}))
|
|
@@ -621,18 +621,22 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
|
|
|
621
621
|
|
|
622
622
|
Returns:
|
|
623
623
|
Imports for the component.
|
|
624
|
+
|
|
625
|
+
Raises:
|
|
626
|
+
ValueError: If the transformers are not of type LiteralVar.
|
|
624
627
|
"""
|
|
625
628
|
imports = defaultdict(list)
|
|
629
|
+
if not isinstance(self.transformers, LiteralVar):
|
|
630
|
+
raise ValueError(
|
|
631
|
+
f"transformers should be a LiteralVar type. Got {type(self.transformers)} instead."
|
|
632
|
+
)
|
|
626
633
|
for transformer in self.transformers._var_value:
|
|
627
634
|
if isinstance(transformer, ShikiBaseTransformers):
|
|
628
635
|
imports[transformer.library].extend(
|
|
629
636
|
[ImportVar(tag=str(fn)) for fn in transformer.fns]
|
|
630
637
|
)
|
|
631
|
-
|
|
638
|
+
if transformer.library not in self.lib_dependencies:
|
|
632
639
|
self.lib_dependencies.append(transformer.library)
|
|
633
|
-
if transformer.library not in self.lib_dependencies
|
|
634
|
-
else None
|
|
635
|
-
)
|
|
636
640
|
return imports
|
|
637
641
|
|
|
638
642
|
@classmethod
|
|
@@ -653,8 +657,9 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
|
|
|
653
657
|
raise ValueError(
|
|
654
658
|
f"the function names should be str names of functions in the specified transformer: {library!r}"
|
|
655
659
|
)
|
|
656
|
-
return ShikiBaseTransformers(
|
|
657
|
-
library=library,
|
|
660
|
+
return ShikiBaseTransformers(
|
|
661
|
+
library=library,
|
|
662
|
+
fns=[FunctionStringVar.create(fn) for fn in fns], # pyright: ignore [reportCallIssue]
|
|
658
663
|
)
|
|
659
664
|
|
|
660
665
|
def _render(self, props: dict[str, Any] | None = None):
|
|
@@ -757,13 +762,13 @@ class ShikiHighLevelCodeBlock(ShikiCodeBlock):
|
|
|
757
762
|
|
|
758
763
|
if can_copy:
|
|
759
764
|
code = children[0]
|
|
760
|
-
copy_button = (
|
|
765
|
+
copy_button = (
|
|
761
766
|
copy_button
|
|
762
767
|
if copy_button is not None
|
|
763
768
|
else Button.create(
|
|
764
769
|
Icon.create(tag="copy", size=16, color=color("gray", 11)),
|
|
765
770
|
on_click=[
|
|
766
|
-
set_clipboard(cls._strip_transformer_triggers(code)),
|
|
771
|
+
set_clipboard(cls._strip_transformer_triggers(code)),
|
|
767
772
|
copy_script(),
|
|
768
773
|
],
|
|
769
774
|
style=Style(
|
reflex/components/dynamic.py
CHANGED
|
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Union
|
|
|
4
4
|
|
|
5
5
|
from reflex import constants
|
|
6
6
|
from reflex.utils import imports
|
|
7
|
-
from reflex.utils.exceptions import
|
|
7
|
+
from reflex.utils.exceptions import DynamicComponentMissingLibraryError
|
|
8
8
|
from reflex.utils.format import format_library_name
|
|
9
9
|
from reflex.utils.serializers import serializer
|
|
10
10
|
from reflex.vars import Var, get_unique_variable_name
|
|
@@ -36,13 +36,15 @@ def bundle_library(component: Union["Component", str]):
|
|
|
36
36
|
component: The component to bundle the library with.
|
|
37
37
|
|
|
38
38
|
Raises:
|
|
39
|
-
|
|
39
|
+
DynamicComponentMissingLibraryError: Raised when a dynamic component is missing a library.
|
|
40
40
|
"""
|
|
41
41
|
if isinstance(component, str):
|
|
42
42
|
bundled_libraries.add(component)
|
|
43
43
|
return
|
|
44
44
|
if component.library is None:
|
|
45
|
-
raise
|
|
45
|
+
raise DynamicComponentMissingLibraryError(
|
|
46
|
+
"Component must have a library to bundle."
|
|
47
|
+
)
|
|
46
48
|
bundled_libraries.add(format_library_name(component.library))
|
|
47
49
|
|
|
48
50
|
|
|
@@ -136,6 +138,23 @@ def load_dynamic_serializer():
|
|
|
136
138
|
|
|
137
139
|
module_code_lines.insert(0, "const React = window.__reflex.react;")
|
|
138
140
|
|
|
141
|
+
function_line = next(
|
|
142
|
+
index
|
|
143
|
+
for index, line in enumerate(module_code_lines)
|
|
144
|
+
if line.startswith("export default function")
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
module_code_lines = [
|
|
148
|
+
line
|
|
149
|
+
for _, line in sorted(
|
|
150
|
+
enumerate(module_code_lines),
|
|
151
|
+
key=lambda x: (
|
|
152
|
+
not (x[1].startswith("import ") and x[0] < function_line),
|
|
153
|
+
x[0],
|
|
154
|
+
),
|
|
155
|
+
)
|
|
156
|
+
]
|
|
157
|
+
|
|
139
158
|
return "\n".join(
|
|
140
159
|
[
|
|
141
160
|
"//__reflex_evaluate",
|
reflex/components/el/element.py
CHANGED
|
@@ -102,7 +102,7 @@ class Fieldset(Element):
|
|
|
102
102
|
name: Var[Union[str, int, bool]]
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
def on_submit_event_spec() -> Tuple[Var[
|
|
105
|
+
def on_submit_event_spec() -> Tuple[Var[dict[str, Any]]]:
|
|
106
106
|
"""Event handler spec for the on_submit event.
|
|
107
107
|
|
|
108
108
|
Returns:
|
|
@@ -111,7 +111,7 @@ def on_submit_event_spec() -> Tuple[Var[Dict[str, Any]]]:
|
|
|
111
111
|
return (FORM_DATA,)
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
def on_submit_string_event_spec() -> Tuple[Var[
|
|
114
|
+
def on_submit_string_event_spec() -> Tuple[Var[dict[str, str]]]:
|
|
115
115
|
"""Event handler spec for the on_submit event.
|
|
116
116
|
|
|
117
117
|
Returns:
|
|
@@ -153,7 +153,7 @@ class Form(BaseHTML):
|
|
|
153
153
|
target: Var[Union[str, int, bool]]
|
|
154
154
|
|
|
155
155
|
# If true, the form will be cleared after submit.
|
|
156
|
-
reset_on_submit: Var[bool] = False
|
|
156
|
+
reset_on_submit: Var[bool] = Var.create(False)
|
|
157
157
|
|
|
158
158
|
# The name used to make this form's submit handler function unique.
|
|
159
159
|
handle_submit_unique_name: Var[str]
|
|
@@ -405,7 +405,7 @@ class Input(BaseHTML):
|
|
|
405
405
|
(value_var := Var.create(value))._var_type
|
|
406
406
|
):
|
|
407
407
|
props["value"] = ternary_operation(
|
|
408
|
-
(value_var != Var.create(None)) # pyright: ignore [
|
|
408
|
+
(value_var != Var.create(None)) # pyright: ignore [reportArgumentType]
|
|
409
409
|
& (value_var != Var(_js_expr="undefined")),
|
|
410
410
|
value,
|
|
411
411
|
Var.create(""),
|
|
@@ -270,8 +270,8 @@ class Fieldset(Element):
|
|
|
270
270
|
"""
|
|
271
271
|
...
|
|
272
272
|
|
|
273
|
-
def on_submit_event_spec() -> Tuple[Var[
|
|
274
|
-
def on_submit_string_event_spec() -> Tuple[Var[
|
|
273
|
+
def on_submit_event_spec() -> Tuple[Var[dict[str, Any]]]: ...
|
|
274
|
+
def on_submit_string_event_spec() -> Tuple[Var[dict[str, str]]]: ...
|
|
275
275
|
|
|
276
276
|
class Form(BaseHTML):
|
|
277
277
|
@overload
|
|
@@ -341,10 +341,10 @@ class Form(BaseHTML):
|
|
|
341
341
|
on_submit: Optional[
|
|
342
342
|
Union[
|
|
343
343
|
Union[
|
|
344
|
-
EventType[[], BASE_STATE], EventType[[
|
|
344
|
+
EventType[[], BASE_STATE], EventType[[dict[str, Any]], BASE_STATE]
|
|
345
345
|
],
|
|
346
346
|
Union[
|
|
347
|
-
EventType[[], BASE_STATE], EventType[[
|
|
347
|
+
EventType[[], BASE_STATE], EventType[[dict[str, str]], BASE_STATE]
|
|
348
348
|
],
|
|
349
349
|
]
|
|
350
350
|
] = None,
|
reflex/components/lucide/icon.py
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
from reflex.components.component import Component
|
|
4
4
|
from reflex.utils import format
|
|
5
|
-
from reflex.
|
|
5
|
+
from reflex.utils.imports import ImportVar
|
|
6
|
+
from reflex.vars.base import LiteralVar, Var
|
|
7
|
+
from reflex.vars.sequence import LiteralStringVar
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class LucideIconComponent(Component):
|
|
9
11
|
"""Lucide Icon Component."""
|
|
10
12
|
|
|
11
|
-
library = "lucide-react@0.
|
|
13
|
+
library = "lucide-react@0.471.1"
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
class Icon(LucideIconComponent):
|
|
@@ -32,6 +34,7 @@ class Icon(LucideIconComponent):
|
|
|
32
34
|
Raises:
|
|
33
35
|
AttributeError: The errors tied to bad usage of the Icon component.
|
|
34
36
|
ValueError: If the icon tag is invalid.
|
|
37
|
+
TypeError: If the icon name is not a string.
|
|
35
38
|
|
|
36
39
|
Returns:
|
|
37
40
|
The created component.
|
|
@@ -39,7 +42,6 @@ class Icon(LucideIconComponent):
|
|
|
39
42
|
if children:
|
|
40
43
|
if len(children) == 1 and isinstance(children[0], str):
|
|
41
44
|
props["tag"] = children[0]
|
|
42
|
-
children = []
|
|
43
45
|
else:
|
|
44
46
|
raise AttributeError(
|
|
45
47
|
f"Passing multiple children to Icon component is not allowed: remove positional arguments {children[1:]} to fix"
|
|
@@ -47,19 +49,46 @@ class Icon(LucideIconComponent):
|
|
|
47
49
|
if "tag" not in props:
|
|
48
50
|
raise AttributeError("Missing 'tag' keyword-argument for Icon")
|
|
49
51
|
|
|
52
|
+
tag: str | Var | LiteralVar = props.pop("tag")
|
|
53
|
+
if isinstance(tag, LiteralVar):
|
|
54
|
+
if isinstance(tag, LiteralStringVar):
|
|
55
|
+
tag = tag._var_value
|
|
56
|
+
else:
|
|
57
|
+
raise TypeError(f"Icon name must be a string, got {type(tag)}")
|
|
58
|
+
elif isinstance(tag, Var):
|
|
59
|
+
return DynamicIcon.create(name=tag, **props)
|
|
60
|
+
|
|
50
61
|
if (
|
|
51
|
-
not isinstance(
|
|
52
|
-
or format.to_snake_case(
|
|
62
|
+
not isinstance(tag, str)
|
|
63
|
+
or format.to_snake_case(tag) not in LUCIDE_ICON_LIST
|
|
53
64
|
):
|
|
54
65
|
raise ValueError(
|
|
55
|
-
f"Invalid icon tag: {
|
|
66
|
+
f"Invalid icon tag: {tag}. Please use one of the following: {', '.join(LUCIDE_ICON_LIST[0:25])}, ..."
|
|
56
67
|
"\nSee full list at https://lucide.dev/icons."
|
|
57
68
|
)
|
|
58
69
|
|
|
59
|
-
|
|
70
|
+
if tag in LUCIDE_ICON_MAPPING_OVERRIDE:
|
|
71
|
+
props["tag"] = LUCIDE_ICON_MAPPING_OVERRIDE[tag]
|
|
72
|
+
else:
|
|
73
|
+
props["tag"] = format.to_title_case(format.to_snake_case(tag)) + "Icon"
|
|
60
74
|
props["alias"] = f"Lucide{props['tag']}"
|
|
61
75
|
props.setdefault("color", "var(--current-color)")
|
|
62
|
-
return super().create(
|
|
76
|
+
return super().create(**props)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class DynamicIcon(LucideIconComponent):
|
|
80
|
+
"""A DynamicIcon component."""
|
|
81
|
+
|
|
82
|
+
tag = "DynamicIcon"
|
|
83
|
+
|
|
84
|
+
name: Var[str]
|
|
85
|
+
|
|
86
|
+
def _get_imports(self):
|
|
87
|
+
_imports = super()._get_imports()
|
|
88
|
+
if self.library:
|
|
89
|
+
_imports.pop(self.library)
|
|
90
|
+
_imports["lucide-react/dynamic"] = [ImportVar("DynamicIcon", install=False)]
|
|
91
|
+
return _imports
|
|
63
92
|
|
|
64
93
|
|
|
65
94
|
LUCIDE_ICON_LIST = [
|
|
@@ -841,6 +870,7 @@ LUCIDE_ICON_LIST = [
|
|
|
841
870
|
"house",
|
|
842
871
|
"house_plug",
|
|
843
872
|
"house_plus",
|
|
873
|
+
"house_wifi",
|
|
844
874
|
"ice_cream_bowl",
|
|
845
875
|
"ice_cream_cone",
|
|
846
876
|
"id_card",
|
|
@@ -1529,6 +1559,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1529
1559
|
"trending_up_down",
|
|
1530
1560
|
"triangle",
|
|
1531
1561
|
"triangle_alert",
|
|
1562
|
+
"triangle_dashed",
|
|
1532
1563
|
"triangle_right",
|
|
1533
1564
|
"trophy",
|
|
1534
1565
|
"truck",
|
|
@@ -1634,3 +1665,10 @@ LUCIDE_ICON_LIST = [
|
|
|
1634
1665
|
"zoom_in",
|
|
1635
1666
|
"zoom_out",
|
|
1636
1667
|
]
|
|
1668
|
+
|
|
1669
|
+
# The default transformation of some icon names doesn't match how the
|
|
1670
|
+
# icons are exported from Lucide. Manual overrides can go here.
|
|
1671
|
+
LUCIDE_ICON_MAPPING_OVERRIDE = {
|
|
1672
|
+
"grid_2x_2_check": "Grid2x2Check",
|
|
1673
|
+
"grid_2x_2_x": "Grid2x2X",
|
|
1674
|
+
}
|
|
@@ -104,12 +104,60 @@ class Icon(LucideIconComponent):
|
|
|
104
104
|
Raises:
|
|
105
105
|
AttributeError: The errors tied to bad usage of the Icon component.
|
|
106
106
|
ValueError: If the icon tag is invalid.
|
|
107
|
+
TypeError: If the icon name is not a string.
|
|
107
108
|
|
|
108
109
|
Returns:
|
|
109
110
|
The created component.
|
|
110
111
|
"""
|
|
111
112
|
...
|
|
112
113
|
|
|
114
|
+
class DynamicIcon(LucideIconComponent):
|
|
115
|
+
@overload
|
|
116
|
+
@classmethod
|
|
117
|
+
def create( # type: ignore
|
|
118
|
+
cls,
|
|
119
|
+
*children,
|
|
120
|
+
name: Optional[Union[Var[str], str]] = None,
|
|
121
|
+
style: Optional[Style] = None,
|
|
122
|
+
key: Optional[Any] = None,
|
|
123
|
+
id: Optional[Any] = None,
|
|
124
|
+
class_name: Optional[Any] = None,
|
|
125
|
+
autofocus: Optional[bool] = None,
|
|
126
|
+
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
|
|
127
|
+
on_blur: Optional[EventType[[], BASE_STATE]] = None,
|
|
128
|
+
on_click: Optional[EventType[[], BASE_STATE]] = None,
|
|
129
|
+
on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
|
|
130
|
+
on_double_click: Optional[EventType[[], BASE_STATE]] = None,
|
|
131
|
+
on_focus: Optional[EventType[[], BASE_STATE]] = None,
|
|
132
|
+
on_mount: Optional[EventType[[], BASE_STATE]] = None,
|
|
133
|
+
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
|
|
134
|
+
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
|
|
135
|
+
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
|
|
136
|
+
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
|
|
137
|
+
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
|
|
138
|
+
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
|
|
139
|
+
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
|
|
140
|
+
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
|
|
141
|
+
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
|
|
142
|
+
**props,
|
|
143
|
+
) -> "DynamicIcon":
|
|
144
|
+
"""Create the component.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
*children: The children of the component.
|
|
148
|
+
style: The style of the component.
|
|
149
|
+
key: A unique key for the component.
|
|
150
|
+
id: The id for the component.
|
|
151
|
+
class_name: The class name for the component.
|
|
152
|
+
autofocus: Whether the component should take the focus once the page is loaded
|
|
153
|
+
custom_attrs: custom attribute
|
|
154
|
+
**props: The props of the component.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
The component.
|
|
158
|
+
"""
|
|
159
|
+
...
|
|
160
|
+
|
|
113
161
|
LUCIDE_ICON_LIST = [
|
|
114
162
|
"a_arrow_down",
|
|
115
163
|
"a_arrow_up",
|
|
@@ -889,6 +937,7 @@ LUCIDE_ICON_LIST = [
|
|
|
889
937
|
"house",
|
|
890
938
|
"house_plug",
|
|
891
939
|
"house_plus",
|
|
940
|
+
"house_wifi",
|
|
892
941
|
"ice_cream_bowl",
|
|
893
942
|
"ice_cream_cone",
|
|
894
943
|
"id_card",
|
|
@@ -1577,6 +1626,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1577
1626
|
"trending_up_down",
|
|
1578
1627
|
"triangle",
|
|
1579
1628
|
"triangle_alert",
|
|
1629
|
+
"triangle_dashed",
|
|
1580
1630
|
"triangle_right",
|
|
1581
1631
|
"trophy",
|
|
1582
1632
|
"truck",
|
|
@@ -1682,3 +1732,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1682
1732
|
"zoom_in",
|
|
1683
1733
|
"zoom_out",
|
|
1684
1734
|
]
|
|
1735
|
+
LUCIDE_ICON_MAPPING_OVERRIDE = {
|
|
1736
|
+
"grid_2x_2_check": "Grid2x2Check",
|
|
1737
|
+
"grid_2x_2_x": "Grid2x2X",
|
|
1738
|
+
}
|
|
@@ -8,7 +8,7 @@ from functools import lru_cache
|
|
|
8
8
|
from hashlib import md5
|
|
9
9
|
from typing import Any, Callable, Dict, Sequence, Union
|
|
10
10
|
|
|
11
|
-
from reflex.components.component import Component, CustomComponent
|
|
11
|
+
from reflex.components.component import BaseComponent, Component, CustomComponent
|
|
12
12
|
from reflex.components.tags.tag import Tag
|
|
13
13
|
from reflex.utils import types
|
|
14
14
|
from reflex.utils.imports import ImportDict, ImportVar
|
|
@@ -65,8 +65,8 @@ def get_base_component_map() -> dict[str, Callable]:
|
|
|
65
65
|
"h5": lambda value: Heading.create(value, as_="h5", size="2", margin_y="0.5em"),
|
|
66
66
|
"h6": lambda value: Heading.create(value, as_="h6", size="1", margin_y="0.5em"),
|
|
67
67
|
"p": lambda value: Text.create(value, margin_y="1em"),
|
|
68
|
-
"ul": lambda value: UnorderedList.create(value, margin_y="1em"),
|
|
69
|
-
"ol": lambda value: OrderedList.create(value, margin_y="1em"),
|
|
68
|
+
"ul": lambda value: UnorderedList.create(value, margin_y="1em"),
|
|
69
|
+
"ol": lambda value: OrderedList.create(value, margin_y="1em"),
|
|
70
70
|
"li": lambda value: ListItem.create(value, margin_y="0.5em"),
|
|
71
71
|
"a": lambda value: Link.create(value),
|
|
72
72
|
"code": lambda value: Code.create(value),
|
|
@@ -236,7 +236,7 @@ class Markdown(Component):
|
|
|
236
236
|
),
|
|
237
237
|
},
|
|
238
238
|
*[
|
|
239
|
-
component(_MOCK_ARG)._get_all_imports()
|
|
239
|
+
component(_MOCK_ARG)._get_all_imports()
|
|
240
240
|
for component in self.component_map.values()
|
|
241
241
|
],
|
|
242
242
|
]
|
|
@@ -327,7 +327,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
|
|
|
327
327
|
if tag != "codeblock"
|
|
328
328
|
# For codeblock, the mapping for some cases returns an array of elements. Let's join them into a string.
|
|
329
329
|
else ternary_operation(
|
|
330
|
-
ARRAY_ISARRAY.call(_CHILDREN), #
|
|
330
|
+
ARRAY_ISARRAY.call(_CHILDREN), # pyright: ignore [reportArgumentType]
|
|
331
331
|
_CHILDREN.to(list).join("\n"),
|
|
332
332
|
_CHILDREN,
|
|
333
333
|
).to(str)
|
|
@@ -379,7 +379,9 @@ const {_LANGUAGE!s} = match ? match[1] : '';
|
|
|
379
379
|
# fallback to the default fn Var creation if the component is not a MarkdownComponentMap.
|
|
380
380
|
return MarkdownComponentMap.create_map_fn_var(fn_body=formatted_component)
|
|
381
381
|
|
|
382
|
-
def _get_map_fn_custom_code_from_children(
|
|
382
|
+
def _get_map_fn_custom_code_from_children(
|
|
383
|
+
self, component: BaseComponent
|
|
384
|
+
) -> list[str]:
|
|
383
385
|
"""Recursively get markdown custom code from children components.
|
|
384
386
|
|
|
385
387
|
Args:
|
|
@@ -409,7 +411,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
|
|
|
409
411
|
return custom_code_list
|
|
410
412
|
|
|
411
413
|
@staticmethod
|
|
412
|
-
def _component_map_hash(component_map) -> str:
|
|
414
|
+
def _component_map_hash(component_map: dict) -> str:
|
|
413
415
|
inp = str(
|
|
414
416
|
{tag: component(_MOCK_ARG) for tag, component in component_map.items()}
|
|
415
417
|
).encode()
|
|
@@ -425,7 +427,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
|
|
|
425
427
|
for _component in self.component_map.values():
|
|
426
428
|
comp = _component(_MOCK_ARG)
|
|
427
429
|
hooks.update(comp._get_all_hooks())
|
|
428
|
-
formatted_hooks = MACROS.module.renderHooks(hooks) #
|
|
430
|
+
formatted_hooks = MACROS.module.renderHooks(hooks) # pyright: ignore [reportAttributeAccessIssue]
|
|
429
431
|
return f"""
|
|
430
432
|
function {self._get_component_map_name()} () {{
|
|
431
433
|
{formatted_hooks}
|
|
@@ -28,9 +28,9 @@ class MomentDelta:
|
|
|
28
28
|
class Moment(NoSSRComponent):
|
|
29
29
|
"""The Moment component."""
|
|
30
30
|
|
|
31
|
-
tag: str = "Moment"
|
|
31
|
+
tag: str | None = "Moment"
|
|
32
32
|
is_default = True
|
|
33
|
-
library: str = "react-moment"
|
|
33
|
+
library: str | None = "react-moment"
|
|
34
34
|
lib_dependencies: List[str] = ["moment"]
|
|
35
35
|
|
|
36
36
|
# How often the date update (how often time update / 0 to disable).
|
reflex/components/next/image.py
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"""Image component from next/image."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
from typing import Any, Literal, Optional, Union
|
|
4
6
|
|
|
5
7
|
from reflex.event import EventHandler, no_args_event_spec
|
|
6
|
-
from reflex.utils import types
|
|
8
|
+
from reflex.utils import console, types
|
|
7
9
|
from reflex.vars.base import Var
|
|
8
10
|
|
|
9
11
|
from .base import NextComponent
|
|
10
12
|
|
|
13
|
+
DEFAULT_W_H = "100%"
|
|
14
|
+
|
|
11
15
|
|
|
12
16
|
class Image(NextComponent):
|
|
13
17
|
"""Display an image."""
|
|
@@ -53,7 +57,7 @@ class Image(NextComponent):
|
|
|
53
57
|
loading: Var[Literal["lazy", "eager"]]
|
|
54
58
|
|
|
55
59
|
# A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur".
|
|
56
|
-
|
|
60
|
+
blur_data_url: Var[str]
|
|
57
61
|
|
|
58
62
|
# Fires when the image has loaded.
|
|
59
63
|
on_load: EventHandler[no_args_event_spec]
|
|
@@ -80,10 +84,18 @@ class Image(NextComponent):
|
|
|
80
84
|
Returns:
|
|
81
85
|
_type_: _description_
|
|
82
86
|
"""
|
|
87
|
+
if "blurDataURL" in props:
|
|
88
|
+
console.deprecate(
|
|
89
|
+
feature_name="blurDataURL",
|
|
90
|
+
reason="Use blur_data_url instead",
|
|
91
|
+
deprecation_version="0.7.0",
|
|
92
|
+
removal_version="0.8.0",
|
|
93
|
+
)
|
|
94
|
+
props["blur_data_url"] = props.pop("blurDataURL")
|
|
95
|
+
|
|
83
96
|
style = props.get("style", {})
|
|
84
|
-
DEFAULT_W_H = "100%"
|
|
85
97
|
|
|
86
|
-
def check_prop_type(prop_name, prop_value):
|
|
98
|
+
def check_prop_type(prop_name: str, prop_value: int | str | None):
|
|
87
99
|
if types.check_prop_in_allowed_types(prop_value, allowed_types=[int]):
|
|
88
100
|
props[prop_name] = prop_value
|
|
89
101
|
|