state.notice);
const keybindings = useAtomValue(primaryServerKeybindingsAtom);
- const summary = notice ? threadUndoNoticeSummary(notice) : null;
+ // Short enough to fit beside the utility icons; screen readers hear the full summary.
+ const summary = notice
+ ? notice.count === 1
+ ? notice.action
+ : `${notice.action} ${notice.count}`
+ : null;
// Keeps the last text on screen while it fades out, then unmounts on transitionend.
const [shownSummary, setShownSummary] = useState(summary);
@@ -23,21 +29,23 @@ export function SidebarThreadUndoNotice({ className }: { className?: string }) {
if (!text) return null;
return (
- {
- if (!summary && event.target === event.currentTarget) setShownSummary(null);
- }}
- className={cn(
- "flex gap-1 px-2 text-2xs leading-6 text-sidebar-muted-foreground transition-opacity duration-200 ease-out starting:opacity-0",
- !summary && "opacity-0",
- className,
- )}
- >
- {text},
- {threadUndoLabel(keybindings)}
-
+ // No min-w-0: the undo button sets this item's minimum, so a shared row squeezes its neighbour.
+
+ {
+ if (!summary && event.target === event.currentTarget) setShownSummary(null);
+ }}
+ // Reversed wrap: a summary that does not fit beside the undo button drops to a
+ // second line that overflow hides, instead of truncating mid-word. Browse mode
+ // reads the button first; the live announcement carries the full sentence.
+ className={cn(
+ "flex h-6 min-w-0 flex-1 flex-row-reverse flex-wrap gap-x-1 overflow-hidden text-2xs leading-6 whitespace-nowrap text-sidebar-muted-foreground transition-opacity duration-200 ease-out starting:opacity-0",
+ !summary && "opacity-0",
+ )}
+ >
+ {threadUndoLabel(keybindings)}
+ {text},
+
+
);
}
diff --git a/apps/web/src/hooks/showThreadUndoNotice.ts b/apps/web/src/hooks/showThreadUndoNotice.ts
index 5b6b68826fdea..977dcd68d1ab7 100644
--- a/apps/web/src/hooks/showThreadUndoNotice.ts
+++ b/apps/web/src/hooks/showThreadUndoNotice.ts
@@ -28,7 +28,7 @@ type UndoNotice = {
export const useThreadUndoNotice = create<{ notice: UndoNotice | null }>(() => ({ notice: null }));
-export function threadUndoNoticeSummary(notice: Pick): string {
+function threadUndoNoticeSummary(notice: Pick): string {
const noun = notice.action === "Discarded" ? "draft" : "thread";
return `${notice.action} ${notice.count} ${noun}${notice.count === 1 ? "" : "s"}`;
}