From a32932c2137ba7ab5b09c20d0762392ed71c7178 Mon Sep 17 00:00:00 2001 From: shivam <91240327+shivamhwp@users.noreply.github.com> Date: Wed, 11 Nov 2026 13:14:43 +0000 Subject: [PATCH 1/6] fix(web): composer notice buttons line up under the title when they wrap On a narrow composer a notice's buttons wrap to a second line. That line was pushed to the right edge, so the buttons sat under nothing. They now start under the title, and the dismiss button and the "+N" count stay at the row's end. A title too long for the first line also stays beside its icon instead of dropping below it. Co-Authored-By: Claude Fable 5.2 --- apps/web/src/components/chat/ComposerBanner.tsx | 6 ++++-- .../src/components/chat/ComposerBannerStack.tsx | 16 ++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/web/src/components/chat/ComposerBanner.tsx b/apps/web/src/components/chat/ComposerBanner.tsx index 1422f0d580390..261c75763ec51 100644 --- a/apps/web/src/components/chat/ComposerBanner.tsx +++ b/apps/web/src/components/chat/ComposerBanner.tsx @@ -133,8 +133,9 @@ function Row({ "group/banner-row grid min-h-4 w-full min-w-0 grid-cols-[var(--composer-banner-icon-column)_minmax(0,1fr)_auto] items-center gap-x-2 text-start", "not-has-[>[data-slot=composer-banner-actions]]:grid-cols-[var(--composer-banner-icon-column)_minmax(0,1fr)]", "[&:is(button)]:cursor-pointer [&:is(button)]:rounded-xl [&:is(button)]:hover:bg-foreground/5 [&:is(button)]:focus-visible:outline-2 [&:is(button)]:focus-visible:-outline-offset-2 [&:is(button)]:focus-visible:outline-ring", + // The icon hangs in the row's start padding, so actions that wrap start under the title. layout === "wrap-actions" && - "flex flex-wrap *:data-[slot=composer-banner-content]:max-w-[calc(100%-var(--composer-banner-icon-column)-var(--spacing))] *:data-[slot=composer-banner-content]:grow", + "flex flex-wrap ps-(--composer-banner-text-inset) [--composer-banner-text-inset:calc(var(--composer-banner-icon-column)+--spacing(2))] *:data-[slot=composer-banner-content]:max-w-full *:data-[slot=composer-banner-content]:grow-999 *:data-[slot=composer-banner-icon]:-ms-(--composer-banner-text-inset)", layout === "approval" && "items-start gap-x-2 gap-y-3", className, ), @@ -189,7 +190,8 @@ function Actions({ className, ...props }: ComponentProps<"span">) { className={cn( "col-start-3 row-start-1 flex flex-wrap items-center justify-end gap-1.5", "group-data-[composer-banner-layout=approval]/banner-row:self-center @max-[560px]:group-data-[composer-banner-layout=approval]/banner-row:col-start-2 @max-[560px]:group-data-[composer-banner-layout=approval]/banner-row:col-end-4 @max-[560px]:group-data-[composer-banner-layout=approval]/banner-row:row-start-2", - "group-data-[composer-banner-layout=wrap-actions]/banner-row:ms-auto", + // Beside the title this is as wide as its buttons; wrapped, it fills the line. + "group-data-[composer-banner-layout=wrap-actions]/banner-row:grow group-data-[composer-banner-layout=wrap-actions]/banner-row:justify-start", className, )} {...props} diff --git a/apps/web/src/components/chat/ComposerBannerStack.tsx b/apps/web/src/components/chat/ComposerBannerStack.tsx index 597168973d7f8..3196c71d592db 100644 --- a/apps/web/src/components/chat/ComposerBannerStack.tsx +++ b/apps/web/src/components/chat/ComposerBannerStack.tsx @@ -249,13 +249,17 @@ function NoticeCard({ {item.actions || item.onDismiss || overflow ? ( - {overflow} {item.actions} - {item.onDismiss ? ( - + {overflow || item.onDismiss ? ( + + {overflow} + {item.onDismiss ? ( + + ) : null} + ) : null} ) : null} From 6ac10c5fb05c3a2e5c4785538c28c649d471b3c9 Mon Sep 17 00:00:00 2001 From: shivam <91240327+shivamhwp@users.noreply.github.com> Date: Thu, 12 Nov 2026 02:02:29 +0000 Subject: [PATCH 2/6] fix(web): notice dismiss stays on the title line when buttons wrap The X and the +N count now sit beside the title, and a notice with a description shows one details button that carries the title too. Co-Authored-By: Claude Opus 5.5 --- .../src/components/chat/ComposerBanner.tsx | 8 +- .../components/chat/ComposerBannerStack.tsx | 86 +++++++++++-------- 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/apps/web/src/components/chat/ComposerBanner.tsx b/apps/web/src/components/chat/ComposerBanner.tsx index 261c75763ec51..7418a436db49f 100644 --- a/apps/web/src/components/chat/ComposerBanner.tsx +++ b/apps/web/src/components/chat/ComposerBanner.tsx @@ -133,9 +133,8 @@ function Row({ "group/banner-row grid min-h-4 w-full min-w-0 grid-cols-[var(--composer-banner-icon-column)_minmax(0,1fr)_auto] items-center gap-x-2 text-start", "not-has-[>[data-slot=composer-banner-actions]]:grid-cols-[var(--composer-banner-icon-column)_minmax(0,1fr)]", "[&:is(button)]:cursor-pointer [&:is(button)]:rounded-xl [&:is(button)]:hover:bg-foreground/5 [&:is(button)]:focus-visible:outline-2 [&:is(button)]:focus-visible:-outline-offset-2 [&:is(button)]:focus-visible:outline-ring", - // The icon hangs in the row's start padding, so actions that wrap start under the title. - layout === "wrap-actions" && - "flex flex-wrap ps-(--composer-banner-text-inset) [--composer-banner-text-inset:calc(var(--composer-banner-icon-column)+--spacing(2))] *:data-[slot=composer-banner-content]:max-w-full *:data-[slot=composer-banner-content]:grow-999 *:data-[slot=composer-banner-icon]:-ms-(--composer-banner-text-inset)", + // Buttons wrap below the title, so the icon and the end controls hold the first line. + layout === "wrap-actions" && "items-start", layout === "approval" && "items-start gap-x-2 gap-y-3", className, ), @@ -157,6 +156,7 @@ function Icon({ className, ...props }: ComponentProps<"span">) { className={cn( "col-start-1 row-start-1 flex w-(--composer-banner-icon-column) min-w-0 flex-none items-center justify-center text-(--surface-tint) [&>svg]:size-3", "group-data-[composer-banner-layout=approval]/banner-row:pt-0.5 group-data-[composer-banner-layout=approval]/banner-row:text-warning-foreground group-data-[composer-banner-layout=approval]/banner-row:[&>svg]:size-[13px]", + "group-data-[composer-banner-layout=wrap-actions]/banner-row:h-7 sm:group-data-[composer-banner-layout=wrap-actions]/banner-row:h-6", className, )} {...props} @@ -190,8 +190,6 @@ function Actions({ className, ...props }: ComponentProps<"span">) { className={cn( "col-start-3 row-start-1 flex flex-wrap items-center justify-end gap-1.5", "group-data-[composer-banner-layout=approval]/banner-row:self-center @max-[560px]:group-data-[composer-banner-layout=approval]/banner-row:col-start-2 @max-[560px]:group-data-[composer-banner-layout=approval]/banner-row:col-end-4 @max-[560px]:group-data-[composer-banner-layout=approval]/banner-row:row-start-2", - // Beside the title this is as wide as its buttons; wrapped, it fills the line. - "group-data-[composer-banner-layout=wrap-actions]/banner-row:grow group-data-[composer-banner-layout=wrap-actions]/banner-row:justify-start", className, )} {...props} diff --git a/apps/web/src/components/chat/ComposerBannerStack.tsx b/apps/web/src/components/chat/ComposerBannerStack.tsx index 3196c71d592db..9ecd82eb09fcf 100644 --- a/apps/web/src/components/chat/ComposerBannerStack.tsx +++ b/apps/web/src/components/chat/ComposerBannerStack.tsx @@ -103,11 +103,13 @@ export function NoticeText({ className, detailsLabel, details, + detailsHeading, }: { readonly children: ReactNode; readonly className: string; readonly detailsLabel: string; readonly details?: ReactNode; + readonly detailsHeading?: ReactNode; }) { const textRef = useRef(null); const detailsRef = useRef(null); @@ -194,7 +196,10 @@ export function NoticeText({ side="top" className="max-w-[min(30rem,calc(100vw-2rem))] whitespace-normal wrap-anywhere [--inline-button-text-align:start] [--inline-button-white-space:normal] [&_[data-slot=inline-button]]:max-w-full" > - {details ?? children} + + {detailsHeading} + {details ?? children} + ) : null} @@ -222,44 +227,49 @@ function NoticeCard({ > {item.icon} - - - {item.title} - - {item.description ? ( - - {item.description} - + + + {item.description ? ( + <> + {item.title} + {item.title}} + className="w-0 min-w-0 grow truncate font-medium text-muted-foreground @max-[400px]:sr-only" + > + {item.description} + + + ) : ( + + {item.title} + + )} + + {item.actions ? ( + {item.actions} ) : null} - - {item.actions || item.onDismiss || overflow ? ( - - {item.actions} - {overflow || item.onDismiss ? ( - - {overflow} - {item.onDismiss ? ( - - ) : null} - + + {overflow || item.onDismiss ? ( + + {overflow} + {item.onDismiss ? ( + ) : null} ) : null} From b240add0694c45c7088eaa847c144ca3e584141e Mon Sep 17 00:00:00 2001 From: shivam <91240327+shivamhwp@users.noreply.github.com> Date: Thu, 12 Nov 2026 02:41:28 +0000 Subject: [PATCH 3/6] fix(web): narrow notices stack their description and buttons under the title Below 480px a notice shows its title and dismiss on the first line, then its description in full and its buttons, all from the title's edge. The details button is gone there because nothing is cut off. Co-Authored-By: Claude Opus 5.5 --- .../web/src/components/chat/ComposerBanner.tsx | 1 - .../components/chat/ComposerBannerStack.tsx | 18 +++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/web/src/components/chat/ComposerBanner.tsx b/apps/web/src/components/chat/ComposerBanner.tsx index 7418a436db49f..259165109ad19 100644 --- a/apps/web/src/components/chat/ComposerBanner.tsx +++ b/apps/web/src/components/chat/ComposerBanner.tsx @@ -156,7 +156,6 @@ function Icon({ className, ...props }: ComponentProps<"span">) { className={cn( "col-start-1 row-start-1 flex w-(--composer-banner-icon-column) min-w-0 flex-none items-center justify-center text-(--surface-tint) [&>svg]:size-3", "group-data-[composer-banner-layout=approval]/banner-row:pt-0.5 group-data-[composer-banner-layout=approval]/banner-row:text-warning-foreground group-data-[composer-banner-layout=approval]/banner-row:[&>svg]:size-[13px]", - "group-data-[composer-banner-layout=wrap-actions]/banner-row:h-7 sm:group-data-[composer-banner-layout=wrap-actions]/banner-row:h-6", className, )} {...props} diff --git a/apps/web/src/components/chat/ComposerBannerStack.tsx b/apps/web/src/components/chat/ComposerBannerStack.tsx index 9ecd82eb09fcf..ea9f9deb58a9d 100644 --- a/apps/web/src/components/chat/ComposerBannerStack.tsx +++ b/apps/web/src/components/chat/ComposerBannerStack.tsx @@ -181,6 +181,7 @@ export function NoticeText({ render={