style(prettier): format code style

This commit is contained in:
unix
2020-05-06 14:18:28 +08:00
parent cf8e277324
commit 112c826575
263 changed files with 4927 additions and 3992 deletions

View File

@@ -8,7 +8,7 @@ describe('Input', () => {
const wrapper = mount(<Input placeholder="placeholder" />)
expect(() => wrapper.unmount()).not.toThrow()
})
it('should work with different sizes', () => {
const wrapper = mount(
<div>
@@ -16,29 +16,31 @@ describe('Input', () => {
<Input size="small" />
<Input size="large" />
<Input width="50%" />
</div>
</div>,
)
expect(wrapper.html()).toMatchSnapshot()
})
it('should work with different status', () => {
const wrapper = mount(
<div>
<Input status="secondary" />
<Input status="success" />
<Input status="warning" />
</div>
</div>,
)
expect(wrapper.html()).toMatchSnapshot()
})
it('should be work with label', () => {
const wrapper = mount(
<div>
<Input label="label" />
<Input labelRight="label" />
<Input><span>Block Label</span></Input>
</div>
<Input>
<span>Block Label</span>
</Input>
</div>,
)
expect(wrapper.html()).toMatchSnapshot()
})
@@ -47,95 +49,104 @@ describe('Input', () => {
<div>
<Input icon={<span>test-icon</span>} />
<Input iconRight={<span>test-icon</span>} />
</div>
</div>,
)
expect(wrapper.html()).toMatchSnapshot()
})
it('should set input from value', () => {
let wrapper = mount(<Input initialValue="test" />)
let input = wrapper.find('input').getDOMNode() as HTMLInputElement
expect(input.value).toEqual('test')
wrapper = mount(<Input value="test2" />)
input = wrapper.find('input').getDOMNode() as HTMLInputElement
expect(input.value).toEqual('test2')
wrapper.setProps({ value: 'test3' })
input = wrapper.find('input').getDOMNode() as HTMLInputElement
expect(input.value).toEqual('test3')
})
it('should trigger event when input changed', () => {
let value = ''
const callback = jest.fn()
.mockImplementation((e: React.ChangeEvent<HTMLInputElement>) => value = e.target.value)
const callback = jest
.fn()
.mockImplementation((e: React.ChangeEvent<HTMLInputElement>) => (value = e.target.value))
const wrapper = mount(<Input onChange={callback} />)
wrapper.find('input').at(0)
wrapper
.find('input')
.at(0)
.simulate('change', { target: { value: 'test' } })
expect(callback).toHaveBeenCalled()
expect(value).toEqual('test')
})
it('should ignore event when input disabled', () => {
const callback = jest.fn()
const wrapper = mount(<Input onChange={callback} disabled />)
wrapper.find('input').at(0)
wrapper
.find('input')
.at(0)
.simulate('change', { target: { value: 'test' } })
expect(callback).not.toHaveBeenCalled()
})
it('should ignore event when input readonly', () => {
const callback = jest.fn()
const wrapper = mount(<Input onChange={callback} readOnly />)
wrapper.find('input').at(0)
wrapper
.find('input')
.at(0)
.simulate('change', { target: { value: 'test' } })
expect(callback).not.toHaveBeenCalled()
})
it('should clear text', () => {
let value = ''
const callback = jest.fn()
.mockImplementation((e: React.ChangeEvent<HTMLInputElement>) => value = e.target.value)
const callback = jest
.fn()
.mockImplementation((e: React.ChangeEvent<HTMLInputElement>) => (value = e.target.value))
const clearHandler = jest.fn()
const wrapper = mount(<Input onChange={callback} clearable onClearClick={clearHandler} />)
wrapper.find('input').at(0)
wrapper
.find('input')
.at(0)
.simulate('change', { target: { value: 'test' } })
expect(callback).toHaveBeenCalled()
expect(value).toEqual('test')
wrapper.find('.clear-icon').at(0)
.simulate('click', nativeEvent)
wrapper.find('.clear-icon').at(0).simulate('click', nativeEvent)
expect(clearHandler).toHaveBeenCalled()
expect(value).toEqual('')
})
it('should trigger focus correctly', () => {
const focus = jest.fn()
const blur = jest.fn()
const wrapper = mount(<Input onFocus={focus} onBlur={blur} />)
const input = wrapper.find('input').at(0)
input.simulate('focus')
expect(focus).toHaveBeenCalled()
input.simulate('blur')
expect(blur).toHaveBeenCalled()
})
it('should trigger icon event', () => {
const click = jest.fn()
const wrapper = mount(
<Input icon={<span id="test-icon">icon</span>} onIconClick={click} iconClickable />
<Input icon={<span id="test-icon">icon</span>} onIconClick={click} iconClickable />,
)
wrapper.find('#test-icon').simulate('click', nativeEvent)
expect(click).toHaveBeenCalled()
})
it('should ignore icon event when input disabled', () => {
const click = jest.fn()
const wrapper = mount(
<Input icon={<span id="test-icon">icon</span>} onIconClick={click} iconClickable disabled />
<Input icon={<span id="test-icon">icon</span>} onIconClick={click} iconClickable disabled />,
)
wrapper.find('#test-icon').simulate('click', nativeEvent)
expect(click).not.toHaveBeenCalled()

View File

@@ -11,14 +11,14 @@ describe('InputPassword', () => {
expect(wrapper.html()).toMatchSnapshot()
expect(() => wrapper.unmount()).not.toThrow()
})
it('should toggle input type', () => {
const wrapper = mount(<Input.Password />)
wrapper.find('.input-icon').simulate('click', nativeEvent)
const el = wrapper.find('input').getDOMNode() as HTMLInputElement
expect(el.type).toEqual('text')
})
it('should hide toggle icon', () => {
const wrapper = mount(<Input.Password hideToggle />)
expect(wrapper.find('.input-icon').length).toBe(0)

View File

@@ -5,8 +5,7 @@ import { Input, useInput } from 'components'
describe('UseInput', () => {
it('should follow change with use-input', () => {
let log = ''
const logSpy = jest.spyOn(console, 'log')
.mockImplementation(msg => log = msg)
const logSpy = jest.spyOn(console, 'log').mockImplementation((msg) => (log = msg))
const MockInput: React.FC<{ value?: string }> = ({ value }) => {
const { state, setState, bindings } = useInput('')
useEffect(() => {
@@ -17,23 +16,28 @@ describe('UseInput', () => {
}, [state])
return <Input {...bindings} />
}
const wrapper = mount(<MockInput />)
wrapper.setProps({ value: 'test' })
const input = wrapper.find('input').at(0).getDOMNode() as HTMLInputElement
expect(input.value).toEqual('test')
expect(log).toContain('test')
log = ''
wrapper.find('input').at(0)
.simulate('change', { target: { value: 'test-change' }})
wrapper
.find('input')
.at(0)
.simulate('change', { target: { value: 'test-change' } })
expect(log).toContain('test-change')
logSpy.mockRestore()
})
it('should follow change with use-input', () => {
const MockInput: React.FC<{ value?: string, resetValue?: boolean }> = ({ value, resetValue }) => {
const MockInput: React.FC<{ value?: string; resetValue?: boolean }> = ({
value,
resetValue,
}) => {
const { reset, setState, bindings } = useInput('')
useEffect(() => {
if (value) setState(value)
@@ -43,12 +47,12 @@ describe('UseInput', () => {
}, [resetValue])
return <Input {...bindings} />
}
const wrapper = mount(<MockInput />)
wrapper.setProps({ value: 'test' })
let input = wrapper.find('input').at(0).getDOMNode() as HTMLInputElement
expect(input.value).toEqual('test')
wrapper.setProps({ resetValue: true })
input = wrapper.find('input').at(0).getDOMNode() as HTMLInputElement
expect(input.value).toEqual('')

View File

@@ -1,14 +1,11 @@
import React from 'react'
import useTheme from '../styles/use-theme'
export interface InputBlockLabelLabel {
}
export interface InputBlockLabelLabel {}
const InputBlockLabel: React.FC<React.PropsWithChildren<InputBlockLabelLabel>> = ({
children,
}) => {
const InputBlockLabel: React.FC<React.PropsWithChildren<InputBlockLabelLabel>> = ({ children }) => {
const theme = useTheme()
return (
<label>
{children}
@@ -22,11 +19,11 @@ const InputBlockLabel: React.FC<React.PropsWithChildren<InputBlockLabelLabel>> =
font-size: 1rem;
line-height: 1.5;
}
label > :global(*:first-child) {
margin-top: 0;
}
label > :global(*:last-child) {
margin-bottom: 0;
}

View File

@@ -8,9 +8,7 @@ interface Props {
disabled?: boolean
}
const InputIconClear: React.FC<Props> = ({
onClick, heightRatio, disabled, visibale,
}) => {
const InputIconClear: React.FC<Props> = ({ onClick, heightRatio, disabled, visibale }) => {
const theme = useTheme()
const width = useMemo(() => {
return heightRatio ? `calc(10.66px * ${heightRatio})` : '18px'
@@ -23,12 +21,18 @@ const InputIconClear: React.FC<Props> = ({
}
return (
<div onClick={clickHandler} className={`clear-icon ${visibale ? 'visibale' : ''}`}>
<svg viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"
strokeLinejoin="round" fill="none" shapeRendering="geometricPrecision">
<svg
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
fill="none"
shapeRendering="geometricPrecision">
<path d="M18 6L6 18" />
<path d="M6 6l12 12" />
</svg>
<style jsx>{`
.clear-icon {
padding: 0 ${theme.layout.gapHalf};
@@ -43,16 +47,16 @@ const InputIconClear: React.FC<Props> = ({
visibility: hidden;
opacity: 0;
}
.visibale {
visibility: visible;
opacity: 1;
}
.clear-icon:hover {
color: ${disabled ? theme.palette.accents_3 : theme.palette.foreground};
}
svg {
color: currentColor;
width: ${width};

View File

@@ -8,9 +8,7 @@ export interface InputIconProps {
onClick: (e: React.MouseEvent<HTMLDivElement>) => void
}
const InputIcon: React.FC<InputIconProps> = ({
icon, ratio, clickable, onClick,
}) => {
const InputIcon: React.FC<InputIconProps> = ({ icon, ratio, clickable, onClick }) => {
const theme = useTheme()
const width = useMemo(() => {
return `calc(${ratio} * ${theme.layout.gap} * .42)`

View File

@@ -7,10 +7,12 @@ export interface InputLabel {
}
const InputLabel: React.FC<React.PropsWithChildren<InputLabel>> = ({
children, isRight, fontSize,
children,
isRight,
fontSize,
}) => {
const theme = useTheme()
return (
<span className={isRight ? 'right' : ''}>
{children}
@@ -33,7 +35,7 @@ const InputLabel: React.FC<React.PropsWithChildren<InputLabel>> = ({
font-size: ${fontSize};
line-height: 1;
}
span.right {
border-top-left-radius: 0;
border-bottom-left-radius: 0;

View File

@@ -14,7 +14,7 @@ export type InputProps = Props & typeof defaultProps & NativeAttrs
const simulateChangeEvent = (
el: HTMLInputElement,
event: React.MouseEvent<HTMLDivElement>
event: React.MouseEvent<HTMLDivElement>,
): React.ChangeEvent<HTMLInputElement> => {
return {
...event,
@@ -23,196 +23,240 @@ const simulateChangeEvent = (
}
}
const Input = React.forwardRef<HTMLInputElement, React.PropsWithChildren<InputProps>>(({
label, labelRight, size, status, icon, iconRight, iconClickable, onIconClick,
initialValue, onChange, readOnly, value, onClearClick, clearable, width,
className, onBlur, onFocus, autoComplete, placeholder, children, disabled,
...props
}, ref: React.Ref<HTMLInputElement | null>) => {
const theme = useTheme()
const inputRef = useRef<HTMLInputElement>(null)
useImperativeHandle(ref, () => inputRef.current)
const Input = React.forwardRef<HTMLInputElement, React.PropsWithChildren<InputProps>>(
(
{
label,
labelRight,
size,
status,
icon,
iconRight,
iconClickable,
onIconClick,
initialValue,
onChange,
readOnly,
value,
onClearClick,
clearable,
width,
className,
onBlur,
onFocus,
autoComplete,
placeholder,
children,
disabled,
...props
},
ref: React.Ref<HTMLInputElement | null>,
) => {
const theme = useTheme()
const inputRef = useRef<HTMLInputElement>(null)
useImperativeHandle(ref, () => inputRef.current)
const [selfValue, setSelfValue] = useState<string>(initialValue)
const [hover, setHover] = useState<boolean>(false)
const { heightRatio, fontSize } = useMemo(() => getSizes(size),[size])
const showClearIcon = useMemo(() => clearable && selfValue !== '', [selfValue, clearable])
const labelClasses = useMemo(
() => labelRight ? 'right-label' : (label ? 'left-label' : ''),
[label, labelRight],
)
const iconClasses = useMemo(
() => iconRight ? 'right-icon' : (icon ? 'left-icon' : ''),
[icon, iconRight],
)
const { color, borderColor, hoverBorder } = useMemo(
() => getColors(theme.palette, status),
[theme.palette, status],
)
const changeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
if (disabled || readOnly) return
setSelfValue(event.target.value)
onChange && onChange(event)
}
const clearHandler = (event: React.MouseEvent<HTMLDivElement>) => {
setSelfValue('')
onClearClick && onClearClick(event)
/* istanbul ignore next */
if (!inputRef.current) return
const changeEvent = simulateChangeEvent(inputRef.current, event)
changeEvent.target.value = ''
onChange && onChange(changeEvent)
inputRef.current.focus()
}
const [selfValue, setSelfValue] = useState<string>(initialValue)
const [hover, setHover] = useState<boolean>(false)
const { heightRatio, fontSize } = useMemo(() => getSizes(size), [size])
const showClearIcon = useMemo(() => clearable && selfValue !== '', [selfValue, clearable])
const labelClasses = useMemo(() => (labelRight ? 'right-label' : label ? 'left-label' : ''), [
label,
labelRight,
])
const iconClasses = useMemo(() => (iconRight ? 'right-icon' : icon ? 'left-icon' : ''), [
icon,
iconRight,
])
const { color, borderColor, hoverBorder } = useMemo(() => getColors(theme.palette, status), [
theme.palette,
status,
])
const changeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
if (disabled || readOnly) return
setSelfValue(event.target.value)
onChange && onChange(event)
}
const focusHandler = (e: React.FocusEvent<HTMLInputElement>) => {
setHover(true)
onFocus && onFocus(e)
}
const blurHandler = (e: React.FocusEvent<HTMLInputElement>) => {
setHover(false)
onBlur && onBlur(e)
}
const iconClickHandler = (e: React.MouseEvent<HTMLDivElement>) => {
if (disabled) return
onIconClick && onIconClick(e)
}
const iconProps = useMemo(() => ({
ratio: heightRatio,
clickable: iconClickable,
onClick: iconClickHandler,
}), [heightRatio, iconClickable])
useEffect(() => {
if (value === undefined) return
setSelfValue(value)
}, [value])
return (
<div className="with-label">
{children && <InputBlockLabel>{children}</InputBlockLabel>}
<div className={`input-container ${className}`}>
{label && <InputLabel fontSize={fontSize}>{label}</InputLabel>}
<div className={`input-wrapper ${hover ? 'hover' : ''} ${disabled ? 'disabled' : ''} ${labelClasses}`}>
{icon && <InputIcon icon={icon} {...iconProps} />}
<input type="text" ref={inputRef}
className={`${disabled ? 'disabled' : ''} ${iconClasses}`}
value={selfValue}
placeholder={placeholder}
disabled={disabled}
readOnly={readOnly}
onFocus={focusHandler}
onBlur={blurHandler}
onChange={changeHandler}
autoComplete={autoComplete}
{...props}
/>
{clearable && <InputClearIcon
visibale={showClearIcon}
heightRatio={heightRatio}
disabled={disabled || readOnly}
onClick={clearHandler} />}
{iconRight && <InputIcon icon={iconRight} {...iconProps} />}
const clearHandler = (event: React.MouseEvent<HTMLDivElement>) => {
setSelfValue('')
onClearClick && onClearClick(event)
/* istanbul ignore next */
if (!inputRef.current) return
const changeEvent = simulateChangeEvent(inputRef.current, event)
changeEvent.target.value = ''
onChange && onChange(changeEvent)
inputRef.current.focus()
}
const focusHandler = (e: React.FocusEvent<HTMLInputElement>) => {
setHover(true)
onFocus && onFocus(e)
}
const blurHandler = (e: React.FocusEvent<HTMLInputElement>) => {
setHover(false)
onBlur && onBlur(e)
}
const iconClickHandler = (e: React.MouseEvent<HTMLDivElement>) => {
if (disabled) return
onIconClick && onIconClick(e)
}
const iconProps = useMemo(
() => ({
ratio: heightRatio,
clickable: iconClickable,
onClick: iconClickHandler,
}),
[heightRatio, iconClickable],
)
useEffect(() => {
if (value === undefined) return
setSelfValue(value)
}, [value])
return (
<div className="with-label">
{children && <InputBlockLabel>{children}</InputBlockLabel>}
<div className={`input-container ${className}`}>
{label && <InputLabel fontSize={fontSize}>{label}</InputLabel>}
<div
className={`input-wrapper ${hover ? 'hover' : ''} ${
disabled ? 'disabled' : ''
} ${labelClasses}`}>
{icon && <InputIcon icon={icon} {...iconProps} />}
<input
type="text"
ref={inputRef}
className={`${disabled ? 'disabled' : ''} ${iconClasses}`}
value={selfValue}
placeholder={placeholder}
disabled={disabled}
readOnly={readOnly}
onFocus={focusHandler}
onBlur={blurHandler}
onChange={changeHandler}
autoComplete={autoComplete}
{...props}
/>
{clearable && (
<InputClearIcon
visibale={showClearIcon}
heightRatio={heightRatio}
disabled={disabled || readOnly}
onClick={clearHandler}
/>
)}
{iconRight && <InputIcon icon={iconRight} {...iconProps} />}
</div>
{labelRight && (
<InputLabel fontSize={fontSize} isRight={true}>
{labelRight}
</InputLabel>
)}
</div>
{labelRight && <InputLabel fontSize={fontSize} isRight={true}>{labelRight}</InputLabel>}
<style jsx>{`
.with-label {
display: inline-block;
width: ${width};
box-sizing: border-box;
-webkit-box-align: center;
}
.input-container {
display: inline-flex;
align-items: center;
width: ${width};
height: calc(${heightRatio} * ${theme.layout.gap});
}
.input-wrapper {
display: inline-flex;
vertical-align: middle;
align-items: center;
height: 100%;
flex: 1;
user-select: none;
border-radius: ${theme.layout.radius};
border: 1px solid ${borderColor};
transition: border 0.2s ease 0s, color 0.2s ease 0s;
}
.input-wrapper.left-label {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.input-wrapper.right-label {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-wrapper.disabled {
background-color: ${theme.palette.accents_1};
border-color: ${theme.palette.accents_2};
cursor: not-allowed;
}
input.disabled {
cursor: not-allowed;
}
.input-wrapper.hover {
border-color: ${hoverBorder};
}
input {
margin: 4px 10px;
padding: 0;
box-shadow: none;
font-size: ${fontSize};
background-color: transparent;
border: none;
color: ${color};
outline: none;
border-radius: 0;
width: 100%;
-webkit-appearance: none;
}
input.left-icon {
margin-left: 0;
}
input.right-icon {
margin-right: 0;
}
::placeholder,
::-moz-placeholder,
:-ms-input-placeholder,
::-webkit-input-placeholder {
color: ${theme.palette.accents_3};
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:active,
input:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0 30px ${theme.palette.background} inset !important;
-webkit-text-fill-color: ${color} !important;
}
`}</style>
</div>
<style jsx>{`
.with-label {
display: inline-block;
width: ${width};
box-sizing: border-box;
-webkit-box-align: center;
}
.input-container {
display: inline-flex;
align-items: center;
width: ${width};
height: calc(${heightRatio} * ${theme.layout.gap});
}
.input-wrapper {
display: inline-flex;
vertical-align: middle;
align-items: center;
height: 100%;
flex: 1;
user-select: none;
border-radius: ${theme.layout.radius};
border: 1px solid ${borderColor};
transition: border 0.2s ease 0s, color 0.2s ease 0s;
}
.input-wrapper.left-label {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.input-wrapper.right-label {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-wrapper.disabled {
background-color: ${theme.palette.accents_1};
border-color: ${theme.palette.accents_2};
cursor: not-allowed;
}
input.disabled {
cursor: not-allowed;
}
.input-wrapper.hover {
border-color: ${hoverBorder};
}
input {
margin: 4px 10px;
padding: 0;
box-shadow: none;
font-size: ${fontSize};
background-color: transparent;
border: none;
color: ${color};
outline: none;
border-radius: 0;
width: 100%;
-webkit-appearance: none;
}
input.left-icon {
margin-left: 0;
}
input.right-icon {
margin-right: 0;
}
::placeholder, ::-moz-placeholder, :-ms-input-placeholder, ::-webkit-input-placeholder {
color: ${theme.palette.accents_3};
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:active,
input:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0 30px ${theme.palette.background} inset !important;
-webkit-text-fill-color: ${color} !important;
}
`}</style>
</div>
)
})
)
},
)
type InputComponent<P = {}> = React.ForwardRefExoticComponent<P> & {
Textarea: typeof Textarea
Password: typeof InputPassword
}
type ComponentProps = Partial<typeof defaultProps> & Omit<Props, keyof typeof defaultProps> & NativeAttrs
type ComponentProps = Partial<typeof defaultProps> &
Omit<Props, keyof typeof defaultProps> &
NativeAttrs
Input.defaultProps = defaultProps

View File

@@ -6,18 +6,26 @@ interface Props {
const PasswordIcon: React.FC<Props> = ({ visible }) => {
return (
<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"
strokeLinejoin="round" fill="none" shapeRendering="geometricPrecision" style={{ color: 'currentColor' }}>
<svg
viewBox="0 0 24 24"
width="16"
height="16"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
fill="none"
shapeRendering="geometricPrecision"
style={{ color: 'currentColor' }}>
{!visible ? (
<>
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
<circle cx="12" cy="12" r="3"/>
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
<circle cx="12" cy="12" r="3" />
</>
) : (
<>
<path
d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19m-6.72-1.07a3 3 0 11-4.24-4.24"/>
<path d="M1 1l22 22"/>
<path d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19m-6.72-1.07a3 3 0 11-4.24-4.24" />
<path d="M1 1l22 22" />
</>
)}
</svg>

View File

@@ -16,35 +16,41 @@ const passwordDefaultProps = {
type NativeAttrs = Omit<React.InputHTMLAttributes<any>, keyof PasswordProps>
export type InputPasswordProps = PasswordProps & typeof passwordDefaultProps & NativeAttrs
const InputPassword = React.forwardRef<HTMLInputElement, React.PropsWithChildren<InputPasswordProps>>(({
hideToggle, children, ...props
}, ref: React.Ref<HTMLInputElement | null>) => {
const InputPassword = React.forwardRef<
HTMLInputElement,
React.PropsWithChildren<InputPasswordProps>
>(({ hideToggle, children, ...props }, ref: React.Ref<HTMLInputElement | null>) => {
const inputRef = useRef<HTMLInputElement>(null)
const [visible, setVisible] = useState<boolean>(false)
useImperativeHandle(ref, () => inputRef.current)
const iconClickHandler = () => {
setVisible(v => !v)
setVisible((v) => !v)
/* istanbul ignore next */
if (inputRef && inputRef.current) {
inputRef.current.focus()
}
}
const inputProps = useMemo(() => ({
...props,
ref: inputRef,
iconClickable: true,
onIconClick: iconClickHandler,
type: visible ? 'text' : 'password',
}), [props, iconClickHandler, visible, inputRef])
const inputProps = useMemo(
() => ({
...props,
ref: inputRef,
iconClickable: true,
onIconClick: iconClickHandler,
type: visible ? 'text' : 'password',
}),
[props, iconClickHandler, visible, inputRef],
)
const icon = useMemo(() => {
if (hideToggle) return null
return <PasswordIcon visible={visible} />
}, [hideToggle, visible])
return (
<Input iconRight={icon} {...inputProps}>{children}</Input>
<Input iconRight={icon} {...inputProps}>
{children}
</Input>
)
})

View File

@@ -63,7 +63,7 @@ export const getColors = (palette: ZeitUIThemesPalette, status?: NormalTypes): I
hoverBorder: palette.errorDark,
},
}
if (!status) return colors.default
return colors[status]
}

View File

@@ -1,7 +1,9 @@
import React, { Dispatch, MutableRefObject, SetStateAction } from 'react'
import useCurrentState from '../utils/use-current-state'
const useInput = (initialValue: string): {
const useInput = (
initialValue: string,
): {
state: string
setState: Dispatch<SetStateAction<string>>
currentRef: MutableRefObject<string>
@@ -12,7 +14,7 @@ const useInput = (initialValue: string): {
}
} => {
const [state, setState, currentRef] = useCurrentState<string>(initialValue)
return {
state,
setState,