import { Fragment, InputEvent, KeyboardEvent, useEffect, useMemo, useRef } from "react"; import { Input } from "../text/Input"; import clsx from "clsx"; interface TotpInputProps { value: string; length: number; onValue: (value: string) => void; type?: "number" | "alphabet"; autoFocus?: boolean; autoComplete?: "one-time-code"; name?: string; } const space = " "; const getIsValidValue = (value: string, type: TotpInputProps["type"]) => { if (type === "number") { return /[0-9]/.test(value); } return /[0-9A-Za-z]/.test(value); }; export function TotpInput({ value = "", length, onValue, type = "alphabet", autoFocus, name, }: TotpInputProps) { const list = useMemo(() => Array.from({ length }), [length]); const splitValues = value.split(""); const values = list.map((_, i) => { // TODO different from [i]?.[0] vs [i] const value = splitValues[i] || space; if (!getIsValidValue(value, type)) { return space; } return value; }); const refArray = useRef<(HTMLInputElement | null)[]>([]); const focus = (i: number) => { const el = refArray.current?.[i]; el?.focus?.(); }; useEffect(() => { if (refArray.current.length !== list.length) { refArray.current = refArray.current.slice(0, list.length); } }, [list.length]); const handleMultipleValues = (multipleValues: string, i: number) => { const result = multipleValues .slice(0, list.length - i) .split("") .filter((pastedValue) => { const value = pastedValue[0]; return getIsValidValue(value, type); }); if (!result.length) { return; } const newValues = [...values]; newValues.splice(i, result.length, ...result); focus(Math.min(i + result.length, length - 1)); onValue(newValues.join("")); }; const focusIndex = Math.min(value.trim().length, length - 1); return (