diff --git a/.changeset/green-streets-open.md b/.changeset/green-streets-open.md new file mode 100644 index 0000000000000..9cf822bf9cc3d --- /dev/null +++ b/.changeset/green-streets-open.md @@ -0,0 +1,6 @@ +--- +"@gradio/textbox": minor +"gradio": minor +--- + +feat:Adding `maxlength` attribute handling of `textarea` and `input` HTML element for the `gr.TextBox()` component via a `max_length` parameter diff --git a/gradio/components/textbox.py b/gradio/components/textbox.py index 32202a9b04a2a..628970412b94a 100644 --- a/gradio/components/textbox.py +++ b/gradio/components/textbox.py @@ -58,6 +58,7 @@ def __init__( text_align: Literal["left", "right"] | None = None, rtl: bool = False, show_copy_button: bool = False, + max_length: int | None = None, ): """ Parameters: @@ -85,6 +86,7 @@ def __init__( rtl: If True and `type` is "text", sets the direction of the text to right-to-left (cursor appears on the left of the text). Default is False, which renders cursor on the right. show_copy_button: If True, includes a copy button to copy the text in the textbox. Only applies if show_label is True. autoscroll: If True, will automatically scroll to the bottom of the textbox when the value changes, unless the user scrolls up. If False, will not scroll to the bottom of the textbox when the value changes. + max_length: maximum number of characters (including newlines) allowed in the textbox. If None, there is no maximum length. """ if type not in ["text", "password", "email"]: raise ValueError('`type` must be one of "text", "password", or "email".') @@ -118,6 +120,7 @@ def __init__( self.type = type self.rtl = rtl self.text_align = text_align + self.max_length = max_length def preprocess(self, payload: str | None) -> str | None: """ diff --git a/gradio/templates.py b/gradio/templates.py index be9f7e4e5a915..9971a0093b1b0 100644 --- a/gradio/templates.py +++ b/gradio/templates.py @@ -51,6 +51,7 @@ def __init__( text_align: Literal["left", "right"] | None = None, rtl: bool = False, show_copy_button: bool = False, + max_length: int | None = None, ): super().__init__( value=value, @@ -77,6 +78,7 @@ def __init__( text_align=text_align, rtl=rtl, show_copy_button=show_copy_button, + max_length=max_length, ) diff --git a/js/textbox/Index.svelte b/js/textbox/Index.svelte index ca58d14d03ab2..d582877a20407 100644 --- a/js/textbox/Index.svelte +++ b/js/textbox/Index.svelte @@ -43,6 +43,7 @@ export let autofocus = false; export let autoscroll = true; export let interactive: boolean; + export let max_length: number | undefined = undefined; gradio.dispatch("change", value)} on:input={() => gradio.dispatch("input")} on:submit={() => gradio.dispatch("submit")} diff --git a/js/textbox/README.md b/js/textbox/README.md index 78a024e712936..4341304d2d060 100644 --- a/js/textbox/README.md +++ b/js/textbox/README.md @@ -24,6 +24,7 @@ BaseTextbox export let autofocus = false; export let text_align: "left" | "right" | undefined = undefined; export let autoscroll = true; + export let max_length: number | undefined = undefined; ``` BaseExample diff --git a/js/textbox/Textbox.stories.svelte b/js/textbox/Textbox.stories.svelte index 406e8828e4c55..6684ba4af7107 100644 --- a/js/textbox/Textbox.stories.svelte +++ b/js/textbox/Textbox.stories.svelte @@ -48,6 +48,10 @@ description: "Whether to render right-to-left", control: { type: "boolean" }, defaultValue: false + }, + max_length: { + description: "The maximum number of characters allowed in the textbox", + control: { type: "number" } } }} /> diff --git a/js/textbox/shared/Textbox.svelte b/js/textbox/shared/Textbox.svelte index 68229865db21a..00d228188b65f 100644 --- a/js/textbox/shared/Textbox.svelte +++ b/js/textbox/shared/Textbox.svelte @@ -26,6 +26,7 @@ export let autofocus = false; export let text_align: "left" | "right" | undefined = undefined; export let autoscroll = true; + export let max_length: number | undefined = undefined; let el: HTMLTextAreaElement | HTMLInputElement; let copied = false; @@ -194,6 +195,7 @@ {placeholder} {disabled} {autofocus} + maxlength={max_length} on:keypress={handle_keypress} on:blur on:select={handle_select} @@ -210,6 +212,7 @@ {placeholder} {disabled} {autofocus} + maxlength={max_length} on:keypress={handle_keypress} on:blur on:select={handle_select} @@ -226,6 +229,7 @@ {placeholder} {disabled} {autofocus} + maxlength={max_length} on:keypress={handle_keypress} on:blur on:select={handle_select} @@ -260,6 +264,7 @@ rows={lines} {disabled} {autofocus} + maxlength={max_length} on:keypress={handle_keypress} on:blur on:select={handle_select} diff --git a/test/components/test_textbox.py b/test/components/test_textbox.py index a17b37e5be382..0c7500df7e9e0 100644 --- a/test/components/test_textbox.py +++ b/test/components/test_textbox.py @@ -40,6 +40,7 @@ def test_component_functions(self): "key": None, "info": None, "autoscroll": True, + "max_length": None, } @pytest.mark.asyncio diff --git a/test/test_components.py b/test/test_components.py index 210028f400bff..40abc6d17b98f 100644 --- a/test/test_components.py +++ b/test/test_components.py @@ -101,6 +101,11 @@ def test_constructor_args(): def test_template_component_configs(io_components): + """ + This test ensures that every "template" (the classes defined in gradio/template.py) + has all of the arguments that its parent class has. E.g. the constructor of the `Sketchpad` + class should have all of the arguments that the constructor of `ImageEditor` has + """ template_components = [c for c in io_components if getattr(c, "is_template", False)] for component in template_components: component_parent_class = inspect.getmro(component)[1]