@ruc-lib/input-otp 2.0.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 ADDED
@@ -0,0 +1,107 @@
1
+ # ruclib-carousel
2
+
3
+ This library provides a flexible and customizable Input OTP component for your Angular applications. Users can integrate the Input OTP component using Angular services or selectors with ease. Below are the features, usage instructions, and integration details
4
+
5
+ ## RUC Library Installation Guide
6
+
7
+ Users can easily install the RUC (Ruxptest Library) from npm. Additionally, they can also choose to install individual components based on their requirements.
8
+ Install RUC Library.
9
+
10
+ To install the entire RUC library:
11
+
12
+ `npm install @uxpractice/ruc-lib`
13
+
14
+ ## Install Individual Components
15
+ If users only need the carousel component, they can install it separately:
16
+
17
+ `npm install @ruc-lib/input-otp`
18
+
19
+ After installing the the required package successfully, we have to import the CSS in our style.scss file in following way.
20
+
21
+ `@import "../../../node_modules/primeng/resources/themes/lara-light-indigo/theme.css";`
22
+ `@import "../../../node_modules/primeng/resources/primeng.min.css";`
23
+
24
+ here path of the scss file is subject to change as per choice of the installation
25
+
26
+ for library
27
+ `@import "../node_modules/primeng/resources/themes/lara-light-indigo/theme.css";`
28
+ `@import "../node_modules/primeng/resources/primeng.min.css";`
29
+
30
+ for seperate package
31
+ `@import "../node_modules/primeng/resources/themes/lara-light-indigo/theme.css";`
32
+ `@import "../node_modules/primeng/resources/primeng.min.css";`
33
+
34
+ # import required modules
35
+
36
+ Import ContextModule into app.module.ts file.
37
+
38
+ for library
39
+
40
+ `import { RuclibInputOtpModule } from '@uxpractice/ruc-lib/carousel'`
41
+
42
+ for seperate package
43
+
44
+ `import { RuclibInputOtpModule } from '@ruc-lib/carousel'`
45
+
46
+ # Features
47
+ User can have Basic Input
48
+ User can have Masking support
49
+ User can have Sizing functionality
50
+ User can Integer only support
51
+ User can have Custom OTP length
52
+ User can have Auto focus and auto jump
53
+ User can have Paste support
54
+ User can have Auto Submit on Complete
55
+ User can have Input Timeout/Expiry
56
+ User should enter the Otp input within the specified time limit (optional)
57
+ User can have custom templates/ Layouts (circle, rectangle and underscore lines ) for the Input OTP
58
+ User can validate input otp validation if the OTP is correct or not
59
+ User can have Copy and Paste Protection
60
+
61
+ # Use component selector
62
+
63
+ ```
64
+ <uxp-input-otp (rucEvent)="passEvent($event)" [rucInputData]="inputObjectDataInputOtp"></uxp-input-otp>
65
+
66
+
67
+ ```
68
+
69
+ # Input and Output
70
+
71
+ # Inputs
72
+ rucInputData -> It is the configuration input to configure the Input OTP component
73
+
74
+ customTheme -> It is the name of the theme.
75
+ # Output
76
+
77
+ # rucInputData (sample object)
78
+
79
+ # Detail definition of the each property can be found in type definition file.
80
+
81
+ ```
82
+ const defaultConfig = {
83
+ length: 6,
84
+ autoFocus: true,
85
+ integerOnly: true,
86
+ autoSubmit: true,
87
+ mask: false,
88
+ size: 'medium', // 'medium' as literal
89
+ copyProtection: true,
90
+ templateType: 'rectangle', // as literal
91
+ validationState: undefined,
92
+ timeLimit: undefined,
93
+ };
94
+
95
+ export const Default: Story = {
96
+ args: {
97
+ rucInputData: { ...defaultConfig },
98
+ },
99
+ };
100
+ ```
101
+
102
+ # Contribution
103
+ Contributions are welcome! Feel free to open issues or pull requests for any enhancements or fixes.
104
+
105
+ # Acknowledgements
106
+ Thank you for choosing the Input OTP Component Library. If you have any feedback or suggestions, please let us know!
107
+
@@ -0,0 +1,4 @@
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
@@ -0,0 +1,142 @@
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;color:inherit}.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}\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;color:inherit}.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}\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=
@@ -0,0 +1,20 @@
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=
@@ -0,0 +1,2 @@
1
+ export const BACKSPACE_KEY = "Backspace";
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGFsL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsV0FBVyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IEJBQ0tTUEFDRV9LRVkgPSBcIkJhY2tzcGFjZVwiIl19
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQtb3RwLWNvbmZpZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tb2RhbC9pbnB1dC1vdHAtY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgaW50ZXJmYWNlIElucHV0T3RwQ29uZmlnIHtcclxuICAvKiogTnVtYmVyIG9mIE9UUCBkaWdpdHMgKi9cclxuICBsZW5ndGg/OiBudW1iZXI7XHJcbiAgLyoqIE1hc2sgaW5wdXQgYXMgcGFzc3dvcmQgKi9cclxuICBtYXNrPzogYm9vbGVhbjtcclxuICAvKiogU2l6ZXM6IHNtYWxsLCBtZWRpdW0sIGxhcmdlICovXHJcbiAgc2l6ZT86ICdzbWFsbCcgfCAnbWVkaXVtJyB8ICdsYXJnZSc7XHJcbiAgLyoqIE9ubHkgYWxsb3cgaW50ZWdlcnMgMC05ICovXHJcbiAgaW50ZWdlck9ubHk/OiBib29sZWFuO1xyXG4gIC8qKiBBdXRvZm9jdXMgYW5kIGF1dG8tanVtcCAqL1xyXG4gIGF1dG9Gb2N1cz86IGJvb2xlYW47XHJcbiAgYXV0b1N1Ym1pdD86IGJvb2xlYW47XHJcbiAgdGltZUxpbWl0PzogbnVtYmVyOyAvLyBPcHRpb25hbCB0aW1lb3V0IGluIHNlY29uZHNcclxuICAvL2NvcHkgYW5kIHBhc3RlIHByb3RlY3Rpb25cclxuICBjb3B5UHJvdGVjdGlvbj8gOiBib29sZWFuXHJcbiAgLy90ZW1wbGF0ZSBzdHlsZVxyXG4gIHRlbXBsYXRlVHlwZT86ICdyZWN0YW5nbGUnIHwgJ2NpcmNsZScgfCAndW5kZXJzY29yZSc7XHJcbiAgLyoqIFZhbGlkYXRpb24gc3RhdGUgZm9yIHZpc3VhbCBmZWVkYmFjayAqL1xyXG52YWxpZGF0aW9uU3RhdGU/OiAndmFsaWQnIHwgJ2ludmFsaWQnIHwgdW5kZWZpbmVkO1xyXG4vKiogT3B0aW9uYWwgc2VwYXJhdG9yIHRvIGJlIGFkZGVkIGJldHdlZW4gT1RQIGRpZ2l0cyBpbiB0aGUgb3V0cHV0ICovXHJcbiAgfSJdfQ==
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVjLWxpYi1pbnB1dC1vdHAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVjLWxpYi1pbnB1dC1vdHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLFNBQVMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9pbmRleCc7XG4iXX0=
@@ -0,0 +1,168 @@
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;color:inherit}.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}\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;color:inherit}.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}\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
@@ -0,0 +1 @@
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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"}
@@ -0,0 +1,167 @@
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;color:inherit}.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}\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;color:inherit}.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}\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
@@ -0,0 +1 @@
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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"}
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './lib/ruclib-input-otp.module';
2
+ export * from './lib/input-otp/input-otp.component';
3
+ export * from './modal/input-otp-config';
@@ -0,0 +1,25 @@
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
+ }
@@ -0,0 +1,10 @@
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
+ }
@@ -0,0 +1 @@
1
+ export declare const BACKSPACE_KEY = "Backspace";
@@ -0,0 +1,18 @@
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
+ }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@ruc-lib/input-otp",
3
+ "version": "2.0.0",
4
+ "license": "MIT",
5
+ "peerDependencies": {
6
+ "@angular/common": "^17.0.0 || ^16.0.0 || ^15.0.0",
7
+ "@angular/core": "^17.0.0 || ^16.0.0 || ^15.0.0",
8
+ "@angular/material": "^15.2.9 || ^14.0.0 || ^13.0.0"
9
+ },
10
+ "dependencies": {
11
+ "tslib": "^2.3.0"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "sideEffects": false,
17
+ "module": "fesm2015/ruc-lib-input-otp.mjs",
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",
22
+ "typings": "index.d.ts",
23
+ "exports": {
24
+ "./package.json": {
25
+ "default": "./package.json"
26
+ },
27
+ ".": {
28
+ "types": "./index.d.ts",
29
+ "esm2020": "./esm2020/ruc-lib-input-otp.mjs",
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"
34
+ }
35
+ }
36
+ }