fix(coach): centre the composer text in its input pill

On a phone the placeholder sat noticeably low. The composer row was
bottom-aligned so the send button would stay beside the last line as the
textarea grows, but that also bottom-aligned a single-line textarea against
a 44 px touch target: 7 px of space above the text and 1 px below.

The row centres its textarea now and the controls keep their own bottom
alignment, so both properties hold. Measured empty, one line and four
lines, phone and desktop: the single-line gap goes 7/1 to 4/4 on a phone
and 2/1 to 2/2 on desktop, and the multi-line case is unchanged with the
send button still level with the last line.
This commit is contained in:
Marc-André Bombeck committed 2026-08-07 16:39:50 +02:00
1 parent c60aa6f9b1
commit d7a95874c2
2 files changed
+17 -7

No files matched your search

@@ -267,11 +267,15 @@ describe("<CoachInput>", () => {
expect(controls?.[0]).not.toMatch(/\bjustify-between\b/);
expect(controls?.[0]).toMatch(/\bshrink-0\b/);
// And the row itself is a row at every width, bottom-aligned so the send
// button stays beside the last line as the textarea grows.
// And the row itself is a row at every width. The textarea is centred in
// it — bottom-aligning a one-line textarea against a 44 px tap target left
// the placeholder sitting visibly low in the pill — while the controls
// keep their own bottom alignment, so the send button stays beside the
// LAST line as the textarea grows rather than drifting to the middle.
const shell = html.match(/<div[^>]*class="[^"]*\bflex-row\b[^"]*"[^>]*>/);
expect(shell?.[0]).toMatch(/\bitems-end\b/);
expect(shell?.[0]).toMatch(/\bitems-center\b/);
expect(shell?.[0]).not.toMatch(/\bflex-col\b/);
expect(controls?.[0]).toMatch(/\bself-end\b/);
});
it("sizes the hub actions trigger to the 44px tap-target floor on phones", () => {
@@ -427,9 +427,15 @@ export function CoachInput({
// hold: focus follows DOM order, and the DOM order (textarea,
// actions, Send) is identical in both layouts. Nothing jumps.
//
// `items-end` keeps the controls beside the LAST line as the textarea
// grows, so the send button stays where the thumb left it.
"flex flex-row items-end gap-1.5 p-1.5",
// `items-center` with the controls pinned `self-end` below. The row
// used to be `items-end` throughout, which bottom-aligned an empty
// one-line textarea against a 44 px touch target: the placeholder sat
// roughly 6 px low in the pill, reading as if the text had slipped.
// Centring the textarea fixes the empty and single-line cases, and
// `self-end` on the controls preserves the reason `items-end` was
// there — as the textarea grows, the send button stays beside the
// LAST line rather than drifting to the middle.
"flex flex-row items-center gap-1.5 p-1.5",
)}
>
<textarea
@@ -455,7 +461,7 @@ export function CoachInput({
/>
<div
data-slot="coach-input-controls"
className="order-2 flex shrink-0 items-center gap-1.5"
className="order-2 flex shrink-0 items-center gap-1.5 self-end"
>
<div
data-slot="coach-input-leading"