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();
     }
   }