authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-05 01:15:29-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-05 14:43:19-08:00
log95fcc89074d44518cded3adfa08dc18284c87fbe
treef789e69c8ebe16bc054b1e04ff9f194125a08741
parenteb59853596b9ea2547c1bde87d2cd9b59a6fef95

Prevent toast content overflow in collapsed stack

- Use the larger of shared stack height and per-toast height to avoid clipping - Make toast content columns flexible with `min-w-0` and `break-words` - Keep action buttons from shrinking so long text wraps instead of overflowing

1 files changed, 23 insertions(+), 11 deletions(-)

apps/web/src/components/ui/toast.tsx+23-11
......@@ -206,7 +206,10 @@ function Toasts({ position = "top-right" }: { position: ToastPosition }) {
206206 "data-[position*=top]:after:top-full",
207207 "data-[position*=bottom]:after:bottom-full",
208208 // Define some variables
209 "[--toast-calc-height:var(--toast-frontmost-height,var(--toast-height))] [--toast-gap:--spacing(3)] [--toast-peek:--spacing(3)] [--toast-scale:calc(max(0,1-(var(--toast-index)*.1)))] [--toast-shrink:calc(1-var(--toast-scale))]",
209 // Base UI exposes a shared front-most height for the collapsed stack.
210 // If that shared measurement is briefly stale, long content can render
211 // outside the card until hover expands the toast and swaps to its own height.
212 "[--toast-calc-height:max(var(--toast-frontmost-height,var(--toast-height)),var(--toast-height))] [--toast-gap:--spacing(3)] [--toast-peek:--spacing(3)] [--toast-scale:calc(max(0,1-(var(--toast-index)*.1)))] [--toast-shrink:calc(1-var(--toast-scale))]",
210213 // Define offset-y variable
211214 "data-[position*=top]:[--toast-calc-offset-y:calc(var(--toast-offset-y)+var(--toast-index)*var(--toast-gap)+var(--toast-swipe-movement-y))]",
212215 "data-[position*=bottom]:[--toast-calc-offset-y:calc(var(--toast-offset-y)*-1+var(--toast-index)*var(--toast-gap)*-1+var(--toast-swipe-movement-y))]",
......@@ -258,7 +261,7 @@ function Toasts({ position = "top-right" }: { position: ToastPosition }) {
258261 "not-data-expanded:pointer-events-none not-data-expanded:opacity-0",
259262 )}
260263 >
261 <div className="flex gap-2">
264 <div className="flex min-w-0 flex-1 gap-2">
262265 {Icon && (
263266 <div
264267 className="[&>svg]:h-lh [&>svg]:w-4 [&_svg]:pointer-events-none [&_svg]:shrink-0"
......@@ -268,16 +271,22 @@ function Toasts({ position = "top-right" }: { position: ToastPosition }) {
268271 </div>
269272 )}
270273
271 <div className="flex flex-col gap-0.5">
272 <Toast.Title className="font-medium" data-slot="toast-title" />
274 <div className="flex min-w-0 flex-1 flex-col gap-0.5">
275 <Toast.Title
276 className="min-w-0 break-words font-medium"
277 data-slot="toast-title"
278 />
273279 <Toast.Description
274 className="text-muted-foreground"
280 className="min-w-0 break-words text-muted-foreground"
275281 data-slot="toast-description"
276282 />
277283 </div>
278284 </div>
279285 {toast.actionProps && (
280 <Toast.Action className={buttonVariants({ size: "xs" })} data-slot="toast-action">
286 <Toast.Action
287 className={cn(buttonVariants({ size: "xs" }), "shrink-0")}
288 data-slot="toast-action"
289 >
281290 {toast.actionProps.children}
282291 </Toast.Action>
283292 )}
......@@ -341,7 +350,7 @@ function AnchoredToasts() {
341350 </Toast.Content>
342351 ) : (
343352 <Toast.Content className="pointer-events-auto flex items-center justify-between gap-1.5 overflow-hidden px-3.5 py-3 text-sm">
344 <div className="flex gap-2">
353 <div className="flex min-w-0 flex-1 gap-2">
345354 {Icon && (
346355 <div
347356 className="[&>svg]:h-lh [&>svg]:w-4 [&_svg]:pointer-events-none [&_svg]:shrink-0"
......@@ -351,17 +360,20 @@ function AnchoredToasts() {
351360 </div>
352361 )}
353362
354 <div className="flex flex-col gap-0.5">
355 <Toast.Title className="font-medium" data-slot="toast-title" />
363 <div className="flex min-w-0 flex-1 flex-col gap-0.5">
364 <Toast.Title
365 className="min-w-0 break-words font-medium"
366 data-slot="toast-title"
367 />
356368 <Toast.Description
357 className="text-muted-foreground"
369 className="min-w-0 break-words text-muted-foreground"
358370 data-slot="toast-description"
359371 />
360372 </div>
361373 </div>
362374 {toast.actionProps && (
363375 <Toast.Action
364 className={buttonVariants({ size: "xs" })}
376 className={cn(buttonVariants({ size: "xs" }), "shrink-0")}
365377 data-slot="toast-action"
366378 >
367379 {toast.actionProps.children}