[REF-1368] Move common form functionality to rx.el.forms (#2801)
* [REF-1368] Move common form functionality to rx.el.forms Allow plain HTML Form element to have magic on_submit event handler. * Chakra and Radix forms inherit `on_submit` functionality from rx.el.form Consolidate logic in the basic HTML form and use it in both Radix and Chakra form wrappers. * from __future__ import annotations for py38
This commit is contained in:
parent
8903ebb8b0
commit
5d647a498f
@ -1,4 +1,5 @@
|
|||||||
"""Integration tests for forms."""
|
"""Integration tests for forms."""
|
||||||
|
import functools
|
||||||
import time
|
import time
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
|
||||||
@ -10,8 +11,12 @@ from reflex.testing import AppHarness
|
|||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
|
|
||||||
|
|
||||||
def FormSubmit():
|
def FormSubmit(form_component):
|
||||||
"""App with a form using on_submit."""
|
"""App with a form using on_submit.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
form_component: The str name of the form component to use.
|
||||||
|
"""
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class FormState(rx.State):
|
class FormState(rx.State):
|
||||||
@ -32,7 +37,7 @@ def FormSubmit():
|
|||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="token",
|
id="token",
|
||||||
),
|
),
|
||||||
rx.form.root(
|
eval(form_component)(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
rx.chakra.input(id="name_input"),
|
rx.chakra.input(id="name_input"),
|
||||||
rx.hstack(rx.chakra.pin_input(length=4, id="pin_input")),
|
rx.hstack(rx.chakra.pin_input(length=4, id="pin_input")),
|
||||||
@ -63,8 +68,12 @@ def FormSubmit():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def FormSubmitName():
|
def FormSubmitName(form_component):
|
||||||
"""App with a form using on_submit."""
|
"""App with a form using on_submit.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
form_component: The str name of the form component to use.
|
||||||
|
"""
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class FormState(rx.State):
|
class FormState(rx.State):
|
||||||
@ -85,7 +94,7 @@ def FormSubmitName():
|
|||||||
is_read_only=True,
|
is_read_only=True,
|
||||||
id="token",
|
id="token",
|
||||||
),
|
),
|
||||||
rx.form.root(
|
eval(form_component)(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
rx.chakra.input(name="name_input"),
|
rx.chakra.input(name="name_input"),
|
||||||
rx.hstack(rx.chakra.pin_input(length=4, name="pin_input")),
|
rx.hstack(rx.chakra.pin_input(length=4, name="pin_input")),
|
||||||
@ -128,7 +137,23 @@ def FormSubmitName():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(
|
@pytest.fixture(
|
||||||
scope="session", params=[FormSubmit, FormSubmitName], ids=["id", "name"]
|
scope="session",
|
||||||
|
params=[
|
||||||
|
functools.partial(FormSubmit, form_component="rx.form.root"),
|
||||||
|
functools.partial(FormSubmitName, form_component="rx.form.root"),
|
||||||
|
functools.partial(FormSubmit, form_component="rx.el.form"),
|
||||||
|
functools.partial(FormSubmitName, form_component="rx.el.form"),
|
||||||
|
functools.partial(FormSubmit, form_component="rx.chakra.form"),
|
||||||
|
functools.partial(FormSubmitName, form_component="rx.chakra.form"),
|
||||||
|
],
|
||||||
|
ids=[
|
||||||
|
"id-radix",
|
||||||
|
"name-radix",
|
||||||
|
"id-html",
|
||||||
|
"name-html",
|
||||||
|
"id-chakra",
|
||||||
|
"name-chakra",
|
||||||
|
],
|
||||||
)
|
)
|
||||||
def form_submit(request, tmp_path_factory) -> Generator[AppHarness, None, None]:
|
def form_submit(request, tmp_path_factory) -> Generator[AppHarness, None, None]:
|
||||||
"""Start FormSubmit app at tmp_path via AppHarness.
|
"""Start FormSubmit app at tmp_path via AppHarness.
|
||||||
@ -140,9 +165,11 @@ def form_submit(request, tmp_path_factory) -> Generator[AppHarness, None, None]:
|
|||||||
Yields:
|
Yields:
|
||||||
running AppHarness instance
|
running AppHarness instance
|
||||||
"""
|
"""
|
||||||
|
param_id = request._pyfuncitem.callspec.id.replace("-", "_")
|
||||||
with AppHarness.create(
|
with AppHarness.create(
|
||||||
root=tmp_path_factory.mktemp("form_submit"),
|
root=tmp_path_factory.mktemp("form_submit"),
|
||||||
app_source=request.param, # type: ignore
|
app_source=request.param, # type: ignore
|
||||||
|
app_name=request.param.func.__name__ + f"_{param_id}",
|
||||||
) as harness:
|
) as harness:
|
||||||
assert harness.app_instance is not None, "app is not running"
|
assert harness.app_instance is not None, "app is not running"
|
||||||
yield harness
|
yield harness
|
||||||
|
@ -1,39 +1,13 @@
|
|||||||
"""Form components."""
|
"""Form components."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from hashlib import md5
|
|
||||||
from typing import Any, Dict, Iterator
|
|
||||||
|
|
||||||
from jinja2 import Environment
|
|
||||||
|
|
||||||
from reflex.components.chakra import ChakraComponent
|
from reflex.components.chakra import ChakraComponent
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.components.tags import Tag
|
from reflex.components.el.elements.forms import Form as HTMLForm
|
||||||
from reflex.constants import Dirs, EventTriggers
|
from reflex.vars import Var
|
||||||
from reflex.event import EventChain
|
|
||||||
from reflex.utils import imports
|
|
||||||
from reflex.utils.format import format_event_chain, to_camel_case
|
|
||||||
from reflex.vars import BaseVar, Var
|
|
||||||
|
|
||||||
FORM_DATA = Var.create("form_data")
|
|
||||||
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
|
||||||
"""
|
|
||||||
const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {
|
|
||||||
const $form = ev.target
|
|
||||||
ev.preventDefault()
|
|
||||||
const {{ form_data }} = {...Object.fromEntries(new FormData($form).entries()), ...{{ field_ref_mapping }}}
|
|
||||||
|
|
||||||
{{ on_submit_event_chain }}
|
|
||||||
|
|
||||||
if ({{ reset_on_submit }}) {
|
|
||||||
$form.reset()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Form(ChakraComponent):
|
class Form(ChakraComponent, HTMLForm):
|
||||||
"""A form component."""
|
"""A form component."""
|
||||||
|
|
||||||
tag = "Box"
|
tag = "Box"
|
||||||
@ -41,112 +15,6 @@ class Form(ChakraComponent):
|
|||||||
# What the form renders to.
|
# What the form renders to.
|
||||||
as_: Var[str] = "form" # type: ignore
|
as_: Var[str] = "form" # type: ignore
|
||||||
|
|
||||||
# If true, the form will be cleared after submit.
|
|
||||||
reset_on_submit: Var[bool] = False # type: ignore
|
|
||||||
|
|
||||||
# The name used to make this form's submit handler function unique
|
|
||||||
handle_submit_unique_name: Var[str]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create(cls, *children, **props) -> Component:
|
|
||||||
"""Create a form component.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
*children: The children of the form.
|
|
||||||
**props: The properties of the form.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The form component.
|
|
||||||
"""
|
|
||||||
if "handle_submit_unique_name" in props:
|
|
||||||
return super().create(*children, **props)
|
|
||||||
|
|
||||||
# Render the form hooks and use the hash of the resulting code to create a unique name.
|
|
||||||
props["handle_submit_unique_name"] = ""
|
|
||||||
form = super().create(*children, **props)
|
|
||||||
code_hash = md5(str(form.get_hooks()).encode("utf-8")).hexdigest()
|
|
||||||
form.handle_submit_unique_name = code_hash
|
|
||||||
return form
|
|
||||||
|
|
||||||
def _get_imports(self) -> imports.ImportDict:
|
|
||||||
return imports.merge_imports(
|
|
||||||
super()._get_imports(),
|
|
||||||
{
|
|
||||||
"react": {imports.ImportVar(tag="useCallback")},
|
|
||||||
f"/{Dirs.STATE_PATH}": {
|
|
||||||
imports.ImportVar(tag="getRefValue"),
|
|
||||||
imports.ImportVar(tag="getRefValues"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
def _get_hooks(self) -> str | None:
|
|
||||||
if EventTriggers.ON_SUBMIT not in self.event_triggers:
|
|
||||||
return
|
|
||||||
return HANDLE_SUBMIT_JS_JINJA2.render(
|
|
||||||
handle_submit_unique_name=self.handle_submit_unique_name,
|
|
||||||
form_data=FORM_DATA,
|
|
||||||
field_ref_mapping=str(Var.create_safe(self._get_form_refs())),
|
|
||||||
on_submit_event_chain=format_event_chain(
|
|
||||||
self.event_triggers[EventTriggers.ON_SUBMIT]
|
|
||||||
),
|
|
||||||
reset_on_submit=self.reset_on_submit,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _render(self) -> Tag:
|
|
||||||
render_tag = (
|
|
||||||
super()
|
|
||||||
._render()
|
|
||||||
.remove_props(
|
|
||||||
"reset_on_submit",
|
|
||||||
"handle_submit_unique_name",
|
|
||||||
to_camel_case(EventTriggers.ON_SUBMIT),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if EventTriggers.ON_SUBMIT in self.event_triggers:
|
|
||||||
render_tag.add_props(
|
|
||||||
**{
|
|
||||||
EventTriggers.ON_SUBMIT: BaseVar(
|
|
||||||
_var_name=f"handleSubmit_{self.handle_submit_unique_name}",
|
|
||||||
_var_type=EventChain,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return render_tag
|
|
||||||
|
|
||||||
def _get_form_refs(self) -> Dict[str, Any]:
|
|
||||||
# Send all the input refs to the handler.
|
|
||||||
form_refs = {}
|
|
||||||
for ref in self.get_refs():
|
|
||||||
# when ref start with refs_ it's an array of refs, so we need different method
|
|
||||||
# to collect data
|
|
||||||
if ref.startswith("refs_"):
|
|
||||||
ref_var = Var.create_safe(ref[:-3]).as_ref()
|
|
||||||
form_refs[ref[5:-3]] = Var.create_safe(
|
|
||||||
f"getRefValues({str(ref_var)})", _var_is_local=False
|
|
||||||
)._replace(merge_var_data=ref_var._var_data)
|
|
||||||
else:
|
|
||||||
ref_var = Var.create_safe(ref).as_ref()
|
|
||||||
form_refs[ref[4:]] = Var.create_safe(
|
|
||||||
f"getRefValue({str(ref_var)})", _var_is_local=False
|
|
||||||
)._replace(merge_var_data=ref_var._var_data)
|
|
||||||
return form_refs
|
|
||||||
|
|
||||||
def get_event_triggers(self) -> Dict[str, Any]:
|
|
||||||
"""Get the event triggers that pass the component's value to the handler.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A dict mapping the event trigger to the var that is passed to the handler.
|
|
||||||
"""
|
|
||||||
return {
|
|
||||||
**super().get_event_triggers(),
|
|
||||||
EventTriggers.ON_SUBMIT: lambda e0: [FORM_DATA],
|
|
||||||
}
|
|
||||||
|
|
||||||
def _get_vars(self) -> Iterator[Var]:
|
|
||||||
yield from super()._get_vars()
|
|
||||||
yield from self._get_form_refs().values()
|
|
||||||
|
|
||||||
|
|
||||||
class FormControl(ChakraComponent):
|
class FormControl(ChakraComponent):
|
||||||
"""Provide context to form components."""
|
"""Provide context to form components."""
|
||||||
|
@ -7,32 +7,85 @@ from typing import Any, Dict, Literal, Optional, Union, overload
|
|||||||
from reflex.vars import Var, BaseVar, ComputedVar
|
from reflex.vars import Var, BaseVar, ComputedVar
|
||||||
from reflex.event import EventChain, EventHandler, EventSpec
|
from reflex.event import EventChain, EventHandler, EventSpec
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
from hashlib import md5
|
|
||||||
from typing import Any, Dict, Iterator
|
|
||||||
from jinja2 import Environment
|
|
||||||
from reflex.components.chakra import ChakraComponent
|
from reflex.components.chakra import ChakraComponent
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.components.tags import Tag
|
from reflex.components.el.elements.forms import Form as HTMLForm
|
||||||
from reflex.constants import Dirs, EventTriggers
|
from reflex.vars import Var
|
||||||
from reflex.event import EventChain
|
|
||||||
from reflex.utils import imports
|
|
||||||
from reflex.utils.format import format_event_chain, to_camel_case
|
|
||||||
from reflex.vars import BaseVar, Var
|
|
||||||
|
|
||||||
FORM_DATA = Var.create("form_data")
|
class Form(ChakraComponent, HTMLForm):
|
||||||
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
|
||||||
"\n const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {\n const $form = ev.target\n ev.preventDefault()\n const {{ form_data }} = {...Object.fromEntries(new FormData($form).entries()), ...{{ field_ref_mapping }}}\n\n {{ on_submit_event_chain }}\n\n if ({{ reset_on_submit }}) {\n $form.reset()\n }\n })\n "
|
|
||||||
)
|
|
||||||
|
|
||||||
class Form(ChakraComponent):
|
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@classmethod
|
||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
as_: Optional[Union[Var[str], str]] = None,
|
as_: Optional[Union[Var[str], str]] = None,
|
||||||
|
accept: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
accept_charset: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
action: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
auto_complete: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
enc_type: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
method: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
name: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
no_validate: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
target: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
||||||
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
||||||
|
access_key: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
auto_capitalize: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
content_editable: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
context_menu: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
dir: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
draggable: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
enter_key_hint: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
hidden: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
input_mode: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
item_prop: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
lang: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
role: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
slot: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
spell_check: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
tab_index: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
title: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
style: Optional[Style] = None,
|
style: Optional[Style] = None,
|
||||||
key: Optional[Any] = None,
|
key: Optional[Any] = None,
|
||||||
id: Optional[Any] = None,
|
id: Optional[Any] = None,
|
||||||
@ -94,8 +147,33 @@ class Form(ChakraComponent):
|
|||||||
Args:
|
Args:
|
||||||
*children: The children of the form.
|
*children: The children of the form.
|
||||||
as_: What the form renders to.
|
as_: What the form renders to.
|
||||||
|
accept: MIME types the server accepts for file upload
|
||||||
|
accept_charset: Character encodings to be used for form submission
|
||||||
|
action: URL where the form's data should be submitted
|
||||||
|
auto_complete: Whether the form should have autocomplete enabled
|
||||||
|
enc_type: Encoding type for the form data when submitted
|
||||||
|
method: HTTP method to use for form submission
|
||||||
|
name: Name of the form
|
||||||
|
no_validate: Indicates that the form should not be validated on submit
|
||||||
|
target: Where to display the response after submitting the form
|
||||||
reset_on_submit: If true, the form will be cleared after submit.
|
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
|
handle_submit_unique_name: The name used to make this form's submit handler function unique.
|
||||||
|
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.
|
||||||
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
||||||
|
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
||||||
|
draggable: Defines whether the element can be dragged.
|
||||||
|
enter_key_hint: Hints what media types the media element is able to play.
|
||||||
|
hidden: Defines whether the element is hidden.
|
||||||
|
input_mode: Defines the type of the element.
|
||||||
|
item_prop: Defines the name of the element for metadata purposes.
|
||||||
|
lang: Defines the language used in the element.
|
||||||
|
role: Defines the role of the element.
|
||||||
|
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
||||||
|
spell_check: Defines whether the element may be checked for spelling errors.
|
||||||
|
tab_index: Defines the position of the current element in the tabbing order.
|
||||||
|
title: Defines a tooltip for the element.
|
||||||
style: The style of the component.
|
style: The style of the component.
|
||||||
key: A unique key for the component.
|
key: A unique key for the component.
|
||||||
id: The id for the component.
|
id: The id for the component.
|
||||||
@ -108,7 +186,6 @@ class Form(ChakraComponent):
|
|||||||
The form component.
|
The form component.
|
||||||
"""
|
"""
|
||||||
...
|
...
|
||||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
|
||||||
|
|
||||||
class FormControl(ChakraComponent):
|
class FormControl(ChakraComponent):
|
||||||
@overload
|
@overload
|
||||||
|
@ -1,12 +1,38 @@
|
|||||||
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py."""
|
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py."""
|
||||||
from typing import Any, Dict, Union
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from hashlib import md5
|
||||||
|
from typing import Any, Dict, Iterator, Union
|
||||||
|
|
||||||
|
from jinja2 import Environment
|
||||||
|
|
||||||
from reflex.components.el.element import Element
|
from reflex.components.el.element import Element
|
||||||
from reflex.constants.event import EventTriggers
|
from reflex.components.tags.tag import Tag
|
||||||
from reflex.vars import Var
|
from reflex.constants import Dirs, EventTriggers
|
||||||
|
from reflex.event import EventChain
|
||||||
|
from reflex.utils import imports
|
||||||
|
from reflex.utils.format import format_event_chain
|
||||||
|
from reflex.vars import BaseVar, Var
|
||||||
|
|
||||||
from .base import BaseHTML
|
from .base import BaseHTML
|
||||||
|
|
||||||
|
FORM_DATA = Var.create("form_data")
|
||||||
|
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
||||||
|
"""
|
||||||
|
const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {
|
||||||
|
const $form = ev.target
|
||||||
|
ev.preventDefault()
|
||||||
|
const {{ form_data }} = {...Object.fromEntries(new FormData($form).entries()), ...{{ field_ref_mapping }}}
|
||||||
|
|
||||||
|
{{ on_submit_event_chain }}
|
||||||
|
|
||||||
|
if ({{ reset_on_submit }}) {
|
||||||
|
$form.reset()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Button(BaseHTML):
|
class Button(BaseHTML):
|
||||||
"""Display the button element."""
|
"""Display the button element."""
|
||||||
@ -101,6 +127,111 @@ class Form(BaseHTML):
|
|||||||
# Where to display the response after submitting the form
|
# Where to display the response after submitting the form
|
||||||
target: Var[Union[str, int, bool]]
|
target: Var[Union[str, int, bool]]
|
||||||
|
|
||||||
|
# If true, the form will be cleared after submit.
|
||||||
|
reset_on_submit: Var[bool] = False # type: ignore
|
||||||
|
|
||||||
|
# The name used to make this form's submit handler function unique.
|
||||||
|
handle_submit_unique_name: Var[str]
|
||||||
|
|
||||||
|
def get_event_triggers(self) -> Dict[str, Any]:
|
||||||
|
"""Event triggers for radix form root.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The triggers for event supported by Root.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
**super().get_event_triggers(),
|
||||||
|
EventTriggers.ON_SUBMIT: lambda e0: [FORM_DATA],
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, *children, **props):
|
||||||
|
"""Create a form component.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*children: The children of the form.
|
||||||
|
**props: The properties of the form.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The form component.
|
||||||
|
"""
|
||||||
|
if "handle_submit_unique_name" in props:
|
||||||
|
return super().create(*children, **props)
|
||||||
|
|
||||||
|
# Render the form hooks and use the hash of the resulting code to create a unique name.
|
||||||
|
props["handle_submit_unique_name"] = ""
|
||||||
|
form = super().create(*children, **props)
|
||||||
|
form.handle_submit_unique_name = md5(
|
||||||
|
str(form.get_hooks()).encode("utf-8")
|
||||||
|
).hexdigest()
|
||||||
|
return form
|
||||||
|
|
||||||
|
def _get_imports(self) -> imports.ImportDict:
|
||||||
|
return imports.merge_imports(
|
||||||
|
super()._get_imports(),
|
||||||
|
{
|
||||||
|
"react": {imports.ImportVar(tag="useCallback")},
|
||||||
|
f"/{Dirs.STATE_PATH}": {
|
||||||
|
imports.ImportVar(tag="getRefValue"),
|
||||||
|
imports.ImportVar(tag="getRefValues"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_hooks(self) -> str | None:
|
||||||
|
if EventTriggers.ON_SUBMIT not in self.event_triggers:
|
||||||
|
return
|
||||||
|
return HANDLE_SUBMIT_JS_JINJA2.render(
|
||||||
|
handle_submit_unique_name=self.handle_submit_unique_name,
|
||||||
|
form_data=FORM_DATA,
|
||||||
|
field_ref_mapping=str(Var.create_safe(self._get_form_refs())),
|
||||||
|
on_submit_event_chain=format_event_chain(
|
||||||
|
self.event_triggers[EventTriggers.ON_SUBMIT]
|
||||||
|
),
|
||||||
|
reset_on_submit=self.reset_on_submit,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _render(self) -> Tag:
|
||||||
|
render_tag = super()._render()
|
||||||
|
if EventTriggers.ON_SUBMIT in self.event_triggers:
|
||||||
|
render_tag.add_props(
|
||||||
|
**{
|
||||||
|
EventTriggers.ON_SUBMIT: BaseVar(
|
||||||
|
_var_name=f"handleSubmit_{self.handle_submit_unique_name}",
|
||||||
|
_var_type=EventChain,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return render_tag
|
||||||
|
|
||||||
|
def _get_form_refs(self) -> Dict[str, Any]:
|
||||||
|
# Send all the input refs to the handler.
|
||||||
|
form_refs = {}
|
||||||
|
for ref in self.get_refs():
|
||||||
|
# when ref start with refs_ it's an array of refs, so we need different method
|
||||||
|
# to collect data
|
||||||
|
if ref.startswith("refs_"):
|
||||||
|
ref_var = Var.create_safe(ref[:-3]).as_ref()
|
||||||
|
form_refs[ref[5:-3]] = Var.create_safe(
|
||||||
|
f"getRefValues({str(ref_var)})", _var_is_local=False
|
||||||
|
)._replace(merge_var_data=ref_var._var_data)
|
||||||
|
else:
|
||||||
|
ref_var = Var.create_safe(ref).as_ref()
|
||||||
|
form_refs[ref[4:]] = Var.create_safe(
|
||||||
|
f"getRefValue({str(ref_var)})", _var_is_local=False
|
||||||
|
)._replace(merge_var_data=ref_var._var_data)
|
||||||
|
return form_refs
|
||||||
|
|
||||||
|
def _get_vars(self) -> Iterator[Var]:
|
||||||
|
yield from super()._get_vars()
|
||||||
|
yield from self._get_form_refs().values()
|
||||||
|
|
||||||
|
def _exclude_props(self) -> list[str]:
|
||||||
|
return super()._exclude_props() + [
|
||||||
|
"reset_on_submit",
|
||||||
|
"handle_submit_unique_name",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class Input(BaseHTML):
|
class Input(BaseHTML):
|
||||||
"""Display the input element."""
|
"""Display the input element."""
|
||||||
|
@ -7,12 +7,23 @@ from typing import Any, Dict, Literal, Optional, Union, overload
|
|||||||
from reflex.vars import Var, BaseVar, ComputedVar
|
from reflex.vars import Var, BaseVar, ComputedVar
|
||||||
from reflex.event import EventChain, EventHandler, EventSpec
|
from reflex.event import EventChain, EventHandler, EventSpec
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
from typing import Any, Dict, Union
|
from hashlib import md5
|
||||||
|
from typing import Any, Dict, Iterator, Union
|
||||||
|
from jinja2 import Environment
|
||||||
from reflex.components.el.element import Element
|
from reflex.components.el.element import Element
|
||||||
from reflex.constants.event import EventTriggers
|
from reflex.components.tags.tag import Tag
|
||||||
from reflex.vars import Var
|
from reflex.constants import Dirs, EventTriggers
|
||||||
|
from reflex.event import EventChain
|
||||||
|
from reflex.utils import imports
|
||||||
|
from reflex.utils.format import format_event_chain
|
||||||
|
from reflex.vars import BaseVar, Var
|
||||||
from .base import BaseHTML
|
from .base import BaseHTML
|
||||||
|
|
||||||
|
FORM_DATA = Var.create("form_data")
|
||||||
|
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
||||||
|
"\n const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {\n const $form = ev.target\n ev.preventDefault()\n const {{ form_data }} = {...Object.fromEntries(new FormData($form).entries()), ...{{ field_ref_mapping }}}\n\n {{ on_submit_event_chain }}\n\n if ({{ reset_on_submit }}) {\n $form.reset()\n }\n })\n "
|
||||||
|
)
|
||||||
|
|
||||||
class Button(BaseHTML):
|
class Button(BaseHTML):
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -407,6 +418,7 @@ class Fieldset(Element):
|
|||||||
...
|
...
|
||||||
|
|
||||||
class Form(BaseHTML):
|
class Form(BaseHTML):
|
||||||
|
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@classmethod
|
||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
@ -437,6 +449,8 @@ class Form(BaseHTML):
|
|||||||
target: Optional[
|
target: Optional[
|
||||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
] = None,
|
] = None,
|
||||||
|
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
||||||
|
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
||||||
access_key: Optional[
|
access_key: Optional[
|
||||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
] = None,
|
] = None,
|
||||||
@ -525,15 +539,18 @@ class Form(BaseHTML):
|
|||||||
on_scroll: Optional[
|
on_scroll: Optional[
|
||||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||||
] = None,
|
] = None,
|
||||||
|
on_submit: Optional[
|
||||||
|
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||||
|
] = None,
|
||||||
on_unmount: Optional[
|
on_unmount: Optional[
|
||||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||||
] = None,
|
] = None,
|
||||||
**props
|
**props
|
||||||
) -> "Form":
|
) -> "Form":
|
||||||
"""Create the component.
|
"""Create a form component.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*children: The children of the component.
|
*children: The children of the form.
|
||||||
accept: MIME types the server accepts for file upload
|
accept: MIME types the server accepts for file upload
|
||||||
accept_charset: Character encodings to be used for form submission
|
accept_charset: Character encodings to be used for form submission
|
||||||
action: URL where the form's data should be submitted
|
action: URL where the form's data should be submitted
|
||||||
@ -543,6 +560,8 @@ class Form(BaseHTML):
|
|||||||
name: Name of the form
|
name: Name of the form
|
||||||
no_validate: Indicates that the form should not be validated on submit
|
no_validate: Indicates that the form should not be validated on submit
|
||||||
target: Where to display the response after submitting the form
|
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.
|
||||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
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.
|
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.
|
content_editable: Indicates whether the element's content is editable.
|
||||||
@ -565,13 +584,10 @@ class Form(BaseHTML):
|
|||||||
class_name: The class name for the component.
|
class_name: The class name for the component.
|
||||||
autofocus: Whether the component should take the focus once the page is loaded
|
autofocus: Whether the component should take the focus once the page is loaded
|
||||||
custom_attrs: custom attribute
|
custom_attrs: custom attribute
|
||||||
**props: The props of the component.
|
**props: The properties of the form.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The component.
|
The form component.
|
||||||
|
|
||||||
Raises:
|
|
||||||
TypeError: If an invalid child is passed.
|
|
||||||
"""
|
"""
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -2,40 +2,16 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from hashlib import md5
|
from typing import Any, Dict, Literal
|
||||||
from typing import Any, Dict, Iterator, Literal
|
|
||||||
|
|
||||||
from jinja2 import Environment
|
|
||||||
|
|
||||||
from reflex.components.component import Component, ComponentNamespace
|
from reflex.components.component import Component, ComponentNamespace
|
||||||
|
from reflex.components.el.elements.forms import Form as HTMLForm
|
||||||
from reflex.components.radix.themes.components.text_field import TextFieldInput
|
from reflex.components.radix.themes.components.text_field import TextFieldInput
|
||||||
from reflex.components.tags.tag import Tag
|
|
||||||
from reflex.constants.base import Dirs
|
|
||||||
from reflex.constants.event import EventTriggers
|
from reflex.constants.event import EventTriggers
|
||||||
from reflex.event import EventChain
|
from reflex.vars import Var
|
||||||
from reflex.utils import imports
|
|
||||||
from reflex.utils.format import format_event_chain, to_camel_case
|
|
||||||
from reflex.vars import BaseVar, Var
|
|
||||||
|
|
||||||
from .base import RadixPrimitiveComponentWithClassName
|
from .base import RadixPrimitiveComponentWithClassName
|
||||||
|
|
||||||
FORM_DATA = Var.create("form_data")
|
|
||||||
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
|
||||||
"""
|
|
||||||
const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {
|
|
||||||
const $form = ev.target
|
|
||||||
ev.preventDefault()
|
|
||||||
const {{ form_data }} = {...Object.fromEntries(new FormData($form).entries()), ...{{ field_ref_mapping }}}
|
|
||||||
|
|
||||||
{{ on_submit_event_chain }}
|
|
||||||
|
|
||||||
if ({{ reset_on_submit }}) {
|
|
||||||
$form.reset()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class FormComponent(RadixPrimitiveComponentWithClassName):
|
class FormComponent(RadixPrimitiveComponentWithClassName):
|
||||||
"""Base class for all @radix-ui/react-form components."""
|
"""Base class for all @radix-ui/react-form components."""
|
||||||
@ -43,19 +19,13 @@ class FormComponent(RadixPrimitiveComponentWithClassName):
|
|||||||
library = "@radix-ui/react-form@^0.0.3"
|
library = "@radix-ui/react-form@^0.0.3"
|
||||||
|
|
||||||
|
|
||||||
class FormRoot(FormComponent):
|
class FormRoot(FormComponent, HTMLForm):
|
||||||
"""The root component of a radix form."""
|
"""The root component of a radix form."""
|
||||||
|
|
||||||
tag = "Root"
|
tag = "Root"
|
||||||
|
|
||||||
alias = "RadixFormRoot"
|
alias = "RadixFormRoot"
|
||||||
|
|
||||||
# If true, the form will be cleared after submit.
|
|
||||||
reset_on_submit: Var[bool] = False # type: ignore
|
|
||||||
|
|
||||||
# The name used to make this form's submit handler function unique.
|
|
||||||
handle_submit_unique_name: Var[str]
|
|
||||||
|
|
||||||
def get_event_triggers(self) -> Dict[str, Any]:
|
def get_event_triggers(self) -> Dict[str, Any]:
|
||||||
"""Event triggers for radix form root.
|
"""Event triggers for radix form root.
|
||||||
|
|
||||||
@ -64,106 +34,15 @@ class FormRoot(FormComponent):
|
|||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
**super().get_event_triggers(),
|
**super().get_event_triggers(),
|
||||||
EventTriggers.ON_SUBMIT: lambda e0: [FORM_DATA],
|
|
||||||
EventTriggers.ON_CLEAR_SERVER_ERRORS: lambda: [],
|
EventTriggers.ON_CLEAR_SERVER_ERRORS: lambda: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create(cls, *children, **props):
|
|
||||||
"""Create a form component.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
*children: The children of the form.
|
|
||||||
**props: The properties of the form.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The form component.
|
|
||||||
"""
|
|
||||||
if "handle_submit_unique_name" in props:
|
|
||||||
return super().create(*children, **props)
|
|
||||||
|
|
||||||
# Render the form hooks and use the hash of the resulting code to create a unique name.
|
|
||||||
props["handle_submit_unique_name"] = ""
|
|
||||||
form = super().create(*children, **props)
|
|
||||||
form.handle_submit_unique_name = md5(
|
|
||||||
str(form.get_hooks()).encode("utf-8")
|
|
||||||
).hexdigest()
|
|
||||||
return form
|
|
||||||
|
|
||||||
def _get_imports(self) -> imports.ImportDict:
|
|
||||||
return imports.merge_imports(
|
|
||||||
super()._get_imports(),
|
|
||||||
{
|
|
||||||
"react": {imports.ImportVar(tag="useCallback")},
|
|
||||||
f"/{Dirs.STATE_PATH}": {
|
|
||||||
imports.ImportVar(tag="getRefValue"),
|
|
||||||
imports.ImportVar(tag="getRefValues"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
def _get_hooks(self) -> str | None:
|
|
||||||
if EventTriggers.ON_SUBMIT not in self.event_triggers:
|
|
||||||
return
|
|
||||||
return HANDLE_SUBMIT_JS_JINJA2.render(
|
|
||||||
handle_submit_unique_name=self.handle_submit_unique_name,
|
|
||||||
form_data=FORM_DATA,
|
|
||||||
field_ref_mapping=str(Var.create_safe(self._get_form_refs())),
|
|
||||||
on_submit_event_chain=format_event_chain(
|
|
||||||
self.event_triggers[EventTriggers.ON_SUBMIT]
|
|
||||||
),
|
|
||||||
reset_on_submit=self.reset_on_submit,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _render(self) -> Tag:
|
|
||||||
render_tag = (
|
|
||||||
super()
|
|
||||||
._render()
|
|
||||||
.remove_props(
|
|
||||||
"reset_on_submit",
|
|
||||||
"handle_submit_unique_name",
|
|
||||||
to_camel_case(EventTriggers.ON_SUBMIT),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if EventTriggers.ON_SUBMIT in self.event_triggers:
|
|
||||||
render_tag.add_props(
|
|
||||||
**{
|
|
||||||
EventTriggers.ON_SUBMIT: BaseVar(
|
|
||||||
_var_name=f"handleSubmit_{self.handle_submit_unique_name}",
|
|
||||||
_var_type=EventChain,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return render_tag
|
|
||||||
|
|
||||||
def _get_form_refs(self) -> Dict[str, Any]:
|
|
||||||
# Send all the input refs to the handler.
|
|
||||||
form_refs = {}
|
|
||||||
for ref in self.get_refs():
|
|
||||||
# when ref start with refs_ it's an array of refs, so we need different method
|
|
||||||
# to collect data
|
|
||||||
if ref.startswith("refs_"):
|
|
||||||
ref_var = Var.create_safe(ref[:-3]).as_ref()
|
|
||||||
form_refs[ref[5:-3]] = Var.create_safe(
|
|
||||||
f"getRefValues({str(ref_var)})", _var_is_local=False
|
|
||||||
)._replace(merge_var_data=ref_var._var_data)
|
|
||||||
else:
|
|
||||||
ref_var = Var.create_safe(ref).as_ref()
|
|
||||||
form_refs[ref[4:]] = Var.create_safe(
|
|
||||||
f"getRefValue({str(ref_var)})", _var_is_local=False
|
|
||||||
)._replace(merge_var_data=ref_var._var_data)
|
|
||||||
return form_refs
|
|
||||||
|
|
||||||
def _apply_theme(self, theme: Component):
|
def _apply_theme(self, theme: Component):
|
||||||
return {
|
return {
|
||||||
"width": "260px",
|
"width": "260px",
|
||||||
**self.style,
|
**self.style,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_vars(self) -> Iterator[Var]:
|
|
||||||
yield from super()._get_vars()
|
|
||||||
yield from self._get_form_refs().values()
|
|
||||||
|
|
||||||
|
|
||||||
class FormField(FormComponent):
|
class FormField(FormComponent):
|
||||||
"""A form field component."""
|
"""A form field component."""
|
||||||
|
@ -7,25 +7,14 @@ from typing import Any, Dict, Literal, Optional, Union, overload
|
|||||||
from reflex.vars import Var, BaseVar, ComputedVar
|
from reflex.vars import Var, BaseVar, ComputedVar
|
||||||
from reflex.event import EventChain, EventHandler, EventSpec
|
from reflex.event import EventChain, EventHandler, EventSpec
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
from hashlib import md5
|
from typing import Any, Dict, Literal
|
||||||
from typing import Any, Dict, Iterator, Literal
|
|
||||||
from jinja2 import Environment
|
|
||||||
from reflex.components.component import Component, ComponentNamespace
|
from reflex.components.component import Component, ComponentNamespace
|
||||||
|
from reflex.components.el.elements.forms import Form as HTMLForm
|
||||||
from reflex.components.radix.themes.components.text_field import TextFieldInput
|
from reflex.components.radix.themes.components.text_field import TextFieldInput
|
||||||
from reflex.components.tags.tag import Tag
|
|
||||||
from reflex.constants.base import Dirs
|
|
||||||
from reflex.constants.event import EventTriggers
|
from reflex.constants.event import EventTriggers
|
||||||
from reflex.event import EventChain
|
from reflex.vars import Var
|
||||||
from reflex.utils import imports
|
|
||||||
from reflex.utils.format import format_event_chain, to_camel_case
|
|
||||||
from reflex.vars import BaseVar, Var
|
|
||||||
from .base import RadixPrimitiveComponentWithClassName
|
from .base import RadixPrimitiveComponentWithClassName
|
||||||
|
|
||||||
FORM_DATA = Var.create("form_data")
|
|
||||||
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
|
||||||
"\n const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {\n const $form = ev.target\n ev.preventDefault()\n const {{ form_data }} = {...Object.fromEntries(new FormData($form).entries()), ...{{ field_ref_mapping }}}\n\n {{ on_submit_event_chain }}\n\n if ({{ reset_on_submit }}) {\n $form.reset()\n }\n })\n "
|
|
||||||
)
|
|
||||||
|
|
||||||
class FormComponent(RadixPrimitiveComponentWithClassName):
|
class FormComponent(RadixPrimitiveComponentWithClassName):
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -107,16 +96,81 @@ class FormComponent(RadixPrimitiveComponentWithClassName):
|
|||||||
"""
|
"""
|
||||||
...
|
...
|
||||||
|
|
||||||
class FormRoot(FormComponent):
|
class FormRoot(FormComponent, HTMLForm):
|
||||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@classmethod
|
||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
|
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||||
|
accept: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
accept_charset: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
action: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
auto_complete: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
enc_type: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
method: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
name: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
no_validate: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
target: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
||||||
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
||||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
access_key: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
auto_capitalize: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
content_editable: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
context_menu: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
dir: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
draggable: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
enter_key_hint: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
hidden: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
input_mode: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
item_prop: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
lang: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
role: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
slot: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
spell_check: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
tab_index: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
title: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
style: Optional[Style] = None,
|
style: Optional[Style] = None,
|
||||||
key: Optional[Any] = None,
|
key: Optional[Any] = None,
|
||||||
id: Optional[Any] = None,
|
id: Optional[Any] = None,
|
||||||
@ -180,9 +234,34 @@ class FormRoot(FormComponent):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
*children: The children of the form.
|
*children: The children of the form.
|
||||||
|
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
|
||||||
|
action: URL where the form's data should be submitted
|
||||||
|
auto_complete: Whether the form should have autocomplete enabled
|
||||||
|
enc_type: Encoding type for the form data when submitted
|
||||||
|
method: HTTP method to use for form submission
|
||||||
|
name: Name of the form
|
||||||
|
no_validate: Indicates that the form should not be validated on submit
|
||||||
|
target: Where to display the response after submitting the form
|
||||||
reset_on_submit: If true, the form will be cleared after submit.
|
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.
|
handle_submit_unique_name: The name used to make this form's submit handler function unique.
|
||||||
as_child: Change the default rendered element for the one passed as a child.
|
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.
|
||||||
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
||||||
|
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
||||||
|
draggable: Defines whether the element can be dragged.
|
||||||
|
enter_key_hint: Hints what media types the media element is able to play.
|
||||||
|
hidden: Defines whether the element is hidden.
|
||||||
|
input_mode: Defines the type of the element.
|
||||||
|
item_prop: Defines the name of the element for metadata purposes.
|
||||||
|
lang: Defines the language used in the element.
|
||||||
|
role: Defines the role of the element.
|
||||||
|
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
||||||
|
spell_check: Defines whether the element may be checked for spelling errors.
|
||||||
|
tab_index: Defines the position of the current element in the tabbing order.
|
||||||
|
title: Defines a tooltip for the element.
|
||||||
style: The style of the component.
|
style: The style of the component.
|
||||||
key: A unique key for the component.
|
key: A unique key for the component.
|
||||||
id: The id for the component.
|
id: The id for the component.
|
||||||
@ -743,9 +822,74 @@ class Form(FormRoot):
|
|||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
|
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||||
|
accept: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
accept_charset: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
action: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
auto_complete: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
enc_type: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
method: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
name: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
no_validate: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
target: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
||||||
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
||||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
access_key: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
auto_capitalize: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
content_editable: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
context_menu: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
dir: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
draggable: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
enter_key_hint: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
hidden: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
input_mode: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
item_prop: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
lang: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
role: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
slot: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
spell_check: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
tab_index: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
title: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
style: Optional[Style] = None,
|
style: Optional[Style] = None,
|
||||||
key: Optional[Any] = None,
|
key: Optional[Any] = None,
|
||||||
id: Optional[Any] = None,
|
id: Optional[Any] = None,
|
||||||
@ -809,9 +953,34 @@ class Form(FormRoot):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
*children: The children of the form.
|
*children: The children of the form.
|
||||||
|
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
|
||||||
|
action: URL where the form's data should be submitted
|
||||||
|
auto_complete: Whether the form should have autocomplete enabled
|
||||||
|
enc_type: Encoding type for the form data when submitted
|
||||||
|
method: HTTP method to use for form submission
|
||||||
|
name: Name of the form
|
||||||
|
no_validate: Indicates that the form should not be validated on submit
|
||||||
|
target: Where to display the response after submitting the form
|
||||||
reset_on_submit: If true, the form will be cleared after submit.
|
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.
|
handle_submit_unique_name: The name used to make this form's submit handler function unique.
|
||||||
as_child: Change the default rendered element for the one passed as a child.
|
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.
|
||||||
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
||||||
|
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
||||||
|
draggable: Defines whether the element can be dragged.
|
||||||
|
enter_key_hint: Hints what media types the media element is able to play.
|
||||||
|
hidden: Defines whether the element is hidden.
|
||||||
|
input_mode: Defines the type of the element.
|
||||||
|
item_prop: Defines the name of the element for metadata purposes.
|
||||||
|
lang: Defines the language used in the element.
|
||||||
|
role: Defines the role of the element.
|
||||||
|
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
||||||
|
spell_check: Defines whether the element may be checked for spelling errors.
|
||||||
|
tab_index: Defines the position of the current element in the tabbing order.
|
||||||
|
title: Defines a tooltip for the element.
|
||||||
style: The style of the component.
|
style: The style of the component.
|
||||||
key: A unique key for the component.
|
key: A unique key for the component.
|
||||||
id: The id for the component.
|
id: The id for the component.
|
||||||
@ -837,9 +1006,74 @@ class FormNamespace(ComponentNamespace):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def __call__(
|
def __call__(
|
||||||
*children,
|
*children,
|
||||||
|
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||||
|
accept: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
accept_charset: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
action: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
auto_complete: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
enc_type: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
method: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
name: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
no_validate: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
target: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
reset_on_submit: Optional[Union[Var[bool], bool]] = None,
|
||||||
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
handle_submit_unique_name: Optional[Union[Var[str], str]] = None,
|
||||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
access_key: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
auto_capitalize: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
content_editable: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
context_menu: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
dir: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
draggable: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
enter_key_hint: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
hidden: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
input_mode: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
item_prop: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
lang: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
role: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
slot: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||||
|
spell_check: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
tab_index: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
|
title: Optional[
|
||||||
|
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||||
|
] = None,
|
||||||
style: Optional[Style] = None,
|
style: Optional[Style] = None,
|
||||||
key: Optional[Any] = None,
|
key: Optional[Any] = None,
|
||||||
id: Optional[Any] = None,
|
id: Optional[Any] = None,
|
||||||
@ -903,9 +1137,34 @@ class FormNamespace(ComponentNamespace):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
*children: The children of the form.
|
*children: The children of the form.
|
||||||
|
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
|
||||||
|
action: URL where the form's data should be submitted
|
||||||
|
auto_complete: Whether the form should have autocomplete enabled
|
||||||
|
enc_type: Encoding type for the form data when submitted
|
||||||
|
method: HTTP method to use for form submission
|
||||||
|
name: Name of the form
|
||||||
|
no_validate: Indicates that the form should not be validated on submit
|
||||||
|
target: Where to display the response after submitting the form
|
||||||
reset_on_submit: If true, the form will be cleared after submit.
|
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.
|
handle_submit_unique_name: The name used to make this form's submit handler function unique.
|
||||||
as_child: Change the default rendered element for the one passed as a child.
|
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.
|
||||||
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
||||||
|
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
||||||
|
draggable: Defines whether the element can be dragged.
|
||||||
|
enter_key_hint: Hints what media types the media element is able to play.
|
||||||
|
hidden: Defines whether the element is hidden.
|
||||||
|
input_mode: Defines the type of the element.
|
||||||
|
item_prop: Defines the name of the element for metadata purposes.
|
||||||
|
lang: Defines the language used in the element.
|
||||||
|
role: Defines the role of the element.
|
||||||
|
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
||||||
|
spell_check: Defines whether the element may be checked for spelling errors.
|
||||||
|
tab_index: Defines the position of the current element in the tabbing order.
|
||||||
|
title: Defines a tooltip for the element.
|
||||||
style: The style of the component.
|
style: The style of the component.
|
||||||
key: A unique key for the component.
|
key: A unique key for the component.
|
||||||
id: The id for the component.
|
id: The id for the component.
|
||||||
|
Loading…
Reference in New Issue
Block a user