diff --git a/packages/react-component-library/src/components/Toast/Toast.stories.tsx b/packages/react-component-library/src/components/Toast/Toast.stories.tsx
index 822369f6d1..5cada79a86 100644
--- a/packages/react-component-library/src/components/Toast/Toast.stories.tsx
+++ b/packages/react-component-library/src/components/Toast/Toast.stories.tsx
@@ -1,8 +1,9 @@
import React, { useEffect } from 'react'
import { Meta, StoryFn } from '@storybook/react'
-import { TOAST_APPEARANCE, Toast, ToastProps, showToast } from '.'
+import { TOAST_APPEARANCE, Toast, ToastProps, showToast, dismissToast } from '.'
import { Button } from '../Button'
+import { Group } from '../Group'
export default {
component: Toast,
@@ -31,13 +32,22 @@ const ToastButton = (props: ToastProps) => {
return (
-
+
+
+
+
)
}
diff --git a/packages/react-component-library/src/components/Toast/Toast.test.tsx b/packages/react-component-library/src/components/Toast/Toast.test.tsx
index f9690d6939..a4b16df6a8 100644
--- a/packages/react-component-library/src/components/Toast/Toast.test.tsx
+++ b/packages/react-component-library/src/components/Toast/Toast.test.tsx
@@ -1,8 +1,8 @@
import React from 'react'
import { color } from '@royalnavy/design-tokens'
-import { render, screen, waitFor, within } from '@testing-library/react'
+import { render, screen, within, waitFor } from '@testing-library/react'
-import { TOAST_APPEARANCE, Toast, showToast } from '.'
+import { TOAST_APPEARANCE, Toast, dismissToast, showToast } from '.'
const LABEL = 'Example label'
const MESSAGE = 'This is an example toast message'
@@ -19,12 +19,20 @@ function setup() {
/* Added this function to resolve an issue when running tests for
* the whole of this file and more than one toast is shown */
-async function getLastToast(lastToastLabel: string) {
- await waitFor(() => {
- expect(screen.getByText(lastToastLabel)).toBeInTheDocument()
- })
-
- return screen.getAllByRole('status')[0]
+async function getLastToast(label?: string) {
+ try {
+ const toasts = await screen.findAllByRole('status', {
+ name: label ? new RegExp(label, 'i') : undefined,
+ })
+
+ return toasts[0]
+ } catch (error) {
+ if (error instanceof Error && error.message.includes('Unable to find')) {
+ return null
+ }
+
+ throw error
+ }
}
it('renders the toast', async () => {
@@ -41,11 +49,11 @@ it('renders the toast', async () => {
const contentId = screen.getByText(MESSAGE).getAttribute('id')
expect(lastToast).toHaveAttribute('aria-describedby', contentId)
- expect(within(lastToast).getByTestId('icon')).toHaveAttribute(
+ expect(within(lastToast!).getByTestId('icon')).toHaveAttribute(
'aria-hidden',
'true'
)
- expect(within(lastToast).getByTestId('icon')).toHaveStyle({
+ expect(within(lastToast!).getByTestId('icon')).toHaveStyle({
color: color('action', '500'),
})
@@ -66,9 +74,9 @@ it('sets new props when `showToast` is called with new props', async () => {
const lastToast = await getLastToast(expectedNewLabel)
- expect(within(lastToast).getByText(expectedNewLabel)).toBeInTheDocument()
- expect(within(lastToast).getByText(expectedNewMessage)).toBeInTheDocument()
- expect(within(lastToast).getByTestId('icon')).toHaveStyle({
+ expect(within(lastToast!).getByText(expectedNewLabel)).toBeInTheDocument()
+ expect(within(lastToast!).getByText(expectedNewMessage)).toBeInTheDocument()
+ expect(within(lastToast!).getByTestId('icon')).toHaveStyle({
color: color('danger', '500'),
})
})
@@ -91,8 +99,8 @@ it('sets the message when the message is JSX', async () => {
const lastToast = await getLastToast(expectedNewLabel)
- expect(within(lastToast).getByText(expectedNewLabel)).toBeInTheDocument()
- expect(within(lastToast).getAllByRole('paragraph')).toHaveLength(2)
+ expect(within(lastToast!).getByText(expectedNewLabel)).toBeInTheDocument()
+ expect(within(lastToast!).getAllByRole('paragraph')).toHaveLength(2)
})
it('sets unique IDs when there are multiple toasts', async () => {
@@ -121,3 +129,18 @@ it('sets an accessible name when there is no message', async () => {
expect(toast).toHaveAccessibleName(new RegExp(label))
})
+
+it('dismisses all toasts when `dismissToast` is called', async () => {
+ setup()
+
+ showToast(MESSAGE)
+ showToast(MESSAGE)
+
+ expect(screen.queryAllByRole('status').length).toBeGreaterThan(0)
+
+ dismissToast()
+
+ await waitFor(() => {
+ expect(screen.queryAllByRole('status')).toHaveLength(0)
+ })
+})
diff --git a/packages/react-component-library/src/components/Toast/Toast.tsx b/packages/react-component-library/src/components/Toast/Toast.tsx
index 2ff6cbc603..930ec20b36 100644
--- a/packages/react-component-library/src/components/Toast/Toast.tsx
+++ b/packages/react-component-library/src/components/Toast/Toast.tsx
@@ -64,7 +64,7 @@ export const Toast = (props: ToastProps) => {
const { dateTime, label, appearance = TOAST_APPEARANCE.INFO, ...rest } = props
const { toasts, handlers } = useToaster()
- const { startPause, endPause, updateHeight, calculateOffset } = handlers
+ const { startPause, endPause, updateHeight } = handlers
const [time] = useState(
(dateTime || new Date()).toLocaleTimeString('en-GB', {
@@ -85,10 +85,12 @@ export const Toast = (props: ToastProps) => {
onMouseLeave={endPause}
style={{
position: 'fixed',
- top: 0,
- right: 0,
- padding: spacing('4'),
+ top: spacing('4'),
+ right: spacing('4'),
zIndex: zIndex('overlay', 999),
+ display: 'flex',
+ flexDirection: 'column',
+ gap: spacing('4'),
}}
>
{toasts.map((item: HotToast & ToastProps) => {
@@ -98,11 +100,6 @@ export const Toast = (props: ToastProps) => {
const toastTitleId = `${titleId}-${item.id}`
const toastDescriptionId = `${descriptionId}-${item.id}`
- const offset = calculateOffset(item, {
- reverseOrder: true,
- gutter: 1,
- })
-
const ref = (el: HTMLDivElement) => {
if (el && typeof height !== 'number') {
updateHeight(id, el.getBoundingClientRect().height)
@@ -115,7 +112,6 @@ export const Toast = (props: ToastProps) => {
style={{
transition: 'all 0.5s ease-out',
opacity: visible ? 1 : 0,
- transform: `translateY(${offset - height}px)`,
}}
ref={ref}
>
@@ -183,3 +179,7 @@ export const showToast = (
})
}
}
+
+export const dismissToast = (id?: string) => {
+ toast.dismiss(id)
+}
diff --git a/packages/react-component-library/src/components/Toast/partials/StyledToast.tsx b/packages/react-component-library/src/components/Toast/partials/StyledToast.tsx
index ffb69478c5..f82de03a11 100644
--- a/packages/react-component-library/src/components/Toast/partials/StyledToast.tsx
+++ b/packages/react-component-library/src/components/Toast/partials/StyledToast.tsx
@@ -1,5 +1,5 @@
import styled, { css } from 'styled-components'
-import { color, shadow, spacing } from '@royalnavy/design-tokens'
+import { color, shadow } from '@royalnavy/design-tokens'
import { StyledLabel } from './StyledLabel'
import { Appearance } from '../Toast'
@@ -22,7 +22,6 @@ export const StyledToast = styled.div`
border: 1px solid ${color('neutral', '100')};
border-radius: 4px;
width: 340px;
- margin-bottom: ${spacing('6')};
background-color: ${color('neutral', 'white')};
${({ $appearance }) => css`