@adminforth/two-factors-auth 1.9.0 → 1.9.2

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/build.log CHANGED
@@ -11,5 +11,5 @@ custom/package-lock.json
11
11
  custom/package.json
12
12
  custom/tsconfig.json
13
13
 
14
- sent 31,846 bytes received 134 bytes 63,960.00 bytes/sec
15
- total size is 31,348 speedup is 0.98
14
+ sent 34,648 bytes received 134 bytes 69,564.00 bytes/sec
15
+ total size is 34,157 speedup is 0.98
@@ -92,10 +92,17 @@
92
92
  onMounted(async () => {
93
93
  await nextTick();
94
94
  tagOtpInputs();
95
+ document.addEventListener('focusin', handleGlobalFocusIn, true);
96
+ focusFirstAvailableOtpInput();
97
+ const rootEl = otpRoot.value;
98
+ rootEl && rootEl.addEventListener('focusout', handleFocusOut, true);
95
99
  });
96
100
 
97
101
  onBeforeUnmount(() => {
98
102
  window.removeEventListener('paste', handlePaste);
103
+ document.removeEventListener('focusin', handleGlobalFocusIn, true);
104
+ const rootEl = otpRoot.value;
105
+ rootEl && rootEl.removeEventListener('focusout', handleFocusOut, true);
99
106
  });
100
107
 
101
108
  async function sendCode (value) {
@@ -131,6 +138,42 @@
131
138
  code.value?.fillInput(pastedText);
132
139
  }
133
140
  }
141
+
142
+ function getOtpInputs() {
143
+ const root = otpRoot.value;
144
+ if (!root) return [];
145
+ return Array.from(root.querySelectorAll('input.otp-input'));
146
+ }
147
+
148
+ function focusFirstAvailableOtpInput() {
149
+ const inputs = getOtpInputs();
150
+ if (!inputs.length) return;
151
+ const firstEmpty = inputs.find((i) => !i.value);
152
+ (firstEmpty || inputs[0]).focus();
153
+ }
154
+
155
+ function handleGlobalFocusIn(event) {
156
+ const inputs = getOtpInputs();
157
+ if (!inputs.length) return;
158
+ const target = event.target;
159
+ if (!target) return;
160
+ if (!inputs.includes(target)) {
161
+ requestAnimationFrame(() => {
162
+ focusFirstAvailableOtpInput();
163
+ });
164
+ }
165
+ }
166
+
167
+ function handleFocusOut() {
168
+ requestAnimationFrame(() => {
169
+ const inputs = getOtpInputs();
170
+ if (!inputs.length) return;
171
+ const active = document.activeElement;
172
+ if (!active || !inputs.includes(active)) {
173
+ focusFirstAvailableOtpInput();
174
+ }
175
+ });
176
+ }
134
177
  </script>
135
178
 
136
179
  <style scoped lang='scss'>
@@ -85,13 +85,14 @@ const { t } = useI18n();
85
85
 
86
86
  const code = ref(null);
87
87
  const codeError = ref(null);
88
+ const bindValue = ref('');
88
89
  const handleOnComplete = (value) => {
89
90
  sendCode(value);
90
91
  };
91
92
 
92
93
  const router = useRouter();
93
94
  const inProgress = ref(false);
94
- const otpRoot = ref(null);
95
+ const otpRoot = ref<HTMLElement | null>(null);
95
96
 
96
97
  const coreStore = useCoreStore();
97
98
  const user = useUserStore();
@@ -154,12 +155,19 @@ onMounted(async () => {
154
155
  }
155
156
 
156
157
  window.addEventListener('paste', handlePaste);
158
+ document.addEventListener('focusin', handleGlobalFocusIn, true);
157
159
  await nextTick();
158
160
  tagOtpInputs();
161
+ focusFirstAvailableOtpInput();
162
+ const rootEl = otpRoot.value;
163
+ rootEl && rootEl.addEventListener('focusout', handleFocusOut, true);
159
164
  });
