@sowell/quasar-app-extension-auth 1.11.0 → 1.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sowell/quasar-app-extension-auth",
3
- "version": "1.11.0",
3
+ "version": "1.11.2",
4
4
  "description": "A Quasar app extension to manage Authentication",
5
5
  "main": "src/index.js",
6
6
  "repository": "https://github.com/sowell-ai/quasar.extension.auth",
@@ -11,7 +11,7 @@
11
11
  alt="Background logo"
12
12
  />
13
13
  </div>
14
- <div class="row justify-between items-center full-width q-px-lg q-pt-lg top-bar">
14
+ <div class="row justify-between items-center full-width q-px-lg top-bar">
15
15
  <div
16
16
  class="row items-center back-link"
17
17
  data-testid="restricted-back-btn"
@@ -62,7 +62,7 @@
62
62
 
63
63
  <div
64
64
  v-else
65
- class="row justify-center full-height q-pl-sm q-pr-sm"
65
+ class="row justify-center full-height q-pl-sm q-pr-sm send-email-form"
66
66
  style="background: #f4f5f6"
67
67
  data-testid="ask-password-change-form"
68
68
  >
@@ -107,6 +107,9 @@
107
107
  <q-input
108
108
  data-testid="email-input"
109
109
  v-model="email"
110
+ type="email"
111
+ autocapitalize="off"
112
+ autocorrect="off"
110
113
  dense
111
114
  borderless
112
115
  bg-color="white"
@@ -119,7 +122,7 @@
119
122
  </q-input>
120
123
  </div>
121
124
  </q-card-section>
122
- <q-space class="mobile" />
125
+ <q-space v-if="!keyboardOpen" class="mobile" />
123
126
  <q-card-actions class="q-ml-lg q-mr-lg q-mb-lg row justify-center">
124
127
  <q-btn
125
128
  data-testid="submit-btn"
@@ -145,6 +148,7 @@
145
148
  import { computed, defineComponent, ref } from "vue"
146
149
  import { useI18n } from "vue-i18n"
147
150
  import prompts from "app/quasar.extensions.json"
