@ozen-ui/kit
Version:
React component library
178 lines (177 loc) • 11.7 kB
JavaScript
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';