160
165
 
161
166
  onBeforeUnmount(() => {
162
167
  window.removeEventListener('paste', handlePaste);
168
+ document.removeEventListener('focusin', handleGlobalFocusIn, true);
169
+ const rootEl = otpRoot.value;
170
+ rootEl && rootEl.removeEventListener('focusout', handleFocusOut, true);
163
171
  });
164
172
 
165
173
  function tagOtpInputs() {
@@ -175,6 +183,42 @@ function tagOtpInputs() {
175
183
  });
176
184
  }
177
185
 
186
+ function getOtpInputs(): HTMLInputElement[] {
187
+ const root = otpRoot.value;
188
+ if (!root) return [];
189
+ return Array.from(root.querySelectorAll('input.otp-input')) as HTMLInputElement[];
190
+ }
191
+
192
+ function focusFirstAvailableOtpInput(): void {
193
+ const inputs = getOtpInputs();
194
+ if (!inputs.length) return;
195
+ const firstEmpty = inputs.find((i) => !i.value);
196
+ (firstEmpty || inputs[0]).focus();
197
+ }
198
+
199
+ function handleGlobalFocusIn(event: FocusEvent): void {
200
+ const inputs = getOtpInputs();
201
+ if (!inputs.length) return;
202
+ const target = event.target as HTMLElement | null;
203
+ if (!target) return;
204
+ if (!inputs.includes(target as HTMLInputElement)) {
205
+ requestAnimationFrame(() => {
206
+ focusFirstAvailableOtpInput();
207
+ });
208
+ }
209
+ }
210
+
211
+ function handleFocusOut(): void {
212
+ requestAnimationFrame(() => {
213
+ const inputs = getOtpInputs();
214
+ if (!inputs.length) return;
215
+ const active = document.activeElement as HTMLElement | null;
216
+ if (!active || !inputs.includes(active as HTMLInputElement)) {
217
+ focusFirstAvailableOtpInput();
218
+ }
219
+ });
220
+ }
221
+
178
222
  async function sendCode (value) {
179
223
  inProgress.value = true;
180
224
 
@@ -92,10 +92,17 @@
92
92
  onMounted(async () => {
93
93
  await nextTick();
94
94
  tagOtpInputs();
95
+ document.addEventListener('focusin', handleGlobalFocusIn, true);
96
+ focusFirstAvailableOtpInput();
97
+ const rootEl = otpRoot.value;
98
+ rootEl && rootEl.addEventListener('focusout', handleFocusOut, true);
95
99
  });
96
100
 
97
101
  onBeforeUnmount(() => {
98
102
  window.removeEventListener('paste', handlePaste);
103
+ document.removeEventListener('focusin', handleGlobalFocusIn, true);
104
+ const rootEl = otpRoot.value;
105
+ rootEl && rootEl.removeEventListener('focusout', handleFocusOut, true);
99
106
  });
100
107
 
101
108
  async function sendCode (value) {
@@ -131,6 +138,42 @@
131
138
  code.value?.fillInput(pastedText);
132
139
  }
133
140
  }
141
+
142
+ function getOtpInputs() {
143
+ const root = otpRoot.value;
144
+ if (!root) return [];
145
+ return Array.from(root.querySelectorAll('input.otp-input'));
146
+ }
147
+
148
+ function focusFirstAvailableOtpInput() {
149
+ const inputs = getOtpInputs();
150
+ if (!inputs.length) return;
151
+ const firstEmpty = inputs.find((i) => !i.value);
152
+ (firstEmpty || inputs[0]).focus();
153
+ }
154
+
155
+ function handleGlobalFocusIn(event) {
156
+ const inputs = getOtpInputs();
157
+ if (!inputs.length) return;
158
+ const target = event.target;
159
+ if (!target) return;
160
+ if (!inputs.includes(target)) {
161
+ requestAnimationFrame(() => {
162
+ focusFirstAvailableOtpInput();
163
+ });
164
+ }
165
+ }
166
+
167
+ function handleFocusOut() {
168
+ requestAnimationFrame(() => {
169
+ const inputs = getOtpInputs();
170
+ if (!inputs.length) return;
171
+ const active = document.activeElement;
172
+ if (!active || !inputs.includes(active)) {
173
+ focusFirstAvailableOtpInput();
174
+ }
175
+ });
176
+ }
134
177
  </script>
