import * as React from 'react'; import raf from 'rc-util/lib/raf'; import Input, { type InputProps, type InputRef } from '../Input'; export interface OTPInputProps extends Omit { index: number; onChange: (index: number, value: string) => void; /** Tell parent to do active offset */ onActiveChange: (nextIndex: number) => void; } const OTPInput = React.forwardRef((props, ref) => { const { value, onChange, onActiveChange, index, ...restProps } = props; const onInternalChange: React.ChangeEventHandler = (e) => { onChange(index, e.target.value); }; // ========================== Ref =========================== const inputRef = React.useRef(null); React.useImperativeHandle(ref, () => inputRef.current!); // ========================= Focus ========================== const syncSelection = () => { raf(() => { const inputEle = inputRef.current?.input; if (document.activeElement === inputEle && inputEle) { inputEle.select(); } }); }; // ======================== Keyboard ======================== const onInternalKeyDown: React.KeyboardEventHandler = ({ key }) => { if (key === 'ArrowLeft') { onActiveChange(index - 1); } else if (key === 'ArrowRight') { onActiveChange(index + 1); } syncSelection(); }; const onInternalKeyUp: React.KeyboardEventHandler = (e) => { if (e.key === 'Backspace' && !value) { onActiveChange(index - 1); } syncSelection(); }; // ========================= Render ========================= return ( ); }); export default OTPInput;