[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."""
|
||||
import functools
|
||||
import time
|
||||
from typing import Generator
|
||||
|
||||
@ -10,8 +11,12 @@ from reflex.testing import AppHarness
|
||||
from reflex.utils import format
|
||||
|
||||
|
||||
def FormSubmit():
|
||||
"""App with a form using on_submit."""
|
||||
def FormSubmit(form_component):
|
||||
"""App with a form using on_submit.
|
||||
|
||||
Args:
|
||||
form_component: The str name of the form component to use.
|
||||
"""
|
||||
import reflex as rx
|
||||
|
||||
class FormState(rx.State):
|
||||
@ -32,7 +37,7 @@ def FormSubmit():
|
||||
is_read_only=True,
|
||||
id="token",
|
||||
),
|
||||
rx.form.root(
|
||||
eval(form_component)(
|
||||
rx.vstack(
|
||||
rx.chakra.input(id="name_input"),
|
||||
rx.hstack(rx.chakra.pin_input(length=4, id="pin_input")),
|
||||
@ -63,8 +68,12 @@ def FormSubmit():
|
||||
)
|
||||
|
||||
|
||||
def FormSubmitName():
|
||||
"""App with a form using on_submit."""
|
||||
def FormSubmitName(form_component):
|
||||
"""App with a form using on_submit.
|
||||
|
||||
Args:
|
||||
form_component: The str name of the form component to use.
|
||||
"""
|
||||
import reflex as rx
|
||||
|
||||
class FormState(rx.State):
|
||||
@ -85,7 +94,7 @@ def FormSubmitName():
|
||||
is_read_only=True,
|
||||
id="token",
|
||||
),
|
||||
rx.form.root(
|
||||
eval(form_component)(
|
||||
rx.vstack(
|
||||
rx.chakra.input(name="name_input"),
|
||||
rx.hstack(rx.chakra.pin_input(length=4, name="pin_input")),
|
||||
@ -128,7 +137,23 @@ def FormSubmitName():
|
||||
|
||||
|
||||
@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]:
|
||||
"""Start FormSubmit app at tmp_path via AppHarness.
|
||||
@ -140,9 +165,11 @@ def form_submit(request, tmp_path_factory) -> Generator[AppHarness, None, None]:
|
||||
Yields:
|
||||
running AppHarness instance
|
||||
"""
|
||||
param_id = request._pyfuncitem.callspec.id.replace("-", "_")
|
||||
with AppHarness.create(
|
||||
root=tmp_path_factory.mktemp("form_submit"),
|
||||
app_source=request.param, # type: ignore
|
||||
app_name=request.param.func.__name__ + f"_{param_id}",
|
||||
) as harness:
|
||||
assert harness.app_instance is not None, "app is not running"
|
||||
yield harness
|
||||
|
@ -1,39 +1,13 @@
|
||||
"""Form components."""
|
||||
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.component import Component
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.constants import Dirs, EventTriggers
|
||||
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()
|
||||
}
|
||||
})
|
||||
"""
|
||||
)
|
||||
from reflex.components.el.elements.forms import Form as HTMLForm
|
||||
from reflex.vars import Var
|
||||
|
||||
|
||||
class Form(ChakraComponent):
|
||||
class Form(ChakraComponent, HTMLForm):
|
||||
"""A form component."""
|
||||
|
||||
tag = "Box"
|
||||
@ -41,112 +15,6 @@ class Form(ChakraComponent):
|
||||
# What the form renders to.
|
||||
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):
|
||||
"""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.event import EventChain, EventHandler, EventSpec
|
||||
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.component import Component
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.constants import Dirs, EventTriggers
|
||||
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
|
||||
from reflex.components.el.elements.forms import Form as HTMLForm
|
||||
from reflex.vars import Var
|
||||
|
||||
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 Form(ChakraComponent):
|
||||
class Form(ChakraComponent, HTMLForm):
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
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,
|
||||
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,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
@ -94,8 +147,33 @@ class Form(ChakraComponent):
|
||||
Args:
|
||||
*children: The children of the form.
|
||||
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.
|
||||
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.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -108,7 +186,6 @@ class Form(ChakraComponent):
|
||||
The form component.
|
||||
"""
|
||||
...
|
||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||
|
||||
class FormControl(ChakraComponent):
|
||||
@overload
|
||||
|
@ -1,12 +1,38 @@
|
||||
"""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.constants.event import EventTriggers
|
||||
from reflex.vars import Var
|
||||
from reflex.components.tags.tag import Tag
|
||||
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
|
||||
|
||||
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):
|
||||
"""Display the button element."""
|
||||
@ -101,6 +127,111 @@ class Form(BaseHTML):
|
||||
# Where to display the response after submitting the form
|
||||
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):
|
||||
"""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.event import EventChain, EventHandler, EventSpec
|
||||
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.constants.event import EventTriggers
|
||||
from reflex.vars import Var
|
||||
from reflex.components.tags.tag import Tag
|
||||
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
|
||||
|
||||
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):
|
||||
@overload
|
||||
@classmethod
|
||||
@ -407,6 +418,7 @@ class Fieldset(Element):
|
||||
...
|
||||
|
||||
class Form(BaseHTML):
|
||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -437,6 +449,8 @@ class Form(BaseHTML):
|
||||
target: Optional[
|
||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||
] = None,
|
||||
reset_on_submit: Optional[Union[Var[bool], bool]] = 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,
|
||||
@ -525,15 +539,18 @@ class Form(BaseHTML):
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_submit: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
**props
|
||||
) -> "Form":
|
||||
"""Create the component.
|
||||
"""Create a form component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
*children: The children of the form.
|
||||
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
|
||||
@ -543,6 +560,8 @@ class Form(BaseHTML):
|
||||
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.
|
||||
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.
|
||||
@ -565,13 +584,10 @@ class Form(BaseHTML):
|
||||
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 props of the component.
|
||||
**props: The properties of the form.
|
||||
|
||||
Returns:
|
||||
The component.
|
||||
|
||||
Raises:
|
||||
TypeError: If an invalid child is passed.
|
||||
The form component.
|
||||
"""
|
||||
...
|
||||
|
||||
|
@ -2,40 +2,16 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from hashlib import md5
|
||||
from typing import Any, Dict, Iterator, Literal
|
||||
|
||||
from jinja2 import Environment
|
||||
from typing import Any, Dict, Literal
|
||||
|
||||
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.tags.tag import Tag
|
||||
from reflex.constants.base import Dirs
|
||||
from reflex.constants.event import EventTriggers
|
||||
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
|
||||
from reflex.vars import Var
|
||||
|
||||
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):
|
||||
"""Base class for all @radix-ui/react-form components."""
|
||||
@ -43,19 +19,13 @@ class FormComponent(RadixPrimitiveComponentWithClassName):
|
||||
library = "@radix-ui/react-form@^0.0.3"
|
||||
|
||||
|
||||
class FormRoot(FormComponent):
|
||||
class FormRoot(FormComponent, HTMLForm):
|
||||
"""The root component of a radix form."""
|
||||
|
||||
tag = "Root"
|
||||
|
||||
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]:
|
||||
"""Event triggers for radix form root.
|
||||
|
||||
@ -64,106 +34,15 @@ class FormRoot(FormComponent):
|
||||
"""
|
||||
return {
|
||||
**super().get_event_triggers(),
|
||||
EventTriggers.ON_SUBMIT: lambda e0: [FORM_DATA],
|
||||
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):
|
||||
return {
|
||||
"width": "260px",
|
||||
**self.style,
|
||||
}
|
||||
|
||||
def _get_vars(self) -> Iterator[Var]:
|
||||
yield from super()._get_vars()
|
||||
yield from self._get_form_refs().values()
|
||||
|
||||
|
||||
class FormField(FormComponent):
|
||||
"""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.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from hashlib import md5
|
||||
from typing import Any, Dict, Iterator, Literal
|
||||
from jinja2 import Environment
|
||||
from typing import Any, Dict, Literal
|
||||
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.tags.tag import Tag
|
||||
from reflex.constants.base import Dirs
|
||||
from reflex.constants.event import EventTriggers
|
||||
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
|
||||
from reflex.vars import Var
|
||||
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):
|
||||
@overload
|
||||
@classmethod
|
||||
@ -107,16 +96,81 @@ class FormComponent(RadixPrimitiveComponentWithClassName):
|
||||
"""
|
||||
...
|
||||
|
||||
class FormRoot(FormComponent):
|
||||
class FormRoot(FormComponent, HTMLForm):
|
||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*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,
|
||||
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,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
@ -180,9 +234,34 @@ class FormRoot(FormComponent):
|
||||
|
||||
Args:
|
||||
*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.
|
||||
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.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -743,9 +822,74 @@ class Form(FormRoot):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*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,
|
||||
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,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
@ -809,9 +953,34 @@ class Form(FormRoot):
|
||||
|
||||
Args:
|
||||
*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.
|
||||
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.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -837,9 +1006,74 @@ class FormNamespace(ComponentNamespace):
|
||||
@staticmethod
|
||||
def __call__(
|
||||
*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,
|
||||
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,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
@ -903,9 +1137,34 @@ class FormNamespace(ComponentNamespace):
|
||||
|
||||
Args:
|
||||
*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.
|
||||
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.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
Loading…
Reference in New Issue
Block a user