refactor: refactor TextField component

This commit is contained in:
Hossein Mehrabi 2023-02-23 23:50:11 +03:30
parent 242868b6d9
commit b865ef30e8
5 changed files with 77 additions and 47 deletions

View File

@ -4,8 +4,6 @@ import { iconButtonClasses } from './IconButton.classes'
export const IconButtonStyles = css` export const IconButtonStyles = css`
.${iconButtonClasses.root} { .${iconButtonClasses.root} {
display: flex; display: flex;
width: 32px;
height: 28px;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@ -1,15 +1,16 @@
export const textFieldClasses = { export const textFieldClasses = {
root: `lsd-textField`, root: `lsd-text-field`,
input: `lsd-textField__input`, inputContainer: `lsd-text-field-input-container`,
icon: `lsd-textField__icon`, input: `lsd-text-field-input-container__input`,
icon: `lsd-text-field-input-container__icon`,
clearButton: `lsd-text-field-input-container__clear-button`,
supportingText: 'lsd-textField__supporting-text', supportingText: 'lsd-text-field__supporting-text',
disabled: `lsd-textField--disabled`, disabled: `lsd-text-field--disabled`,
error: 'lsd-textField--error', error: 'lsd-text-field--error',
large: `lsd-textField--large`, large: `lsd-text-field--large`,
medium: `lsd-textField--medium`, medium: `lsd-text-field--medium`,
withIcon: `lsd-textField--with-icon`,
} }

View File

@ -1,4 +1,5 @@
import { Meta, Story } from '@storybook/react' import { Meta, Story } from '@storybook/react'
import { useStorybookIconComponent } from '../../utils/storybook.utils'
import { TextField, TextFieldProps } from './TextField' import { TextField, TextFieldProps } from './TextField'
export default { export default {
@ -12,18 +13,37 @@ export default {
}, },
defaultValue: 'large', defaultValue: 'large',
}, },
icon: {
type: {
name: 'enum',
value: useStorybookIconComponent.options,
},
defaultValue: 'FolderIcon',
},
}, },
} as Meta } as Meta
export const Root: Story<TextFieldProps> = (args) => ( export const Root: Story<Omit<TextFieldProps, 'icon'> & { icon: string }> = ({
<TextField {...args}>TextField</TextField> icon,
) ...args
}) => {
const Icon = useStorybookIconComponent(icon)
return (
<TextField {...args} icon={Icon && <Icon color="primary" />}>
TextField
</TextField>
)
}
Root.args = { Root.args = {
size: 'large', size: 'large',
supportingText: 'Supporting text', supportingText: 'Supporting text',
disabled: false, disabled: false,
withIcon: false,
error: false, error: false,
errorIcon: false,
icon: 'None',
clearButton: true,
placeholder: 'Placeholder', placeholder: 'Placeholder',
defaultValue: 'default value', defaultValue: 'default value',
onChange: undefined, onChange: undefined,

View File

@ -6,11 +6,11 @@ export const TextFieldStyles = css`
width: auto; width: auto;
border-bottom: 1px solid rgb(var(--lsd-border-primary)); border-bottom: 1px solid rgb(var(--lsd-border-primary));
box-sizing: border-box; box-sizing: border-box;
align-items: center;
} }
.${textFieldClasses.root} > div { .${textFieldClasses.inputContainer} {
display: flex; display: flex;
align-items: center;
justify-content: space-between; justify-content: space-between;
} }
@ -36,7 +36,7 @@ export const TextFieldStyles = css`
opacity: 0.3; opacity: 0.3;
} }
.${textFieldClasses.error} { .${textFieldClasses.error} .${textFieldClasses.input} {
text-decoration: line-through; text-decoration: line-through;
} }
@ -57,12 +57,19 @@ export const TextFieldStyles = css`
padding: 6px 12px; padding: 6px 12px;
} }
.${textFieldClasses.withIcon} { .${textFieldClasses.clearButton} {
padding: 0;
width: auto;
height: auto;
margin: 0;
border: 0;
svg {
width: 100%;
height: auto;
}
} }
.${textFieldClasses.icon} { .${textFieldClasses.icon} {
cursor: pointer;
display: flex;
align-items: center;
} }
` `

View File

@ -1,7 +1,8 @@
import clsx from 'clsx' import clsx from 'clsx'
import React, { useRef } from 'react' import React, { useRef } from 'react'
import { useInput } from '../../utils/useInput' import { useInput } from '../../utils/useInput'
import { CheckIcon, CloseIcon, ErrorIcon } from '../Icons' import { IconButton } from '../IconButton'
import { CloseIcon, ErrorIcon } from '../Icons'
import { Typography } from '../Typography' import { Typography } from '../Typography'
import { textFieldClasses } from './TextField.classes' import { textFieldClasses } from './TextField.classes'
@ -11,8 +12,10 @@ export type TextFieldProps = Omit<
> & > &
Pick<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> & { Pick<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> & {
size?: 'large' | 'medium' size?: 'large' | 'medium'
withIcon?: boolean icon?: React.ReactNode
error?: boolean error?: boolean
errorIcon?: boolean
clearButton?: boolean
disabled?: boolean disabled?: boolean
supportingText?: string supportingText?: string
value?: string value?: string
@ -25,13 +28,16 @@ export const TextField: React.FC<TextFieldProps> & {
classes: typeof textFieldClasses classes: typeof textFieldClasses
} = ({ } = ({
size = 'large', size = 'large',
withIcon = false, icon,
supportingText,
error = false, error = false,
errorIcon = false,
clearButton,
supportingText,
children, children,
value, value,
placeholder, placeholder,
defaultValue, defaultValue,
disabled,
onChange, onChange,
inputProps = {}, inputProps = {},
...props ...props
@ -43,41 +49,39 @@ export const TextField: React.FC<TextFieldProps> & {
return ( return (
<div <div
aria-disabled={disabled ? 'true' : 'false'}
className={clsx( className={clsx(
props.className, props.className,
textFieldClasses.root, textFieldClasses.root,
textFieldClasses[size], textFieldClasses[size],
props.disabled && textFieldClasses.disabled, disabled && textFieldClasses.disabled,
withIcon && textFieldClasses.withIcon, error && textFieldClasses.error,
)} )}
{...props} {...props}
> >
<div> <div className={textFieldClasses.inputContainer}>
<input <input
placeholder={placeholder} placeholder={placeholder}
{...inputProps} {...inputProps}
ref={ref} ref={ref}
value={input.value} value={input.value}
onChange={input.onChange} onChange={input.onChange}
className={clsx( className={clsx(inputProps.className, textFieldClasses.input)}
inputProps.className,
textFieldClasses.input,
error && textFieldClasses.error,
)}
/> />
{withIcon && error ? ( {error && errorIcon ? (
<span className={textFieldClasses.icon} onClick={onCancel}> <ErrorIcon color="primary" className={textFieldClasses.icon} />
<ErrorIcon color="primary" className={textFieldClasses.icon} /> ) : clearButton && input.filled ? (
</span> <IconButton
) : withIcon && !input.filled ? ( disabled={disabled}
<span className={textFieldClasses.icon}> onClick={() => !disabled && onCancel()}
<CheckIcon color="primary" /> aria-label="clear"
</span> className={textFieldClasses.clearButton}
) : withIcon && input.filled ? ( >
<span className={textFieldClasses.icon} onClick={onCancel}> <CloseIcon color="primary" className={textFieldClasses.icon} />
<CloseIcon color="primary" /> </IconButton>
</span> ) : (
) : null} icon
)}
</div> </div>
{supportingText && ( {supportingText && (
<div className={clsx(textFieldClasses.supportingText)}> <div className={clsx(textFieldClasses.supportingText)}>