ui: chat compose grows with content + better default size

- rows='1' → rows='3' so the compose box has presence even when empty
  (it was a one-line slit, easy to miss).
- Add `field-sizing: content` on .fb-compose__textarea so modern browsers
  (Chrome 123+ / Firefox 137+ / Safari 17.4+) auto-grow it to fit content
  natively. Cap at the existing max-height: 10rem with overflow-y: auto so
  long messages don't eat the bubbles scroll area.
- For older browsers: feature-detect via CSS.supports('field-sizing',
  'content'). When unsupported, an oninput handler sets style.height =
  scrollHeight + 'px' (capped at 160px). Modern browsers no-op the JS
  resizer to avoid fighting the native CSS rule.
- After send (chatBody → ''), an $effect clears the inline height so the
  textarea snaps back to rows='3'. Native field-sizing handles this on
  its own; the effect only fires on the JS-fallback path.
- Shorten placeholder to "Nachricht…" — the keyboard hint was chrome the
  user discovers on their own.
This commit is contained in:
mAi
2026-05-06 16:33:42 +02:00
parent 18644275f1
commit c261b8e75b
2 changed files with 32 additions and 2 deletions

View File

@@ -1835,6 +1835,11 @@ body { min-height: 100vh; }
min-height: 2.5rem;
max-height: 10rem;
resize: none;
overflow-y: auto;
/* Modern browsers (Chrome 123+ / Firefox 137+ / Safari 17.4+) auto-grow
the textarea to fit its content. Older browsers fall back to the JS
resizer in /f/[slug]/+page.svelte's autosizeCompose. */
field-sizing: content;
}
.fb-compose__send {

View File

@@ -56,6 +56,7 @@
let pollHandle: ReturnType<typeof setInterval> | null = null;
let lastSeenAt: string | null = null;
let chatListEl = $state<HTMLDivElement | null>(null);
let composeEl = $state<HTMLTextAreaElement | null>(null);
let results = $state<AggregatedResults | null>(null);
let resultsPollHandle: ReturnType<typeof setInterval> | null = null;
@@ -436,6 +437,28 @@
}
}
// Auto-grow the compose textarea with content. Modern browsers handle this
// natively via `field-sizing: content`; for older browsers we fall back to
// resizing on input. Capped at 10rem (160px) — matches .fb-compose__textarea.
const supportsFieldSizing =
typeof CSS !== 'undefined' && typeof CSS.supports === 'function'
? CSS.supports('field-sizing', 'content')
: false;
function autosizeCompose(el: HTMLTextAreaElement): void {
if (supportsFieldSizing) return;
el.style.height = 'auto';
el.style.height = `${Math.min(el.scrollHeight, 160)}px`;
}
// Reset the inline height after a send (chatBody → '') so the textarea
// snaps back to its rows="3" default. No-op when field-sizing handles it.
$effect(() => {
if (chatBody === '' && composeEl && !supportsFieldSizing) {
composeEl.style.height = '';
}
});
function onComposeKeydown(e: KeyboardEvent): void {
// Enter alone (no shift, no IME composition) sends. Shift+Enter inserts a newline.
// Cmd/Ctrl+Enter also sends — covers users who expect that shortcut.
@@ -800,11 +823,13 @@
>
<textarea
class="fb-textarea fb-compose__textarea"
placeholder="Dein Beitrag … (Enter zum Senden, Shift+Enter für Zeilenumbruch)"
placeholder="Nachricht…"
maxlength="2000"
bind:value={chatBody}
bind:this={composeEl}
onkeydown={onComposeKeydown}
rows="1"
oninput={(e) => autosizeCompose(e.currentTarget as HTMLTextAreaElement)}
rows="3"
></textarea>
<button
type="submit"