From 6dac4221de5d3c628ff850a3c9f342c485c347db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20Fern=C3=A1ndez=20Saavedra?= Date: Wed, 27 Nov 2024 11:05:25 +0100 Subject: [PATCH 1/7] feat: add snackbar component --- .../experimental/Snackbar/Snackbar.tsx | 35 ++++++++++++++++ .../Snackbar/docs/Snackbar.stories.tsx | 41 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/components/experimental/Snackbar/Snackbar.tsx create mode 100644 src/components/experimental/Snackbar/docs/Snackbar.stories.tsx diff --git a/src/components/experimental/Snackbar/Snackbar.tsx b/src/components/experimental/Snackbar/Snackbar.tsx new file mode 100644 index 00000000..5e28b04d --- /dev/null +++ b/src/components/experimental/Snackbar/Snackbar.tsx @@ -0,0 +1,35 @@ +import React, { ReactNode, type ReactElement } from 'react'; +import styled from 'styled-components'; +import { SpaceProps, LayoutProps, PositionProps, FlexboxProps } from 'styled-system'; + +import { get } from '../../../utils/experimental/themeGet'; +import { getSemanticValue } from '../../../essentials/experimental'; +import { textStyles } from '../Text/Text'; + +const Container = styled.div` + position: relative; + justify-content: space-between; + + border: none; + outline: none; + border-radius: ${get('radii.4')}; + padding: ${get('space.4')} ${get('space.5')}; + color: ${getSemanticValue('inverse-on-surface')}; + background-color: ${getSemanticValue('inverse-surface')}; + + display: inline-flex; + align-items: center; + gap: ${get('space.1')}; + + ${textStyles.variants.body2} +`; + +interface SnackbarProps extends SpaceProps, LayoutProps, PositionProps, FlexboxProps { + children?: ReactNode; +} + +const Snackbar = ({ children, ...restProps }: SnackbarProps): ReactElement => ( + {children} +); + +export { Snackbar, SnackbarProps }; diff --git a/src/components/experimental/Snackbar/docs/Snackbar.stories.tsx b/src/components/experimental/Snackbar/docs/Snackbar.stories.tsx new file mode 100644 index 00000000..465a0aec --- /dev/null +++ b/src/components/experimental/Snackbar/docs/Snackbar.stories.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; + +import { Snackbar } from '../Snackbar'; +import { XCrossIcon } from '../../../../icons'; +import { getSemanticValue } from '../../../../essentials/experimental/cssVariables'; + +const meta: Meta = { + title: 'Experimental/Components/Snackbar', + component: Snackbar, + parameters: { + layout: 'centered' + }, + argTypes: {}, + args: { + children: 'Booking successfully cancelled' + } +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; + +export const WithDismissIcon: Story = { + args: { + children: ( + <> + Booking successfully cancelled + + + ) + } +}; From 22b2404b73e4060429b87f82269b5d4ade383c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20Fern=C3=A1ndez=20Saavedra?= Date: Wed, 27 Nov 2024 11:11:27 +0100 Subject: [PATCH 2/7] feat: add export --- src/components/experimental/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/experimental/index.ts b/src/components/experimental/index.ts index 7d1c04f0..92ffbef8 100644 --- a/src/components/experimental/index.ts +++ b/src/components/experimental/index.ts @@ -11,6 +11,7 @@ export { Label } from './Label/Label'; export { ListBox, ListBoxItem } from './ListBox/ListBox'; export { Popover } from './Popover/Popover'; export { Select } from './Select/Select'; +export { Snackbar } from './Snackbar/Snackbar'; export { Table, Row, Cell, Skeleton, Column, TableBody, TableHeader } from './Table/Table'; export { Text } from './Text/Text'; export { TextField } from './TextField/TextField'; From e033379baad3fbc15fbbf8329cf1a488e29369e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20Fern=C3=A1ndez=20Saavedra?= Date: Wed, 27 Nov 2024 11:19:45 +0100 Subject: [PATCH 3/7] chore: add tests --- .../experimental/Snackbar/Snackbar.spec.tsx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/components/experimental/Snackbar/Snackbar.spec.tsx diff --git a/src/components/experimental/Snackbar/Snackbar.spec.tsx b/src/components/experimental/Snackbar/Snackbar.spec.tsx new file mode 100644 index 00000000..10028ff6 --- /dev/null +++ b/src/components/experimental/Snackbar/Snackbar.spec.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { Snackbar } from './Snackbar'; + +test('renders the Snackbar component with children', () => { + render( + + Test Snackbar + + ); + expect(screen.getByText('Test Snackbar')).toBeInTheDocument(); +}); + +test('clickable component inside Snackbar can be clicked', () => { + const handleClick = jest.fn(); + render( + + + + ); + screen.getByText('Click Me').click(); + expect(handleClick).toHaveBeenCalledTimes(1); +}); From 625a7e874edbf7af4589f8b5031d5d5ced76610d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20Fern=C3=A1ndez=20Saavedra?= Date: Wed, 27 Nov 2024 13:11:27 +0100 Subject: [PATCH 4/7] fix: container padding --- src/components/experimental/Snackbar/Snackbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/experimental/Snackbar/Snackbar.tsx b/src/components/experimental/Snackbar/Snackbar.tsx index 5e28b04d..fe911f75 100644 --- a/src/components/experimental/Snackbar/Snackbar.tsx +++ b/src/components/experimental/Snackbar/Snackbar.tsx @@ -13,7 +13,7 @@ const Container = styled.div` border: none; outline: none; border-radius: ${get('radii.4')}; - padding: ${get('space.4')} ${get('space.5')}; + padding: ${get('space.3')} ${get('space.4')}; color: ${getSemanticValue('inverse-on-surface')}; background-color: ${getSemanticValue('inverse-surface')}; From d2bf40935efeba991b13c4b84b3a6aaaed3c01bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20Fern=C3=A1ndez=20Saavedra?= Date: Wed, 27 Nov 2024 13:14:53 +0100 Subject: [PATCH 5/7] feat: add dismiss button as part of the component --- .../experimental/Snackbar/Snackbar.spec.tsx | 17 ++++++------- .../experimental/Snackbar/Snackbar.tsx | 25 ++++++++++++++++--- .../Snackbar/docs/Snackbar.stories.tsx | 20 ++++----------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/components/experimental/Snackbar/Snackbar.spec.tsx b/src/components/experimental/Snackbar/Snackbar.spec.tsx index 10028ff6..f88be8df 100644 --- a/src/components/experimental/Snackbar/Snackbar.spec.tsx +++ b/src/components/experimental/Snackbar/Snackbar.spec.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import { Snackbar } from './Snackbar'; test('renders the Snackbar component with children', () => { @@ -11,15 +11,14 @@ test('renders the Snackbar component with children', () => { expect(screen.getByText('Test Snackbar')).toBeInTheDocument(); }); -test('clickable component inside Snackbar can be clicked', () => { - const handleClick = jest.fn(); +test('renders the dismiss button when hasDismissButton is true and calls onDismiss when clicked', () => { + const onDismiss = jest.fn(); render( - - + + Test Snackbar ); - screen.getByText('Click Me').click(); - expect(handleClick).toHaveBeenCalledTimes(1); + const dismissButton = screen.getByTestId('snackbar-close-icon'); + fireEvent.click(dismissButton); + expect(onDismiss).toHaveBeenCalledTimes(1); }); diff --git a/src/components/experimental/Snackbar/Snackbar.tsx b/src/components/experimental/Snackbar/Snackbar.tsx index fe911f75..abc4aebf 100644 --- a/src/components/experimental/Snackbar/Snackbar.tsx +++ b/src/components/experimental/Snackbar/Snackbar.tsx @@ -5,6 +5,7 @@ import { SpaceProps, LayoutProps, PositionProps, FlexboxProps } from 'styled-sys import { get } from '../../../utils/experimental/themeGet'; import { getSemanticValue } from '../../../essentials/experimental'; import { textStyles } from '../Text/Text'; +import { XCrossIcon } from '../../../icons'; const Container = styled.div` position: relative; @@ -25,11 +26,29 @@ const Container = styled.div` `; interface SnackbarProps extends SpaceProps, LayoutProps, PositionProps, FlexboxProps { - children?: ReactNode; + children: ReactNode; + hasDismissButton?: boolean; + onDismiss?: () => void; } -const Snackbar = ({ children, ...restProps }: SnackbarProps): ReactElement => ( - {children} +const Snackbar = ({ + children, + hasDismissButton = false, + onDismiss = null, + ...restProps +}: SnackbarProps): ReactElement => ( + + {children} + {hasDismissButton && ( + + )} + ); export { Snackbar, SnackbarProps }; diff --git a/src/components/experimental/Snackbar/docs/Snackbar.stories.tsx b/src/components/experimental/Snackbar/docs/Snackbar.stories.tsx index 465a0aec..3df6ccab 100644 --- a/src/components/experimental/Snackbar/docs/Snackbar.stories.tsx +++ b/src/components/experimental/Snackbar/docs/Snackbar.stories.tsx @@ -1,10 +1,7 @@ -import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { Snackbar } from '../Snackbar'; -import { XCrossIcon } from '../../../../icons'; -import { getSemanticValue } from '../../../../essentials/experimental/cssVariables'; const meta: Meta = { title: 'Experimental/Components/Snackbar', @@ -14,7 +11,9 @@ const meta: Meta = { }, argTypes: {}, args: { - children: 'Booking successfully cancelled' + children: 'Booking successfully cancelled', + hasDismissButton: false, + onDismiss: null } }; @@ -26,16 +25,7 @@ export const Default: Story = {}; export const WithDismissIcon: Story = { args: { - children: ( - <> - Booking successfully cancelled - - - ) + hasDismissButton: true, + onDismiss: action('Remove snackbar') } }; From 0c1d3f292da001f0df217e7f72e14f41d81213d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20Fern=C3=A1ndez=20Saavedra?= Date: Wed, 27 Nov 2024 14:28:29 +0100 Subject: [PATCH 6/7] fix: use icon button --- src/components/experimental/Snackbar/Snackbar.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/experimental/Snackbar/Snackbar.tsx b/src/components/experimental/Snackbar/Snackbar.tsx index abc4aebf..afaea844 100644 --- a/src/components/experimental/Snackbar/Snackbar.tsx +++ b/src/components/experimental/Snackbar/Snackbar.tsx @@ -6,6 +6,7 @@ import { get } from '../../../utils/experimental/themeGet'; import { getSemanticValue } from '../../../essentials/experimental'; import { textStyles } from '../Text/Text'; import { XCrossIcon } from '../../../icons'; +import { IconButton } from '../IconButton/IconButton'; const Container = styled.div` position: relative; @@ -25,6 +26,12 @@ const Container = styled.div` ${textStyles.variants.body2} `; +const DismissButton = styled(IconButton)` + height: unset; + width: unset; + padding: 0; +`; + interface SnackbarProps extends SpaceProps, LayoutProps, PositionProps, FlexboxProps { children: ReactNode; hasDismissButton?: boolean; @@ -40,12 +47,10 @@ const Snackbar = ({ {children} {hasDismissButton && ( - } + onPress={onDismiss} /> )} From 0b64656fb5bb5f6a65ea9cb69c88b0500d31e1b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20Fern=C3=A1ndez=20Saavedra?= Date: Wed, 27 Nov 2024 15:26:08 +0100 Subject: [PATCH 7/7] fix: remove cursor prop from component --- src/components/experimental/Snackbar/Snackbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/experimental/Snackbar/Snackbar.tsx b/src/components/experimental/Snackbar/Snackbar.tsx index afaea844..26804cf1 100644 --- a/src/components/experimental/Snackbar/Snackbar.tsx +++ b/src/components/experimental/Snackbar/Snackbar.tsx @@ -49,7 +49,7 @@ const Snackbar = ({ {hasDismissButton && ( } + Icon={() => } onPress={onDismiss} /> )}