Skip to content

Commit cdd3c11

Browse files
Merge pull request #590 from catho/QTM-728
feat(QTM-728): Migrated to css modules and updated types and snapshots
2 parents 81e7ae0 + 10ab4a7 commit cdd3c11

File tree

6 files changed

+154
-193
lines changed

6 files changed

+154
-193
lines changed

components/AutoComplete/AutoComplete.jsx

+45-165
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { useState, useRef, useEffect } from 'react';
22
import PropTypes from 'prop-types';
3-
import styled, { css } from 'styled-components';
4-
import { shadow, normalizeChars } from '../shared';
5-
import { baseFontSize, colors, spacing } from '../shared/theme';
3+
import classNames from 'classnames';
4+
import { normalizeChars } from '../shared';
65
import Icon from '../Icon';
76

87
import {
@@ -13,140 +12,10 @@ import {
1312
RequiredMark,
1413
} from '../Input/sub-components';
1514
import useKeyPress from './SubComponents/UseKeyPress';
15+
import styles from './AutoComplete.module.css';
1616

17-
const ITEM_HEIGHT = '44px';
18-
const MAX_ITEMS_VISIBILITY = 7;
19-
const DROPITEM_FONT_SIZE = baseFontSize * 0.875;
2017
const NON_FOCUSABLE_SUGGESTION_INDEX = -1;
2118

22-
const ComponentWrapper = styled.div`
23-
${({
24-
theme: {
25-
colors: { neutral },
26-
},
27-
skin = 'default',
28-
}) => css`
29-
position: relative;
30-
color: ${skin === 'default' ? neutral[700] : neutral[0]};
31-
`}
32-
`;
33-
34-
const InputWrapper = styled.div`
35-
position: relative;
36-
`;
37-
38-
const propsNotContainedInTextInput = ['theme'];
39-
40-
const InputText = styled(TextInput).withConfig({
41-
shouldForwardProp: (prop) => !propsNotContainedInTextInput.includes(prop),
42-
})`
43-
${({
44-
theme: {
45-
spacing: { xsmall },
46-
},
47-
}) => css`
48-
margin-top: ${xsmall}px;
49-
`}
50-
`;
51-
52-
const InputIcon = styled(Icon)`
53-
cursor: pointer;
54-
position: absolute;
55-
${({
56-
theme: {
57-
spacing: { xsmall, medium },
58-
},
59-
}) => css`
60-
right: ${medium}px;
61-
bottom: ${xsmall * 1.25}px;
62-
width: ${baseFontSize * 1.5}px;
63-
`}
64-
`;
65-
66-
const InputErrorIcon = styled(InputIcon).attrs({ name: 'error' })`
67-
${({
68-
theme: {
69-
colors: {
70-
error: { 700: error700 },
71-
},
72-
},
73-
skin,
74-
}) => css`
75-
color: ${skin === 'default' ? error700 : 'inherit'};
76-
`}
77-
`;
78-
79-
const List = styled.ul`
80-
border-radius: 4px;
81-
box-sizing: border-box;
82-
list-style: none;
83-
max-height: calc(${ITEM_HEIGHT} * ${MAX_ITEMS_VISIBILITY});
84-
overflow: auto;
85-
padding: 0;
86-
position: absolute;
87-
width: 100%;
88-
z-index: 1;
89-
90-
${({ theme }) => {
91-
const {
92-
spacing: { xxsmall },
93-
colors: {
94-
neutral: { 0: neutral0, 700: neutral700 },
95-
},
96-
} = theme;
97-
return css`
98-
background-color: ${neutral0};
99-
margin-top: ${xxsmall}px;
100-
${shadow(3, neutral700)({ theme })};
101-
`;
102-
}}
103-
`;
104-
105-
const ListItem = styled.li`
106-
display: flex;
107-
align-items: center;
108-
justify-content: space-between;
109-
box-sizing: border-box;
110-
cursor: pointer;
111-
height: ${ITEM_HEIGHT};
112-
${({
113-
theme: {
114-
spacing: { xsmall, medium },
115-
colors: {
116-
neutral: { 0: neutral0, 700: neutral700 },
117-
},
118-
},
119-
}) => css`
120-
color: ${neutral700};
121-
font-size: ${DROPITEM_FONT_SIZE}px;
122-
background-color: ${neutral0};
123-
padding: ${xsmall}px ${medium}px;
124-
`}
125-
126-
&[aria-selected = 'true' ], &:hover {
127-
${({
128-
theme: {
129-
colors: {
130-
neutral: { 100: neutral100 },
131-
},
132-
},
133-
}) => css`
134-
background-color: ${neutral100};
135-
`}
136-
}
137-
`;
138-
139-
const PoliteStatus = styled.div`
140-
border: 0;
141-
clip: rect(0 0 0 0);
142-
height: 1px;
143-
margin: -1px;
144-
overflow: hidden;
145-
padding: 0;
146-
position: absolute;
147-
width: 1px;
148-
`;
149-
15019
const AutoComplete = ({
15120
id = '',
15221
name = '',
@@ -157,15 +26,25 @@ const AutoComplete = ({
15726
helperText = '',
15827
placeholder = 'Select an option',
15928
suggestions,
160-
theme = {
161-
spacing,
162-
colors,
163-
},
16429
onSelectedItem = () => {},
16530
onChange = () => {},
16631
required = false,
16732
skin = 'default',
16833
}) => {
34+
const wrapperClass = classNames(styles.wrapper, {
35+
[styles['wrapper-dark']]: skin === 'dark',
36+
});
37+
const inputWrapperClass = classNames(styles['input-wrapper']);
38+
const inputTextClass = classNames(styles['input-text']);
39+
const inputIconClass = classNames(styles['input-icon']);
40+
const inputErrorIconClass = classNames(
41+
styles['input-icon'],
42+
styles[`input-error-icon-${skin}`],
43+
);
44+
const listClass = classNames(styles['list-suggestions'], 'shadow-3');
45+
const itemClass = classNames(styles['item-suggestions']);
46+
const politeClass = classNames(styles['polite-status']);
47+
16948
const [userTypedValue, setUserTypedValue] = useState(value);
17049
const [filterSuggestions, setFilterSuggestions] = useState(suggestions);
17150
const [filterSuggestionsLength, setFilterSuggestionsLength] = useState(
@@ -248,27 +127,27 @@ const AutoComplete = ({
248127

249128
const generateSuggestions = () =>
250129
showSuggestions && filterSuggestions ? (
251-
<List
252-
theme={theme}
130+
<ul
253131
role="listbox"
254132
id="autocompleteOptions"
255133
ref={listOptions}
256-
skin={skin}
134+
className={listClass}
257135
>
258136
{filterSuggestions.map((item, index) => (
259-
<ListItem
137+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
138+
<li
260139
key={item}
261140
aria-posinset={index}
262141
onClick={() => handleItemClick(item)}
263-
theme={theme}
142+
className={itemClass}
264143
aria-selected={index === cursor}
265144
role="option"
266145
tabIndex="-1"
267146
>
268147
{item}
269-
</ListItem>
148+
</li>
270149
))}
271-
</List>
150+
</ul>
272151
) : null;
273152

274153
const generateAssistiveDescript = () => {
@@ -346,13 +225,13 @@ const AutoComplete = ({
346225
}, [suggestions]);
347226

348227
return (
349-
<ComponentWrapper theme={theme} skin={skin}>
350-
<InputWrapper ref={wrapperRef}>
228+
<div className={wrapperClass}>
229+
<div className={inputWrapperClass} ref={wrapperRef}>
351230
<InputLabel htmlFor={id}>
352231
{label}
353232
{required && <RequiredMark skin={skin}>*</RequiredMark>}
354233
</InputLabel>
355-
<InputText
234+
<TextInput
356235
id={id}
357236
ref={autoInputRef}
358237
name={name}
@@ -370,39 +249,40 @@ const AutoComplete = ({
370249
onChange={(e) => handleChange(e.target.value)}
371250
skin={skin}
372251
required={required}
373-
theme={theme}
252+
className={inputTextClass}
374253
/>
375254
{userTypedValue && !error && !disabled && (
376-
<InputIcon
377-
theme={theme}
255+
<Icon
378256
name="clear"
379257
description="limpar valor"
380258
onClick={() => handleClearValue()}
259+
className={inputIconClass}
381260
/>
382261
)}
383262
{generateSuggestions()}
384263
{error && (
385-
<InputErrorIcon description={error} theme={theme} skin={skin} />
264+
<Icon
265+
name="error"
266+
description={error}
267+
className={inputErrorIconClass}
268+
/>
386269
)}
387-
</InputWrapper>
270+
</div>
388271
{helperText && <HelperText>{helperText}</HelperText>}
389-
{error && (
390-
<InputErrorMessage theme={theme} skin={skin}>
391-
{error}
392-
</InputErrorMessage>
393-
)}
394-
<PoliteStatus role="status" aria-atomic="true" aria-live="polite">
272+
{error && <InputErrorMessage skin={skin}>{error}</InputErrorMessage>}
273+
<div
274+
role="status"
275+
aria-atomic="true"
276+
aria-live="polite"
277+
className={politeClass}
278+
>
395279
{generateAssistiveDescript()}
396-
</PoliteStatus>
397-
</ComponentWrapper>
280+
</div>
281+
</div>
398282
);
399283
};
400284

401285
AutoComplete.propTypes = {
402-
theme: PropTypes.shape({
403-
colors: PropTypes.object,
404-
spacing: PropTypes.object,
405-
}),
406286
/** A list of string or objects with the values to show in component */
407287
suggestions: PropTypes.arrayOf(PropTypes.string).isRequired,
408288
id: PropTypes.string,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
:root {
2+
--max-items-visibility: 7;
3+
--item-height: 44px;
4+
--dropitem-font-size: calc(var(--qtm-base-font-size) * 0.875);
5+
}
6+
7+
.wrapper {
8+
position: relative;
9+
color: var(--qtm-colors-neutral-700);
10+
}
11+
12+
.input-wrapper {
13+
position: relative;
14+
}
15+
16+
.wrapper-dark {
17+
color: var(--qtm-colors-neutral-0);
18+
}
19+
20+
.input-text {
21+
margin-top: var(--qtm-spacing-xsmall);
22+
}
23+
24+
.input-icon {
25+
cursor: pointer;
26+
position: absolute;
27+
right: var(--qtm-spacing-medium);
28+
bottom: calc(var(--qtm-spacing-xsmall) * 1.25);
29+
width: calc(var(--qtm-base-font-size) * 1.5);
30+
}
31+
32+
.input-error-icon-default {
33+
color: var(--qtm-colors-error-700);
34+
}
35+
36+
.input-error-icon-dark {
37+
color: inherit;
38+
}
39+
40+
.polite-status {
41+
border: 0;
42+
clip: rect(0 0 0 0);
43+
height: 1px;
44+
margin: -1px;
45+
overflow: hidden;
46+
padding: 0;
47+
position: absolute;
48+
width: 1px;
49+
}
50+
51+
.list-suggestions {
52+
border-radius: 4px;
53+
box-sizing: border-box;
54+
list-style: none;
55+
max-height: calc(var(--item-height) * var(--max-items-visibility));
56+
overflow: auto;
57+
padding: 0;
58+
position: absolute;
59+
width: 100%;
60+
z-index: 1;
61+
background-color: var(--qtm-colors-neutral-0);
62+
margin-top: var(--qtm-spacing-xxsmall);
63+
}
64+
65+
.item-suggestions {
66+
display: flex;
67+
align-items: center;
68+
justify-content: space-between;
69+
box-sizing: border-box;
70+
cursor: pointer;
71+
height: var(--item-height);
72+
color: var(--qtm-colors-neutral-700);
73+
font-size: var(--dropitem-font-size);
74+
background-color: var(--qtm-colors-neutral-0);
75+
padding: var(--qtm-spacing-xsmall) var(--qtm-spacing-medium);
76+
}
77+
78+
.item-suggestions[aria-selected='true'],
79+
.item-suggestions:hover {
80+
background-color: var(--qtm-colors-neutral-100);
81+
}

0 commit comments

Comments
 (0)