From af850852cd61cfb9a413d47902a6a877164ddbd0 Mon Sep 17 00:00:00 2001 From: Pier-Luc Gendreau Date: Fri, 2 May 2025 07:21:24 -0400 Subject: [PATCH] feat: add toast index to ToastRegion render props This is useful when toasts can be rendered differently based on their index in the queue. For example, when multiple toasts are displayed, the first one could be on top, and the others could be rendered behind it, and apply transforms (i.e. scale) so toasts beyond the first one appear smaller. --- packages/react-aria-components/src/Toast.tsx | 8 ++-- .../react-aria-components/test/Toast.test.js | 48 +++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/react-aria-components/src/Toast.tsx b/packages/react-aria-components/src/Toast.tsx index 391163227b8..821215d710b 100644 --- a/packages/react-aria-components/src/Toast.tsx +++ b/packages/react-aria-components/src/Toast.tsx @@ -48,7 +48,7 @@ export interface ToastRegionProps extends AriaToastRegionProps, StyleRenderPr /** The queue of toasts to display. */ queue: ToastQueue, /** A function to render each toast, or children containing a ``. */ - children: ReactNode | ((renderProps: {toast: QueuedToast}) => ReactElement) + children: ReactNode | ((renderProps: {toast: QueuedToast, index: number}) => ReactElement) } /** @@ -106,7 +106,7 @@ export const ToastRegion = /*#__PURE__*/ (forwardRef as forwardRefType)(function export interface ToastListProps extends Omit, 'queue' | 'children'> { /** A function to render each toast. */ - children: (renderProps: {toast: QueuedToast}) => ReactElement + children: (renderProps: {toast: QueuedToast; index: number}) => ReactElement } export const ToastList = /*#__PURE__*/ (forwardRef as forwardRefType)(function ToastList(props: ToastListProps, ref: ForwardedRef) { @@ -126,9 +126,9 @@ export const ToastList = /*#__PURE__*/ (forwardRef as forwardRefType)(function T return (
    - {state.visibleToasts.map((toast) => ( + {state.visibleToasts.map((toast, index) => (
  1. - {props.children({toast})} + {props.children({toast, index})}
  2. ))}
diff --git a/packages/react-aria-components/test/Toast.test.js b/packages/react-aria-components/test/Toast.test.js index d0e63d0746a..ebafd378f58 100644 --- a/packages/react-aria-components/test/Toast.test.js +++ b/packages/react-aria-components/test/Toast.test.js @@ -250,6 +250,54 @@ describe('Toast', () => { expect(document.activeElement).toBe(button); }); + it('should provide toast index', async () => { + const queue = new ToastQueue(); + function ToastToggle() { + return ( + <> + + {({toast, index}) => ( + + + {`${toast.content}: ${index}`} + + + + )} + + + + ); + } + + let {getByText, getAllByRole, queryByRole} = render(); + let button = getByRole('button'); + + await user.click(button); + + act(() => jest.advanceTimersByTime(100)); + let toasts = getAllByRole('alertdialog'); + expect(toasts).toHaveLength(3); + + expect(getByText('First toast: 0')).toBeVisible(); + expect(getByText('Second toast: 1')).toBeVisible(); + expect(getByText('Third toast: 2')).toBeVisible(); + + await user.click(button); + expect(queryByRole('alertdialog')).toBeNull(); + }); + it('should support programmatically closing toasts', async () => { const queue = new ToastQueue(); function ToastToggle() {