@ruc-lib/input-otp 2.0.2 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -27
- package/fesm2022/ruc-lib-input-otp.mjs +153 -0
- package/fesm2022/ruc-lib-input-otp.mjs.map +1 -0
- package/index.d.ts +47 -3
- package/package.json +6 -18
- package/esm2020/index.mjs +0 -4
- package/esm2020/lib/input-otp/input-otp.component.mjs +0 -142
- package/esm2020/lib/ruclib-input-otp.module.mjs +0 -20
- package/esm2020/modal/constants.mjs +0 -2
- package/esm2020/modal/input-otp-config.mjs +0 -2
- package/esm2020/ruc-lib-input-otp.mjs +0 -5
- package/fesm2015/ruc-lib-input-otp.mjs +0 -168
- package/fesm2015/ruc-lib-input-otp.mjs.map +0 -1
- package/fesm2020/ruc-lib-input-otp.mjs +0 -167
- package/fesm2020/ruc-lib-input-otp.mjs.map +0 -1
- package/lib/input-otp/input-otp.component.d.ts +0 -25
- package/lib/ruclib-input-otp.module.d.ts +0 -10
- package/modal/constants.d.ts +0 -1
- package/modal/input-otp-config.d.ts +0 -18
package/README.md
CHANGED
|
@@ -35,37 +35,45 @@ for seperate package
|
|
|
35
35
|
`@import "../node_modules/primeng/resources/themes/lara-light-indigo/theme.css";`
|
|
36
36
|
`@import "../node_modules/primeng/resources/primeng.min.css";`
|
|
37
37
|
|
|
38
|
-
## Usage
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
In your Angular module file (e.g., `app.module.ts`), import the `RuclibInputOtpModule`:
|
|
39
|
+
# Version Compatibility
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
41
|
+
Please ensure you install the correct version of `@ruc-lib/input-otp` based on your Angular version.
|
|
42
|
+
|
|
43
|
+
| Angular Version | Compatible `@ruc-lib/input-otp` Version |
|
|
44
|
+
|--------------------|---------------------------------------------|
|
|
45
|
+
| 15.x.x | `npm install @ruc-lib/input-otp@^3.0.0` |
|
|
46
|
+
| 16.x.x | `npm install @ruc-lib/input-otp@^3.0.0` |
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
### 1. Import the Component
|
|
52
|
+
In your Angular component file (e.g., `app.component.ts`), import the `RuclibInputOtpComponent`:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { Component } from '@angular/core';
|
|
56
|
+
|
|
57
|
+
// For Complete Library
|
|
58
|
+
import { RuclibInputOtpComponent } from '@uxpractice/ruc-lib/input-otp';
|
|
59
|
+
|
|
60
|
+
// For Individual Package
|
|
61
|
+
import { RuclibInputOtpComponent } from '@ruc-lib/input-otp';
|
|
62
|
+
|
|
63
|
+
@Component({
|
|
64
|
+
selector: 'app-root',
|
|
65
|
+
imports: [RuclibInputOtpComponent],
|
|
66
|
+
templateUrl: './app.component.html',
|
|
67
|
+
})
|
|
68
|
+
export class AppComponent {
|
|
69
|
+
// Component code here
|
|
70
|
+
}
|
|
63
71
|
```
|
|
64
72
|
### 2. Use the Component
|
|
65
|
-
In your component's template, use the `<uxp-input-otp>` selector and pass the configuration object to the `rucInputData` input.
|
|
73
|
+
In your component's template, use the `<uxp-ruclib-input-otp>` selector and pass the configuration object to the `rucInputData` input.
|
|
66
74
|
|
|
67
75
|
```html
|
|
68
|
-
<uxp-input-otp [customTheme]="customTheme" [rucInputData]="inputObjectDataInputOtp"></uxp-input-otp>
|
|
76
|
+
<uxp-ruclib-input-otp [customTheme]="customTheme" [rucInputData]="inputObjectDataInputOtp"></uxp-ruclib-input-otp>
|
|
69
77
|
```
|
|
70
78
|
|
|
71
79
|
## API Reference
|
|
@@ -143,9 +151,25 @@ User can validate input otp validation if the OTP is correct or not
|
|
|
143
151
|
User can have Copy and Paste Protection
|
|
144
152
|
|
|
145
153
|
|
|
154
|
+
> ⚠️ **IMPORTANT: Custom Theme Usage in Angular Material**
|
|
155
|
+
|
|
156
|
+
When implementing **custom themes**, such as:
|
|
157
|
+
|
|
158
|
+
```scss
|
|
159
|
+
.custom-theme-1 {
|
|
160
|
+
@include angular-material-theme($custom-theme);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// You must also include the typography mixin to ensure text styles are applied correctly as shown below:
|
|
164
|
+
.custom-theme-1 {
|
|
165
|
+
@include angular-material-theme($custom-theme);
|
|
166
|
+
@include mat.typography-level($theme-custom-typography-name, body-1);
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
|
|
146
171
|
# Contribution
|
|
147
172
|
Contributions are welcome! Feel free to open issues or pull requests for any enhancements or fixes.
|
|
148
173
|
|
|
149
174
|
# Acknowledgements
|
|
150
|
-
Thank you for choosing the Input OTP Component Library. If you have any feedback or suggestions, please let us know!
|
|
151
|
-
|
|
175
|
+
Thank you for choosing the Input OTP Component Library. If you have any feedback or suggestions, please let us know!
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter, ViewChildren, Input, Output, Component } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
6
|
+
import * as i2 from '@angular/forms';
|
|
7
|
+
import { FormsModule } from '@angular/forms';
|
|
8
|
+
|
|
9
|
+
const BACKSPACE_KEY = "Backspace";
|
|
10
|
+
|
|
11
|
+
class RuclibInputOtpComponent {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.DEFAULT_OTP_LENGTH = 6;
|
|
14
|
+
this.TIME_LEFT = "Time left";
|
|
15
|
+
this.EXPIRED_MSG = "OTP expired. Please request a new one.";
|
|
16
|
+
this.rucEvent = new EventEmitter();
|
|
17
|
+
this.rucInputData = {};
|
|
18
|
+
this.timeLeft = 0;
|
|
19
|
+
this.timerId = null;
|
|
20
|
+
this.otpValues = [];
|
|
21
|
+
}
|
|
22
|
+
ngOnInit() {
|
|
23
|
+
this.otpValues = Array(this.rucInputData.length || 6).fill('');
|
|
24
|
+
if (this.rucInputData.timeLimit) {
|
|
25
|
+
this.timeLeft = this.rucInputData.timeLimit;
|
|
26
|
+
}
|
|
27
|
+
// Set default for copyProtection
|
|
28
|
+
if (this.rucInputData.copyProtection === undefined) {
|
|
29
|
+
this.rucInputData.copyProtection = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
ngAfterViewInit() {
|
|
33
|
+
// Merge input config with defaults
|
|
34
|
+
this.otpValues = Array(this.rucInputData.length || 6).fill('');
|
|
35
|
+
if (this.rucInputData.autoFocus) {
|
|
36
|
+
setTimeout(() => this.inputs.first?.nativeElement.focus(), 0); // Auto-focus first input
|
|
37
|
+
}
|
|
38
|
+
if (this.rucInputData.timeLimit) {
|
|
39
|
+
this.timeLeft = this.rucInputData.timeLimit;
|
|
40
|
+
this.timerId = setInterval(() => {
|
|
41
|
+
this.timeLeft--;
|
|
42
|
+
if (this.timeLeft <= 0) {
|
|
43
|
+
clearInterval(this.timerId);
|
|
44
|
+
this.disableAllInputs();
|
|
45
|
+
this.rucEvent.emit({ eventName: 'timeout', eventOutput: null });
|
|
46
|
+
}
|
|
47
|
+
}, 1000);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Handle OTP input
|
|
51
|
+
handleInput(event, index) {
|
|
52
|
+
const input = event.target;
|
|
53
|
+
const value = input.value;
|
|
54
|
+
if (this.rucInputData.integerOnly && !/^\d*$/.test(value)) {
|
|
55
|
+
input.value = ''; // Allow integers only
|
|
56
|
+
this.otpValues[index] = '';
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.otpValues[index] = value.slice(-1); // Take last digit
|
|
60
|
+
input.value = this.otpValues[index];
|
|
61
|
+
// Auto-jump to next input
|
|
62
|
+
if (value && index < (this.rucInputData.length || 6) - 1 && this.rucInputData.autoFocus) {
|
|
63
|
+
this.inputs.toArray()[index + 1].nativeElement.focus();
|
|
64
|
+
}
|
|
65
|
+
// Auto-submit on complete
|
|
66
|
+
if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {
|
|
67
|
+
if (this.timerId) {
|
|
68
|
+
clearInterval(this.timerId);
|
|
69
|
+
this.timerId = null;
|
|
70
|
+
}
|
|
71
|
+
this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Handle Keyboard navigation
|
|
75
|
+
handleKeyDown(event, index) {
|
|
76
|
+
const input = event.target;
|
|
77
|
+
if (event.key === BACKSPACE_KEY && !input.value && index > 0 && this.rucInputData.autoFocus) {
|
|
78
|
+
this.inputs.toArray()[index - 1].nativeElement.focus();
|
|
79
|
+
}
|
|
80
|
+
else if (event.key === 'ArrowLeft' && index > 0) {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
this.inputs.toArray()[index - 1].nativeElement.focus();
|
|
83
|
+
}
|
|
84
|
+
else if (event.key === 'ArrowRight' && index < (this.rucInputData.length || 6) - 1) {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
this.inputs.toArray()[index + 1].nativeElement.focus();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//Handle Paste Event
|
|
90
|
+
handlePaste(event) {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
let pasteData = event.clipboardData?.getData('text');
|
|
93
|
+
if (this.rucInputData.integerOnly) {
|
|
94
|
+
pasteData = pasteData?.replace(/\D/g, ''); // Extract digits only
|
|
95
|
+
}
|
|
96
|
+
if (!pasteData)
|
|
97
|
+
return;
|
|
98
|
+
const pasteLength = Math.min(pasteData.length, this.rucInputData.length || 6);
|
|
99
|
+
for (let i = 0; i < pasteLength; i++) {
|
|
100
|
+
this.otpValues[i] = pasteData[i];
|
|
101
|
+
this.inputs.toArray()[i].nativeElement.value = pasteData[i];
|
|
102
|
+
}
|
|
103
|
+
// Focus last filled input or last input
|
|
104
|
+
const focusIndex = pasteLength < (this.rucInputData.length || 6) ? pasteLength : (this.rucInputData.length || 6) - 1;
|
|
105
|
+
this.inputs.toArray()[focusIndex].nativeElement.focus();
|
|
106
|
+
// Auto-submit if complete
|
|
107
|
+
if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {
|
|
108
|
+
if (this.timerId) {
|
|
109
|
+
clearInterval(this.timerId);
|
|
110
|
+
this.timerId = null;
|
|
111
|
+
}
|
|
112
|
+
this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//Check if OTP is completed
|
|
116
|
+
isOtpComplete(otpArray) {
|
|
117
|
+
return otpArray.every(val => val.trim() !== '');
|
|
118
|
+
}
|
|
119
|
+
// Disable inputs
|
|
120
|
+
disableAllInputs() {
|
|
121
|
+
this.inputs.forEach((inputRef) => {
|
|
122
|
+
inputRef.nativeElement.disabled = true;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
//Clear Interval
|
|
126
|
+
ngOnDestroy() {
|
|
127
|
+
if (this.timerId) {
|
|
128
|
+
clearInterval(this.timerId);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RuclibInputOtpComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
132
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: RuclibInputOtpComponent, isStandalone: true, selector: "uxp-ruclib-input-otp", inputs: { customTheme: "customTheme", rucInputData: "rucInputData" }, outputs: { rucEvent: "rucEvent" }, viewQueries: [{ propertyName: "inputs", predicate: ["otpInput"], descendants: true }], ngImport: i0, template: "<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n @for (_ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); track _; let i = $index) {\r\n <input\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n }\r\n</div>\r\n<!-- Timer -->\r\n@if (rucInputData.timeLimit) {\r\n <div class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n </div>\r\n}\r\n<!-- Timeout message -->\r\n@if (rucInputData.timeLimit && timeLeft === 0) {\r\n <div class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n </div>\r\n}\r\n\r\n", styles: [".otp-container{display:flex;gap:10px;justify-content:center}.otp-input{text-align:center;font-size:18px;border:1px solid #ccc;border-radius:4px;outline:none;transition:border-color .2s}.otp-input:focus{border-color:#007bff;box-shadow:0 0 5px #007bff4d}.otp-input::-webkit-outer-spin-button,.otp-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.otp-input[type=number]{-moz-appearance:textfield}.small .otp-input{width:30px;height:30px;font-size:14px}.medium .otp-input{width:40px;height:40px;font-size:18px}.large .otp-input{width:50px;height:50px;font-size:22px}.otp-timer{text-align:center;font-size:.9rem;color:#d9534f;font-weight:700}.otp-timeout-message{text-align:center;color:#d9534f;font-size:.9rem;margin-top:.5rem}.otp-input.rectangle{border-radius:8px}.otp-input.circle{border-radius:50%}.otp-input.underscore{border:none;border-bottom:2px solid #ccc;border-radius:0;background-color:transparent}.otp-input.is-valid{border-color:#28a745;background-color:#e6ffed}.otp-input.is-invalid{border-color:#dc3545;background-color:#ffe6e6}.dark-theme .otp-input:not(.is-invalid){color:#fff;background-color:#333}.light-theme .otp-input:not(.is-invalid){color:#000}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatIconModule }, { 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.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
|
|
133
|
+
}
|
|
134
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RuclibInputOtpComponent, decorators: [{
|
|
135
|
+
type: Component,
|
|
136
|
+
args: [{ selector: 'uxp-ruclib-input-otp', imports: [CommonModule, MatIconModule, FormsModule], template: "<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n @for (_ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); track _; let i = $index) {\r\n <input\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n }\r\n</div>\r\n<!-- Timer -->\r\n@if (rucInputData.timeLimit) {\r\n <div class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n </div>\r\n}\r\n<!-- Timeout message -->\r\n@if (rucInputData.timeLimit && timeLeft === 0) {\r\n <div class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n </div>\r\n}\r\n\r\n", styles: [".otp-container{display:flex;gap:10px;justify-content:center}.otp-input{text-align:center;font-size:18px;border:1px solid #ccc;border-radius:4px;outline:none;transition:border-color .2s}.otp-input:focus{border-color:#007bff;box-shadow:0 0 5px #007bff4d}.otp-input::-webkit-outer-spin-button,.otp-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.otp-input[type=number]{-moz-appearance:textfield}.small .otp-input{width:30px;height:30px;font-size:14px}.medium .otp-input{width:40px;height:40px;font-size:18px}.large .otp-input{width:50px;height:50px;font-size:22px}.otp-timer{text-align:center;font-size:.9rem;color:#d9534f;font-weight:700}.otp-timeout-message{text-align:center;color:#d9534f;font-size:.9rem;margin-top:.5rem}.otp-input.rectangle{border-radius:8px}.otp-input.circle{border-radius:50%}.otp-input.underscore{border:none;border-bottom:2px solid #ccc;border-radius:0;background-color:transparent}.otp-input.is-valid{border-color:#28a745;background-color:#e6ffed}.otp-input.is-invalid{border-color:#dc3545;background-color:#ffe6e6}.dark-theme .otp-input:not(.is-invalid){color:#fff;background-color:#333}.light-theme .otp-input:not(.is-invalid){color:#000}\n"] }]
|
|
137
|
+
}], propDecorators: { rucEvent: [{
|
|
138
|
+
type: Output
|
|
139
|
+
}], customTheme: [{
|
|
140
|
+
type: Input
|
|
141
|
+
}], rucInputData: [{
|
|
142
|
+
type: Input
|
|
143
|
+
}], inputs: [{
|
|
144
|
+
type: ViewChildren,
|
|
145
|
+
args: ['otpInput']
|
|
146
|
+
}] } });
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Generated bundle index. Do not edit.
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
export { RuclibInputOtpComponent };
|
|
153
|
+
//# sourceMappingURL=ruc-lib-input-otp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ruc-lib-input-otp.mjs","sources":["../../src/modal/constants.ts","../../src/lib/ruclib-input-otp/ruclib-input-otp.component.ts","../../src/lib/ruclib-input-otp/ruclib-input-otp.component.html","../../src/ruc-lib-input-otp.ts"],"sourcesContent":["export const BACKSPACE_KEY = \"Backspace\"","import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, QueryList, ViewChildren } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { InputOtpConfig } from '../../modal/input-otp-config';\r\nimport { BACKSPACE_KEY } from '../../modal/constants';\r\n\r\n@Component({\r\n selector: 'uxp-ruclib-input-otp',\r\n imports: [CommonModule, MatIconModule, FormsModule],\r\n templateUrl: './ruclib-input-otp.component.html',\r\n styleUrl: './ruclib-input-otp.component.scss'\r\n})\r\nexport class RuclibInputOtpComponent implements OnInit, AfterViewInit, OnDestroy {\r\n readonly DEFAULT_OTP_LENGTH = 6;\r\n readonly TIME_LEFT = \"Time left\";\r\n readonly EXPIRED_MSG = \"OTP expired. Please request a new one.\"\r\n\r\n @Output() rucEvent = new EventEmitter<any>();\r\n @Input() customTheme?: string;\r\n\r\n @Input() rucInputData: InputOtpConfig = {};\r\n timeLeft = 0;\r\n timerId: any = null;\r\n\r\n @ViewChildren('otpInput') inputs!: QueryList<ElementRef<HTMLInputElement>>;\r\n\r\n otpValues: string[] = [];\r\n\r\n ngOnInit(): void {\r\n this.otpValues = Array(this.rucInputData.length || 6).fill('');\r\n if (this.rucInputData.timeLimit) {\r\n this.timeLeft = this.rucInputData.timeLimit;\r\n }\r\n\r\n // Set default for copyProtection\r\n if (this.rucInputData.copyProtection === undefined) {\r\n this.rucInputData.copyProtection = true;\r\n }\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n // Merge input config with defaults\r\n this.otpValues = Array(this.rucInputData.length || 6).fill('');\r\n if (this.rucInputData.autoFocus) {\r\n setTimeout(() => this.inputs.first?.nativeElement.focus(), 0); // Auto-focus first input\r\n }\r\n\r\n if (this.rucInputData.timeLimit) {\r\n this.timeLeft = this.rucInputData.timeLimit;\r\n this.timerId = setInterval(() => {\r\n this.timeLeft--;\r\n if (this.timeLeft <= 0) {\r\n clearInterval(this.timerId);\r\n this.disableAllInputs();\r\n this.rucEvent.emit({ eventName: 'timeout', eventOutput: null });\r\n }\r\n }, 1000);\r\n }\r\n }\r\n// Handle OTP input\r\n handleInput(event: Event, index: number): void {\r\n const input = event.target as HTMLInputElement;\r\n const value = input.value;\r\n\r\n if (this.rucInputData.integerOnly && !/^\\d*$/.test(value)) {\r\n input.value = ''; // Allow integers only\r\n this.otpValues[index] = '';\r\n return;\r\n }\r\n\r\n this.otpValues[index] = value.slice(-1); // Take last digit\r\n input.value = this.otpValues[index];\r\n\r\n // Auto-jump to next input\r\n if (value && index < (this.rucInputData.length || 6) - 1 && this.rucInputData.autoFocus) {\r\n this.inputs.toArray()[index + 1].nativeElement.focus();\r\n }\r\n\r\n // Auto-submit on complete\r\n if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n this.timerId = null;\r\n }\r\n this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });\r\n }\r\n }\r\n\r\n// Handle Keyboard navigation\r\n handleKeyDown(event: KeyboardEvent, index: number): void {\r\n const input = event.target as HTMLInputElement;\r\n\r\n if (event.key === BACKSPACE_KEY && !input.value && index > 0 && this.rucInputData.autoFocus) {\r\n this.inputs.toArray()[index - 1].nativeElement.focus();\r\n } else if (event.key === 'ArrowLeft' && index > 0) {\r\n event.preventDefault();\r\n this.inputs.toArray()[index - 1].nativeElement.focus();\r\n } else if (event.key === 'ArrowRight' && index < (this.rucInputData.length || 6) - 1) {\r\n event.preventDefault();\r\n this.inputs.toArray()[index + 1].nativeElement.focus();\r\n }\r\n }\r\n\r\n//Handle Paste Event\r\n handlePaste(event: ClipboardEvent): void {\r\n event.preventDefault();\r\n let pasteData = event.clipboardData?.getData('text');\r\n if (this.rucInputData.integerOnly) {\r\n pasteData = pasteData?.replace(/\\D/g, ''); // Extract digits only\r\n }\r\n if (!pasteData) return;\r\n\r\n const pasteLength = Math.min(pasteData.length, this.rucInputData.length || 6);\r\n for (let i = 0; i < pasteLength; i++) {\r\n this.otpValues[i] = pasteData[i];\r\n this.inputs.toArray()[i].nativeElement.value = pasteData[i];\r\n }\r\n\r\n // Focus last filled input or last input\r\n const focusIndex = pasteLength < (this.rucInputData.length || 6) ? pasteLength : (this.rucInputData.length || 6) - 1;\r\n this.inputs.toArray()[focusIndex].nativeElement.focus();\r\n\r\n // Auto-submit if complete\r\n if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n this.timerId = null;\r\n }\r\n this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });\r\n }\r\n }\r\n\r\n //Check if OTP is completed\r\n private isOtpComplete(otpArray: string[]): boolean {\r\n return otpArray.every(val => val.trim() !== '');\r\n }\r\n\r\n// Disable inputs\r\n private disableAllInputs(): void {\r\n this.inputs.forEach((inputRef) => {\r\n inputRef.nativeElement.disabled = true;\r\n });\r\n }\r\n\r\n //Clear Interval\r\n ngOnDestroy(): void {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n }\r\n }\r\n}\r\n\r\n","<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n @for (_ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); track _; let i = $index) {\r\n <input\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n }\r\n</div>\r\n<!-- Timer -->\r\n@if (rucInputData.timeLimit) {\r\n <div class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n </div>\r\n}\r\n<!-- Timeout message -->\r\n@if (rucInputData.timeLimit && timeLeft === 0) {\r\n <div class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n </div>\r\n}\r\n\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { OnInit, AfterViewInit, OnDestroy, EventEmitter, QueryList, ElementRef } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
interface InputOtpConfig {
|
|
5
|
+
/** Number of OTP digits */
|
|
6
|
+
length?: number;
|
|
7
|
+
/** Mask input as password */
|
|
8
|
+
mask?: boolean;
|
|
9
|
+
/** Sizes: small, medium, large */
|
|
10
|
+
size?: 'small' | 'medium' | 'large';
|
|
11
|
+
/** Only allow integers 0-9 */
|
|
12
|
+
integerOnly?: boolean;
|
|
13
|
+
/** Autofocus and auto-jump */
|
|
14
|
+
autoFocus?: boolean;
|
|
15
|
+
autoSubmit?: boolean;
|
|
16
|
+
timeLimit?: number;
|
|
17
|
+
copyProtection?: boolean;
|
|
18
|
+
templateType?: 'rectangle' | 'circle' | 'underscore';
|
|
19
|
+
/** Validation state for visual feedback */
|
|
20
|
+
validationState?: 'valid' | 'invalid' | undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare class RuclibInputOtpComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
24
|
+
readonly DEFAULT_OTP_LENGTH = 6;
|
|
25
|
+
readonly TIME_LEFT = "Time left";
|
|
26
|
+
readonly EXPIRED_MSG = "OTP expired. Please request a new one.";
|
|
27
|
+
rucEvent: EventEmitter<any>;
|
|
28
|
+
customTheme?: string;
|
|
29
|
+
rucInputData: InputOtpConfig;
|
|
30
|
+
timeLeft: number;
|
|
31
|
+
timerId: any;
|
|
32
|
+
inputs: QueryList<ElementRef<HTMLInputElement>>;
|
|
33
|
+
otpValues: string[];
|
|
34
|
+
ngOnInit(): void;
|
|
35
|
+
ngAfterViewInit(): void;
|
|
36
|
+
handleInput(event: Event, index: number): void;
|
|
37
|
+
handleKeyDown(event: KeyboardEvent, index: number): void;
|
|
38
|
+
handlePaste(event: ClipboardEvent): void;
|
|
39
|
+
private isOtpComplete;
|
|
40
|
+
private disableAllInputs;
|
|
41
|
+
ngOnDestroy(): void;
|
|
42
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RuclibInputOtpComponent, never>;
|
|
43
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RuclibInputOtpComponent, "uxp-ruclib-input-otp", never, { "customTheme": { "alias": "customTheme"; "required": false; }; "rucInputData": { "alias": "rucInputData"; "required": false; }; }, { "rucEvent": "rucEvent"; }, never, never, true, never>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { RuclibInputOtpComponent };
|
|
47
|
+
export type { InputOtpConfig };
|
package/package.json
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ruc-lib/input-otp",
|
|
3
|
-
"version": "
|
|
4
|
-
"license": "MIT",
|
|
3
|
+
"version": "3.1.0",
|
|
5
4
|
"peerDependencies": {
|
|
6
|
-
"@angular/common": "^
|
|
7
|
-
"@angular/core": "^
|
|
8
|
-
"@angular/material": "^15.
|
|
5
|
+
"@angular/common": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0",
|
|
6
|
+
"@angular/core": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0",
|
|
7
|
+
"@angular/material": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0"
|
|
9
8
|
},
|
|
10
9
|
"dependencies": {
|
|
11
10
|
"tslib": "^2.3.0"
|
|
12
11
|
},
|
|
13
|
-
"publishConfig": {
|
|
14
|
-
"access": "public"
|
|
15
|
-
},
|
|
16
12
|
"sideEffects": false,
|
|
17
|
-
"module": "
|
|
18
|
-
"es2020": "fesm2020/ruc-lib-input-otp.mjs",
|
|
19
|
-
"esm2020": "esm2020/ruc-lib-input-otp.mjs",
|
|
20
|
-
"fesm2020": "fesm2020/ruc-lib-input-otp.mjs",
|
|
21
|
-
"fesm2015": "fesm2015/ruc-lib-input-otp.mjs",
|
|
13
|
+
"module": "fesm2022/ruc-lib-input-otp.mjs",
|
|
22
14
|
"typings": "index.d.ts",
|
|
23
15
|
"exports": {
|
|
24
16
|
"./package.json": {
|
|
@@ -26,11 +18,7 @@
|
|
|
26
18
|
},
|
|
27
19
|
".": {
|
|
28
20
|
"types": "./index.d.ts",
|
|
29
|
-
"
|
|
30
|
-
"es2020": "./fesm2020/ruc-lib-input-otp.mjs",
|
|
31
|
-
"es2015": "./fesm2015/ruc-lib-input-otp.mjs",
|
|
32
|
-
"node": "./fesm2015/ruc-lib-input-otp.mjs",
|
|
33
|
-
"default": "./fesm2020/ruc-lib-input-otp.mjs"
|
|
21
|
+
"default": "./fesm2022/ruc-lib-input-otp.mjs"
|
|
34
22
|
}
|
|
35
23
|
}
|
|
36
24
|
}
|
package/esm2020/index.mjs
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export * from './lib/ruclib-input-otp.module';
|
|
2
|
-
export * from './lib/input-otp/input-otp.component';
|
|
3
|
-
export * from './modal/input-otp-config';
|
|
4
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLHFDQUFxQyxDQUFDO0FBQ3BELGNBQWMsMEJBQTBCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2xpYi9ydWNsaWItaW5wdXQtb3RwLm1vZHVsZSc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbGliL2lucHV0LW90cC9pbnB1dC1vdHAuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9tb2RhbC9pbnB1dC1vdHAtY29uZmlnJztcclxuIl19
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter, ViewChildren, QueryList, } from '@angular/core';
|
|
2
|
-
import { BACKSPACE_KEY } from '../../modal/constants';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
import * as i1 from "@angular/common";
|
|
5
|
-
import * as i2 from "@angular/forms";
|
|
6
|
-
export class InputOtpComponent {
|
|
7
|
-
constructor() {
|
|
8
|
-
this.DEFAULT_OTP_LENGTH = 6;
|
|
9
|
-
this.TIME_LEFT = "Time left";
|
|
10
|
-
this.EXPIRED_MSG = "OTP expired. Please request a new one.";
|
|
11
|
-
this.rucEvent = new EventEmitter();
|
|
12
|
-
this.rucInputData = {};
|
|
13
|
-
this.timeLeft = 0;
|
|
14
|
-
this.timerId = null;
|
|
15
|
-
this.otpValues = [];
|
|
16
|
-
}
|
|
17
|
-
ngOnInit() {
|
|
18
|
-
this.otpValues = Array(this.rucInputData.length || 6).fill('');
|
|
19
|
-
if (this.rucInputData.timeLimit) {
|
|
20
|
-
this.timeLeft = this.rucInputData.timeLimit;
|
|
21
|
-
}
|
|
22
|
-
// Set default for copyProtection
|
|
23
|
-
if (this.rucInputData.copyProtection === undefined) {
|
|
24
|
-
this.rucInputData.copyProtection = true;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
ngAfterViewInit() {
|
|
28
|
-
// Merge input config with defaults
|
|
29
|
-
this.otpValues = Array(this.rucInputData.length || 6).fill('');
|
|
30
|
-
if (this.rucInputData.autoFocus) {
|
|
31
|
-
setTimeout(() => this.inputs.first?.nativeElement.focus(), 0); // Auto-focus first input
|
|
32
|
-
}
|
|
33
|
-
if (this.rucInputData.timeLimit) {
|
|
34
|
-
this.timeLeft = this.rucInputData.timeLimit;
|
|
35
|
-
this.timerId = setInterval(() => {
|
|
36
|
-
this.timeLeft--;
|
|
37
|
-
if (this.timeLeft <= 0) {
|
|
38
|
-
clearInterval(this.timerId);
|
|
39
|
-
this.disableAllInputs();
|
|
40
|
-
this.rucEvent.emit({ eventName: 'timeout', eventOutput: null });
|
|
41
|
-
}
|
|
42
|
-
}, 1000);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
// Handle OTP input
|
|
46
|
-
handleInput(event, index) {
|
|
47
|
-
const input = event.target;
|
|
48
|
-
const value = input.value;
|
|
49
|
-
if (this.rucInputData.integerOnly && !/^\d*$/.test(value)) {
|
|
50
|
-
input.value = ''; // Allow integers only
|
|
51
|
-
this.otpValues[index] = '';
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
this.otpValues[index] = value.slice(-1); // Take last digit
|
|
55
|
-
input.value = this.otpValues[index];
|
|
56
|
-
// Auto-jump to next input
|
|
57
|
-
if (value && index < (this.rucInputData.length || 6) - 1 && this.rucInputData.autoFocus) {
|
|
58
|
-
this.inputs.toArray()[index + 1].nativeElement.focus();
|
|
59
|
-
}
|
|
60
|
-
// Auto-submit on complete
|
|
61
|
-
if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {
|
|
62
|
-
if (this.timerId) {
|
|
63
|
-
clearInterval(this.timerId);
|
|
64
|
-
this.timerId = null;
|
|
65
|
-
}
|
|
66
|
-
this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
// Handle Keyboard navigation
|
|
70
|
-
handleKeyDown(event, index) {
|
|
71
|
-
const input = event.target;
|
|
72
|
-
if (event.key === BACKSPACE_KEY && !input.value && index > 0 && this.rucInputData.autoFocus) {
|
|
73
|
-
this.inputs.toArray()[index - 1].nativeElement.focus();
|
|
74
|
-
}
|
|
75
|
-
else if (event.key === 'ArrowLeft' && index > 0) {
|
|
76
|
-
event.preventDefault();
|
|
77
|
-
this.inputs.toArray()[index - 1].nativeElement.focus();
|
|
78
|
-
}
|
|
79
|
-
else if (event.key === 'ArrowRight' && index < (this.rucInputData.length || 6) - 1) {
|
|
80
|
-
event.preventDefault();
|
|
81
|
-
this.inputs.toArray()[index + 1].nativeElement.focus();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
//Handle Paste Event
|
|
85
|
-
handlePaste(event) {
|
|
86
|
-
event.preventDefault();
|
|
87
|
-
let pasteData = event.clipboardData?.getData('text');
|
|
88
|
-
if (this.rucInputData.integerOnly) {
|
|
89
|
-
pasteData = pasteData?.replace(/\D/g, ''); // Extract digits only
|
|
90
|
-
}
|
|
91
|
-
if (!pasteData)
|
|
92
|
-
return;
|
|
93
|
-
const pasteLength = Math.min(pasteData.length, this.rucInputData.length || 6);
|
|
94
|
-
for (let i = 0; i < pasteLength; i++) {
|
|
95
|
-
this.otpValues[i] = pasteData[i];
|
|
96
|
-
this.inputs.toArray()[i].nativeElement.value = pasteData[i];
|
|
97
|
-
}
|
|
98
|
-
// Focus last filled input or last input
|
|
99
|
-
const focusIndex = pasteLength < (this.rucInputData.length || 6) ? pasteLength : (this.rucInputData.length || 6) - 1;
|
|
100
|
-
this.inputs.toArray()[focusIndex].nativeElement.focus();
|
|
101
|
-
// Auto-submit if complete
|
|
102
|
-
if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {
|
|
103
|
-
if (this.timerId) {
|
|
104
|
-
clearInterval(this.timerId);
|
|
105
|
-
this.timerId = null;
|
|
106
|
-
}
|
|
107
|
-
this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
//Check if OTP is completed
|
|
111
|
-
isOtpComplete(otpArray) {
|
|
112
|
-
return otpArray.every(val => val.trim() !== '');
|
|
113
|
-
}
|
|
114
|
-
// Disable inputs
|
|
115
|
-
disableAllInputs() {
|
|
116
|
-
this.inputs.forEach((inputRef) => {
|
|
117
|
-
inputRef.nativeElement.disabled = true;
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
//Clear Interval
|
|
121
|
-
ngOnDestroy() {
|
|
122
|
-
if (this.timerId) {
|
|
123
|
-
clearInterval(this.timerId);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
InputOtpComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: InputOtpComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
128
|
-
InputOtpComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: InputOtpComponent, selector: "uxp-input-otp", inputs: { customTheme: "customTheme", rucInputData: "rucInputData" }, outputs: { rucEvent: "rucEvent" }, viewQueries: [{ propertyName: "inputs", predicate: ["otpInput"], descendants: true }], ngImport: i0, template: "<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n <input *ngFor=\"let _ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); let i = index\"\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n</div>\r\n<!-- Timer -->\r\n<div *ngIf=\"rucInputData.timeLimit\" class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n</div>\r\n<!-- Timeout message -->\r\n<div *ngIf=\"rucInputData.timeLimit && timeLeft === 0\" class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n</div>\r\n\r\n", styles: [".otp-container{display:flex;gap:10px;justify-content:center}.otp-input{text-align:center;font-size:18px;border:1px solid #ccc;border-radius:4px;outline:none;transition:border-color .2s}.otp-input:focus{border-color:#007bff;box-shadow:0 0 5px #007bff4d}.otp-input::-webkit-outer-spin-button,.otp-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.otp-input[type=number]{-moz-appearance:textfield}.small .otp-input{width:30px;height:30px;font-size:14px}.medium .otp-input{width:40px;height:40px;font-size:18px}.large .otp-input{width:50px;height:50px;font-size:22px}.otp-timer{text-align:center;font-size:.9rem;color:#d9534f;font-weight:700}.otp-timeout-message{text-align:center;color:#d9534f;font-size:.9rem;margin-top:.5rem}.otp-input.rectangle{border-radius:8px}.otp-input.circle{border-radius:50%}.otp-input.underscore{border:none;border-bottom:2px solid #ccc;border-radius:0;background-color:transparent}.otp-input.is-valid{border-color:#28a745;background-color:#e6ffed}.otp-input.is-invalid{border-color:#dc3545;background-color:#ffe6e6}.dark-theme .otp-input:not(.is-invalid){color:#fff;background-color:#333}.light-theme .otp-input:not(.is-invalid){color:#000}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
129
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: InputOtpComponent, decorators: [{
|
|
130
|
-
type: Component,
|
|
131
|
-
args: [{ selector: 'uxp-input-otp', template: "<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n <input *ngFor=\"let _ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); let i = index\"\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n</div>\r\n<!-- Timer -->\r\n<div *ngIf=\"rucInputData.timeLimit\" class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n</div>\r\n<!-- Timeout message -->\r\n<div *ngIf=\"rucInputData.timeLimit && timeLeft === 0\" class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n</div>\r\n\r\n", styles: [".otp-container{display:flex;gap:10px;justify-content:center}.otp-input{text-align:center;font-size:18px;border:1px solid #ccc;border-radius:4px;outline:none;transition:border-color .2s}.otp-input:focus{border-color:#007bff;box-shadow:0 0 5px #007bff4d}.otp-input::-webkit-outer-spin-button,.otp-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.otp-input[type=number]{-moz-appearance:textfield}.small .otp-input{width:30px;height:30px;font-size:14px}.medium .otp-input{width:40px;height:40px;font-size:18px}.large .otp-input{width:50px;height:50px;font-size:22px}.otp-timer{text-align:center;font-size:.9rem;color:#d9534f;font-weight:700}.otp-timeout-message{text-align:center;color:#d9534f;font-size:.9rem;margin-top:.5rem}.otp-input.rectangle{border-radius:8px}.otp-input.circle{border-radius:50%}.otp-input.underscore{border:none;border-bottom:2px solid #ccc;border-radius:0;background-color:transparent}.otp-input.is-valid{border-color:#28a745;background-color:#e6ffed}.otp-input.is-invalid{border-color:#dc3545;background-color:#ffe6e6}.dark-theme .otp-input:not(.is-invalid){color:#fff;background-color:#333}.light-theme .otp-input:not(.is-invalid){color:#000}\n"] }]
|
|
132
|
-
}], propDecorators: { rucEvent: [{
|
|
133
|
-
type: Output
|
|
134
|
-
}], customTheme: [{
|
|
135
|
-
type: Input
|
|
136
|
-
}], rucInputData: [{
|
|
137
|
-
type: Input
|
|
138
|
-
}], inputs: [{
|
|
139
|
-
type: ViewChildren,
|
|
140
|
-
args: ['otpInput']
|
|
141
|
-
}] } });
|
|
142
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQtb3RwLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvaW5wdXQtb3RwL2lucHV0LW90cC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zcmMvbGliL2lucHV0LW90cC9pbnB1dC1vdHAuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxLQUFLLEVBQ0wsTUFBTSxFQUNOLFlBQVksRUFDWixZQUFZLEVBRVosU0FBUyxHQUlWLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQzs7OztBQU90RCxNQUFNLE9BQU8saUJBQWlCO0lBTDlCO1FBTVcsdUJBQWtCLEdBQUksQ0FBQyxDQUFDO1FBQ3hCLGNBQVMsR0FBRyxXQUFXLENBQUM7UUFDeEIsZ0JBQVcsR0FBRyx3Q0FBd0MsQ0FBQTtRQUVyRCxhQUFRLEdBQUcsSUFBSSxZQUFZLEVBQU8sQ0FBQztRQUdwQyxpQkFBWSxHQUFtQixFQUFFLENBQUM7UUFDM0MsYUFBUSxHQUFHLENBQUMsQ0FBQztRQUNiLFlBQU8sR0FBUSxJQUFJLENBQUM7UUFJcEIsY0FBUyxHQUFhLEVBQUUsQ0FBQztLQTRIMUI7SUExSEMsUUFBUTtRQUNOLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMvRCxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxFQUFFO1lBQy9CLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUM7U0FDN0M7UUFFSCxpQ0FBaUM7UUFDakMsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLGNBQWMsS0FBSyxTQUFTLEVBQUU7WUFDbEQsSUFBSSxDQUFD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QUFhLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUM1QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQzthQUNyQjtZQUNELElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQ3RGO0lBQ0gsQ0FBQztJQUVELDJCQUEyQjtJQUNuQixhQUFhLENBQUMsUUFBa0I7UUFDdEMsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFSCxpQkFBaUI7SUFDUCxnQkFBZ0I7UUFDdEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRTtZQUMvQixRQUFRLENBQUMsYUFBYSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDekMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsZ0JBQWdCO0lBQ2hCLFdBQVc7UUFDVCxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDaEIsYUFBYSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztTQUM3QjtJQUNILENBQUM7OytHQXpJVSxpQkFBaUI7bUdBQWpCLGlCQUFpQixxUENwQjlCLHE4Q0E4QkE7NEZEVmEsaUJBQWlCO2tCQUw3QixTQUFTOytCQUNFLGVBQWU7OEJBU2YsUUFBUTtzQkFBakIsTUFBTTtnQkFDRSxXQUFXO3NCQUFuQixLQUFLO2dCQUVHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBSW9CLE1BQU07c0JBQS9CLFlBQVk7dUJBQUMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgQ29tcG9uZW50LFxyXG4gIElucHV0LFxyXG4gIE91dHB1dCxcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgVmlld0NoaWxkcmVuLFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgUXVlcnlMaXN0LFxyXG4gIEFmdGVyVmlld0luaXQsXHJcbiAgT25EZXN0cm95LFxyXG4gIE9uSW5pdCxcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgSW5wdXRPdHBDb25maWcgfSBmcm9tICcuLi8uLi9tb2RhbC9pbnB1dC1vdHAtY29uZmlnJztcclxuaW1wb3J0IHsgQkFDS1NQQUNFX0tFWSB9IGZyb20gJy4uLy4uL21vZGFsL2NvbnN0YW50cyc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ3V4cC1pbnB1dC1vdHAnLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9pbnB1dC1vdHAuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL2lucHV0LW90cC5jb21wb25lbnQuc2NzcyddXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBJbnB1dE90cENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcclxuICByZWFkb25seSBERUZBVUxUX09UUF9MRU5HVEggID0gNjtcclxuICByZWFkb25seSBUSU1FX0xFRlQgPSBcIlRpbWUgbGVmdFwiO1xyXG4gIHJlYWRvbmx5IEVYUElSRURfTVNHID0gXCJPVFAgZXhwaXJlZC4gUGxlYXNlIHJlcXVlc3QgYSBuZXcgb25lLlwiXHJcblxyXG4gIEBPdXRwdXQoKSBydWNFdmVudCA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xyXG4gIEBJbnB1dCgpIGN1c3RvbVRoZW1lPzogc3RyaW5nO1xyXG5cclxuICBASW5wdXQoKSBydWNJbnB1dERhdGE6IElucHV0T3RwQ29uZmlnID0ge307XHJcbiAgdGltZUxlZnQgPSAwO1xyXG4gIHRpbWVySWQ6IGFueSA9IG51bGw7XHJcblxyXG4gIEBWaWV3Q2hpbGRyZW4oJ290cElucHV0JykgaW5wdXRzITogUXVlcnlMaXN0PEVsZW1lbnRSZWY8SFRNTElucHV0RWxlbWVudD4+O1xyXG5cclxuICBvdHBWYWx1ZXM6IHN0cmluZ1tdID0gW107XHJcblxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5vdHBWYWx1ZXMgPSBBcnJheSh0aGlzLnJ1Y0lucHV0RGF0YS5sZW5ndGggfHwgNikuZmlsbCgnJyk7XHJcbiAgICBpZiAodGhpcy5ydWNJbnB1dERhdGEudGltZUxpbWl0KSB7XHJcbiAgICAgIHRoaXMudGltZUxlZnQgPSB0aGlzLnJ1Y0lucHV0RGF0YS50aW1lTGltaXQ7XHJcbiAgICB9XHJcblxyXG4gIC8vIFNldCBkZWZhdWx0IGZvciBjb3B5UHJvdGVjdGlvblxyXG4gIGlmICh0aGlzLnJ1Y0lucHV0RGF0YS5jb3B5UHJvdGVjdGlvbiA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICB0aGlzLnJ1Y0lucHV0RGF0YS5jb3B5UHJvdGVjdGlvbiA9IHRydWU7XHJcbiAgfVxyXG4gIH1cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xyXG4gICAgLy8gTWVyZ2UgaW5wdXQgY29uZmlnIHdpdGggZGVmYXVsdHNcclxuICAgIHRoaXMub3RwVmFsdWVzID0gQXJyYXkodGhpcy5ydWNJbnB1dERhdGEubGVuZ3RoIHx8IDYpLmZpbGwoJycpO1xyXG4gICAgaWYgKHRoaXMucnVjSW5wdXREYXRhLmF1dG9Gb2N1cykge1xyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMuaW5wdXRzLmZpcnN0Py5uYXRpdmVFbGVtZW50LmZvY3VzKCksIDApOyAvLyBBdXRvLWZvY3VzIGZpcnN0IGlucHV0XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMucnVjSW5wdXREYXRhLnRpbWVMaW1pdCkge1xyXG4gICAgICB0aGlzLnRpbWVMZWZ0ID0gdGhpcy5ydWNJbnB1dERhdGEudGltZUxpbWl0O1xyXG4gICAgICB0aGlzLnRpbWVySWQgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICAgICAgdGhpcy50aW1lTGVmdC0tO1xyXG4gICAgICAgIGlmICh0aGlzLnRpbWVMZWZ0IDw9IDApIHtcclxuICAgICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy50aW1lcklkKTtcclxuICAgICAgICAgIHRoaXMuZGlzYWJsZUFsbElucHV0cygpO1xyXG4gICAgICAgICAgdGhpcy5ydWNFdmVudC5lbWl0KHsgZXZlbnROYW1lOiAndGltZW91dCcsIGV2ZW50T3V0cHV0OiBudWxsIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfSwgMTAwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG4vLyBIYW5kbGUgT1RQIGlucHV0XHJcbiAgaGFuZGxlSW5wdXQoZXZlbnQ6IEV2ZW50LCBpbmRleDogbnVtYmVyKTogdm9pZCB7XHJcbiAgICBjb25zdCBpbnB1dCA9IGV2ZW50LnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50O1xyXG4gICAgY29uc3QgdmFsdWUgPSBpbnB1dC52YWx1ZTtcclxuXHJcbiAgICBpZiAodGhpcy5ydWNJbnB1dERhdGEuaW50ZWdlck9ubHkgJiYgIS9eXFxkKiQvLnRlc3QodmFsdWUpKSB7XHJcbiAgICAgIGlucHV0LnZhbHVlID0gJyc7IC8vIEFsbG93IGludGVnZXJzIG9ubHlcclxuICAgICAgdGhpcy5vdHBWYWx1ZXNbaW5kZXhdID0gJyc7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLm90cFZhbHVlc1tpbmRleF0gPSB2YWx1ZS5zbGljZSgtMSk7IC8vIFRha2UgbGFzdCBkaWdpdFxyXG4gICAgaW5wdXQudmFsdWUgPSB0aGlzLm90cFZhbHVlc1tpbmRleF07XHJcblxyXG4gICAgLy8gQXV0by1qdW1wIHRvIG5leHQgaW5wdXRcclxuICAgIGlmICh2YWx1ZSAmJiBpbmRleCA8ICh0aGlzLnJ1Y0lucHV0RGF0YS5sZW5ndGggfHwgNikgLSAxICYmIHRoaXMucnVjSW5wdXREYXRhLmF1dG9Gb2N1cykge1xyXG4gICAgICB0aGlzLmlucHV0cy50b0FycmF5KClbaW5kZXggKyAxXS5uYXRpdmVFbGVtZW50LmZvY3VzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQXV0by1zdWJtaXQgb24gY29tcGxldGVcclxuICAgIGlmICh0aGlzLnJ1Y0lucHV0RGF0YS5hdXRvU3VibWl0ICYmIHRoaXMuaXNPdHBDb21wbGV0ZSh0aGlzLm90cFZhbHVlcykpIHtcclxuICAgICAgaWYgKHRoaXMudGltZXJJZCkge1xyXG4gICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy50aW1lcklkKTtcclxuICAgICAgICB0aGlzLnRpbWVySWQgPSBudWxsO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMucnVjRXZlbnQuZW1pdCh7IGV2ZW50TmFtZTogJ2NvbXBsZXRlZCcsIGV2ZW50T3V0cHV0OiB0aGlzLm90cFZhbHVlcy5qb2luKCcnKSB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4vLyBIYW5kbGUgS2V5Ym9hcmQgbmF2aWdhdGlvblxyXG4gIGhhbmRsZUtleURvd24oZXZlbnQ6IEtleWJvYXJkRXZlbnQsIGluZGV4OiBudW1iZXIpOiB2b2lkIHtcclxuICAgIGNvbnN0IGlucHV0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XHJcblxyXG4gICAgaWYgKGV2ZW50LmtleSA9PT0gQkFDS1NQQUNFX0tFWSAmJiAhaW5wdXQudmFsdWUgJiYgaW5kZXggPiAwICYmIHRoaXMucnVjSW5wdXREYXRhLmF1dG9Gb2N1cykge1xyXG4gICAgICB0aGlzLmlucHV0cy50b0FycmF5KClbaW5kZXggLSAxXS5uYXRpdmVFbGVtZW50LmZvY3VzKCk7XHJcbiAgICB9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gJ0Fycm93TGVmdCcgJiYgaW5kZXggPiAwKSB7XHJcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgIHRoaXMuaW5wdXRzLnRvQXJyYXkoKVtpbmRleCAtIDFdLm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcclxuICAgIH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSAnQXJyb3dSaWdodCcgJiYgaW5kZXggPCAodGhpcy5ydWNJbnB1dERhdGEubGVuZ3RoIHx8IDYpIC0gMSkge1xyXG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICB0aGlzLmlucHV0cy50b0FycmF5KClbaW5kZXggKyAxXS5uYXRpdmVFbGVtZW50LmZvY3VzKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuLy9IYW5kbGUgUGFzdGUgRXZlbnRcclxuICBoYW5kbGVQYXN0ZShldmVudDogQ2xpcGJvYXJkRXZlbnQpOiB2b2lkIHtcclxuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICBsZXQgcGFzdGVEYXRhID0gZXZlbnQuY2xpcGJvYXJkRGF0YT8uZ2V0RGF0YSgndGV4dCcpO1xyXG4gICAgaWYgKHRoaXMucnVjSW5wdXREYXRhLmludGVnZXJPbmx5KSB7XHJcbiAgICAgIHBhc3RlRGF0YSA9IHBhc3RlRGF0YT8ucmVwbGFjZSgvXFxEL2csICcnKTsgLy8gRXh0cmFjdCBkaWdpdHMgb25seVxyXG4gICAgfVxyXG4gICAgaWYgKCFwYXN0ZURhdGEpIHJldHVybjtcclxuXHJcbiAgICBjb25zdCBwYXN0ZUxlbmd0aCA9IE1hdGgubWluKHBhc3RlRGF0YS5sZW5ndGgsIHRoaXMucnVjSW5wdXREYXRhLmxlbmd0aCB8fCA2KTtcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGFzdGVMZW5ndGg7IGkrKykge1xyXG4gICAgICB0aGlzLm90cFZhbHVlc1tpXSA9IHBhc3RlRGF0YVtpXTtcclxuICAgICAgdGhpcy5pbnB1dHMudG9BcnJheSgpW2ldLm5hdGl2ZUVsZW1lbnQudmFsdWUgPSBwYXN0ZURhdGFbaV07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRm9jdXMgbGFzdCBmaWxsZWQgaW5wdXQgb3IgbGFzdCBpbnB1dFxyXG4gICAgY29uc3QgZm9jdXNJbmRleCA9IHBhc3RlTGVuZ3RoIDwgKHRoaXMucnVjSW5wdXREYXRhLmxlbmd0aCB8fCA2KSA/IHBhc3RlTGVuZ3RoIDogKHRoaXMucnVjSW5wdXREYXRhLmxlbmd0aCB8fCA2KSAtIDE7XHJcbiAgICB0aGlzLmlucHV0cy50b0FycmF5KClbZm9jdXNJbmRleF0ubmF0aXZlRWxlbWVudC5mb2N1cygpO1xyXG5cclxuICAgIC8vIEF1dG8tc3VibWl0IGlmIGNvbXBsZXRlXHJcbiAgICBpZiAodGhpcy5ydWNJbnB1dERhdGEuYXV0b1N1Ym1pdCAmJiB0aGlzLmlzT3RwQ29tcGxldGUodGhpcy5vdHBWYWx1ZXMpKSB7XHJcbiAgICAgIGlmICh0aGlzLnRpbWVySWQpIHtcclxuICAgICAgICBjbGVhckludGVydmFsKHRoaXMudGltZXJJZCk7XHJcbiAgICAgICAgdGhpcy50aW1lcklkID0gbnVsbDtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLnJ1Y0V2ZW50LmVtaXQoeyBldmVudE5hbWU6ICdjb21wbGV0ZWQnLCBldmVudE91dHB1dDogdGhpcy5vdHBWYWx1ZXMuam9pbignJykgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvL0NoZWNrIGlmIE9UUCBpcyBjb21wbGV0ZWRcclxuICBwcml2YXRlIGlzT3RwQ29tcGxldGUob3RwQXJyYXk6IHN0cmluZ1tdKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gb3RwQXJyYXkuZXZlcnkodmFsID0+IHZhbC50cmltKCkgIT09ICcnKTtcclxuICB9XHJcblxyXG4vLyBEaXNhYmxlIGlucHV0c1xyXG4gIHByaXZhdGUgZGlzYWJsZUFsbElucHV0cygpOiB2b2lkIHtcclxuICAgIHRoaXMuaW5wdXRzLmZvckVhY2goKGlucHV0UmVmKSA9PiB7XHJcbiAgICAgIGlucHV0UmVmLm5hdGl2ZUVsZW1lbnQuZGlzYWJsZWQgPSB0cnVlO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvL0NsZWFyIEludGVydmFsXHJcbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy50aW1lcklkKSB7XHJcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy50aW1lcklkKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiPGRpdiBjbGFzcz1cInt7Y3VzdG9tVGhlbWV9fSBvdHAtY29udGFpbmVyXCIgW25nQ2xhc3NdPVwicnVjSW5wdXREYXRhLnNpemUgfHwgJ21lZGl1bSdcIiAocGFzdGUpPVwiaGFuZGxlUGFzdGUoJGV2ZW50KVwiPlxyXG4gIDxpbnB1dCAqbmdGb3I9XCJsZXQgXyBvZiBbXS5jb25zdHJ1Y3RvcihydWNJbnB1dERhdGEubGVuZ3RoIHx8IERFRkFVTFRfT1RQX0xFTkdUSCk7IGxldCBpID0gaW5kZXhcIlxyXG4gICAgICAgICAjb3RwSW5wdXRcclxuICAgICAgICAgW3R5cGVdPVwicnVjSW5wdXREYXRhLm1hc2sgPyAncGFzc3dvcmQnIDogJ3RleHQnXCJcclxuICAgICAgICAgW25nQ2xhc3NdPVwiW1xyXG4gICAgICAgICdvdHAtaW5wdXQnLFxyXG4gICAgICAgIHJ1Y0lucHV0RGF0YS50ZW1wbGF0ZVR5cGUgfHwgJ3JlY3RhbmdsZScsXHJcbiAgICAgICAgcnVjSW5wdXREYXRhLnZhbGlkYXRpb25TdGF0ZSA9PT0gJ3ZhbGlkJyA/ICdpcy12YWxpZCcgOiAnJyxcclxuICAgICAgICBydWNJbnB1dERhdGEudmFsaWRhdGlvblN0YXRlID09PSAnaW52YWxpZCcgPyAnaXMtaW52YWxpZCcgOiAnJ1xyXG4gICAgICBdXCJcclxuICAgICAgICAgbWF4bGVuZ3RoPVwiMVwiXHJcbiAgICAgICAgIFsobmdNb2RlbCldPVwib3RwVmFsdWVzW2ldXCJcclxuICAgICAgICAgKGlucHV0KT1cImhhbmRsZUlucHV0KCRldmVudCwgaSlcIlxyXG4gICAgICAgICAoY29weSk9XCJydWNJbnB1dERhdGEuY29weVByb3RlY3Rpb24gJiYgJGV2ZW50LnByZXZlbnREZWZhdWx0KClcIlxyXG4gICAgICAgICAocGFzdGUpPVwicnVjSW5wdXREYXRhLmNvcHlQcm90ZWN0aW9uICYmICRldmVudC5wcmV2ZW50RGVmYXVsdCgpXCIgICAgXHJcbiAgICAgICAgIChjb250ZXh0bWVudSk9XCJydWNJbnB1dERhdGEuY29weVByb3RlY3Rpb24gJiYgJGV2ZW50LnByZXZlbnREZWZhdWx0KClcIiAgICAgXHJcbiAgICAgICAgIChrZXlkb3duKT1cImhhbmRsZUtleURvd24oJGV2ZW50LCBpKVwiXHJcbiAgICAgICAgIFthdHRyLmlucHV0bW9kZV09XCJydWNJbnB1dERhdGEuaW50ZWdlck9ubHkgPyAnbnVtZXJpYycgOiAndGV4dCdcIlxyXG4gICAgICAgICBbcGF0dGVybl09XCJydWNJbnB1dERhdGEuaW50ZWdlck9ubHkgPyAnWzAtOV0qJyA6ICcuKidcIlxyXG4gICAgICAgICBhdXRvY29tcGxldGU9XCJvbmUtdGltZS1jb2RlXCI+XHJcbjwvZGl2PlxyXG48IS0tIFRpbWVyIC0tPlxyXG48ZGl2ICpuZ0lmPVwicnVjSW5wdXREYXRhLnRpbWVMaW1pdFwiIGNsYXNzPVwib3RwLXRpbWVyXCI+XHJcbiAge3tUSU1FX0xFRlR9fToge3sgdGltZUxlZnQgfX1zXHJcbjwvZGl2PlxyXG48IS0tIFRpbWVvdXQgbWVzc2FnZSAtLT5cclxuPGRpdiAqbmdJZj1cInJ1Y0lucHV0RGF0YS50aW1lTGltaXQgJiYgdGltZUxlZnQgPT09IDBcIiBjbGFzcz1cIm90cC10aW1lb3V0LW1lc3NhZ2VcIj5cclxuICB7e0VYUElSRURfTVNHfX1cclxuPC9kaXY+XHJcblxyXG4iXX0=
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { NgModule } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
4
|
-
import { FormsModule } from '@angular/forms';
|
|
5
|
-
import { InputOtpComponent } from './input-otp/input-otp.component';
|
|
6
|
-
import * as i0 from "@angular/core";
|
|
7
|
-
export class RuclibInputOtpModule {
|
|
8
|
-
}
|
|
9
|
-
RuclibInputOtpModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
10
|
-
RuclibInputOtpModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, declarations: [InputOtpComponent], imports: [CommonModule, MatIconModule, FormsModule], exports: [InputOtpComponent] });
|
|
11
|
-
RuclibInputOtpModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, imports: [CommonModule, MatIconModule, FormsModule] });
|
|
12
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, decorators: [{
|
|
13
|
-
type: NgModule,
|
|
14
|
-
args: [{
|
|
15
|
-
imports: [CommonModule, MatIconModule, FormsModule],
|
|
16
|
-
declarations: [InputOtpComponent],
|
|
17
|
-
exports: [InputOtpComponent]
|
|
18
|
-
}]
|
|
19
|
-
}] });
|
|
20
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVjbGliLWlucHV0LW90cC5tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3J1Y2xpYi1pbnB1dC1vdHAubW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUNBQWlDLENBQUM7O0FBUXBFLE1BQU0sT0FBTyxvQkFBb0I7O2tIQUFwQixvQkFBb0I7bUhBQXBCLG9CQUFvQixpQkFKaEIsaUJBQWlCLGFBRHRCLFlBQVksRUFBRSxhQUFhLEVBQUUsV0FBVyxhQUV2QyxpQkFBaUI7bUhBR2pCLG9CQUFvQixZQUxyQixZQUFZLEVBQUUsYUFBYSxFQUFFLFdBQVc7NEZBS3ZDLG9CQUFvQjtrQkFOaEMsUUFBUTttQkFBQztvQkFDUixPQUFPLEVBQUUsQ0FBQyxZQUFZLEVBQUUsYUFBYSxFQUFFLFdBQVcsQ0FBQztvQkFDbkQsWUFBWSxFQUFFLENBQUMsaUJBQWlCLENBQUM7b0JBQ2pDLE9BQU8sRUFBRyxDQUFDLGlCQUFpQixDQUFDO2lCQUU5QiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IE1hdEljb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pY29uJztcclxuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IElucHV0T3RwQ29tcG9uZW50IH0gZnJvbSAnLi9pbnB1dC1vdHAvaW5wdXQtb3RwLmNvbXBvbmVudCc7XHJcblxyXG5ATmdNb2R1bGUoe1xyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIE1hdEljb25Nb2R1bGUsIEZvcm1zTW9kdWxlXSxcclxuICBkZWNsYXJhdGlvbnM6IFtJbnB1dE90cENvbXBvbmVudF0sXHJcbiAgZXhwb3J0cyA6IFtJbnB1dE90cENvbXBvbmVudF1cclxuXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBSdWNsaWJJbnB1dE90cE1vZHVsZSB7fVxyXG4iXX0=
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
export const BACKSPACE_KEY = "Backspace";
|
|
2
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGFsL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsV0FBVyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IEJBQ0tTUEFDRV9LRVkgPSBcIkJhY2tzcGFjZVwiIl19
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
export {};
|
|
2
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQtb3RwLWNvbmZpZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tb2RhbC9pbnB1dC1vdHAtY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgaW50ZXJmYWNlIElucHV0T3RwQ29uZmlnIHtcclxuICAvKiogTnVtYmVyIG9mIE9UUCBkaWdpdHMgKi9cclxuICBsZW5ndGg/OiBudW1iZXI7XHJcbiAgLyoqIE1hc2sgaW5wdXQgYXMgcGFzc3dvcmQgKi9cclxuICBtYXNrPzogYm9vbGVhbjtcclxuICAvKiogU2l6ZXM6IHNtYWxsLCBtZWRpdW0sIGxhcmdlICovXHJcbiAgc2l6ZT86ICdzbWFsbCcgfCAnbWVkaXVtJyB8ICdsYXJnZSc7XHJcbiAgLyoqIE9ubHkgYWxsb3cgaW50ZWdlcnMgMC05ICovXHJcbiAgaW50ZWdlck9ubHk/OiBib29sZWFuO1xyXG4gIC8qKiBBdXRvZm9jdXMgYW5kIGF1dG8tanVtcCAqL1xyXG4gIGF1dG9Gb2N1cz86IGJvb2xlYW47XHJcbiAgYXV0b1N1Ym1pdD86IGJvb2xlYW47XHJcbiAgdGltZUxpbWl0PzogbnVtYmVyOyAvLyBPcHRpb25hbCB0aW1lb3V0IGluIHNlY29uZHNcclxuICAvL2NvcHkgYW5kIHBhc3RlIHByb3RlY3Rpb25cclxuICBjb3B5UHJvdGVjdGlvbj8gOiBib29sZWFuXHJcbiAgLy90ZW1wbGF0ZSBzdHlsZVxyXG4gIHRlbXBsYXRlVHlwZT86ICdyZWN0YW5nbGUnIHwgJ2NpcmNsZScgfCAndW5kZXJzY29yZSc7XHJcbiAgLyoqIFZhbGlkYXRpb24gc3RhdGUgZm9yIHZpc3VhbCBmZWVkYmFjayAqL1xyXG52YWxpZGF0aW9uU3RhdGU/OiAndmFsaWQnIHwgJ2ludmFsaWQnIHwgdW5kZWZpbmVkO1xyXG4vKiogT3B0aW9uYWwgc2VwYXJhdG9yIHRvIGJlIGFkZGVkIGJldHdlZW4gT1RQIGRpZ2l0cyBpbiB0aGUgb3V0cHV0ICovXHJcbiAgfSJdfQ==
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generated bundle index. Do not edit.
|
|
3
|
-
*/
|
|
4
|
-
export * from './index';
|
|
5
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVjLWxpYi1pbnB1dC1vdHAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVjLWxpYi1pbnB1dC1vdHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLFNBQVMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9pbmRleCc7XG4iXX0=
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { EventEmitter, Component, Output, Input, ViewChildren, NgModule } from '@angular/core';
|
|
3
|
-
import * as i1 from '@angular/common';
|
|
4
|
-
import { CommonModule } from '@angular/common';
|
|
5
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
6
|
-
import * as i2 from '@angular/forms';
|
|
7
|
-
import { FormsModule } from '@angular/forms';
|
|
8
|
-
|
|
9
|
-
const BACKSPACE_KEY = "Backspace";
|
|
10
|
-
|
|
11
|
-
class InputOtpComponent {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.DEFAULT_OTP_LENGTH = 6;
|
|
14
|
-
this.TIME_LEFT = "Time left";
|
|
15
|
-
this.EXPIRED_MSG = "OTP expired. Please request a new one.";
|
|
16
|
-
this.rucEvent = new EventEmitter();
|
|
17
|
-
this.rucInputData = {};
|
|
18
|
-
this.timeLeft = 0;
|
|
19
|
-
this.timerId = null;
|
|
20
|
-
this.otpValues = [];
|
|
21
|
-
}
|
|
22
|
-
ngOnInit() {
|
|
23
|
-
this.otpValues = Array(this.rucInputData.length || 6).fill('');
|
|
24
|
-
if (this.rucInputData.timeLimit) {
|
|
25
|
-
this.timeLeft = this.rucInputData.timeLimit;
|
|
26
|
-
}
|
|
27
|
-
// Set default for copyProtection
|
|
28
|
-
if (this.rucInputData.copyProtection === undefined) {
|
|
29
|
-
this.rucInputData.copyProtection = true;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
ngAfterViewInit() {
|
|
33
|
-
// Merge input config with defaults
|
|
34
|
-
this.otpValues = Array(this.rucInputData.length || 6).fill('');
|
|
35
|
-
if (this.rucInputData.autoFocus) {
|
|
36
|
-
setTimeout(() => { var _a; return (_a = this.inputs.first) === null || _a === void 0 ? void 0 : _a.nativeElement.focus(); }, 0); // Auto-focus first input
|
|
37
|
-
}
|
|
38
|
-
if (this.rucInputData.timeLimit) {
|
|
39
|
-
this.timeLeft = this.rucInputData.timeLimit;
|
|
40
|
-
this.timerId = setInterval(() => {
|
|
41
|
-
this.timeLeft--;
|
|
42
|
-
if (this.timeLeft <= 0) {
|
|
43
|
-
clearInterval(this.timerId);
|
|
44
|
-
this.disableAllInputs();
|
|
45
|
-
this.rucEvent.emit({ eventName: 'timeout', eventOutput: null });
|
|
46
|
-
}
|
|
47
|
-
}, 1000);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
// Handle OTP input
|
|
51
|
-
handleInput(event, index) {
|
|
52
|
-
const input = event.target;
|
|
53
|
-
const value = input.value;
|
|
54
|
-
if (this.rucInputData.integerOnly && !/^\d*$/.test(value)) {
|
|
55
|
-
input.value = ''; // Allow integers only
|
|
56
|
-
this.otpValues[index] = '';
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
this.otpValues[index] = value.slice(-1); // Take last digit
|
|
60
|
-
input.value = this.otpValues[index];
|
|
61
|
-
// Auto-jump to next input
|
|
62
|
-
if (value && index < (this.rucInputData.length || 6) - 1 && this.rucInputData.autoFocus) {
|
|
63
|
-
this.inputs.toArray()[index + 1].nativeElement.focus();
|
|
64
|
-
}
|
|
65
|
-
// Auto-submit on complete
|
|
66
|
-
if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {
|
|
67
|
-
if (this.timerId) {
|
|
68
|
-
clearInterval(this.timerId);
|
|
69
|
-
this.timerId = null;
|
|
70
|
-
}
|
|
71
|
-
this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// Handle Keyboard navigation
|
|
75
|
-
handleKeyDown(event, index) {
|
|
76
|
-
const input = event.target;
|
|
77
|
-
if (event.key === BACKSPACE_KEY && !input.value && index > 0 && this.rucInputData.autoFocus) {
|
|
78
|
-
this.inputs.toArray()[index - 1].nativeElement.focus();
|
|
79
|
-
}
|
|
80
|
-
else if (event.key === 'ArrowLeft' && index > 0) {
|
|
81
|
-
event.preventDefault();
|
|
82
|
-
this.inputs.toArray()[index - 1].nativeElement.focus();
|
|
83
|
-
}
|
|
84
|
-
else if (event.key === 'ArrowRight' && index < (this.rucInputData.length || 6) - 1) {
|
|
85
|
-
event.preventDefault();
|
|
86
|
-
this.inputs.toArray()[index + 1].nativeElement.focus();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
//Handle Paste Event
|
|
90
|
-
handlePaste(event) {
|
|
91
|
-
var _a;
|
|
92
|
-
event.preventDefault();
|
|
93
|
-
let pasteData = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text');
|
|
94
|
-
if (this.rucInputData.integerOnly) {
|
|
95
|
-
pasteData = pasteData === null || pasteData === void 0 ? void 0 : pasteData.replace(/\D/g, ''); // Extract digits only
|
|
96
|
-
}
|
|
97
|
-
if (!pasteData)
|
|
98
|
-
return;
|
|
99
|
-
const pasteLength = Math.min(pasteData.length, this.rucInputData.length || 6);
|
|
100
|
-
for (let i = 0; i < pasteLength; i++) {
|
|
101
|
-
this.otpValues[i] = pasteData[i];
|
|
102
|
-
this.inputs.toArray()[i].nativeElement.value = pasteData[i];
|
|
103
|
-
}
|
|
104
|
-
// Focus last filled input or last input
|
|
105
|
-
const focusIndex = pasteLength < (this.rucInputData.length || 6) ? pasteLength : (this.rucInputData.length || 6) - 1;
|
|
106
|
-
this.inputs.toArray()[focusIndex].nativeElement.focus();
|
|
107
|
-
// Auto-submit if complete
|
|
108
|
-
if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {
|
|
109
|
-
if (this.timerId) {
|
|
110
|
-
clearInterval(this.timerId);
|
|
111
|
-
this.timerId = null;
|
|
112
|
-
}
|
|
113
|
-
this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
//Check if OTP is completed
|
|
117
|
-
isOtpComplete(otpArray) {
|
|
118
|
-
return otpArray.every(val => val.trim() !== '');
|
|
119
|
-
}
|
|
120
|
-
// Disable inputs
|
|
121
|
-
disableAllInputs() {
|
|
122
|
-
this.inputs.forEach((inputRef) => {
|
|
123
|
-
inputRef.nativeElement.disabled = true;
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
//Clear Interval
|
|
127
|
-
ngOnDestroy() {
|
|
128
|
-
if (this.timerId) {
|
|
129
|
-
clearInterval(this.timerId);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
InputOtpComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: InputOtpComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
134
|
-
InputOtpComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: InputOtpComponent, selector: "uxp-input-otp", inputs: { customTheme: "customTheme", rucInputData: "rucInputData" }, outputs: { rucEvent: "rucEvent" }, viewQueries: [{ propertyName: "inputs", predicate: ["otpInput"], descendants: true }], ngImport: i0, template: "<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n <input *ngFor=\"let _ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); let i = index\"\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n</div>\r\n<!-- Timer -->\r\n<div *ngIf=\"rucInputData.timeLimit\" class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n</div>\r\n<!-- Timeout message -->\r\n<div *ngIf=\"rucInputData.timeLimit && timeLeft === 0\" class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n</div>\r\n\r\n", styles: [".otp-container{display:flex;gap:10px;justify-content:center}.otp-input{text-align:center;font-size:18px;border:1px solid #ccc;border-radius:4px;outline:none;transition:border-color .2s}.otp-input:focus{border-color:#007bff;box-shadow:0 0 5px #007bff4d}.otp-input::-webkit-outer-spin-button,.otp-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.otp-input[type=number]{-moz-appearance:textfield}.small .otp-input{width:30px;height:30px;font-size:14px}.medium .otp-input{width:40px;height:40px;font-size:18px}.large .otp-input{width:50px;height:50px;font-size:22px}.otp-timer{text-align:center;font-size:.9rem;color:#d9534f;font-weight:700}.otp-timeout-message{text-align:center;color:#d9534f;font-size:.9rem;margin-top:.5rem}.otp-input.rectangle{border-radius:8px}.otp-input.circle{border-radius:50%}.otp-input.underscore{border:none;border-bottom:2px solid #ccc;border-radius:0;background-color:transparent}.otp-input.is-valid{border-color:#28a745;background-color:#e6ffed}.otp-input.is-invalid{border-color:#dc3545;background-color:#ffe6e6}.dark-theme .otp-input:not(.is-invalid){color:#fff;background-color:#333}.light-theme .otp-input:not(.is-invalid){color:#000}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
135
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: InputOtpComponent, decorators: [{
|
|
136
|
-
type: Component,
|
|
137
|
-
args: [{ selector: 'uxp-input-otp', template: "<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n <input *ngFor=\"let _ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); let i = index\"\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n</div>\r\n<!-- Timer -->\r\n<div *ngIf=\"rucInputData.timeLimit\" class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n</div>\r\n<!-- Timeout message -->\r\n<div *ngIf=\"rucInputData.timeLimit && timeLeft === 0\" class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n</div>\r\n\r\n", styles: [".otp-container{display:flex;gap:10px;justify-content:center}.otp-input{text-align:center;font-size:18px;border:1px solid #ccc;border-radius:4px;outline:none;transition:border-color .2s}.otp-input:focus{border-color:#007bff;box-shadow:0 0 5px #007bff4d}.otp-input::-webkit-outer-spin-button,.otp-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.otp-input[type=number]{-moz-appearance:textfield}.small .otp-input{width:30px;height:30px;font-size:14px}.medium .otp-input{width:40px;height:40px;font-size:18px}.large .otp-input{width:50px;height:50px;font-size:22px}.otp-timer{text-align:center;font-size:.9rem;color:#d9534f;font-weight:700}.otp-timeout-message{text-align:center;color:#d9534f;font-size:.9rem;margin-top:.5rem}.otp-input.rectangle{border-radius:8px}.otp-input.circle{border-radius:50%}.otp-input.underscore{border:none;border-bottom:2px solid #ccc;border-radius:0;background-color:transparent}.otp-input.is-valid{border-color:#28a745;background-color:#e6ffed}.otp-input.is-invalid{border-color:#dc3545;background-color:#ffe6e6}.dark-theme .otp-input:not(.is-invalid){color:#fff;background-color:#333}.light-theme .otp-input:not(.is-invalid){color:#000}\n"] }]
|
|
138
|
-
}], propDecorators: { rucEvent: [{
|
|
139
|
-
type: Output
|
|
140
|
-
}], customTheme: [{
|
|
141
|
-
type: Input
|
|
142
|
-
}], rucInputData: [{
|
|
143
|
-
type: Input
|
|
144
|
-
}], inputs: [{
|
|
145
|
-
type: ViewChildren,
|
|
146
|
-
args: ['otpInput']
|
|
147
|
-
}] } });
|
|
148
|
-
|
|
149
|
-
class RuclibInputOtpModule {
|
|
150
|
-
}
|
|
151
|
-
RuclibInputOtpModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
152
|
-
RuclibInputOtpModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, declarations: [InputOtpComponent], imports: [CommonModule, MatIconModule, FormsModule], exports: [InputOtpComponent] });
|
|
153
|
-
RuclibInputOtpModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, imports: [CommonModule, MatIconModule, FormsModule] });
|
|
154
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, decorators: [{
|
|
155
|
-
type: NgModule,
|
|
156
|
-
args: [{
|
|
157
|
-
imports: [CommonModule, MatIconModule, FormsModule],
|
|
158
|
-
declarations: [InputOtpComponent],
|
|
159
|
-
exports: [InputOtpComponent]
|
|
160
|
-
}]
|
|
161
|
-
}] });
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Generated bundle index. Do not edit.
|
|
165
|
-
*/
|
|
166
|
-
|
|
167
|
-
export { InputOtpComponent, RuclibInputOtpModule };
|
|
168
|
-
//# sourceMappingURL=ruc-lib-input-otp.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ruc-lib-input-otp.mjs","sources":["../../src/modal/constants.ts","../../src/lib/input-otp/input-otp.component.ts","../../src/lib/input-otp/input-otp.component.html","../../src/lib/ruclib-input-otp.module.ts","../../src/ruc-lib-input-otp.ts"],"sourcesContent":["export const BACKSPACE_KEY = \"Backspace\"","import {\r\n Component,\r\n Input,\r\n Output,\r\n EventEmitter,\r\n ViewChildren,\r\n ElementRef,\r\n QueryList,\r\n AfterViewInit,\r\n OnDestroy,\r\n OnInit,\r\n} from '@angular/core';\r\nimport { InputOtpConfig } from '../../modal/input-otp-config';\r\nimport { BACKSPACE_KEY } from '../../modal/constants';\r\n\r\n@Component({\r\n selector: 'uxp-input-otp',\r\n templateUrl: './input-otp.component.html',\r\n styleUrls: ['./input-otp.component.scss']\r\n})\r\nexport class InputOtpComponent implements OnInit, AfterViewInit, OnDestroy {\r\n readonly DEFAULT_OTP_LENGTH = 6;\r\n readonly TIME_LEFT = \"Time left\";\r\n readonly EXPIRED_MSG = \"OTP expired. Please request a new one.\"\r\n\r\n @Output() rucEvent = new EventEmitter<any>();\r\n @Input() customTheme?: string;\r\n\r\n @Input() rucInputData: InputOtpConfig = {};\r\n timeLeft = 0;\r\n timerId: any = null;\r\n\r\n @ViewChildren('otpInput') inputs!: QueryList<ElementRef<HTMLInputElement>>;\r\n\r\n otpValues: string[] = [];\r\n\r\n ngOnInit(): void {\r\n this.otpValues = Array(this.rucInputData.length || 6).fill('');\r\n if (this.rucInputData.timeLimit) {\r\n this.timeLeft = this.rucInputData.timeLimit;\r\n }\r\n\r\n // Set default for copyProtection\r\n if (this.rucInputData.copyProtection === undefined) {\r\n this.rucInputData.copyProtection = true;\r\n }\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n // Merge input config with defaults\r\n this.otpValues = Array(this.rucInputData.length || 6).fill('');\r\n if (this.rucInputData.autoFocus) {\r\n setTimeout(() => this.inputs.first?.nativeElement.focus(), 0); // Auto-focus first input\r\n }\r\n\r\n if (this.rucInputData.timeLimit) {\r\n this.timeLeft = this.rucInputData.timeLimit;\r\n this.timerId = setInterval(() => {\r\n this.timeLeft--;\r\n if (this.timeLeft <= 0) {\r\n clearInterval(this.timerId);\r\n this.disableAllInputs();\r\n this.rucEvent.emit({ eventName: 'timeout', eventOutput: null });\r\n }\r\n }, 1000);\r\n }\r\n }\r\n// Handle OTP input\r\n handleInput(event: Event, index: number): void {\r\n const input = event.target as HTMLInputElement;\r\n const value = input.value;\r\n\r\n if (this.rucInputData.integerOnly && !/^\\d*$/.test(value)) {\r\n input.value = ''; // Allow integers only\r\n this.otpValues[index] = '';\r\n return;\r\n }\r\n\r\n this.otpValues[index] = value.slice(-1); // Take last digit\r\n input.value = this.otpValues[index];\r\n\r\n // Auto-jump to next input\r\n if (value && index < (this.rucInputData.length || 6) - 1 && this.rucInputData.autoFocus) {\r\n this.inputs.toArray()[index + 1].nativeElement.focus();\r\n }\r\n\r\n // Auto-submit on complete\r\n if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n this.timerId = null;\r\n }\r\n this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });\r\n }\r\n }\r\n\r\n// Handle Keyboard navigation\r\n handleKeyDown(event: KeyboardEvent, index: number): void {\r\n const input = event.target as HTMLInputElement;\r\n\r\n if (event.key === BACKSPACE_KEY && !input.value && index > 0 && this.rucInputData.autoFocus) {\r\n this.inputs.toArray()[index - 1].nativeElement.focus();\r\n } else if (event.key === 'ArrowLeft' && index > 0) {\r\n event.preventDefault();\r\n this.inputs.toArray()[index - 1].nativeElement.focus();\r\n } else if (event.key === 'ArrowRight' && index < (this.rucInputData.length || 6) - 1) {\r\n event.preventDefault();\r\n this.inputs.toArray()[index + 1].nativeElement.focus();\r\n }\r\n }\r\n\r\n//Handle Paste Event\r\n handlePaste(event: ClipboardEvent): void {\r\n event.preventDefault();\r\n let pasteData = event.clipboardData?.getData('text');\r\n if (this.rucInputData.integerOnly) {\r\n pasteData = pasteData?.replace(/\\D/g, ''); // Extract digits only\r\n }\r\n if (!pasteData) return;\r\n\r\n const pasteLength = Math.min(pasteData.length, this.rucInputData.length || 6);\r\n for (let i = 0; i < pasteLength; i++) {\r\n this.otpValues[i] = pasteData[i];\r\n this.inputs.toArray()[i].nativeElement.value = pasteData[i];\r\n }\r\n\r\n // Focus last filled input or last input\r\n const focusIndex = pasteLength < (this.rucInputData.length || 6) ? pasteLength : (this.rucInputData.length || 6) - 1;\r\n this.inputs.toArray()[focusIndex].nativeElement.focus();\r\n\r\n // Auto-submit if complete\r\n if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n this.timerId = null;\r\n }\r\n this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });\r\n }\r\n }\r\n\r\n //Check if OTP is completed\r\n private isOtpComplete(otpArray: string[]): boolean {\r\n return otpArray.every(val => val.trim() !== '');\r\n }\r\n\r\n// Disable inputs\r\n private disableAllInputs(): void {\r\n this.inputs.forEach((inputRef) => {\r\n inputRef.nativeElement.disabled = true;\r\n });\r\n }\r\n\r\n //Clear Interval\r\n ngOnDestroy(): void {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n }\r\n }\r\n}\r\n","<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n <input *ngFor=\"let _ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); let i = index\"\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n</div>\r\n<!-- Timer -->\r\n<div *ngIf=\"rucInputData.timeLimit\" class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n</div>\r\n<!-- Timeout message -->\r\n<div *ngIf=\"rucInputData.timeLimit && timeLeft === 0\" class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n</div>\r\n\r\n","import { NgModule } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { InputOtpComponent } from './input-otp/input-otp.component';\r\n\r\n@NgModule({\r\n imports: [CommonModule, MatIconModule, FormsModule],\r\n declarations: [InputOtpComponent],\r\n exports : [InputOtpComponent]\r\n\r\n})\r\nexport class RuclibInputOtpModule {}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { EventEmitter, Component, Output, Input, ViewChildren, NgModule } from '@angular/core';
|
|
3
|
-
import * as i1 from '@angular/common';
|
|
4
|
-
import { CommonModule } from '@angular/common';
|
|
5
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
6
|
-
import * as i2 from '@angular/forms';
|
|
7
|
-
import { FormsModule } from '@angular/forms';
|
|
8
|
-
|
|
9
|
-
const BACKSPACE_KEY = "Backspace";
|
|
10
|
-
|
|
11
|
-
class InputOtpComponent {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.DEFAULT_OTP_LENGTH = 6;
|
|
14
|
-
this.TIME_LEFT = "Time left";
|
|
15
|
-
this.EXPIRED_MSG = "OTP expired. Please request a new one.";
|
|
16
|
-
this.rucEvent = new EventEmitter();
|
|
17
|
-
this.rucInputData = {};
|
|
18
|
-
this.timeLeft = 0;
|
|
19
|
-
this.timerId = null;
|
|
20
|
-
this.otpValues = [];
|
|
21
|
-
}
|
|
22
|
-
ngOnInit() {
|
|
23
|
-
this.otpValues = Array(this.rucInputData.length || 6).fill('');
|
|
24
|
-
if (this.rucInputData.timeLimit) {
|
|
25
|
-
this.timeLeft = this.rucInputData.timeLimit;
|
|
26
|
-
}
|
|
27
|
-
// Set default for copyProtection
|
|
28
|
-
if (this.rucInputData.copyProtection === undefined) {
|
|
29
|
-
this.rucInputData.copyProtection = true;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
ngAfterViewInit() {
|
|
33
|
-
// Merge input config with defaults
|
|
34
|
-
this.otpValues = Array(this.rucInputData.length || 6).fill('');
|
|
35
|
-
if (this.rucInputData.autoFocus) {
|
|
36
|
-
setTimeout(() => this.inputs.first?.nativeElement.focus(), 0); // Auto-focus first input
|
|
37
|
-
}
|
|
38
|
-
if (this.rucInputData.timeLimit) {
|
|
39
|
-
this.timeLeft = this.rucInputData.timeLimit;
|
|
40
|
-
this.timerId = setInterval(() => {
|
|
41
|
-
this.timeLeft--;
|
|
42
|
-
if (this.timeLeft <= 0) {
|
|
43
|
-
clearInterval(this.timerId);
|
|
44
|
-
this.disableAllInputs();
|
|
45
|
-
this.rucEvent.emit({ eventName: 'timeout', eventOutput: null });
|
|
46
|
-
}
|
|
47
|
-
}, 1000);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
// Handle OTP input
|
|
51
|
-
handleInput(event, index) {
|
|
52
|
-
const input = event.target;
|
|
53
|
-
const value = input.value;
|
|
54
|
-
if (this.rucInputData.integerOnly && !/^\d*$/.test(value)) {
|
|
55
|
-
input.value = ''; // Allow integers only
|
|
56
|
-
this.otpValues[index] = '';
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
this.otpValues[index] = value.slice(-1); // Take last digit
|
|
60
|
-
input.value = this.otpValues[index];
|
|
61
|
-
// Auto-jump to next input
|
|
62
|
-
if (value && index < (this.rucInputData.length || 6) - 1 && this.rucInputData.autoFocus) {
|
|
63
|
-
this.inputs.toArray()[index + 1].nativeElement.focus();
|
|
64
|
-
}
|
|
65
|
-
// Auto-submit on complete
|
|
66
|
-
if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {
|
|
67
|
-
if (this.timerId) {
|
|
68
|
-
clearInterval(this.timerId);
|
|
69
|
-
this.timerId = null;
|
|
70
|
-
}
|
|
71
|
-
this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// Handle Keyboard navigation
|
|
75
|
-
handleKeyDown(event, index) {
|
|
76
|
-
const input = event.target;
|
|
77
|
-
if (event.key === BACKSPACE_KEY && !input.value && index > 0 && this.rucInputData.autoFocus) {
|
|
78
|
-
this.inputs.toArray()[index - 1].nativeElement.focus();
|
|
79
|
-
}
|
|
80
|
-
else if (event.key === 'ArrowLeft' && index > 0) {
|
|
81
|
-
event.preventDefault();
|
|
82
|
-
this.inputs.toArray()[index - 1].nativeElement.focus();
|
|
83
|
-
}
|
|
84
|
-
else if (event.key === 'ArrowRight' && index < (this.rucInputData.length || 6) - 1) {
|
|
85
|
-
event.preventDefault();
|
|
86
|
-
this.inputs.toArray()[index + 1].nativeElement.focus();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
//Handle Paste Event
|
|
90
|
-
handlePaste(event) {
|
|
91
|
-
event.preventDefault();
|
|
92
|
-
let pasteData = event.clipboardData?.getData('text');
|
|
93
|
-
if (this.rucInputData.integerOnly) {
|
|
94
|
-
pasteData = pasteData?.replace(/\D/g, ''); // Extract digits only
|
|
95
|
-
}
|
|
96
|
-
if (!pasteData)
|
|
97
|
-
return;
|
|
98
|
-
const pasteLength = Math.min(pasteData.length, this.rucInputData.length || 6);
|
|
99
|
-
for (let i = 0; i < pasteLength; i++) {
|
|
100
|
-
this.otpValues[i] = pasteData[i];
|
|
101
|
-
this.inputs.toArray()[i].nativeElement.value = pasteData[i];
|
|
102
|
-
}
|
|
103
|
-
// Focus last filled input or last input
|
|
104
|
-
const focusIndex = pasteLength < (this.rucInputData.length || 6) ? pasteLength : (this.rucInputData.length || 6) - 1;
|
|
105
|
-
this.inputs.toArray()[focusIndex].nativeElement.focus();
|
|
106
|
-
// Auto-submit if complete
|
|
107
|
-
if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {
|
|
108
|
-
if (this.timerId) {
|
|
109
|
-
clearInterval(this.timerId);
|
|
110
|
-
this.timerId = null;
|
|
111
|
-
}
|
|
112
|
-
this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
//Check if OTP is completed
|
|
116
|
-
isOtpComplete(otpArray) {
|
|
117
|
-
return otpArray.every(val => val.trim() !== '');
|
|
118
|
-
}
|
|
119
|
-
// Disable inputs
|
|
120
|
-
disableAllInputs() {
|
|
121
|
-
this.inputs.forEach((inputRef) => {
|
|
122
|
-
inputRef.nativeElement.disabled = true;
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
//Clear Interval
|
|
126
|
-
ngOnDestroy() {
|
|
127
|
-
if (this.timerId) {
|
|
128
|
-
clearInterval(this.timerId);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
InputOtpComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: InputOtpComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
133
|
-
InputOtpComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: InputOtpComponent, selector: "uxp-input-otp", inputs: { customTheme: "customTheme", rucInputData: "rucInputData" }, outputs: { rucEvent: "rucEvent" }, viewQueries: [{ propertyName: "inputs", predicate: ["otpInput"], descendants: true }], ngImport: i0, template: "<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n <input *ngFor=\"let _ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); let i = index\"\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n</div>\r\n<!-- Timer -->\r\n<div *ngIf=\"rucInputData.timeLimit\" class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n</div>\r\n<!-- Timeout message -->\r\n<div *ngIf=\"rucInputData.timeLimit && timeLeft === 0\" class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n</div>\r\n\r\n", styles: [".otp-container{display:flex;gap:10px;justify-content:center}.otp-input{text-align:center;font-size:18px;border:1px solid #ccc;border-radius:4px;outline:none;transition:border-color .2s}.otp-input:focus{border-color:#007bff;box-shadow:0 0 5px #007bff4d}.otp-input::-webkit-outer-spin-button,.otp-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.otp-input[type=number]{-moz-appearance:textfield}.small .otp-input{width:30px;height:30px;font-size:14px}.medium .otp-input{width:40px;height:40px;font-size:18px}.large .otp-input{width:50px;height:50px;font-size:22px}.otp-timer{text-align:center;font-size:.9rem;color:#d9534f;font-weight:700}.otp-timeout-message{text-align:center;color:#d9534f;font-size:.9rem;margin-top:.5rem}.otp-input.rectangle{border-radius:8px}.otp-input.circle{border-radius:50%}.otp-input.underscore{border:none;border-bottom:2px solid #ccc;border-radius:0;background-color:transparent}.otp-input.is-valid{border-color:#28a745;background-color:#e6ffed}.otp-input.is-invalid{border-color:#dc3545;background-color:#ffe6e6}.dark-theme .otp-input:not(.is-invalid){color:#fff;background-color:#333}.light-theme .otp-input:not(.is-invalid){color:#000}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
134
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: InputOtpComponent, decorators: [{
|
|
135
|
-
type: Component,
|
|
136
|
-
args: [{ selector: 'uxp-input-otp', template: "<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n <input *ngFor=\"let _ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); let i = index\"\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n</div>\r\n<!-- Timer -->\r\n<div *ngIf=\"rucInputData.timeLimit\" class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n</div>\r\n<!-- Timeout message -->\r\n<div *ngIf=\"rucInputData.timeLimit && timeLeft === 0\" class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n</div>\r\n\r\n", styles: [".otp-container{display:flex;gap:10px;justify-content:center}.otp-input{text-align:center;font-size:18px;border:1px solid #ccc;border-radius:4px;outline:none;transition:border-color .2s}.otp-input:focus{border-color:#007bff;box-shadow:0 0 5px #007bff4d}.otp-input::-webkit-outer-spin-button,.otp-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.otp-input[type=number]{-moz-appearance:textfield}.small .otp-input{width:30px;height:30px;font-size:14px}.medium .otp-input{width:40px;height:40px;font-size:18px}.large .otp-input{width:50px;height:50px;font-size:22px}.otp-timer{text-align:center;font-size:.9rem;color:#d9534f;font-weight:700}.otp-timeout-message{text-align:center;color:#d9534f;font-size:.9rem;margin-top:.5rem}.otp-input.rectangle{border-radius:8px}.otp-input.circle{border-radius:50%}.otp-input.underscore{border:none;border-bottom:2px solid #ccc;border-radius:0;background-color:transparent}.otp-input.is-valid{border-color:#28a745;background-color:#e6ffed}.otp-input.is-invalid{border-color:#dc3545;background-color:#ffe6e6}.dark-theme .otp-input:not(.is-invalid){color:#fff;background-color:#333}.light-theme .otp-input:not(.is-invalid){color:#000}\n"] }]
|
|
137
|
-
}], propDecorators: { rucEvent: [{
|
|
138
|
-
type: Output
|
|
139
|
-
}], customTheme: [{
|
|
140
|
-
type: Input
|
|
141
|
-
}], rucInputData: [{
|
|
142
|
-
type: Input
|
|
143
|
-
}], inputs: [{
|
|
144
|
-
type: ViewChildren,
|
|
145
|
-
args: ['otpInput']
|
|
146
|
-
}] } });
|
|
147
|
-
|
|
148
|
-
class RuclibInputOtpModule {
|
|
149
|
-
}
|
|
150
|
-
RuclibInputOtpModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
151
|
-
RuclibInputOtpModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, declarations: [InputOtpComponent], imports: [CommonModule, MatIconModule, FormsModule], exports: [InputOtpComponent] });
|
|
152
|
-
RuclibInputOtpModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, imports: [CommonModule, MatIconModule, FormsModule] });
|
|
153
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: RuclibInputOtpModule, decorators: [{
|
|
154
|
-
type: NgModule,
|
|
155
|
-
args: [{
|
|
156
|
-
imports: [CommonModule, MatIconModule, FormsModule],
|
|
157
|
-
declarations: [InputOtpComponent],
|
|
158
|
-
exports: [InputOtpComponent]
|
|
159
|
-
}]
|
|
160
|
-
}] });
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Generated bundle index. Do not edit.
|
|
164
|
-
*/
|
|
165
|
-
|
|
166
|
-
export { InputOtpComponent, RuclibInputOtpModule };
|
|
167
|
-
//# sourceMappingURL=ruc-lib-input-otp.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ruc-lib-input-otp.mjs","sources":["../../src/modal/constants.ts","../../src/lib/input-otp/input-otp.component.ts","../../src/lib/input-otp/input-otp.component.html","../../src/lib/ruclib-input-otp.module.ts","../../src/ruc-lib-input-otp.ts"],"sourcesContent":["export const BACKSPACE_KEY = \"Backspace\"","import {\r\n Component,\r\n Input,\r\n Output,\r\n EventEmitter,\r\n ViewChildren,\r\n ElementRef,\r\n QueryList,\r\n AfterViewInit,\r\n OnDestroy,\r\n OnInit,\r\n} from '@angular/core';\r\nimport { InputOtpConfig } from '../../modal/input-otp-config';\r\nimport { BACKSPACE_KEY } from '../../modal/constants';\r\n\r\n@Component({\r\n selector: 'uxp-input-otp',\r\n templateUrl: './input-otp.component.html',\r\n styleUrls: ['./input-otp.component.scss']\r\n})\r\nexport class InputOtpComponent implements OnInit, AfterViewInit, OnDestroy {\r\n readonly DEFAULT_OTP_LENGTH = 6;\r\n readonly TIME_LEFT = \"Time left\";\r\n readonly EXPIRED_MSG = \"OTP expired. Please request a new one.\"\r\n\r\n @Output() rucEvent = new EventEmitter<any>();\r\n @Input() customTheme?: string;\r\n\r\n @Input() rucInputData: InputOtpConfig = {};\r\n timeLeft = 0;\r\n timerId: any = null;\r\n\r\n @ViewChildren('otpInput') inputs!: QueryList<ElementRef<HTMLInputElement>>;\r\n\r\n otpValues: string[] = [];\r\n\r\n ngOnInit(): void {\r\n this.otpValues = Array(this.rucInputData.length || 6).fill('');\r\n if (this.rucInputData.timeLimit) {\r\n this.timeLeft = this.rucInputData.timeLimit;\r\n }\r\n\r\n // Set default for copyProtection\r\n if (this.rucInputData.copyProtection === undefined) {\r\n this.rucInputData.copyProtection = true;\r\n }\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n // Merge input config with defaults\r\n this.otpValues = Array(this.rucInputData.length || 6).fill('');\r\n if (this.rucInputData.autoFocus) {\r\n setTimeout(() => this.inputs.first?.nativeElement.focus(), 0); // Auto-focus first input\r\n }\r\n\r\n if (this.rucInputData.timeLimit) {\r\n this.timeLeft = this.rucInputData.timeLimit;\r\n this.timerId = setInterval(() => {\r\n this.timeLeft--;\r\n if (this.timeLeft <= 0) {\r\n clearInterval(this.timerId);\r\n this.disableAllInputs();\r\n this.rucEvent.emit({ eventName: 'timeout', eventOutput: null });\r\n }\r\n }, 1000);\r\n }\r\n }\r\n// Handle OTP input\r\n handleInput(event: Event, index: number): void {\r\n const input = event.target as HTMLInputElement;\r\n const value = input.value;\r\n\r\n if (this.rucInputData.integerOnly && !/^\\d*$/.test(value)) {\r\n input.value = ''; // Allow integers only\r\n this.otpValues[index] = '';\r\n return;\r\n }\r\n\r\n this.otpValues[index] = value.slice(-1); // Take last digit\r\n input.value = this.otpValues[index];\r\n\r\n // Auto-jump to next input\r\n if (value && index < (this.rucInputData.length || 6) - 1 && this.rucInputData.autoFocus) {\r\n this.inputs.toArray()[index + 1].nativeElement.focus();\r\n }\r\n\r\n // Auto-submit on complete\r\n if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n this.timerId = null;\r\n }\r\n this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });\r\n }\r\n }\r\n\r\n// Handle Keyboard navigation\r\n handleKeyDown(event: KeyboardEvent, index: number): void {\r\n const input = event.target as HTMLInputElement;\r\n\r\n if (event.key === BACKSPACE_KEY && !input.value && index > 0 && this.rucInputData.autoFocus) {\r\n this.inputs.toArray()[index - 1].nativeElement.focus();\r\n } else if (event.key === 'ArrowLeft' && index > 0) {\r\n event.preventDefault();\r\n this.inputs.toArray()[index - 1].nativeElement.focus();\r\n } else if (event.key === 'ArrowRight' && index < (this.rucInputData.length || 6) - 1) {\r\n event.preventDefault();\r\n this.inputs.toArray()[index + 1].nativeElement.focus();\r\n }\r\n }\r\n\r\n//Handle Paste Event\r\n handlePaste(event: ClipboardEvent): void {\r\n event.preventDefault();\r\n let pasteData = event.clipboardData?.getData('text');\r\n if (this.rucInputData.integerOnly) {\r\n pasteData = pasteData?.replace(/\\D/g, ''); // Extract digits only\r\n }\r\n if (!pasteData) return;\r\n\r\n const pasteLength = Math.min(pasteData.length, this.rucInputData.length || 6);\r\n for (let i = 0; i < pasteLength; i++) {\r\n this.otpValues[i] = pasteData[i];\r\n this.inputs.toArray()[i].nativeElement.value = pasteData[i];\r\n }\r\n\r\n // Focus last filled input or last input\r\n const focusIndex = pasteLength < (this.rucInputData.length || 6) ? pasteLength : (this.rucInputData.length || 6) - 1;\r\n this.inputs.toArray()[focusIndex].nativeElement.focus();\r\n\r\n // Auto-submit if complete\r\n if (this.rucInputData.autoSubmit && this.isOtpComplete(this.otpValues)) {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n this.timerId = null;\r\n }\r\n this.rucEvent.emit({ eventName: 'completed', eventOutput: this.otpValues.join('') });\r\n }\r\n }\r\n\r\n //Check if OTP is completed\r\n private isOtpComplete(otpArray: string[]): boolean {\r\n return otpArray.every(val => val.trim() !== '');\r\n }\r\n\r\n// Disable inputs\r\n private disableAllInputs(): void {\r\n this.inputs.forEach((inputRef) => {\r\n inputRef.nativeElement.disabled = true;\r\n });\r\n }\r\n\r\n //Clear Interval\r\n ngOnDestroy(): void {\r\n if (this.timerId) {\r\n clearInterval(this.timerId);\r\n }\r\n }\r\n}\r\n","<div class=\"{{customTheme}} otp-container\" [ngClass]=\"rucInputData.size || 'medium'\" (paste)=\"handlePaste($event)\">\r\n <input *ngFor=\"let _ of [].constructor(rucInputData.length || DEFAULT_OTP_LENGTH); let i = index\"\r\n #otpInput\r\n [type]=\"rucInputData.mask ? 'password' : 'text'\"\r\n [ngClass]=\"[\r\n 'otp-input',\r\n rucInputData.templateType || 'rectangle',\r\n rucInputData.validationState === 'valid' ? 'is-valid' : '',\r\n rucInputData.validationState === 'invalid' ? 'is-invalid' : ''\r\n ]\"\r\n maxlength=\"1\"\r\n [(ngModel)]=\"otpValues[i]\"\r\n (input)=\"handleInput($event, i)\"\r\n (copy)=\"rucInputData.copyProtection && $event.preventDefault()\"\r\n (paste)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (contextmenu)=\"rucInputData.copyProtection && $event.preventDefault()\" \r\n (keydown)=\"handleKeyDown($event, i)\"\r\n [attr.inputmode]=\"rucInputData.integerOnly ? 'numeric' : 'text'\"\r\n [pattern]=\"rucInputData.integerOnly ? '[0-9]*' : '.*'\"\r\n autocomplete=\"one-time-code\">\r\n</div>\r\n<!-- Timer -->\r\n<div *ngIf=\"rucInputData.timeLimit\" class=\"otp-timer\">\r\n {{TIME_LEFT}}: {{ timeLeft }}s\r\n</div>\r\n<!-- Timeout message -->\r\n<div *ngIf=\"rucInputData.timeLimit && timeLeft === 0\" class=\"otp-timeout-message\">\r\n {{EXPIRED_MSG}}\r\n</div>\r\n\r\n","import { NgModule } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { InputOtpComponent } from './input-otp/input-otp.component';\r\n\r\n@NgModule({\r\n imports: [CommonModule, MatIconModule, FormsModule],\r\n declarations: [InputOtpComponent],\r\n exports : [InputOtpComponent]\r\n\r\n})\r\nexport class RuclibInputOtpModule {}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { EventEmitter, ElementRef, QueryList, AfterViewInit, OnDestroy, OnInit } from '@angular/core';
|
|
2
|
-
import { InputOtpConfig } from '../../modal/input-otp-config';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export declare class InputOtpComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
5
|
-
readonly DEFAULT_OTP_LENGTH = 6;
|
|
6
|
-
readonly TIME_LEFT = "Time left";
|
|
7
|
-
readonly EXPIRED_MSG = "OTP expired. Please request a new one.";
|
|
8
|
-
rucEvent: EventEmitter<any>;
|
|
9
|
-
customTheme?: string;
|
|
10
|
-
rucInputData: InputOtpConfig;
|
|
11
|
-
timeLeft: number;
|
|
12
|
-
timerId: any;
|
|
13
|
-
inputs: QueryList<ElementRef<HTMLInputElement>>;
|
|
14
|
-
otpValues: string[];
|
|
15
|
-
ngOnInit(): void;
|
|
16
|
-
ngAfterViewInit(): void;
|
|
17
|
-
handleInput(event: Event, index: number): void;
|
|
18
|
-
handleKeyDown(event: KeyboardEvent, index: number): void;
|
|
19
|
-
handlePaste(event: ClipboardEvent): void;
|
|
20
|
-
private isOtpComplete;
|
|
21
|
-
private disableAllInputs;
|
|
22
|
-
ngOnDestroy(): void;
|
|
23
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<InputOtpComponent, never>;
|
|
24
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<InputOtpComponent, "uxp-input-otp", never, { "customTheme": "customTheme"; "rucInputData": "rucInputData"; }, { "rucEvent": "rucEvent"; }, never, never, false, never>;
|
|
25
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import * as i0 from "@angular/core";
|
|
2
|
-
import * as i1 from "./input-otp/input-otp.component";
|
|
3
|
-
import * as i2 from "@angular/common";
|
|
4
|
-
import * as i3 from "@angular/material/icon";
|
|
5
|
-
import * as i4 from "@angular/forms";
|
|
6
|
-
export declare class RuclibInputOtpModule {
|
|
7
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<RuclibInputOtpModule, never>;
|
|
8
|
-
static ɵmod: i0.ɵɵNgModuleDeclaration<RuclibInputOtpModule, [typeof i1.InputOtpComponent], [typeof i2.CommonModule, typeof i3.MatIconModule, typeof i4.FormsModule], [typeof i1.InputOtpComponent]>;
|
|
9
|
-
static ɵinj: i0.ɵɵInjectorDeclaration<RuclibInputOtpModule>;
|
|
10
|
-
}
|
package/modal/constants.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const BACKSPACE_KEY = "Backspace";
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export interface InputOtpConfig {
|
|
2
|
-
/** Number of OTP digits */
|
|
3
|
-
length?: number;
|
|
4
|
-
/** Mask input as password */
|
|
5
|
-
mask?: boolean;
|
|
6
|
-
/** Sizes: small, medium, large */
|
|
7
|
-
size?: 'small' | 'medium' | 'large';
|
|
8
|
-
/** Only allow integers 0-9 */
|
|
9
|
-
integerOnly?: boolean;
|
|
10
|
-
/** Autofocus and auto-jump */
|
|
11
|
-
autoFocus?: boolean;
|
|
12
|
-
autoSubmit?: boolean;
|
|
13
|
-
timeLimit?: number;
|
|
14
|
-
copyProtection?: boolean;
|
|
15
|
-
templateType?: 'rectangle' | 'circle' | 'underscore';
|
|
16
|
-
/** Validation state for visual feedback */
|
|
17
|
-
validationState?: 'valid' | 'invalid' | undefined;
|
|
18
|
-
}
|