naive-ui
Version:
A Vue 3 Component Library. Fairly Complete, Theme Customizable, Uses TypeScript, Fast
243 lines (242 loc) • 11.8 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.inputOtpProps = void 0;
const seemly_1 = require("seemly");
const vooks_1 = require("vooks");
const vue_1 = require("vue");
const _mixins_1 = require("../../_mixins");
const _utils_1 = require("../../_utils");
const input_1 = require("../../input");
const light_1 = __importDefault(require("../styles/light"));
const index_cssr_1 = __importDefault(require("./styles/index.cssr"));
exports.inputOtpProps = Object.assign(Object.assign({}, _mixins_1.useTheme.props), { defaultValue: { type: Array, default: [] }, value: Array, length: {
type: Number,
default: 6
}, size: String, disabled: Boolean, mask: Boolean, readonly: Boolean, status: String, gap: [String, Number], placeholder: { type: String, default: '' }, allowInput: Function, onBlur: [Function, Array], onFocus: [Function, Array], 'onUpdate:value': [Function, Array], onUpdateValue: [Function, Array], onFinish: [Function, Array] });
exports.default = (0, vue_1.defineComponent)({
name: 'InputOtp',
props: exports.inputOtpProps,
slots: Object,
setup(props) {
const { mergedClsPrefixRef, mergedRtlRef, inlineThemeDisabled } = (0, _mixins_1.useConfig)(props);
const themeRef = (0, _mixins_1.useTheme)('InputOtp', '-input-otp', index_cssr_1.default, light_1.default, props, mergedClsPrefixRef);
const rtlEnabledRef = (0, _mixins_1.useRtl)('InputOtp', mergedRtlRef, mergedClsPrefixRef);
// form-item
const formItem = (0, _mixins_1.useFormItem)(props);
const { mergedSizeRef, mergedDisabledRef, mergedStatusRef } = formItem;
const cssVarsRef = (0, vue_1.computed)(() => {
const { value: size } = mergedSizeRef;
const { gap: propGap } = props;
const { self: { [(0, _utils_1.createKey)('inputWidth', size)]: inputWidth, [(0, _utils_1.createKey)('gap', size)]: gap } } = themeRef.value;
return {
'--n-gap': propGap === undefined
? gap
: typeof propGap === 'number'
? (0, seemly_1.pxfy)(propGap)
: propGap,
'--n-input-width': inputWidth
};
});
const themeClassHandle = inlineThemeDisabled
? (0, _mixins_1.useThemeClass)('input-otp', (0, vue_1.computed)(() => {
const { value: size } = mergedSizeRef;
return size[0];
}), cssVarsRef, props)
: undefined;
const uncontrolledValueRef = (0, vue_1.ref)(props.defaultValue);
const controlledValueRef = (0, vue_1.toRef)(props, 'value');
const mergedValueRef = (0, vooks_1.useMergedState)(controlledValueRef, uncontrolledValueRef);
const inputRefList = (0, vue_1.ref)([]);
const inputTypeRef = (0, vue_1.computed)(() => props.mask ? 'password' : 'text');
const handleFocus = (e, index) => {
// If it's focused from other input element inside the component, returns
if (inputRefList === null || inputRefList === void 0 ? void 0 : inputRefList.value.some(inputInst => inputInst.inputElRef === e.relatedTarget)) {
return;
}
const { onFocus } = props;
if (onFocus) {
(0, _utils_1.call)(onFocus, e, index);
}
const { nTriggerFormFocus } = formItem;
nTriggerFormFocus();
};
const handleBlur = (e, index) => {
// If it's blured to other input element inside the component, returns
if (inputRefList === null || inputRefList === void 0 ? void 0 : inputRefList.value.some(inputInst => inputInst.inputElRef === e.relatedTarget)) {
return;
}
const { onBlur } = props;
const { nTriggerFormBlur } = formItem;
if (onBlur)
(0, _utils_1.call)(onBlur, e, index);
nTriggerFormBlur();
};
const focusOnChar = (charIndex) => {
if (charIndex >= props.length)
return;
if (charIndex < 0)
return;
inputRefList === null || inputRefList === void 0 ? void 0 : inputRefList.value[charIndex].focus();
inputRefList === null || inputRefList === void 0 ? void 0 : inputRefList.value[charIndex].select();
};
const focusOnNextChar = (currentIndex) => {
if (currentIndex >= props.length - 1) {
return;
}
focusOnChar(currentIndex + 1);
};
const focusOnPrevChar = (currentIndex) => {
if (currentIndex <= 0) {
return;
}
focusOnChar(currentIndex - 1);
};
const justifyValue = (value) => {
const justifiedValue = value ? Array.from(value) : [];
const length = props.length;
while (justifiedValue.length > length) {
justifiedValue.pop();
}
while (justifiedValue.length < length) {
justifiedValue.push('');
}
return justifiedValue;
};
function doUpdateValue(value, meta) {
const { nTriggerFormInput, nTriggerFormChange } = formItem;
if ((0, _utils_1.isArrayShallowEqual)(value, mergedValueRef.value)) {
nTriggerFormInput();
return;
}
const { 'onUpdate:value': _onUpdateValue, onUpdateValue, length, onFinish } = props;
if (_onUpdateValue)
(0, _utils_1.call)(_onUpdateValue, value, meta);
if (onUpdateValue)
(0, _utils_1.call)(onUpdateValue, value, meta);
if (value.filter(v => v).length === length && onFinish) {
(0, _utils_1.call)(onFinish, value);
}
uncontrolledValueRef.value = value;
nTriggerFormInput();
nTriggerFormChange();
}
const handlePaste = (e, index) => {
e.preventDefault();
const { clipboardData } = e;
const text = clipboardData === null || clipboardData === void 0 ? void 0 : clipboardData.getData('text');
if (!text)
return;
const currentValue = justifyValue(mergedValueRef.value);
let startIndex = index;
const allowInput = props.allowInput;
let pasteApplied = false;
let appendedText = '';
for (let i = 0; i < text.length; ++i) {
if (allowInput && !allowInput(text[i], startIndex, currentValue)) {
continue;
}
pasteApplied = true;
currentValue[startIndex] = text[i];
appendedText += text[i];
startIndex++;
if (startIndex >= currentValue.length) {
break;
}
}
if (pasteApplied) {
focusOnChar(startIndex);
doUpdateValue(currentValue, {
diff: appendedText,
index: startIndex,
source: 'paste'
});
}
};
const handleKeydown = (e, index) => {
const keyCode = e.code || e.key;
const currentValue = justifyValue(mergedValueRef.value);
if (keyCode === 'Backspace') {
e.preventDefault();
currentValue[Math.max(index, 0)] = '';
doUpdateValue(currentValue, { diff: '', index, source: 'delete' });
focusOnPrevChar(index);
}
else if (keyCode === 'ArrowLeft') {
e.preventDefault();
focusOnPrevChar(index);
}
else if (keyCode === 'ArrowRight') {
e.preventDefault();
focusOnNextChar(index);
}
};
const handleInput = (value, index) => {
const currentValue = justifyValue(mergedValueRef.value);
const currentValueAtIndex = currentValue[index];
const diff = value.replace(currentValueAtIndex, '');
const char = diff[diff.length - 1] || value[value.length - 1] || '';
const allowInput = props.allowInput;
if (allowInput && !allowInput(char, index, currentValue)) {
return;
}
currentValue[index] = char;
doUpdateValue(currentValue, { diff: char, index, source: 'input' });
focusOnNextChar(index);
};
const getTemplateEvents = (index) => {
return {
onInput: (value) => handleInput(value, index),
onPaste: (event) => handlePaste(event, index),
onKeydown: (event) => handleKeydown(event, index),
onFocus: (event) => handleFocus(event, index),
onBlur: (event) => handleBlur(event, index)
};
};
return {
mergedTheme: themeRef,
perItemValueArray: (0, vue_1.computed)(() => justifyValue(mergedValueRef.value)),
mergedClsPrefix: mergedClsPrefixRef,
inputRefList,
inputType: inputTypeRef,
rtlEnabled: rtlEnabledRef,
mergedStatus: mergedStatusRef,
mergedDisabled: mergedDisabledRef,
cssVars: inlineThemeDisabled ? undefined : cssVarsRef,
themeClass: themeClassHandle === null || themeClassHandle === void 0 ? void 0 : themeClassHandle.themeClass,
getTemplateEvents,
onRender: themeClassHandle === null || themeClassHandle === void 0 ? void 0 : themeClassHandle.onRender
};
},
render() {
const { mergedTheme, mergedClsPrefix, perItemValueArray, size, placeholder, mergedDisabled, mergedStatus, readonly, inputType, $slots, getTemplateEvents, themeClass, onRender } = this;
onRender === null || onRender === void 0 ? void 0 : onRender();
return ((0, vue_1.h)("div", { style: this.cssVars, class: [
`${mergedClsPrefix}-input-otp`,
themeClass,
this.rtlEnabled && `${mergedClsPrefix}-input-otp--rtl`
] }, (0, seemly_1.repeat)(this.length, undefined).map((_, index) => (0, _utils_1.resolveSlotWithTypedProps)($slots.default, Object.assign({ index, value: perItemValueArray[index], type: inputType, size,
placeholder, disabled: mergedDisabled, readonly, status: mergedStatus, builtinThemeOverrides: {
paddingTiny: '0',
paddingSmall: '0',
paddingMedium: '0',
paddingLarge: '0'
}, theme: mergedTheme.peers.Input, themeOverrides: mergedTheme.peerOverrides.Input, ref: (el) => (this.inputRefList[index] = el) }, getTemplateEvents(index)), (_a) => {
var { index } = _a, restProps = __rest(_a, ["index"]);
return [(0, vue_1.h)(input_1.NInput, Object.assign({}, restProps, { key: index }))];
}))));
}
});
;