From a14a6e4514ab63d55d263552280b0b14ae86b8e1 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 14 Nov 2025 09:57:27 +0100 Subject: [PATCH] feat: enhance Toast component with customizable duration and improved styling --- src/components/toast/Toast.stories.tsx | 9 +++-- src/components/toast/Toast.style.scss | 56 +++++++++++++++++++++++--- src/components/toast/Toast.tsx | 14 +++++-- 3 files changed, 66 insertions(+), 13 deletions(-) diff --git a/src/components/toast/Toast.stories.tsx b/src/components/toast/Toast.stories.tsx index d202317b..f4b3e1eb 100644 --- a/src/components/toast/Toast.stories.tsx +++ b/src/components/toast/Toast.stories.tsx @@ -17,16 +17,17 @@ export const ExampleToast = () => { const renderToast = () => { toast({ - title: "Error", - color: "error", + title: "Cannot delete the last administrative role", + color: "warning", dismissible: true, - children: "INVALID_LOGIN_DATA", + duration: 10000, + children: Some content }) } return (
- + diff --git a/src/components/toast/Toast.style.scss b/src/components/toast/Toast.style.scss index 999fcfe6..1a418e88 100644 --- a/src/components/toast/Toast.style.scss +++ b/src/components/toast/Toast.style.scss @@ -1,10 +1,13 @@ @use "../../styles/helpers"; @use "../../styles/variables"; @use "../../styles/box"; +@use "sass:math"; .toast { padding: variables.$md; + width: 100%; + overflow: hidden; & { @include helpers.borderRadius(); @@ -14,7 +17,7 @@ &__header { align-items: flex-start; justify-content: space-between; - gap: variables.$xxs; + gap: variables.$xs; } &__icon { @@ -24,13 +27,13 @@ } &__content { - margin-top: variables.$xxs; box-sizing: border-box; + margin-left: 27px; } &__header-wrapper { - align-items: center; - gap: variables.$xxs; + align-items: flex-start; + gap: variables.$xs; > svg { min-width: variables.$md; @@ -51,8 +54,49 @@ } svg { - min-width: variables.$md; - min-height: variables.$md; + min-width: variables.$md; + min-height: variables.$md; + } + } + + @keyframes toast-duration { + from { + width: 0%; + } + to { + width: 100%; + } + } + + &:hover { + .toast__duration { + &:after { + animation-play-state: paused; + } + } + } + + &__duration { + position: relative; + margin: variables.$md (-1 * variables.$md) (-1 * variables.$md); + padding: variables.$xxs variables.$md (variables.$xxs + 0.25rem); + + & { + border-top: 1px solid helpers.borderColor(); + } + + &::after { + content: ""; + position: absolute; + left: 0; + bottom: 0; + width: 0%; // Start: leer + height: 4px; + background: helpers.borderColor(); + animation-name: toast-duration; + animation-duration: var(--toast-duration, 4000ms); + animation-timing-function: linear; + animation-fill-mode: forwards; } } } diff --git a/src/components/toast/Toast.tsx b/src/components/toast/Toast.tsx index 6c90e487..9dd3a461 100644 --- a/src/components/toast/Toast.tsx +++ b/src/components/toast/Toast.tsx @@ -24,6 +24,7 @@ export interface ToastProps extends Omit, "title" //defaults to false dismissible?: boolean onClose?: (event: React.MouseEvent) => void + duration?: number //defaults to 4000 } export function toast(toast: Omit) { @@ -31,18 +32,20 @@ export function toast(toast: Omit) { {toast.children} - )) + ), { + duration: toast.duration ?? 4000 + }) } export function Toast(props: ToastProps) { - const {dismissible = false, color = "secondary", title, onClose = () => {}, children, ...rest} = props + const {dismissible = false, color = "secondary", title, onClose = () => {}, children, duration = 4000, ...rest} = props return (
{color && } - {title} + {title} {dismissible && sonnerToast.dismiss(props.id)}> @@ -55,6 +58,11 @@ export function Toast(props: ToastProps) { {children}
} +
+ This message will close in {duration / 1000} seconds +
) }