@aldoivan10/vuetify-dialog
Version:
Plugin to use dialogs from vuetify programatically
277 lines (216 loc) • 12.5 kB
Markdown
# ⭐ 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 /vuetify-dialog
pnpm add /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
="$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"
="$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.