feat(coach): replace the textarea hint footer with an info-icon tooltip

The composer rendered the keyboard-shortcut hint ("Enter to send,
Shift+Enter for new line") as a prose `<span>` directly under the
textarea. Combined with the disclaimer and the send button, the
footer ate ~140 px of vertical room for what is essentially a single-
sentence affordance.

Replace the `<span>` with an `Info` icon wrapped in a Radix `<Tooltip>`
sat left of the send button. The existing `composerHint` translation
surfaces both as the trigger's `aria-label` (so screen-readers still
hear it on focus) and as the tooltip body for sighted users on hover.
The slot `data-slot="coach-input-hint"` stays so consumers can still
target the affordance.
This commit is contained in:
Marc-André Bombeck committed 2026-05-15 16:47:25 +02:00
1 parent 4d88764e4f
commit fe18a8810c
2 files changed
+47 -11

No files matched your search

@@ -26,12 +26,19 @@ describe("<CoachInput>", () => {
expect(html).not.toContain("Coach replies are generated");
});
it("renders the localised placeholder + hint", () => {
it("renders the localised placeholder + the tooltip-trigger hint", () => {
// v1.4.27 F15 — the verbose prose hint footer was replaced by an
// Info icon wrapped in a tooltip. The same `composerHint`
// translation now surfaces as the trigger's `aria-label` (so
// screen-readers still announce it on focus) and as the tooltip
// body for sighted users on hover.
const html = render(
<CoachInput value="" onChange={() => {}} onSubmit={() => {}} />,
);
expect(html).toContain("Ask anything about your data");
expect(html).toContain("Press Enter to send");
expect(html).toMatch(
/aria-label="Press Enter to send[^"]*"\s+data-slot="coach-input-hint"/,
);
});
it("renders the German placeholder under the 'de' locale", () => {
@@ -7,9 +7,15 @@ import {
useEffect,
useRef,
} from "react";
import { Loader2, Send } from "lucide-react";
import { Info, Loader2, Send } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { useTranslations } from "@/lib/i18n/context";
@@ -174,19 +180,42 @@ export function CoachInput({
"placeholder:text-muted-foreground disabled:opacity-60",
)}
/>
<div className="mt-1.5 flex items-center gap-2">
<span
data-slot="coach-input-hint"
className="text-muted-foreground text-[11px]"
>
{t("insights.coach.composerHint")}
</span>
{/* v1.4.27 F15 — the verbose "Enter to send, Shift+Enter for
new line" prose footer used to render under the textarea;
it ate ~140 px of vertical room for an Apple-Health-like
single-message exchange. The hint now sits behind a tiny
Info icon left of the send button; the existing
translation string surfaces as the tooltip body so
screen-reader users still hear it on focus. */}
<div className="mt-1.5 flex items-center justify-end gap-2">
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
aria-label={t("insights.coach.composerHint")}
data-slot="coach-input-hint"
className={cn(
"text-muted-foreground hover:text-foreground",
"focus-visible:ring-ring/50 inline-flex h-7 w-7",
"items-center justify-center rounded",
"focus-visible:ring-2 focus-visible:outline-none",
)}
>
<Info className="size-3.5" aria-hidden="true" />
</button>
</TooltipTrigger>
<TooltipContent>
{t("insights.coach.composerHint")}
</TooltipContent>
</Tooltip>
</TooltipProvider>
<Button
type="submit"
size="sm"
disabled={!canSubmit}
data-slot="coach-input-send"
className="ml-auto gap-1.5"
className="gap-1.5"
>
{isStreaming ? (
<Loader2 className="size-3.5 animate-spin" aria-hidden="true" />