feat: add Status component (#2838)

Closes #2820
This commit is contained in:
Thaïs
2023-12-05 11:07:51 +01:00
committed by GitHub
parent b4323f67a5
commit 5c0ad30186
6 changed files with 139 additions and 47 deletions

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
const StyledSoonPill = styled.span`
align-items: center;
background: ${({ theme }) => theme.background.transparent.light};
border-radius: 50px;
border-radius: ${({ theme }) => theme.border.radius.pill};
color: ${({ theme }) => theme.font.color.light};
display: inline-block;
font-size: ${({ theme }) => theme.font.size.xs};

View File

@ -0,0 +1,55 @@
import styled from '@emotion/styled';
import { ThemeColor } from '@/ui/theme/constants/colors';
import { themeColorSchema } from '@/ui/theme/utils/themeColorSchema';
const StyledStatus = styled.h3<{
color: ThemeColor;
}>`
align-items: center;
background: ${({ color, theme }) => theme.tag.background[color]};
border-radius: ${({ theme }) => theme.border.radius.pill};
color: ${({ color, theme }) => theme.tag.text[color]};
display: inline-flex;
font-size: ${({ theme }) => theme.font.size.md};
font-style: normal;
font-weight: ${({ theme }) => theme.font.weight.regular};
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ theme }) => theme.spacing(5)};
margin: 0;
overflow: hidden;
padding: 0 ${({ theme }) => theme.spacing(2)};
&:before {
background-color: ${({ color, theme }) => theme.tag.text[color]};
border-radius: ${({ theme }) => theme.border.radius.rounded};
content: '';
display: block;
flex-shrink: 0;
height: ${({ theme }) => theme.spacing(1)};
width: ${({ theme }) => theme.spacing(1)};
}
`;
const StyledContent = styled.span`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
type StatusProps = {
className?: string;
color: ThemeColor;
text: string;
onClick?: () => void;
};
export const Status = ({ className, color, text, onClick }: StatusProps) => (
<StyledStatus
className={className}
color={themeColorSchema.catch('gray').parse(color)}
onClick={onClick}
>
<StyledContent>{text}</StyledContent>
</StyledStatus>
);

View File

@ -0,0 +1,66 @@
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import { mainColorNames, ThemeColor } from '@/ui/theme/constants/colors';
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { CatalogStory } from '~/testing/types';
import { Status } from '../Status';
const meta: Meta<typeof Status> = {
title: 'UI/Display/Status/Status',
component: Status,
args: {
text: 'Urgent',
},
};
export default meta;
type Story = StoryObj<typeof Status>;
export const Default: Story = {
args: {
color: 'red',
onClick: jest.fn(),
},
decorators: [ComponentDecorator],
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const status = canvas.getByRole('heading', { level: 3 });
await userEvent.click(status);
expect(args.onClick).toHaveBeenCalled();
},
};
export const WithLongText: Story = {
decorators: [ComponentDecorator],
args: {
color: 'green',
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
},
parameters: {
container: { width: 100 },
},
};
export const Catalog: CatalogStory<Story, typeof Status> = {
argTypes: {
color: { control: false },
},
parameters: {
catalog: {
dimensions: [
{
name: 'colors',
values: mainColorNames,
props: (color: ThemeColor) => ({ color }),
},
],
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,43 +1,23 @@
import styled from '@emotion/styled';
import { ThemeColor } from '@/ui/theme/constants/colors';
const tagColors = [
'green',
'turquoise',
'sky',
'blue',
'purple',
'pink',
'red',
'orange',
'yellow',
'gray',
];
export type TagColor = (typeof tagColors)[number];
export const castToTagColor = (color: string): TagColor =>
tagColors.find((tagColor) => tagColor === color) ?? 'gray';
import { themeColorSchema } from '@/ui/theme/utils/themeColorSchema';
const StyledTag = styled.h3<{
color: TagColor;
color: ThemeColor;
}>`
align-items: center;
background: ${({ color, theme }) => theme.tag.background[color]};
border-radius: ${({ theme }) => theme.border.radius.sm};
color: ${({ color, theme }) => theme.tag.text[color]};
display: inline-flex;
flex-direction: row;
font-size: ${({ theme }) => theme.font.size.md};
font-style: normal;
font-weight: ${({ theme }) => theme.font.weight.regular};
gap: ${({ theme }) => theme.spacing(2)};
height: ${({ theme }) => theme.spacing(5)};
margin: 0;
overflow: hidden;
padding-left: ${({ theme }) => theme.spacing(2)};
padding-right: ${({ theme }) => theme.spacing(2)};
padding: 0 ${({ theme }) => theme.spacing(2)};
`;
const StyledContent = styled.span`
@ -46,7 +26,7 @@ const StyledContent = styled.span`
white-space: nowrap;
`;
export type TagProps = {
type TagProps = {
className?: string;
color: ThemeColor;
text: string;
@ -56,7 +36,7 @@ export type TagProps = {
export const Tag = ({ className, color, text, onClick }: TagProps) => (
<StyledTag
className={className}
color={castToTagColor(color)}
color={themeColorSchema.catch('gray').parse(color)}
onClick={onClick}
>
<StyledContent>{text}</StyledContent>

View File

@ -1,17 +1,20 @@
import { expect } from '@storybook/jest';
import { expect, jest } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react';
import { userEvent } from '@storybook/testing-library';
import { userEvent, within } from '@storybook/testing-library';
import { ThemeColor } from '@/ui/theme/constants/colors';
import { mainColorNames, ThemeColor } from '@/ui/theme/constants/colors';
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { CatalogStory } from '~/testing/types';
import { Tag, TagColor } from '../Tag';
import { Tag } from '../Tag';
const meta: Meta<typeof Tag> = {
title: 'UI/Display/Tag/Tag',
component: Tag,
args: {
text: 'Urgent',
},
};
export default meta;
@ -19,15 +22,14 @@ type Story = StoryObj<typeof Tag>;
export const Default: Story = {
args: {
text: 'Urgent',
color: 'red',
onClick: jest.fn(),
},
argTypes: { onClick: { action: 'clicked' } },
decorators: [ComponentDecorator],
play: async ({ canvasElement, args }) => {
const tag = canvasElement.querySelector('h3');
const canvas = within(canvasElement);
if (!tag) throw new Error('Tag not found');
const tag = canvas.getByRole('heading', { level: 3 });
await userEvent.click(tag);
await expect(args.onClick).toHaveBeenCalled();
@ -46,7 +48,6 @@ export const WithLongText: Story = {
};
export const Catalog: CatalogStory<Story, typeof Tag> = {
args: { text: 'Urgent' },
argTypes: {
color: { control: false },
},
@ -55,18 +56,7 @@ export const Catalog: CatalogStory<Story, typeof Tag> = {
dimensions: [
{
name: 'colors',
values: [
'green',
'turquoise',
'sky',
'blue',
'purple',
'pink',
'red',
'orange',
'yellow',
'gray',
] satisfies TagColor[],
values: mainColorNames,
props: (color: ThemeColor) => ({ color }),
},
],

View File

@ -6,6 +6,7 @@ const common = {
sm: '4px',
md: '8px',
xl: '20px',
pill: '999px',
rounded: '100%',
},
};