Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | 1x 1x 30x 1x 18x 18x 1x 30x 30x 30x 30x 18x 30x 18x 30x 18x 18x 18x 30x 30x 30x 1x 1x | import {forwardRef, useCallback, useEffect, useMemo, useRef} from 'react'
import cx from 'classnames'
import PropTypes from 'prop-types'
import useMergeRefs from '@s-ui/react-hooks/lib/useMergeRefs'
import {actions as pinInputActions} from './reducer/index.js'
import {BASE_CLASSNAME, MASK} from './config.js'
import {usePinInputContext} from './PinInputContext.js'
const CLASSNAME = `${BASE_CLASSNAME}Field`
const getClassName = ({size, status, isFullWidth}) => {
return cx(CLASSNAME, {
[`${CLASSNAME}--size-${size}`]: size,
[`${CLASSNAME}--status-${status}`]: status,
[`${CLASSNAME}--fullWidth`]: isFullWidth
})
}
const getInputMode = ({inputMode, mask}) => {
const maskToInputMode = {
[MASK.NUMBER]: 'numeric',
[MASK.ALPHABETIC]: 'text',
[MASK.ALPHANUMERIC]: 'text'
}
return inputMode || maskToInputMode[mask]
}
const PinInputField = forwardRef(({isFullWidth, ...props}, forwardedRef) => {
const innerRef = useRef()
const {
disabled,
dispatch,
getIndex,
inputMode,
isOneTimeCode,
isPassword,
mask,
onChange = () => null,
placeholder,
setFocus,
size,
status,
value = []
} = usePinInputContext()
const index = getIndex(innerRef.current)
const setElement = useCallback(
node => {
dispatch(pinInputActions.setElement({node}))
},
[dispatch]
)
const removeElement = useCallback(
node => {
dispatch(pinInputActions.removeElement({node}))
},
[dispatch]
)
useEffect(() => {
Eif (innerRef.current) {
setElement(innerRef.current)
}
return () => removeElement(innerRef.current) // eslint-disable-line react-hooks/exhaustive-deps
}, [innerRef, setElement, removeElement])
const onFocusHandler = () => {
if (index >= 0) {
setFocus(index)
}
}
const inputModeMemoized = useMemo(() => getInputMode({inputMode, mask}), [mask, inputMode])
return (
<input
className={getClassName({size, status, isFullWidth})}
disabled={disabled}
maxLength="1"
onChange={onChange}
onClick={onFocusHandler}
onFocus={onFocusHandler}
placeholder={placeholder}
inputMode={inputModeMemoized}
ref={useMergeRefs(innerRef, forwardedRef)}
value={value[index] || ''}
{...(isPassword && {type: 'password'})}
{...(isOneTimeCode && {autoComplete: 'one-time-code'})}
{...props}
/>
)
})
PinInputField.displayName = 'PinInputField'
PinInputField.propTypes = {
/** number value position */
index: PropTypes.number,
/** true input full width false default */
isFullWidth: PropTypes.bool
}
export default PinInputField
|