Improve chat's input UX

This commit is contained in:
dtonon 2026-06-15 13:54:48 +02:00
parent 30f52af4b1
commit fb74eda8a1
3 changed files with 94 additions and 11 deletions

View file

@ -0,0 +1,48 @@
import type { Action } from "svelte/action";
type AutogrowParams = {
// When false the action is inert, leaving the textarea at its native size.
enabled?: boolean;
// Max height in lines before the textarea starts scrolling.
maxRows?: number;
// A value to watch; resize is re-run whenever it changes (e.g. after a reset).
value?: unknown;
};
// Grow a textarea with its content up to maxRows lines, then scroll.
export const autogrow: Action<
HTMLTextAreaElement,
AutogrowParams | undefined
> = (node, params) => {
let enabled = params?.enabled ?? true;
let maxRows = params?.maxRows ?? 10;
function resize() {
if (!enabled) return;
const cs = getComputedStyle(node);
const lh = parseFloat(cs.lineHeight) || 20;
const vPad = parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom);
const vBorder =
parseFloat(cs.borderTopWidth) + parseFloat(cs.borderBottomWidth);
const max = lh * maxRows + vPad + vBorder;
node.style.height = "auto";
const next = Math.min(node.scrollHeight, max);
node.style.height = `${next}px`;
node.style.overflowY = node.scrollHeight > max ? "auto" : "hidden";
}
node.addEventListener("input", resize);
resize();
return {
update(next) {
enabled = next?.enabled ?? true;
maxRows = next?.maxRows ?? 10;
// Re-run on watched-value changes, including programmatic resets.
resize();
},
destroy() {
node.removeEventListener("input", resize);
},
};
};