MCPcopy
hub / github.com/simstudioai/sim / ToastProvider

Function ToastProvider

packages/emcn/src/components/toast/toast.tsx:387–640  ·  view source on GitHub ↗
({ children }: { children?: ReactNode })

Source from the content-addressed store, hash-verified

385 * ```
386 */
387export function ToastProvider({ children }: { children?: ReactNode }) {
388 const pathname = usePathname()
389 const reduceMotion = useReducedMotion() ?? false
390 /** On the workflow editor (`/w/[id]` and the `/w` index) the stack insets by `--panel-width` / `--terminal-height` to clear the panel and terminal. */
391 const isWorkflowPage = pathname ? /\/w(\/|$)/.test(pathname) : false
392
393 const [toasts, setToasts] = useState<ToastData[]>([])
394 const [heights, setHeights] = useState<Record<string, number>>({})
395 const [expanded, setExpanded] = useState(false)
396 const [mounted, setMounted] = useState(false)
397 const timersRef = useRef(new Map<string, ReturnType<typeof setTimeout>>())
398
399 useEffect(() => {
400 setMounted(true)
401 }, [])
402
403 /**
404 * Reset the hover-expanded flag whenever the stack empties. The hover wrapper
405 * unmounts without firing mouse-leave when the last toast goes (dismiss / clear
406 * / navigation), so without this `expanded` could stay `true` and stop the next
407 * toasts from auto-dismissing.
408 */
409 useEffect(() => {
410 if (toasts.length === 0) setExpanded(false)
411 }, [toasts.length])
412
413 /**
414 * Adds a toast. Actionable toasts persist (`duration: 0`) unless an explicit
415 * `duration` is given. When the stack exceeds `STACK_LIMIT` the oldest
416 * auto-dismissable toast is evicted first, so a persistent (actionable) toast
417 * isn't silently dropped — only an all-persistent overflow evicts the oldest.
418 */
419 const addToast = useCallback((input: ToastInput): string => {
420 const id = generateId()
421 const data: ToastData = {
422 id,
423 message: input.message,
424 description: input.description,
425 variant: input.variant ?? 'default',
426 action: input.action,
427 duration: input.duration ?? (input.action ? 0 : AUTO_DISMISS_MS),
428 persistAcrossRoutes: input.persistAcrossRoutes ?? false,
429 }
430 setToasts((prev) => {
431 const next = [...prev, data]
432 if (next.length <= STACK_LIMIT) return next
433 const evictIndex = next.findIndex((t) => t.duration > 0)
434 next.splice(evictIndex === -1 ? 0 : evictIndex, 1)
435 return next
436 })
437 return id
438 }, [])
439
440 const dismissToast = useCallback((id: string) => {
441 const timer = timersRef.current.get(id)
442 if (timer) {
443 clearTimeout(timer)
444 timersRef.current.delete(id)

Callers

nothing calls this directly

Calls 8

generateIdFunction · 0.90
createToastFnFunction · 0.85
testMethod · 0.80
containsMethod · 0.80
getMethod · 0.65
deleteMethod · 0.65
clearMethod · 0.65
setMethod · 0.65

Tested by

no test coverage detected