From 10ab4a7772f6db440ab16df42e41cdf6485f160b Mon Sep 17 00:00:00 2001 From: Marcos Conceicao Date: Tue, 8 Oct 2024 14:46:26 -0300 Subject: [PATCH] feat(AutoComplete.jsx): Migrated to css modules and updated types and snapshots --- components/AutoComplete/AutoComplete.jsx | 210 ++++-------------- .../AutoComplete/AutoComplete.module.css | 81 +++++++ .../AutoComplete.unit.test.jsx.snap | 50 +++-- components/AutoComplete/index.css | 1 + components/AutoComplete/index.d.ts | 4 - components/index.css | 1 + 6 files changed, 154 insertions(+), 193 deletions(-) create mode 100644 components/AutoComplete/AutoComplete.module.css create mode 100644 components/AutoComplete/index.css diff --git a/components/AutoComplete/AutoComplete.jsx b/components/AutoComplete/AutoComplete.jsx index c87a36f1e..b8469efde 100644 --- a/components/AutoComplete/AutoComplete.jsx +++ b/components/AutoComplete/AutoComplete.jsx @@ -1,8 +1,7 @@ import { useState, useRef, useEffect } from 'react'; import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; -import { shadow, normalizeChars } from '../shared'; -import { baseFontSize, colors, spacing } from '../shared/theme'; +import classNames from 'classnames'; +import { normalizeChars } from '../shared'; import Icon from '../Icon'; import { @@ -13,140 +12,10 @@ import { RequiredMark, } from '../Input/sub-components'; import useKeyPress from './SubComponents/UseKeyPress'; +import styles from './AutoComplete.module.css'; -const ITEM_HEIGHT = '44px'; -const MAX_ITEMS_VISIBILITY = 7; -const DROPITEM_FONT_SIZE = baseFontSize * 0.875; const NON_FOCUSABLE_SUGGESTION_INDEX = -1; -const ComponentWrapper = styled.div` - ${({ - theme: { - colors: { neutral }, - }, - skin = 'default', - }) => css` - position: relative; - color: ${skin === 'default' ? neutral[700] : neutral[0]}; - `} -`; - -const InputWrapper = styled.div` - position: relative; -`; - -const propsNotContainedInTextInput = ['theme']; - -const InputText = styled(TextInput).withConfig({ - shouldForwardProp: (prop) => !propsNotContainedInTextInput.includes(prop), -})` - ${({ - theme: { - spacing: { xsmall }, - }, - }) => css` - margin-top: ${xsmall}px; - `} -`; - -const InputIcon = styled(Icon)` - cursor: pointer; - position: absolute; - ${({ - theme: { - spacing: { xsmall, medium }, - }, - }) => css` - right: ${medium}px; - bottom: ${xsmall * 1.25}px; - width: ${baseFontSize * 1.5}px; - `} -`; - -const InputErrorIcon = styled(InputIcon).attrs({ name: 'error' })` - ${({ - theme: { - colors: { - error: { 700: error700 }, - }, - }, - skin, - }) => css` - color: ${skin === 'default' ? error700 : 'inherit'}; - `} -`; - -const List = styled.ul` - border-radius: 4px; - box-sizing: border-box; - list-style: none; - max-height: calc(${ITEM_HEIGHT} * ${MAX_ITEMS_VISIBILITY}); - overflow: auto; - padding: 0; - position: absolute; - width: 100%; - z-index: 1; - - ${({ theme }) => { - const { - spacing: { xxsmall }, - colors: { - neutral: { 0: neutral0, 700: neutral700 }, - }, - } = theme; - return css` - background-color: ${neutral0}; - margin-top: ${xxsmall}px; - ${shadow(3, neutral700)({ theme })}; - `; - }} -`; - -const ListItem = styled.li` - display: flex; - align-items: center; - justify-content: space-between; - box-sizing: border-box; - cursor: pointer; - height: ${ITEM_HEIGHT}; - ${({ - theme: { - spacing: { xsmall, medium }, - colors: { - neutral: { 0: neutral0, 700: neutral700 }, - }, - }, - }) => css` - color: ${neutral700}; - font-size: ${DROPITEM_FONT_SIZE}px; - background-color: ${neutral0}; - padding: ${xsmall}px ${medium}px; - `} - - &[aria-selected = 'true' ], &:hover { - ${({ - theme: { - colors: { - neutral: { 100: neutral100 }, - }, - }, - }) => css` - background-color: ${neutral100}; - `} - } -`; - -const PoliteStatus = styled.div` - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; -`; - const AutoComplete = ({ id = '', name = '', @@ -157,15 +26,25 @@ const AutoComplete = ({ helperText = '', placeholder = 'Select an option', suggestions, - theme = { - spacing, - colors, - }, onSelectedItem = () => {}, onChange = () => {}, required = false, skin = 'default', }) => { + const wrapperClass = classNames(styles.wrapper, { + [styles['wrapper-dark']]: skin === 'dark', + }); + const inputWrapperClass = classNames(styles['input-wrapper']); + const inputTextClass = classNames(styles['input-text']); + const inputIconClass = classNames(styles['input-icon']); + const inputErrorIconClass = classNames( + styles['input-icon'], + styles[`input-error-icon-${skin}`], + ); + const listClass = classNames(styles['list-suggestions'], 'shadow-3'); + const itemClass = classNames(styles['item-suggestions']); + const politeClass = classNames(styles['polite-status']); + const [userTypedValue, setUserTypedValue] = useState(value); const [filterSuggestions, setFilterSuggestions] = useState(suggestions); const [filterSuggestionsLength, setFilterSuggestionsLength] = useState( @@ -248,27 +127,27 @@ const AutoComplete = ({ const generateSuggestions = () => showSuggestions && filterSuggestions ? ( - {filterSuggestions.map((item, index) => ( - handleItemClick(item)} - theme={theme} + className={itemClass} aria-selected={index === cursor} role="option" tabIndex="-1" > {item} - + ))} - + ) : null; const generateAssistiveDescript = () => { @@ -346,13 +225,13 @@ const AutoComplete = ({ }, [suggestions]); return ( - - +
+
{label} {required && *} - handleChange(e.target.value)} skin={skin} required={required} - theme={theme} + className={inputTextClass} /> {userTypedValue && !error && !disabled && ( - handleClearValue()} + className={inputIconClass} /> )} {generateSuggestions()} {error && ( - + )} - +
{helperText && {helperText}} - {error && ( - - {error} - - )} - + {error && {error}} +
{generateAssistiveDescript()} - - +
+
); }; AutoComplete.propTypes = { - theme: PropTypes.shape({ - colors: PropTypes.object, - spacing: PropTypes.object, - }), /** A list of string or objects with the values to show in component */ suggestions: PropTypes.arrayOf(PropTypes.string).isRequired, id: PropTypes.string, diff --git a/components/AutoComplete/AutoComplete.module.css b/components/AutoComplete/AutoComplete.module.css new file mode 100644 index 000000000..745ef6dfd --- /dev/null +++ b/components/AutoComplete/AutoComplete.module.css @@ -0,0 +1,81 @@ +:root { + --max-items-visibility: 7; + --item-height: 44px; + --dropitem-font-size: calc(var(--qtm-base-font-size) * 0.875); +} + +.wrapper { + position: relative; + color: var(--qtm-colors-neutral-700); +} + +.input-wrapper { + position: relative; +} + +.wrapper-dark { + color: var(--qtm-colors-neutral-0); +} + +.input-text { + margin-top: var(--qtm-spacing-xsmall); +} + +.input-icon { + cursor: pointer; + position: absolute; + right: var(--qtm-spacing-medium); + bottom: calc(var(--qtm-spacing-xsmall) * 1.25); + width: calc(var(--qtm-base-font-size) * 1.5); +} + +.input-error-icon-default { + color: var(--qtm-colors-error-700); +} + +.input-error-icon-dark { + color: inherit; +} + +.polite-status { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.list-suggestions { + border-radius: 4px; + box-sizing: border-box; + list-style: none; + max-height: calc(var(--item-height) * var(--max-items-visibility)); + overflow: auto; + padding: 0; + position: absolute; + width: 100%; + z-index: 1; + background-color: var(--qtm-colors-neutral-0); + margin-top: var(--qtm-spacing-xxsmall); +} + +.item-suggestions { + display: flex; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + cursor: pointer; + height: var(--item-height); + color: var(--qtm-colors-neutral-700); + font-size: var(--dropitem-font-size); + background-color: var(--qtm-colors-neutral-0); + padding: var(--qtm-spacing-xsmall) var(--qtm-spacing-medium); +} + +.item-suggestions[aria-selected='true'], +.item-suggestions:hover { + background-color: var(--qtm-colors-neutral-100); +} \ No newline at end of file diff --git a/components/AutoComplete/__snapshots__/AutoComplete.unit.test.jsx.snap b/components/AutoComplete/__snapshots__/AutoComplete.unit.test.jsx.snap index f9fb67358..b96c012a0 100644 --- a/components/AutoComplete/__snapshots__/AutoComplete.unit.test.jsx.snap +++ b/components/AutoComplete/__snapshots__/AutoComplete.unit.test.jsx.snap @@ -24,22 +24,21 @@ exports[`AutoComplete Should render Autocomplete 1`] = ` width: 100%; } -.c0 { - position: relative; - color: #424242; +.AutoComplete-module__wrapper___0v99I { + color: var(--qtm-colors-neutral-700); } -.c1 { +.AutoComplete-module__input-wrapper___Yz9qd, +.AutoComplete-module__wrapper___0v99I { position: relative; } -.c2 { - margin-top: 8px; +.AutoComplete-module__input-text___8DYxo { + margin-top: var(--qtm-spacing-xsmall); } -.c3 { +.AutoComplete-module__polite-status___DWMsJ { border: 0; - -webkit-clip: rect(0 0 0 0); clip: rect(0 0 0 0); height: 1px; margin: -1px; @@ -50,10 +49,10 @@ exports[`AutoComplete Should render Autocomplete 1`] = ` }