innoboxrr-vue-datatable 2.3.0 → 3.0.0
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/README.md +130 -168
- package/index.js +13 -2
- package/package.json +6 -4
- package/src/DataTable.vue +249 -424
- package/src/components/DataTableComponent.vue +218 -174
- package/src/components/SelectPaginationComponent.vue +78 -93
- package/src/table.js +251 -0
- package/src/useDataTable.js +370 -0
- package/src/useTheme.js +20 -0
- package/src/components/DisabledLinkComponent.vue +0 -45
- package/src/components/IconLinkComponent.vue +0 -81
- package/src/components/IconRouteComponent.vue +0 -84
- package/src/components/NavDropdownComponent.vue +0 -118
- package/src/components/PaginationComponent.vue +0 -79
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
<a
|
|
4
|
-
class="block px-4 py-2 dark:hover:text-white dark:text-slate-400"
|
|
5
|
-
:href="link"
|
|
6
|
-
:target="target">
|
|
7
|
-
|
|
8
|
-
<Icon
|
|
9
|
-
class="fe-mr-sm"
|
|
10
|
-
:icon="resolved"
|
|
11
|
-
:width="size"
|
|
12
|
-
:height="size"
|
|
13
|
-
aria-hidden="true" />
|
|
14
|
-
|
|
15
|
-
<span :class="textClass">{{ text }}</span>
|
|
16
|
-
|
|
17
|
-
</a>
|
|
18
|
-
|
|
19
|
-
</template>
|
|
20
|
-
|
|
21
|
-
<script setup>
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Antes esto pintaba `<span class="uk-icon" uk-icon="icon: fa-plus">` y
|
|
25
|
-
* llamaba a `globalThis.UIkit.update()` al montar. Para que ese icono
|
|
26
|
-
* apareciera hacian falta tres dependencias que ningun package.json
|
|
27
|
-
* declaraba: uikit, fontawesome y uikit-custom-icons, que hacia de puente
|
|
28
|
-
* entre las dos.
|
|
29
|
-
*
|
|
30
|
-
* Ahora el nombre se resuelve contra el mapa de innoboxrr-form-core, que
|
|
31
|
-
* es el mismo que usa la rama React.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
import { computed, onScopeDispose, ref } from 'vue'
|
|
35
|
-
import { Icon } from '@iconify/vue'
|
|
36
|
-
import { iconFor, onIconChange } from 'innoboxrr-form-core'
|
|
37
|
-
|
|
38
|
-
const props = defineProps({
|
|
39
|
-
link: {
|
|
40
|
-
type: String,
|
|
41
|
-
default: '#'
|
|
42
|
-
},
|
|
43
|
-
text: {
|
|
44
|
-
type: String,
|
|
45
|
-
required: true
|
|
46
|
-
},
|
|
47
|
-
icon: {
|
|
48
|
-
type: String,
|
|
49
|
-
required: true
|
|
50
|
-
},
|
|
51
|
-
ratio: {
|
|
52
|
-
type: Number,
|
|
53
|
-
required: false,
|
|
54
|
-
default: 1
|
|
55
|
-
},
|
|
56
|
-
textClass: {
|
|
57
|
-
type: String,
|
|
58
|
-
default: ""
|
|
59
|
-
},
|
|
60
|
-
target: {
|
|
61
|
-
type: String,
|
|
62
|
-
default: "_self"
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// Un cambio de mapa en caliente repinta lo ya montado.
|
|
67
|
-
const version = ref(0)
|
|
68
|
-
|
|
69
|
-
onScopeDispose(onIconChange(() => version.value++))
|
|
70
|
-
|
|
71
|
-
const resolved = computed(() => {
|
|
72
|
-
version.value
|
|
73
|
-
|
|
74
|
-
return iconFor(props.icon)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
// `ratio` era el multiplicador de UIkit sobre 16px. Se conserva para no
|
|
78
|
-
// romper a quien ya lo pasa.
|
|
79
|
-
const size = computed(() => props.ratio * 16)
|
|
80
|
-
|
|
81
|
-
</script>
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
<router-link
|
|
4
|
-
:to="pathObject"
|
|
5
|
-
class="block px-4 py-2 dark:hover:text-white dark:text-slate-400">
|
|
6
|
-
|
|
7
|
-
<Icon
|
|
8
|
-
class="fe-mr-sm"
|
|
9
|
-
:icon="resolved"
|
|
10
|
-
:width="size"
|
|
11
|
-
:height="size"
|
|
12
|
-
aria-hidden="true" />
|
|
13
|
-
|
|
14
|
-
<span :class="textClass">{{ text }}</span>
|
|
15
|
-
|
|
16
|
-
</router-link>
|
|
17
|
-
|
|
18
|
-
</template>
|
|
19
|
-
|
|
20
|
-
<script setup>
|
|
21
|
-
|
|
22
|
-
import { computed, onScopeDispose, ref } from 'vue'
|
|
23
|
-
import { Icon } from '@iconify/vue'
|
|
24
|
-
import { iconFor, onIconChange } from 'innoboxrr-form-core'
|
|
25
|
-
|
|
26
|
-
const props = defineProps({
|
|
27
|
-
name: {
|
|
28
|
-
type: String,
|
|
29
|
-
required: true
|
|
30
|
-
},
|
|
31
|
-
// Vue 3 exige factoria en los defaults de objeto: un literal comparte
|
|
32
|
-
// la misma instancia entre todas las filas de la tabla.
|
|
33
|
-
params: {
|
|
34
|
-
type: Object,
|
|
35
|
-
default: () => ({})
|
|
36
|
-
},
|
|
37
|
-
query: {
|
|
38
|
-
type: Object,
|
|
39
|
-
default: () => ({})
|
|
40
|
-
},
|
|
41
|
-
text: {
|
|
42
|
-
type: String,
|
|
43
|
-
required: true
|
|
44
|
-
},
|
|
45
|
-
icon: {
|
|
46
|
-
type: String,
|
|
47
|
-
required: true
|
|
48
|
-
},
|
|
49
|
-
ratio: {
|
|
50
|
-
type: Number,
|
|
51
|
-
required: false,
|
|
52
|
-
default: 1
|
|
53
|
-
},
|
|
54
|
-
textClass: {
|
|
55
|
-
type: String,
|
|
56
|
-
default: ""
|
|
57
|
-
},
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
// Estaba en data(), asi que se calculaba una sola vez al crear el
|
|
61
|
-
// componente: al reutilizar la fila para otro registro el enlace seguia
|
|
62
|
-
// apuntando al anterior.
|
|
63
|
-
const pathObject = computed(() => ({
|
|
64
|
-
name: props.name,
|
|
65
|
-
params: props.params,
|
|
66
|
-
query: props.query,
|
|
67
|
-
}))
|
|
68
|
-
|
|
69
|
-
// Un cambio de mapa en caliente repinta lo ya montado.
|
|
70
|
-
const version = ref(0)
|
|
71
|
-
|
|
72
|
-
onScopeDispose(onIconChange(() => version.value++))
|
|
73
|
-
|
|
74
|
-
const resolved = computed(() => {
|
|
75
|
-
version.value
|
|
76
|
-
|
|
77
|
-
return iconFor(props.icon)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
// `ratio` era el multiplicador de UIkit sobre 16px. Se conserva para no
|
|
81
|
-
// romper a quien ya lo pasa.
|
|
82
|
-
const size = computed(() => props.ratio * 16)
|
|
83
|
-
|
|
84
|
-
</script>
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
<div
|
|
4
|
-
:id="id"
|
|
5
|
-
ref="panel"
|
|
6
|
-
popover
|
|
7
|
-
:class="classFor('menu')"
|
|
8
|
-
@beforetoggle="onBeforeToggle">
|
|
9
|
-
|
|
10
|
-
<ul class="fe-menu-list">
|
|
11
|
-
|
|
12
|
-
<slot></slot>
|
|
13
|
-
|
|
14
|
-
</ul>
|
|
15
|
-
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
</template>
|
|
19
|
-
|
|
20
|
-
<script setup>
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* El menu de acciones de una fila.
|
|
24
|
-
*
|
|
25
|
-
* Antes lo movia `uk-dropdown`, que ademas de la clase traia el JavaScript
|
|
26
|
-
* de UIkit: abrir, cerrar al pulsar fuera, cerrar con Escape, capa
|
|
27
|
-
* superior y posicionamiento, todo dentro de un framework de 12 MB que
|
|
28
|
-
* ningun package.json declaraba.
|
|
29
|
-
*
|
|
30
|
-
* La mitad de eso ya lo hace el navegador. La **Popover API** —el atributo
|
|
31
|
-
* `popover` y el `popovertarget` del boton— aporta de fabrica la capa
|
|
32
|
-
* superior, el cierre al pulsar fuera y el cierre con Escape, sin una
|
|
33
|
-
* linea de JavaScript. Lo unico que falta es colocarlo, y de eso se ocupa
|
|
34
|
-
* Floating UI, que son unos 6 kB y es la pieza que usan por debajo Reka
|
|
35
|
-
* UI, Radix y el propio Flowbite.
|
|
36
|
-
*
|
|
37
|
-
* El boton que lo abre solo necesita `popovertarget` con este mismo id:
|
|
38
|
-
*
|
|
39
|
-
* <button :popovertarget="`dropdown_${row.id}`">…</button>
|
|
40
|
-
* <NavDropdownComponent :id="`dropdown_${row.id}`" pos="left" />
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
import { computed, ref } from 'vue'
|
|
44
|
-
import { autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/dom'
|
|
45
|
-
import { classFor } from 'innoboxrr-form-core'
|
|
46
|
-
|
|
47
|
-
const props = defineProps({
|
|
48
|
-
id: {
|
|
49
|
-
type: String,
|
|
50
|
-
required: true,
|
|
51
|
-
},
|
|
52
|
-
// Se conservan los nombres que usaba UIkit para no romper a quien ya
|
|
53
|
-
// los pasa; `bottom-left` y compania se traducen a los de Floating UI.
|
|
54
|
-
pos: {
|
|
55
|
-
type: String,
|
|
56
|
-
default: 'bottom-left',
|
|
57
|
-
},
|
|
58
|
-
offset: {
|
|
59
|
-
type: Number,
|
|
60
|
-
default: 4,
|
|
61
|
-
},
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
const panel = ref(null)
|
|
65
|
-
|
|
66
|
-
/** Deja de seguir al disparador cuando el menu se cierra. */
|
|
67
|
-
let stopFollowing = null
|
|
68
|
-
|
|
69
|
-
const placement = computed(() => {
|
|
70
|
-
const [side, align] = props.pos.split('-')
|
|
71
|
-
|
|
72
|
-
if (! align) {
|
|
73
|
-
return side
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// UIkit dice `bottom-left` para «debajo, alineado a la izquierda»;
|
|
77
|
-
// Floating UI lo llama `bottom-start`.
|
|
78
|
-
return `${side}-${align === 'left' ? 'start' : 'end'}`
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
const onBeforeToggle = (event) => {
|
|
82
|
-
if (event.newState !== 'open') {
|
|
83
|
-
stopFollowing?.()
|
|
84
|
-
stopFollowing = null
|
|
85
|
-
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// El boton es quien apunta a este panel, asi que se encuentra por el
|
|
90
|
-
// atributo y no hace falta que nadie lo pase como prop.
|
|
91
|
-
const trigger = document.querySelector(`[popovertarget="${props.id}"]`)
|
|
92
|
-
|
|
93
|
-
if (! trigger || ! panel.value) {
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// autoUpdate recoloca al hacer scroll o redimensionar: un menu abierto
|
|
98
|
-
// que se queda flotando donde estaba es peor que uno mal colocado.
|
|
99
|
-
stopFollowing = autoUpdate(trigger, panel.value, () => {
|
|
100
|
-
computePosition(trigger, panel.value, {
|
|
101
|
-
placement: placement.value,
|
|
102
|
-
middleware: [
|
|
103
|
-
offset(props.offset),
|
|
104
|
-
// Si no cabe abajo, se va arriba; si se sale por un lado,
|
|
105
|
-
// se desplaza para caber.
|
|
106
|
-
flip(),
|
|
107
|
-
shift({ padding: 8 }),
|
|
108
|
-
],
|
|
109
|
-
}).then(({ x, y }) => {
|
|
110
|
-
Object.assign(panel.value.style, {
|
|
111
|
-
left: `${x}px`,
|
|
112
|
-
top: `${y}px`,
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
</script>
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
<ul v-if="length > 3" class="fe-pagination fe-justify-center" fe-mb>
|
|
4
|
-
|
|
5
|
-
<li v-if="firstLink != null">
|
|
6
|
-
|
|
7
|
-
<a href="#" @click="emit('go', firstLink)">
|
|
8
|
-
|
|
9
|
-
<span fe-page-prev></span>
|
|
10
|
-
|
|
11
|
-
</a>
|
|
12
|
-
|
|
13
|
-
</li>
|
|
14
|
-
|
|
15
|
-
<li
|
|
16
|
-
v-for="link in middleLinks"
|
|
17
|
-
:key="link.label"
|
|
18
|
-
:class="{ 'fe-disabled': link.url == null, 'fe-active': link.active, }">
|
|
19
|
-
|
|
20
|
-
<a href="#" @click="emit('go', link.url)">
|
|
21
|
-
|
|
22
|
-
{{ link.label }}
|
|
23
|
-
|
|
24
|
-
</a>
|
|
25
|
-
|
|
26
|
-
</li>
|
|
27
|
-
|
|
28
|
-
<li v-if="lastLink != null">
|
|
29
|
-
|
|
30
|
-
<a href="#" @click="emit('go', lastLink)">
|
|
31
|
-
|
|
32
|
-
<span fe-page-next></span>
|
|
33
|
-
|
|
34
|
-
</a>
|
|
35
|
-
|
|
36
|
-
</li>
|
|
37
|
-
|
|
38
|
-
</ul>
|
|
39
|
-
|
|
40
|
-
</template>
|
|
41
|
-
|
|
42
|
-
<script setup>
|
|
43
|
-
|
|
44
|
-
import { computed } from 'vue'
|
|
45
|
-
|
|
46
|
-
const props = defineProps({
|
|
47
|
-
links: {
|
|
48
|
-
type: Array,
|
|
49
|
-
required: true,
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
const emit = defineEmits(['go'])
|
|
54
|
-
|
|
55
|
-
const length = computed(() => props.links.length)
|
|
56
|
-
|
|
57
|
-
const firstLink = computed(() => length.value > 0 ? props.links[0].url : null)
|
|
58
|
-
|
|
59
|
-
const lastLink = computed(() => {
|
|
60
|
-
|
|
61
|
-
const last = props.links[length.value - 1]
|
|
62
|
-
|
|
63
|
-
return length.value > 0 && last !== undefined ? last.url : null
|
|
64
|
-
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
const middleLinks = computed(() => props.links.slice(1, -1))
|
|
68
|
-
|
|
69
|
-
</script>
|
|
70
|
-
|
|
71
|
-
<style scoped>
|
|
72
|
-
|
|
73
|
-
.fe-pagination > .fe-active > * {
|
|
74
|
-
color: #666;
|
|
75
|
-
font-weight: 600;
|
|
76
|
-
border-bottom: 3px solid var(--primary-color);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
</style>
|