151
+ import { useKeyboardOpen } from "../../composables/useKeyboardOpen"
148
152
  import {
149
153
  ionMailOutline,
150
154
  ionPaperPlaneOutline,
@@ -179,6 +183,7 @@ export default defineComponent({
179
183
  "@sowell/auth": { USE_SSO },
180
184
  } = prompts
181
185
  const email = ref("")
186
+ const { keyboardOpen } = useKeyboardOpen()
182
187
  const sendEmail = () => {
183
188
  emit("resetPassword", email.value)
184
189
  }
@@ -200,6 +205,7 @@ export default defineComponent({
200
205
 
201
206
  return {
202
207
  email,
208
+ keyboardOpen,
203
209
  sendEmail,
204
210
  emit,
205
211
  USE_SSO,
@@ -247,9 +253,18 @@ export default defineComponent({
247
253
  max-height: 100vh;
248
254
  }
249
255
 
256
+ /* Ce composant s'affiche dans un q-dialog. Sur iOS, Quasar (q-ios-padding)
257
+ décale déjà .q-dialog__inner sous la barre d'état : on ne lit donc PAS
258
+ env(), sinon le décalage serait doublé. --safe-area-inset-top n'est
259
+ injectée que par Capacitor SystemBars sur Android (edge-to-edge, 15+). */
250
260
  .top-bar {
251
261
  z-index: 1;
252
262
  max-width: 430px;
263
+ padding-top: calc(24px + var(--safe-area-inset-top, 0px));
264
+ }
265
+
266
+ .send-email-form {
267
+ padding-top: var(--safe-area-inset-top, 0px);
253
268
  }
254
269
 
255
270
  .back-link {
@@ -8,7 +8,7 @@
8
8
  class="background-logo"
9
9
  alt="Background logo" />
10
10
  </div>
11
- <div class="row justify-between items-center full-width q-px-lg q-pt-lg top-bar">
11
+ <div class="row justify-between items-center full-width q-px-lg top-bar">
12
12
  <div
13
13
  class="row items-center back-link"
14
14
  data-testid="back-btn"
@@ -424,6 +424,11 @@ export default defineComponent({
424
424
  .top-bar {
425
425
  z-index: 1;
426
426
  max-width: 430px;
427
+ /* 24px = ancien q-pt-lg. Sur iOS (viewport-fit=cover), la page n'a pas de
428
+ q-header : le padding iOS de Quasar ne s'applique pas, on ajoute donc la
429
+ safe-area ici. --safe-area-inset-top est injectée par SystemBars sur
430
+ Android ; env() vaut 0 sur le web. */
431
+ padding-top: calc(24px + var(--safe-area-inset-top, env(safe-area-inset-top, 0px)));
427
432
  }
428
433
 
429
434
  .back-link {
@@ -8,7 +8,7 @@
8
8
  class="background-logo"
9
9
  alt="Background logo" />
10
10
  </div>
11
- <div class="row justify-between items-center full-width q-px-lg q-pt-lg top-bar">
11
+ <div class="row justify-between items-center full-width q-px-lg top-bar">
12
12
  <div
13
13
  class="row items-center back-link"
14
14
  data-testid="back-btn"
@@ -317,6 +317,11 @@ export default defineComponent({
317
317
  .top-bar {
318
318
  z-index: 1;
319
319
  max-width: 430px;
320
+ /* 24px = ancien q-pt-lg. Sur iOS (viewport-fit=cover), la page n'a pas de
321
+ q-header : le padding iOS de Quasar ne s'applique pas, on ajoute donc la
322
+ safe-area ici. --safe-area-inset-top est injectée par SystemBars sur
323
+ Android ; env() vaut 0 sur le web. */
324
+ padding-top: calc(24px + var(--safe-area-inset-top, env(safe-area-inset-top, 0px)));
320
325
  }
321
326
 
322
327
  .back-link {
@@ -0,0 +1,55 @@
1
+ import { ref, onMounted, onBeforeUnmount } from "vue"
2
+
3
+ // Ecart minimal (px CSS) entre la fenetre de mise en page et la zone visible
4
+ // pour conclure qu'un clavier virtuel est ouvert. Les barres d'URL ou de
5
+ // navigation qui se replient restent largement en dessous.
6
+ export const KEYBOARD_GAP_THRESHOLD = 150
7
+
8
+ interface ViewportHost {
9
+ innerHeight: number
10
+ visualViewport?: {
11
+ height: number
12
+ addEventListener: (type: "resize", listener: () => void) => void
13
+ removeEventListener: (type: "resize", listener: () => void) => void
14
+ } | null
15
+ }
16
+
17
+ // Android 15+ edge-to-edge (WebView >= 140) : le clavier ne reduit que
18
+ // visualViewport, innerHeight reste inchange. Sur iOS (Keyboard.resize native)
19
+ // ou Android classique la WebView entiere retrecit : l'ecart reste nul et on
20
+ // ne detecte rien, la mise en page suit deja le clavier.
21
+ export const isKeyboardOpen = (host: ViewportHost): boolean => {
22
+ const viewport = host.visualViewport
23
+ if (!viewport) return false
24
+ return host.innerHeight - viewport.height > KEYBOARD_GAP_THRESHOLD
25
+ }
26
+
27
+ // Appelle `onChange` a chaque variation de l'etat (et une fois a l'initialisation),
28
+ // rend la fonction de nettoyage. Sans visualViewport : etat false, rien a ecouter.
29
+ export const observeKeyboard = (
30
+ host: ViewportHost,
31
+ onChange: (open: boolean) => void
32
+ ): (() => void) => {
33
+ const update = () => onChange(isKeyboardOpen(host))
34
+ update()
35
+ const viewport = host.visualViewport
36
+ if (!viewport) return () => undefined
37
+ viewport.addEventListener("resize", update)
38
+ return () => viewport.removeEventListener("resize", update)
39
+ }
40
+
41
+ export const useKeyboardOpen = () => {
42
+ const keyboardOpen = ref(false)
43
+ let stop: (() => void) | undefined
44
+ onMounted(() => {
45
+ if (typeof window === "undefined") return
46
+ stop = observeKeyboard(window, (open) => {
47
+ keyboardOpen.value = open
48
+ })
49
+ })
50
+ onBeforeUnmount(() => {
51
+ stop?.()
52
+ stop = undefined
53
+ })
54
+ return { keyboardOpen }
55
+ }