135
178
 
136
179
  <style scoped lang='scss'>
@@ -85,13 +85,14 @@ const { t } = useI18n();
85
85
 
86
86
  const code = ref(null);
87
87
  const codeError = ref(null);
88
+ const bindValue = ref('');
88
89
  const handleOnComplete = (value) => {
89
90
  sendCode(value);
90
91
  };
91
92
 
92
93
  const router = useRouter();
93
94
  const inProgress = ref(false);
94
- const otpRoot = ref(null);
95
+ const otpRoot = ref<HTMLElement | null>(null);
95
96
 
96
97
  const coreStore = useCoreStore();
97
98
  const user = useUserStore();
@@ -154,12 +155,19 @@ onMounted(async () => {
154
155
  }
155
156
 
156
157
  window.addEventListener('paste', handlePaste);
158
+ document.addEventListener('focusin', handleGlobalFocusIn, true);
157
159
  await nextTick();
158
160
  tagOtpInputs();
161
+ focusFirstAvailableOtpInput();
162
+ const rootEl = otpRoot.value;
163
+ rootEl && rootEl.addEventListener('focusout', handleFocusOut, true);
159
164
  });
160
165
 
161
166
  onBeforeUnmount(() => {
162
167
  window.removeEventListener('paste', handlePaste);
168
+ document.removeEventListener('focusin', handleGlobalFocusIn, true);
169
+ const rootEl = otpRoot.value;
170
+ rootEl && rootEl.removeEventListener('focusout', handleFocusOut, true);
163
171
  });
164
172
 
165
173
  function tagOtpInputs() {
@@ -175,6 +183,42 @@ function tagOtpInputs() {
175
183
  });
176
184
  }
177
185
 
186
+ function getOtpInputs(): HTMLInputElement[] {
187
+ const root = otpRoot.value;
188
+ if (!root) return [];
189
+ return Array.from(root.querySelectorAll('input.otp-input')) as HTMLInputElement[];
190
+ }
191
+
192
+ function focusFirstAvailableOtpInput(): void {
193
+ const inputs = getOtpInputs();
194
+ if (!inputs.length) return;
195
+ const firstEmpty = inputs.find((i) => !i.value);
196
+ (firstEmpty || inputs[0]).focus();
197
+ }
198
+
199
+ function handleGlobalFocusIn(event: FocusEvent): void {
200
+ const inputs = getOtpInputs();
201
+ if (!inputs.length) return;
202
+ const target = event.target as HTMLElement | null;
203
+ if (!target) return;
204
+ if (!inputs.includes(target as HTMLInputElement)) {
205
+ requestAnimationFrame(() => {
206
+ focusFirstAvailableOtpInput();
207
+ });
208
+ }
209
+ }
210
+
211
+ function handleFocusOut(): void {
212
+ requestAnimationFrame(() => {
213
+ const inputs = getOtpInputs();
214
+ if (!inputs.length) return;
215
+ const active = document.activeElement as HTMLElement | null;
216
+ if (!active || !inputs.includes(active as HTMLInputElement)) {
217
+ focusFirstAvailableOtpInput();
218
+ }
219
+ });
220
+ }
221
+
178
222
  async function sendCode (value) {
179
223
  inProgress.value = true;
180
224
 
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@adminforth/two-factors-auth",
3
- "version": "1.9.0",
3
+ "version": "1.9.2",
4
4
  "description": "AdminForth plugin for two factors authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
7
10
  "homepage": "https://adminforth.dev/docs/tutorial/Plugins/TwoFactorsAuth/",
8
11
  "repository": {
9
12
  "type": "git",