textarea: expose auto_height and enter_key_submit props (#2884)
* textarea: expose auto_height and enter_key_submit props These two props improve the workflow for chat apps and other situations where we want multiline input. auto_height: resize the textarea based on its contents enter_key_submit: pressing enter submits the enclosing form (shift+enter inserts new lines) Fix #1231 * Update pyi
This commit is contained in:
parent
68c56a9811
commit
8ef193809c
@ -2,7 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from hashlib import md5
|
||||
from typing import Any, Dict, Iterator, Union
|
||||
from typing import Any, Dict, Iterator, Set, Union
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
@ -500,6 +500,36 @@ class Select(BaseHTML):
|
||||
}
|
||||
|
||||
|
||||
AUTO_HEIGHT_JS = """
|
||||
const autoHeightOnInput = (e, is_enabled) => {
|
||||
if (is_enabled) {
|
||||
const el = e.target;
|
||||
el.style.overflowY = "hidden";
|
||||
el.style.height = "auto";
|
||||
el.style.height = (e.target.scrollHeight) + "px";
|
||||
if (el.form && !el.form.data_resize_on_reset) {
|
||||
el.form.addEventListener("reset", () => window.setTimeout(() => autoHeightOnInput(e, is_enabled), 0))
|
||||
el.form.data_resize_on_reset = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
ENTER_KEY_SUBMIT_JS = """
|
||||
const enterKeySubmitOnKeyDown = (e, is_enabled) => {
|
||||
if (is_enabled && e.which === 13 && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
if (!e.repeat) {
|
||||
if (e.target.form) {
|
||||
e.target.form.requestSubmit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class Textarea(BaseHTML):
|
||||
"""Display the textarea element."""
|
||||
|
||||
@ -511,6 +541,9 @@ class Textarea(BaseHTML):
|
||||
# Automatically focuses the textarea when the page loads
|
||||
auto_focus: Var[Union[str, int, bool]]
|
||||
|
||||
# Automatically fit the content height to the text (use min-height with this prop)
|
||||
auto_height: Var[bool]
|
||||
|
||||
# Visible width of the text control, in average character widths
|
||||
cols: Var[Union[str, int, bool]]
|
||||
|
||||
@ -520,6 +553,9 @@ class Textarea(BaseHTML):
|
||||
# Disables the textarea
|
||||
disabled: Var[Union[str, int, bool]]
|
||||
|
||||
# Enter key submits form (shift-enter adds new line)
|
||||
enter_key_submit: Var[bool]
|
||||
|
||||
# Associates the textarea with a form (by id)
|
||||
form: Var[Union[str, int, bool]]
|
||||
|
||||
@ -550,6 +586,47 @@ class Textarea(BaseHTML):
|
||||
# How the text in the textarea is to be wrapped when submitting the form
|
||||
wrap: Var[Union[str, int, bool]]
|
||||
|
||||
def _exclude_props(self) -> list[str]:
|
||||
return super()._exclude_props() + [
|
||||
"auto_height",
|
||||
"enter_key_submit",
|
||||
]
|
||||
|
||||
def get_custom_code(self) -> Set[str]:
|
||||
"""Include the custom code for auto_height and enter_key_submit functionality.
|
||||
|
||||
Returns:
|
||||
The custom code for the component.
|
||||
"""
|
||||
custom_code = super().get_custom_code()
|
||||
if self.auto_height is not None:
|
||||
custom_code.add(AUTO_HEIGHT_JS)
|
||||
if self.enter_key_submit is not None:
|
||||
custom_code.add(ENTER_KEY_SUBMIT_JS)
|
||||
return custom_code
|
||||
|
||||
def _render(self) -> Tag:
|
||||
tag = super()._render()
|
||||
if self.enter_key_submit is not None:
|
||||
if "on_key_down" in self.event_triggers:
|
||||
raise ValueError(
|
||||
"Cannot combine `enter_key_submit` with `on_key_down`.",
|
||||
)
|
||||
tag.add_props(
|
||||
on_key_down=Var.create_safe(
|
||||
f"(e) => enterKeySubmitOnKeyDown(e, {self.enter_key_submit._var_name_unwrapped})",
|
||||
_var_is_local=False,
|
||||
)._replace(merge_var_data=self.enter_key_submit._var_data),
|
||||
)
|
||||
if self.auto_height is not None:
|
||||
tag.add_props(
|
||||
on_input=Var.create_safe(
|
||||
f"(e) => autoHeightOnInput(e, {self.auto_height._var_name_unwrapped})",
|
||||
_var_is_local=False,
|
||||
)._replace(merge_var_data=self.auto_height._var_data),
|
||||
)
|
||||
return tag
|
||||
|
||||
def get_event_triggers(self) -> Dict[str, Any]:
|
||||
"""Get the event triggers that pass the component's value to the handler.
|
||||
|
||||
|
@ -8,7 +8,7 @@ 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, Union
|
||||
from typing import Any, Dict, Iterator, Set, Union
|
||||
from jinja2 import Environment
|
||||
from reflex.components.el.element import Element
|
||||
from reflex.components.tags.tag import Tag
|
||||
@ -2018,7 +2018,11 @@ class Select(BaseHTML):
|
||||
"""
|
||||
...
|
||||
|
||||
AUTO_HEIGHT_JS = '\nconst autoHeightOnInput = (e, is_enabled) => {\n if (is_enabled) {\n const el = e.target;\n el.style.overflowY = "hidden";\n el.style.height = "auto";\n el.style.height = (e.target.scrollHeight) + "px";\n if (el.form && !el.form.data_resize_on_reset) {\n el.form.addEventListener("reset", () => window.setTimeout(() => autoHeightOnInput(e, is_enabled), 0))\n el.form.data_resize_on_reset = true;\n }\n }\n}\n'
|
||||
ENTER_KEY_SUBMIT_JS = "\nconst enterKeySubmitOnKeyDown = (e, is_enabled) => {\n if (is_enabled && e.which === 13 && !e.shiftKey) {\n e.preventDefault();\n if (!e.repeat) {\n if (e.target.form) {\n e.target.form.requestSubmit();\n }\n }\n }\n}\n"
|
||||
|
||||
class Textarea(BaseHTML):
|
||||
def get_custom_code(self) -> Set[str]: ...
|
||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
@ -2031,6 +2035,7 @@ class Textarea(BaseHTML):
|
||||
auto_focus: Optional[
|
||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||
] = None,
|
||||
auto_height: Optional[Union[Var[bool], bool]] = None,
|
||||
cols: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||
dirname: Optional[
|
||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||
@ -2038,6 +2043,7 @@ class Textarea(BaseHTML):
|
||||
disabled: Optional[
|
||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||
] = None,
|
||||
enter_key_submit: Optional[Union[Var[bool], bool]] = None,
|
||||
form: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||
max_length: Optional[
|
||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||
@ -2168,9 +2174,11 @@ class Textarea(BaseHTML):
|
||||
*children: The children of the component.
|
||||
auto_complete: Whether the form control should have autocomplete enabled
|
||||
auto_focus: Automatically focuses the textarea when the page loads
|
||||
auto_height: Automatically fit the content height to the text (use min-height with this prop)
|
||||
cols: Visible width of the text control, in average character widths
|
||||
dirname: Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted
|
||||
disabled: Disables the textarea
|
||||
enter_key_submit: Enter key submits form (shift-enter adds new line)
|
||||
form: Associates the textarea with a form (by id)
|
||||
max_length: Maximum number of characters allowed in the textarea
|
||||
min_length: Minimum number of characters required in the textarea
|
||||
|
@ -108,7 +108,9 @@ class TextArea(RadixThemesComponent, el.Textarea):
|
||||
rows: Optional[Union[Var[str], str]] = None,
|
||||
value: Optional[Union[Var[str], str]] = None,
|
||||
wrap: Optional[Union[Var[str], str]] = None,
|
||||
auto_height: Optional[Union[Var[bool], bool]] = None,
|
||||
cols: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
|
||||
enter_key_submit: Optional[Union[Var[bool], bool]] = None,
|
||||
access_key: Optional[
|
||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||
] = None,
|
||||
@ -232,7 +234,9 @@ class TextArea(RadixThemesComponent, el.Textarea):
|
||||
rows: Visible number of lines in the text control
|
||||
value: The controlled value of the textarea, read only unless used with on_change
|
||||
wrap: How the text in the textarea is to be wrapped when submitting the form
|
||||
auto_height: Automatically fit the content height to the text (use min-height with this prop)
|
||||
cols: Visible width of the text control, in average character widths
|
||||
enter_key_submit: Enter key submits form (shift-enter adds new line)
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user