Skip to content

Commit

Permalink
Implemented new UI component - Message (Tests + Stories)
Browse files Browse the repository at this point in the history
  • Loading branch information
miksrv committed Oct 9, 2024
1 parent 28ac372 commit 79140fe
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 0 deletions.
64 changes: 64 additions & 0 deletions src/components/message/Message.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react'

import '@testing-library/jest-dom'

import Message from './Message'

import { render, screen } from '@testing-library/react'

describe('Message Component', () => {
it('renders the Message component with title and children', () => {
render(<Message title='Test Title'>This is a test message</Message>)

const titleElement = screen.getByText(/Test Title/i)
expect(titleElement).toBeInTheDocument()

const contentElement = screen.getByText(/This is a test message/i)
expect(contentElement).toBeInTheDocument()
})

it('applies correct styles based on message type', () => {
render(
<Message
type='warning'
title='Warning Title'
>
Warning content
</Message>
)

const titleElement = screen.getByText(/Warning Title/i)
expect(titleElement).toBeInTheDocument()

const sectionElement = titleElement.closest('section')
expect(sectionElement).toHaveClass('warning')
})

it('renders list items when list is provided', () => {
const items = ['Item 1', 'Item 2', 'Item 3']
render(<Message list={items} />)

items.forEach((item) => {
const listItem = screen.getByText(item)
expect(listItem).toBeInTheDocument()
})
})

it('does not render empty list items', () => {
const items = ['Item 1', '', 'Item 3']
render(<Message list={items} />)

expect(screen.getByText('Item 1')).toBeInTheDocument()
expect(screen.getByText('Item 3')).toBeInTheDocument()
})

it('renders correctly without a title or list', () => {
render(<Message>This message has no title or list</Message>)

const contentElement = screen.getByText(/This message has no title or list/i)
expect(contentElement).toBeInTheDocument()

expect(screen.queryByRole('heading')).not.toBeInTheDocument()
expect(screen.queryByRole('list')).not.toBeInTheDocument()
})
})
29 changes: 29 additions & 0 deletions src/components/message/Message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react'

import { cn } from '../../utils'

import styles from './styles.module.sass'

/**
* Message component properties
*/
export interface MessageProps extends React.HTMLAttributes<HTMLDivElement> {
/** Type of the message that defines the visual style ('negative', 'positive', 'warning', or 'info') */
type?: 'error' | 'warning' | 'success' | 'info'
/** Title to be displayed at the top of the message */
title?: string
/** Content or children elements inside the message */
children?: React.ReactNode
}

const Message: React.FC<MessageProps> = ({ title, children, type, ...props }) => (
<section
{...props}
className={cn(styles.message, type && styles[type])}
>
{title && <div className={styles.title}>{title}</div>}
{children && <div className={styles.content}>{children}</div>}
</section>
)

export default Message
2 changes: 2 additions & 0 deletions src/components/message/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './Message'
export type { MessageProps } from './Message'
32 changes: 32 additions & 0 deletions src/components/message/styles.module.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.message
border-radius: var(--border-radius)
font-family: var(--font-family), sans-serif
font-size: var(--font-size)
box-sizing: border-box
width: 100%
padding: 8px 12px
position: relative

&.error
background-color: var(--color-red-background)
color: var(--color-red)

&.warning
background-color: var(--color-orange-background)
color: var(--color-orange)

&.success
background-color: var(--color-green-background)
color: var(--color-green)

&.info
background-color: var(--color-main-background)
color: var(--color-main)

.title
margin: 0 0 5px
font-weight: 600

.content, ul
margin: 0
font-size: var(--font-size-small)
60 changes: 60 additions & 0 deletions storybook/stories/Message.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react'

import { Message, MessageProps } from '../../src'

import { Meta, StoryFn } from '@storybook/react'

const meta: Meta<MessageProps> = {
title: 'Components/Message',
component: Message,
argTypes: {
type: {
control: 'select',
options: ['error', 'warning', 'success', 'info'],
description: 'The message type that defines the styles'
},
title: { control: 'text', description: 'Message Title' },
children: { control: 'text', description: 'Content inside the message' }
}
}

export default meta

const Template: StoryFn<MessageProps> = (args: MessageProps) => <Message {...args} />

// History with type positive
export const PositiveMessage = Template.bind({})
PositiveMessage.args = {
type: 'success',
title: 'Success!',
children: 'Your action was successful.'
}

// History with type negative
export const NegativeMessage = Template.bind({})
NegativeMessage.args = {
type: 'error',
title: 'Error!',
children: 'There was an error processing your request.'
}

// History with warning
export const WarningMessage = Template.bind({})
WarningMessage.args = {
type: 'warning',
title: 'Warning!',
children: 'Please double-check the information.'
}

// History with information message and list
export const InfoMessageWithList = Template.bind({})
InfoMessageWithList.args = {
type: 'info',
title: 'Information',
children: (
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
)
}

0 comments on commit 79140fe

Please sign in to comment.