Repository: gradio-app/gradio

Issue:
Textbox Autoheight Logic
Continuation of halted discussion at #929 

I propose having `lines=1` by default, always having autoheight logic for `textbox` component to increase its size with the incoming input. What are your thoughts @abidlabs @aliabid94 @pngwn?


```
@abidlabs @pngwn I think having input textbox lines dynamically changing would be great as well. It would make it much more less cumbersome, WDYT?

Guess it depends how picky users are about how the component is laid out. We could use the autoheight logic when a lines value isn't provided?

Yeah I thought the same thing at first, then later thought what about respecting the line size initially and let the line size increase when input does not fit in.
Btw the default lines value is 1 currently, but we could change it.
```


Discussion:
I don't have a strong opinion on this. I can see how increasing the input textbox height can be useful in some cases, but in other cases (imagine a large text that is copy-pasted), then it could lead to the textbox becoming very large and crowding out the other components.
> I don't have a strong opinion on this. I can see how increasing the input textbox height can be useful in some cases, but in other cases (imagine a large text that is copy-pasted), then it could lead to the textbox becoming very large and crowding out the other components.

Is large text a use case though?
If it is then we shan't enable it by default or make it closable by parameters. 
Then how does this sound?

- If lines is not provided we make it autoheight
- If autoheight is True, we make it autoheight
- otherwise autoHeight is False
We could also set a max pretty easily.
Then what about taking
- lines as min
- max_lines as max
- autoheight is enabled by default, only disabled when it is `autoheight=False`
I assume that should be `autoheight=False` above. 

Otherwise, seems reasonable. 

I think we can wait until after 3.0 as this doesn't seem be urgent.
Would like to include in 3.0 if it is a short work from frontend perspective. Otherwise can wait in low priority.
Frontend logic is already there really (for outputs), just needs hooking up to whatever param we want to use to control it. I think there should be a default max_height/ max_lines otherwise weird stuff might happen. Probably around 10.

Ok then, I will update accordingly.
Sorry one quick thing:

If we have a `lines` parameter and a `max_lines` parameter, do we need `autoheight`? We can just allow a user to block auto-adjusting by setting `max_lines` equal to `lines`? We can cutdown on one unnecessary parameter and prevent parameter settings from clashing
Agree with @abidlabs, lets use `lines` as max_lines.

Proposal:

autoheight is enabled by default:

- when autoheight is True, min_lines is 1 and max_lines is `lines`
- when autoheight is False, min_lines = max_lines = `lines`

How does this sound @abidlabs and @pngwn?
Actually, I wasn't suggesting using `lines` as `max_lines`. I was saying to drop the `autoheight` parameter, because that can be inferred from the value of `lines` and `max_lines`.

* We should use `lines` as the number of lines that are shown by default (aka the minimum height), because that's the current behavior and we don't want to break that
* We can add `max_lines` to mean the biggest that the `Textbox` can become. By default, this could be equal to `None`, which means that the textbox can become arbitrarily large. If the user does not want resizing, they can simply set this equal to `lines`
Makes sense, I support this, what about you @pngwn?

> Actually, I wasn't suggesting using `lines` as `max_lines`. I was saying to drop the `autoheight` parameter, because that can be inferred from the value of `lines` and `max_lines`.
> 
>     * We should use `lines` as the number of lines that are shown by default (aka the minimum height), because that's the current behavior and we don't want to break that
> 
>     * We can add `max_lines` to mean the biggest that the `Textbox` can become. By default, this could be equal to `None`, which means that the textbox can become arbitrarily large. If the user does not want resizing, they can simply set this equal to `lines`


Moving this to 3.0 milestone since it is implemented in the backend #1009, feel free to move it to 2023 milestone.

Resolving patch:
diff --git a/demo/gpt_j/run.py b/demo/gpt_j/run.py
--- a/demo/gpt_j/run.py
+++ b/demo/gpt_j/run.py
@@ -10,7 +10,7 @@
 
 demo = gr.Interface.load(
     "huggingface/EleutherAI/gpt-j-6B",
-    inputs=gr.Textbox(lines=5, label="Input Text"),
+    inputs=gr.Textbox(lines=5, max_lines=6, label="Input Text"),
     title=title,
     examples=examples,
 )


Test patch:
diff --git a/ui/packages/app/src/components/Textbox/Textbox.test.ts b/ui/packages/app/src/components/Textbox/Textbox.test.ts
--- a/ui/packages/app/src/components/Textbox/Textbox.test.ts
+++ b/ui/packages/app/src/components/Textbox/Textbox.test.ts
@@ -9,26 +9,26 @@ describe("Textbox", () => {
 	afterEach(() => cleanup());
 
 	test("renders provided value", () => {
-		const { container, getByLabelText } = render(Textbox, {
+		const { getByDisplayValue } = render(Textbox, {
 			lines: 1,
 			mode: "dynamic",
 			value: "hello world",
 			label: "Textbox"
 		});
 
-		const item: HTMLInputElement = getByLabelText("Textbox");
+		const item: HTMLInputElement = getByDisplayValue("hello world");
 		assert.equal(item.value, "hello world");
 	});
 
 	test("changing the text should update the value", async () => {
-		const { component, getByLabelText } = render(Textbox, {
+		const { component, getByLabelText, getByDisplayValue } = render(Textbox, {
 			lines: 1,
 			mode: "dynamic",
-			value: "",
+			value: "hi ",
 			label: "Textbox"
 		});
 
-		const item: HTMLInputElement = getByLabelText("Textbox");
+		const item: HTMLInputElement = getByDisplayValue("hi");
 
 		const mock = spy();
 		component.$on("change", mock);
@@ -39,22 +39,9 @@ describe("Textbox", () => {
 		// wait for debounce
 		await wait(300);
 
-		assert.equal(item.value, "some text");
-		assert.equal(component.value, "some text");
+		assert.equal(item.value, "hi some text");
+		assert.equal(component.value, "hi some text");
 		assert.equal(mock.callCount, 1);
-		assert.equal(mock.calls[0][0].detail, "some text");
-	});
-
-	test("component should respect placeholder", async () => {
-		const { getByLabelText } = render(Textbox, {
-			lines: 1,
-			mode: "dynamic",
-			value: "",
-			placeholder: "placeholder text",
-			label: "Textbox"
-		});
-
-		const item: HTMLInputElement = getByLabelText("Textbox");
-		assert.equal(item.placeholder, "placeholder text");
+		assert.equal(mock.calls[0][0].detail, "hi some text");
 	});
 });