UNPKG

@aldoivan10/vuetify-dialog

Version:

Plugin to use dialogs from vuetify programatically

277 lines (216 loc) 12.5 kB
# Dialog `Dialog` es una librería para crear diálogos [vuetify](https://vuetifyjs.com/en/components/dialogs/) mediante código. ## 📦 Instalación ```bash npm i @aldoivan/vuetify-dialog pnpm add @aldoivan/vuetify-dialog ``` Luego, importa e instala la librería en tu proyecto Vue: ```typescript import { createApp } from "vue" import { Dialog } from "@aldoivan/vuetify-dialog" import { createVuetify } from "vuetify" const app = createApp(App) // Instalar primero vuetify app.use(createVuetify(...)) // Instalar después el plugin para un correcto funcionamiento app.use(Dialog) ``` ### Singleton Por defecto, los diálogos estan configurados de tal forma que se montan y desmontan por cada uso (al cerrarse se desmonta), esto es beneficioso cuando no se recuere un uso constante de ellos. Sin embargo, cuando su uso es recurrente, se tiene la opción de usar un único diálogo al cual solo se le cambian las propiedades (singleton). Para activar este modo hay que pasar el parámetro a las opciones: ```typescript app.use(Dialog, { singleton: true }) // Por defecto false ``` También se puede activar/desactivar mediante la función de clase: ```typescript const dialog = useDialog() dialog.setSingleton(boolean) ``` ## 📖 Uso ### Composable `useDialog` Puedes usar el composable `useDialog` en cualquier parte del código (stores, scripts, etc): ```typescript const dialog = useDialog() dialog.alert({ body: { content: "Diálogo desde el código" } }) ``` ### `$dialog` De igual forma, puedes acceder dentro del `template` a la variable global `$dialog` para mostrar los diálogos: ```vue <template> <button @click="$dialog.alert({ body: { content: 'Diálogo desde elemento' } })" > Mostrar diálogo </button> </template> ``` ### Cerrar diálogo mediante `$emit` Cuando el body, header o actions es un `Component` se puede cerrar el diálogo haciendo uso de `$emit` y pasando un valor (opcional) en cualquier momento llamando al event `closeDialog`: ```vue // ChoiceForm.vue <script setup lang="ts"> import { ref } from "vue" defineEmits<{ closeDialog: [value: number] }>() const users = ref([ { id: 1, name: "Aldo" }, { id: 2, name: "Ivonne" }, { id: 3, name: "Laura" }, { id: 4, name: "Pedro" }, ]) </script> <template> <v-card-text> <v-row> <v-col :cols="12" v-for="({ id, name }, key) in users" :key > <v-btn :text="name" @click="$emit('closeDialog', id)" variant="tonal" color="secondary" class="w-100" /> </v-col> </v-row> </v-card-text> </template> ``` ### Cerrar diálogo mediante `onClick` prop Si las `actions` se crean usando el arreglo `Button[]`, las funciones `onClick` recibirán como primer parámetro la función `closeDialog`, la cual al ser llamada cerrará el diálogo, dicha función opcionalmente puede recibir un parámetro que retornará el valor del modal. Adicionalmente se ha agregado la capacidad de recibir `ref` en las propiedades pasadas en cada elemento, y se obtendrá como segundo parámetro `props` (puedes checar algunos ejemplos en [code/src](https://www.npmjs.com/package/@aldoivan10/vuetify-dialog?activeTab=code) ): ```typescript const loading = ref(false) const disabled = ref(false) const result = await dialog.show<true | undefined>({ body: { content: "Cerrar mediante <b>onClick</b>", props: { html: true } }, actions: [ { text: "Aceptar", variant: "flat", onClick: (closeDialog) => closeDialog(true), }, { text: "Cancelar", variant: "flat", color: "error", loading, disabled, onClick: (closeDialog, props) => { props.loading = true props.disabled = true setTimeout(() => closeDialog(), 3000) // Cerrar en 3 segundos }, }, ], }) console.log(result) ``` ## 🗪 Diálogos por defecto ### Simple Este diálog únicamente renderiza el `Header` y `Body`, no puede recibir `Actions`, por tanto, debe cerrarse mediante el evento `$emit`: ```typescript import ChoiceForm from "./components/ChoiceForm.vue" const result = await dialog.simple<any>({ header: { content: { title: "Escoge al usuario" } }, body: { content: markRaw(ChoiceForm) }, // content: Component }) console.log(result) ``` ### Alert Este diálog únicamente renderiza el `Header` y `Body`, y como `Actions` tiene un único botón (con valor undefined) personalizable (el prop value, es el valor retornado al cerrar el diálogo): ```typescript const result = await dialog.alert<number>({ header: { content: { title: "¡Alerta!", subtitle: "Urgente" } }, body: { content: "Soy una <b>alerta<b> :D", props: { html: true } }, action: { value: 123, text: "Aceptar" }, // action: Button }) console.log(result) // result = 123 ``` ### Confirm Este diálog únicamente renderiza el `Header` y `Body`, y como `Actions` tiene un 2 bótones personalizables para cancelar (con valor false) y aceptar (con valor true) (el prop value, es el valor retornado al cerrar el diálogo): ```typescript const result = await dialog.confirm<boolean>({ header: { content: { title: "¡Alto!", subtitle: "Responde" } }, body: { content: "¿Te ha gustado?", props: { html: true } }, acceptBtn: { text: "Sí" }, cancelBtn: { text: "No" }, }) console.log(result) // true ó false ``` ### Custom Diálogo 100% personalizable mediante las props: ```typescript const result = await dialog.show<string | number | Array<number> | Object>({ header: { content: { title: "Personalizado", subtitle: ":D" } }, body: { content: "Soy un componente <b>custom</b>", props: { html: true } }, actions: [ { text: "Aceptar", variant: "flat", onClick: (closeDialog) => closeDialog("Boton 1"), }, { text: "Cancelar", color: "error", onClick: (closeDialog) => closeDialog(20), }, { text: "Extra 1", color: "success", variant: "tonal", onClick: (closeDialog) => closeDialog({ id: 1, name: "Nameless" }), }, { onClick: (closeDialog) => closeDialog([1, 2, 3, 4]), text: "Extra 2", variant: "outlined", color: "primary", }, ], }) console.log(result) // true ó false ``` ## 📚 API ### Propiedades Para lanzar un diálogo es necesario pasar un objeto con las siguientes propiedades: | Propiedad | Tipo | Descripción | | -------------- | :-----------------: | :----------------------------------------------------------------------------------------------------------------------------: | | header? | Header | Opcional, cabecera del diálogo | | body? | Body | Opcional, cuerpo del diálogo | | actions? | Actions \| Button[] | Opcional, acciones del diálogo, puede se run objeto o un arreglo de propiedades de [VBtn](https://vuetifyjs.com/en/api/v-btn/) | | transition? | string | Opcional, por defecto: `"scale-transition"` | | fullscreen? | boolean | Opcional, por defecto: `false` | | persistent? | boolean | Opcional, por defecto: `true` | | minWidth? | string \| number | Opcional, por defecto: `"25%"` | | width? | string \| number | Opcional, por defecto: `"fit-content"` | | [Key: string]? | any | Opcionales, todas las propiedades admisibles de [VDialog](scale-""https://vuetifyjs.com/en/api/v-dialog/) | #### `Header` | Propiedad | Tipo | Descripción | | --------- | :-----------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------: | | content | { title?: string, subtitle?: string, prependAvatar?: string, appendAvatar?: string, preppendIcon?: string, appendIcon?: string, class?: string } \| Component | Contenido del Header, debe ser un objeto con las propiedades descritas o un `Component` de Vue | | props? | Record<string, any> | Opcional, `props` que se pasarán solo cuando `content` sea un `Component` | #### `Body` | Propiedad | Tipo | Descripción | | --------- | :--------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------: | | content | string \| Component | Contenido del Body, debe una cadena o un `Component` de Vue | | props? | Record<string, any> & { html?: boolean } | Opcional, `props` que se pasarán solo cuando `content` sea un `Component`. Cuando `content` es una cadena solo recibe si la cadena se debe renderizar como html. | #### `Actions` | Propiedad | Tipo | Descripción | | --------- | :-----------------: | :------------------------------------------: | | content | Component | `Component` a renderizar | | props? | Record<string, any> | Opcional, `props` que se pasarán al content. | #### `Button` | Propiedad | Tipo | Descripción | | -------------- | :--------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | onClick | (closeDialog: (val?: any) => void, props: Record<string, any>) => void | Opcional, acción a hacer clic sobre el botón. | | shortcut? | { value: string, modifiers?: { click?: boolean; prevent?: boolean } } | Opcional, atajo del teclado para poder hacer clic sobre el botón. (Solo si se tiene instalada la dependencia [VShortcut](https://www.npmjs.com/package/@aldoivan10/v-shortcut)) | | [Key: string]? | any | Opcionales, todas las propiedades admisibles de [VBtn](https://vuetifyjs.com/en/api/v-btn/) | ## 📃 Licencia Este proyecto está bajo la licencia MIT. Consulta el archivo LICENSE para más detalles.