diff --git a/lib/components/Note/Note.stories.tsx b/lib/components/Note/Note.stories.tsx new file mode 100644 index 0000000..e2a7564 --- /dev/null +++ b/lib/components/Note/Note.stories.tsx @@ -0,0 +1,160 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { fn } from '@storybook/test'; + +import { Note } from './Note'; + +const meta = { + title: 'Snackbars/Note', + component: Note, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +const title = 'Lorem ipsum'; +const description = 'Ipsum dolor est nonummy sit amet accusata mediocre me tulsa opus.'; + +export const ConfirmationNote: Story = { + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8296', + }, + docs: { + description: { + story: 'This is a success toast component for displaying a text.', + }, + }, + layout: 'fullscreen', + viewport: { + defaultViewport: 'desktop', + }, + }, + args: { + title, + description, + readMoreText: 'Lue lisää', + readMoreHref: '/', + onCloseClick: fn(), + }, +}; + +export const LongTitleText: Story = { + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8357', + }, + docs: { + description: { + story: 'This is a success toast component for displaying a long title text.', + }, + }, + layout: 'fullscreen', + viewport: { + defaultViewport: 'desktop', + }, + }, + args: { + title: 'Lorem ipsum dolor est nonummy noblem ester!', + description, + readMoreText: 'Lue lisää', + readMoreHref: '/', + onCloseClick: fn(), + }, +}; + +export const PermanentNote: Story = { + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8278', + }, + docs: { + description: { + story: 'This is a success toast component for displaying a permanent note.', + }, + }, + layout: 'fullscreen', + viewport: { + defaultViewport: 'desktop', + }, + }, + args: { + title, + description, + readMoreText: 'Lue lisää', + readMoreHref: '/', + }, +}; + +export const NoCTA: Story = { + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8316', + }, + docs: { + description: { + story: 'This is a success toast component for displaying a permanent note.', + }, + }, + layout: 'fullscreen', + viewport: { + defaultViewport: 'desktop', + }, + }, + args: { + title, + description, + onCloseClick: fn(), + }, +}; + +export const WarningNote: Story = { + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8344', + }, + docs: { + description: { + story: 'This is a warning toast component for displaying a text.', + }, + }, + layout: 'fullscreen', + viewport: { + defaultViewport: 'desktop', + }, + }, + args: { + title, + description, + variant: 'warning', + }, +}; + +export const ErrorNote: Story = { + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/6M2LrpSCcB0thlFDaQAI2J/cx_jod_client?node-id=542%3A8331', + }, + docs: { + description: { + story: 'This is a warning toast component for displaying a text.', + }, + }, + layout: 'fullscreen', + viewport: { + defaultViewport: 'desktop', + }, + }, + args: { + title, + description, + variant: 'error', + }, +}; diff --git a/lib/components/Note/Note.test.tsx b/lib/components/Note/Note.test.tsx new file mode 100644 index 0000000..a5554b1 --- /dev/null +++ b/lib/components/Note/Note.test.tsx @@ -0,0 +1,73 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { render, screen, cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; + +import { Note } from './Note'; + +afterEach(() => { + cleanup(); +}); + +describe('Note component', () => { + it('renders with default variant', () => { + const { container } = render(); + const noteElement = screen.getByRole('alert'); + expect(noteElement).toBeInTheDocument(); + expect(noteElement).toHaveClass('bg-success text-white'); + expect(container.firstChild).toMatchSnapshot(); + }); + + it('renders with success variant', () => { + const { container } = render(); + const noteElement = screen.getByRole('alert'); + expect(noteElement).toBeInTheDocument(); + expect(noteElement).toHaveClass('bg-success text-white'); + expect(container.firstChild).toMatchSnapshot(); + }); + + it('renders with warning variant', () => { + const { container } = render(); + const noteElement = screen.getByRole('alert'); + expect(noteElement).toBeInTheDocument(); + expect(noteElement).toHaveClass('bg-warning text-black'); + expect(container.firstChild).toMatchSnapshot(); + }); + + it('renders with error variant', () => { + const { container } = render(); + const noteElement = screen.getByRole('alert'); + expect(noteElement).toBeInTheDocument(); + expect(noteElement).toHaveClass('bg-alert text-white'); + expect(container.firstChild).toMatchSnapshot(); + }); + + it('renders with read more link', () => { + const { container } = render( + , + ); + const readMoreLink = screen.getByRole('button', { name: 'Read more' }); + expect(readMoreLink).toBeInTheDocument(); + expect(readMoreLink).toHaveAttribute('href', '/'); + expect(container.firstChild).toMatchSnapshot(); + }); + + it('renders with close button', () => { + const onCloseClick = vi.fn(); + const { container } = render( + , + ); + const closeButton = screen.getByLabelText('Close'); + expect(closeButton).toBeInTheDocument(); + expect(closeButton.firstChild).toHaveClass('material-symbols-outlined'); + expect(closeButton).toHaveAttribute('aria-label', 'Close'); + closeButton.click(); + expect(onCloseClick).toHaveBeenCalled(); + expect(container.firstChild).toMatchSnapshot(); + }); +}); diff --git a/lib/components/Note/Note.tsx b/lib/components/Note/Note.tsx new file mode 100644 index 0000000..6373d4c --- /dev/null +++ b/lib/components/Note/Note.tsx @@ -0,0 +1,57 @@ +export interface NoteProps { + /** Title shown on the note */ + title?: string; + /** Description shown on the note */ + description?: string; + /** Icon shown on the note */ + variant?: 'success' | 'warning' | 'error'; + /** Callback fired on tap/click of the close button */ + onCloseClick?: () => void; + /** Text for read more link */ + readMoreText?: string; + /** Link to read more */ + readMoreHref?: string; +} + +export const Note = ({ + title, + description, + variant = 'success', + onCloseClick, + readMoreText, + readMoreHref, +}: NoteProps) => ( +
+
+
+
{title}
+
{description}
+
+
+ {variant === 'success' && readMoreText && readMoreHref && ( + + {readMoreText} + + )} + {onCloseClick && ( + + )} +
+
+
+); diff --git a/lib/components/Note/__snapshots__/Note.test.tsx.snap b/lib/components/Note/__snapshots__/Note.test.tsx.snap new file mode 100644 index 0000000..9f3ff4d --- /dev/null +++ b/lib/components/Note/__snapshots__/Note.test.tsx.snap @@ -0,0 +1,231 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Note component > renders with close button 1`] = ` + +`; + +exports[`Note component > renders with default variant 1`] = ` +