reka-ui
Version:
Vue port for Radix UI Primitives.
172 lines (169 loc) • 6.36 kB
JavaScript
import { defineComponent, computed, watch, onMounted, onUnmounted, createBlock, openBlock, unref, withKeys, withCtx, renderSlot, nextTick } from 'vue';
import { i as injectPinInputRootContext } from './PinInputRoot.js';
import { u as usePrimitiveElement } from '../Primitive/usePrimitiveElement.js';
import { P as Primitive } from '../Primitive/Primitive.js';
import { u as useArrowNavigation } from '../shared/useArrowNavigation.js';
import { g as getActiveElement } from '../shared/getActiveElement.js';
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "PinInputInput",
props: {
index: {},
disabled: { type: Boolean },
asChild: { type: Boolean },
as: { default: "input" }
},
setup(__props) {
const props = __props;
const context = injectPinInputRootContext();
const inputElements = computed(() => Array.from(context.inputElements.value));
const currentValue = computed(() => context.currentModelValue.value[props.index]);
const disabled = computed(() => props.disabled || context.disabled.value);
const isOtpMode = computed(() => context.otp.value);
const isNumericMode = computed(() => context.type.value === "number");
const isPasswordMode = computed(() => context.mask.value);
const { primitiveElement, currentElement } = usePrimitiveElement();
function handleInput(event) {
const target = event.target;
if ((event.data?.length ?? 0) > 1) {
handleMultipleCharacter(target.value);
return;
}
if (isNumericMode.value && !/^\d*$/.test(target.value)) {
target.value = target.value.replace(/\D/g, "");
return;
}
target.value = target.value.slice(-1);
updateModelValueAt(props.index, target.value);
const nextEl = inputElements.value[props.index + 1];
if (nextEl)
nextEl.focus();
}
function resetPlaceholder() {
const target = currentElement.value;
nextTick(() => {
if (target && !target.value)
target.placeholder = context.placeholder.value;
});
}
function handleKeydown(event) {
useArrowNavigation(event, getActiveElement(), void 0, {
itemsArray: inputElements.value,
focus: true,
loop: false,
arrowKeyOptions: "horizontal",
dir: context.dir.value
});
}
function handleBackspace(event) {
event.preventDefault();
const target = event.target;
const value = target.value;
if (value) {
updateModelValueAt(props.index, "");
} else {
const prevEl = inputElements.value[props.index - 1];
if (prevEl) {
prevEl.focus();
updateModelValueAt(props.index - 1, "");
}
}
}
function handleDelete(event) {
if (event.key === "Delete") {
event.preventDefault();
updateModelValueAt(props.index, "");
}
}
function handleFocus(event) {
const target = event.target;
target.setSelectionRange(1, 1);
if (!target.value)
target.placeholder = "";
}
function handleBlur(event) {
resetPlaceholder();
}
function handlePaste(event) {
event.preventDefault();
const clipboardData = event.clipboardData;
if (!clipboardData)
return;
const values = clipboardData.getData("text");
handleMultipleCharacter(values);
}
function handleMultipleCharacter(values) {
const tempModelValue = [...context.currentModelValue.value];
const initialIndex = values.length >= inputElements.value.length ? 0 : props.index;
const lastIndex = Math.min(initialIndex + values.length, inputElements.value.length);
for (let i = initialIndex; i < lastIndex; i++) {
const input = inputElements.value[i];
const value = values[i - initialIndex];
if (isNumericMode.value && !/^\d*$/.test(value))
continue;
tempModelValue[i] = value;
input.focus();
}
context.modelValue.value = tempModelValue;
inputElements.value[lastIndex]?.focus();
}
function removeTrailingEmptyStrings(input) {
let i = input.length - 1;
while (i >= 0 && input[i] === "") {
input.pop();
i--;
}
return input;
}
function updateModelValueAt(index, value) {
const tempModelValue = [...context.currentModelValue.value];
tempModelValue[index] = value;
context.modelValue.value = removeTrailingEmptyStrings(tempModelValue);
}
watch(currentValue, () => {
if (!currentValue.value) {
resetPlaceholder();
}
});
onMounted(() => {
context.onInputElementChange(currentElement.value);
});
onUnmounted(() => {
context.inputElements?.value.delete(currentElement.value);
});
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(Primitive), {
ref_key: "primitiveElement",
ref: primitiveElement,
autocapitalize: "none",
as: _ctx.as,
"as-child": _ctx.asChild,
autocomplete: isOtpMode.value ? "one-time-code" : "false",
type: isPasswordMode.value ? "password" : "text",
inputmode: isNumericMode.value ? "numeric" : "text",
pattern: isNumericMode.value ? "[0-9]*" : void 0,
placeholder: unref(context).placeholder.value,
value: currentValue.value,
disabled: disabled.value,
"data-disabled": disabled.value ? "" : void 0,
"data-complete": unref(context).isCompleted.value ? "" : void 0,
"aria-label": `pin input ${_ctx.index + 1} of ${inputElements.value.length}`,
onInput: _cache[0] || (_cache[0] = ($event) => handleInput($event)),
onKeydown: [
withKeys(handleKeydown, ["left", "right", "up", "down", "home", "end"]),
withKeys(handleBackspace, ["backspace"]),
withKeys(handleDelete, ["delete"])
],
onFocus: handleFocus,
onBlur: handleBlur,
onPaste: handlePaste
}, {
default: withCtx(() => [
renderSlot(_ctx.$slots, "default")
]),
_: 3
}, 8, ["as", "as-child", "autocomplete", "type", "inputmode", "pattern", "placeholder", "value", "disabled", "data-disabled", "data-complete", "aria-label"]);
};
}
});
export { _sfc_main as _ };
//# sourceMappingURL=PinInputInput.js.map