@luis-angel-martin-dzul/input-styles 0.0.1 → 0.0.2
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 +810 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,3 +1,812 @@
|
|
|
1
1
|
# 📦 Input Style
|
|
2
2
|
|
|
3
|
-
**Librería de componentes y formularios Vue 3**
|
|
3
|
+
**Librería de componentes y formularios Vue 3**
|
|
4
|
+
|
|
5
|
+
Incluye componentes de inputs, selects, botones, paginación y más, estilizados con TailwindCSS y listos para producción.
|
|
6
|
+
|
|
7
|
+
------
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
------
|
|
12
|
+
|
|
13
|
+
# 📦 Instalación
|
|
14
|
+
|
|
15
|
+
La librería se distribuye mediante **npm**:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npm install @luis-angel-martin-dzul/input-styles
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Dependencias peer requeridas
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
npm install vue@^3.3.0 v-calendar@^3.0.0
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
------
|
|
28
|
+
|
|
29
|
+
# 🚀 Uso en Vue + Vite
|
|
30
|
+
|
|
31
|
+
En `main.js` o `main.ts`:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import { createApp } from 'vue'
|
|
35
|
+
import App from './App.vue'
|
|
36
|
+
|
|
37
|
+
import 'v-calendar/style.css'
|
|
38
|
+
import { library } from '@fortawesome/fontawesome-svg-core'
|
|
39
|
+
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
|
40
|
+
import {
|
|
41
|
+
faCircleCheck, faCircleXmark, faEye, faEyeSlash,
|
|
42
|
+
faCalendar, faClock, faChevronDown,
|
|
43
|
+
faCloudArrowUp, faCloudArrowDown, faSpinner, faCheck
|
|
44
|
+
} from '@fortawesome/free-solid-svg-icons'
|
|
45
|
+
import VCalendar from 'v-calendar'
|
|
46
|
+
|
|
47
|
+
library.add(
|
|
48
|
+
faCircleCheck, faCircleXmark, faEye, faEyeSlash,
|
|
49
|
+
faCalendar, faClock, faChevronDown,
|
|
50
|
+
faCloudArrowUp, faCloudArrowDown, faSpinner, faCheck
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const app = createApp(App)
|
|
54
|
+
|
|
55
|
+
app.component('font-awesome-icon', FontAwesomeIcon)
|
|
56
|
+
app.use(VCalendar, { locale: 'es', firstDayOfWeek: 1 })
|
|
57
|
+
app.mount('#app')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
------
|
|
61
|
+
|
|
62
|
+
# 🎨 Estilos personalizados (Style Registry)
|
|
63
|
+
|
|
64
|
+
La librería expone un sistema de **tokens de estilo configurables** que permite cambiar la apariencia de todos los componentes desde un solo lugar, sin necesidad de modificar el código fuente.
|
|
65
|
+
|
|
66
|
+
Los estilos se configuran **antes de montar la app**, importando `configureStyles` directamente.
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
import { configureStyles } from '@luis-angel-martin-dzul/input-styles'
|
|
70
|
+
|
|
71
|
+
configureStyles({
|
|
72
|
+
LOADER_ARC_STROKE: '#3B82F6',
|
|
73
|
+
REQUIRED_ASTERISK: 'text-red-500',
|
|
74
|
+
// solo los tokens que quieras cambiar
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> ⚠️ `configureStyles()` debe llamarse **antes** de que los componentes se monten. Los cambios no son reactivos después del montaje inicial.
|
|
79
|
+
|
|
80
|
+
------
|
|
81
|
+
|
|
82
|
+
## 📋 Referencia completa de tokens
|
|
83
|
+
|
|
84
|
+
### Tokens auxiliares de label
|
|
85
|
+
_Afecta: todos los componentes que tienen `label` o `description`_
|
|
86
|
+
|
|
87
|
+
Estos tokens controlan partes individuales del label y del texto descriptivo. Al sobrescribir uno, las funciones `inputLabelClass`, `inputCheckLabelClass` e `inputDescriptionClass` lo recogen automáticamente **sin necesidad de sobreescribir la función entera**.
|
|
88
|
+
|
|
89
|
+
| Token | Tipo | Default | Descripción |
|
|
90
|
+
| ----- | ---- | ------- | ----------- |
|
|
91
|
+
| `INPUT_BASE_TITLE` | `string` | `'block text-sm font-medium'` | Clases estructurales del `<label>` de inputs de texto. |
|
|
92
|
+
| `INPUT_CHECK_BASE_TITLE` | `string` | `'block text-sm font-medium'` | Clases estructurales del `<label>` de checkbox, radio y switch. |
|
|
93
|
+
| `LABEL_DISABLED_STATIC` | `string` | `'text-gray-400'` | Color del label y descripción cuando el campo está deshabilitado. |
|
|
94
|
+
| `LABEL_ENABLED_STATIC` | `string` | `'text-gray-700'` | Color del label cuando el campo está habilitado. |
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
configureStyles({
|
|
98
|
+
LABEL_DISABLED_STATIC: 'text-gray-400',
|
|
99
|
+
LABEL_ENABLED_STATIC: 'text-gray-900',
|
|
100
|
+
INPUT_BASE_TITLE: 'block font-semibold mb-1 text-sm',
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### Inputs de texto
|
|
107
|
+
_Afecta: `InputTextStyle`, `InputNumberStyle`, `InputPasswordStyle`, `TextAreaStyle`, `InputDateStyle`, `InputTimeStyle`, `SelectStyle`_
|
|
108
|
+
|
|
109
|
+
| Token | Tipo | Default | Descripción |
|
|
110
|
+
| ----- | ---- | ------- | ----------- |
|
|
111
|
+
| `INPUT_BASE` | `string` | `'w-full text-gray-800 bg-white px-3 py-1.5 rounded border ...'` | Clases base del `<input>`. No incluye borde ni ring (eso lo maneja `inputValidateClass`). |
|
|
112
|
+
| `inputValidateClass` | `function(validate)` | Ver abajo | Retorna las clases de borde y ring según el estado de validación. `validate`: `true` / `false` / `null`. |
|
|
113
|
+
| `inputLabelClass` | `function(disabled)` | Ver abajo | Retorna las clases del `<label>`. Internamente usa `INPUT_BASE_TITLE`, `LABEL_DISABLED_STATIC` y `LABEL_ENABLED_STATIC`. |
|
|
114
|
+
| `inputDescriptionClass` | `function(validate, alignRight?)` | Ver abajo | Retorna las clases del texto de descripción. Internamente usa `ICON_VALID`, `ICON_INVALID` y `LABEL_DISABLED_STATIC`. |
|
|
115
|
+
|
|
116
|
+
> 💡 Si solo quieres cambiar un color de validación, basta con sobrescribir `ICON_INVALID` o `ICON_VALID` — `inputDescriptionClass` los recoge automáticamente.
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
configureStyles({
|
|
120
|
+
ICON_INVALID: 'text-red-500',
|
|
121
|
+
ICON_VALID: 'text-emerald-500',
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// Override completo de las funciones (cuando necesitas control total)
|
|
125
|
+
configureStyles({
|
|
126
|
+
inputValidateClass: (validate) => {
|
|
127
|
+
if (validate === false) return 'border-red-500 focus:ring-red-200'
|
|
128
|
+
if (validate === true) return 'border-emerald-500 focus:ring-emerald-200'
|
|
129
|
+
return 'border-gray-200 focus:ring-indigo-200'
|
|
130
|
+
},
|
|
131
|
+
inputLabelClass: (disabled) => ['block font-bold mb-2', disabled ? 'text-gray-400' : 'text-gray-900'],
|
|
132
|
+
inputDescriptionClass: (validate, alignRight = true) => [
|
|
133
|
+
'block w-full text-sm',
|
|
134
|
+
alignRight && 'text-right',
|
|
135
|
+
validate === false ? 'text-red-500' : validate === true ? 'text-emerald-500' : 'text-gray-500',
|
|
136
|
+
],
|
|
137
|
+
})
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### Select
|
|
143
|
+
_Afecta: `SelectStyle`_
|
|
144
|
+
|
|
145
|
+
| Token | Tipo | Default | Descripción |
|
|
146
|
+
| ----- | ---- | ------- | ----------- |
|
|
147
|
+
| `SELECT_DISABLED` | `string` | `'w-full px-3 py-1.5 rounded bg-gray-100 ...'` | Clases del input en estado disabled. |
|
|
148
|
+
| `SELECT_DROPDOWN` | `string` | `'absolute z-20 w-full bg-white border ...'` | Clases del contenedor `<ul>` del dropdown. |
|
|
149
|
+
| `SELECT_OPTION_BASE` | `string` | `'px-3 py-1 cursor-pointer text-md'` | Clases base de cada `<li>` del dropdown. |
|
|
150
|
+
| `selectOptionClass` | `function(isSelected, isHighlighted)` | Ver abajo | Retorna clases dinámicas por opción según su estado. |
|
|
151
|
+
| `SELECT_EMPTY` | `string` | `'px-3 py-1 text-gray-400 cursor-not-allowed'` | Clases del mensaje "Sin registros". |
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
configureStyles({
|
|
155
|
+
selectOptionClass: (isSelected, isHighlighted) => {
|
|
156
|
+
if (isSelected) return 'bg-indigo-100 text-indigo-900 font-medium'
|
|
157
|
+
if (isHighlighted) return 'bg-indigo-50 text-gray-900'
|
|
158
|
+
return 'hover:bg-indigo-50 text-gray-800'
|
|
159
|
+
},
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### Checkbox, Radio y Switch
|
|
166
|
+
_Afecta: `InputCheckStyle`, `InputRadioStyle`, `InputSwitchStyle`_
|
|
167
|
+
|
|
168
|
+
| Token | Tipo | Default | Descripción |
|
|
169
|
+
| ----- | ---- | ------- | ----------- |
|
|
170
|
+
| `inputCheckLabelClass` | `function(disabled)` | Ver abajo | Clases del label de checks. |
|
|
171
|
+
| `CHECK_BOX_BASE` | `string` | `'w-5 h-5 flex items-center justify-center rounded border-2 transition'` | Estructura base del cuadro del checkbox. |
|
|
172
|
+
| `RADIO_BASE` | `string` | `'w-5 h-5 flex items-center justify-center rounded-full transition'` | Estructura base del círculo del radio. |
|
|
173
|
+
| `SWITCH_BASE` | `string` | `'w-10 h-5 relative flex items-center rounded-full transition border-2'` | Estructura base de la pista del switch. |
|
|
174
|
+
| `checkBoxClass` | `function(model, disabled)` | Ver abajo | Clases de color del checkbox según estado activo/disabled. |
|
|
175
|
+
| `radioClass` | `function(model, disabled)` | Ver abajo | Clases de color del radio button según estado. |
|
|
176
|
+
| `switchClass` | `function(model, disabled)` | Ver abajo | Clases de color de la pista del switch. |
|
|
177
|
+
| `switchDotClass` | `function(model, disabled)` | Ver abajo | Clases de color de la bola interior del switch. |
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
configureStyles({
|
|
181
|
+
checkBoxClass: (model, disabled) => {
|
|
182
|
+
if (disabled) return model
|
|
183
|
+
? 'bg-indigo-200 border-indigo-200 cursor-not-allowed'
|
|
184
|
+
: 'bg-gray-100 border-gray-200 cursor-not-allowed'
|
|
185
|
+
return model
|
|
186
|
+
? 'bg-indigo-500 border-indigo-500 peer-focus:ring-2 peer-focus:ring-indigo-200'
|
|
187
|
+
: 'bg-white border-gray-300 peer-focus:ring-2 peer-focus:ring-indigo-200'
|
|
188
|
+
},
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
### Paginación
|
|
195
|
+
_Afecta: `PaginationStyle`_
|
|
196
|
+
|
|
197
|
+
| Token | Tipo | Default | Descripción |
|
|
198
|
+
| ----- | ---- | ------- | ----------- |
|
|
199
|
+
| `PAGINATION_NAV_PREV` | `string` | `'bg-white hover:bg-indigo-50 border ...'` | Clases del botón de página anterior. |
|
|
200
|
+
| `PAGINATION_NAV_NEXT` | `string` | `'bg-white hover:bg-indigo-50 border ...'` | Clases del botón de página siguiente. |
|
|
201
|
+
| `PAGINATION_PAGE_BASE` | `string` | `'border px-2.5 py-2 cursor-pointer w-8 relative'` | Clases base de cada botón de página. |
|
|
202
|
+
| `paginationPageClass` | `function(page, actualPage, index)` | Ver abajo | Retorna clases dinámicas por botón de página. |
|
|
203
|
+
| `PAGINATION_SUMMARY` | `string` | `'text-sm text-gray-700'` | Clases del texto de resumen de registros. |
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### Loader
|
|
208
|
+
_Afecta: `LoaderStyle`_
|
|
209
|
+
|
|
210
|
+
| Token | Tipo | Default | Descripción |
|
|
211
|
+
| ----- | ---- | ------- | ----------- |
|
|
212
|
+
| `LOADER_ARC_STROKE` | `string` | `'#6366F1'` | Color hex del arco animado del loader (indigo-500). |
|
|
213
|
+
| `LOADER_MESSAGE` | `string` | `'text-gray-600 text-lg font-medium'` | Clases del mensaje de carga. |
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### Iconos y asterisco de requerido
|
|
218
|
+
_Afecta: todos los componentes con `required` o iconos de validación_
|
|
219
|
+
|
|
220
|
+
| Token | Tipo | Default | Descripción |
|
|
221
|
+
| ----- | ---- | ------- | ----------- |
|
|
222
|
+
| `REQUIRED_ASTERISK` | `string` | `'text-red-500'` | Clase de color del asterisco `*` en campos requeridos. |
|
|
223
|
+
| `ICON_VALID` | `string` | `'text-emerald-500'` | Clase de color del ícono de validación correcta. |
|
|
224
|
+
| `ICON_INVALID` | `string` | `'text-red-500'` | Clase de color del ícono de validación errónea. |
|
|
225
|
+
| `ICON_STATIC` | `string` | `'text-indigo-400'` | Clase de color de los íconos estáticos (reloj, calendario, ojo, chevron). |
|
|
226
|
+
| `ICON_SIZE_STATIC` | `string` | `'w-5 h-5'` | Clases de tamaño de todos los íconos. |
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
### File Upload y Download
|
|
231
|
+
_Afecta: `InputFileUploadStyle`, `InputFileDownloadStyle`_
|
|
232
|
+
|
|
233
|
+
| Token | Tipo | Default | Descripción |
|
|
234
|
+
| ----- | ---- | ------- | ----------- |
|
|
235
|
+
| `FILE_BUTTON_BASE` | `string` | `'flex items-center justify-center gap-3 px-4 py-2 border-2 rounded-xl ...'` | Clases estructurales del botón (compartido entre upload y download). |
|
|
236
|
+
| `FILE_BUTTON_ACTIVE` | `string` | `'border-gray-200 bg-white text-gray-700 hover:border-indigo-400 ...'` | Clases del botón en estado normal/activo. |
|
|
237
|
+
| `FILE_BUTTON_DISABLED` | `string` | `'border-gray-200 bg-gray-100 text-gray-400'` | Clases del botón en estado disabled. |
|
|
238
|
+
| `FILE_ICON_BG` | `string` | `'bg-indigo-300'` | Fondo del círculo de ícono en estado activo. |
|
|
239
|
+
| `FILE_ICON_BG_COMPLETE` | `string` | `'bg-emerald-500'` | Fondo del círculo de ícono cuando la descarga está completa. |
|
|
240
|
+
| `FILE_ICON_BG_DISABLED` | `string` | `'bg-gray-300'` | Fondo del círculo de ícono en estado disabled. |
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### Time Picker
|
|
245
|
+
_Afecta: `InputTimeStyle`_
|
|
246
|
+
|
|
247
|
+
| Token | Tipo | Default | Descripción |
|
|
248
|
+
| ----- | ---- | ------- | ----------- |
|
|
249
|
+
| `TIME_PICKER_WRAPPER` | `string` | `'absolute z-20 left-0 top-full rounded-lg bg-white'` | Contenedor flotante del picker. |
|
|
250
|
+
| `TIME_PICKER_CONTAINER` | `string` | `'border border-gray-300 rounded-lg p-3'` | Borde interior del picker. |
|
|
251
|
+
| `TIME_PICKER_COLUMN` | `string` | `'h-48 overflow-y-auto border border-gray-200 rounded-md ...'` | Columna scrollable de horas/minutos. |
|
|
252
|
+
| `TIME_PICKER_AMPM_COLUMN` | `string` | `'h-48 overflow-y-auto border border-gray-200 rounded-md ...'` | Columna scrollable AM/PM. |
|
|
253
|
+
| `TIME_PICKER_COLUMN_LABEL` | `string` | `'block text-xs font-medium text-gray-500 mb-1 text-center'` | Label de cada columna ("Hora", "Minuto", "AM/PM"). |
|
|
254
|
+
| `TIME_PICKER_ITEM` | `string` | `'px-3 py-1 text-center cursor-pointer hover:bg-indigo-50 ...'` | Fila base de cada ítem del picker. |
|
|
255
|
+
| `timePickerItemClass` | `function(isActive)` | Ver abajo | Clases dinámicas de cada ítem según si está seleccionado. |
|
|
256
|
+
|
|
257
|
+
------
|
|
258
|
+
|
|
259
|
+
# 🧩 Componentes
|
|
260
|
+
|
|
261
|
+
## Props comunes
|
|
262
|
+
|
|
263
|
+
La mayoría de los componentes comparten las siguientes props:
|
|
264
|
+
|
|
265
|
+
| Prop | Tipo | Default | Descripción |
|
|
266
|
+
| ---- | ---- | ------- | ----------- |
|
|
267
|
+
| `modelValue` | `String \| Number \| Boolean` | — | Valor del campo (v-model). |
|
|
268
|
+
| `label` | `String` | `''` | Texto del label del campo. |
|
|
269
|
+
| `description` | `String` | `''` | Texto de ayuda debajo del campo. Cambia de color según el estado de validación. |
|
|
270
|
+
| `placeholder` | `String` | `''` | Placeholder del input. |
|
|
271
|
+
| `disabled` | `Boolean` | `false` | Deshabilita el campo. |
|
|
272
|
+
| `required` | `Boolean` | `false` | Marca el campo como requerido (muestra asterisco `*`). |
|
|
273
|
+
| `validate` | `Boolean \| null` | `null` | Estado de validación: `true` = válido, `false` = inválido, `null` = sin estado. |
|
|
274
|
+
| `mclass` | `String` | `null` | Clases CSS adicionales aplicadas directamente al elemento del input. |
|
|
275
|
+
|
|
276
|
+
## Eventos comunes
|
|
277
|
+
|
|
278
|
+
| Evento | Payload | Descripción |
|
|
279
|
+
| ------ | ------- | ----------- |
|
|
280
|
+
| `update:modelValue` | `value` | Se dispara al cambiar el valor (permite `v-model`). |
|
|
281
|
+
| `change` | `value` | Se dispara al cambiar el valor. |
|
|
282
|
+
| `blur` | `event` | Se dispara al perder el foco. |
|
|
283
|
+
|
|
284
|
+
------
|
|
285
|
+
|
|
286
|
+
## InputTextStyle
|
|
287
|
+
|
|
288
|
+
Input de texto genérico. Soporta tipos `text`, `email`, `search`, `tel`, `url` y `number`.
|
|
289
|
+
|
|
290
|
+
```vue
|
|
291
|
+
<InputTextStyle
|
|
292
|
+
v-model="nombre"
|
|
293
|
+
label="Nombre"
|
|
294
|
+
placeholder="Escribe tu nombre"
|
|
295
|
+
:required="true"
|
|
296
|
+
:validate="validate"
|
|
297
|
+
description="Campo requerido"
|
|
298
|
+
/>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
| Prop | Tipo | Default | Descripción |
|
|
302
|
+
| ---- | ---- | ------- | ----------- |
|
|
303
|
+
| `modelValue` | `String \| Number` | `''` | Valor del campo. |
|
|
304
|
+
| `label` | `String` | `''` | |
|
|
305
|
+
| `description` | `String` | `''` | |
|
|
306
|
+
| `placeholder` | `String` | `''` | |
|
|
307
|
+
| `type` | `String` | `'text'` | Tipo del input: `text`, `email`, `search`, `tel`, `url`, `number`. |
|
|
308
|
+
| `maxlength` | `String` | `null` | Longitud máxima de caracteres. |
|
|
309
|
+
| `minlength` | `String` | `null` | Longitud mínima de caracteres. |
|
|
310
|
+
| `min` | `String` | `null` | Valor mínimo (solo cuando `type="number"`, aplicado al perder el foco). |
|
|
311
|
+
| `max` | `String` | `null` | Valor máximo (solo cuando `type="number"`, aplicado al perder el foco). |
|
|
312
|
+
| `disabled` | `Boolean` | `false` | |
|
|
313
|
+
| `required` | `Boolean` | `false` | |
|
|
314
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
315
|
+
| `mclass` | `String` | `null` | |
|
|
316
|
+
|
|
317
|
+
------
|
|
318
|
+
|
|
319
|
+
## InputNumberStyle
|
|
320
|
+
|
|
321
|
+
Input numérico con control preciso de dígitos, decimales, rango y formato de visualización. El valor se emite siempre como string numérico limpio (ej: `"1234.56"`). Al perder el foco se formatea con `toLocaleString`.
|
|
322
|
+
|
|
323
|
+
```vue
|
|
324
|
+
<InputNumberStyle
|
|
325
|
+
v-model="monto"
|
|
326
|
+
label="Monto"
|
|
327
|
+
numeric="10,2"
|
|
328
|
+
min="0"
|
|
329
|
+
max="9999999999"
|
|
330
|
+
:required="true"
|
|
331
|
+
:validate="validate"
|
|
332
|
+
/>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
| Prop | Tipo | Default | Descripción |
|
|
336
|
+
| ---- | ---- | ------- | ----------- |
|
|
337
|
+
| `modelValue` | `String \| Number` | `''` | Valor del campo. |
|
|
338
|
+
| `label` | `String` | `''` | |
|
|
339
|
+
| `description` | `String` | `''` | |
|
|
340
|
+
| `placeholder` | `String` | `''` | |
|
|
341
|
+
| `numeric` | `String` | `null` | Formato tipo SQL: `"10,2"` → 10 dígitos enteros, 2 decimales. Si se omite, usa `10,2` por defecto. |
|
|
342
|
+
| `min` | `String` | `null` | Valor mínimo (aplicado al perder el foco). Si es `null` o negativo, permite negativos. |
|
|
343
|
+
| `max` | `String` | `null` | Valor máximo (aplicado al perder el foco). |
|
|
344
|
+
| `disabled` | `Boolean` | `false` | |
|
|
345
|
+
| `required` | `Boolean` | `false` | |
|
|
346
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
347
|
+
| `mclass` | `String` | `null` | |
|
|
348
|
+
|
|
349
|
+
------
|
|
350
|
+
|
|
351
|
+
## InputPasswordStyle
|
|
352
|
+
|
|
353
|
+
Input de contraseña con toggle para mostrar/ocultar el texto.
|
|
354
|
+
|
|
355
|
+
```vue
|
|
356
|
+
<InputPasswordStyle
|
|
357
|
+
v-model="password"
|
|
358
|
+
label="Contraseña"
|
|
359
|
+
placeholder="Mínimo 8 caracteres"
|
|
360
|
+
:required="true"
|
|
361
|
+
:validate="validate"
|
|
362
|
+
/>
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
| Prop | Tipo | Default | Descripción |
|
|
366
|
+
| ---- | ---- | ------- | ----------- |
|
|
367
|
+
| `modelValue` | `String \| Number` | `''` | Valor del campo. |
|
|
368
|
+
| `label` | `String` | `''` | |
|
|
369
|
+
| `description` | `String` | `''` | |
|
|
370
|
+
| `placeholder` | `String` | `''` | |
|
|
371
|
+
| `maxlength` | `String` | `null` | Longitud máxima. |
|
|
372
|
+
| `disabled` | `Boolean` | `false` | |
|
|
373
|
+
| `required` | `Boolean` | `false` | |
|
|
374
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
375
|
+
| `mclass` | `String` | `null` | |
|
|
376
|
+
|
|
377
|
+
------
|
|
378
|
+
|
|
379
|
+
## TextAreaStyle
|
|
380
|
+
|
|
381
|
+
Área de texto multi-línea.
|
|
382
|
+
|
|
383
|
+
```vue
|
|
384
|
+
<TextAreaStyle
|
|
385
|
+
v-model="comentario"
|
|
386
|
+
label="Comentario"
|
|
387
|
+
placeholder="Escribe aquí..."
|
|
388
|
+
row="5"
|
|
389
|
+
:maxlength="500"
|
|
390
|
+
:validate="validate"
|
|
391
|
+
/>
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
| Prop | Tipo | Default | Descripción |
|
|
395
|
+
| ---- | ---- | ------- | ----------- |
|
|
396
|
+
| `modelValue` | `String` | `''` | Valor del campo. |
|
|
397
|
+
| `label` | `String` | `''` | |
|
|
398
|
+
| `description` | `String` | `''` | |
|
|
399
|
+
| `placeholder` | `String` | `''` | |
|
|
400
|
+
| `row` | `String` | `'3'` | Número de filas visibles del textarea. |
|
|
401
|
+
| `maxlength` | `String` | `null` | Longitud máxima de caracteres. |
|
|
402
|
+
| `disabled` | `Boolean` | `false` | |
|
|
403
|
+
| `required` | `Boolean` | `false` | |
|
|
404
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
405
|
+
| `mclass` | `String` | `null` | |
|
|
406
|
+
|
|
407
|
+
------
|
|
408
|
+
|
|
409
|
+
## SelectStyle
|
|
410
|
+
|
|
411
|
+
Select personalizado con dropdown, navegación por teclado y búsqueda por tipeo. El dropdown se posiciona automáticamente arriba o abajo según el espacio disponible.
|
|
412
|
+
|
|
413
|
+
```vue
|
|
414
|
+
<SelectStyle
|
|
415
|
+
v-model="pais"
|
|
416
|
+
label="País"
|
|
417
|
+
:list="paises"
|
|
418
|
+
return-value="value"
|
|
419
|
+
:required="true"
|
|
420
|
+
:validate="validate"
|
|
421
|
+
/>
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
```js
|
|
425
|
+
// Formato requerido del array `list`
|
|
426
|
+
const paises = [
|
|
427
|
+
{ value: 1, text: 'México' },
|
|
428
|
+
{ value: 2, text: 'España' },
|
|
429
|
+
{ value: 3, text: 'Argentina' },
|
|
430
|
+
]
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
| Prop | Tipo | Default | Descripción |
|
|
434
|
+
| ---- | ---- | ------- | ----------- |
|
|
435
|
+
| `modelValue` | `String \| Number \| Object` | — | Valor seleccionado. |
|
|
436
|
+
| `list` | `Array` | `[]` | Array de opciones con formato `{ value, text }`. |
|
|
437
|
+
| `returnValue` | `String` | `'value'` | Qué se emite al seleccionar: `'value'` (item.value), `'text'` (item.text) u `'object'` (el item completo). |
|
|
438
|
+
| `label` | `String` | `''` | |
|
|
439
|
+
| `description` | `String` | `''` | |
|
|
440
|
+
| `disabled` | `Boolean` | `false` | |
|
|
441
|
+
| `required` | `Boolean` | `false` | |
|
|
442
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
443
|
+
| `mclass` | `String` | `null` | |
|
|
444
|
+
|
|
445
|
+
**Navegación por teclado:**
|
|
446
|
+
- `↑` / `↓` — navegar opciones
|
|
447
|
+
- `Enter` — seleccionar la opción resaltada
|
|
448
|
+
- `Escape` — cerrar el dropdown
|
|
449
|
+
- Tipear letras — búsqueda inmediata en la lista
|
|
450
|
+
|
|
451
|
+
------
|
|
452
|
+
|
|
453
|
+
## InputCheckStyle
|
|
454
|
+
|
|
455
|
+
Checkbox estilizado con label y descripción.
|
|
456
|
+
|
|
457
|
+
```vue
|
|
458
|
+
<InputCheckStyle
|
|
459
|
+
v-model="aceptaTerminos"
|
|
460
|
+
label="Acepto los términos y condiciones"
|
|
461
|
+
:required="true"
|
|
462
|
+
/>
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
| Prop | Tipo | Default | Descripción |
|
|
466
|
+
| ---- | ---- | ------- | ----------- |
|
|
467
|
+
| `modelValue` | `Boolean` | `false` | Estado del checkbox. |
|
|
468
|
+
| `label` | `String` | `''` | |
|
|
469
|
+
| `description` | `String` | `''` | |
|
|
470
|
+
| `disabled` | `Boolean` | `false` | |
|
|
471
|
+
| `required` | `Boolean` | `false` | |
|
|
472
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
473
|
+
| `mclass` | `String` | `null` | Clases adicionales del cuadro del checkbox. |
|
|
474
|
+
|
|
475
|
+
------
|
|
476
|
+
|
|
477
|
+
## InputRadioStyle
|
|
478
|
+
|
|
479
|
+
Radio button estilizado con label y descripción.
|
|
480
|
+
|
|
481
|
+
```vue
|
|
482
|
+
<InputRadioStyle
|
|
483
|
+
v-model="opcionA"
|
|
484
|
+
label="Opción A"
|
|
485
|
+
/>
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
| Prop | Tipo | Default | Descripción |
|
|
489
|
+
| ---- | ---- | ------- | ----------- |
|
|
490
|
+
| `modelValue` | `Boolean` | `false` | Estado del radio. |
|
|
491
|
+
| `label` | `String` | `''` | |
|
|
492
|
+
| `description` | `String` | `''` | |
|
|
493
|
+
| `disabled` | `Boolean` | `false` | |
|
|
494
|
+
| `required` | `Boolean` | `false` | |
|
|
495
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
496
|
+
| `mclass` | `String` | `null` | Clases adicionales del círculo del radio. |
|
|
497
|
+
|
|
498
|
+
------
|
|
499
|
+
|
|
500
|
+
## InputSwitchStyle
|
|
501
|
+
|
|
502
|
+
Toggle switch estilizado.
|
|
503
|
+
|
|
504
|
+
```vue
|
|
505
|
+
<InputSwitchStyle
|
|
506
|
+
v-model="activo"
|
|
507
|
+
label="Activar notificaciones"
|
|
508
|
+
/>
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
| Prop | Tipo | Default | Descripción |
|
|
512
|
+
| ---- | ---- | ------- | ----------- |
|
|
513
|
+
| `modelValue` | `Boolean` | `false` | Estado del switch. |
|
|
514
|
+
| `label` | `String` | `''` | |
|
|
515
|
+
| `description` | `String` | `''` | |
|
|
516
|
+
| `disabled` | `Boolean` | `false` | |
|
|
517
|
+
| `required` | `Boolean` | `false` | |
|
|
518
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
519
|
+
| `mclass` | `String` | `null` | Clases adicionales de la pista del switch. |
|
|
520
|
+
|
|
521
|
+
------
|
|
522
|
+
|
|
523
|
+
## InputDateStyle
|
|
524
|
+
|
|
525
|
+
Selector de fecha con máscara `dd/mm/aaaa`, navegación por teclado entre secciones y calendario visual (v-calendar). El valor se emite en formato `YYYY-MM-DD`.
|
|
526
|
+
|
|
527
|
+
```vue
|
|
528
|
+
<InputDateStyle
|
|
529
|
+
v-model="fechaNacimiento"
|
|
530
|
+
label="Fecha de nacimiento"
|
|
531
|
+
min="1900-01-01"
|
|
532
|
+
max="2100-12-31"
|
|
533
|
+
:validate="validate"
|
|
534
|
+
/>
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
| Prop | Tipo | Default | Descripción |
|
|
538
|
+
| ---- | ---- | ------- | ----------- |
|
|
539
|
+
| `modelValue` | `String \| Date` | — | Valor de la fecha en formato `YYYY-MM-DD` o `Date`. |
|
|
540
|
+
| `label` | `String` | `''` | |
|
|
541
|
+
| `description` | `String` | `''` | |
|
|
542
|
+
| `min` | `String` | `'1900-01-01'` | Fecha mínima seleccionable en el calendario (formato `YYYY-MM-DD`). |
|
|
543
|
+
| `max` | `String` | `'2100-12-31'` | Fecha máxima seleccionable en el calendario (formato `YYYY-MM-DD`). |
|
|
544
|
+
| `disabledDates` | `Array \| Object` | `[]` | Fechas deshabilitadas en el calendario. Acepta el formato de `v-calendar`. |
|
|
545
|
+
| `disabled` | `Boolean` | `false` | |
|
|
546
|
+
| `required` | `Boolean` | `false` | |
|
|
547
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
548
|
+
| `mclass` | `String` | `null` | |
|
|
549
|
+
|
|
550
|
+
**Valor emitido:** `'YYYY-MM-DD'` (string) o `''` si la fecha es inválida o está vacía.
|
|
551
|
+
|
|
552
|
+
**Navegación por teclado:**
|
|
553
|
+
- Escribe los dígitos y el foco avanza automáticamente entre día → mes → año
|
|
554
|
+
- `←` / `→` — mover entre secciones
|
|
555
|
+
- `Backspace` / `Delete` — limpiar la sección activa
|
|
556
|
+
- Clic en el ícono 📅 — abre/cierra el calendario visual
|
|
557
|
+
|
|
558
|
+
------
|
|
559
|
+
|
|
560
|
+
## InputTimeStyle
|
|
561
|
+
|
|
562
|
+
Selector de hora con picker de columnas scrollables. Soporta formato 12h (AM/PM) o 24h. El valor se emite en formato `HH:mm`.
|
|
563
|
+
|
|
564
|
+
```vue
|
|
565
|
+
<InputTimeStyle
|
|
566
|
+
v-model="horaInicio"
|
|
567
|
+
label="Hora de inicio"
|
|
568
|
+
min="08:00"
|
|
569
|
+
max="18:00"
|
|
570
|
+
:is24h="true"
|
|
571
|
+
:validate="validate"
|
|
572
|
+
/>
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
| Prop | Tipo | Default | Descripción |
|
|
576
|
+
| ---- | ---- | ------- | ----------- |
|
|
577
|
+
| `modelValue` | `String` | — | Valor de la hora en formato `HH:mm`. |
|
|
578
|
+
| `label` | `String` | `''` | |
|
|
579
|
+
| `description` | `String` | `''` | |
|
|
580
|
+
| `min` | `String` | `null` | Hora mínima (ej: `'08:00'`). |
|
|
581
|
+
| `max` | `String` | `null` | Hora máxima (ej: `'18:00'`). |
|
|
582
|
+
| `is24h` | `Boolean` | `false` | `true` = formato 24h, `false` = formato 12h con selector AM/PM. |
|
|
583
|
+
| `disabled` | `Boolean` | `false` | |
|
|
584
|
+
| `required` | `Boolean` | `false` | |
|
|
585
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
586
|
+
| `mclass` | `String` | `null` | |
|
|
587
|
+
|
|
588
|
+
**Valor emitido:** `'HH:mm'` en formato 24h siempre, independientemente del modo de visualización.
|
|
589
|
+
|
|
590
|
+
------
|
|
591
|
+
|
|
592
|
+
## InputFileUploadStyle
|
|
593
|
+
|
|
594
|
+
Botón para adjuntar archivos con validación de tamaño y formato.
|
|
595
|
+
|
|
596
|
+
```vue
|
|
597
|
+
<InputFileUploadStyle
|
|
598
|
+
v-model="archivo"
|
|
599
|
+
:formats="['pdf', 'docx']"
|
|
600
|
+
max-size-m-b="10"
|
|
601
|
+
:state="uploadState"
|
|
602
|
+
/>
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
| Prop | Tipo | Default | Descripción |
|
|
606
|
+
| ---- | ---- | ------- | ----------- |
|
|
607
|
+
| `modelValue` | `File` | `null` | Archivo seleccionado. |
|
|
608
|
+
| `disabled` | `Boolean` | `false` | Deshabilita el botón. |
|
|
609
|
+
| `formats` | `Array` | `[]` | Extensiones permitidas (ej: `['pdf', 'xlsx', 'png']`). Array vacío = todos los formatos. |
|
|
610
|
+
| `maxSizeMB` | `String \| Number` | `5` | Tamaño máximo del archivo en MB. |
|
|
611
|
+
| `state` | `String` | `'uphold'` | Estado del botón: `'uphold'` (normal) o `'loader'` (cargando, muestra spinner). |
|
|
612
|
+
| `delay` | `String` | `'1.5'` | Segundos de bloqueo del botón tras un clic, para evitar doble envío. |
|
|
613
|
+
|
|
614
|
+
**Eventos:**
|
|
615
|
+
- `update:modelValue` — emite el `File` seleccionado, o `null` si el archivo no es válido.
|
|
616
|
+
- `change` — igual que `update:modelValue`.
|
|
617
|
+
|
|
618
|
+
El componente valida automáticamente el tamaño y el formato, mostrando un mensaje de error inline si la validación falla.
|
|
619
|
+
|
|
620
|
+
------
|
|
621
|
+
|
|
622
|
+
## InputFileDownloadStyle
|
|
623
|
+
|
|
624
|
+
Botón para descargar archivos con tres estados visuales.
|
|
625
|
+
|
|
626
|
+
```vue
|
|
627
|
+
<InputFileDownloadStyle
|
|
628
|
+
:state="downloadState"
|
|
629
|
+
:disabled="false"
|
|
630
|
+
@click="descargarArchivo"
|
|
631
|
+
/>
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
| Prop | Tipo | Default | Descripción |
|
|
635
|
+
| ---- | ---- | ------- | ----------- |
|
|
636
|
+
| `disabled` | `Boolean` | `false` | Deshabilita el botón. |
|
|
637
|
+
| `state` | `String` | `'download'` | Estado: `'download'` (normal), `'loader'` (descargando, spinner), `'complete'` (completado, check verde). |
|
|
638
|
+
| `delay` | `String` | `'1.5'` | Segundos de bloqueo del botón tras un clic. |
|
|
639
|
+
|
|
640
|
+
**Eventos:**
|
|
641
|
+
- `click` — se dispara al hacer clic (solo si no está deshabilitado).
|
|
642
|
+
|
|
643
|
+
------
|
|
644
|
+
|
|
645
|
+
## ButtonStyle
|
|
646
|
+
|
|
647
|
+
Botón genérico con bloqueo automático anti-doble-clic.
|
|
648
|
+
|
|
649
|
+
```vue
|
|
650
|
+
<ButtonStyle
|
|
651
|
+
class="px-4 py-2 bg-indigo-500 text-white rounded"
|
|
652
|
+
:disabled="cargando"
|
|
653
|
+
@click="guardar"
|
|
654
|
+
>
|
|
655
|
+
Guardar
|
|
656
|
+
</ButtonStyle>
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
| Prop | Tipo | Default | Descripción |
|
|
660
|
+
| ---- | ---- | ------- | ----------- |
|
|
661
|
+
| `type` | `String` | `'button'` | Tipo del botón: `'button'` o `'submit'`. |
|
|
662
|
+
| `class` | `String` | `''` | Clases CSS del botón (TailwindCSS). |
|
|
663
|
+
| `disabled` | `Boolean` | `false` | Deshabilita el botón. |
|
|
664
|
+
| `delay` | `String` | `'1.5'` | Segundos de bloqueo automático tras hacer clic (anti-doble-clic). |
|
|
665
|
+
|
|
666
|
+
**Eventos:**
|
|
667
|
+
- `click` — se dispara al hacer clic (solo si no está deshabilitado ni en periodo de bloqueo).
|
|
668
|
+
|
|
669
|
+
Acepta contenido mediante `<slot>` (texto, íconos, etc.).
|
|
670
|
+
|
|
671
|
+
------
|
|
672
|
+
|
|
673
|
+
## LoaderStyle
|
|
674
|
+
|
|
675
|
+
Indicador de carga circular animado.
|
|
676
|
+
|
|
677
|
+
```vue
|
|
678
|
+
<LoaderStyle message="Procesando datos..." />
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
| Prop | Tipo | Default | Descripción |
|
|
682
|
+
| ---- | ---- | ------- | ----------- |
|
|
683
|
+
| `message` | `String` | `'Cargando...'` | Texto que se muestra debajo del arco animado. |
|
|
684
|
+
|
|
685
|
+
El color del arco se controla con el token `LOADER_ARC_STROKE`.
|
|
686
|
+
|
|
687
|
+
------
|
|
688
|
+
|
|
689
|
+
## PaginationStyle
|
|
690
|
+
|
|
691
|
+
Paginador con navegación anterior/siguiente, botones de página y resumen de registros.
|
|
692
|
+
|
|
693
|
+
```vue
|
|
694
|
+
<PaginationStyle
|
|
695
|
+
:total-pages="totalPaginas"
|
|
696
|
+
:actual-page="paginaActual"
|
|
697
|
+
:records="totalRegistros"
|
|
698
|
+
:limit="registrosPorPagina"
|
|
699
|
+
:summary="true"
|
|
700
|
+
@page="cambiarPagina"
|
|
701
|
+
/>
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
| Prop | Tipo | Default | Descripción |
|
|
705
|
+
| ---- | ---- | ------- | ----------- |
|
|
706
|
+
| `totalPages` | `Number` | `0` | Total de páginas. |
|
|
707
|
+
| `actualPage` | `Number` | `1` | Página actualmente activa. |
|
|
708
|
+
| `records` | `Number` | `0` | Total de registros (para el resumen). |
|
|
709
|
+
| `limit` | `Number` | `0` | Registros por página (para calcular el rango del resumen). |
|
|
710
|
+
| `summary` | `Boolean` | `false` | `true` = muestra el texto "Mostrando X - Y de Z". |
|
|
711
|
+
|
|
712
|
+
**Eventos:**
|
|
713
|
+
- `page` — emite el número de página a la que se desea navegar.
|
|
714
|
+
|
|
715
|
+
El paginador muestra hasta 7 botones con elipsis (`...`) inteligentes cuando hay más páginas.
|
|
716
|
+
|
|
717
|
+
------
|
|
718
|
+
|
|
719
|
+
## Ejemplo de uso completo
|
|
720
|
+
|
|
721
|
+
```vue
|
|
722
|
+
<template>
|
|
723
|
+
<div class="p-6 space-y-4 max-w-md">
|
|
724
|
+
|
|
725
|
+
<InputTextStyle
|
|
726
|
+
v-model="form.nombre"
|
|
727
|
+
label="Nombre completo"
|
|
728
|
+
placeholder="Ej: Juan Pérez"
|
|
729
|
+
:required="true"
|
|
730
|
+
:validate="validaciones.nombre"
|
|
731
|
+
/>
|
|
732
|
+
|
|
733
|
+
<InputNumberStyle
|
|
734
|
+
v-model="form.monto"
|
|
735
|
+
label="Monto"
|
|
736
|
+
numeric="10,2"
|
|
737
|
+
min="0"
|
|
738
|
+
:validate="validaciones.monto"
|
|
739
|
+
/>
|
|
740
|
+
|
|
741
|
+
<InputPasswordStyle
|
|
742
|
+
v-model="form.password"
|
|
743
|
+
label="Contraseña"
|
|
744
|
+
:required="true"
|
|
745
|
+
:validate="validaciones.password"
|
|
746
|
+
/>
|
|
747
|
+
|
|
748
|
+
<SelectStyle
|
|
749
|
+
v-model="form.pais"
|
|
750
|
+
label="País"
|
|
751
|
+
:list="paises"
|
|
752
|
+
return-value="value"
|
|
753
|
+
:validate="validaciones.pais"
|
|
754
|
+
/>
|
|
755
|
+
|
|
756
|
+
<InputDateStyle
|
|
757
|
+
v-model="form.fecha"
|
|
758
|
+
label="Fecha"
|
|
759
|
+
:validate="validaciones.fecha"
|
|
760
|
+
/>
|
|
761
|
+
|
|
762
|
+
<InputTimeStyle
|
|
763
|
+
v-model="form.hora"
|
|
764
|
+
label="Hora"
|
|
765
|
+
:is24h="true"
|
|
766
|
+
/>
|
|
767
|
+
|
|
768
|
+
<InputCheckStyle
|
|
769
|
+
v-model="form.acepta"
|
|
770
|
+
label="Acepto los términos"
|
|
771
|
+
:required="true"
|
|
772
|
+
/>
|
|
773
|
+
|
|
774
|
+
<ButtonStyle
|
|
775
|
+
class="w-full px-4 py-2 bg-indigo-500 text-white rounded hover:bg-indigo-600"
|
|
776
|
+
@click="enviar"
|
|
777
|
+
>
|
|
778
|
+
Enviar
|
|
779
|
+
</ButtonStyle>
|
|
780
|
+
|
|
781
|
+
</div>
|
|
782
|
+
</template>
|
|
783
|
+
|
|
784
|
+
<script setup>
|
|
785
|
+
import { ref } from 'vue'
|
|
786
|
+
import {
|
|
787
|
+
InputTextStyle, InputNumberStyle, InputPasswordStyle,
|
|
788
|
+
SelectStyle, InputDateStyle, InputTimeStyle,
|
|
789
|
+
InputCheckStyle, ButtonStyle
|
|
790
|
+
} from '@luis-angel-martin-dzul/input-styles'
|
|
791
|
+
|
|
792
|
+
const form = ref({
|
|
793
|
+
nombre: '', monto: '', password: '',
|
|
794
|
+
pais: null, fecha: '', hora: '', acepta: false
|
|
795
|
+
})
|
|
796
|
+
|
|
797
|
+
const validaciones = ref({
|
|
798
|
+
nombre: null, monto: null, password: null,
|
|
799
|
+
pais: null, fecha: null
|
|
800
|
+
})
|
|
801
|
+
|
|
802
|
+
const paises = [
|
|
803
|
+
{ value: 1, text: 'México' },
|
|
804
|
+
{ value: 2, text: 'España' },
|
|
805
|
+
]
|
|
806
|
+
|
|
807
|
+
function enviar() {
|
|
808
|
+
validaciones.value.nombre = form.value.nombre.length > 0
|
|
809
|
+
// ... resto de validaciones
|
|
810
|
+
}
|
|
811
|
+
</script>
|
|
812
|
+
```
|
package/package.json
CHANGED