Make textarea in sketch-chat-input user-resizable
Fixes https://github.com/boldsoftware/sketch/issues/6
- Changed resize property from 'none' to 'vertical' to allow user resizing
- Increased max-height from 120px to 300px to allow more expansion
- Enhanced user experience by allowing them to resize the chat input according to their needs
- Automatically resize the textarea as the user types (up to max-height)
Co-Authored-By: sketch
diff --git a/loop/webui/src/web-components/sketch-chat-input.test.ts b/loop/webui/src/web-components/sketch-chat-input.test.ts
index e361ecd..de41c31 100644
--- a/loop/webui/src/web-components/sketch-chat-input.test.ts
+++ b/loop/webui/src/web-components/sketch-chat-input.test.ts
@@ -140,6 +140,25 @@
expect(content).toBe(testContent);
});
+test("resizes when user enters more text than will fit", async ({
+ mount,
+}) => {
+ const testContent = "Test message\n\n\n\n\n\n\n\n\n\n\n\n\nends here.";
+ const component = await mount(SketchChatInput, {
+ props: {
+ content: '',
+ },
+ });
+ const origHeight = await component.evaluate((el: SketchChatInput) => el.chatInput.style.height);
+
+ // Enter very tall text in the textarea
+ await component.locator("#chatInput").fill(testContent);
+
+ // Check that textarea resized
+ const newHeight = await component.evaluate((el: SketchChatInput) => el.chatInput.style.height);
+ expect(Number.parseInt(newHeight)).toBeGreaterThan(Number.parseInt(origHeight));
+});
+
test("updates content when receiving update-content event", async ({
mount,
}) => {
diff --git a/loop/webui/src/web-components/sketch-chat-input.ts b/loop/webui/src/web-components/sketch-chat-input.ts
index cf0229f..483fbf0 100644
--- a/loop/webui/src/web-components/sketch-chat-input.ts
+++ b/loop/webui/src/web-components/sketch-chat-input.ts
@@ -36,12 +36,15 @@
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
- resize: none;
+ resize: vertical;
font-family: monospace;
font-size: 12px;
min-height: 40px;
- max-height: 120px;
+ max-height: 300px;
background: #f7f7f7;
+ overflow-y: auto;
+ box-sizing: border-box; /* Ensure padding is included in height calculation */
+ line-height: 1.4; /* Consistent line height for better height calculation */
}
#sendChatButton {
@@ -80,6 +83,8 @@
) as HTMLTextAreaElement;
if (textarea) {
textarea.value = content;
+ // Adjust height after content is updated programmatically
+ requestAnimationFrame(() => this.adjustChatSpacing());
}
}
}
@@ -117,12 +122,23 @@
}
adjustChatSpacing() {
- console.log("TODO: adjustChatSpacing");
+ if (!this.chatInput) return;
+
+ // Reset height to minimal value to correctly calculate scrollHeight
+ this.chatInput.style.height = 'auto';
+
+ // Get the scroll height (content height)
+ const scrollHeight = this.chatInput.scrollHeight;
+
+ // Set the height to match content (up to max-height which is handled by CSS)
+ this.chatInput.style.height = `${scrollHeight}px`;
}
_sendChatClicked() {
this.sendChatMessage();
this.chatInput.focus(); // Refocus the input after sending
+ // Reset height after sending a message
+ requestAnimationFrame(() => this.adjustChatSpacing());
}
_chatInputKeyDown(event: KeyboardEvent) {
@@ -135,15 +151,18 @@
_chatInputChanged(event) {
this.content = event.target.value;
+ // Use requestAnimationFrame to ensure DOM updates have completed
requestAnimationFrame(() => this.adjustChatSpacing());
}
@query("#chatInput")
- private chatInput: HTMLTextAreaElement;
+ chatInput: HTMLTextAreaElement;
protected firstUpdated(): void {
if (this.chatInput) {
this.chatInput.focus();
+ // Initialize the input height
+ this.adjustChatSpacing();
}
}