mirror of https://github.com/acid-info/lsd.git
feat: enhance TextField functionality
This commit is contained in:
parent
146337e8f4
commit
74a54a6575
|
@ -25,4 +25,6 @@ Root.args = {
|
|||
withIcon: false,
|
||||
error: false,
|
||||
placeholder: 'Placeholder',
|
||||
defaultValue: 'default value',
|
||||
onChange: undefined,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import clsx from 'clsx'
|
||||
import React, { useRef, useState } from 'react'
|
||||
import React, { useRef } from 'react'
|
||||
import { useInput } from '../../utils/useInput'
|
||||
import { CheckIcon, CloseIcon, ErrorIcon } from '../Icons'
|
||||
import { Typography } from '../Typography'
|
||||
import { textFieldClasses } from './TextField.classes'
|
||||
|
@ -7,15 +8,17 @@ import { textFieldClasses } from './TextField.classes'
|
|||
export type TextFieldProps = Omit<
|
||||
React.HTMLAttributes<HTMLDivElement>,
|
||||
'onChange' | 'value'
|
||||
> & {
|
||||
size?: 'large' | 'medium'
|
||||
withIcon?: boolean
|
||||
error?: boolean
|
||||
disabled?: boolean
|
||||
supportingText?: string
|
||||
value?: string
|
||||
onChange?: (value: any) => void
|
||||
}
|
||||
> &
|
||||
Pick<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> & {
|
||||
size?: 'large' | 'medium'
|
||||
withIcon?: boolean
|
||||
error?: boolean
|
||||
disabled?: boolean
|
||||
supportingText?: string
|
||||
value?: string
|
||||
defaultValue?: string
|
||||
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
|
||||
}
|
||||
|
||||
export const TextField: React.FC<TextFieldProps> & {
|
||||
classes: typeof textFieldClasses
|
||||
|
@ -26,26 +29,18 @@ export const TextField: React.FC<TextFieldProps> & {
|
|||
error = false,
|
||||
children,
|
||||
value,
|
||||
defaultValue,
|
||||
onChange,
|
||||
inputProps = {},
|
||||
...props
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [inputValue, setInputValue] = useState<string>('')
|
||||
const ref = useRef<HTMLInputElement>(null)
|
||||
const input = useInput({ defaultValue, value, onChange, ref })
|
||||
|
||||
const handleChange = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
const newValue = e.currentTarget.value
|
||||
if (onChange) onChange(newValue)
|
||||
setInputValue(newValue)
|
||||
}
|
||||
|
||||
const onCancel = () => {
|
||||
setInputValue('')
|
||||
if (typeof onChange !== 'undefined') onChange('')
|
||||
}
|
||||
const onCancel = () => input.setValue('')
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx(
|
||||
props.className,
|
||||
textFieldClasses.root,
|
||||
|
@ -53,26 +48,29 @@ export const TextField: React.FC<TextFieldProps> & {
|
|||
props.disabled && textFieldClasses.disabled,
|
||||
withIcon && textFieldClasses.withIcon,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
onChange={handleChange}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
value={input.value}
|
||||
onChange={input.onChange}
|
||||
className={clsx(
|
||||
inputProps.className,
|
||||
textFieldClasses.input,
|
||||
error && textFieldClasses.error,
|
||||
)}
|
||||
value={inputValue}
|
||||
{...props}
|
||||
/>
|
||||
{withIcon && error ? (
|
||||
<span className={textFieldClasses.icon} onClick={onCancel}>
|
||||
<ErrorIcon color="primary" className={textFieldClasses.icon} />
|
||||
</span>
|
||||
) : withIcon && !inputValue.length ? (
|
||||
) : withIcon && !input.filled ? (
|
||||
<span className={textFieldClasses.icon}>
|
||||
<CheckIcon color="primary" />
|
||||
</span>
|
||||
) : withIcon && inputValue.length ? (
|
||||
) : withIcon && input.filled ? (
|
||||
<span className={textFieldClasses.icon} onClick={onCancel}>
|
||||
<CloseIcon color="primary" />
|
||||
</span>
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
export type InputValueType =
|
||||
React.InputHTMLAttributes<HTMLInputElement>['value']
|
||||
|
||||
export type InputOnChangeType =
|
||||
React.InputHTMLAttributes<HTMLInputElement>['onChange']
|
||||
|
||||
export type InputProps = {
|
||||
value?: InputValueType
|
||||
defaultValue?: InputValueType
|
||||
onChange?: InputOnChangeType
|
||||
ref?: React.RefObject<HTMLInputElement>
|
||||
}
|
||||
|
||||
export const useInput = (props: InputProps) => {
|
||||
const [value, setValue] = useState<InputValueType>(
|
||||
props.value ?? props.defaultValue ?? '',
|
||||
)
|
||||
|
||||
const uncontrolled = typeof props.value === 'undefined'
|
||||
const filled =
|
||||
typeof value === 'undefined'
|
||||
? false
|
||||
: typeof value === 'string'
|
||||
? value.length > 0
|
||||
: value.toString().length > 0
|
||||
|
||||
const onChange: InputOnChangeType = (event) => {
|
||||
if (uncontrolled) return setValue(event.target.value)
|
||||
props.onChange && props.onChange(event)
|
||||
}
|
||||
|
||||
const setter = (value: InputValueType) => {
|
||||
if (!props.ref?.current) return
|
||||
|
||||
const element = props.ref.current
|
||||
const event = new Event('input', { bubbles: true })
|
||||
|
||||
Object.getOwnPropertyDescriptor(
|
||||
window.HTMLInputElement.prototype,
|
||||
'value',
|
||||
)?.set?.call?.(element, value)
|
||||
|
||||
element.dispatchEvent(event)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
!uncontrolled && setValue(props.value)
|
||||
}, [uncontrolled, props.value])
|
||||
|
||||
return {
|
||||
value,
|
||||
filled,
|
||||
onChange,
|
||||
setValue: setter,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue