Skip to content

Commit

Permalink
feat: add error Tag and SelectList variants (#372)
Browse files Browse the repository at this point in the history
* fix: add Open Sans font to storybook

* feat: add variants of tag component in Tag and SelectList (#354)

* feat: add variants of tag component, resolve comments

---------

Co-authored-by: Yurii Pavlovskyi <yurii.pavlovskyi@free-now.com>
  • Loading branch information
hackbnw and Yurii Pavlovskyi authored Sep 1, 2023
1 parent ac726a2 commit e0eecdd
Show file tree
Hide file tree
Showing 7 changed files with 307 additions and 40 deletions.
7 changes: 7 additions & 0 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,12 @@
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans:200,300,400,400i,600,600i,700,800" rel="stylesheet" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#ffffff" />

<style>
body {
font-family: 'Open Sans', sans-serif;
}
</style>
62 changes: 62 additions & 0 deletions src/components/SelectList/SelectList.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { render, screen } from '@testing-library/react';
import * as React from 'react';
import { SelectList } from './SelectList';
import { SemanticColors } from '../../essentials';

describe('SelectList', () => {
it('renders options in multi select', () => {
const options = [
{
label: 'Sales',
value: 'sales'
},
{
label: 'Marketing',
value: 'marketing',
error: true
}
];

render(<SelectList options={options} value={options} isMulti />);

const normalTag = screen.getByText('Sales').parentElement;
expect(normalTag).toHaveStyle(`
background-color: ${SemanticColors.background.info};
border-color: ${SemanticColors.border.infoEmphasized};
`);

const errorTag = screen.getByText('Marketing').parentElement;
expect(errorTag).toHaveStyle(`
background-color: transparent;
border-color: ${SemanticColors.border.dangerEmphasized};
`);
});

it('disables options in multi select when control is disabled', () => {
const options = [
{
label: 'Sales',
value: 'sales'
},
{
label: 'Marketing',
value: 'marketing',
error: true
}
];

render(<SelectList options={options} value={options} isMulti isDisabled />);

const normalTag = screen.getByText('Sales').parentElement;
expect(normalTag).toHaveStyle(`
background-color: transparent;
border-color: ${SemanticColors.border.primary};
`);

const errorTag = screen.getByText('Marketing').parentElement;
expect(errorTag).toHaveStyle(`
background-color: transparent;
border-color: ${SemanticColors.border.primary};
`);
});
});
98 changes: 80 additions & 18 deletions src/components/SelectList/SelectList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@ import { SelectListProps } from './types';

type WithSelectProps<T> = T & { selectProps: SelectListProps };

const getOptionError = (option: unknown): boolean =>
typeof option === 'object' && 'error' in option && Boolean(option.error);

const getOptionVariant = (selectProps: Props, option: unknown): 'default' | 'disabled' | 'error' => {
if (selectProps.isDisabled) {
return 'disabled';
}

if (getOptionError(option)) {
return 'error';
}

return 'default';
};

const getColor = (key: string, props: Props) => String(get(key)(props));

const customStyles: StylesConfig = {
container: (provided, { selectProps }: WithSelectProps<Props>) => {
const bSize = {
Expand Down Expand Up @@ -169,35 +186,79 @@ const customStyles: StylesConfig = {
cursor: state.isDisabled ? 'not-allowed' : 'default'
};
},
multiValue: (provided, { selectProps }: { selectProps: Props }) => {
multiValue: (provided, { selectProps, data }) => {
const optionVariant = getOptionVariant(selectProps, data);

const styles = {
...provided,
color: Colors.ACTION_BLUE_900,
border: `0.0625rem solid ${Colors.ACTION_BLUE_900}`,
border: '0.0625rem solid',
borderRadius: '1rem',
backgroundColor: Colors.ACTION_BLUE_50,
marginRight: '0.375rem',
marginTop: '0.125rem',
marginLeft: 0,
marginBottom: '0.125rem',
maxWidth: 'calc(100% - 0.5rem)',
transition: 'color 125ms ease, background-color 125ms ease',
'&:hover': {
backgroundColor: Colors.ACTION_BLUE_900,
color: Colors.WHITE
}
transition: 'color 125ms ease, background-color 125ms ease'
};

if (selectProps.isDisabled) {
return {
...styles,
color: Colors.AUTHENTIC_BLUE_200,
backgroundColor: 'transparent',
borderColor: Colors.AUTHENTIC_BLUE_200
};
}
switch (optionVariant) {
case 'disabled':
return {
...styles,

color: getColor('semanticColors.text.disabled', selectProps),
backgroundColor: 'transparent',
borderColor: getColor('semanticColors.border.primary', selectProps),

'> [role="button"]': {
color: getColor('semanticColors.icon.disabled', selectProps)
}
};
case 'error':
return {
...styles,
color: getColor('semanticColors.text.dangerInverted', selectProps),
backgroundColor: 'transparent',
borderColor: getColor('semanticColors.border.dangerEmphasized', selectProps),

'> [role="button"]': {
color: getColor('semanticColors.icon.danger', selectProps)
},

'&:hover': {
color: getColor('semanticColors.text.primaryInverted', selectProps),
backgroundColor: getColor('semanticColors.background.dangerEmphasized', selectProps),
borderColor: getColor('semanticColors.border.dangerEmphasized', selectProps),

return styles;
'> [role="button"]': {
color: getColor('semanticColors.icon.primaryInverted', selectProps)
}
}
};
case 'default':
default:
return {
...styles,

color: getColor('semanticColors.text.link', selectProps),
backgroundColor: getColor('semanticColors.background.info', selectProps),
borderColor: getColor('semanticColors.border.infoEmphasized', selectProps),

'> [role="button"]': {
color: getColor('semanticColors.icon.action', selectProps)
},

'&:hover': {
color: getColor('semanticColors.text.primaryInverted', selectProps),
backgroundColor: getColor('semanticColors.background.infoEmphasized', selectProps),
borderColor: getColor('semanticColors.border.infoEmphasized', selectProps),

'> [role="button"]': {
color: getColor('semanticColors.icon.primaryInverted', selectProps)
}
}
};
}
},
multiValueLabel: (provided, { selectProps }) => ({
...provided,
Expand All @@ -214,6 +275,7 @@ const customStyles: StylesConfig = {
paddingLeft: '0',
paddingRight: '0.25rem',
paddingTop: '0',
transition: 'color 125ms ease',
'&:hover': {
color: 'inherit',
background: 'transparent'
Expand Down
33 changes: 33 additions & 0 deletions src/components/SelectList/docs/SelectList.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,39 @@ export const WithError: Story = {
}
};

const errorOptions = [
{
label: 'Sales',
value: 'sales'
},
{
label: 'Marketing',
value: 'marketing',
error: true
}
];

export const MultiSelectError: Story = {
args: {
label: 'Multi select with error',
error: true,
isMulti: true,
options: errorOptions,
value: errorOptions
}
};

export const MultiSelectDisabled: Story = {
args: {
label: 'Disabled multi select',
error: true,
isMulti: true,
isDisabled: true,
options: errorOptions,
value: errorOptions
}
};

export const Inverted: Story = {
args: {
inverted: true
Expand Down
32 changes: 31 additions & 1 deletion src/components/Tag/Tag.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { render, fireEvent } from '@testing-library/react';
import { render, fireEvent, screen } from '@testing-library/react';
import * as React from 'react';
import { Tag } from './Tag';
import { SemanticColors } from '../../essentials';

describe('Tag', () => {
it('renders with default props', () => {
Expand All @@ -26,4 +27,33 @@ describe('Tag', () => {

expect(queryByTestId('dismiss-icon')).toBeNull();
});

it('renders disabled variant', () => {
const { container } = render(<Tag variant="disabled">Lorem</Tag>);

expect(container.firstChild).toHaveStyle(`
border-color: ${SemanticColors.border.primary};
`);
expect(screen.getByText('Lorem')).toHaveStyle(`
color: ${SemanticColors.text.disabled};
`);
expect(screen.getByTestId('dismiss-icon')).toHaveStyle(`
color: ${SemanticColors.icon.disabled};
`);
});

it('renders error variant', () => {
const { container } = render(<Tag variant="error">Lorem</Tag>);

expect(container.firstChild).toHaveStyle(`
background-color: ${SemanticColors.background.danger};
border-color: ${SemanticColors.border.dangerEmphasized};
`);
expect(screen.getByText('Lorem')).toHaveStyle(`
color: ${SemanticColors.text.dangerInverted};
`);
expect(screen.getByTestId('dismiss-icon')).toHaveStyle(`
color: ${SemanticColors.icon.danger};
`);
});
});
Loading

0 comments on commit e0eecdd

Please sign in to comment.