Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

V4: Single-file implementation of form components #6026

Merged
merged 12 commits into from Oct 25, 2023
10 changes: 10 additions & 0 deletions .changeset/plenty-parks-glow.md
@@ -0,0 +1,10 @@
---
"@gradio/checkbox": minor
"@gradio/checkboxgroup": minor
"@gradio/number": minor
"@gradio/radio": minor
"@gradio/slider": minor
"gradio": minor
---

feat:V4: Single-file implementation of form components
11 changes: 9 additions & 2 deletions gradio/_simple_templates/simpledropdown.py
Expand Up @@ -33,7 +33,9 @@ def __init__(
visible: bool = True,
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
**kwargs,
render: bool = True,
root_url: str | None = None,
_skip_init_processing: bool = False,
):
"""
Parameters:
Expand All @@ -49,6 +51,9 @@ def __init__(
visible: If False, component will be hidden.
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: bool = True,
root_url: str | None = None,
_skip_init_processing: bool = False,
"""
self.choices = (
# Although we expect choices to be a list of lists, it can be a list of tuples if the Gradio app
Expand All @@ -69,7 +74,9 @@ def __init__(
elem_id=elem_id,
elem_classes=elem_classes,
value=value,
**kwargs,
render=render,
root_url=root_url,
_skip_init_processing=_skip_init_processing,
)

def api_info(self) -> dict[str, Any]:
Expand Down
10 changes: 8 additions & 2 deletions gradio/_simple_templates/simpletextbox.py
Expand Up @@ -35,7 +35,9 @@ def __init__(
rtl: bool = False,
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
**kwargs,
render: bool = True,
root_url: str | None = None,
_skip_init_processing: bool = False,
):
"""
Parameters:
Expand All @@ -51,6 +53,8 @@ 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.
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
root_url: The remote URL that of the Gradio app that this component belongs to. Used in `gr.load()`. Should not be set manually.
"""
self.placeholder = placeholder
self.rtl = rtl
Expand All @@ -65,7 +69,9 @@ def __init__(
elem_id=elem_id,
elem_classes=elem_classes,
value=value,
**kwargs,
render=render,
root_url=root_url,
_skip_init_processing=_skip_init_processing,
)

def preprocess(self, x: str | None) -> str | None:
Expand Down
10 changes: 6 additions & 4 deletions gradio/cli/commands/components/show.py
Expand Up @@ -25,6 +25,8 @@
"State",
}

_BEGINNER_FRIENDLY = {"Slider", "Radio", "Checkbox", "Number", "CheckboxGroup", "File"}


def _get_table_items(module):
items = []
Expand All @@ -35,12 +37,12 @@ def _get_table_items(module):
) or (name in _IGNORE):
continue
tags = []
if "Simple" in name or name in {"File"}:
tags.append("馃尡馃Beginner Friendly馃尡馃")
if "Simple" in name or name in _BEGINNER_FRIENDLY:
tags.append(":seedling::handshake:Beginner Friendly:seedling::handshake:")
if issubclass(gr_cls, FormComponent):
tags.append("馃摑馃ЗForm Component馃摑馃З")
tags.append(":pencil::jigsaw:Form Component:pencil::jigsaw:")
if name in gradio.layouts.__all__:
tags.append("馃搻Layout馃搻")
tags.append(":triangular_ruler:Layout:triangular_ruler:")
doc = inspect.getdoc(gr_cls) or "No description available."
doc = doc.split(".")[0]
if tags:
Expand Down
1 change: 1 addition & 0 deletions gradio/components/video.py
Expand Up @@ -52,6 +52,7 @@ class Video(Component):
Events.play,
Events.pause,
Events.end,
Events.upload,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny oversight on my part

]

