ngx-otp-pin
Version:
A reusable, standalone Angular OTP input component supporting multiple character types, automatic focus movement, and style customization from the parent.
105 lines (100 loc) • 6.73 kB
JavaScript
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, ViewChildren, Output, Input, Component } from '@angular/core';
import * as i2 from '@angular/forms';
import { FormsModule } from '@angular/forms';
var OTP_TYPE;
(function (OTP_TYPE) {
OTP_TYPE["DIGITS"] = "DIGITS";
OTP_TYPE["CAPITAL_LETTERS"] = "CAPITAL_LETTERS";
OTP_TYPE["LETTERS"] = "LETTERS";
OTP_TYPE["SMALL_LETTERS"] = "SMALL_LETTERS";
OTP_TYPE["ALPHA_NUMERIC"] = "ALPHA_NUMERIC";
})(OTP_TYPE || (OTP_TYPE = {}));
class NgxOtp {
size = 4;
type = OTP_TYPE.DIGITS;
isPassword = false;
containerStyles = {};
inputStyles = {};
containerClass = '';
inputClass = '';
opt = [];
optValue = new EventEmitter();
constructor() { }
ngOnInit() {
this.opt = new Array(this.size);
console.log(this.opt);
}
inputRefs;
move(currentIndex, $event) {
const key = $event.key;
if (key === 'Backspace' || key === 'Delete') {
this.opt[currentIndex] = '';
const prevInput = this.inputRefs.get(currentIndex - 1);
if (this.opt[currentIndex] === '' && prevInput) {
prevInput.nativeElement.focus();
}
}
else if (this.isValidKey(key)) {
this.opt[currentIndex] = key;
const nextInput = this.inputRefs.get(currentIndex + 1);
if (nextInput) {
nextInput.nativeElement.focus();
}
}
this.optValue.emit(this.opt.join(''));
$event.preventDefault();
}
isValidKey(key) {
switch (this.type) {
case OTP_TYPE.DIGITS:
return /^[0-9]$/.test(key);
case OTP_TYPE.CAPITAL_LETTERS:
return /^[A-Z]$/.test(key);
case OTP_TYPE.SMALL_LETTERS:
return /^[a-z]$/.test(key);
case OTP_TYPE.LETTERS:
return /^[a-zA-Z]$/.test(key);
case OTP_TYPE.ALPHA_NUMERIC:
return /^[a-zA-Z0-9]$/.test(key);
default:
return false;
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxOtp, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: NgxOtp, isStandalone: true, selector: "ngx-otp", inputs: { size: "size", type: "type", isPassword: "isPassword", containerStyles: "containerStyles", inputStyles: "inputStyles", containerClass: "containerClass", inputClass: "inputClass" }, outputs: { optValue: "opt" }, viewQueries: [{ propertyName: "inputRefs", predicate: ["otpInput"], descendants: true }], ngImport: i0, template: "<div>\r\n <div aria-label=\"otp container\" [ngClass]=\"containerClass\" [ngStyle]=\"containerStyles\" class=\"otp-container\">\r\n @for(digit of opt; track $index) {\r\n <div class=\"digital\">\r\n <input #otpInput [attr.aria-label]=\"'opt number ' + $index\" [ngClass]=\"inputClass\" [ngStyle]=\"inputStyles\"\r\n [ngModel]=\"digit\" [id]=\"'input_'+$index\" [type]=\"isPassword? 'password':'text'\"\r\n (keydown)=\"move($index, $event)\" maxlength=\"1\" />\r\n </div>\r\n }\r\n </div>\r\n\r\n</div>", styles: [".otp-container{display:flex;gap:20px;justify-content:center}.otp-container .digital{width:40px;height:40px}.otp-container .digital input{border:0;border:1px solid rgb(177,177,177);border-radius:10px;width:100%;height:100%;text-align:center;font-size:20px}.timer{margin-top:20px;font-size:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxOtp, decorators: [{
type: Component,
args: [{ selector: 'ngx-otp', standalone: true, imports: [CommonModule, FormsModule], template: "<div>\r\n <div aria-label=\"otp container\" [ngClass]=\"containerClass\" [ngStyle]=\"containerStyles\" class=\"otp-container\">\r\n @for(digit of opt; track $index) {\r\n <div class=\"digital\">\r\n <input #otpInput [attr.aria-label]=\"'opt number ' + $index\" [ngClass]=\"inputClass\" [ngStyle]=\"inputStyles\"\r\n [ngModel]=\"digit\" [id]=\"'input_'+$index\" [type]=\"isPassword? 'password':'text'\"\r\n (keydown)=\"move($index, $event)\" maxlength=\"1\" />\r\n </div>\r\n }\r\n </div>\r\n\r\n</div>", styles: [".otp-container{display:flex;gap:20px;justify-content:center}.otp-container .digital{width:40px;height:40px}.otp-container .digital input{border:0;border:1px solid rgb(177,177,177);border-radius:10px;width:100%;height:100%;text-align:center;font-size:20px}.timer{margin-top:20px;font-size:12px}\n"] }]
}], ctorParameters: () => [], propDecorators: { size: [{
type: Input
}], type: [{
type: Input
}], isPassword: [{
type: Input
}], containerStyles: [{
type: Input
}], inputStyles: [{
type: Input
}], containerClass: [{
type: Input
}], inputClass: [{
type: Input
}], optValue: [{
type: Output,
args: ['opt']
}], inputRefs: [{
type: ViewChildren,
args: ['otpInput']
}] } });
/*
* Public API Surface of ngx-otp
*/
/**
* Generated bundle index. Do not edit.
*/
export { NgxOtp, OTP_TYPE };
//# sourceMappingURL=ngx-otp-pin.mjs.map