Enhancement: Add focus event to textbox and number component (#5005)

* Add focus event to textbox and number component

* add changeset

* Combine Blurrable and Focusable into Focusable event

* Add focus and blur to Dropdown and Colorpicker components

* add focus to home page template

* Add Focus to doc

* Fix linting error

* fixes

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
Co-authored-by: Ali Abid <aabid94@gmail.com>
This commit is contained in:
Jody Zhou 2023-08-01 16:02:50 -04:00 committed by GitHub
parent 95ea19d65f
commit f5539c7618
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 75 additions and 50 deletions

View File

@ -0,0 +1,7 @@
---
"@gradio/app": minor
"@gradio/form": minor
"gradio": minor
---
feat:Enhancement: Add focus event to textbox and number component

View File

@ -9,8 +9,8 @@ from gradio_client.serializing import StringSerializable
from gradio.components.base import IOComponent, _Keywords
from gradio.events import (
Blurrable,
Changeable,
Focusable,
Inputable,
Submittable,
)
@ -20,7 +20,7 @@ set_documentation_group("component")
@document()
class ColorPicker(
Changeable, Inputable, Submittable, Blurrable, IOComponent, StringSerializable
Changeable, Inputable, Submittable, Focusable, IOComponent, StringSerializable
):
"""
Creates a color picker for user to select a color as string input.

View File

@ -11,9 +11,9 @@ from gradio_client.serializing import SimpleSerializable
from gradio.components.base import FormComponent, IOComponent, _Keywords
from gradio.deprecation import warn_style_method_deprecation
from gradio.events import (
Blurrable,
Changeable,
EventListenerMethod,
Focusable,
Inputable,
Selectable,
)
@ -27,7 +27,7 @@ class Dropdown(
Changeable,
Inputable,
Selectable,
Blurrable,
Focusable,
IOComponent,
SimpleSerializable,
):

View File

@ -11,8 +11,8 @@ from gradio_client.serializing import NumberSerializable
from gradio.components.base import FormComponent, IOComponent, _Keywords
from gradio.events import (
Blurrable,
Changeable,
Focusable,
Inputable,
Submittable,
)
@ -28,7 +28,7 @@ class Number(
Changeable,
Inputable,
Submittable,
Blurrable,
Focusable,
IOComponent,
NumberSerializable,
NeighborInterpretable,

View File

@ -15,9 +15,9 @@ from gradio.components.base import (
)
from gradio.deprecation import warn_style_method_deprecation
from gradio.events import (
Blurrable,
Changeable,
EventListenerMethod,
Focusable,
Inputable,
Selectable,
Submittable,
@ -34,7 +34,7 @@ class Textbox(
Inputable,
Selectable,
Submittable,
Blurrable,
Focusable,
IOComponent,
StringSerializable,
TokenInterpretable,

View File

@ -286,9 +286,15 @@ class Recordable(EventListener):
"""
@document("*blur", inherit=True)
class Blurrable(EventListener):
@document("*focus", "*blur", inherit=True)
class Focusable(EventListener):
def __init__(self):
self.focus = EventListenerMethod(self, "focus")
"""
This listener is triggered when the component is focused (e.g. when the user clicks inside a textbox).
This method can be used when this component is in a Gradio Blocks.
"""
self.blur = EventListenerMethod(self, "blur")
"""
This listener is triggered when the component's is unfocused/blurred (e.g. when the user clicks outside of a textbox).

View File

@ -34,6 +34,7 @@
on:input
on:submit
on:blur
on:focus
disabled={mode === "static"}
/>
</Block>

View File

@ -48,6 +48,7 @@
on:input
on:select
on:blur
on:focus
disabled={mode === "static"}
/>
</Block>

View File

@ -48,5 +48,6 @@
on:input
on:submit
on:blur
on:focus
/>
</Block>

View File

@ -54,6 +54,7 @@
on:submit
on:blur
on:select
on:focus
disabled={mode === "static"}
/>
</Block>

View File

@ -14,6 +14,7 @@
input: undefined;
submit: undefined;
blur: undefined;
focus: undefined;
}>();
function handle_change() {
@ -22,6 +23,7 @@
dispatch("input");
}
}
afterUpdate(() => {
value_is_output = false;
});
@ -31,7 +33,7 @@
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="block">
<BlockTitle {show_label} {info}>{label}</BlockTitle>
<input type="color" on:blur bind:value {disabled} />
<input type="color" bind:value on:focus on:blur {disabled} />
</label>
<style>

View File

@ -22,6 +22,7 @@
input: undefined;
select: SelectData;
blur: undefined;
focus: undefined;
}>();
let inputValue: string | undefined,
@ -86,6 +87,33 @@
e.preventDefault();
}
function handle_blur(e: FocusEvent) {
if (multiselect) {
inputValue = "";
} else if (!allow_custom_value) {
if (value !== inputValue) {
if (typeof value === "string" && inputValue == "") {
inputValue = value;
} else {
value = undefined;
inputValue = "";
}
}
}
showOptions = false;
dispatch("blur");
}
function handle_focus(e: FocusEvent){
dispatch("focus");
showOptions = !showOptions;
if (showOptions) {
filtered = choices;
} else {
filterInput.blur();
}
}
function handleOptionMousedown(e: any): void {
const option = e.detail.target.dataset.value;
if (allow_custom_value) {
@ -113,15 +141,6 @@
}
}
function handleFocus(): void {
showOptions = !showOptions;
if (showOptions) {
filtered = choices;
} else {
filterInput.blur();
}
}
function handleKeydown(e: any) {
if (e.key === "Enter" && activeOption != undefined) {
if (!multiselect) {
@ -208,28 +227,14 @@
autocomplete="off"
bind:value={inputValue}
bind:this={filterInput}
on:focus={handleFocus}
on:keydown={handleKeydown}
on:keyup={() => {
if (allow_custom_value) {
value = inputValue;
}
}}
on:blur={() => {
if (multiselect) {
inputValue = "";
} else if (!allow_custom_value) {
if (value !== inputValue) {
if (typeof value === "string" && inputValue == "") {
inputValue = value;
} else {
value = undefined;
inputValue = "";
}
}
}
showOptions = false;
}}
on:blur={handle_blur}
on:focus={handle_focus}
/>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div

View File

@ -18,6 +18,7 @@
submit: undefined;
blur: undefined;
input: undefined;
focus: undefined;
}>();
function handle_change(): void {
@ -40,10 +41,6 @@
dispatch("submit");
}
}
function handle_blur(e: FocusEvent): void {
dispatch("blur");
}
</script>
<label class="block" class:container>
@ -55,7 +52,8 @@
max={maximum}
{step}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:blur
on:focus
{disabled}
/>
</label>

View File

@ -33,6 +33,7 @@
blur: undefined;
select: SelectData;
input: undefined;
focus: undefined;
}>();
function handle_change() {
@ -46,10 +47,6 @@
});
$: value, handle_change();
function handle_blur() {
dispatch("blur");
}
async function handle_copy() {
if ("clipboard" in navigator) {
await navigator.clipboard.writeText(value);
@ -153,8 +150,9 @@
{disabled}
{autofocus}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:blur
on:select={handle_select}
on:focus
style={text_align ? "text-align: " + text_align : ""}
/>
{:else if type === "password"}
@ -168,8 +166,9 @@
{disabled}
{autofocus}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:blur
on:select={handle_select}
on:focus
autocomplete=""
/>
{:else if type === "email"}
@ -183,8 +182,9 @@
{disabled}
{autofocus}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:blur
on:select={handle_select}
on:focus
autocomplete="email"
/>
{/if}
@ -208,8 +208,9 @@
{disabled}
{autofocus}
on:keypress={handle_keypress}
on:blur={handle_blur}
on:blur
on:select={handle_select}
on:focus
style={text_align ? "text-align: " + text_align : ""}
/>
{/if}

View File

@ -1,4 +1,4 @@
lockfileVersion: '6.0'
lockfileVersion: '6.1'
settings:
autoInstallPeers: true

View File

@ -72,6 +72,7 @@ ordered_events = [
"Pause()",
"Stream()",
"Blur()",
"Focus()",
"Upload()",
]

View File

@ -323,6 +323,7 @@
<th class="p-3 font-normal bg-white border-t">Pause</th>
<th class="p-3 font-normal bg-white border-t">Stream</th>
<th class="p-3 font-normal bg-white border-t">Blur</th>
<th class="p-3 font-normal bg-white border-t">Focus</th>
<th class="p-3 font-normal bg-white border-t border-r">Upload</th>
</tr>
</thead>