def __init__(
Expand Down
30 changes: 23 additions & 7 deletions js/checkbox/Index.svelte
@@ -1,10 +1,15 @@
<script context="module" lang="ts">
export { default as BaseCheckbox } from "./shared/Checkbox.svelte";
</script>

<script lang="ts">
import type { Gradio } from "@gradio/utils";
import Checkbox from "./shared/Checkbox.svelte";
import { Block, Info } from "@gradio/atoms";
import { StatusTracker } from "@gradio/statustracker";
import type { LoadingStatus } from "@gradio/statustracker";
import type { SelectData } from "@gradio/utils";
import { afterUpdate } from "svelte";
import BaseCheckbox from "./shared/Checkbox.svelte";

export let elem_id = "";
export let elem_classes: string[] = [];
Expand All @@ -23,6 +28,19 @@
input: never;
}>;
export let mode: "static" | "interactive";

function handle_change(): void {
gradio.dispatch("change");
if (!value_is_output) {
gradio.dispatch("input");
}
}
afterUpdate(() => {
value_is_output = false;
});

// When the value changes, dispatch the change event via handle_change()
// See the docs for an explanation: https://svelte.dev/docs/svelte-components#script-3-$-marks-a-statement-as-reactive
</script>

<Block {visible} {elem_id} {elem_classes} {container} {scale} {min_width}>
Expand All @@ -36,13 +54,11 @@
<Info>{info}</Info>
{/if}

<Checkbox
{label}
<BaseCheckbox
bind:value
bind:value_is_output
on:change={() => gradio.dispatch("change")}
on:input={() => gradio.dispatch("input")}
{label}
{mode}
on:change={handle_change}
on:select={(e) => gradio.dispatch("select", e.detail)}
disabled={mode === "static"}
/>
</Block>
1 change: 1 addition & 0 deletions js/checkbox/package.json
Expand Up @@ -7,6 +7,7 @@
"license": "ISC",
"private": false,
"main_changeset": true,
"main": "./Index.svelte",
"exports": {
".": "./Index.svelte",
"./example": "./Example.svelte",
Expand Down
64 changes: 32 additions & 32 deletions js/checkbox/shared/Checkbox.svelte
@@ -1,51 +1,51 @@
<script lang="ts">
import { createEventDispatcher, afterUpdate } from "svelte";
import type { SelectData } from "@gradio/utils";
import { createEventDispatcher } from "svelte";

export let value: boolean;
export let value_is_output = false;
export let disabled = false;
export let label: string;
export let value = false;
export let label = "Checkbox";
export let mode: "static" | "interactive";

const dispatch = createEventDispatcher<{
change: boolean;
select: SelectData;
input: undefined;
}>();

function handle_change(): void {
dispatch("change", value);
if (!value_is_output) {
dispatch("input");
// When the value changes, dispatch the change event via handle_change()
// See the docs for an explanation: https://svelte.dev/docs/svelte-components#script-3-$-marks-a-statement-as-reactive
$: value, dispatch("change", value);
$: disabled = mode === "static";

async function handle_enter(
event: KeyboardEvent & { currentTarget: EventTarget & HTMLInputElement }
): Promise<void> {
if (event.key === "Enter") {
value = !value;
dispatch("select", {
index: 0,
value: event.currentTarget.checked,
selected: event.currentTarget.checked
});
}
}
afterUpdate(() => {
value_is_output = false;
});
$: value, handle_change();

async function handle_input(
event: Event & { currentTarget: EventTarget & HTMLInputElement }
): Promise<void> {
value = event.currentTarget.checked;
dispatch("select", {
index: 0,
value: event.currentTarget.checked,
selected: event.currentTarget.checked
});
}
</script>

<label class:disabled>
<input
bind:checked={value}
on:keydown={(event) => {
if (event.key === "Enter") {
value = !value;
dispatch("select", {
index: 0,
value: label,
selected: value
});
}
}}
on:input={(evt) => {
value = evt.currentTarget.checked;
dispatch("select", {
index: 0,
value: label,
selected: evt.currentTarget.checked
});
}}
on:keydown={handle_enter}
on:input={handle_input}
{disabled}
type="checkbox"
name="test"
Expand Down
2 changes: 1 addition & 1 deletion js/checkboxgroup/Checkboxgroup.stories.svelte
@@ -1,6 +1,6 @@
<script>
import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
import Checkboxgroup from "./shared/Checkboxgroup.svelte";
import Checkboxgroup from "./Index.svelte";
</script>

<Meta
Expand Down