Repository: nextui-org/nextui
File: packages/components/toast/src/use-toast.ts (TypeScript)

Code before:
  useEffect(() => {
    if (progressBarRef.current) {
      progressBarRef.current.style.width = "0%";
    }
  }, []);

  const [isLoading, setIsLoading] = useState<boolean>(!!promiseProp);

  useEffect(() => {
    if (!promiseProp) return;
    promiseProp.finally(() => {
      setIsLoading(false);
    });
  }, [promiseProp]);

  useEffect(() => {
    const updateProgress = (timestamp: number) => {
      if (!timeout || isLoading) {
        return;
      }

      if (startTime.current === null) {
        startTime.current = timestamp;
      }

      if (isToastHovered || isRegionExpanded || index !== 0) {
        pausedTime.current += timestamp - startTime.current;
        startTime.current = null;
        animationRef.current = requestAnimationFrame(updateProgress);

        return;
      }

      const elapsed = timestamp - startTime.current + pausedTime.current;

      timeElapsed.current = elapsed;
      if (timeElapsed.current >= timeout) {
        state.close(toast.key);
      }

      progressRef.current = Math.min((elapsed / timeout) * 100, 100);

      if (progressBarRef.current) {
        progressBarRef.current.style.width = `${
          shouldShowTimeoutProgress ? progressRef.current : 0
        }%`;
      }

      if (progressRef.current < 100) {
        animationRef.current = requestAnimationFrame(updateProgress);
      }

Review comment (suggestion):
```suggestion
      if (isToastHovered || isRegionExpanded) {
```
Now since we are planning to remove the toast by FIFO, we can keep the timer running for all the toasts. This is because with the current implementation, first toast will close and then the timer for the second toast will start. The current implementation will have following: 

https://github.com/user-attachments/assets/e54f4f9c-1018-47ca-98fe-db99076405b4

But I think keeping the timer on for all the toast will make more sense.

Also you might have to look for the proper animation for the exiting. You can use `isToastExiting` for the same.

Code after:
  useEffect(() => {
    if (progressBarRef.current) {
      progressBarRef.current.style.width = "0%";
    }
  }, []);

  const [isLoading, setIsLoading] = useState<boolean>(!!promiseProp);
  const [isToastExiting, setIsToastExiting] = useState(false);

  useEffect(() => {
    if (!promiseProp) return;
    promiseProp.finally(() => {
      setIsLoading(false);
    });
  }, [promiseProp]);

  useEffect(() => {
    const updateProgress = (timestamp: number) => {
      if (!timeout || isLoading) {
        return;
      }

      if (startTime.current === null) {
        startTime.current = timestamp;
      }

      if (isToastHovered || isRegionExpanded) {
        pausedTime.current += timestamp - startTime.current;
        startTime.current = null;
        animationRef.current = requestAnimationFrame(updateProgress);

        return;
      }

      const elapsed = timestamp - startTime.current + pausedTime.current;

      timeElapsed.current = elapsed;
      if (timeElapsed.current >= timeout) {
        setIsToastExiting(true);
      }

      progressRef.current = Math.min((elapsed / timeout) * 100, 100);

      if (progressBarRef.current) {
        progressBarRef.current.style.width = `${
          shouldShowTimeoutProgress ? progressRef.current : 0
        }%`;
      }

      if (progressRef.current < 100) {
        animationRef.current = requestAnimationFrame(updateProgress);