fixed textarea scrolling

This commit is contained in:
Lucas Oliveira 2025-10-02 17:33:35 -03:00
parent ae98857cf7
commit 80ac15edbb
3 changed files with 88 additions and 13 deletions

View file

@ -44,6 +44,7 @@
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-syntax-highlighter": "^15.6.1",
"react-textarea-autosize": "^8.5.9",
"rehype-mathjax": "^7.1.0",
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.1",
@ -8473,6 +8474,23 @@
"react": ">= 0.14.0"
}
},
"node_modules/react-textarea-autosize": {
"version": "8.5.9",
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.9.tgz",
"integrity": "sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.20.13",
"use-composed-ref": "^1.3.0",
"use-latest": "^1.2.1"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@ -10126,6 +10144,51 @@
}
}
},
"node_modules/use-composed-ref": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.4.0.tgz",
"integrity": "sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-isomorphic-layout-effect": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz",
"integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-latest": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.3.0.tgz",
"integrity": "sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==",
"license": "MIT",
"dependencies": {
"use-isomorphic-layout-effect": "^1.1.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-sidecar": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",

View file

@ -45,6 +45,7 @@
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-syntax-highlighter": "^15.6.1",
"react-textarea-autosize": "^8.5.9",
"rehype-mathjax": "^7.1.0",
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.1",

View file

@ -17,6 +17,7 @@ import {
Zap,
} from "lucide-react";
import { useEffect, useRef, useState } from "react";
import TextareaAutosize from "react-textarea-autosize";
import { filterAccentClasses } from "@/components/knowledge-filter-panel";
import { MarkdownRenderer } from "@/components/markdown-renderer";
import { ProtectedRoute } from "@/components/protected-route";
@ -132,6 +133,7 @@ function ChatPage() {
const [availableFilters, setAvailableFilters] = useState<
KnowledgeFilterData[]
>([]);
const [textareaHeight, setTextareaHeight] = useState(40);
const [filterSearchTerm, setFilterSearchTerm] = useState("");
const [selectedFilterIndex, setSelectedFilterIndex] = useState(0);
const [isFilterHighlighted, setIsFilterHighlighted] = useState(false);
@ -2024,14 +2026,16 @@ function ChatPage() {
setIsFilterDropdownOpen(true);
setFilterSearchTerm("");
setSelectedFilterIndex(0);
// Get button position for popover anchoring
const button = document.querySelector('[data-filter-button]') as HTMLElement;
const button = document.querySelector(
"[data-filter-button]",
) as HTMLElement;
if (button) {
const rect = button.getBoundingClientRect();
setAnchorPosition({
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2 - 12
y: rect.top + rect.height / 2 - 12,
});
}
} else {
@ -2256,18 +2260,29 @@ function ChatPage() {
</span>
</div>
)}
<textarea
<div className="relative" style={{height: `${textareaHeight + 60}px`}}>
<TextareaAutosize
ref={inputRef}
value={input}
onChange={onChange}
onKeyDown={handleKeyDown}
onHeightChange={(height) => setTextareaHeight(height)}
maxRows={7}
minRows={2}
placeholder="Type to ask a question..."
disabled={loading}
className={`w-full bg-transparent px-4 ${
selectedFilter ? "py-2 pb-4" : "py-4"
} min-h-[100px] focus-visible:outline-none resize-none`}
rows={1}
selectedFilter ? "pt-2" : "pt-4"
} focus-visible:outline-none resize-none`}
rows={2}
/>
{/* Safe area at bottom for buttons */}
<div
className="absolute bottom-0 left-0 right-0 bg-transparent pointer-events-none"
style={{ height: '60px' }}
/>
</div>
</div>
<input
ref={fileInputRef}
@ -2344,9 +2359,7 @@ function ChatPage() {
>
<span>No knowledge filter</span>
{!selectedFilter && (
<Check
className="h-4 w-4 shrink-0"
/>
<Check className="h-4 w-4 shrink-0" />
)}
</button>
)}
@ -2376,9 +2389,7 @@ function ChatPage() {
)}
</div>
{selectedFilter?.id === filter.id && (
<Check
className="h-4 w-4 shrink-0"
/>
<Check className="h-4 w-4 shrink-0" />
)}
</button>
))}