@innertia-solutions/ui 0.1.5 → 0.1.6
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/Forms/SelectServer.vue +45 -205
- package/package.json +3 -2
- package/plugins/preline.client.ts +77 -0
|
@@ -1,198 +1,38 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
// Props del componente
|
|
3
3
|
const props = defineProps({
|
|
4
|
-
// Endpoint para la carga
|
|
5
|
-
endpoint: {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
placeholder: {
|
|
37
|
-
type: String,
|
|
38
|
-
required: false,
|
|
39
|
-
default: "Seleccionar opción...",
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
// Size configuration
|
|
43
|
-
size: {
|
|
44
|
-
type: String,
|
|
45
|
-
required: false,
|
|
46
|
-
default: "sm",
|
|
47
|
-
validator: (value) => ["xs", "sm", "md", "lg"].includes(value),
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
// Style configuration
|
|
51
|
-
class: {
|
|
52
|
-
type: String,
|
|
53
|
-
required: false,
|
|
54
|
-
default: "",
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
severity: {
|
|
58
|
-
type: String,
|
|
59
|
-
required: false,
|
|
60
|
-
default: "primary",
|
|
61
|
-
validator: (value) =>
|
|
62
|
-
["primary", "secondary", "success", "danger", "warning", "info"].includes(
|
|
63
|
-
value
|
|
64
|
-
),
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
// Functional properties
|
|
68
|
-
multiple: {
|
|
69
|
-
type: Boolean,
|
|
70
|
-
required: false,
|
|
71
|
-
default: false,
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
searchable: {
|
|
75
|
-
type: Boolean,
|
|
76
|
-
required: false,
|
|
77
|
-
default: false,
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
loading: {
|
|
81
|
-
type: Boolean,
|
|
82
|
-
required: false,
|
|
83
|
-
default: false,
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
disabled: {
|
|
87
|
-
type: Boolean,
|
|
88
|
-
required: false,
|
|
89
|
-
default: false,
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
clearable: {
|
|
93
|
-
type: Boolean,
|
|
94
|
-
required: false,
|
|
95
|
-
default: false,
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
// Search configuration
|
|
99
|
-
searchPlaceholder: {
|
|
100
|
-
type: String,
|
|
101
|
-
required: false,
|
|
102
|
-
default: "Buscar...",
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
minSearchLength: {
|
|
106
|
-
type: Number,
|
|
107
|
-
required: false,
|
|
108
|
-
default: 0,
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
searchLimit: {
|
|
112
|
-
type: Number,
|
|
113
|
-
required: false,
|
|
114
|
-
default: 0,
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
// Multiple selection configuration
|
|
118
|
-
tagsMode: {
|
|
119
|
-
type: Boolean,
|
|
120
|
-
required: false,
|
|
121
|
-
default: false,
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
showCounter: {
|
|
125
|
-
type: Boolean,
|
|
126
|
-
required: false,
|
|
127
|
-
default: false,
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
maxSelection: {
|
|
131
|
-
type: Number,
|
|
132
|
-
required: false,
|
|
133
|
-
default: 0,
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
// Form integration
|
|
137
|
-
name: {
|
|
138
|
-
type: String,
|
|
139
|
-
required: false,
|
|
140
|
-
default: "",
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
// Event control
|
|
144
|
-
emitFocusEvents: {
|
|
145
|
-
type: Boolean,
|
|
146
|
-
required: false,
|
|
147
|
-
default: false,
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
// Validation
|
|
151
|
-
errorMessage: {
|
|
152
|
-
type: String,
|
|
153
|
-
required: false,
|
|
154
|
-
default: "",
|
|
155
|
-
},
|
|
156
|
-
|
|
157
|
-
successMessage: {
|
|
158
|
-
type: String,
|
|
159
|
-
required: false,
|
|
160
|
-
default: "",
|
|
161
|
-
},
|
|
162
|
-
|
|
163
|
-
// Advanced options
|
|
164
|
-
allowEmpty: {
|
|
165
|
-
type: Boolean,
|
|
166
|
-
required: false,
|
|
167
|
-
default: true,
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
closeOnSelect: {
|
|
171
|
-
type: Boolean,
|
|
172
|
-
required: false,
|
|
173
|
-
default: true,
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
// Campo personalizable para mostrar como texto/label
|
|
177
|
-
labelKey: {
|
|
178
|
-
type: String,
|
|
179
|
-
required: false,
|
|
180
|
-
default: "label",
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
// Campo personalizable para el valor real
|
|
184
|
-
valueKey: {
|
|
185
|
-
type: String,
|
|
186
|
-
required: false,
|
|
187
|
-
default: "id",
|
|
188
|
-
},
|
|
189
|
-
|
|
190
|
-
// Campo personalizable para descripción adicional
|
|
191
|
-
descriptionKey: {
|
|
192
|
-
type: String,
|
|
193
|
-
required: false,
|
|
194
|
-
default: "description",
|
|
195
|
-
},
|
|
4
|
+
// Endpoint para la carga desde API
|
|
5
|
+
endpoint: { type: String, required: true },
|
|
6
|
+
listFormat: { type: Boolean, default: true },
|
|
7
|
+
perPage: { type: Number, default: 15 },
|
|
8
|
+
initialOptions: { type: Array, default: () => [] },
|
|
9
|
+
|
|
10
|
+
// v-model
|
|
11
|
+
modelValue: { type: [String, Number, Array, Object], default: null },
|
|
12
|
+
|
|
13
|
+
// Form wrapper
|
|
14
|
+
label: { type: String, default: "" },
|
|
15
|
+
placeholder: { type: String, default: "Seleccionar..." },
|
|
16
|
+
hint: { type: String, default: "" },
|
|
17
|
+
error: { type: String, default: "" },
|
|
18
|
+
|
|
19
|
+
// Functional
|
|
20
|
+
multiple: { type: Boolean, default: false },
|
|
21
|
+
searchable: { type: Boolean, default: true },
|
|
22
|
+
disabled: { type: Boolean, default: false },
|
|
23
|
+
clearable: { type: Boolean, default: false },
|
|
24
|
+
searchPlaceholder: { type: String, default: "Buscar..." },
|
|
25
|
+
minSearchLength: { type: Number, default: 0 },
|
|
26
|
+
tagsMode: { type: Boolean, default: false },
|
|
27
|
+
showCounter: { type: Boolean, default: false },
|
|
28
|
+
maxSelection: { type: Number, default: 0 },
|
|
29
|
+
allowEmpty: { type: Boolean, default: true },
|
|
30
|
+
closeOnSelect: { type: Boolean, default: true },
|
|
31
|
+
|
|
32
|
+
// Claves de campo
|
|
33
|
+
labelKey: { type: String, default: "name" },
|
|
34
|
+
valueKey: { type: String, default: "id" },
|
|
35
|
+
descriptionKey: { type: String, default: "description" },
|
|
196
36
|
});
|
|
197
37
|
|
|
198
38
|
// Emits
|
|
@@ -490,13 +330,8 @@ const sizeClasses = computed(() => {
|
|
|
490
330
|
|
|
491
331
|
// Computed classes for validation states
|
|
492
332
|
const validationClasses = computed(() => {
|
|
493
|
-
if (props.
|
|
494
|
-
|
|
495
|
-
}
|
|
496
|
-
if (props.successMessage) {
|
|
497
|
-
return "border-emerald-500";
|
|
498
|
-
}
|
|
499
|
-
return "border-gray-200 dark:border-slate-700";
|
|
333
|
+
if (props.error) return "border-red-400 dark:border-red-500";
|
|
334
|
+
return "border-slate-200 dark:border-slate-700";
|
|
500
335
|
});
|
|
501
336
|
|
|
502
337
|
// Combined select classes
|
|
@@ -662,6 +497,12 @@ onMounted(() => {
|
|
|
662
497
|
</script>
|
|
663
498
|
|
|
664
499
|
<template>
|
|
500
|
+
<div class="space-y-1.5">
|
|
501
|
+
<!-- Label -->
|
|
502
|
+
<label v-if="label" class="block text-sm font-medium text-slate-700 dark:text-slate-300">
|
|
503
|
+
{{ label }}
|
|
504
|
+
</label>
|
|
505
|
+
|
|
665
506
|
<div class="relative" ref="selectRef">
|
|
666
507
|
<!-- Hidden input for form integration -->
|
|
667
508
|
<input v-if="name" type="hidden" :name="name" :value="multiple
|
|
@@ -876,11 +717,10 @@ onMounted(() => {
|
|
|
876
717
|
</Transition>
|
|
877
718
|
|
|
878
719
|
<!-- Validation messages -->
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
<
|
|
883
|
-
|
|
884
|
-
</div>
|
|
720
|
+
</div>
|
|
721
|
+
|
|
722
|
+
<!-- Error / Hint -->
|
|
723
|
+
<p v-if="error" class="text-xs text-red-500 dark:text-red-400">{{ error }}</p>
|
|
724
|
+
<p v-else-if="hint" class="text-xs text-slate-400 dark:text-slate-500">{{ hint }}</p>
|
|
885
725
|
</div>
|
|
886
726
|
</template>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@innertia-solutions/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Innertia Solutions — Nuxt UI layer: components and composables",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nuxt",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"nuxt": ">=3.0.0",
|
|
25
|
-
"vue": ">=3.0.0"
|
|
25
|
+
"vue": ">=3.0.0",
|
|
26
|
+
"preline": ">=2.0.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"nuxt": "^3.16.0",
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
HSStaticMethods?: { autoInit?: () => void }
|
|
4
|
+
HSSelect?: new (el: HTMLElement) => { destroy?: () => void }
|
|
5
|
+
HSThemeAppearance?: { init?: () => void }
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default defineNuxtPlugin(async () => {
|
|
10
|
+
if (!process.client) return
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
await import('preline')
|
|
14
|
+
|
|
15
|
+
const initPreline = () => {
|
|
16
|
+
try { window.HSStaticMethods?.autoInit?.() } catch (_) {}
|
|
17
|
+
try { window.HSThemeAppearance?.init?.() } catch (_) {}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const performMultipleInits = () => {
|
|
21
|
+
initPreline()
|
|
22
|
+
setTimeout(initPreline, 50)
|
|
23
|
+
setTimeout(initPreline, 200)
|
|
24
|
+
setTimeout(initPreline, 500)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Inicialización inicial
|
|
28
|
+
if (document.readyState === 'loading') {
|
|
29
|
+
document.addEventListener('DOMContentLoaded', performMultipleInits)
|
|
30
|
+
} else {
|
|
31
|
+
nextTick(performMultipleInits)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const nuxtApp = useNuxtApp()
|
|
35
|
+
|
|
36
|
+
// Re-inicializar en cada cambio de página
|
|
37
|
+
nuxtApp.hooks.hook('page:finish', () => {
|
|
38
|
+
requestAnimationFrame(performMultipleInits)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
nuxtApp.hooks.hookOnce('app:mounted', () => {
|
|
42
|
+
performMultipleInits()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// MutationObserver: reinicializar cuando aparezcan elementos Preline en el DOM
|
|
46
|
+
const observer = new MutationObserver((mutations) => {
|
|
47
|
+
const hasPreline = mutations.some(({ addedNodes }) =>
|
|
48
|
+
Array.from(addedNodes).some((node) => {
|
|
49
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return false
|
|
50
|
+
const el = node as Element
|
|
51
|
+
return (
|
|
52
|
+
el.querySelector?.('[data-hs-overlay],[data-hs-dropdown],[data-hs-select]') ||
|
|
53
|
+
el.hasAttribute?.('data-hs-overlay') ||
|
|
54
|
+
el.hasAttribute?.('data-hs-dropdown') ||
|
|
55
|
+
el.hasAttribute?.('data-hs-select') ||
|
|
56
|
+
(typeof el.className === 'string' && el.className.includes('hs-'))
|
|
57
|
+
)
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
if (hasPreline) {
|
|
61
|
+
setTimeout(initPreline, 10)
|
|
62
|
+
setTimeout(initPreline, 100)
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
if (document.readyState === 'loading') {
|
|
67
|
+
document.addEventListener('DOMContentLoaded', () =>
|
|
68
|
+
observer.observe(document.body, { childList: true, subtree: true })
|
|
69
|
+
)
|
|
70
|
+
} else {
|
|
71
|
+
observer.observe(document.body, { childList: true, subtree: true })
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.warn('[innertia-ui] Error al cargar Preline:', e)
|
|
76
|
+
}
|
|
77
|
+
})
|