@dnax/ui 0.0.10 → 0.0.11
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/components/QDialog.vue +2 -2
- package/components/QDialogProvider.vue +20 -26
- package/components/internal/QDialogHost.vue +45 -0
- package/index.ts +1 -1
- package/lib/q.ts +35 -2
- package/package.json +1 -1
- package/scripts/generate-exports.ts +1 -1
- package/styles/main.css +52 -0
package/components/QDialog.vue
CHANGED
|
@@ -40,8 +40,8 @@ interface Props {
|
|
|
40
40
|
contentStyle?: StyleValue
|
|
41
41
|
noBackdropDismiss?: boolean
|
|
42
42
|
noEscDismiss?: boolean
|
|
43
|
-
/** Animation : fade | zoom | slide-up | slide-down | slide-left | slide-right (sinon basée sur position) */
|
|
44
|
-
transition?: "fade" | "zoom" | "slide-up" | "slide-down" | "slide-left" | "slide-right"
|
|
43
|
+
/** Animation : fade | zoom | slide-up | slide-down | slide-left | slide-right | swipe-left | swipe-right (sinon basée sur position) */
|
|
44
|
+
transition?: "fade" | "zoom" | "slide-up" | "slide-down" | "slide-left" | "slide-right" | "swipe-left" | "swipe-right"
|
|
45
45
|
/** Durée des transitions d'entrée/sortie en ms (défaut CSS : ~200ms entrée, ~150ms sortie) */
|
|
46
46
|
transitionDuration?: number
|
|
47
47
|
}
|
|
@@ -2,26 +2,28 @@
|
|
|
2
2
|
// QDialogProvider — rend la pile de dialogues programmatiques ($q.dialog).
|
|
3
3
|
// Intégré dans QConfigProvider (rendu automatiquement par le plus externe),
|
|
4
4
|
// mais utilisable aussi en autonome : <q-dialog-provider><slot /></q-dialog-provider>.
|
|
5
|
-
//
|
|
6
|
-
//
|
|
5
|
+
//
|
|
6
|
+
// Pattern Quasar : le composant passé à $q.dialog.open({ component }) DOIT contenir
|
|
7
|
+
// un <q-dialog v-model="open" @hide="onDialogHide"> à sa racine, piloté via le
|
|
8
|
+
// composable useDialogPluginComponent() (exporté par @dnax/ui). Le provider fournit
|
|
9
|
+
// le contexte (open, onOK, onCancel) via QDialogHost ; à la fermeture (backdrop,
|
|
10
|
+
// Échap, ×, onDialogOK, onDialogCancel), le résolveur correspondant est appelé
|
|
7
11
|
// puis l'entrée est retirée de la pile.
|
|
8
12
|
import { computed, inject } from "vue"
|
|
9
13
|
import { dialogStack, closeDialog } from "../lib/q"
|
|
10
14
|
import type { DialogController } from "../lib/q"
|
|
11
15
|
import { qConfigKey } from "../lib/config"
|
|
12
16
|
import { themeVarsStyle } from "../lib/themeVars"
|
|
17
|
+
import QDialogHost from "./internal/QDialogHost.vue"
|
|
13
18
|
|
|
14
19
|
const dialogs = dialogStack
|
|
15
20
|
|
|
16
21
|
const config = inject(qConfigKey, null)
|
|
17
22
|
|
|
18
|
-
// Les dialogs sont téléportés au body (QDialog) : on repose
|
|
19
|
-
// sur
|
|
23
|
+
// Les dialogs sont téléportés au body (QDialog du composant passé) : on repose
|
|
24
|
+
// les tokens du thème sur le host pour qu'ils héritent des couleurs/radius du provider.
|
|
20
25
|
const dialogThemeStyle = themeVarsStyle(computed(() => config?.theme.value ?? {}))
|
|
21
26
|
|
|
22
|
-
const contentStyle = (ctrl: DialogController) =>
|
|
23
|
-
typeof ctrl._opts.fullscreen === "string" ? { width: ctrl._opts.fullscreen } : undefined
|
|
24
|
-
|
|
25
27
|
const handleOk = (ctrl: DialogController, data?: unknown) => {
|
|
26
28
|
ctrl._resolvers.ok?.(data)
|
|
27
29
|
closeDialog(ctrl)
|
|
@@ -38,28 +40,20 @@ const handleDismiss = (ctrl: DialogController) => {
|
|
|
38
40
|
|
|
39
41
|
<template>
|
|
40
42
|
<slot />
|
|
41
|
-
<
|
|
43
|
+
<div
|
|
42
44
|
v-for="(dialog, idx) in dialogs"
|
|
43
45
|
:key="idx"
|
|
44
|
-
:
|
|
45
|
-
:maximized="dialog._opts.fullscreen === true"
|
|
46
|
-
:content-style="[contentStyle(dialog), dialogThemeStyle]"
|
|
47
|
-
:content-class="dialog._opts.class"
|
|
48
|
-
:persistent="dialog._opts.persistent"
|
|
49
|
-
@update:model-value="(v: boolean) => !v && handleDismiss(dialog)"
|
|
46
|
+
:style="dialogThemeStyle"
|
|
50
47
|
>
|
|
51
|
-
<q-dialog-
|
|
52
|
-
|
|
53
|
-
:
|
|
54
|
-
:
|
|
55
|
-
|
|
56
|
-
<component
|
|
57
|
-
:is="dialog._opts.component"
|
|
58
|
-
v-bind="dialog._opts.componentProps"
|
|
48
|
+
<q-dialog-host
|
|
49
|
+
:ctrl="dialog"
|
|
50
|
+
:on-ok="(data?: unknown) => handleOk(dialog, data)"
|
|
51
|
+
:on-cancel="() => handleCancel(dialog)"
|
|
52
|
+
:on-hide="() => handleDismiss(dialog)"
|
|
59
53
|
@ok="(data?: unknown) => handleOk(dialog, data)"
|
|
60
|
-
@cancel="handleCancel(dialog)"
|
|
61
|
-
@dismiss="handleDismiss(dialog)"
|
|
62
|
-
@close="handleDismiss(dialog)"
|
|
54
|
+
@cancel="() => handleCancel(dialog)"
|
|
55
|
+
@dismiss="() => handleDismiss(dialog)"
|
|
56
|
+
@close="() => handleDismiss(dialog)"
|
|
63
57
|
/>
|
|
64
|
-
</
|
|
58
|
+
</div>
|
|
65
59
|
</template>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// QDialogHost — host interne du $q.dialog : rend le composant passé tel quel et
|
|
3
|
+
// lui fournit le contexte plugin (pattern Quasar). Le composant passé DOIT
|
|
4
|
+
// contenir un <q-dialog v-model="open" @hide="onDialogHide"> comme racine, piloté
|
|
5
|
+
// via useDialogPluginComponent(). À la fermeture (backdrop/Échap/× → @hide), ou
|
|
6
|
+
// via onDialogOK / onDialogCancel, les résolveurs sont appelés et l'entrée retirée.
|
|
7
|
+
import { provide, ref } from "vue"
|
|
8
|
+
import { qDialogPluginKey } from "../../lib/q"
|
|
9
|
+
import type { DialogController } from "../../lib/q"
|
|
10
|
+
|
|
11
|
+
const props = defineProps<{
|
|
12
|
+
ctrl: DialogController
|
|
13
|
+
onOk: (data?: unknown) => void
|
|
14
|
+
onCancel: () => void
|
|
15
|
+
onHide: () => void
|
|
16
|
+
}>()
|
|
17
|
+
|
|
18
|
+
const open = ref(true)
|
|
19
|
+
|
|
20
|
+
provide(qDialogPluginKey, {
|
|
21
|
+
open,
|
|
22
|
+
onOK: (data?: unknown) => props.onOk(data),
|
|
23
|
+
onCancel: () => props.onCancel(),
|
|
24
|
+
onHide: () => props.onHide(),
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// Le composant émet aussi les events legacy (ok/cancel/dismiss/close)
|
|
28
|
+
const emit = defineEmits<{
|
|
29
|
+
ok: [data?: unknown]
|
|
30
|
+
cancel: []
|
|
31
|
+
dismiss: []
|
|
32
|
+
close: []
|
|
33
|
+
}>()
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<component
|
|
38
|
+
:is="props.ctrl._opts.component"
|
|
39
|
+
v-bind="props.ctrl._opts.componentProps"
|
|
40
|
+
@ok="emit('ok', $event)"
|
|
41
|
+
@cancel="emit('cancel')"
|
|
42
|
+
@dismiss="emit('dismiss')"
|
|
43
|
+
@close="emit('close')"
|
|
44
|
+
/>
|
|
45
|
+
</template>
|
package/index.ts
CHANGED
|
@@ -126,7 +126,7 @@ export { default as QUploader } from "./components/QUploader.vue"
|
|
|
126
126
|
export { default as QVideo } from "./components/QVideo.vue"
|
|
127
127
|
export { default as QVirtualScroll } from "./components/QVirtualScroll.vue"
|
|
128
128
|
|
|
129
|
-
export { $q, usePlugin, useQ, QPlugin, dialogStack, closeDialog, bottomSheetStack, closeBottomSheet } from "./lib/q"
|
|
129
|
+
export { $q, usePlugin, useQ, QPlugin, dialogStack, closeDialog, bottomSheetStack, closeBottomSheet, useDialogPluginComponent } from "./lib/q"
|
|
130
130
|
export type {
|
|
131
131
|
DialogOptions,
|
|
132
132
|
DialogController,
|
package/lib/q.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
// app.use(QPlugin) → accès $q via this.$q / getCurrentInstance().proxy.$q
|
|
6
6
|
// ou import direct :
|
|
7
7
|
// import { $q } from "@dnax/ui" → $q.dialog.open(...)
|
|
8
|
-
import { ref } from "vue"
|
|
8
|
+
import { inject, ref } from "vue"
|
|
9
9
|
import { h } from "vue"
|
|
10
|
-
import type { App, Component, Ref } from "vue"
|
|
10
|
+
import type { App, Component, InjectionKey, Ref } from "vue"
|
|
11
11
|
import { toast } from "vue-sonner"
|
|
12
12
|
import type { ExternalToast } from "vue-sonner"
|
|
13
13
|
import QNotifyToast from "../components/QNotifyToast.vue"
|
|
@@ -44,6 +44,39 @@ export interface DialogController {
|
|
|
44
44
|
_opts: DialogOptions
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
// — Contexte plugin dialog (pattern Quasar) —
|
|
48
|
+
// Le composant passé à $q.dialog.open({ component }) DOIT contenir un
|
|
49
|
+
// <q-dialog v-model="open" @hide="onDialogHide"> à sa racine ; il pilote
|
|
50
|
+
// l'ouverture via le composable useDialogPluginComponent().
|
|
51
|
+
export interface DialogPluginContext {
|
|
52
|
+
/** Ref d'ouverture (v-model du <q-dialog> du composant) */
|
|
53
|
+
open: Ref<boolean>
|
|
54
|
+
/** Ferme en validant — le résolveur onOK est appelé */
|
|
55
|
+
onOK: (data?: unknown) => void
|
|
56
|
+
/** Ferme en annulant — le résolveur onCancel est appelé */
|
|
57
|
+
onCancel: () => void
|
|
58
|
+
/** Fermé par backdrop / Échap / × — le résolveur onDismiss est appelé */
|
|
59
|
+
onHide: () => void
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const qDialogPluginKey: InjectionKey<DialogPluginContext> = Symbol("q-dialog-plugin")
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Composable Quasar-style pour les composants passés à $q.dialog.open().
|
|
66
|
+
* Le composant doit rendre un <q-dialog v-model="open" @hide="onDialogHide">
|
|
67
|
+
* comme racine. Expose aussi onDialogOK / onDialogCancel pour fermer en validant
|
|
68
|
+
* ou en annulant, et onDialogHide à brancher sur @hide du q-dialog.
|
|
69
|
+
*/
|
|
70
|
+
export function useDialogPluginComponent() {
|
|
71
|
+
const ctx = inject(qDialogPluginKey, null)
|
|
72
|
+
return {
|
|
73
|
+
open: ctx?.open ?? ref(false),
|
|
74
|
+
onDialogHide: () => ctx?.onHide(),
|
|
75
|
+
onDialogOK: (data?: unknown) => ctx?.onOK(data),
|
|
76
|
+
onDialogCancel: () => ctx?.onCancel(),
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
47
80
|
// — Pile de dialogues (singleton module-level, client-side) —
|
|
48
81
|
const dialogs: Ref<DialogController[]> = ref([])
|
|
49
82
|
|
package/package.json
CHANGED
|
@@ -26,7 +26,7 @@ const exports = files
|
|
|
26
26
|
|
|
27
27
|
// Exports manuels (composables / helpers) — conservés à chaque régénération
|
|
28
28
|
const manualExports = `
|
|
29
|
-
export { $q, usePlugin, useQ, QPlugin, dialogStack, closeDialog, bottomSheetStack, closeBottomSheet } from "./lib/q"
|
|
29
|
+
export { $q, usePlugin, useQ, QPlugin, dialogStack, closeDialog, bottomSheetStack, closeBottomSheet, useDialogPluginComponent } from "./lib/q"
|
|
30
30
|
export type {
|
|
31
31
|
DialogOptions,
|
|
32
32
|
DialogController,
|
package/styles/main.css
CHANGED
|
@@ -6237,6 +6237,58 @@ html.dark body {
|
|
|
6237
6237
|
}
|
|
6238
6238
|
}
|
|
6239
6239
|
|
|
6240
|
+
/* swipe-* : le panneau glisse depuis un bord et y REVIENT à la fermeture
|
|
6241
|
+
(aller-retour, comme la sidebar) — swipe-left : vient de la droite et y
|
|
6242
|
+
retourne ; swipe-right : vient de la gauche et y retourne. */
|
|
6243
|
+
.q-dialog-swipe-left-enter-active,
|
|
6244
|
+
.q-dialog-swipe-left-leave-active,
|
|
6245
|
+
.q-dialog-swipe-right-enter-active,
|
|
6246
|
+
.q-dialog-swipe-right-leave-active {
|
|
6247
|
+
transition: opacity var(--q-dialog-duration-enter, 0.2s) ease;
|
|
6248
|
+
}
|
|
6249
|
+
|
|
6250
|
+
.q-dialog-swipe-left-enter-active .q-dialog__content,
|
|
6251
|
+
.q-dialog-swipe-left-leave-active .q-dialog__content {
|
|
6252
|
+
--q-dialog-swipe-x: 100vw;
|
|
6253
|
+
}
|
|
6254
|
+
|
|
6255
|
+
.q-dialog-swipe-right-enter-active .q-dialog__content,
|
|
6256
|
+
.q-dialog-swipe-right-leave-active .q-dialog__content {
|
|
6257
|
+
--q-dialog-swipe-x: -100vw;
|
|
6258
|
+
}
|
|
6259
|
+
|
|
6260
|
+
.q-dialog-swipe-left-enter-active .q-dialog__content,
|
|
6261
|
+
.q-dialog-swipe-right-enter-active .q-dialog__content {
|
|
6262
|
+
animation: q-dialog-swipe-in var(--q-dialog-duration-enter, 0.3s) cubic-bezier(0.32, 0.72, 0, 1);
|
|
6263
|
+
}
|
|
6264
|
+
|
|
6265
|
+
.q-dialog-swipe-left-leave-active .q-dialog__content,
|
|
6266
|
+
.q-dialog-swipe-right-leave-active .q-dialog__content {
|
|
6267
|
+
animation: q-dialog-swipe-out var(--q-dialog-duration-leave, 0.2s) ease-in forwards;
|
|
6268
|
+
}
|
|
6269
|
+
|
|
6270
|
+
@keyframes q-dialog-swipe-in {
|
|
6271
|
+
from {
|
|
6272
|
+
opacity: 0.6;
|
|
6273
|
+
transform: translateX(var(--q-dialog-swipe-x, 100vw));
|
|
6274
|
+
}
|
|
6275
|
+
to {
|
|
6276
|
+
opacity: 1;
|
|
6277
|
+
transform: none;
|
|
6278
|
+
}
|
|
6279
|
+
}
|
|
6280
|
+
|
|
6281
|
+
@keyframes q-dialog-swipe-out {
|
|
6282
|
+
from {
|
|
6283
|
+
opacity: 1;
|
|
6284
|
+
transform: none;
|
|
6285
|
+
}
|
|
6286
|
+
to {
|
|
6287
|
+
opacity: 0;
|
|
6288
|
+
transform: translateX(var(--q-dialog-swipe-x, 100vw));
|
|
6289
|
+
}
|
|
6290
|
+
}
|
|
6291
|
+
|
|
6240
6292
|
/* ===== QContainer ===== */
|
|
6241
6293
|
.q-container {
|
|
6242
6294
|
width: 100%;
|