Merge branch 'main' into lendemor/type_check_event_handler
This commit is contained in:
commit
c6a625fc44
@ -42,8 +42,7 @@ def get_lighthouse_scores(directory_path: str | Path) -> dict:
|
||||
try:
|
||||
for filename in directory_path.iterdir():
|
||||
if filename.suffix == ".json" and filename.stem != "manifest":
|
||||
file_path = directory_path / filename
|
||||
data = json.loads(file_path.read_text())
|
||||
data = json.loads(filename.read_text())
|
||||
# Extract scores and add them to the dictionary with the filename as key
|
||||
scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = {
|
||||
"performance_score": data["categories"]["performance"]["score"],
|
||||
|
@ -36,14 +36,10 @@
|
||||
{# component: component dictionary #}
|
||||
{% macro render_tag(component) %}
|
||||
<{{component.name}} {{- render_props(component.props) }}>
|
||||
{%- if component.args is not none -%}
|
||||
{{- render_arg_content(component) }}
|
||||
{%- else -%}
|
||||
{{ component.contents }}
|
||||
{% for child in component.children %}
|
||||
{{ render(child) }}
|
||||
{% endfor %}
|
||||
{%- endif -%}
|
||||
{{ component.contents }}
|
||||
{% for child in component.children %}
|
||||
{{ render(child) }}
|
||||
{% endfor %}
|
||||
</{{component.name}}>
|
||||
{%- endmacro %}
|
||||
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
} from "$/utils/context.js";
|
||||
import debounce from "$/utils/helpers/debounce";
|
||||
import throttle from "$/utils/helpers/throttle";
|
||||
import * as Babel from "@babel/standalone";
|
||||
|
||||
// Endpoint URLs.
|
||||
const EVENTURL = env.EVENT;
|
||||
@ -139,8 +138,7 @@ export const evalReactComponent = async (component) => {
|
||||
if (!window.React && window.__reflex) {
|
||||
window.React = window.__reflex.react;
|
||||
}
|
||||
const output = Babel.transform(component, { presets: ["react"] }).code;
|
||||
const encodedJs = encodeURIComponent(output);
|
||||
const encodedJs = encodeURIComponent(component);
|
||||
const dataUri = "data:text/javascript;charset=utf-8," + encodedJs;
|
||||
const module = await eval(`import(dataUri)`);
|
||||
return module.default;
|
||||
|
188
reflex/app.py
188
reflex/app.py
@ -46,7 +46,6 @@ from starlette_admin.contrib.sqla.view import ModelView
|
||||
from reflex import constants
|
||||
from reflex.admin import AdminDash
|
||||
from reflex.app_mixins import AppMixin, LifespanMixin, MiddlewareMixin
|
||||
from reflex.base import Base
|
||||
from reflex.compiler import compiler
|
||||
from reflex.compiler import utils as compiler_utils
|
||||
from reflex.compiler.compiler import (
|
||||
@ -70,7 +69,14 @@ from reflex.components.core.client_side_routing import (
|
||||
from reflex.components.core.upload import Upload, get_upload_dir
|
||||
from reflex.components.radix import themes
|
||||
from reflex.config import environment, get_config
|
||||
from reflex.event import Event, EventHandler, EventSpec, window_alert
|
||||
from reflex.event import (
|
||||
Event,
|
||||
EventHandler,
|
||||
EventSpec,
|
||||
EventType,
|
||||
IndividualEventType,
|
||||
window_alert,
|
||||
)
|
||||
from reflex.model import Model, get_db_status
|
||||
from reflex.page import (
|
||||
DECORATED_PAGES,
|
||||
@ -189,11 +195,12 @@ class UnevaluatedPage:
|
||||
title: Union[Var, str, None]
|
||||
description: Union[Var, str, None]
|
||||
image: str
|
||||
on_load: Union[EventHandler, EventSpec, List[Union[EventHandler, EventSpec]], None]
|
||||
on_load: Union[EventType[[]], None]
|
||||
meta: List[Dict[str, str]]
|
||||
|
||||
|
||||
class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
@dataclasses.dataclass()
|
||||
class App(MiddlewareMixin, LifespanMixin):
|
||||
"""The main Reflex app that encapsulates the backend and frontend.
|
||||
|
||||
Every Reflex app needs an app defined in its main module.
|
||||
@ -215,24 +222,26 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
"""
|
||||
|
||||
# The global [theme](https://reflex.dev/docs/styling/theming/#theme) for the entire app.
|
||||
theme: Optional[Component] = themes.theme(accent_color="blue")
|
||||
theme: Optional[Component] = dataclasses.field(
|
||||
default_factory=lambda: themes.theme(accent_color="blue")
|
||||
)
|
||||
|
||||
# The [global style](https://reflex.dev/docs/styling/overview/#global-styles}) for the app.
|
||||
style: ComponentStyle = {}
|
||||
style: ComponentStyle = dataclasses.field(default_factory=dict)
|
||||
|
||||
# A list of URLs to [stylesheets](https://reflex.dev/docs/styling/custom-stylesheets/) to include in the app.
|
||||
stylesheets: List[str] = []
|
||||
stylesheets: List[str] = dataclasses.field(default_factory=list)
|
||||
|
||||
# A component that is present on every page (defaults to the Connection Error banner).
|
||||
overlay_component: Optional[Union[Component, ComponentCallable]] = (
|
||||
default_overlay_component()
|
||||
dataclasses.field(default_factory=default_overlay_component)
|
||||
)
|
||||
|
||||
# Error boundary component to wrap the app with.
|
||||
error_boundary: Optional[ComponentCallable] = default_error_boundary
|
||||
|
||||
# Components to add to the head of every page.
|
||||
head_components: List[Component] = []
|
||||
head_components: List[Component] = dataclasses.field(default_factory=list)
|
||||
|
||||
# The Socket.IO AsyncServer instance.
|
||||
sio: Optional[AsyncServer] = None
|
||||
@ -244,10 +253,12 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
html_custom_attrs: Optional[Dict[str, str]] = None
|
||||
|
||||
# A map from a route to an unevaluated page. PRIVATE.
|
||||
unevaluated_pages: Dict[str, UnevaluatedPage] = {}
|
||||
unevaluated_pages: Dict[str, UnevaluatedPage] = dataclasses.field(
|
||||
default_factory=dict
|
||||
)
|
||||
|
||||
# A map from a page route to the component to render. Users should use `add_page`. PRIVATE.
|
||||
pages: Dict[str, Component] = {}
|
||||
pages: Dict[str, Component] = dataclasses.field(default_factory=dict)
|
||||
|
||||
# The backend API object. PRIVATE.
|
||||
api: FastAPI = None # type: ignore
|
||||
@ -259,7 +270,9 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
_state_manager: Optional[StateManager] = None
|
||||
|
||||
# Mapping from a route to event handlers to trigger when the page loads. PRIVATE.
|
||||
load_events: Dict[str, List[Union[EventHandler, EventSpec]]] = {}
|
||||
load_events: Dict[str, List[IndividualEventType[[]]]] = dataclasses.field(
|
||||
default_factory=dict
|
||||
)
|
||||
|
||||
# Admin dashboard to view and manage the database. PRIVATE.
|
||||
admin_dash: Optional[AdminDash] = None
|
||||
@ -268,7 +281,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
event_namespace: Optional[EventNamespace] = None
|
||||
|
||||
# Background tasks that are currently running. PRIVATE.
|
||||
background_tasks: Set[asyncio.Task] = set()
|
||||
background_tasks: Set[asyncio.Task] = dataclasses.field(default_factory=set)
|
||||
|
||||
# Frontend Error Handler Function
|
||||
frontend_exception_handler: Callable[[Exception], None] = (
|
||||
@ -280,23 +293,14 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
[Exception], Union[EventSpec, List[EventSpec], None]
|
||||
] = default_backend_exception_handler
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __post_init__(self):
|
||||
"""Initialize the app.
|
||||
|
||||
Args:
|
||||
**kwargs: Kwargs to initialize the app with.
|
||||
|
||||
Raises:
|
||||
ValueError: If the event namespace is not provided in the config.
|
||||
Also, if there are multiple client subclasses of rx.BaseState(Subclasses of rx.BaseState should consist
|
||||
of the DefaultState and the client app state).
|
||||
"""
|
||||
if "connect_error_component" in kwargs:
|
||||
raise ValueError(
|
||||
"`connect_error_component` is deprecated, use `overlay_component` instead"
|
||||
)
|
||||
super().__init__(**kwargs)
|
||||
|
||||
# Special case to allow test cases have multiple subclasses of rx.BaseState.
|
||||
if not is_testing_env() and BaseState.__subclasses__() != [State]:
|
||||
# Only rx.State is allowed as Base State subclass.
|
||||
@ -471,9 +475,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
title: str | Var | None = None,
|
||||
description: str | Var | None = None,
|
||||
image: str = constants.DefaultPage.IMAGE,
|
||||
on_load: (
|
||||
EventHandler | EventSpec | list[EventHandler | EventSpec] | None
|
||||
) = None,
|
||||
on_load: EventType[[]] | None = None,
|
||||
meta: list[dict[str, str]] = constants.DefaultPage.META_LIST,
|
||||
):
|
||||
"""Add a page to the app.
|
||||
@ -549,7 +551,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
route: The route of the page to compile.
|
||||
"""
|
||||
component, enable_state = compiler.compile_unevaluated_page(
|
||||
route, self.unevaluated_pages[route], self.state
|
||||
route, self.unevaluated_pages[route], self.state, self.style, self.theme
|
||||
)
|
||||
|
||||
if enable_state:
|
||||
@ -559,7 +561,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
self._check_routes_conflict(route)
|
||||
self.pages[route] = component
|
||||
|
||||
def get_load_events(self, route: str) -> list[EventHandler | EventSpec]:
|
||||
def get_load_events(self, route: str) -> list[IndividualEventType[[]]]:
|
||||
"""Get the load events for a route.
|
||||
|
||||
Args:
|
||||
@ -618,9 +620,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
title: str = constants.Page404.TITLE,
|
||||
image: str = constants.Page404.IMAGE,
|
||||
description: str = constants.Page404.DESCRIPTION,
|
||||
on_load: (
|
||||
EventHandler | EventSpec | list[EventHandler | EventSpec] | None
|
||||
) = None,
|
||||
on_load: EventType[[]] | None = None,
|
||||
meta: list[dict[str, str]] = constants.DefaultPage.META_LIST,
|
||||
):
|
||||
"""Define a custom 404 page for any url having no match.
|
||||
@ -842,6 +842,21 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
if constants.Page404.SLUG not in self.unevaluated_pages:
|
||||
self.add_custom_404_page()
|
||||
|
||||
# Fix up the style.
|
||||
self.style = evaluate_style_namespaces(self.style)
|
||||
|
||||
# Add the app wrappers.
|
||||
app_wrappers: Dict[tuple[int, str], Component] = {
|
||||
# Default app wrap component renders {children}
|
||||
(0, "AppWrap"): AppWrap.create()
|
||||
}
|
||||
|
||||
if self.theme is not None:
|
||||
# If a theme component was provided, wrap the app with it
|
||||
app_wrappers[(20, "Theme")] = self.theme
|
||||
# Fix #2992 by removing the top-level appearance prop
|
||||
self.theme.appearance = None
|
||||
|
||||
for route in self.unevaluated_pages:
|
||||
self._compile_page(route)
|
||||
|
||||
@ -868,7 +883,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
progress.start()
|
||||
task = progress.add_task(
|
||||
f"[{get_compilation_time()}] Compiling:",
|
||||
total=len(self.unevaluated_pages)
|
||||
total=len(self.pages)
|
||||
+ fixed_pages_within_executor
|
||||
+ adhoc_steps_without_executor,
|
||||
)
|
||||
@ -879,24 +894,41 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
# Store the compile results.
|
||||
compile_results = []
|
||||
|
||||
# Add the app wrappers.
|
||||
app_wrappers: Dict[tuple[int, str], Component] = {
|
||||
# Default app wrap component renders {children}
|
||||
(0, "AppWrap"): AppWrap.create()
|
||||
}
|
||||
if self.theme is not None:
|
||||
# If a theme component was provided, wrap the app with it
|
||||
app_wrappers[(20, "Theme")] = self.theme
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Fix up the style.
|
||||
self.style = evaluate_style_namespaces(self.style)
|
||||
|
||||
# Track imports and custom components found.
|
||||
all_imports = {}
|
||||
custom_components = set()
|
||||
|
||||
# This has to happen before compiling stateful components as that
|
||||
# prevents recursive functions from reaching all components.
|
||||
for component in self.pages.values():
|
||||
# Add component._get_all_imports() to all_imports.
|
||||
all_imports.update(component._get_all_imports())
|
||||
|
||||
# Add the app wrappers from this component.
|
||||
app_wrappers.update(component._get_all_app_wrap_components())
|
||||
|
||||
# Add the custom components from the page to the set.
|
||||
custom_components |= component._get_all_custom_components()
|
||||
|
||||
# Perform auto-memoization of stateful components.
|
||||
(
|
||||
stateful_components_path,
|
||||
stateful_components_code,
|
||||
page_components,
|
||||
) = compiler.compile_stateful_components(self.pages.values())
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Catch "static" apps (that do not define a rx.State subclass) which are trying to access rx.State.
|
||||
if code_uses_state_contexts(stateful_components_code) and self.state is None:
|
||||
raise ReflexRuntimeError(
|
||||
"To access rx.State in frontend components, at least one "
|
||||
"subclass of rx.State must be defined in the app."
|
||||
)
|
||||
compile_results.append((stateful_components_path, stateful_components_code))
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Compile the root document before fork.
|
||||
@ -908,10 +940,6 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
)
|
||||
)
|
||||
|
||||
# Fix #2992 by removing the top-level appearance prop
|
||||
if self.theme is not None:
|
||||
self.theme.appearance = None
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Use a forking process pool, if possible. Much faster, especially for large sites.
|
||||
@ -931,43 +959,19 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
max_workers=environment.REFLEX_COMPILE_THREADS
|
||||
)
|
||||
|
||||
for route, component in self.pages.items():
|
||||
component._add_style_recursive(self.style, self.theme)
|
||||
|
||||
for route, component in zip(self.pages, page_components):
|
||||
ExecutorSafeFunctions.COMPONENTS[route] = component
|
||||
|
||||
for route, page in self.unevaluated_pages.items():
|
||||
if route in self.pages:
|
||||
continue
|
||||
|
||||
ExecutorSafeFunctions.UNCOMPILED_PAGES[route] = page
|
||||
|
||||
ExecutorSafeFunctions.STATE = self.state
|
||||
|
||||
pages_results = []
|
||||
|
||||
with executor:
|
||||
result_futures = []
|
||||
pages_futures = []
|
||||
|
||||
def _submit_work(fn, *args, **kwargs):
|
||||
f = executor.submit(fn, *args, **kwargs)
|
||||
# f = executor.apipe(fn, *args, **kwargs)
|
||||
result_futures.append(f)
|
||||
|
||||
# Compile all page components.
|
||||
for route in self.unevaluated_pages:
|
||||
if route in self.pages:
|
||||
continue
|
||||
|
||||
f = executor.submit(
|
||||
ExecutorSafeFunctions.compile_unevaluated_page,
|
||||
route,
|
||||
self.style,
|
||||
self.theme,
|
||||
)
|
||||
pages_futures.append(f)
|
||||
|
||||
# Compile the pre-compiled pages.
|
||||
for route in self.pages:
|
||||
_submit_work(
|
||||
@ -995,42 +999,6 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
compile_results.append(future.result())
|
||||
progress.advance(task)
|
||||
|
||||
for future in concurrent.futures.as_completed(pages_futures):
|
||||
pages_results.append(future.result())
|
||||
progress.advance(task)
|
||||
|
||||
for route, component, compiled_page in pages_results:
|
||||
self._check_routes_conflict(route)
|
||||
self.pages[route] = component
|
||||
compile_results.append(compiled_page)
|
||||
|
||||
for _, component in self.pages.items():
|
||||
# Add component._get_all_imports() to all_imports.
|
||||
all_imports.update(component._get_all_imports())
|
||||
|
||||
# Add the app wrappers from this component.
|
||||
app_wrappers.update(component._get_all_app_wrap_components())
|
||||
|
||||
# Add the custom components from the page to the set.
|
||||
custom_components |= component._get_all_custom_components()
|
||||
|
||||
# Perform auto-memoization of stateful components.
|
||||
(
|
||||
stateful_components_path,
|
||||
stateful_components_code,
|
||||
page_components,
|
||||
) = compiler.compile_stateful_components(self.pages.values())
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Catch "static" apps (that do not define a rx.State subclass) which are trying to access rx.State.
|
||||
if code_uses_state_contexts(stateful_components_code) and self.state is None:
|
||||
raise ReflexRuntimeError(
|
||||
"To access rx.State in frontend components, at least one "
|
||||
"subclass of rx.State must be defined in the app."
|
||||
)
|
||||
compile_results.append((stateful_components_path, stateful_components_code))
|
||||
|
||||
app_root = self._app_root(app_wrappers=app_wrappers)
|
||||
|
||||
# Get imports from AppWrap components.
|
||||
@ -1423,7 +1391,7 @@ def upload(app: App):
|
||||
if isinstance(func, EventHandler):
|
||||
if func.is_background:
|
||||
raise UploadTypeError(
|
||||
f"@rx.background is not supported for upload handler `{handler}`.",
|
||||
f"@rx.event(background=True) is not supported for upload handler `{handler}`.",
|
||||
)
|
||||
func = func.fn
|
||||
if isinstance(func, functools.partial):
|
||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import dataclasses
|
||||
import functools
|
||||
import inspect
|
||||
from typing import Callable, Coroutine, Set, Union
|
||||
@ -16,11 +17,14 @@ from reflex.utils.exceptions import InvalidLifespanTaskType
|
||||
from .mixin import AppMixin
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class LifespanMixin(AppMixin):
|
||||
"""A Mixin that allow tasks to run during the whole app lifespan."""
|
||||
|
||||
# Lifespan tasks that are planned to run.
|
||||
lifespan_tasks: Set[Union[asyncio.Task, Callable]] = set()
|
||||
lifespan_tasks: Set[Union[asyncio.Task, Callable]] = dataclasses.field(
|
||||
default_factory=set
|
||||
)
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def _run_lifespan_tasks(self, app: FastAPI):
|
||||
|
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import dataclasses
|
||||
from typing import List
|
||||
|
||||
from reflex.event import Event
|
||||
@ -12,11 +13,12 @@ from reflex.state import BaseState, StateUpdate
|
||||
from .mixin import AppMixin
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class MiddlewareMixin(AppMixin):
|
||||
"""Middleware Mixin that allow to add middleware to the app."""
|
||||
|
||||
# Middleware to add to the app. Users should use `add_middleware`. PRIVATE.
|
||||
middleware: List[Middleware] = []
|
||||
middleware: List[Middleware] = dataclasses.field(default_factory=list)
|
||||
|
||||
def _init_mixin(self):
|
||||
self.middleware.append(HydrateMiddleware())
|
||||
|
@ -1,9 +1,10 @@
|
||||
"""Default mixin for all app mixins."""
|
||||
|
||||
from reflex.base import Base
|
||||
import dataclasses
|
||||
|
||||
|
||||
class AppMixin(Base):
|
||||
@dataclasses.dataclass
|
||||
class AppMixin:
|
||||
"""Define the base class for all app mixins."""
|
||||
|
||||
def _init_mixin(self):
|
||||
|
@ -127,7 +127,7 @@ def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None)
|
||||
|
||||
|
||||
def _compile_page(
|
||||
component: Component,
|
||||
component: BaseComponent,
|
||||
state: Type[BaseState] | None,
|
||||
) -> str:
|
||||
"""Compile the component given the app state.
|
||||
@ -425,7 +425,7 @@ def compile_contexts(
|
||||
|
||||
|
||||
def compile_page(
|
||||
path: str, component: Component, state: Type[BaseState] | None
|
||||
path: str, component: BaseComponent, state: Type[BaseState] | None
|
||||
) -> tuple[str, str]:
|
||||
"""Compile a single page.
|
||||
|
||||
@ -540,7 +540,11 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
def compile_unevaluated_page(
|
||||
route: str, page: UnevaluatedPage, state: Type[BaseState] | None = None
|
||||
route: str,
|
||||
page: UnevaluatedPage,
|
||||
state: Type[BaseState] | None = None,
|
||||
style: ComponentStyle | None = None,
|
||||
theme: Component | None = None,
|
||||
) -> Tuple[Component, bool]:
|
||||
"""Compiles an uncompiled page into a component and adds meta information.
|
||||
|
||||
@ -548,6 +552,8 @@ def compile_unevaluated_page(
|
||||
route: The route of the page.
|
||||
page: The uncompiled page object.
|
||||
state: The state of the app.
|
||||
style: The style of the page.
|
||||
theme: The theme of the page.
|
||||
|
||||
Returns:
|
||||
The compiled component and whether state should be enabled.
|
||||
@ -560,6 +566,8 @@ def compile_unevaluated_page(
|
||||
if isinstance(component, tuple):
|
||||
component = Fragment.create(*component)
|
||||
|
||||
component._add_style_recursive(style or {}, theme)
|
||||
|
||||
enable_state = False
|
||||
# Ensure state is enabled if this page uses state.
|
||||
if state is None:
|
||||
@ -627,7 +635,7 @@ class ExecutorSafeFunctions:
|
||||
|
||||
"""
|
||||
|
||||
COMPONENTS: Dict[str, Component] = {}
|
||||
COMPONENTS: Dict[str, BaseComponent] = {}
|
||||
UNCOMPILED_PAGES: Dict[str, UnevaluatedPage] = {}
|
||||
STATE: Optional[Type[BaseState]] = None
|
||||
|
||||
|
@ -4,10 +4,11 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Iterator
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.component import Component, LiteralComponentVar
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.components.tags.tagless import Tagless
|
||||
from reflex.vars import ArrayVar, BooleanVar, ObjectVar, Var
|
||||
from reflex.utils.imports import ParsedImportDict
|
||||
from reflex.vars import BooleanVar, ObjectVar, Var
|
||||
|
||||
|
||||
class Bare(Component):
|
||||
@ -31,9 +32,77 @@ class Bare(Component):
|
||||
contents = str(contents) if contents is not None else ""
|
||||
return cls(contents=contents) # type: ignore
|
||||
|
||||
def _get_all_hooks_internal(self) -> dict[str, None]:
|
||||
"""Include the hooks for the component.
|
||||
|
||||
Returns:
|
||||
The hooks for the component.
|
||||
"""
|
||||
hooks = super()._get_all_hooks_internal()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
hooks |= self.contents._var_value._get_all_hooks_internal()
|
||||
return hooks
|
||||
|
||||
def _get_all_hooks(self) -> dict[str, None]:
|
||||
"""Include the hooks for the component.
|
||||
|
||||
Returns:
|
||||
The hooks for the component.
|
||||
"""
|
||||
hooks = super()._get_all_hooks()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
hooks |= self.contents._var_value._get_all_hooks()
|
||||
return hooks
|
||||
|
||||
def _get_all_imports(self) -> ParsedImportDict:
|
||||
"""Include the imports for the component.
|
||||
|
||||
Returns:
|
||||
The imports for the component.
|
||||
"""
|
||||
imports = super()._get_all_imports()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
var_data = self.contents._get_all_var_data()
|
||||
if var_data:
|
||||
imports |= {k: list(v) for k, v in var_data.imports}
|
||||
return imports
|
||||
|
||||
def _get_all_dynamic_imports(self) -> set[str]:
|
||||
"""Get dynamic imports for the component.
|
||||
|
||||
Returns:
|
||||
The dynamic imports.
|
||||
"""
|
||||
dynamic_imports = super()._get_all_dynamic_imports()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
dynamic_imports |= self.contents._var_value._get_all_dynamic_imports()
|
||||
return dynamic_imports
|
||||
|
||||
def _get_all_custom_code(self) -> set[str]:
|
||||
"""Get custom code for the component.
|
||||
|
||||
Returns:
|
||||
The custom code.
|
||||
"""
|
||||
custom_code = super()._get_all_custom_code()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
custom_code |= self.contents._var_value._get_all_custom_code()
|
||||
return custom_code
|
||||
|
||||
def _get_all_refs(self) -> set[str]:
|
||||
"""Get the refs for the children of the component.
|
||||
|
||||
Returns:
|
||||
The refs for the children.
|
||||
"""
|
||||
refs = super()._get_all_refs()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
refs |= self.contents._var_value._get_all_refs()
|
||||
return refs
|
||||
|
||||
def _render(self) -> Tag:
|
||||
if isinstance(self.contents, Var):
|
||||
if isinstance(self.contents, (BooleanVar, ObjectVar, ArrayVar)):
|
||||
if isinstance(self.contents, (BooleanVar, ObjectVar)):
|
||||
return Tagless(contents=f"{{{str(self.contents.to_string())}}}")
|
||||
return Tagless(contents=f"{{{str(self.contents)}}}")
|
||||
return Tagless(contents=str(self.contents))
|
||||
|
@ -50,6 +50,7 @@ class ErrorBoundary(Component):
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
on_error: Fired when the boundary catches an error.
|
||||
Fallback_component: Rendered instead of the children when an error is caught.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
|
@ -65,6 +65,9 @@ class Script(Component):
|
||||
*children: The children of the component.
|
||||
src: Required unless inline script is used
|
||||
strategy: When the script will execute: afterInteractive (defer-like behavior) | beforeInteractive | lazyOnload (async-like behavior)
|
||||
on_load: Triggered when the script is loading
|
||||
on_ready: Triggered when the script has loaded
|
||||
on_error: Triggered when the script has errored
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import dataclasses
|
||||
import typing
|
||||
from abc import ABC, abstractmethod
|
||||
from functools import lru_cache, wraps
|
||||
@ -59,7 +60,15 @@ from reflex.utils.imports import (
|
||||
parse_imports,
|
||||
)
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
from reflex.vars.base import (
|
||||
CachedVarOperation,
|
||||
LiteralVar,
|
||||
Var,
|
||||
cached_property_no_lock,
|
||||
)
|
||||
from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar
|
||||
from reflex.vars.number import ternary_operation
|
||||
from reflex.vars.object import ObjectVar
|
||||
from reflex.vars.sequence import LiteralArrayVar
|
||||
|
||||
|
||||
@ -648,7 +657,7 @@ class Component(BaseComponent, ABC):
|
||||
# Look for component specific triggers,
|
||||
# e.g. variable declared as EventHandler types.
|
||||
for field in self.get_fields().values():
|
||||
if types._issubclass(field.type_, EventHandler):
|
||||
if types._issubclass(field.outer_type_, EventHandler):
|
||||
args_spec = None
|
||||
annotation = field.annotation
|
||||
if (metadata := getattr(annotation, "__metadata__", None)) is not None:
|
||||
@ -2349,3 +2358,203 @@ class MemoizationLeaf(Component):
|
||||
|
||||
|
||||
load_dynamic_serializer()
|
||||
|
||||
|
||||
class ComponentVar(Var[Component], python_types=BaseComponent):
|
||||
"""A Var that represents a Component."""
|
||||
|
||||
|
||||
def empty_component() -> Component:
|
||||
"""Create an empty component.
|
||||
|
||||
Returns:
|
||||
An empty component.
|
||||
"""
|
||||
from reflex.components.base.bare import Bare
|
||||
|
||||
return Bare.create("")
|
||||
|
||||
|
||||
def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) -> Var:
|
||||
"""Convert a render dict to a Var.
|
||||
|
||||
Args:
|
||||
tag: The render dict.
|
||||
imported_names: The names of the imported components.
|
||||
|
||||
Returns:
|
||||
The Var.
|
||||
"""
|
||||
if not isinstance(tag, dict):
|
||||
if isinstance(tag, Component):
|
||||
return render_dict_to_var(tag.render(), imported_names)
|
||||
return Var.create(tag)
|
||||
|
||||
if "iterable" in tag:
|
||||
function_return = Var.create(
|
||||
[
|
||||
render_dict_to_var(child.render(), imported_names)
|
||||
for child in tag["children"]
|
||||
]
|
||||
)
|
||||
|
||||
func = ArgsFunctionOperation.create(
|
||||
(tag["arg_var_name"], tag["index_var_name"]),
|
||||
function_return,
|
||||
)
|
||||
|
||||
return FunctionStringVar.create("Array.prototype.map.call").call(
|
||||
tag["iterable"]
|
||||
if not isinstance(tag["iterable"], ObjectVar)
|
||||
else tag["iterable"].items(),
|
||||
func,
|
||||
)
|
||||
|
||||
if tag["name"] == "match":
|
||||
element = tag["cond"]
|
||||
|
||||
conditionals = tag["default"]
|
||||
|
||||
for case in tag["match_cases"][::-1]:
|
||||
condition = case[0].to_string() == element.to_string()
|
||||
for pattern in case[1:-1]:
|
||||
condition = condition | (pattern.to_string() == element.to_string())
|
||||
|
||||
conditionals = ternary_operation(
|
||||
condition,
|
||||
case[-1],
|
||||
conditionals,
|
||||
)
|
||||
|
||||
return conditionals
|
||||
|
||||
if "cond" in tag:
|
||||
return ternary_operation(
|
||||
tag["cond"],
|
||||
render_dict_to_var(tag["true_value"], imported_names),
|
||||
render_dict_to_var(tag["false_value"], imported_names)
|
||||
if tag["false_value"] is not None
|
||||
else Var.create(None),
|
||||
)
|
||||
|
||||
props = {}
|
||||
|
||||
special_props = []
|
||||
|
||||
for prop_str in tag["props"]:
|
||||
if "=" not in prop_str:
|
||||
special_props.append(Var(prop_str).to(ObjectVar))
|
||||
continue
|
||||
prop = prop_str.index("=")
|
||||
key = prop_str[:prop]
|
||||
value = prop_str[prop + 2 : -1]
|
||||
props[key] = value
|
||||
|
||||
props = Var.create({Var.create(k): Var(v) for k, v in props.items()})
|
||||
|
||||
for prop in special_props:
|
||||
props = props.merge(prop)
|
||||
|
||||
contents = tag["contents"][1:-1] if tag["contents"] else None
|
||||
|
||||
raw_tag_name = tag.get("name")
|
||||
tag_name = Var(raw_tag_name or "Fragment")
|
||||
|
||||
tag_name = (
|
||||
Var.create(raw_tag_name)
|
||||
if raw_tag_name
|
||||
and raw_tag_name.split(".")[0] not in imported_names
|
||||
and raw_tag_name.lower() == raw_tag_name
|
||||
else tag_name
|
||||
)
|
||||
|
||||
return FunctionStringVar.create(
|
||||
"jsx",
|
||||
).call(
|
||||
tag_name,
|
||||
props,
|
||||
*([Var(contents)] if contents is not None else []),
|
||||
*[render_dict_to_var(child, imported_names) for child in tag["children"]],
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass(
|
||||
eq=False,
|
||||
frozen=True,
|
||||
)
|
||||
class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
|
||||
"""A Var that represents a Component."""
|
||||
|
||||
_var_value: BaseComponent = dataclasses.field(default_factory=empty_component)
|
||||
|
||||
@cached_property_no_lock
|
||||
def _cached_var_name(self) -> str:
|
||||
"""Get the name of the var.
|
||||
|
||||
Returns:
|
||||
The name of the var.
|
||||
"""
|
||||
var_data = self._get_all_var_data()
|
||||
if var_data is not None:
|
||||
# flatten imports
|
||||
imported_names = {j.alias or j.name for i in var_data.imports for j in i[1]}
|
||||
else:
|
||||
imported_names = set()
|
||||
return str(render_dict_to_var(self._var_value.render(), imported_names))
|
||||
|
||||
@cached_property_no_lock
|
||||
def _cached_get_all_var_data(self) -> VarData | None:
|
||||
"""Get the VarData for the var.
|
||||
|
||||
Returns:
|
||||
The VarData for the var.
|
||||
"""
|
||||
return VarData.merge(
|
||||
VarData(
|
||||
imports={
|
||||
"@emotion/react": [
|
||||
ImportVar(tag="jsx"),
|
||||
],
|
||||
}
|
||||
),
|
||||
VarData(
|
||||
imports=self._var_value._get_all_imports(),
|
||||
),
|
||||
VarData(
|
||||
imports={
|
||||
"react": [
|
||||
ImportVar(tag="Fragment"),
|
||||
],
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""Get the hash of the var.
|
||||
|
||||
Returns:
|
||||
The hash of the var.
|
||||
"""
|
||||
return hash((self.__class__.__name__, self._js_expr))
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
value: Component,
|
||||
_var_data: VarData | None = None,
|
||||
):
|
||||
"""Create a var from a value.
|
||||
|
||||
Args:
|
||||
value: The value of the var.
|
||||
_var_data: Additional hooks and imports associated with the Var.
|
||||
|
||||
Returns:
|
||||
The var.
|
||||
"""
|
||||
return LiteralComponentVar(
|
||||
_js_expr="",
|
||||
_var_type=type(value),
|
||||
_var_data=_var_data,
|
||||
_var_value=value,
|
||||
)
|
||||
|
@ -50,6 +50,7 @@ class Clipboard(Fragment):
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
targets: The element ids to attach the event listener to. Defaults to all child components or the document.
|
||||
on_paste: Called when the user pastes data into the document. Data is a list of tuples of (mime_type, data). Binary types will be base64 encoded as a data uri.
|
||||
on_paste_event_actions: Save the original event actions for the on_paste event.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
|
@ -5,11 +5,17 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple
|
||||
|
||||
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
|
||||
from reflex.components.component import (
|
||||
Component,
|
||||
ComponentNamespace,
|
||||
MemoizationLeaf,
|
||||
StatefulComponent,
|
||||
)
|
||||
from reflex.components.el.elements.forms import Input
|
||||
from reflex.components.radix.themes.layout.box import Box
|
||||
from reflex.config import environment
|
||||
from reflex.constants import Dirs
|
||||
from reflex.constants.compiler import Imports
|
||||
from reflex.event import (
|
||||
CallableEventSpec,
|
||||
EventChain,
|
||||
@ -19,9 +25,10 @@ from reflex.event import (
|
||||
call_script,
|
||||
parse_args_spec,
|
||||
)
|
||||
from reflex.utils import format
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import CallableVar, LiteralVar, Var
|
||||
from reflex.vars.base import CallableVar, LiteralVar, Var, get_unique_variable_name
|
||||
from reflex.vars.sequence import LiteralStringVar
|
||||
|
||||
DEFAULT_UPLOAD_ID: str = "default"
|
||||
@ -179,9 +186,7 @@ class Upload(MemoizationLeaf):
|
||||
|
||||
library = "react-dropzone@14.2.10"
|
||||
|
||||
tag = "ReactDropzone"
|
||||
|
||||
is_default = True
|
||||
tag = ""
|
||||
|
||||
# The list of accepted file types. This should be a dictionary of MIME types as keys and array of file formats as
|
||||
# values.
|
||||
@ -201,7 +206,7 @@ class Upload(MemoizationLeaf):
|
||||
min_size: Var[int]
|
||||
|
||||
# Whether to allow multiple files to be uploaded.
|
||||
multiple: Var[bool] = True # type: ignore
|
||||
multiple: Var[bool]
|
||||
|
||||
# Whether to disable click to upload.
|
||||
no_click: Var[bool]
|
||||
@ -232,6 +237,8 @@ class Upload(MemoizationLeaf):
|
||||
# Mark the Upload component as used in the app.
|
||||
cls.is_used = True
|
||||
|
||||
props.setdefault("multiple", True)
|
||||
|
||||
# Apply the default classname
|
||||
given_class_name = props.pop("class_name", [])
|
||||
if isinstance(given_class_name, str):
|
||||
@ -243,17 +250,6 @@ class Upload(MemoizationLeaf):
|
||||
upload_props = {
|
||||
key: value for key, value in props.items() if key in supported_props
|
||||
}
|
||||
# The file input to use.
|
||||
upload = Input.create(type="file")
|
||||
upload.special_props = [Var(_js_expr="{...getInputProps()}", _var_type=None)]
|
||||
|
||||
# The dropzone to use.
|
||||
zone = Box.create(
|
||||
upload,
|
||||
*children,
|
||||
**{k: v for k, v in props.items() if k not in supported_props},
|
||||
)
|
||||
zone.special_props = [Var(_js_expr="{...getRootProps()}", _var_type=None)]
|
||||
|
||||
# Create the component.
|
||||
upload_props["id"] = props.get("id", DEFAULT_UPLOAD_ID)
|
||||
@ -275,9 +271,74 @@ class Upload(MemoizationLeaf):
|
||||
),
|
||||
)
|
||||
upload_props["on_drop"] = on_drop
|
||||
|
||||
input_props_unique_name = get_unique_variable_name()
|
||||
root_props_unique_name = get_unique_variable_name()
|
||||
|
||||
event_var, callback_str = StatefulComponent._get_memoized_event_triggers(
|
||||
Box.create(on_click=upload_props["on_drop"]) # type: ignore
|
||||
)["on_click"]
|
||||
|
||||
upload_props["on_drop"] = event_var
|
||||
|
||||
upload_props = {
|
||||
format.to_camel_case(key): value for key, value in upload_props.items()
|
||||
}
|
||||
|
||||
use_dropzone_arguements = {
|
||||
"onDrop": event_var,
|
||||
**upload_props,
|
||||
}
|
||||
|
||||
left_side = f"const {{getRootProps: {root_props_unique_name}, getInputProps: {input_props_unique_name}}} "
|
||||
right_side = f"useDropzone({str(Var.create(use_dropzone_arguements))})"
|
||||
|
||||
var_data = VarData.merge(
|
||||
VarData(
|
||||
imports=Imports.EVENTS,
|
||||
hooks={
|
||||
"const [addEvents, connectError] = useContext(EventLoopContext);": None
|
||||
},
|
||||
),
|
||||
event_var._get_all_var_data(),
|
||||
VarData(
|
||||
hooks={
|
||||
callback_str: None,
|
||||
f"{left_side} = {right_side};": None,
|
||||
},
|
||||
imports={
|
||||
"react-dropzone": "useDropzone",
|
||||
**Imports.EVENTS,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
# The file input to use.
|
||||
upload = Input.create(type="file")
|
||||
upload.special_props = [
|
||||
Var(
|
||||
_js_expr=f"{{...{input_props_unique_name}()}}",
|
||||
_var_type=None,
|
||||
_var_data=var_data,
|
||||
)
|
||||
]
|
||||
|
||||
# The dropzone to use.
|
||||
zone = Box.create(
|
||||
upload,
|
||||
*children,
|
||||
**{k: v for k, v in props.items() if k not in supported_props},
|
||||
)
|
||||
zone.special_props = [
|
||||
Var(
|
||||
_js_expr=f"{{...{root_props_unique_name}()}}",
|
||||
_var_type=None,
|
||||
_var_data=var_data,
|
||||
)
|
||||
]
|
||||
|
||||
return super().create(
|
||||
zone,
|
||||
**upload_props,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@ -295,11 +356,6 @@ class Upload(MemoizationLeaf):
|
||||
return (arg_value[0], placeholder)
|
||||
return arg_value
|
||||
|
||||
def _render(self):
|
||||
out = super()._render()
|
||||
out.args = ("getRootProps", "getInputProps")
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
|
||||
return {
|
||||
|
@ -6,7 +6,11 @@
|
||||
from pathlib import Path
|
||||
from typing import Any, ClassVar, Dict, List, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
|
||||
from reflex.components.component import (
|
||||
Component,
|
||||
ComponentNamespace,
|
||||
MemoizationLeaf,
|
||||
)
|
||||
from reflex.constants import Dirs
|
||||
from reflex.event import (
|
||||
CallableEventSpec,
|
||||
@ -142,6 +146,7 @@ class Upload(MemoizationLeaf):
|
||||
no_click: Whether to disable click to upload.
|
||||
no_drag: Whether to disable drag and drop.
|
||||
no_keyboard: Whether to disable using the space/enter keys to upload.
|
||||
on_drop: Fired when files are dropped.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -207,6 +212,7 @@ class StyledUpload(Upload):
|
||||
no_click: Whether to disable click to upload.
|
||||
no_drag: Whether to disable drag and drop.
|
||||
no_keyboard: Whether to disable using the space/enter keys to upload.
|
||||
on_drop: Fired when files are dropped.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -272,6 +278,7 @@ class UploadNamespace(ComponentNamespace):
|
||||
no_click: Whether to disable click to upload.
|
||||
no_drag: Whether to disable drag and drop.
|
||||
no_keyboard: Whether to disable using the space/enter keys to upload.
|
||||
on_drop: Fired when files are dropped.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -253,6 +253,22 @@ class DataEditor(NoSSRComponent):
|
||||
scroll_offset_x: Initial scroll offset on the horizontal axis.
|
||||
scroll_offset_y: Initial scroll offset on the vertical axis.
|
||||
theme: global theme
|
||||
on_cell_activated: Fired when a cell is activated.
|
||||
on_cell_clicked: Fired when a cell is clicked.
|
||||
on_cell_context_menu: Fired when a cell is right-clicked.
|
||||
on_cell_edited: Fired when a cell is edited.
|
||||
on_group_header_clicked: Fired when a group header is clicked.
|
||||
on_group_header_context_menu: Fired when a group header is right-clicked.
|
||||
on_group_header_renamed: Fired when a group header is renamed.
|
||||
on_header_clicked: Fired when a header is clicked.
|
||||
on_header_context_menu: Fired when a header is right-clicked.
|
||||
on_header_menu_click: Fired when a header menu item is clicked.
|
||||
on_item_hovered: Fired when an item is hovered.
|
||||
on_delete: Fired when a selection is deleted.
|
||||
on_finished_editing: Fired when editing is finished.
|
||||
on_row_appended: Fired when a row is appended.
|
||||
on_selection_cleared: Fired when the selection is cleared.
|
||||
on_column_resize: Fired when a column is resized.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -33,8 +33,8 @@ def copy_script() -> Any:
|
||||
f"""
|
||||
// Event listener for the parent click
|
||||
document.addEventListener('click', function(event) {{
|
||||
// Find the closest div (parent element)
|
||||
const parent = event.target.closest('div');
|
||||
// Find the closest button (parent element)
|
||||
const parent = event.target.closest('button');
|
||||
// If the parent is found
|
||||
if (parent) {{
|
||||
// Find the SVG element within the parent
|
||||
|
@ -63,6 +63,9 @@ def load_dynamic_serializer():
|
||||
"""
|
||||
# Causes a circular import, so we import here.
|
||||
from reflex.compiler import templates, utils
|
||||
from reflex.components.base.bare import Bare
|
||||
|
||||
component = Bare.create(Var.create(component))
|
||||
|
||||
rendered_components = {}
|
||||
# Include dynamic imports in the shared component.
|
||||
@ -127,14 +130,15 @@ def load_dynamic_serializer():
|
||||
module_code_lines[ix] = line.replace(
|
||||
"export function", "export default function", 1
|
||||
)
|
||||
line_stripped = line.strip()
|
||||
if line_stripped.startswith("{") and line_stripped.endswith("}"):
|
||||
module_code_lines[ix] = line_stripped[1:-1]
|
||||
|
||||
module_code_lines.insert(0, "const React = window.__reflex.react;")
|
||||
|
||||
return "\n".join(
|
||||
[
|
||||
"//__reflex_evaluate",
|
||||
"/** @jsx jsx */",
|
||||
"const { jsx } = window.__reflex['@emotion/react']",
|
||||
*module_code_lines,
|
||||
]
|
||||
)
|
||||
|
@ -359,6 +359,7 @@ class Form(BaseHTML):
|
||||
target: Where to display the response after submitting the form
|
||||
reset_on_submit: If true, the form will be cleared after submit.
|
||||
handle_submit_unique_name: The name used to make this form's submit handler function unique.
|
||||
on_submit: Fired when the form is submitted
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
@ -523,6 +524,11 @@ class Input(BaseHTML):
|
||||
type: Specifies the type of input
|
||||
use_map: Name of the image map used with the input
|
||||
value: Value of the input
|
||||
on_change: Fired when the input value changes
|
||||
on_focus: Fired when the input gains focus
|
||||
on_blur: Fired when the input loses focus
|
||||
on_key_down: Fired when a key is pressed down
|
||||
on_key_up: Fired when a key is released
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
@ -1272,6 +1278,7 @@ class Select(BaseHTML):
|
||||
name: Name of the select, used when submitting the form
|
||||
required: Indicates that the select control must have a selected option
|
||||
size: Number of visible options in a drop-down list
|
||||
on_change: Fired when the select value changes
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
@ -1400,6 +1407,11 @@ class Textarea(BaseHTML):
|
||||
rows: Visible number of lines in the text control
|
||||
value: The controlled value of the textarea, read only unless used with on_change
|
||||
wrap: How the text in the textarea is to be wrapped when submitting the form
|
||||
on_change: Fired when the input value changes
|
||||
on_focus: Fired when the input gains focus
|
||||
on_blur: Fired when the input loses focus
|
||||
on_key_down: Fired when a key is pressed down
|
||||
on_key_up: Fired when a key is released
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
|
@ -101,6 +101,7 @@ class Moment(NoSSRComponent):
|
||||
local: Outputs the result in local time.
|
||||
tz: Display the date in the given timezone.
|
||||
locale: The locale to use when rendering.
|
||||
on_change: Fires when the date changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -72,6 +72,8 @@ class Image(NextComponent):
|
||||
placeholder: A placeholder to use while the image is loading. Possible values are blur, empty, or data:image/.... Defaults to empty.
|
||||
loading: Allows passing CSS styles to the underlying image element. style: Var[Any] The loading behavior of the image. Defaults to lazy. Can hurt performance, recommended to use `priority` instead.
|
||||
blurDataURL: A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur".
|
||||
on_load: Fires when the image has loaded.
|
||||
on_error: Fires when the image has an error.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -89,6 +89,26 @@ class Plotly(NoSSRComponent):
|
||||
template: The template for visual appearance of the graph.
|
||||
config: The config of the graph.
|
||||
use_resize_handler: If true, the graph will resize when the window is resized.
|
||||
on_after_plot: Fired after the plot is redrawn.
|
||||
on_animated: Fired after the plot was animated.
|
||||
on_animating_frame: Fired while animating a single frame (does not currently pass data through).
|
||||
on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example).
|
||||
on_autosize: Fired when the plot is responsively sized.
|
||||
on_before_hover: Fired whenever mouse moves over a plot.
|
||||
on_button_clicked: Fired when a plotly UI button is clicked.
|
||||
on_click: Fired when the plot is clicked.
|
||||
on_deselect: Fired when a selection is cleared (via double click).
|
||||
on_double_click: Fired when the plot is double clicked.
|
||||
on_hover: Fired when a plot element is hovered over.
|
||||
on_relayout: Fired after the plot is layed out (zoom, pan, etc).
|
||||
on_relayouting: Fired while the plot is being layed out.
|
||||
on_restyle: Fired after the plot style is changed.
|
||||
on_redraw: Fired after the plot is redrawn.
|
||||
on_selected: Fired after selecting plot elements.
|
||||
on_selecting: Fired while dragging a selection.
|
||||
on_transitioning: Fired while an animation is occuring.
|
||||
on_transition_interrupted: Fired when a transition is stopped early.
|
||||
on_unhover: Fired when a hovered element is no longer hovered.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -280,6 +280,7 @@ class AccordionRoot(AccordionComponent):
|
||||
duration: The time in milliseconds to animate open and close
|
||||
easing: The easing function to use for the animation.
|
||||
show_dividers: Whether to show divider lines between items.
|
||||
on_value_change: Fired when the opened the accordions changes.
|
||||
color_scheme: The color scheme of the component.
|
||||
variant: The variant of the component.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
|
@ -60,7 +60,7 @@ class DrawerRoot(DrawerComponent):
|
||||
# When `True`, it prevents scroll restoration. Defaults to `True`.
|
||||
preventScrollRestoration: Var[bool]
|
||||
|
||||
# Fires when the drawer is opened.
|
||||
# Fires when the drawer is opened or closed.
|
||||
on_open_change: EventHandler[identity_event(bool)]
|
||||
|
||||
|
||||
@ -79,8 +79,8 @@ class DrawerTrigger(DrawerComponent):
|
||||
"""Create a new DrawerTrigger instance.
|
||||
|
||||
Args:
|
||||
children: The children of the element.
|
||||
props: The properties of the element.
|
||||
*children: The children of the element.
|
||||
**props: The properties of the element.
|
||||
|
||||
Returns:
|
||||
The new DrawerTrigger instance.
|
||||
|
@ -119,6 +119,7 @@ class DrawerRoot(DrawerComponent):
|
||||
modal: When `False`, it allows to interact with elements outside of the drawer without closing it. Defaults to `True`.
|
||||
direction: Direction of the drawer. Defaults to `"bottom"`
|
||||
preventScrollRestoration: When `True`, it prevents scroll restoration. Defaults to `True`.
|
||||
on_open_change: Fires when the drawer is opened or closed.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
@ -166,8 +167,15 @@ class DrawerTrigger(DrawerComponent):
|
||||
"""Create a new DrawerTrigger instance.
|
||||
|
||||
Args:
|
||||
children: The children of the element.
|
||||
props: The properties of the element.
|
||||
*children: The children of the element.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The properties of the element.
|
||||
|
||||
Returns:
|
||||
The new DrawerTrigger instance.
|
||||
@ -360,8 +368,15 @@ class DrawerClose(DrawerTrigger):
|
||||
"""Create a new DrawerTrigger instance.
|
||||
|
||||
Args:
|
||||
children: The children of the element.
|
||||
props: The properties of the element.
|
||||
*children: The children of the element.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The properties of the element.
|
||||
|
||||
Returns:
|
||||
The new DrawerTrigger instance.
|
||||
@ -529,6 +544,7 @@ class Drawer(ComponentNamespace):
|
||||
modal: When `False`, it allows to interact with elements outside of the drawer without closing it. Defaults to `True`.
|
||||
direction: Direction of the drawer. Defaults to `"bottom"`
|
||||
preventScrollRestoration: When `True`, it prevents scroll restoration. Defaults to `True`.
|
||||
on_open_change: Fires when the drawer is opened or closed.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
|
@ -139,6 +139,7 @@ class FormRoot(FormComponent, HTMLForm):
|
||||
|
||||
Args:
|
||||
*children: The children of the form.
|
||||
on_clear_server_errors: Fired when the errors are cleared.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
accept: MIME types the server accepts for file upload
|
||||
accept_charset: Character encodings to be used for form submission
|
||||
@ -151,6 +152,7 @@ class FormRoot(FormComponent, HTMLForm):
|
||||
target: Where to display the response after submitting the form
|
||||
reset_on_submit: If true, the form will be cleared after submit.
|
||||
handle_submit_unique_name: The name used to make this form's submit handler function unique.
|
||||
on_submit: Fired when the form is submitted
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
@ -606,6 +608,7 @@ class Form(FormRoot):
|
||||
|
||||
Args:
|
||||
*children: The children of the form.
|
||||
on_clear_server_errors: Fired when the errors are cleared.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
accept: MIME types the server accepts for file upload
|
||||
accept_charset: Character encodings to be used for form submission
|
||||
@ -618,6 +621,7 @@ class Form(FormRoot):
|
||||
target: Where to display the response after submitting the form
|
||||
reset_on_submit: If true, the form will be cleared after submit.
|
||||
handle_submit_unique_name: The name used to make this form's submit handler function unique.
|
||||
on_submit: Fired when the form is submitted
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
@ -730,6 +734,7 @@ class FormNamespace(ComponentNamespace):
|
||||
|
||||
Args:
|
||||
*children: The children of the form.
|
||||
on_clear_server_errors: Fired when the errors are cleared.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
accept: MIME types the server accepts for file upload
|
||||
accept_charset: Character encodings to be used for form submission
|
||||
@ -742,6 +747,7 @@ class FormNamespace(ComponentNamespace):
|
||||
target: Where to display the response after submitting the form
|
||||
reset_on_submit: If true, the form will be cleared after submit.
|
||||
handle_submit_unique_name: The name used to make this form's submit handler function unique.
|
||||
on_submit: Fired when the form is submitted
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
|
@ -117,6 +117,8 @@ class SliderRoot(SliderComponent):
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
on_value_change: Fired when the value of a thumb changes.
|
||||
on_value_commit: Fired when a thumb is released.
|
||||
as_child: Change the default rendered element for the one passed as a child.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
|
@ -416,6 +416,7 @@ class ColorModeSwitch(Switch):
|
||||
color_scheme: Override theme color for switch
|
||||
high_contrast: Whether to render the switch with higher contrast color against background
|
||||
radius: Override theme radius for switch: "none" | "small" | "full"
|
||||
on_change: Props to rename Fired when the value of the switch changes
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -55,6 +55,7 @@ class AlertDialogRoot(RadixThemesComponent):
|
||||
Args:
|
||||
*children: Child components.
|
||||
open: The controlled open state of the dialog.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -186,6 +187,9 @@ class AlertDialogContent(elements.Div, RadixThemesComponent):
|
||||
*children: Child components.
|
||||
size: The size of the content.
|
||||
force_mount: Whether to force mount the content on open.
|
||||
on_open_auto_focus: Fired when the dialog is opened.
|
||||
on_close_auto_focus: Fired when the dialog is closed.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
|
@ -151,6 +151,7 @@ class Checkbox(RadixThemesComponent):
|
||||
required: Whether the checkbox is required
|
||||
name: The name of the checkbox control when submitting the form.
|
||||
value: The value of the checkbox control when submitting the form.
|
||||
on_change: Props to rename Fired when the checkbox is checked or unchecked.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -297,6 +298,7 @@ class HighLevelCheckbox(RadixThemesComponent):
|
||||
required: Whether the checkbox is required
|
||||
name: The name of the checkbox control when submitting the form.
|
||||
value: The value of the checkbox control when submitting the form.
|
||||
on_change: Props to rename Fired when the checkbox is checked or unchecked.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -441,6 +443,7 @@ class CheckboxNamespace(ComponentNamespace):
|
||||
required: Whether the checkbox is required
|
||||
name: The name of the checkbox control when submitting the form.
|
||||
value: The value of the checkbox control when submitting the form.
|
||||
on_change: Props to rename Fired when the checkbox is checked or unchecked.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -52,6 +52,7 @@ class ContextMenuRoot(RadixThemesComponent):
|
||||
Args:
|
||||
*children: Child components.
|
||||
modal: The modality of the context menu. When set to true, interaction with outside elements will be disabled and only menu content will be visible to screen readers.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -238,6 +239,11 @@ class ContextMenuContent(RadixThemesComponent):
|
||||
high_contrast: Whether to render the button with higher contrast color against background
|
||||
align_offset: The vertical distance in pixels from the anchor.
|
||||
avoid_collisions: When true, overrides the side and aligns preferences to prevent collisions with boundary edges.
|
||||
on_close_auto_focus: Fired when the context menu is closed.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
on_pointer_down_outside: Fired when a pointer down event happens outside the context menu.
|
||||
on_focus_outside: Fired when focus moves outside the context menu.
|
||||
on_interact_outside: Fired when interacting outside the context menu.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -393,6 +399,10 @@ class ContextMenuSubContent(RadixThemesComponent):
|
||||
Args:
|
||||
*children: Child components.
|
||||
loop: When true, keyboard navigation will loop from last item to first, and vice versa.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
on_pointer_down_outside: Fired when a pointer down event happens outside the context menu.
|
||||
on_focus_outside: Fired when focus moves outside the context menu.
|
||||
on_interact_outside: Fired when interacting outside the context menu.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -53,6 +53,7 @@ class DialogRoot(RadixThemesComponent):
|
||||
Args:
|
||||
*children: Child components.
|
||||
open: The controlled open state of the dialog.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -233,6 +234,11 @@ class DialogContent(elements.Div, RadixThemesComponent):
|
||||
Args:
|
||||
*children: Child components.
|
||||
size: DialogContent size "1" - "4"
|
||||
on_open_auto_focus: Fired when the dialog is opened.
|
||||
on_close_auto_focus: Fired when the dialog is closed.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
on_pointer_down_outside: Fired when the pointer is down outside the dialog.
|
||||
on_interact_outside: Fired when the pointer interacts outside the dialog.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
@ -395,6 +401,7 @@ class Dialog(ComponentNamespace):
|
||||
Args:
|
||||
*children: Child components.
|
||||
open: The controlled open state of the dialog.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -65,6 +65,7 @@ class DropdownMenuRoot(RadixThemesComponent):
|
||||
open: The controlled open state of the dropdown menu. Must be used in conjunction with onOpenChange.
|
||||
modal: The modality of the dropdown menu. When set to true, interaction with outside elements will be disabled and only menu content will be visible to screen readers. Defaults to True.
|
||||
dir: The reading direction of submenus when applicable. If omitted, inherits globally from DirectionProvider or assumes LTR (left-to-right) reading mode.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -280,6 +281,11 @@ class DropdownMenuContent(RadixThemesComponent):
|
||||
arrow_padding: The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. Defaults to 0.
|
||||
sticky: The sticky behavior on the align axis. "partial" will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless. Defaults to "partial".
|
||||
hide_when_detached: Whether to hide the content when the trigger becomes fully occluded. Defaults to False.
|
||||
on_close_auto_focus: Fired when the dialog is closed.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
on_pointer_down_outside: Fired when the pointer is down outside the dialog.
|
||||
on_focus_outside: Fired when focus moves outside the dialog.
|
||||
on_interact_outside: Fired when the pointer interacts outside the dialog.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -377,6 +383,7 @@ class DropdownMenuSub(RadixThemesComponent):
|
||||
*children: Child components.
|
||||
open: The controlled open state of the submenu. Must be used in conjunction with `on_open_change`.
|
||||
default_open: The open state of the submenu when it is initially rendered. Use when you do not need to control its open state.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -459,6 +466,10 @@ class DropdownMenuSubContent(RadixThemesComponent):
|
||||
arrow_padding: The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. Defaults to 0.
|
||||
sticky: The sticky behavior on the align axis. "partial" will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless. Defaults to "partial".
|
||||
hide_when_detached: Whether to hide the content when the trigger becomes fully occluded. Defaults to False.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
on_pointer_down_outside: Fired when the pointer is down outside the dialog.
|
||||
on_focus_outside: Fired when focus moves outside the dialog.
|
||||
on_interact_outside: Fired when the pointer interacts outside the dialog.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -580,6 +591,7 @@ class DropdownMenuItem(RadixThemesComponent):
|
||||
as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
|
||||
disabled: When true, prevents the user from interacting with the item.
|
||||
text_value: Optional text used for typeahead purposes. By default the typeahead behavior will use the .textContent of the item. Use this when the content is complex, or you have non-textual content inside.
|
||||
on_select: Fired when the item is selected.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -59,6 +59,7 @@ class HoverCardRoot(RadixThemesComponent):
|
||||
open: The controlled open state of the hover card. Must be used in conjunction with onOpenChange.
|
||||
open_delay: The duration from when the mouse enters the trigger until the hover card opens.
|
||||
close_delay: The duration from when the mouse leaves the trigger until the hover card closes.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -272,6 +273,7 @@ class HoverCard(ComponentNamespace):
|
||||
open: The controlled open state of the hover card. Must be used in conjunction with onOpenChange.
|
||||
open_delay: The duration from when the mouse enters the trigger until the hover card opens.
|
||||
close_delay: The duration from when the mouse leaves the trigger until the hover card closes.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -55,6 +55,7 @@ class PopoverRoot(RadixThemesComponent):
|
||||
*children: Child components.
|
||||
open: The controlled open state of the popover.
|
||||
modal: The modality of the popover. When set to true, interaction with outside elements will be disabled and only popover content will be visible to screen readers.
|
||||
on_open_change: Fired when the open state changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -207,6 +208,12 @@ class PopoverContent(elements.Div, RadixThemesComponent):
|
||||
align: The preferred alignment against the anchor. May change when collisions occur.
|
||||
align_offset: The vertical distance in pixels from the anchor.
|
||||
avoid_collisions: When true, overrides the side andalign preferences to prevent collisions with boundary edges.
|
||||
on_open_auto_focus: Fired when the dialog is opened.
|
||||
on_close_auto_focus: Fired when the dialog is closed.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
on_pointer_down_outside: Fired when the pointer is down outside the dialog.
|
||||
on_focus_outside: Fired when focus moves outside the dialog.
|
||||
on_interact_outside: Fired when the pointer interacts outside the dialog.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
|
@ -201,6 +201,7 @@ class RadioCardsRoot(RadixThemesComponent):
|
||||
orientation: The orientation of the component.
|
||||
dir: The reading direction of the radio group. If omitted, inherits globally from DirectionProvider or assumes LTR (left-to-right) reading mode.
|
||||
loop: When true, keyboard navigation will loop from last item to first, and vice versa.
|
||||
on_value_change: Event handler called when the value changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -146,6 +146,7 @@ class RadioGroupRoot(RadixThemesComponent):
|
||||
disabled: Whether the radio group is disabled
|
||||
name: The name of the group. Submitted with its owning form as part of a name/value pair.
|
||||
required: Whether the radio group is required
|
||||
on_change: Props to rename Fired when the value of the radio group changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -148,6 +148,7 @@ class SegmentedControlRoot(RadixThemesComponent):
|
||||
radius: The radius of the segmented control: "none" | "small" | "medium" | "large" | "full"
|
||||
default_value: The default value of the segmented control.
|
||||
value: The current value of the segmented control.
|
||||
on_change: Handles the `onChange` event for the SegmentedControl component.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -77,6 +77,8 @@ class SelectRoot(RadixThemesComponent):
|
||||
name: The name of the select control when submitting the form.
|
||||
disabled: When True, prevents the user from interacting with select.
|
||||
required: When True, indicates that the user must select a value before the owning form can be submitted.
|
||||
on_change: Props to rename Fired when the value of the select changes.
|
||||
on_open_change: Fired when the select is opened or closed.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -351,6 +353,9 @@ class SelectContent(RadixThemesComponent):
|
||||
side_offset: The distance in pixels from the anchor. Only available when position is set to popper.
|
||||
align: The preferred alignment against the anchor. May change when collisions occur. Only available when position is set to popper.
|
||||
align_offset: The vertical distance in pixels from the anchor. Only available when position is set to popper.
|
||||
on_close_auto_focus: Fired when the select content is closed.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
on_pointer_down_outside: Fired when a pointer down event happens outside the select content.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -719,6 +724,8 @@ class HighLevelSelect(SelectRoot):
|
||||
name: The name of the select control when submitting the form.
|
||||
disabled: When True, prevents the user from interacting with select.
|
||||
required: When True, indicates that the user must select a value before the owning form can be submitted.
|
||||
on_change: Props to rename Fired when the value of the select changes.
|
||||
on_open_change: Fired when the select is opened or closed.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -893,6 +900,8 @@ class Select(ComponentNamespace):
|
||||
name: The name of the select control when submitting the form.
|
||||
disabled: When True, prevents the user from interacting with select.
|
||||
required: When True, indicates that the user must select a value before the owning form can be submitted.
|
||||
on_change: Props to rename Fired when the value of the select changes.
|
||||
on_open_change: Fired when the select is opened or closed.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -189,6 +189,8 @@ class Slider(RadixThemesComponent):
|
||||
step: The step value of the slider.
|
||||
disabled: Whether the slider is disabled
|
||||
orientation: The orientation of the slider.
|
||||
on_change: Props to rename Fired when the value of the slider changes.
|
||||
on_value_commit: Fired when a thumb is released after being dragged.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -155,6 +155,7 @@ class Switch(RadixThemesComponent):
|
||||
color_scheme: Override theme color for switch
|
||||
high_contrast: Whether to render the switch with higher contrast color against background
|
||||
radius: Override theme radius for switch: "none" | "small" | "full"
|
||||
on_change: Props to rename Fired when the value of the switch changes
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -70,6 +70,7 @@ class TabsRoot(RadixThemesComponent):
|
||||
orientation: The orientation of the tabs.
|
||||
dir: Reading direction of the tabs.
|
||||
activation_mode: The mode of activation for the tabs. "automatic" will activate the tab when focused. "manual" will activate the tab when clicked.
|
||||
on_change: Props to rename Fired when the value of the tabs changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -369,6 +370,7 @@ class Tabs(ComponentNamespace):
|
||||
orientation: The orientation of the tabs.
|
||||
dir: Reading direction of the tabs.
|
||||
activation_mode: The mode of activation for the tabs. "automatic" will activate the tab when focused. "manual" will activate the tab when clicked.
|
||||
on_change: Props to rename Fired when the value of the tabs changes.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -214,6 +214,11 @@ class TextArea(RadixThemesComponent, elements.Textarea):
|
||||
auto_height: Automatically fit the content height to the text (use min-height with this prop)
|
||||
cols: Visible width of the text control, in average character widths
|
||||
enter_key_submit: Enter key submits form (shift-enter adds new line)
|
||||
on_change: Fired when the input value changes
|
||||
on_focus: Fired when the input gains focus
|
||||
on_blur: Fired when the input loses focus
|
||||
on_key_down: Fired when a key is pressed down
|
||||
on_key_up: Fired when a key is released
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
|
@ -188,6 +188,11 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
|
||||
required: Indicates that the input is required
|
||||
type: Specifies the type of input
|
||||
value: Value of the input
|
||||
on_change: Fired when the value of the textarea changes.
|
||||
on_focus: Fired when the textarea is focused.
|
||||
on_blur: Fired when the textarea is blurred.
|
||||
on_key_down: Fired when a key is pressed down.
|
||||
on_key_up: Fired when a key is released.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
@ -500,6 +505,11 @@ class TextField(ComponentNamespace):
|
||||
required: Indicates that the input is required
|
||||
type: Specifies the type of input
|
||||
value: Value of the input
|
||||
on_change: Fired when the value of the textarea changes.
|
||||
on_focus: Fired when the textarea is focused.
|
||||
on_blur: Fired when the textarea is blurred.
|
||||
on_key_down: Fired when a key is pressed down.
|
||||
on_key_up: Fired when a key is released.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
|
@ -106,6 +106,9 @@ class Tooltip(RadixThemesComponent):
|
||||
disable_hoverable_content: Prevents Tooltip content from remaining open when hovering.
|
||||
force_mount: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.
|
||||
aria_label: By default, screenreaders will announce the content inside the component. If this is not descriptive enough, or you have content that cannot be announced, use aria-label as a more descriptive label.
|
||||
on_open_change: Fired when the open state changes.
|
||||
on_escape_key_down: Fired when the escape key is pressed.
|
||||
on_pointer_down_outside: Fired when the pointer is down outside the tooltip.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -82,6 +82,22 @@ class Audio(ReactPlayer):
|
||||
muted: Mutes the player
|
||||
width: Set the width of the player: ex:640px
|
||||
height: Set the height of the player: ex:640px
|
||||
on_ready: Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
|
||||
on_start: Called when media starts playing.
|
||||
on_play: Called when media starts or resumes playing after pausing or buffering.
|
||||
on_progress: Callback containing played and loaded progress as a fraction, and playedSeconds and loadedSeconds in seconds. eg { played: 0.12, playedSeconds: 11.3, loaded: 0.34, loadedSeconds: 16.7 }
|
||||
on_duration: Callback containing duration of the media, in seconds.
|
||||
on_pause: Called when media is paused.
|
||||
on_buffer: Called when media starts buffering.
|
||||
on_buffer_end: Called when media has finished buffering. Works for files, YouTube and Facebook.
|
||||
on_seek: Called when media seeks with seconds parameter.
|
||||
on_playback_rate_change: Called when playback rate of the player changed. Only supported by YouTube, Vimeo (if enabled), Wistia, and file paths.
|
||||
on_playback_quality_change: Called when playback quality of the player changed. Only supported by YouTube (if enabled).
|
||||
on_ended: Called when media finishes playing. Does not fire when loop is set to true.
|
||||
on_error: Called when an error occurs whilst attempting to play media.
|
||||
on_click_preview: Called when user clicks the light mode preview.
|
||||
on_enable_pip: Called when picture-in-picture mode is enabled.
|
||||
on_disable_pip: Called when picture-in-picture mode is disabled.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -85,6 +85,22 @@ class ReactPlayer(NoSSRComponent):
|
||||
muted: Mutes the player
|
||||
width: Set the width of the player: ex:640px
|
||||
height: Set the height of the player: ex:640px
|
||||
on_ready: Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
|
||||
on_start: Called when media starts playing.
|
||||
on_play: Called when media starts or resumes playing after pausing or buffering.
|
||||
on_progress: Callback containing played and loaded progress as a fraction, and playedSeconds and loadedSeconds in seconds. eg { played: 0.12, playedSeconds: 11.3, loaded: 0.34, loadedSeconds: 16.7 }
|
||||
on_duration: Callback containing duration of the media, in seconds.
|
||||
on_pause: Called when media is paused.
|
||||
on_buffer: Called when media starts buffering.
|
||||
on_buffer_end: Called when media has finished buffering. Works for files, YouTube and Facebook.
|
||||
on_seek: Called when media seeks with seconds parameter.
|
||||
on_playback_rate_change: Called when playback rate of the player changed. Only supported by YouTube, Vimeo (if enabled), Wistia, and file paths.
|
||||
on_playback_quality_change: Called when playback quality of the player changed. Only supported by YouTube (if enabled).
|
||||
on_ended: Called when media finishes playing. Does not fire when loop is set to true.
|
||||
on_error: Called when an error occurs whilst attempting to play media.
|
||||
on_click_preview: Called when user clicks the light mode preview.
|
||||
on_enable_pip: Called when picture-in-picture mode is enabled.
|
||||
on_disable_pip: Called when picture-in-picture mode is disabled.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -82,6 +82,22 @@ class Video(ReactPlayer):
|
||||
muted: Mutes the player
|
||||
width: Set the width of the player: ex:640px
|
||||
height: Set the height of the player: ex:640px
|
||||
on_ready: Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
|
||||
on_start: Called when media starts playing.
|
||||
on_play: Called when media starts or resumes playing after pausing or buffering.
|
||||
on_progress: Callback containing played and loaded progress as a fraction, and playedSeconds and loadedSeconds in seconds. eg { played: 0.12, playedSeconds: 11.3, loaded: 0.34, loadedSeconds: 16.7 }
|
||||
on_duration: Callback containing duration of the media, in seconds.
|
||||
on_pause: Called when media is paused.
|
||||
on_buffer: Called when media starts buffering.
|
||||
on_buffer_end: Called when media has finished buffering. Works for files, YouTube and Facebook.
|
||||
on_seek: Called when media seeks with seconds parameter.
|
||||
on_playback_rate_change: Called when playback rate of the player changed. Only supported by YouTube, Vimeo (if enabled), Wistia, and file paths.
|
||||
on_playback_quality_change: Called when playback quality of the player changed. Only supported by YouTube (if enabled).
|
||||
on_ended: Called when media finishes playing. Does not fire when loop is set to true.
|
||||
on_error: Called when an error occurs whilst attempting to play media.
|
||||
on_click_preview: Called when user clicks the light mode preview.
|
||||
on_enable_pip: Called when picture-in-picture mode is enabled.
|
||||
on_disable_pip: Called when picture-in-picture mode is disabled.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -168,6 +168,13 @@ class Axis(Recharts):
|
||||
min_tick_gap: The minimum gap between two adjacent labels. Default: 5
|
||||
stroke: The stroke color of axis. Default: rx.color("gray", 9)
|
||||
text_anchor: The text anchor of axis. Default: "middle"
|
||||
on_click: The customized event handler of click on the ticks of this axis
|
||||
on_mouse_down: The customized event handler of mousedown on the ticks of this axis
|
||||
on_mouse_up: The customized event handler of mouseup on the ticks of this axis
|
||||
on_mouse_move: The customized event handler of mousemove on the ticks of this axis
|
||||
on_mouse_out: The customized event handler of mouseout on the ticks of this axis
|
||||
on_mouse_enter: The customized event handler of mouseenter on the ticks of this axis
|
||||
on_mouse_leave: The customized event handler of mouseleave on the ticks of this axis
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -347,6 +354,13 @@ class XAxis(Axis):
|
||||
min_tick_gap: The minimum gap between two adjacent labels. Default: 5
|
||||
stroke: The stroke color of axis. Default: rx.color("gray", 9)
|
||||
text_anchor: The text anchor of axis. Default: "middle"
|
||||
on_click: The customized event handler of click on the ticks of this axis
|
||||
on_mouse_down: The customized event handler of mousedown on the ticks of this axis
|
||||
on_mouse_up: The customized event handler of mouseup on the ticks of this axis
|
||||
on_mouse_move: The customized event handler of mousemove on the ticks of this axis
|
||||
on_mouse_out: The customized event handler of mouseout on the ticks of this axis
|
||||
on_mouse_enter: The customized event handler of mouseenter on the ticks of this axis
|
||||
on_mouse_leave: The customized event handler of mouseleave on the ticks of this axis
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -522,6 +536,13 @@ class YAxis(Axis):
|
||||
min_tick_gap: The minimum gap between two adjacent labels. Default: 5
|
||||
stroke: The stroke color of axis. Default: rx.color("gray", 9)
|
||||
text_anchor: The text anchor of axis. Default: "middle"
|
||||
on_click: The customized event handler of click on the ticks of this axis
|
||||
on_mouse_down: The customized event handler of mousedown on the ticks of this axis
|
||||
on_mouse_up: The customized event handler of mouseup on the ticks of this axis
|
||||
on_mouse_move: The customized event handler of mousemove on the ticks of this axis
|
||||
on_mouse_out: The customized event handler of mouseout on the ticks of this axis
|
||||
on_mouse_enter: The customized event handler of mouseenter on the ticks of this axis
|
||||
on_mouse_leave: The customized event handler of mouseleave on the ticks of this axis
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -787,6 +808,16 @@ class Cartesian(Recharts):
|
||||
animation_easing: The type of easing function. Default: "ease"
|
||||
unit: The unit of data. This option will be used in tooltip.
|
||||
name: The name of data. This option will be used in tooltip and legend to represent the component. If no value was set to this option, the value of dataKey will be used alternatively.
|
||||
on_animation_start: The customized event handler of animation start
|
||||
on_animation_end: The customized event handler of animation end
|
||||
on_click: The customized event handler of click on the component in this group
|
||||
on_mouse_down: The customized event handler of mousedown on the component in this group
|
||||
on_mouse_up: The customized event handler of mouseup on the component in this group
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this group
|
||||
on_mouse_over: The customized event handler of mouseover on the component in this group
|
||||
on_mouse_out: The customized event handler of mouseout on the component in this group
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this group
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this group
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -965,6 +996,16 @@ class Area(Cartesian):
|
||||
animation_easing: The type of easing function. Default: "ease"
|
||||
unit: The unit of data. This option will be used in tooltip.
|
||||
name: The name of data. This option will be used in tooltip and legend to represent the component. If no value was set to this option, the value of dataKey will be used alternatively.
|
||||
on_animation_start: The customized event handler of animation start
|
||||
on_animation_end: The customized event handler of animation end
|
||||
on_click: The customized event handler of click on the component in this group
|
||||
on_mouse_down: The customized event handler of mousedown on the component in this group
|
||||
on_mouse_up: The customized event handler of mouseup on the component in this group
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this group
|
||||
on_mouse_over: The customized event handler of mouseover on the component in this group
|
||||
on_mouse_out: The customized event handler of mouseout on the component in this group
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this group
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this group
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -1096,6 +1137,16 @@ class Bar(Cartesian):
|
||||
animation_begin: Specifies when the animation should begin, the unit of this option is ms. Default: 0
|
||||
animation_duration: Specifies the duration of animation, the unit of this option is ms. Default: 1500
|
||||
animation_easing: The type of easing function. Default: "ease"
|
||||
on_animation_start: The customized event handler of animation start
|
||||
on_animation_end: The customized event handler of animation end
|
||||
on_click: The customized event handler of click on the component in this group
|
||||
on_mouse_down: The customized event handler of mousedown on the component in this group
|
||||
on_mouse_up: The customized event handler of mouseup on the component in this group
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this group
|
||||
on_mouse_over: The customized event handler of mouseover on the component in this group
|
||||
on_mouse_out: The customized event handler of mouseout on the component in this group
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this group
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this group
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -1270,6 +1321,16 @@ class Line(Cartesian):
|
||||
animation_duration: Specifies the duration of animation, the unit of this option is ms. Default: 1500
|
||||
animation_easing: The type of easing function. Default: "ease"
|
||||
name: The name of data. This option will be used in tooltip and legend to represent the component. If no value was set to this option, the value of dataKey will be used alternatively.
|
||||
on_animation_start: The customized event handler of animation start
|
||||
on_animation_end: The customized event handler of animation end
|
||||
on_click: The customized event handler of click on the component in this group
|
||||
on_mouse_down: The customized event handler of mousedown on the component in this group
|
||||
on_mouse_up: The customized event handler of mouseup on the component in this group
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this group
|
||||
on_mouse_over: The customized event handler of mouseover on the component in this group
|
||||
on_mouse_out: The customized event handler of mouseout on the component in this group
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this group
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this group
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -1397,6 +1458,14 @@ class Scatter(Recharts):
|
||||
animation_begin: Specifies when the animation should begin, the unit of this option is ms. Default: 0
|
||||
animation_duration: Specifies the duration of animation, the unit of this option is ms. Default: 1500
|
||||
animation_easing: The type of easing function. Default: "ease"
|
||||
on_click: The customized event handler of click on the component in this group
|
||||
on_mouse_down: The customized event handler of mousedown on the component in this group
|
||||
on_mouse_up: The customized event handler of mouseup on the component in this group
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this group
|
||||
on_mouse_over: The customized event handler of mouseover on the component in this group
|
||||
on_mouse_out: The customized event handler of mouseout on the component in this group
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this group
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this group
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -1503,6 +1572,16 @@ class Funnel(Recharts):
|
||||
animation_easing: The type of easing function. 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear'. Default "ease"
|
||||
stroke: Stroke color. Default: rx.color("gray", 3)
|
||||
trapezoids: The coordinates of all the trapezoids in the funnel, usually calculated internally.
|
||||
on_animation_start: The customized event handler of animation start
|
||||
on_animation_end: The customized event handler of animation end
|
||||
on_click: The customized event handler of click on the component in this group
|
||||
on_mouse_down: The customized event handler of mousedown on the component in this group
|
||||
on_mouse_up: The customized event handler of mouseup on the component in this group
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this group
|
||||
on_mouse_over: The customized event handler of mouseover on the component in this group
|
||||
on_mouse_out: The customized event handler of mouseout on the component in this group
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this group
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this group
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -1757,6 +1836,14 @@ class ReferenceDot(Reference):
|
||||
r: The radius of dot.
|
||||
fill: The color of the area fill.
|
||||
stroke: The color of the line stroke.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_down: The customized event handler of mousedown on the component in this chart
|
||||
on_mouse_up: The customized event handler of mouseup on the component in this chart
|
||||
on_mouse_over: The customized event handler of mouseover on the component in this chart
|
||||
on_mouse_out: The customized event handler of mouseout on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
x_axis_id: The id of x-axis which is corresponding to the data. Default: 0
|
||||
y_axis_id: The id of y-axis which is corresponding to the data. Default: 0
|
||||
if_overflow: Defines how to draw the reference line if it falls partly outside the canvas. If set to 'discard', the reference line will not be drawn at all. If set to 'hidden', the reference line will be clipped to the canvas. If set to 'visible', the reference line will be drawn completely. If set to 'extendDomain', the domain of the overflown axis will be extended such that the reference line fits into the canvas. Default: "discard"
|
||||
|
@ -51,6 +51,10 @@ class ChartBase(RechartsCharts):
|
||||
*children: The children of the chart component.
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -125,6 +129,10 @@ class CategoricalChartBase(ChartBase):
|
||||
stack_offset: The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand' | 'none' | 'wiggle' | 'silhouette'
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -207,6 +215,10 @@ class AreaChart(CategoricalChartBase):
|
||||
stack_offset: The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand' | 'none' | 'wiggle' | 'silhouette'
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -291,6 +303,10 @@ class BarChart(CategoricalChartBase):
|
||||
layout: The layout of area in the chart. 'horizontal' | 'vertical'. Default: "horizontal"
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -365,6 +381,10 @@ class LineChart(CategoricalChartBase):
|
||||
stack_offset: The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand' | 'none' | 'wiggle' | 'silhouette'
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -455,6 +475,10 @@ class ComposedChart(CategoricalChartBase):
|
||||
stack_offset: The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand' | 'none' | 'wiggle' | 'silhouette'
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -505,8 +529,16 @@ class PieChart(ChartBase):
|
||||
Args:
|
||||
*children: The children of the chart component.
|
||||
margin: The sizes of whitespace around the chart, i.e. {"top": 50, "right": 30, "left": 20, "bottom": 5}.
|
||||
on_mouse_down: The customized event handler of mousedown on the sectors in this group
|
||||
on_mouse_up: The customized event handler of mouseup on the sectors in this group
|
||||
on_mouse_over: The customized event handler of mouseover on the sectors in this group
|
||||
on_mouse_out: The customized event handler of mouseout on the sectors in this group
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -562,6 +594,9 @@ class RadarChart(ChartBase):
|
||||
outer_radius: The outer radius of last circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number | Percentage. Default: "80%"
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -634,6 +669,10 @@ class RadialBarChart(ChartBase):
|
||||
bar_size: The size of each bar. If the barSize is not specified, the size of bar will be calculated by the barCategoryGap, barGap and the quantity of bar groups.
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -680,6 +719,10 @@ class ScatterChart(ChartBase):
|
||||
margin: The sizes of whitespace around the chart. Default: {"top": 5, "right": 5, "bottom": 5, "left": 5}
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -736,6 +779,10 @@ class FunnelChart(ChartBase):
|
||||
stroke: The stroke color of each bar. String | Object
|
||||
width: The width of chart container. String or Integer
|
||||
height: The height of chart container.
|
||||
on_click: The customized event handler of click on the component in this chart
|
||||
on_mouse_enter: The customized event handler of mouseenter on the component in this chart
|
||||
on_mouse_move: The customized event handler of mousemove on the component in this chart
|
||||
on_mouse_leave: The customized event handler of mouseleave on the component in this chart
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -809,6 +856,8 @@ class Treemap(RechartsCharts):
|
||||
animation_begin: Specifies when the animation should begin, the unit of this option is ms. Default: 0
|
||||
animation_duration: Specifies the duration of animation, the unit of this option is ms. Default: 1500
|
||||
animation_easing: The type of easing function. 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear'. Default: "ease"
|
||||
on_animation_start: The customized event handler of animation start
|
||||
on_animation_end: The customized event handler of animation end
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -61,6 +61,7 @@ class ResponsiveContainer(Recharts, MemoizationLeaf):
|
||||
min_width: The minimum width of chart container. Number
|
||||
min_height: The minimum height of chart container. Number
|
||||
debounce: If specified a positive number, debounced function will be used to handle the resize event. Default: 0
|
||||
on_resize: If specified provides a callback providing the updated chart width and height values.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -175,6 +176,14 @@ class Legend(Recharts):
|
||||
chart_width: The width of chart container, usually calculated internally.
|
||||
chart_height: The height of chart container, usually calculated internally.
|
||||
margin: The margin of chart container, usually calculated internally.
|
||||
on_click: The customized event handler of click on the items in this group
|
||||
on_mouse_down: The customized event handler of mousedown on the items in this group
|
||||
on_mouse_up: The customized event handler of mouseup on the items in this group
|
||||
on_mouse_move: The customized event handler of mousemove on the items in this group
|
||||
on_mouse_over: The customized event handler of mouseover on the items in this group
|
||||
on_mouse_out: The customized event handler of mouseout on the items in this group
|
||||
on_mouse_enter: The customized event handler of mouseenter on the items in this group
|
||||
on_mouse_leave: The customized event handler of mouseleave on the items in this group
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -391,6 +391,14 @@ class PolarAngleAxis(Recharts):
|
||||
orientation: The orientation of axis text. Default: "outer"
|
||||
stroke: The stroke color of axis. Default: rx.color("gray", 10)
|
||||
allow_duplicated_category: Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True
|
||||
on_click: The customized event handler of click on the ticks of this axis.
|
||||
on_mouse_down: The customized event handler of mousedown on the the ticks of this axis.
|
||||
on_mouse_up: The customized event handler of mouseup on the ticks of this axis.
|
||||
on_mouse_move: The customized event handler of mousemove on the ticks of this axis.
|
||||
on_mouse_over: The customized event handler of mouseover on the ticks of this axis.
|
||||
on_mouse_out: The customized event handler of mouseout on the ticks of this axis.
|
||||
on_mouse_enter: The customized event handler of moustenter on the ticks of this axis.
|
||||
on_mouse_leave: The customized event handler of mouseleave on the ticks of this axis.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -172,6 +172,15 @@ class Editor(NoSSRComponent):
|
||||
hide: Hide the editor default: False
|
||||
hide_toolbar: Hide the editor toolbar default: False
|
||||
disable_toolbar: Disable the editor toolbar default: False
|
||||
on_change: Fired when the editor content changes.
|
||||
on_input: Fired when the something is inputted in the editor.
|
||||
on_blur: Fired when the editor loses focus.
|
||||
on_load: Fired when the editor is loaded.
|
||||
on_copy: Fired when the editor content is copied.
|
||||
on_cut: Fired when the editor content is cut.
|
||||
on_paste: Fired when the editor content is pasted.
|
||||
toggle_code_view: Fired when the code view is toggled.
|
||||
toggle_full_screen: Fired when the full screen mode is toggled.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from reflex.event import EventChain
|
||||
from reflex.utils import format, types
|
||||
@ -23,9 +23,6 @@ class Tag:
|
||||
# The inner contents of the tag.
|
||||
contents: str = ""
|
||||
|
||||
# Args to pass to the tag.
|
||||
args: Optional[Tuple[str, ...]] = None
|
||||
|
||||
# Special props that aren't key value pairs.
|
||||
special_props: List[Var] = dataclasses.field(default_factory=list)
|
||||
|
||||
|
@ -3,14 +3,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import enum
|
||||
import importlib
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Set
|
||||
|
||||
from typing_extensions import get_type_hints
|
||||
from typing_extensions import Annotated, get_type_hints
|
||||
|
||||
from reflex.utils.exceptions import ConfigError, EnvironmentVarValueError
|
||||
from reflex.utils.types import GenericType, is_union, value_inside_optional
|
||||
@ -202,8 +204,8 @@ def interpret_int_env(value: str, field_name: str) -> int:
|
||||
) from ve
|
||||
|
||||
|
||||
def interpret_path_env(value: str, field_name: str) -> Path:
|
||||
"""Interpret a path environment variable value.
|
||||
def interpret_existing_path_env(value: str, field_name: str) -> ExistingPath:
|
||||
"""Interpret a path environment variable value as an existing path.
|
||||
|
||||
Args:
|
||||
value: The environment variable value.
|
||||
@ -221,6 +223,41 @@ def interpret_path_env(value: str, field_name: str) -> Path:
|
||||
return path
|
||||
|
||||
|
||||
def interpret_path_env(value: str, field_name: str) -> Path:
|
||||
"""Interpret a path environment variable value.
|
||||
|
||||
Args:
|
||||
value: The environment variable value.
|
||||
field_name: The field name.
|
||||
|
||||
Returns:
|
||||
The interpreted value.
|
||||
"""
|
||||
return Path(value)
|
||||
|
||||
|
||||
def interpret_enum_env(value: str, field_type: GenericType, field_name: str) -> Any:
|
||||
"""Interpret an enum environment variable value.
|
||||
|
||||
Args:
|
||||
value: The environment variable value.
|
||||
field_type: The field type.
|
||||
field_name: The field name.
|
||||
|
||||
Returns:
|
||||
The interpreted value.
|
||||
|
||||
Raises:
|
||||
EnvironmentVarValueError: If the value is invalid.
|
||||
"""
|
||||
try:
|
||||
return field_type(value)
|
||||
except ValueError as ve:
|
||||
raise EnvironmentVarValueError(
|
||||
f"Invalid enum value: {value} for {field_name}"
|
||||
) from ve
|
||||
|
||||
|
||||
def interpret_env_var_value(
|
||||
value: str, field_type: GenericType, field_name: str
|
||||
) -> Any:
|
||||
@ -252,6 +289,10 @@ def interpret_env_var_value(
|
||||
return interpret_int_env(value, field_name)
|
||||
elif field_type is Path:
|
||||
return interpret_path_env(value, field_name)
|
||||
elif field_type is ExistingPath:
|
||||
return interpret_existing_path_env(value, field_name)
|
||||
elif inspect.isclass(field_type) and issubclass(field_type, enum.Enum):
|
||||
return interpret_enum_env(value, field_type, field_name)
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
@ -259,6 +300,13 @@ def interpret_env_var_value(
|
||||
)
|
||||
|
||||
|
||||
class PathExistsFlag:
|
||||
"""Flag to indicate that a path must exist."""
|
||||
|
||||
|
||||
ExistingPath = Annotated[Path, PathExistsFlag]
|
||||
|
||||
|
||||
@dataclasses.dataclass(init=False)
|
||||
class EnvironmentVariables:
|
||||
"""Environment variables class to instantiate environment variables."""
|
||||
@ -288,7 +336,7 @@ class EnvironmentVariables:
|
||||
REFLEX_WEB_WORKDIR: Path = Path(constants.Dirs.WEB)
|
||||
|
||||
# Path to the alembic config file
|
||||
ALEMBIC_CONFIG: Path = Path(constants.ALEMBIC_CONFIG)
|
||||
ALEMBIC_CONFIG: ExistingPath = Path(constants.ALEMBIC_CONFIG)
|
||||
|
||||
# Disable SSL verification for HTTPX requests.
|
||||
SSL_NO_VERIFY: bool = False
|
||||
@ -401,7 +449,10 @@ class Config(Base):
|
||||
telemetry_enabled: bool = True
|
||||
|
||||
# The bun path
|
||||
bun_path: Path = constants.Bun.DEFAULT_PATH
|
||||
bun_path: ExistingPath = constants.Bun.DEFAULT_PATH
|
||||
|
||||
# Timeout to do a production build of a frontend page.
|
||||
static_page_generation_timeout: int = 60
|
||||
|
||||
# List of origins that are allowed to connect to the backend API.
|
||||
cors_allowed_origins: List[str] = ["*"]
|
||||
@ -525,7 +576,7 @@ class Config(Base):
|
||||
)
|
||||
|
||||
# Interpret the value.
|
||||
value = interpret_env_var_value(env_var, field.type_, field.name)
|
||||
value = interpret_env_var_value(env_var, field.outer_type_, field.name)
|
||||
|
||||
# Set the value.
|
||||
updated_values[key] = value
|
||||
|
@ -118,7 +118,7 @@ class Node(SimpleNamespace):
|
||||
"""Node/ NPM constants."""
|
||||
|
||||
# The Node version.
|
||||
VERSION = "22.10.0"
|
||||
VERSION = "22.11.0"
|
||||
# The minimum required node version.
|
||||
MIN_VERSION = "18.18.0"
|
||||
|
||||
|
138
reflex/event.py
138
reflex/event.py
@ -87,7 +87,7 @@ class Event:
|
||||
BACKGROUND_TASK_MARKER = "_reflex_background_task"
|
||||
|
||||
|
||||
def background(fn):
|
||||
def background(fn, *, __internal_reflex_call: bool = False):
|
||||
"""Decorator to mark event handler as running in the background.
|
||||
|
||||
Args:
|
||||
@ -100,6 +100,13 @@ def background(fn):
|
||||
Raises:
|
||||
TypeError: If the function is not a coroutine function or async generator.
|
||||
"""
|
||||
if not __internal_reflex_call:
|
||||
console.deprecate(
|
||||
"background-decorator",
|
||||
"Use `rx.event(background=True)` instead.",
|
||||
"0.6.5",
|
||||
"0.7.0",
|
||||
)
|
||||
if not inspect.iscoroutinefunction(fn) and not inspect.isasyncgenfunction(fn):
|
||||
raise TypeError("Background task must be async function or generator.")
|
||||
setattr(fn, BACKGROUND_TASK_MARKER, True)
|
||||
@ -766,18 +773,25 @@ def set_focus(ref: str) -> EventSpec:
|
||||
)
|
||||
|
||||
|
||||
def scroll_to(elem_id: str) -> EventSpec:
|
||||
def scroll_to(elem_id: str, align_to_top: bool | Var[bool] = True) -> EventSpec:
|
||||
"""Select the id of a html element for scrolling into view.
|
||||
|
||||
Args:
|
||||
elem_id: the id of the element
|
||||
elem_id: The id of the element to scroll to.
|
||||
align_to_top: Whether to scroll to the top (True) or bottom (False) of the element.
|
||||
|
||||
Returns:
|
||||
An EventSpec to scroll the page to the selected element.
|
||||
"""
|
||||
js_code = f"document.getElementById('{elem_id}').scrollIntoView();"
|
||||
get_element_by_id = FunctionStringVar.create("document.getElementById")
|
||||
|
||||
return call_script(js_code)
|
||||
return call_script(
|
||||
get_element_by_id(elem_id)
|
||||
.call(elem_id)
|
||||
.to(ObjectVar)
|
||||
.scrollIntoView.to(FunctionVar)
|
||||
.call(align_to_top)
|
||||
)
|
||||
|
||||
|
||||
def set_value(ref: str, value: Any) -> EventSpec:
|
||||
@ -1579,6 +1593,8 @@ V3 = TypeVar("V3")
|
||||
V4 = TypeVar("V4")
|
||||
V5 = TypeVar("V5")
|
||||
|
||||
background_event_decorator = background
|
||||
|
||||
if sys.version_info >= (3, 10):
|
||||
from typing import Concatenate
|
||||
|
||||
@ -1611,6 +1627,11 @@ if sys.version_info >= (3, 10):
|
||||
"""
|
||||
return self
|
||||
|
||||
@overload
|
||||
def __call__(
|
||||
self: EventCallback[Q, T],
|
||||
) -> EventCallback[Q, T]: ...
|
||||
|
||||
@overload
|
||||
def __call__(
|
||||
self: EventCallback[Concatenate[V, Q], T], value: V | Var[V]
|
||||
@ -1674,32 +1695,12 @@ if sys.version_info >= (3, 10):
|
||||
|
||||
return partial(self.func, instance) # type: ignore
|
||||
|
||||
def event_handler(func: Callable[Concatenate[Any, P], T]) -> EventCallback[P, T]:
|
||||
"""Wrap a function to be used as an event.
|
||||
|
||||
Args:
|
||||
func: The function to wrap.
|
||||
|
||||
Returns:
|
||||
The wrapped function.
|
||||
"""
|
||||
return func # type: ignore
|
||||
else:
|
||||
|
||||
class EventCallback(Generic[P, T]):
|
||||
"""A descriptor that wraps a function to be used as an event."""
|
||||
|
||||
def event_handler(func: Callable[P, T]) -> Callable[P, T]:
|
||||
"""Wrap a function to be used as an event.
|
||||
|
||||
Args:
|
||||
func: The function to wrap.
|
||||
|
||||
Returns:
|
||||
The wrapped function.
|
||||
"""
|
||||
return func
|
||||
|
||||
|
||||
G = ParamSpec("G")
|
||||
|
||||
@ -1725,8 +1726,93 @@ class EventNamespace(types.SimpleNamespace):
|
||||
EventChainVar = EventChainVar
|
||||
LiteralEventChainVar = LiteralEventChainVar
|
||||
EventType = EventType
|
||||
EventCallback = EventCallback
|
||||
|
||||
if sys.version_info >= (3, 10):
|
||||
|
||||
@overload
|
||||
@staticmethod
|
||||
def __call__(
|
||||
func: None = None, *, background: bool | None = None
|
||||
) -> Callable[[Callable[Concatenate[Any, P], T]], EventCallback[P, T]]: ...
|
||||
|
||||
@overload
|
||||
@staticmethod
|
||||
def __call__(
|
||||
func: Callable[Concatenate[Any, P], T],
|
||||
*,
|
||||
background: bool | None = None,
|
||||
) -> EventCallback[P, T]: ...
|
||||
|
||||
@staticmethod
|
||||
def __call__(
|
||||
func: Callable[Concatenate[Any, P], T] | None = None,
|
||||
*,
|
||||
background: bool | None = None,
|
||||
) -> Union[
|
||||
EventCallback[P, T],
|
||||
Callable[[Callable[Concatenate[Any, P], T]], EventCallback[P, T]],
|
||||
]:
|
||||
"""Wrap a function to be used as an event.
|
||||
|
||||
Args:
|
||||
func: The function to wrap.
|
||||
background: Whether the event should be run in the background. Defaults to False.
|
||||
|
||||
Returns:
|
||||
The wrapped function.
|
||||
"""
|
||||
|
||||
def wrapper(func: Callable[Concatenate[Any, P], T]) -> EventCallback[P, T]:
|
||||
if background is True:
|
||||
return background_event_decorator(func, __internal_reflex_call=True) # type: ignore
|
||||
return func # type: ignore
|
||||
|
||||
if func is not None:
|
||||
return wrapper(func)
|
||||
return wrapper
|
||||
else:
|
||||
|
||||
@overload
|
||||
@staticmethod
|
||||
def __call__(
|
||||
func: None = None, *, background: bool | None = None
|
||||
) -> Callable[[Callable[P, T]], Callable[P, T]]: ...
|
||||
|
||||
@overload
|
||||
@staticmethod
|
||||
def __call__(
|
||||
func: Callable[P, T], *, background: bool | None = None
|
||||
) -> Callable[P, T]: ...
|
||||
|
||||
@staticmethod
|
||||
def __call__(
|
||||
func: Callable[P, T] | None = None,
|
||||
*,
|
||||
background: bool | None = None,
|
||||
) -> Union[
|
||||
Callable[P, T],
|
||||
Callable[[Callable[P, T]], Callable[P, T]],
|
||||
]:
|
||||
"""Wrap a function to be used as an event.
|
||||
|
||||
Args:
|
||||
func: The function to wrap.
|
||||
background: Whether the event should be run in the background. Defaults to False.
|
||||
|
||||
Returns:
|
||||
The wrapped function.
|
||||
"""
|
||||
|
||||
def wrapper(func: Callable[P, T]) -> Callable[P, T]:
|
||||
if background is True:
|
||||
return background_event_decorator(func, __internal_reflex_call=True) # type: ignore
|
||||
return func # type: ignore
|
||||
|
||||
if func is not None:
|
||||
return wrapper(func)
|
||||
return wrapper
|
||||
|
||||
__call__ = staticmethod(event_handler)
|
||||
get_event = staticmethod(get_event)
|
||||
get_hydrate_event = staticmethod(get_hydrate_event)
|
||||
fix_events = staticmethod(fix_events)
|
||||
|
@ -7,7 +7,7 @@ from typing import Any
|
||||
async def run_in_thread(func) -> Any:
|
||||
"""Run a function in a separate thread.
|
||||
|
||||
To not block the UI event queue, run_in_thread must be inside inside a rx.background() decorated method.
|
||||
To not block the UI event queue, run_in_thread must be inside inside a rx.event(background=True) decorated method.
|
||||
|
||||
Args:
|
||||
func (callable): The non-async function to run.
|
||||
|
@ -6,6 +6,7 @@ from collections import defaultdict
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from reflex.config import get_config
|
||||
from reflex.event import EventType
|
||||
|
||||
DECORATED_PAGES: Dict[str, List] = defaultdict(list)
|
||||
|
||||
@ -17,7 +18,7 @@ def page(
|
||||
description: str | None = None,
|
||||
meta: list[Any] | None = None,
|
||||
script_tags: list[Any] | None = None,
|
||||
on_load: Any | list[Any] | None = None,
|
||||
on_load: EventType[[]] | None = None,
|
||||
):
|
||||
"""Decorate a function as a page.
|
||||
|
||||
|
@ -91,7 +91,7 @@ from reflex.utils.exceptions import (
|
||||
)
|
||||
from reflex.utils.exec import is_testing_env
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.utils.types import get_origin, override
|
||||
from reflex.utils.types import _isinstance, get_origin, override
|
||||
from reflex.vars import VarData
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -105,6 +105,15 @@ var = computed_var
|
||||
# If the state is this large, it's considered a performance issue.
|
||||
TOO_LARGE_SERIALIZED_STATE = 100 * 1024 # 100kb
|
||||
|
||||
# Errors caught during pickling of state
|
||||
HANDLED_PICKLE_ERRORS = (
|
||||
pickle.PicklingError,
|
||||
AttributeError,
|
||||
IndexError,
|
||||
TypeError,
|
||||
ValueError,
|
||||
)
|
||||
|
||||
|
||||
def _no_chain_background_task(
|
||||
state_cls: Type["BaseState"], name: str, fn: Callable
|
||||
@ -636,7 +645,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
def computed_var_func(state: Self):
|
||||
result = f(state)
|
||||
|
||||
if not isinstance(result, of_type):
|
||||
if not _isinstance(result, of_type):
|
||||
console.warn(
|
||||
f"Inline ComputedVar {f} expected type {of_type}, got {type(result)}. "
|
||||
"You can specify expected type with `of_type` argument."
|
||||
@ -1274,6 +1283,19 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
f"All state variables must be declared before they can be set."
|
||||
)
|
||||
|
||||
fields = self.get_fields()
|
||||
|
||||
if name in fields and not _isinstance(
|
||||
value, (field_type := fields[name].outer_type_)
|
||||
):
|
||||
console.deprecate(
|
||||
"mismatched-type-assignment",
|
||||
f"Tried to assign value {value} of type {type(value)} to field {type(self).__name__}.{name} of type {field_type}."
|
||||
" This might lead to unexpected behavior.",
|
||||
"0.6.5",
|
||||
"0.7.0",
|
||||
)
|
||||
|
||||
# Set the attribute.
|
||||
super().__setattr__(name, value)
|
||||
|
||||
@ -2063,7 +2085,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
"""
|
||||
try:
|
||||
return pickle.dumps((self._to_schema(), self))
|
||||
except (pickle.PicklingError, AttributeError) as og_pickle_error:
|
||||
except HANDLED_PICKLE_ERRORS as og_pickle_error:
|
||||
error = (
|
||||
f"Failed to serialize state {self.get_full_name()} due to unpicklable object. "
|
||||
"This state will not be persisted. "
|
||||
@ -2077,7 +2099,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
f"Pickle error: {og_pickle_error}. "
|
||||
"Consider `pip install 'dill>=0.3.8'` for more exotic serialization support."
|
||||
)
|
||||
except (pickle.PicklingError, TypeError, ValueError) as ex:
|
||||
except HANDLED_PICKLE_ERRORS as ex:
|
||||
error += f"Dill was also unable to pickle the state: {ex}"
|
||||
console.warn(error)
|
||||
return b""
|
||||
@ -2346,7 +2368,7 @@ class StateProxy(wrapt.ObjectProxy):
|
||||
class State(rx.State):
|
||||
counter: int = 0
|
||||
|
||||
@rx.background
|
||||
@rx.event(background=True)
|
||||
async def bg_increment(self):
|
||||
await asyncio.sleep(1)
|
||||
async with self:
|
||||
@ -3248,7 +3270,7 @@ class StateManagerRedis(StateManager):
|
||||
raise LockExpiredError(
|
||||
f"Lock expired for token {token} while processing. Consider increasing "
|
||||
f"`app.state_manager.lock_expiration` (currently {self.lock_expiration}) "
|
||||
"or use `@rx.background` decorator for long-running tasks."
|
||||
"or use `@rx.event(background=True)` decorator for long-running tasks."
|
||||
)
|
||||
client_token, substate_name = _split_substate_key(token)
|
||||
# If the substate name on the token doesn't match the instance name, it cannot have a parent.
|
||||
|
@ -197,8 +197,16 @@ def make_default_page_title(app_name: str, route: str) -> str:
|
||||
Returns:
|
||||
The default page title.
|
||||
"""
|
||||
title = constants.DefaultPage.TITLE.format(app_name, route)
|
||||
return to_title_case(title, " ")
|
||||
route_parts = [
|
||||
part
|
||||
for part in route.split("/")
|
||||
if part and not (part.startswith("[") and part.endswith("]"))
|
||||
]
|
||||
|
||||
title = constants.DefaultPage.TITLE.format(
|
||||
app_name, route_parts[-1] if route_parts else constants.PageNames.INDEX_ROUTE
|
||||
)
|
||||
return to_title_case(title)
|
||||
|
||||
|
||||
def _escape_js_string(string: str) -> str:
|
||||
|
@ -677,6 +677,7 @@ def _update_next_config(
|
||||
"compress": config.next_compression,
|
||||
"reactStrictMode": config.react_strict_mode,
|
||||
"trailingSlash": True,
|
||||
"staticPageGenerationTimeout": config.static_page_generation_timeout,
|
||||
}
|
||||
if transpile_packages:
|
||||
next_config["transpilePackages"] = list(
|
||||
|
@ -584,6 +584,7 @@ def _generate_component_create_functiondef(
|
||||
)
|
||||
for trigger in sorted(event_triggers)
|
||||
)
|
||||
|
||||
logger.debug(f"Generated {clz.__name__}.create method with {len(kwargs)} kwargs")
|
||||
create_args = ast.arguments(
|
||||
args=[ast.arg(arg="cls")],
|
||||
@ -594,12 +595,17 @@ def _generate_component_create_functiondef(
|
||||
kwarg=ast.arg(arg="props"),
|
||||
defaults=[],
|
||||
)
|
||||
|
||||
definition = ast.FunctionDef(
|
||||
name="create",
|
||||
args=create_args,
|
||||
body=[
|
||||
ast.Expr(
|
||||
value=ast.Constant(value=_generate_docstrings(all_classes, all_props))
|
||||
value=ast.Constant(
|
||||
value=_generate_docstrings(
|
||||
all_classes, [*all_props, *event_triggers]
|
||||
)
|
||||
),
|
||||
),
|
||||
ast.Expr(
|
||||
value=ast.Ellipsis(),
|
||||
|
@ -510,16 +510,66 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None)
|
||||
raise TypeError(f"Invalid type for issubclass: {cls_base}") from te
|
||||
|
||||
|
||||
def _isinstance(obj: Any, cls: GenericType) -> bool:
|
||||
def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
|
||||
"""Check if an object is an instance of a class.
|
||||
|
||||
Args:
|
||||
obj: The object to check.
|
||||
cls: The class to check against.
|
||||
nested: Whether the check is nested.
|
||||
|
||||
Returns:
|
||||
Whether the object is an instance of the class.
|
||||
"""
|
||||
if cls is Any:
|
||||
return True
|
||||
|
||||
if cls is None or cls is type(None):
|
||||
return obj is None
|
||||
|
||||
if is_literal(cls):
|
||||
return obj in get_args(cls)
|
||||
|
||||
if is_union(cls):
|
||||
return any(_isinstance(obj, arg) for arg in get_args(cls))
|
||||
|
||||
origin = get_origin(cls)
|
||||
|
||||
if origin is None:
|
||||
# cls is a simple class
|
||||
return isinstance(obj, cls)
|
||||
|
||||
args = get_args(cls)
|
||||
|
||||
if not args:
|
||||
# cls is a simple generic class
|
||||
return isinstance(obj, origin)
|
||||
|
||||
if nested and args:
|
||||
if origin is list:
|
||||
return isinstance(obj, list) and all(
|
||||
_isinstance(item, args[0]) for item in obj
|
||||
)
|
||||
if origin is tuple:
|
||||
if args[-1] is Ellipsis:
|
||||
return isinstance(obj, tuple) and all(
|
||||
_isinstance(item, args[0]) for item in obj
|
||||
)
|
||||
return (
|
||||
isinstance(obj, tuple)
|
||||
and len(obj) == len(args)
|
||||
and all(_isinstance(item, arg) for item, arg in zip(obj, args))
|
||||
)
|
||||
if origin is dict:
|
||||
return isinstance(obj, dict) and all(
|
||||
_isinstance(key, args[0]) and _isinstance(value, args[1])
|
||||
for key, value in obj.items()
|
||||
)
|
||||
if origin is set:
|
||||
return isinstance(obj, set) and all(
|
||||
_isinstance(item, args[0]) for item in obj
|
||||
)
|
||||
|
||||
return isinstance(obj, get_base_class(cls))
|
||||
|
||||
|
||||
|
@ -63,7 +63,14 @@ from reflex.utils.imports import (
|
||||
ParsedImportDict,
|
||||
parse_imports,
|
||||
)
|
||||
from reflex.utils.types import GenericType, Self, get_origin, has_args, unionize
|
||||
from reflex.utils.types import (
|
||||
GenericType,
|
||||
Self,
|
||||
_isinstance,
|
||||
get_origin,
|
||||
has_args,
|
||||
unionize,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reflex.state import BaseState
|
||||
@ -612,10 +619,6 @@ class Var(Generic[VAR_TYPE]):
|
||||
"""
|
||||
from .object import ObjectVar
|
||||
|
||||
base_type = var_type
|
||||
if types.is_optional(base_type):
|
||||
base_type = types.get_args(base_type)[0]
|
||||
|
||||
fixed_output_type = get_origin(output) or output
|
||||
|
||||
# If the first argument is a python type, we map it to the corresponding Var type.
|
||||
@ -1833,6 +1836,14 @@ class ComputedVar(Var[RETURN_TYPE]):
|
||||
"return", Any
|
||||
)
|
||||
|
||||
if hint is Any:
|
||||
console.deprecate(
|
||||
"untyped-computed-var",
|
||||
"ComputedVar should have a return type annotation.",
|
||||
"0.6.5",
|
||||
"0.7.0",
|
||||
)
|
||||
|
||||
kwargs.setdefault("_js_expr", fget.__name__)
|
||||
kwargs.setdefault("_var_type", hint)
|
||||
|
||||
@ -2026,8 +2037,8 @@ class ComputedVar(Var[RETURN_TYPE]):
|
||||
)
|
||||
|
||||
if not self._cache:
|
||||
return self.fget(instance)
|
||||
|
||||
value = self.fget(instance)
|
||||
else:
|
||||
# handle caching
|
||||
if not hasattr(instance, self._cache_attr) or self.needs_update(instance):
|
||||
# Set cache attr on state instance.
|
||||
@ -2036,7 +2047,18 @@ class ComputedVar(Var[RETURN_TYPE]):
|
||||
instance._was_touched = True
|
||||
# Set the last updated timestamp on the state instance.
|
||||
setattr(instance, self._last_updated_attr, datetime.datetime.now())
|
||||
return getattr(instance, self._cache_attr)
|
||||
value = getattr(instance, self._cache_attr)
|
||||
|
||||
if not _isinstance(value, self._var_type):
|
||||
console.deprecate(
|
||||
"mismatched-computed-var-return",
|
||||
f"Computed var {type(instance).__name__}.{self._js_expr} returned value of type {type(value)}, "
|
||||
f"expected {self._var_type}. This might cause unexpected behavior.",
|
||||
"0.6.5",
|
||||
"0.7.0",
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
def _deps(
|
||||
self,
|
||||
|
@ -1,4 +1,4 @@
|
||||
"""Test @rx.background task functionality."""
|
||||
"""Test @rx.event(background=True) task functionality."""
|
||||
|
||||
from typing import Generator
|
||||
|
||||
@ -22,8 +22,7 @@ def BackgroundTask():
|
||||
_task_id: int = 0
|
||||
iterations: int = 10
|
||||
|
||||
@rx.background
|
||||
@rx.event
|
||||
@rx.event(background=True)
|
||||
async def handle_event(self):
|
||||
async with self:
|
||||
self._task_id += 1
|
||||
@ -32,8 +31,7 @@ def BackgroundTask():
|
||||
self.counter += 1
|
||||
await asyncio.sleep(0.005)
|
||||
|
||||
@rx.background
|
||||
@rx.event
|
||||
@rx.event(background=True)
|
||||
async def handle_event_yield_only(self):
|
||||
async with self:
|
||||
self._task_id += 1
|
||||
@ -48,7 +46,7 @@ def BackgroundTask():
|
||||
def increment(self):
|
||||
self.counter += 1
|
||||
|
||||
@rx.background
|
||||
@rx.event(background=True)
|
||||
async def increment_arbitrary(self, amount: int):
|
||||
async with self:
|
||||
self.counter += int(amount)
|
||||
@ -61,8 +59,7 @@ def BackgroundTask():
|
||||
async def blocking_pause(self):
|
||||
await asyncio.sleep(0.02)
|
||||
|
||||
@rx.background
|
||||
@rx.event
|
||||
@rx.event(background=True)
|
||||
async def non_blocking_pause(self):
|
||||
await asyncio.sleep(0.02)
|
||||
|
||||
@ -74,15 +71,13 @@ def BackgroundTask():
|
||||
self.counter += 1
|
||||
await asyncio.sleep(0.005)
|
||||
|
||||
@rx.background
|
||||
@rx.event
|
||||
@rx.event(background=True)
|
||||
async def handle_racy_event(self):
|
||||
await asyncio.gather(
|
||||
self.racy_task(), self.racy_task(), self.racy_task(), self.racy_task()
|
||||
)
|
||||
|
||||
@rx.background
|
||||
@rx.event
|
||||
@rx.event(background=True)
|
||||
async def nested_async_with_self(self):
|
||||
async with self:
|
||||
self.counter += 1
|
||||
@ -94,8 +89,7 @@ def BackgroundTask():
|
||||
third_state = await self.get_state(ThirdState)
|
||||
await third_state._triple_count()
|
||||
|
||||
@rx.background
|
||||
@rx.event
|
||||
@rx.event(background=True)
|
||||
async def yield_in_async_with_self(self):
|
||||
async with self:
|
||||
self.counter += 1
|
||||
@ -103,8 +97,7 @@ def BackgroundTask():
|
||||
self.counter += 1
|
||||
|
||||
class OtherState(rx.State):
|
||||
@rx.background
|
||||
@rx.event
|
||||
@rx.event(background=True)
|
||||
async def get_other_state(self):
|
||||
async with self:
|
||||
state = await self.get_state(State)
|
||||
|
@ -121,7 +121,7 @@ def FormSubmitName(form_component):
|
||||
on_change=rx.console_log,
|
||||
),
|
||||
rx.button("Submit", type_="submit"),
|
||||
rx.icon_button(FormState.val, icon=rx.icon(tag="plus")),
|
||||
rx.icon_button(rx.icon(tag="plus")),
|
||||
),
|
||||
on_submit=FormState.form_submit,
|
||||
custom_attrs={"action": "/invalid"},
|
||||
|
@ -793,8 +793,8 @@ def test_var_operations(driver, var_operations: AppHarness):
|
||||
("foreach_list_ix", "1\n2"),
|
||||
("foreach_list_nested", "1\n1\n2"),
|
||||
# rx.memo component with state
|
||||
("memo_comp", "[1,2]10"),
|
||||
("memo_comp_nested", "[3,4]5"),
|
||||
("memo_comp", "1210"),
|
||||
("memo_comp_nested", "345"),
|
||||
# foreach in a match
|
||||
("foreach_in_match", "first\nsecond\nthird"),
|
||||
]
|
||||
|
@ -1,205 +0,0 @@
|
||||
import pytest
|
||||
|
||||
import reflex as rx
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def upload_root_component():
|
||||
"""A test upload component function.
|
||||
|
||||
Returns:
|
||||
A test upload component function.
|
||||
"""
|
||||
|
||||
def upload_root_component():
|
||||
return rx.upload.root(
|
||||
rx.button("select file"),
|
||||
rx.text("Drag and drop files here or click to select files"),
|
||||
border="1px dotted black",
|
||||
)
|
||||
|
||||
return upload_root_component()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def upload_component():
|
||||
"""A test upload component function.
|
||||
|
||||
Returns:
|
||||
A test upload component function.
|
||||
"""
|
||||
|
||||
def upload_component():
|
||||
return rx.upload(
|
||||
rx.button("select file"),
|
||||
rx.text("Drag and drop files here or click to select files"),
|
||||
border="1px dotted black",
|
||||
)
|
||||
|
||||
return upload_component()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def upload_component_id_special():
|
||||
def upload_component():
|
||||
return rx.upload(
|
||||
rx.button("select file"),
|
||||
rx.text("Drag and drop files here or click to select files"),
|
||||
border="1px dotted black",
|
||||
id="#spec!`al-_98ID",
|
||||
)
|
||||
|
||||
return upload_component()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def upload_component_with_props():
|
||||
"""A test upload component with props function.
|
||||
|
||||
Returns:
|
||||
A test upload component with props function.
|
||||
"""
|
||||
|
||||
def upload_component_with_props():
|
||||
return rx.upload(
|
||||
rx.button("select file"),
|
||||
rx.text("Drag and drop files here or click to select files"),
|
||||
border="1px dotted black",
|
||||
no_drag=True,
|
||||
max_files=2,
|
||||
)
|
||||
|
||||
return upload_component_with_props()
|
||||
|
||||
|
||||
def test_upload_root_component_render(upload_root_component):
|
||||
"""Test that the render function is set correctly.
|
||||
|
||||
Args:
|
||||
upload_root_component: component fixture
|
||||
"""
|
||||
upload = upload_root_component.render()
|
||||
|
||||
# upload
|
||||
assert upload["name"] == "ReactDropzone"
|
||||
assert upload["props"] == [
|
||||
'id={"default"}',
|
||||
"multiple={true}",
|
||||
"onDrop={e => setFilesById(filesById => {\n"
|
||||
" const updatedFilesById = Object.assign({}, filesById);\n"
|
||||
' updatedFilesById["default"] = e;\n'
|
||||
" return updatedFilesById;\n"
|
||||
" })\n"
|
||||
" }",
|
||||
"ref={ref_default}",
|
||||
]
|
||||
assert upload["args"] == ("getRootProps", "getInputProps")
|
||||
|
||||
# box inside of upload
|
||||
[box] = upload["children"]
|
||||
assert box["name"] == "RadixThemesBox"
|
||||
assert box["props"] == [
|
||||
'className={"rx-Upload"}',
|
||||
'css={({ ["border"] : "1px dotted black" })}',
|
||||
"{...getRootProps()}",
|
||||
]
|
||||
|
||||
# input, button and text inside of box
|
||||
[input, button, text] = box["children"]
|
||||
assert input["name"] == "input"
|
||||
assert input["props"] == ['type={"file"}', "{...getInputProps()}"]
|
||||
|
||||
assert button["name"] == "RadixThemesButton"
|
||||
assert button["children"][0]["contents"] == '{"select file"}'
|
||||
|
||||
assert text["name"] == "RadixThemesText"
|
||||
assert (
|
||||
text["children"][0]["contents"]
|
||||
== '{"Drag and drop files here or click to select files"}'
|
||||
)
|
||||
|
||||
|
||||
def test_upload_component_render(upload_component):
|
||||
"""Test that the render function is set correctly.
|
||||
|
||||
Args:
|
||||
upload_component: component fixture
|
||||
"""
|
||||
upload = upload_component.render()
|
||||
|
||||
# upload
|
||||
assert upload["name"] == "ReactDropzone"
|
||||
assert upload["props"] == [
|
||||
'id={"default"}',
|
||||
"multiple={true}",
|
||||
"onDrop={e => setFilesById(filesById => {\n"
|
||||
" const updatedFilesById = Object.assign({}, filesById);\n"
|
||||
' updatedFilesById["default"] = e;\n'
|
||||
" return updatedFilesById;\n"
|
||||
" })\n"
|
||||
" }",
|
||||
"ref={ref_default}",
|
||||
]
|
||||
assert upload["args"] == ("getRootProps", "getInputProps")
|
||||
|
||||
# box inside of upload
|
||||
[box] = upload["children"]
|
||||
assert box["name"] == "RadixThemesBox"
|
||||
assert box["props"] == [
|
||||
'className={"rx-Upload"}',
|
||||
'css={({ ["border"] : "1px dotted black", ["padding"] : "5em", ["textAlign"] : "center" })}',
|
||||
"{...getRootProps()}",
|
||||
]
|
||||
|
||||
# input, button and text inside of box
|
||||
[input, button, text] = box["children"]
|
||||
assert input["name"] == "input"
|
||||
assert input["props"] == ['type={"file"}', "{...getInputProps()}"]
|
||||
|
||||
assert button["name"] == "RadixThemesButton"
|
||||
assert button["children"][0]["contents"] == '{"select file"}'
|
||||
|
||||
assert text["name"] == "RadixThemesText"
|
||||
assert (
|
||||
text["children"][0]["contents"]
|
||||
== '{"Drag and drop files here or click to select files"}'
|
||||
)
|
||||
|
||||
|
||||
def test_upload_component_with_props_render(upload_component_with_props):
|
||||
"""Test that the render function is set correctly.
|
||||
|
||||
Args:
|
||||
upload_component_with_props: component fixture
|
||||
"""
|
||||
upload = upload_component_with_props.render()
|
||||
|
||||
assert upload["props"] == [
|
||||
'id={"default"}',
|
||||
"maxFiles={2}",
|
||||
"multiple={true}",
|
||||
"noDrag={true}",
|
||||
"onDrop={e => setFilesById(filesById => {\n"
|
||||
" const updatedFilesById = Object.assign({}, filesById);\n"
|
||||
' updatedFilesById["default"] = e;\n'
|
||||
" return updatedFilesById;\n"
|
||||
" })\n"
|
||||
" }",
|
||||
"ref={ref_default}",
|
||||
]
|
||||
|
||||
|
||||
def test_upload_component_id_with_special_chars(upload_component_id_special):
|
||||
upload = upload_component_id_special.render()
|
||||
|
||||
assert upload["props"] == [
|
||||
r'id={"#spec!`al-_98ID"}',
|
||||
"multiple={true}",
|
||||
"onDrop={e => setFilesById(filesById => {\n"
|
||||
" const updatedFilesById = Object.assign({}, filesById);\n"
|
||||
' updatedFilesById["#spec!`al-_98ID"] = e;\n'
|
||||
" return updatedFilesById;\n"
|
||||
" })\n"
|
||||
" }",
|
||||
"ref={ref__spec_al__98ID}",
|
||||
]
|
@ -667,21 +667,18 @@ def test_component_create_unallowed_types(children, test_component):
|
||||
"name": "Fragment",
|
||||
"props": [],
|
||||
"contents": "",
|
||||
"args": None,
|
||||
"special_props": [],
|
||||
"children": [
|
||||
{
|
||||
"name": "RadixThemesText",
|
||||
"props": ['as={"p"}'],
|
||||
"contents": "",
|
||||
"args": None,
|
||||
"special_props": [],
|
||||
"children": [
|
||||
{
|
||||
"name": "",
|
||||
"props": [],
|
||||
"contents": '{"first_text"}',
|
||||
"args": None,
|
||||
"special_props": [],
|
||||
"children": [],
|
||||
"autofocus": False,
|
||||
@ -696,15 +693,12 @@ def test_component_create_unallowed_types(children, test_component):
|
||||
(
|
||||
(rx.text("first_text"), rx.text("second_text")),
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [],
|
||||
"contents": '{"first_text"}',
|
||||
@ -719,11 +713,9 @@ def test_component_create_unallowed_types(children, test_component):
|
||||
"special_props": [],
|
||||
},
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [],
|
||||
"contents": '{"second_text"}',
|
||||
@ -747,15 +739,12 @@ def test_component_create_unallowed_types(children, test_component):
|
||||
(
|
||||
(rx.text("first_text"), rx.box((rx.text("second_text"),))),
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [],
|
||||
"contents": '{"first_text"}',
|
||||
@ -770,19 +759,15 @@ def test_component_create_unallowed_types(children, test_component):
|
||||
"special_props": [],
|
||||
},
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [
|
||||
{
|
||||
"args": None,
|
||||
"autofocus": False,
|
||||
"children": [],
|
||||
"contents": '{"second_text"}',
|
||||
@ -1158,10 +1143,10 @@ def test_component_with_only_valid_children(fixture, request):
|
||||
@pytest.mark.parametrize(
|
||||
"component,rendered",
|
||||
[
|
||||
(rx.text("hi"), '<RadixThemesText as={"p"}>\n {"hi"}\n</RadixThemesText>'),
|
||||
(rx.text("hi"), '<RadixThemesText as={"p"}>\n\n{"hi"}\n</RadixThemesText>'),
|
||||
(
|
||||
rx.box(rx.heading("test", size="3")),
|
||||
'<RadixThemesBox>\n <RadixThemesHeading size={"3"}>\n {"test"}\n</RadixThemesHeading>\n</RadixThemesBox>',
|
||||
'<RadixThemesBox>\n\n<RadixThemesHeading size={"3"}>\n\n{"test"}\n</RadixThemesHeading>\n</RadixThemesBox>',
|
||||
),
|
||||
],
|
||||
)
|
||||
|
@ -71,7 +71,7 @@ class FileUploadState(State):
|
||||
assert file.filename is not None
|
||||
self.img_list.append(file.filename)
|
||||
|
||||
@rx.background
|
||||
@rx.event(background=True)
|
||||
async def bg_upload(self, files: List[rx.UploadFile]):
|
||||
"""Background task cannot be upload handler.
|
||||
|
||||
@ -119,7 +119,7 @@ class ChildFileUploadState(FileStateBase1):
|
||||
assert file.filename is not None
|
||||
self.img_list.append(file.filename)
|
||||
|
||||
@rx.background
|
||||
@rx.event(background=True)
|
||||
async def bg_upload(self, files: List[rx.UploadFile]):
|
||||
"""Background task cannot be upload handler.
|
||||
|
||||
@ -167,7 +167,7 @@ class GrandChildFileUploadState(FileStateBase2):
|
||||
assert file.filename is not None
|
||||
self.img_list.append(file.filename)
|
||||
|
||||
@rx.background
|
||||
@rx.event(background=True)
|
||||
async def bg_upload(self, files: List[rx.UploadFile]):
|
||||
"""Background task cannot be upload handler.
|
||||
|
||||
|
@ -874,7 +874,7 @@ async def test_upload_file_background(state, tmp_path, token):
|
||||
await fn(request_mock, [file_mock])
|
||||
assert (
|
||||
err.value.args[0]
|
||||
== f"@rx.background is not supported for upload handler `{state.get_full_name()}.bg_upload`."
|
||||
== f"@rx.event(background=True) is not supported for upload handler `{state.get_full_name()}.bg_upload`."
|
||||
)
|
||||
|
||||
if isinstance(app.state_manager, StateManagerRedis):
|
||||
@ -1211,7 +1211,7 @@ async def test_process_events(mocker, token: str):
|
||||
],
|
||||
)
|
||||
def test_overlay_component(
|
||||
state: State | None,
|
||||
state: Type[State] | None,
|
||||
overlay_component: Component | ComponentCallable | None,
|
||||
exp_page_child: Type[Component] | None,
|
||||
):
|
||||
@ -1403,13 +1403,6 @@ def test_app_state_determination():
|
||||
assert a4.state is not None
|
||||
|
||||
|
||||
# for coverage
|
||||
def test_raise_on_connect_error():
|
||||
"""Test that the connect_error function is called."""
|
||||
with pytest.raises(ValueError):
|
||||
App(connect_error_component="Foo")
|
||||
|
||||
|
||||
def test_raise_on_state():
|
||||
"""Test that the state is set."""
|
||||
# state kwargs is deprecated, we just make sure the app is created anyway.
|
||||
|
@ -7,8 +7,13 @@ import pytest
|
||||
|
||||
import reflex as rx
|
||||
import reflex.config
|
||||
from reflex.config import environment
|
||||
from reflex.constants import Endpoint
|
||||
from reflex.config import (
|
||||
environment,
|
||||
interpret_boolean_env,
|
||||
interpret_enum_env,
|
||||
interpret_int_env,
|
||||
)
|
||||
from reflex.constants import Endpoint, Env
|
||||
|
||||
|
||||
def test_requires_app_name():
|
||||
@ -208,11 +213,11 @@ def test_replace_defaults(
|
||||
assert getattr(c, key) == value
|
||||
|
||||
|
||||
def reflex_dir_constant():
|
||||
def reflex_dir_constant() -> Path:
|
||||
return environment.REFLEX_DIR
|
||||
|
||||
|
||||
def test_reflex_dir_env_var(monkeypatch, tmp_path):
|
||||
def test_reflex_dir_env_var(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
"""Test that the REFLEX_DIR environment variable is used to set the Reflex.DIR constant.
|
||||
|
||||
Args:
|
||||
@ -224,3 +229,16 @@ def test_reflex_dir_env_var(monkeypatch, tmp_path):
|
||||
mp_ctx = multiprocessing.get_context(method="spawn")
|
||||
with mp_ctx.Pool(processes=1) as pool:
|
||||
assert pool.apply(reflex_dir_constant) == tmp_path
|
||||
|
||||
|
||||
def test_interpret_enum_env() -> None:
|
||||
assert interpret_enum_env(Env.PROD.value, Env, "REFLEX_ENV") == Env.PROD
|
||||
|
||||
|
||||
def test_interpret_int_env() -> None:
|
||||
assert interpret_int_env("3001", "FRONTEND_PORT") == 3001
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value, expected", [("true", True), ("false", False)])
|
||||
def test_interpret_bool_env(value: str, expected: bool) -> None:
|
||||
assert interpret_boolean_env(value, "TELEMETRY_ENABLED") == expected
|
||||
|
@ -24,7 +24,15 @@ from reflex.utils.prerequisites import (
|
||||
app_name="test",
|
||||
),
|
||||
False,
|
||||
'module.exports = {basePath: "", compress: true, reactStrictMode: true, trailingSlash: true};',
|
||||
'module.exports = {basePath: "", compress: true, reactStrictMode: true, trailingSlash: true, staticPageGenerationTimeout: 60};',
|
||||
),
|
||||
(
|
||||
Config(
|
||||
app_name="test",
|
||||
static_page_generation_timeout=30,
|
||||
),
|
||||
False,
|
||||
'module.exports = {basePath: "", compress: true, reactStrictMode: true, trailingSlash: true, staticPageGenerationTimeout: 30};',
|
||||
),
|
||||
(
|
||||
Config(
|
||||
@ -32,7 +40,7 @@ from reflex.utils.prerequisites import (
|
||||
next_compression=False,
|
||||
),
|
||||
False,
|
||||
'module.exports = {basePath: "", compress: false, reactStrictMode: true, trailingSlash: true};',
|
||||
'module.exports = {basePath: "", compress: false, reactStrictMode: true, trailingSlash: true, staticPageGenerationTimeout: 60};',
|
||||
),
|
||||
(
|
||||
Config(
|
||||
@ -40,7 +48,7 @@ from reflex.utils.prerequisites import (
|
||||
frontend_path="/test",
|
||||
),
|
||||
False,
|
||||
'module.exports = {basePath: "/test", compress: true, reactStrictMode: true, trailingSlash: true};',
|
||||
'module.exports = {basePath: "/test", compress: true, reactStrictMode: true, trailingSlash: true, staticPageGenerationTimeout: 60};',
|
||||
),
|
||||
(
|
||||
Config(
|
||||
@ -49,14 +57,14 @@ from reflex.utils.prerequisites import (
|
||||
next_compression=False,
|
||||
),
|
||||
False,
|
||||
'module.exports = {basePath: "/test", compress: false, reactStrictMode: true, trailingSlash: true};',
|
||||
'module.exports = {basePath: "/test", compress: false, reactStrictMode: true, trailingSlash: true, staticPageGenerationTimeout: 60};',
|
||||
),
|
||||
(
|
||||
Config(
|
||||
app_name="test",
|
||||
),
|
||||
True,
|
||||
'module.exports = {basePath: "", compress: true, reactStrictMode: true, trailingSlash: true, output: "export", distDir: "_static"};',
|
||||
'module.exports = {basePath: "", compress: true, reactStrictMode: true, trailingSlash: true, staticPageGenerationTimeout: 60, output: "export", distDir: "_static"};',
|
||||
),
|
||||
],
|
||||
)
|
||||
|
@ -8,6 +8,7 @@ import functools
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
from textwrap import dedent
|
||||
from typing import Any, AsyncGenerator, Callable, Dict, List, Optional, Union
|
||||
from unittest.mock import AsyncMock, Mock
|
||||
@ -1965,7 +1966,7 @@ class BackgroundTaskState(BaseState):
|
||||
"""
|
||||
return self.order
|
||||
|
||||
@rx.background
|
||||
@rx.event(background=True)
|
||||
async def background_task(self):
|
||||
"""A background task that updates the state."""
|
||||
async with self:
|
||||
@ -2002,7 +2003,7 @@ class BackgroundTaskState(BaseState):
|
||||
self.other() # direct calling event handlers works in context
|
||||
self._private_method()
|
||||
|
||||
@rx.background
|
||||
@rx.event(background=True)
|
||||
async def background_task_reset(self):
|
||||
"""A background task that resets the state."""
|
||||
with pytest.raises(ImmutableStateError):
|
||||
@ -2016,7 +2017,7 @@ class BackgroundTaskState(BaseState):
|
||||
async with self:
|
||||
self.order.append("reset")
|
||||
|
||||
@rx.background
|
||||
@rx.event(background=True)
|
||||
async def background_task_generator(self):
|
||||
"""A background task generator that does nothing.
|
||||
|
||||
@ -2724,6 +2725,7 @@ class OnLoadState(State):
|
||||
|
||||
num: int = 0
|
||||
|
||||
@rx.event
|
||||
def test_handler(self):
|
||||
"""Test handler."""
|
||||
self.num += 1
|
||||
@ -3390,9 +3392,15 @@ def test_fallback_pickle():
|
||||
assert unpickled_state._f() == 420
|
||||
assert unpickled_state._o._f() == 42
|
||||
|
||||
# Threading locks are unpicklable normally, and raise TypeError instead of PicklingError.
|
||||
state2 = DillState(_reflex_internal_init=True) # type: ignore
|
||||
state2._g = threading.Lock()
|
||||
pk2 = state2._serialize()
|
||||
unpickled_state2 = BaseState._deserialize(pk2)
|
||||
assert isinstance(unpickled_state2._g, type(threading.Lock()))
|
||||
|
||||
# Some object, like generator, are still unpicklable with dill.
|
||||
state._g = (i for i in range(10))
|
||||
pk = state._serialize()
|
||||
assert len(pk) == 0
|
||||
with pytest.raises(EOFError):
|
||||
BaseState._deserialize(pk)
|
||||
state3 = DillState(_reflex_internal_init=True) # type: ignore
|
||||
state3._g = (i for i in range(10))
|
||||
pk3 = state3._serialize()
|
||||
assert len(pk3) == 0
|
||||
|
Loading…
Reference in New Issue
Block a user