Skip to content

Commit abb3020

Browse files
committed
feat(toast): handle duration prop
1 parent 7a99597 commit abb3020

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { useEffect, useRef } from 'react';
2+
3+
/**
4+
* Hook to handle automatic toast dismissal based on duration
5+
*
6+
* @param duration - Duration in milliseconds before the toast automatically disappears
7+
* @param id - The unique ID of the toast
8+
* @param hide - Function to hide the toast
9+
*
10+
* @example
11+
* ```tsx
12+
* useToastDuration(4000, toastId, hide);
13+
* ```
14+
*/
15+
export function useToastDuration(
16+
duration: number | null | undefined,
17+
id: string | undefined,
18+
hide: ((ids?: string | string[]) => void) | undefined
19+
): void {
20+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
21+
22+
useEffect(() => {
23+
// Clear any existing timeout
24+
if (timeoutRef.current) {
25+
clearTimeout(timeoutRef.current);
26+
timeoutRef.current = null;
27+
}
28+
29+
// Only set timeout if duration is valid and id/hide are available
30+
if (
31+
duration !== null &&
32+
duration !== undefined &&
33+
!isNaN(duration) &&
34+
duration > 0 &&
35+
duration !== Infinity &&
36+
id &&
37+
hide
38+
) {
39+
timeoutRef.current = setTimeout(() => {
40+
hide(id);
41+
}, duration);
42+
}
43+
44+
// Cleanup timeout on unmount or when duration/id/hide changes
45+
return () => {
46+
if (timeoutRef.current) {
47+
clearTimeout(timeoutRef.current);
48+
timeoutRef.current = null;
49+
}
50+
};
51+
}, [duration, id, hide]);
52+
}

src/components/toast/toast.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { cn } from '../../helpers/theme';
77
import type { ViewRef } from '../../helpers/types';
88
import { createContext } from '../../helpers/utils';
99
import * as ToastPrimitive from '../../primitives/toast';
10+
import type { ToastComponentProps } from '../../providers/toast';
1011
import { Button } from '../button';
1112
import { useToastRootAnimation } from './toast.animation';
1213
import { DISPLAY_NAME } from './toast.constants';
14+
import { useToastDuration } from './toast.hooks';
1315
import toastStyles, { styleSheet } from './toast.styles';
1416
import type {
1517
ToastActionProps,
@@ -39,9 +41,18 @@ const ToastRoot = forwardRef<ViewRef, ToastRootProps>((props, ref) => {
3941
className,
4042
style,
4143
animation,
44+
duration = 4000,
45+
hide,
4246
...restProps
4347
} = props;
4448

49+
// Access id from props (id is omitted from ToastRootProps type but available at runtime)
50+
const toastProps = props as ToastRootProps & Pick<ToastComponentProps, 'id'>;
51+
const { id } = toastProps;
52+
53+
// Handle automatic toast dismissal based on duration
54+
useToastDuration(duration, id, hide);
55+
4556
const tvStyles = toastStyles.root({
4657
className,
4758
});

src/components/toast/toast.types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ export interface ToastRootProps
105105
* @default 'top'
106106
*/
107107
placement?: ToastPlacement;
108+
/**
109+
* Duration in milliseconds before the toast automatically disappears
110+
* Set to `null` or `Infinity` to prevent auto-hide
111+
* @default 4000
112+
*/
113+
duration?: number | null;
108114
/**
109115
* Additional CSS class for the toast container
110116
*/

0 commit comments

Comments
 (0)