adverich-kun-ui 0.1.581 → 0.1.582
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/AGENTS.md +233 -13
- package/dist/AGENTS.md +233 -13
- package/dist/adverich-kun-ui.css +1 -1
- package/dist/components/KunTextarea/src/components/KunTextarea.vue.js +138 -119
- package/dist/components/KunTextarea/src/composables/KunTextareaProps.js +6 -1
- package/dist/components/KunTextarea/src/composables/useKunTextareaComposable.js +103 -57
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -264,28 +264,248 @@ Botones de radio.
|
|
|
264
264
|
|
|
265
265
|
### KunTable
|
|
266
266
|
|
|
267
|
-
Tabla con ordenamiento,
|
|
267
|
+
Tabla de datos avanzada con paginación, ordenamiento, filtrado y selección.
|
|
268
268
|
|
|
269
269
|
```vue
|
|
270
|
-
<
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
270
|
+
<template>
|
|
271
|
+
<KunTable
|
|
272
|
+
:items="usuarios"
|
|
273
|
+
:headers="headers"
|
|
274
|
+
:searchable="true"
|
|
275
|
+
:filterable="true"
|
|
276
|
+
:show-select="true"
|
|
277
|
+
v-model:selectedItems="seleccionados"
|
|
278
|
+
@update:sortBy="handleSort"
|
|
279
|
+
>
|
|
280
|
+
<template #item.actions="{ item }">
|
|
281
|
+
<KunBtn icon="mdi-pencil" size="xs" />
|
|
282
|
+
<KunBtn icon="mdi-delete" size="xs" />
|
|
283
|
+
</template>
|
|
284
|
+
</KunTable>
|
|
285
|
+
</template>
|
|
286
|
+
|
|
287
|
+
<script setup>
|
|
288
|
+
import { ref } from 'vue'
|
|
289
|
+
|
|
290
|
+
const usuarios = ref([...])
|
|
291
|
+
|
|
292
|
+
const headers = [
|
|
293
|
+
{ key: 'nombre', value: 'nombre', label: 'Nombre', sortable: true },
|
|
294
|
+
{ key: 'email', value: 'email', label: 'Email', sortable: true },
|
|
295
|
+
{ key: 'rol', value: 'rol', label: 'Rol', sortable: true },
|
|
296
|
+
{ key: 'estado', value: 'estado', label: 'Estado' },
|
|
297
|
+
]
|
|
298
|
+
|
|
299
|
+
const seleccionados = ref([])
|
|
300
|
+
|
|
301
|
+
const handleSort = (sortBy) => {
|
|
302
|
+
console.log('Ordenar por:', sortBy)
|
|
303
|
+
}
|
|
304
|
+
</script>
|
|
277
305
|
```
|
|
278
306
|
|
|
279
307
|
| Prop | Tipo | Default | Descripción |
|
|
280
308
|
|------|------|---------|-------------|
|
|
281
309
|
| items | Array | [] | Datos a mostrar |
|
|
282
|
-
| headers | Array | [] | Configuración de columnas |
|
|
283
|
-
|
|
|
284
|
-
|
|
|
310
|
+
| headers | Array | [] | Configuración de columnas (ver estructura abajo) |
|
|
311
|
+
| selectedItems | Array | [] | v-model: Items seleccionados |
|
|
312
|
+
| searchable | Boolean | false | Habilita barra de búsqueda global |
|
|
313
|
+
| search | String | '' | v-model: Término de búsqueda |
|
|
314
|
+
| filterable | Boolean | false | Habilita filtros avanzados por columna |
|
|
315
|
+
| filters | Array | [] | Configuración de filtros (ver estructura abajo) |
|
|
316
|
+
| showSelect | Boolean | false | Muestra checkboxes de selección |
|
|
285
317
|
| showExpand | Boolean | false | Habilita expansión de filas |
|
|
318
|
+
| hasActions | Boolean | false | Muestra columna de acciones |
|
|
319
|
+
| actionLabel | String | 'Acciones' | Etiqueta de columna de acciones |
|
|
320
|
+
| actionLoadingMap | Object | {} | Mapa de estado loading por ID de item |
|
|
286
321
|
| itemsPerPage | Number | 10 | Items por página |
|
|
287
|
-
|
|
|
288
|
-
|
|
|
322
|
+
| page | Number | 1 | Página actual |
|
|
323
|
+
| sortBy | Array/String | [] | v-model: Criterio de ordenamiento |
|
|
324
|
+
| multiSort | Boolean | false | Permite ordenar por múltiples columnas |
|
|
325
|
+
| pageOptions | Array | [5, 10, 25, 50, 100] | Opciones del selector de items por página |
|
|
326
|
+
| searchableKeys | Array | null | Claves específicas para búsqueda global |
|
|
327
|
+
| searchPlaceholder | String | 'Buscar...' | Placeholder del input de búsqueda |
|
|
328
|
+
| debounceTime | Number | 300 | Debounce en ms para búsqueda |
|
|
329
|
+
| customFilter | Function | null | Función de filtrado personalizada |
|
|
330
|
+
| functionMap | Object | {} | Mapa de funciones para columnas tipo 'function' |
|
|
331
|
+
| hideDefaultHeader | Boolean | false | Oculta header por defecto |
|
|
332
|
+
| hideDefaultFooter | Boolean | false | Oculta footer por defecto |
|
|
333
|
+
| noDataText | String | 'No hay elementos disponibles' | Texto cuando no hay datos |
|
|
334
|
+
| loadingText | String | 'Cargando...' | Texto de estado de carga |
|
|
335
|
+
|
|
336
|
+
**Estructura de `headers`:**
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
const headers = [
|
|
340
|
+
{
|
|
341
|
+
key: 'nombre', // Identificador único
|
|
342
|
+
value: 'nombre', // Clave para acceder al dato (soporta paths: 'usuario.nombre')
|
|
343
|
+
label: 'Nombre', // Texto visible en el header
|
|
344
|
+
sortable: true, // Permite ordenar por esta columna
|
|
345
|
+
headerAlign: 'left', // Alineación: 'left', 'center', 'right'
|
|
346
|
+
columnType: 'function', // Opcional: tipo de columna
|
|
347
|
+
columnFunction: 'formatDate', // Nombre de función en functionMap
|
|
348
|
+
relationPath: 'user.id' // Path alternativo para datos anidados
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Estructura de `filters`:**
|
|
354
|
+
|
|
355
|
+
```javascript
|
|
356
|
+
const filters = [
|
|
357
|
+
{
|
|
358
|
+
value: 'rol', // Clave del filtro (debe coincidir con header.value)
|
|
359
|
+
label: 'Rol', // Etiqueta visible
|
|
360
|
+
text: 'Rol', // Texto alternativo
|
|
361
|
+
name: 'roles', // Nombre para textos genéricos
|
|
362
|
+
items: [...], // Lista de opciones para el filtro
|
|
363
|
+
placeholderText: 'Seleccionar rol',
|
|
364
|
+
textNoItem: 'No hay roles disponibles'
|
|
365
|
+
}
|
|
366
|
+
]
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Slots:**
|
|
370
|
+
|
|
371
|
+
| Slot | Props | Descripción |
|
|
372
|
+
|------|-------|-------------|
|
|
373
|
+
| `#item.{key}` | `{ item, index, value, header }` | Contenido personalizado de celda |
|
|
374
|
+
| `#header.{key}` | `{ header }` | Header personalizado de columna |
|
|
375
|
+
| `#item.actions` | `{ item, index, loading }` | Columna de acciones (si `hasActions`) |
|
|
376
|
+
| `#expand` | `{ item, index }` | Contenido de fila expandida |
|
|
377
|
+
| `#thead` | `{ items, headers, page, itemsPerPage, ... }` | Header completo personalizado |
|
|
378
|
+
| `#tfoot` | `{ items, headers, ... }` | Footer personalizado |
|
|
379
|
+
| `#body.prepend` | `{ items, headers, ... }` | Contenido antes del tbody |
|
|
380
|
+
| `#body.append` | `{ items, headers, ... }` | Contenido después del tbody |
|
|
381
|
+
| `#prependHeader` | - | Contenido antes de la barra de búsqueda |
|
|
382
|
+
| `#prependSearch` | - | Contenido antes del input de búsqueda |
|
|
383
|
+
| `#appendSearch` | - | Contenido después del input de búsqueda |
|
|
384
|
+
| `#footer` | `{ items, headers, page, itemsPerPage, ... }` | Footer completo personalizado |
|
|
385
|
+
|
|
386
|
+
**Eventos:**
|
|
387
|
+
|
|
388
|
+
| Evento | Payload | Descripción |
|
|
389
|
+
|--------|---------|-------------|
|
|
390
|
+
| `update:page` | `Number` | Cambia la página actual |
|
|
391
|
+
| `update:itemsPerPage` | `Number` | Cambia items por página |
|
|
392
|
+
| `update:sortBy` | `Array` | Cambia criterio de ordenamiento |
|
|
393
|
+
| `update:search` | `String` | Cambia término de búsqueda |
|
|
394
|
+
| `update:selectedItems` | `Array` | Cambia items seleccionados |
|
|
395
|
+
| `focusOnSearch` | `Boolean` | Input de búsqueda enfocado/desenfocado |
|
|
396
|
+
|
|
397
|
+
**Clases personalizables:**
|
|
398
|
+
|
|
399
|
+
| Prop | Tipo | Descripción |
|
|
400
|
+
|------|------|-------------|
|
|
401
|
+
| wrapperClass | String | Clase del contenedor principal |
|
|
402
|
+
| tableClass | String | Clase de la etiqueta `<table>` |
|
|
403
|
+
| theadClass | String | Clase del `<thead>` |
|
|
404
|
+
| tbodyClass | String | Clase del `<tbody>` |
|
|
405
|
+
| tfootClass | String | Clase del `<tfoot>` |
|
|
406
|
+
| trClass | String | Clase de las filas `<tr>` |
|
|
407
|
+
| thClass | String | Clase de los headers `<th>` |
|
|
408
|
+
| tdClass | String/Function | Clase de las celdas `<td>` |
|
|
409
|
+
| rowClass | String | Clase adicional para filas |
|
|
410
|
+
| rowClassCondition | String/Function | Condición para aplicar rowClass |
|
|
411
|
+
| selectedClass | String | Clase para filas seleccionadas |
|
|
412
|
+
| stripedClass | String | Clase para filas alternas (striped) |
|
|
413
|
+
|
|
414
|
+
**Características:**
|
|
415
|
+
|
|
416
|
+
- **Búsqueda global:** Filtra en todas las columnas marcadas como `sortable` o en `searchableKeys`
|
|
417
|
+
- **Filtros por columna:** Modal con KunAutocomplete para filtrar por columnas específicas
|
|
418
|
+
- **Ordenamiento:** Simple o múltiple (con `multiSort`). Soporta strings, números y fechas
|
|
419
|
+
- **Selección:** Individual, por página, o todos los filtrados
|
|
420
|
+
- **Expansión:** Filas expandibles con slot `#expand`
|
|
421
|
+
- **Responsive:** En móvil se transforma a vista de tarjetas (KunTableIterators)
|
|
422
|
+
- **Serialización:** Soporta funciones serializadas via `functionMap` para columnas dinámicas
|
|
423
|
+
|
|
424
|
+
**Ejemplo completo:**
|
|
425
|
+
|
|
426
|
+
```vue
|
|
427
|
+
<template>
|
|
428
|
+
<KunTable
|
|
429
|
+
:items="usuarios"
|
|
430
|
+
:headers="headers"
|
|
431
|
+
:filters="filtros"
|
|
432
|
+
:searchable="true"
|
|
433
|
+
:filterable="true"
|
|
434
|
+
:show-select="true"
|
|
435
|
+
v-model:selectedItems="seleccionados"
|
|
436
|
+
:items-per-page="15"
|
|
437
|
+
>
|
|
438
|
+
<template #item.estado="{ item, value }">
|
|
439
|
+
<KunBadge
|
|
440
|
+
:color="value === 'activo' ? 'bg-green-500' : 'bg-red-500'"
|
|
441
|
+
:text="value"
|
|
442
|
+
/>
|
|
443
|
+
</template>
|
|
444
|
+
|
|
445
|
+
<template #item.actions="{ item, loading }">
|
|
446
|
+
<KunBtn
|
|
447
|
+
icon="mdi-pencil"
|
|
448
|
+
size="xs"
|
|
449
|
+
:loading="loading"
|
|
450
|
+
@click="editar(item)"
|
|
451
|
+
/>
|
|
452
|
+
<KunBtn
|
|
453
|
+
icon="mdi-delete"
|
|
454
|
+
size="xs"
|
|
455
|
+
variant="text"
|
|
456
|
+
@click="eliminar(item)"
|
|
457
|
+
/>
|
|
458
|
+
</template>
|
|
459
|
+
|
|
460
|
+
<template #expand="{ item }">
|
|
461
|
+
<div class="p-4 bg-surface-light">
|
|
462
|
+
<p><strong>Biografía:</strong> {{ item.biografia }}</p>
|
|
463
|
+
</div>
|
|
464
|
+
</template>
|
|
465
|
+
</KunTable>
|
|
466
|
+
</template>
|
|
467
|
+
|
|
468
|
+
<script setup>
|
|
469
|
+
import { ref, computed } from 'vue'
|
|
470
|
+
|
|
471
|
+
const usuarios = ref([
|
|
472
|
+
{ id: 1, nombre: 'Juan', email: 'juan@example.com', rol: 'admin', estado: 'activo' },
|
|
473
|
+
{ id: 2, nombre: 'María', email: 'maria@example.com', rol: 'editor', estado: 'inactivo' },
|
|
474
|
+
])
|
|
475
|
+
|
|
476
|
+
const headers = [
|
|
477
|
+
{ key: 'nombre', value: 'nombre', label: 'Nombre', sortable: true },
|
|
478
|
+
{ key: 'email', value: 'email', label: 'Email', sortable: true },
|
|
479
|
+
{ key: 'rol', value: 'rol', label: 'Rol', sortable: true },
|
|
480
|
+
{ key: 'estado', value: 'estado', label: 'Estado', sortable: true },
|
|
481
|
+
]
|
|
482
|
+
|
|
483
|
+
const filtros = [
|
|
484
|
+
{
|
|
485
|
+
value: 'rol',
|
|
486
|
+
label: 'Rol',
|
|
487
|
+
items: [
|
|
488
|
+
{ id: 1, name: 'Admin' },
|
|
489
|
+
{ id: 2, name: 'Editor' },
|
|
490
|
+
{ id: 3, name: 'Viewer' }
|
|
491
|
+
]
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
value: 'estado',
|
|
495
|
+
label: 'Estado',
|
|
496
|
+
items: [
|
|
497
|
+
{ id: 'activo', name: 'Activo' },
|
|
498
|
+
{ id: 'inactivo', name: 'Inactivo' }
|
|
499
|
+
]
|
|
500
|
+
}
|
|
501
|
+
]
|
|
502
|
+
|
|
503
|
+
const seleccionados = ref([])
|
|
504
|
+
|
|
505
|
+
const editar = (item) => console.log('Editar', item)
|
|
506
|
+
const eliminar = (item) => console.log('Eliminar', item)
|
|
507
|
+
</script>
|
|
508
|
+
```
|
|
289
509
|
|
|
290
510
|
---
|
|
291
511
|
|
package/dist/AGENTS.md
CHANGED
|
@@ -264,28 +264,248 @@ Botones de radio.
|
|
|
264
264
|
|
|
265
265
|
### KunTable
|
|
266
266
|
|
|
267
|
-
Tabla con ordenamiento,
|
|
267
|
+
Tabla de datos avanzada con paginación, ordenamiento, filtrado y selección.
|
|
268
268
|
|
|
269
269
|
```vue
|
|
270
|
-
<
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
270
|
+
<template>
|
|
271
|
+
<KunTable
|
|
272
|
+
:items="usuarios"
|
|
273
|
+
:headers="headers"
|
|
274
|
+
:searchable="true"
|
|
275
|
+
:filterable="true"
|
|
276
|
+
:show-select="true"
|
|
277
|
+
v-model:selectedItems="seleccionados"
|
|
278
|
+
@update:sortBy="handleSort"
|
|
279
|
+
>
|
|
280
|
+
<template #item.actions="{ item }">
|
|
281
|
+
<KunBtn icon="mdi-pencil" size="xs" />
|
|
282
|
+
<KunBtn icon="mdi-delete" size="xs" />
|
|
283
|
+
</template>
|
|
284
|
+
</KunTable>
|
|
285
|
+
</template>
|
|
286
|
+
|
|
287
|
+
<script setup>
|
|
288
|
+
import { ref } from 'vue'
|
|
289
|
+
|
|
290
|
+
const usuarios = ref([...])
|
|
291
|
+
|
|
292
|
+
const headers = [
|
|
293
|
+
{ key: 'nombre', value: 'nombre', label: 'Nombre', sortable: true },
|
|
294
|
+
{ key: 'email', value: 'email', label: 'Email', sortable: true },
|
|
295
|
+
{ key: 'rol', value: 'rol', label: 'Rol', sortable: true },
|
|
296
|
+
{ key: 'estado', value: 'estado', label: 'Estado' },
|
|
297
|
+
]
|
|
298
|
+
|
|
299
|
+
const seleccionados = ref([])
|
|
300
|
+
|
|
301
|
+
const handleSort = (sortBy) => {
|
|
302
|
+
console.log('Ordenar por:', sortBy)
|
|
303
|
+
}
|
|
304
|
+
</script>
|
|
277
305
|
```
|
|
278
306
|
|
|
279
307
|
| Prop | Tipo | Default | Descripción |
|
|
280
308
|
|------|------|---------|-------------|
|
|
281
309
|
| items | Array | [] | Datos a mostrar |
|
|
282
|
-
| headers | Array | [] | Configuración de columnas |
|
|
283
|
-
|
|
|
284
|
-
|
|
|
310
|
+
| headers | Array | [] | Configuración de columnas (ver estructura abajo) |
|
|
311
|
+
| selectedItems | Array | [] | v-model: Items seleccionados |
|
|
312
|
+
| searchable | Boolean | false | Habilita barra de búsqueda global |
|
|
313
|
+
| search | String | '' | v-model: Término de búsqueda |
|
|
314
|
+
| filterable | Boolean | false | Habilita filtros avanzados por columna |
|
|
315
|
+
| filters | Array | [] | Configuración de filtros (ver estructura abajo) |
|
|
316
|
+
| showSelect | Boolean | false | Muestra checkboxes de selección |
|
|
285
317
|
| showExpand | Boolean | false | Habilita expansión de filas |
|
|
318
|
+
| hasActions | Boolean | false | Muestra columna de acciones |
|
|
319
|
+
| actionLabel | String | 'Acciones' | Etiqueta de columna de acciones |
|
|
320
|
+
| actionLoadingMap | Object | {} | Mapa de estado loading por ID de item |
|
|
286
321
|
| itemsPerPage | Number | 10 | Items por página |
|
|
287
|
-
|
|
|
288
|
-
|
|
|
322
|
+
| page | Number | 1 | Página actual |
|
|
323
|
+
| sortBy | Array/String | [] | v-model: Criterio de ordenamiento |
|
|
324
|
+
| multiSort | Boolean | false | Permite ordenar por múltiples columnas |
|
|
325
|
+
| pageOptions | Array | [5, 10, 25, 50, 100] | Opciones del selector de items por página |
|
|
326
|
+
| searchableKeys | Array | null | Claves específicas para búsqueda global |
|
|
327
|
+
| searchPlaceholder | String | 'Buscar...' | Placeholder del input de búsqueda |
|
|
328
|
+
| debounceTime | Number | 300 | Debounce en ms para búsqueda |
|
|
329
|
+
| customFilter | Function | null | Función de filtrado personalizada |
|
|
330
|
+
| functionMap | Object | {} | Mapa de funciones para columnas tipo 'function' |
|
|
331
|
+
| hideDefaultHeader | Boolean | false | Oculta header por defecto |
|
|
332
|
+
| hideDefaultFooter | Boolean | false | Oculta footer por defecto |
|
|
333
|
+
| noDataText | String | 'No hay elementos disponibles' | Texto cuando no hay datos |
|
|
334
|
+
| loadingText | String | 'Cargando...' | Texto de estado de carga |
|
|
335
|
+
|
|
336
|
+
**Estructura de `headers`:**
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
const headers = [
|
|
340
|
+
{
|
|
341
|
+
key: 'nombre', // Identificador único
|
|
342
|
+
value: 'nombre', // Clave para acceder al dato (soporta paths: 'usuario.nombre')
|
|
343
|
+
label: 'Nombre', // Texto visible en el header
|
|
344
|
+
sortable: true, // Permite ordenar por esta columna
|
|
345
|
+
headerAlign: 'left', // Alineación: 'left', 'center', 'right'
|
|
346
|
+
columnType: 'function', // Opcional: tipo de columna
|
|
347
|
+
columnFunction: 'formatDate', // Nombre de función en functionMap
|
|
348
|
+
relationPath: 'user.id' // Path alternativo para datos anidados
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Estructura de `filters`:**
|
|
354
|
+
|
|
355
|
+
```javascript
|
|
356
|
+
const filters = [
|
|
357
|
+
{
|
|
358
|
+
value: 'rol', // Clave del filtro (debe coincidir con header.value)
|
|
359
|
+
label: 'Rol', // Etiqueta visible
|
|
360
|
+
text: 'Rol', // Texto alternativo
|
|
361
|
+
name: 'roles', // Nombre para textos genéricos
|
|
362
|
+
items: [...], // Lista de opciones para el filtro
|
|
363
|
+
placeholderText: 'Seleccionar rol',
|
|
364
|
+
textNoItem: 'No hay roles disponibles'
|
|
365
|
+
}
|
|
366
|
+
]
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Slots:**
|
|
370
|
+
|
|
371
|
+
| Slot | Props | Descripción |
|
|
372
|
+
|------|-------|-------------|
|
|
373
|
+
| `#item.{key}` | `{ item, index, value, header }` | Contenido personalizado de celda |
|
|
374
|
+
| `#header.{key}` | `{ header }` | Header personalizado de columna |
|
|
375
|
+
| `#item.actions` | `{ item, index, loading }` | Columna de acciones (si `hasActions`) |
|
|
376
|
+
| `#expand` | `{ item, index }` | Contenido de fila expandida |
|
|
377
|
+
| `#thead` | `{ items, headers, page, itemsPerPage, ... }` | Header completo personalizado |
|
|
378
|
+
| `#tfoot` | `{ items, headers, ... }` | Footer personalizado |
|
|
379
|
+
| `#body.prepend` | `{ items, headers, ... }` | Contenido antes del tbody |
|
|
380
|
+
| `#body.append` | `{ items, headers, ... }` | Contenido después del tbody |
|
|
381
|
+
| `#prependHeader` | - | Contenido antes de la barra de búsqueda |
|
|
382
|
+
| `#prependSearch` | - | Contenido antes del input de búsqueda |
|
|
383
|
+
| `#appendSearch` | - | Contenido después del input de búsqueda |
|
|
384
|
+
| `#footer` | `{ items, headers, page, itemsPerPage, ... }` | Footer completo personalizado |
|
|
385
|
+
|
|
386
|
+
**Eventos:**
|
|
387
|
+
|
|
388
|
+
| Evento | Payload | Descripción |
|
|
389
|
+
|--------|---------|-------------|
|
|
390
|
+
| `update:page` | `Number` | Cambia la página actual |
|
|
391
|
+
| `update:itemsPerPage` | `Number` | Cambia items por página |
|
|
392
|
+
| `update:sortBy` | `Array` | Cambia criterio de ordenamiento |
|
|
393
|
+
| `update:search` | `String` | Cambia término de búsqueda |
|
|
394
|
+
| `update:selectedItems` | `Array` | Cambia items seleccionados |
|
|
395
|
+
| `focusOnSearch` | `Boolean` | Input de búsqueda enfocado/desenfocado |
|
|
396
|
+
|
|
397
|
+
**Clases personalizables:**
|
|
398
|
+
|
|
399
|
+
| Prop | Tipo | Descripción |
|
|
400
|
+
|------|------|-------------|
|
|
401
|
+
| wrapperClass | String | Clase del contenedor principal |
|
|
402
|
+
| tableClass | String | Clase de la etiqueta `<table>` |
|
|
403
|
+
| theadClass | String | Clase del `<thead>` |
|
|
404
|
+
| tbodyClass | String | Clase del `<tbody>` |
|
|
405
|
+
| tfootClass | String | Clase del `<tfoot>` |
|
|
406
|
+
| trClass | String | Clase de las filas `<tr>` |
|
|
407
|
+
| thClass | String | Clase de los headers `<th>` |
|
|
408
|
+
| tdClass | String/Function | Clase de las celdas `<td>` |
|
|
409
|
+
| rowClass | String | Clase adicional para filas |
|
|
410
|
+
| rowClassCondition | String/Function | Condición para aplicar rowClass |
|
|
411
|
+
| selectedClass | String | Clase para filas seleccionadas |
|
|
412
|
+
| stripedClass | String | Clase para filas alternas (striped) |
|
|
413
|
+
|
|
414
|
+
**Características:**
|
|
415
|
+
|
|
416
|
+
- **Búsqueda global:** Filtra en todas las columnas marcadas como `sortable` o en `searchableKeys`
|
|
417
|
+
- **Filtros por columna:** Modal con KunAutocomplete para filtrar por columnas específicas
|
|
418
|
+
- **Ordenamiento:** Simple o múltiple (con `multiSort`). Soporta strings, números y fechas
|
|
419
|
+
- **Selección:** Individual, por página, o todos los filtrados
|
|
420
|
+
- **Expansión:** Filas expandibles con slot `#expand`
|
|
421
|
+
- **Responsive:** En móvil se transforma a vista de tarjetas (KunTableIterators)
|
|
422
|
+
- **Serialización:** Soporta funciones serializadas via `functionMap` para columnas dinámicas
|
|
423
|
+
|
|
424
|
+
**Ejemplo completo:**
|
|
425
|
+
|
|
426
|
+
```vue
|
|
427
|
+
<template>
|
|
428
|
+
<KunTable
|
|
429
|
+
:items="usuarios"
|
|
430
|
+
:headers="headers"
|
|
431
|
+
:filters="filtros"
|
|
432
|
+
:searchable="true"
|
|
433
|
+
:filterable="true"
|
|
434
|
+
:show-select="true"
|
|
435
|
+
v-model:selectedItems="seleccionados"
|
|
436
|
+
:items-per-page="15"
|
|
437
|
+
>
|
|
438
|
+
<template #item.estado="{ item, value }">
|
|
439
|
+
<KunBadge
|
|
440
|
+
:color="value === 'activo' ? 'bg-green-500' : 'bg-red-500'"
|
|
441
|
+
:text="value"
|
|
442
|
+
/>
|
|
443
|
+
</template>
|
|
444
|
+
|
|
445
|
+
<template #item.actions="{ item, loading }">
|
|
446
|
+
<KunBtn
|
|
447
|
+
icon="mdi-pencil"
|
|
448
|
+
size="xs"
|
|
449
|
+
:loading="loading"
|
|
450
|
+
@click="editar(item)"
|
|
451
|
+
/>
|
|
452
|
+
<KunBtn
|
|
453
|
+
icon="mdi-delete"
|
|
454
|
+
size="xs"
|
|
455
|
+
variant="text"
|
|
456
|
+
@click="eliminar(item)"
|
|
457
|
+
/>
|
|
458
|
+
</template>
|
|
459
|
+
|
|
460
|
+
<template #expand="{ item }">
|
|
461
|
+
<div class="p-4 bg-surface-light">
|
|
462
|
+
<p><strong>Biografía:</strong> {{ item.biografia }}</p>
|
|
463
|
+
</div>
|
|
464
|
+
</template>
|
|
465
|
+
</KunTable>
|
|
466
|
+
</template>
|
|
467
|
+
|
|
468
|
+
<script setup>
|
|
469
|
+
import { ref, computed } from 'vue'
|
|
470
|
+
|
|
471
|
+
const usuarios = ref([
|
|
472
|
+
{ id: 1, nombre: 'Juan', email: 'juan@example.com', rol: 'admin', estado: 'activo' },
|
|
473
|
+
{ id: 2, nombre: 'María', email: 'maria@example.com', rol: 'editor', estado: 'inactivo' },
|
|
474
|
+
])
|
|
475
|
+
|
|
476
|
+
const headers = [
|
|
477
|
+
{ key: 'nombre', value: 'nombre', label: 'Nombre', sortable: true },
|
|
478
|
+
{ key: 'email', value: 'email', label: 'Email', sortable: true },
|
|
479
|
+
{ key: 'rol', value: 'rol', label: 'Rol', sortable: true },
|
|
480
|
+
{ key: 'estado', value: 'estado', label: 'Estado', sortable: true },
|
|
481
|
+
]
|
|
482
|
+
|
|
483
|
+
const filtros = [
|
|
484
|
+
{
|
|
485
|
+
value: 'rol',
|
|
486
|
+
label: 'Rol',
|
|
487
|
+
items: [
|
|
488
|
+
{ id: 1, name: 'Admin' },
|
|
489
|
+
{ id: 2, name: 'Editor' },
|
|
490
|
+
{ id: 3, name: 'Viewer' }
|
|
491
|
+
]
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
value: 'estado',
|
|
495
|
+
label: 'Estado',
|
|
496
|
+
items: [
|
|
497
|
+
{ id: 'activo', name: 'Activo' },
|
|
498
|
+
{ id: 'inactivo', name: 'Inactivo' }
|
|
499
|
+
]
|
|
500
|
+
}
|
|
501
|
+
]
|
|
502
|
+
|
|
503
|
+
const seleccionados = ref([])
|
|
504
|
+
|
|
505
|
+
const editar = (item) => console.log('Editar', item)
|
|
506
|
+
const eliminar = (item) => console.log('Eliminar', item)
|
|
507
|
+
</script>
|
|
508
|
+
```
|
|
289
509
|
|
|
290
510
|
---
|
|
291
511
|
|