UNPKG

@ozen-ui/kit

Version:

React component library

178 lines (177 loc) 11.7 kB
import { __assign, __read, __rest } from "tslib"; import './InputOTP.css'; import React, { useImperativeHandle, useEffect, useMemo, useState, } from 'react'; import { useControlled } from '../../hooks/useControlled'; import { useStoredValue } from '../../hooks/useStoredValue'; import { useThemeProps } from '../../hooks/useThemeProps'; import { createEmptyArray } from '../../utils/array'; import { cn } from '../../utils/classname'; import { isFunction } from '../../utils/isFunction'; import { isString } from '../../utils/isString'; import { polymorphicComponentWithRef } from '../../utils/polymorphicComponentWithRef'; import { setRef } from '../../utils/setRef'; import { FieldControl } from '../FieldControl'; import { FieldInput } from '../FieldInput'; import { Fieldset } from '../Fieldset'; import { Stack } from '../Stack'; import { INPUT_OTP_DEFAULT_AUTO_COMPLETE_MODE, INPUT_OTP_DEFAULT_DISABLE_STROKE, INPUT_OTP_DEFAULT_FINISH_BEHAVIOR, INPUT_OTP_DEFAULT_SIZE, INPUT_OTP_DEFAULT_TAG, INPUT_OTP_SPACING_BY_SIZE, } from './constants'; import { maskValue, calculateInput as externalCalculateInput, valueToString, valueToArray, } from './helper'; import { useInputOTPEvents } from './hooks'; export var cnInputOTP = cn('InputOTP'); export var InputOTP = polymorphicComponentWithRef(function (inProps, ref) { var props = useThemeProps({ props: inProps, name: 'InputOTP', }); var _a = props.as, as = _a === void 0 ? INPUT_OTP_DEFAULT_TAG : _a, className = props.className, length = props.length, autoComplete = props.autoComplete, _b = props.autoCompleteMode, autoCompleteMode = _b === void 0 ? INPUT_OTP_DEFAULT_AUTO_COMPLETE_MODE : _b, placeholder = props.placeholder, disabled = props.disabled, error = props.error, onChangeFromProps = props.onChange, ariaLabel = props.ariaLabel, value = props.value, defaultValue = props.defaultValue, mask = props.mask, autoFocus = props.autoFocus, onFinish = props.onFinish, onPasteFromProps = props.onPaste, onKeyDownFromProps = props.onKeyDown, _c = props.disableStroke, disableStroke = _c === void 0 ? INPUT_OTP_DEFAULT_DISABLE_STROKE : _c, validate = props.validate, _d = props.size, size = _d === void 0 ? INPUT_OTP_DEFAULT_SIZE : _d, inputProps = props.inputProps, fieldProps = props.fieldProps, _e = props.finishBehavior, finishBehavior = _e === void 0 ? INPUT_OTP_DEFAULT_FINISH_BEHAVIOR : _e, inputContainerProps = props.inputContainerProps, other = __rest(props, ["as", "className", "length", "autoComplete", "autoCompleteMode", "placeholder", "disabled", "error", "onChange", "ariaLabel", "value", "defaultValue", "mask", "autoFocus", "onFinish", "onPaste", "onKeyDown", "disableStroke", "validate", "size", "inputProps", "fieldProps", "finishBehavior", "inputContainerProps"]); var _f = __read(useState(null), 2), focusedInputIndex = _f[0], setFocusedInputIndex = _f[1]; var _g = __read(useControlled({ value: isString(value) ? valueToArray(value) : value, defaultValue: useMemo(function () { if (isString(defaultValue)) { return valueToArray(defaultValue); } return defaultValue !== null && defaultValue !== void 0 ? defaultValue : []; }, []), name: 'InputOtp', }), 2), valueByIndex = _g[0], setValueByIndexState = _g[1]; var inputs = useStoredValue([]); var setValueByIndex = function (valueByIndex) { setValueByIndexState(valueByIndex); if (onChangeFromProps) { var maskedValueByIndex = maskValue(mask, valueByIndex); onChangeFromProps(valueToString(valueByIndex), valueByIndex, valueToString(maskedValueByIndex), maskedValueByIndex); } }; var calculateInput = function (valueByIndex, index) { return externalCalculateInput({ valueByIndex: valueByIndex, mask: mask, disabled: disabled, index: index, length: length, focusedInputIndex: focusedInputIndex, }); }; var _h = useInputOTPEvents({ inputs: inputs, valueByIndex: valueByIndex, setValueByIndex: setValueByIndex, validate: validate, onFinish: onFinish, onPaste: onPasteFromProps, onKeyDown: onKeyDownFromProps, length: length, mask: mask, finishBehavior: finishBehavior, }), onInputSelect = _h.onInputSelect, onInputChange = _h.onInputChange, onKeyDown = _h.onKeyDown, onPaste = _h.onPaste; var getFirstNonFilledInput = function () { var firstNonFilledInputIndex = inputs.current.findIndex(function (_, index) { var _a; var inputValue = (_a = valueByIndex === null || valueByIndex === void 0 ? void 0 : valueByIndex[index]) !== null && _a !== void 0 ? _a : ''; return inputValue === ''; }); return inputs.current[firstNonFilledInputIndex]; }; var focusFirstNonFilledInput = function () { var _a; (_a = getFirstNonFilledInput()) === null || _a === void 0 ? void 0 : _a.focus(); }; useEffect(function () { if (!autoFocus) { return; } focusFirstNonFilledInput(); }, []); useImperativeHandle(ref, function () { return ({ focus: function () { var _a; if (getFirstNonFilledInput()) { focusFirstNonFilledInput(); } else { (_a = inputs.current[length - 1]) === null || _a === void 0 ? void 0 : _a.focus(); } }, }); }); return (React.createElement(Stack, __assign({ as: as, className: cnInputOTP({ size: size, disabled: disabled, }, [className]), gap: INPUT_OTP_SPACING_BY_SIZE[size] }, other, { ref: ref }), createEmptyArray(length).map(function (_, index) { var _a, _b; var calculatedInput = calculateInput(valueByIndex, index); var isInputDisabled = calculatedInput.isDisabled, value = calculatedInput.value; var processedAutocomplete = (function () { if (autoCompleteMode === 'firstOnly') { return !!autoComplete && index === 0 ? autoComplete : 'off'; } return autoComplete; })(); var processedContainerProps = isFunction(inputContainerProps) ? inputContainerProps(calculatedInput, index) : inputContainerProps; var processedFieldProps = isFunction(fieldProps) ? fieldProps(calculatedInput, index) : fieldProps; var processedInputProps = isFunction(inputProps) ? inputProps(calculatedInput, index) : inputProps; var processedPlaceholder = isFunction(placeholder) ? placeholder(calculatedInput, index) : placeholder; return ( // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions React.createElement("div", __assign({ key: index }, processedContainerProps, { className: cnInputOTP('InputContainer', [ processedContainerProps === null || processedContainerProps === void 0 ? void 0 : processedContainerProps.className, ]), onClick: function () { if (isInputDisabled) { focusFirstNonFilledInput(); } } }), React.createElement(FieldControl, __assign({ size: size, disabled: disabled, error: error, disableStroke: disableStroke }, processedFieldProps, { className: cnInputOTP('Field', { notAvailable: isInputDisabled, }, [processedFieldProps === null || processedFieldProps === void 0 ? void 0 : processedFieldProps.className]) }), React.createElement(FieldInput, __assign({ inputMode: (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.inputMode) !== null && _a !== void 0 ? _a : 'numeric', type: (_b = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.type) !== null && _b !== void 0 ? _b : 'text', value: value, autoComplete: processedAutocomplete, "aria-label": ariaLabel && "".concat(ariaLabel, ": ").concat(index + 1, "."), placeholder: processedPlaceholder, disabled: isInputDisabled }, processedInputProps, { onMouseDown: function (event) { var _a; (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(processedInputProps, event); onInputSelect(index); }, onTouchStart: function (event) { var _a; (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.onTouchStart) === null || _a === void 0 ? void 0 : _a.call(processedInputProps, event); onInputSelect(index); }, onPointerDown: function (event) { var _a; (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.onPointerDown) === null || _a === void 0 ? void 0 : _a.call(processedInputProps, event); onInputSelect(index); }, onChange: function (event) { var _a; (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.onChange) === null || _a === void 0 ? void 0 : _a.call(processedInputProps, event); onInputChange(event, index); }, onKeyDown: function (event) { var _a; (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(processedInputProps, event); onKeyDown(event, index); }, onPaste: function (event) { var _a; (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.onPaste) === null || _a === void 0 ? void 0 : _a.call(processedInputProps, event); onPaste(event, index); }, onFocus: function (event) { var _a; (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(processedInputProps, event); setFocusedInputIndex(index); }, onBlur: function (event) { var _a; (_a = processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(processedInputProps, event); setFocusedInputIndex(null); }, className: cnInputOTP('Input', [ processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.className, ]), ref: function (instance) { if (instance) { inputs.current[index] = instance; } setRef(processedInputProps === null || processedInputProps === void 0 ? void 0 : processedInputProps.ref, instance); } })), React.createElement(Fieldset, null)))); }))); }); InputOTP.displayName = 'InputOTP';