Skip to content

Commit ef88a31

Browse files
authored
refactor(Tag): migrate Tag component (#1302)
* refactor(Tag): migrate tag component * docs(Tag): create new stories * style(Tag): use correct variables * fix(Tag): only do preventDefault in case of enter * docs(Tag): change max-width * style(Tag)!: improve styling and use of maxWidth BREAKING CHANGE: 'size' is no longer a prop
1 parent aeaafb7 commit ef88a31

File tree

7 files changed

+126
-97
lines changed

7 files changed

+126
-97
lines changed

src/components/Tag/Tag.scss

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,70 @@
11
.Tag {
2-
display: flex;
2+
display: inline-flex;
33
align-items: center;
44

5-
padding: var(--space-50) var(--space-75);
6-
border-radius: var(--border-radius);
5+
padding: var(--space-25) var(--space-50);
6+
gap: var(--space-50);
7+
border-radius: var(--space-50);
8+
border: 1px solid var(--color-border-subtle);
9+
cursor: default;
10+
background-color: var(--bg-color, white); // Fallback to --color-background if bgColor isn't provided
11+
12+
&[disabled] {
13+
color: var(--color-text-disabled);
14+
}
715

816
&--isSelected {
9-
box-shadow: 0 0 0 2px var(--color-brand-50);
17+
box-shadow: 0 0 0 var(--space-25) var(--color-brand-50);
1018
}
1119

12-
&--clickable {
20+
&--clickable:not([disabled]) {
1321
cursor: pointer;
22+
23+
&:hover:not([disabled]){
24+
background-color: var(--color-background-neutral-subtlest-hover);
25+
}
26+
27+
&:focus:not([disabled]) {
28+
outline: none;
29+
box-shadow: 0 0 0 var(--space-25) var(--color-info-20);
30+
}
1431
}
1532

1633
&__text{
34+
composes: OneUI-label-text from global;
1735
margin: 0;
1836

1937
white-space: nowrap;
2038
overflow: hidden;
2139
text-overflow: ellipsis;
40+
&[disabled] {
41+
color: var(--color-text-disabled);
42+
}
2243
}
2344

2445
&__deleteButton {
2546
display: flex;
47+
justify-content: center;
2648
align-items: center;
2749

28-
min-width: 15px;
29-
min-height: 15px;
50+
min-width: var(--space-200);
51+
height: var(--space-200);
3052

31-
border: 0;
53+
border: none;
54+
border-radius: var(--space-25);
3255
cursor: pointer;
3356
background-color: var(--transparent);
3457

3558
padding: 0;
36-
margin-left: var(--space-50);
59+
60+
&:focus:not([disabled]) {
61+
outline: none;
62+
box-shadow: 0 0 0 var(--space-25) var(--color-info-20);
63+
}
64+
&[disabled] {
65+
fill: var(--color-text-disabled);
66+
cursor: default;
67+
}
68+
3769
}
3870
}

src/components/Tag/Tag.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import * as React from 'react';
2-
import { MdClose } from 'react-icons/md';
2+
import Close from '@material-design-icons/svg/round/close.svg';
33
import { bem } from '../../utils';
4-
import { Text } from '../Text';
5-
import { ENTER_KEY, Size } from '../../constants';
4+
import { ENTER_KEY } from '../../constants';
65
import styles from './Tag.scss';
76

87
export interface Props extends React.HTMLAttributes<HTMLDivElement> {
@@ -12,8 +11,6 @@ export interface Props extends React.HTMLAttributes<HTMLDivElement> {
1211
bgColor?: string;
1312
/** Max-width of a component */
1413
maxWidth?: string;
15-
/** Size of the text */
16-
size?: Size;
1714
/** Callback, that is fired when a user clicks on a delete icon */
1815
onDelete?: (e: React.KeyboardEvent | React.MouseEvent) => void;
1916
/** Callback, that is fired when a user clicks on an element */
@@ -24,6 +21,8 @@ export interface Props extends React.HTMLAttributes<HTMLDivElement> {
2421
contentStyle?: React.CSSProperties;
2522
/** Close label name for ARIA labelling, it is used when needs to clear data from component */
2623
closeLabel?: string;
24+
/** Should tag be disabled or not */
25+
disabled?: boolean;
2726
}
2827

2928
const { block, elem } = bem('Tag', styles);
@@ -32,15 +31,15 @@ export const Tag = React.forwardRef<HTMLDivElement, Props>(
3231
(
3332
{
3433
children,
35-
bgColor = 'var(--color-background)',
36-
maxWidth = 'fit-content',
37-
size = 'large',
34+
bgColor,
35+
maxWidth = '224px',
3836
onDelete = undefined,
3937
onClick = undefined,
4038
isSelected = false,
4139
contentClassName,
4240
contentStyle,
4341
closeLabel,
42+
disabled,
4443
...rest
4544
},
4645
ref
@@ -65,15 +64,15 @@ export const Tag = React.forwardRef<HTMLDivElement, Props>(
6564

6665
const handleDeleteButtonKeyPress = (e: React.KeyboardEvent) => {
6766
e.stopPropagation();
68-
e.preventDefault();
6967

7068
if (e.key === ENTER_KEY) {
69+
e.preventDefault();
7170
onDelete?.(e);
7271
}
7372
};
7473

7574
return (
76-
<div
75+
<span
7776
{...rest}
7877
ref={ref}
7978
{...block({ isSelected, clickable: !!onClick, ...rest })}
@@ -84,29 +83,35 @@ export const Tag = React.forwardRef<HTMLDivElement, Props>(
8483
onKeyPress: handleTagKeyPress,
8584
})}
8685
style={{
87-
backgroundColor: bgColor,
86+
'--bg-color': bgColor,
8887
maxWidth,
8988
}}
89+
disabled={disabled}
9090
>
91-
<Text
92-
size={size}
91+
<span
9392
{...(areChildrenString && { title: children })}
9493
{...elem('text', { elemClassName: contentClassName })}
94+
disabled={disabled}
9595
style={contentStyle}
9696
>
9797
{children}
98-
</Text>
98+
</span>
9999
{onDelete && (
100100
<button
101101
onClick={handleDeleteClick}
102102
onKeyDown={handleDeleteButtonKeyPress}
103103
type="button"
104+
disabled={disabled}
104105
{...elem('deleteButton')}
105106
>
106-
<MdClose size="15px" aria-label={closeLabel} />
107+
<Close
108+
aria-label={closeLabel}
109+
style={{ width: '100%', height: '100%' }}
110+
viewBox="0 0 24 24"
111+
/>
107112
</button>
108113
)}
109-
</div>
114+
</span>
110115
);
111116
}
112117
);

src/components/Tag/__tests__/Tag.spec.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ describe('<Tag> component', () => {
1313
const text = 'Tag text';
1414
const bgColor = '#ccc';
1515
const maxWidth = '30px';
16-
const textSize = 'large';
1716
const closeLabel = 'close label';
1817

1918
it('should render correctly with minimum amount of props', () => {
@@ -29,7 +28,6 @@ describe('<Tag> component', () => {
2928
isSelected
3029
bgColor={bgColor}
3130
maxWidth={maxWidth}
32-
size={textSize}
3331
onClick={onTagClick}
3432
onDelete={onDeleteClick}
3533
contentClassName="my-class"
@@ -43,10 +41,7 @@ describe('<Tag> component', () => {
4341

4442
expect(view.container).toMatchSnapshot();
4543
expect(button).toBeInTheDocument();
46-
expect(button).toHaveAttribute(
47-
'style',
48-
'background-color: rgb(204, 204, 204); max-width: 30px;'
49-
);
44+
expect(button).toHaveAttribute('style', '--bg-color: #ccc; max-width: 30px;');
5045
});
5146

5247
it('should invoke callback when onClick event is called', async () => {

src/components/Tag/__tests__/__snapshots__/Tag.spec.tsx.snap

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,45 @@
22

33
exports[`<Tag> component should render correctly with full list of props 1`] = `
44
<div>
5-
<div
5+
<span
66
class="Tag Tag--isSelected Tag--clickable"
77
role="button"
8-
style="background-color: rgb(204, 204, 204); max-width: 30px;"
8+
style="--bg-color: #ccc; max-width: 30px;"
99
tabindex="0"
1010
>
11-
<p
11+
<span
1212
class="Tag__text my-class"
1313
style="color: red;"
1414
title="Tag text"
1515
>
1616
Tag text
17-
</p>
17+
</span>
1818
<button
1919
class="Tag__deleteButton"
2020
type="button"
2121
>
2222
<svg
23-
fill="currentColor"
24-
height="15px"
25-
stroke="currentColor"
26-
stroke-width="0"
23+
data-testid="default-icon"
24+
style="width: 100%; height: 100%;"
2725
viewBox="0 0 24 24"
28-
width="15px"
29-
xmlns="http://www.w3.org/2000/svg"
30-
>
31-
<path
32-
d="M0 0h24v24H0z"
33-
fill="none"
34-
/>
35-
<path
36-
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
37-
/>
38-
</svg>
26+
/>
3927
</button>
40-
</div>
28+
</span>
4129
</div>
4230
`;
4331
4432
exports[`<Tag> component should render correctly with minimum amount of props 1`] = `
4533
<div>
46-
<div
34+
<span
4735
class="Tag"
48-
style="max-width: fit-content;"
36+
style="max-width: 224px;"
4937
>
50-
<p
38+
<span
5139
class="Tag__text"
5240
title="Tag text"
5341
>
5442
Tag text
55-
</p>
56-
</div>
43+
</span>
44+
</span>
5745
</div>
5846
`;

src/components/Teaser/__tests__/__snapshots__/Teaser.spec.tsx.snap

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -325,28 +325,28 @@ exports[`Teaser should render with all props defined 1`] = `
325325
<div
326326
class="Teaser__bottom"
327327
>
328-
<div
328+
<span
329329
class="Tag"
330-
style="background-color: yellow; max-width: fit-content;"
330+
style="--bg-color: yellow; max-width: 224px;"
331331
>
332-
<p
332+
<span
333333
class="Tag__text"
334334
title="First Tag"
335335
>
336336
First Tag
337-
</p>
338-
</div>
339-
<div
337+
</span>
338+
</span>
339+
<span
340340
class="Tag"
341-
style="background-color: lightblue; max-width: fit-content;"
341+
style="--bg-color: lightblue; max-width: 224px;"
342342
>
343-
<p
343+
<span
344344
class="Tag__text"
345345
title="Second Tag"
346346
>
347347
Second Tag
348-
</p>
349-
</div>
348+
</span>
349+
</span>
350350
</div>
351351
</div>
352352
</div>

0 commit comments

Comments
 (0)