@luis-angel-martin-dzul/input-styles 0.0.34 → 0.0.38
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 +1420 -1361
- package/dist/input-styles.css +1 -1
- package/dist/input-yuc.es.js +251 -246
- package/dist/input-yuc.umd.js +19 -19
- package/package.json +43 -42
package/README.md
CHANGED
|
@@ -1,1361 +1,1420 @@
|
|
|
1
|
-
# 📦 Input Style
|
|
2
|
-
|
|
3
|
-
**Librería de componentes y formularios Vue 3**
|
|
4
|
-
|
|
5
|
-
Incluye componentes de inputs, selects, botones, paginación y más, estilizados con
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
|
164
|
-
|
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
|
185
|
-
|
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
},
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
|
250
|
-
|
|
|
251
|
-
| `
|
|
252
|
-
| `
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
|
286
|
-
|
|
|
287
|
-
| `
|
|
288
|
-
| `
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
|
298
|
-
|
|
|
299
|
-
| `
|
|
300
|
-
| `
|
|
301
|
-
| `
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
|
323
|
-
|
|
|
324
|
-
| `
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
|
360
|
-
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
|
419
|
-
|
|
|
420
|
-
| `
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
|
499
|
-
|
|
|
500
|
-
| `
|
|
501
|
-
| `
|
|
502
|
-
| `
|
|
503
|
-
| `
|
|
504
|
-
| `
|
|
505
|
-
| `
|
|
506
|
-
| `
|
|
507
|
-
| `
|
|
508
|
-
| `
|
|
509
|
-
| `
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
:
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
|
560
|
-
|
|
|
561
|
-
| `
|
|
562
|
-
| `
|
|
563
|
-
| `
|
|
564
|
-
| `
|
|
565
|
-
| `
|
|
566
|
-
| `
|
|
567
|
-
| `
|
|
568
|
-
| `
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
**
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
|
666
|
-
|
|
|
667
|
-
| `
|
|
668
|
-
| `
|
|
669
|
-
| `
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
|
718
|
-
|
|
|
719
|
-
| `
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
|
927
|
-
|
|
|
928
|
-
| `
|
|
929
|
-
| `
|
|
930
|
-
| `
|
|
931
|
-
| `
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
|
1010
|
-
|
|
|
1011
|
-
| `
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
|
1071
|
-
|
|
|
1072
|
-
| `
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
|
1130
|
-
|
|
|
1131
|
-
| `
|
|
1132
|
-
| `
|
|
1133
|
-
| `
|
|
1134
|
-
| `
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
```
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1
|
+
# 📦 Input Style
|
|
2
|
+
|
|
3
|
+
**Librería de componentes y formularios Vue 3**
|
|
4
|
+
|
|
5
|
+
Incluye componentes de inputs, selects, botones, paginación y más, estilizados con **Tailwind CSS 4** y listos para producción.
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Solo compatible con Tailwind CSS 4.** La librería usa la sintaxis y los nombres de utilidades de la v4 (`outline-hidden`, `backdrop-blur-xs`, `z-100`, etc.) y se configura con `@import "tailwindcss"` + `@source`. **No funciona con Tailwind CSS 3** (`tailwind.config.js` / `content`).
|
|
8
|
+
|
|
9
|
+
------
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
------
|
|
16
|
+
|
|
17
|
+
# 📋 Requisitos
|
|
18
|
+
|
|
19
|
+
| Dependencia | Versión |
|
|
20
|
+
| ----------- | ------- |
|
|
21
|
+
| `vue` | `^3.3.0` |
|
|
22
|
+
| `tailwindcss` | `^4.0.0` |
|
|
23
|
+
| `@tailwindcss/vite` (o `@tailwindcss/postcss`) | `^4.0.0` |
|
|
24
|
+
|
|
25
|
+
------
|
|
26
|
+
|
|
27
|
+
# 📦 Instalación
|
|
28
|
+
|
|
29
|
+
La librería se distribuye mediante **npm**:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
npm install @luis-angel-martin-dzul/input-styles
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Si todavía no tienes Tailwind CSS 4 en tu proyecto:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
npm install tailwindcss @tailwindcss/vite
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
------
|
|
42
|
+
|
|
43
|
+
# 🚀 Uso en Vue + Vite
|
|
44
|
+
|
|
45
|
+
En `main.js` o `main.ts`:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
import { createApp } from 'vue'
|
|
49
|
+
import App from './App.vue'
|
|
50
|
+
|
|
51
|
+
import '@luis-angel-martin-dzul/input-styles/style.css'
|
|
52
|
+
import InputStyle from '@luis-angel-martin-dzul/input-styles'
|
|
53
|
+
|
|
54
|
+
const app = createApp(App)
|
|
55
|
+
|
|
56
|
+
app.use(InputStyle)
|
|
57
|
+
app.mount('#app')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Al instalar el plugin se registran automáticamente todos los componentes y las siguientes **propiedades globales** (disponibles en cualquier componente con la Options API):
|
|
61
|
+
|
|
62
|
+
| Propiedad global | Equivale a | Descripción |
|
|
63
|
+
| ---------------- | ---------- | ----------- |
|
|
64
|
+
| `$alertstyle` | `AlertStyle` | Notificaciones tipo toast (ver [AlertStyle](#alertstyle-notificaciones-tipo-toast)). |
|
|
65
|
+
| `$dialogstyle` | `DialogStyle` | Diálogos de confirmación / info / carga (ver [DialogStyle](#dialogstyle-diálogos-modales)). |
|
|
66
|
+
| `$utilstyle` | `UtilStyle` | Utilidades internas (ej: generación de UUID). |
|
|
67
|
+
|
|
68
|
+
------
|
|
69
|
+
|
|
70
|
+
# 🎨 Configuración de Tailwind CSS 4
|
|
71
|
+
|
|
72
|
+
Tailwind CSS 4 se configura desde el CSS (no existe `tailwind.config.js` ni la opción `content`). Se necesitan **dos pasos**.
|
|
73
|
+
|
|
74
|
+
**1. Activa el plugin de Tailwind en Vite** (`vite.config.js`):
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
import { defineConfig } from 'vite'
|
|
78
|
+
import vue from '@vitejs/plugin-vue'
|
|
79
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
80
|
+
|
|
81
|
+
export default defineConfig({
|
|
82
|
+
plugins: [vue(), tailwindcss()],
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**2. Importa Tailwind e indica con `@source` dónde está la librería.** En el CSS principal de tu app (por ejemplo `src/style.css`):
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
@import "tailwindcss";
|
|
90
|
+
|
|
91
|
+
/* Tailwind 4 ignora node_modules; sin esta línea no se generan las clases que usa la librería. */
|
|
92
|
+
@source "../node_modules/@luis-angel-martin-dzul/input-styles/dist";
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> 💡 La ruta de `@source` es **relativa al archivo CSS** donde la escribes. Ajusta los `../` según su ubicación. Recuerda el `;` al final: es una regla CSS.
|
|
96
|
+
|
|
97
|
+
El CSS propio de la librería (alertas, diálogos y animaciones) se importa aparte, en `main.js`:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
import '@luis-angel-martin-dzul/input-styles/style.css'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Sin `@source`** los componentes se verán sin estilos o a medias, porque las clases de Tailwind que usan no se generan.
|
|
104
|
+
|
|
105
|
+
# 🎨 Estilos personalizados (Style Registry)
|
|
106
|
+
|
|
107
|
+
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.
|
|
108
|
+
|
|
109
|
+
Los estilos se configuran **antes de montar la app**, importando `configureStyles` directamente.
|
|
110
|
+
|
|
111
|
+
> ⚠️ **Los tokens deben escribirse con clases de Tailwind CSS 4.** Además, las clases de tus tokens **tienen que ser visibles para Tailwind**: como se definen en tu propio código (`main.js`), quedan cubiertas por el escaneo automático de tu proyecto. Si las defines en un paquete dentro de `node_modules`, agrégalas con `@source`.
|
|
112
|
+
>
|
|
113
|
+
> Nombres que cambiaron respecto a Tailwind 3 y que debes tener en cuenta al personalizar:
|
|
114
|
+
>
|
|
115
|
+
> | Tailwind 3 | Tailwind 4 |
|
|
116
|
+
> | ---------- | ---------- |
|
|
117
|
+
> | `outline-none` | `outline-hidden` (en v4, `outline-none` quita el contorno por completo) |
|
|
118
|
+
> | `shadow-sm` / `shadow` | `shadow-xs` / `shadow-sm` |
|
|
119
|
+
> | `rounded-sm` / `rounded` | `rounded-xs` / `rounded-sm` |
|
|
120
|
+
> | `blur-sm` / `backdrop-blur-sm` | `blur-xs` / `backdrop-blur-xs` |
|
|
121
|
+
> | `ring` (3px) | `ring-3` (`ring` ahora es de 1px) |
|
|
122
|
+
> | `flex-shrink-0` / `flex-grow` | `shrink-0` / `grow` |
|
|
123
|
+
> | `bg-opacity-50` | `bg-black/50` (modificador de opacidad) |
|
|
124
|
+
> | `bg-[--mi-var]` | `bg-(--mi-var)` |
|
|
125
|
+
> | `!px-2` (important al inicio) | `px-2!` (important al final) |
|
|
126
|
+
|
|
127
|
+
## Opción A — vía `app.use` (recomendado)
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
import InputStyle from '@luis-angel-martin-dzul/input-styles'
|
|
131
|
+
|
|
132
|
+
app.use(InputStyle, {
|
|
133
|
+
styles: {
|
|
134
|
+
INPUT_BASE: 'w-full px-0 py-2 bg-transparent border-b focus:outline-hidden ...',
|
|
135
|
+
ICON_VALID: 'text-emerald-500',
|
|
136
|
+
// solo los tokens que quieras cambiar
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Opción B — importación directa
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
import { configureStyles } from '@luis-angel-martin-dzul/input-styles'
|
|
145
|
+
|
|
146
|
+
configureStyles({
|
|
147
|
+
LOADER_ARC_STROKE: '#3B82F6',
|
|
148
|
+
REQUIRED_ASTERISK: 'text-red-500',
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
⚠️ `configureStyles()` debe llamarse **antes** de que los componentes se monten. Los cambios no son reactivos después del montaje inicial.
|
|
153
|
+
|
|
154
|
+
------
|
|
155
|
+
|
|
156
|
+
## 📋 Referencia completa de tokens
|
|
157
|
+
|
|
158
|
+
### Tokens auxiliares de label
|
|
159
|
+
_Afecta: todos los componentes que tienen `label` o `description`_
|
|
160
|
+
|
|
161
|
+
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**.
|
|
162
|
+
|
|
163
|
+
| Token | Tipo | Default | Descripción |
|
|
164
|
+
| ----- | ---- | ------- | ----------- |
|
|
165
|
+
| `INPUT_BASE_TITLE` | `string` | `'block text-sm font-medium'` | Clases estructurales del `<label>` de inputs de texto. |
|
|
166
|
+
| `INPUT_CHECK_BASE_TITLE` | `string` | `'block text-sm font-medium'` | Clases estructurales del `<label>` de checkbox, radio y switch. |
|
|
167
|
+
| `LABEL_DISABLED_STATIC` | `string` | `'text-gray-400'` | Color del label y descripción cuando el campo está deshabilitado. |
|
|
168
|
+
| `LABEL_ENABLED_STATIC` | `string` | `'text-gray-700'` | Color del label cuando el campo está habilitado. |
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
configureStyles({
|
|
172
|
+
LABEL_DISABLED_STATIC: 'text-gray-400',
|
|
173
|
+
LABEL_ENABLED_STATIC: 'text-gray-900',
|
|
174
|
+
INPUT_BASE_TITLE: 'block font-semibold mb-1 text-sm',
|
|
175
|
+
})
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### Inputs de texto
|
|
181
|
+
_Afecta: `InputTextStyle`, `InputNumberStyle`, `InputPasswordStyle`, `TextAreaStyle`, `InputDateStyle`, `InputDateTimeStyle`, `InputTimeStyle`, `SelectStyle`, `InputAutocompleteStyle`_
|
|
182
|
+
|
|
183
|
+
| Token | Tipo | Default | Descripción |
|
|
184
|
+
| ----- | ---- | ------- | ----------- |
|
|
185
|
+
| `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`). |
|
|
186
|
+
| `inputValidateClass` | `function(validate)` | Ver abajo | Retorna las clases de borde y ring según el estado de validación. `validate`: `true` / `false` / `null`. |
|
|
187
|
+
| `inputLabelClass` | `function(disabled)` | Ver abajo | Retorna las clases del `<label>`. Internamente usa `INPUT_BASE_TITLE`, `LABEL_DISABLED_STATIC` y `LABEL_ENABLED_STATIC`. |
|
|
188
|
+
| `inputDescriptionClass` | `function(validate, alignRight?)` | Ver abajo | Retorna las clases del texto de descripción. Internamente usa `ICON_VALID`, `ICON_INVALID` y `LABEL_DISABLED_STATIC`. |
|
|
189
|
+
|
|
190
|
+
> 💡 Si solo quieres cambiar un color de validación, basta con sobrescribir `ICON_INVALID` o `ICON_VALID` — `inputDescriptionClass` los recoge automáticamente.
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
configureStyles({
|
|
194
|
+
ICON_INVALID: 'text-red-500',
|
|
195
|
+
ICON_VALID: 'text-emerald-500',
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
// Override completo de las funciones (cuando necesitas control total)
|
|
199
|
+
configureStyles({
|
|
200
|
+
inputValidateClass: (validate) => {
|
|
201
|
+
if (validate === false) return 'border-red-500 focus:ring-red-200'
|
|
202
|
+
if (validate === true) return 'border-emerald-500 focus:ring-emerald-200'
|
|
203
|
+
return 'border-gray-200 focus:ring-indigo-200'
|
|
204
|
+
},
|
|
205
|
+
inputLabelClass: (disabled) => ['block font-bold mb-2', disabled ? 'text-gray-400' : 'text-gray-900'],
|
|
206
|
+
inputDescriptionClass: (validate, alignRight = true) => [
|
|
207
|
+
'block w-full text-sm',
|
|
208
|
+
alignRight && 'text-right',
|
|
209
|
+
validate === false ? 'text-red-500' : validate === true ? 'text-emerald-500' : 'text-gray-500',
|
|
210
|
+
],
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### Select
|
|
217
|
+
_Afecta: `SelectStyle`, `InputAutocompleteStyle`_
|
|
218
|
+
|
|
219
|
+
| Token | Tipo | Default | Descripción |
|
|
220
|
+
| ----- | ---- | ------- | ----------- |
|
|
221
|
+
| `SELECT_DISABLED` | `string` | `'w-full px-3 py-1.5 rounded bg-gray-100 ...'` | Clases del input en estado disabled. |
|
|
222
|
+
| `SELECT_DROPDOWN` | `string` | `'absolute z-20 w-full bg-white border ...'` | Clases del contenedor `<ul>` del dropdown. |
|
|
223
|
+
| `SELECT_OPTION_BASE` | `string` | `'px-3 py-1 cursor-pointer text-md'` | Clases base de cada `<li>` del dropdown. |
|
|
224
|
+
| `selectOptionClass` | `function(isSelected, isHighlighted)` | Ver abajo | Retorna clases dinámicas por opción según su estado. |
|
|
225
|
+
| `SELECT_OPTGROUP` | `string` | `'px-2 pt-1 pb-0.5 text-xs font-semibold uppercase ...'` | Clases del encabezado de un grupo de opciones (`optgroup`). |
|
|
226
|
+
| `SELECT_EMPTY` | `string` | `'px-3 py-1 text-gray-400 cursor-not-allowed'` | Clases del mensaje "Sin registros". |
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
configureStyles({
|
|
230
|
+
selectOptionClass: (isSelected, isHighlighted) => {
|
|
231
|
+
if (isSelected) return 'bg-indigo-100 text-indigo-900 font-medium'
|
|
232
|
+
if (isHighlighted) return 'bg-indigo-50 text-gray-900'
|
|
233
|
+
return 'hover:bg-indigo-50 text-gray-800'
|
|
234
|
+
},
|
|
235
|
+
})
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### Checkbox, Radio y Switch
|
|
241
|
+
_Afecta: `InputCheckStyle`, `InputRadioStyle`, `InputSwitchStyle`_
|
|
242
|
+
|
|
243
|
+
| Token | Tipo | Default | Descripción |
|
|
244
|
+
| ----- | ---- | ------- | ----------- |
|
|
245
|
+
| `inputCheckLabelClass` | `function(disabled)` | Ver abajo | Clases del label de checks. |
|
|
246
|
+
| `CHECK_BOX_BASE` | `string` | `'w-5 h-5 flex items-center justify-center rounded border-2 transition'` | Estructura base del cuadro del checkbox. |
|
|
247
|
+
| `RADIO_BASE` | `string` | `'w-5 h-5 flex items-center justify-center rounded-full transition'` | Estructura base del círculo del radio. |
|
|
248
|
+
| `SWITCH_BASE` | `string` | `'w-10 h-5 relative flex items-center rounded-full transition border-2'` | Estructura base de la pista del switch. |
|
|
249
|
+
| `checkBoxClass` | `function(model, disabled)` | Ver abajo | Clases de color del checkbox según estado activo/disabled. |
|
|
250
|
+
| `radioClass` | `function(model, disabled)` | Ver abajo | Clases de color del radio button según estado. |
|
|
251
|
+
| `switchClass` | `function(model, disabled)` | Ver abajo | Clases de color de la pista del switch. |
|
|
252
|
+
| `switchDotClass` | `function(model, disabled)` | Ver abajo | Clases de color de la bola interior del switch. |
|
|
253
|
+
|
|
254
|
+
```js
|
|
255
|
+
configureStyles({
|
|
256
|
+
checkBoxClass: (model, disabled) => {
|
|
257
|
+
if (disabled) return model
|
|
258
|
+
? 'bg-indigo-200 border-indigo-200 cursor-not-allowed'
|
|
259
|
+
: 'bg-gray-100 border-gray-200 cursor-not-allowed'
|
|
260
|
+
return model
|
|
261
|
+
? 'bg-indigo-500 border-indigo-500 peer-focus:ring-2 peer-focus:ring-indigo-200'
|
|
262
|
+
: 'bg-white border-gray-300 peer-focus:ring-2 peer-focus:ring-indigo-200'
|
|
263
|
+
},
|
|
264
|
+
})
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
### Paginación
|
|
270
|
+
_Afecta: `PaginationStyle`_
|
|
271
|
+
|
|
272
|
+
| Token | Tipo | Default | Descripción |
|
|
273
|
+
| ----- | ---- | ------- | ----------- |
|
|
274
|
+
| `PAGINATION_NAV_PREV` | `string` | `'bg-white hover:bg-indigo-50 border ...'` | Clases del botón de página anterior. |
|
|
275
|
+
| `PAGINATION_NAV_NEXT` | `string` | `'bg-white hover:bg-indigo-50 border ...'` | Clases del botón de página siguiente. |
|
|
276
|
+
| `PAGINATION_PAGE_BASE` | `string` | `'border px-2.5 py-2 cursor-pointer w-8 relative'` | Clases base de cada botón de página. |
|
|
277
|
+
| `paginationPageClass` | `function(page, actualPage, index)` | Ver abajo | Retorna clases dinámicas por botón de página. |
|
|
278
|
+
| `PAGINATION_SUMMARY` | `string` | `'text-sm text-gray-700'` | Clases del texto de resumen de registros. |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### Loader
|
|
283
|
+
_Afecta: `LoaderStyle`_
|
|
284
|
+
|
|
285
|
+
| Token | Tipo | Default | Descripción |
|
|
286
|
+
| ----- | ---- | ------- | ----------- |
|
|
287
|
+
| `LOADER_ARC_STROKE` | `string` | `'#6366F1'` | Color hex del arco animado del loader (indigo-500). |
|
|
288
|
+
| `LOADER_MESSAGE` | `string` | `'text-gray-600 text-lg font-medium'` | Clases del mensaje de carga. |
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### Iconos y asterisco de requerido
|
|
293
|
+
_Afecta: todos los componentes con `required` o iconos de validación_
|
|
294
|
+
|
|
295
|
+
| Token | Tipo | Default | Descripción |
|
|
296
|
+
| ----- | ---- | ------- | ----------- |
|
|
297
|
+
| `REQUIRED_ASTERISK` | `string` | `'text-red-500'` | Clase de color del asterisco `*` en campos requeridos. |
|
|
298
|
+
| `ICON_VALID` | `string` | `'text-emerald-500'` | Clase de color del ícono de validación correcta. |
|
|
299
|
+
| `ICON_INVALID` | `string` | `'text-red-500'` | Clase de color del ícono de validación errónea. |
|
|
300
|
+
| `ICON_STATIC` | `string` | `'text-indigo-400'` | Clase de color de los íconos estáticos (reloj, calendario, ojo, chevron). |
|
|
301
|
+
| `ICON_SIZE_STATIC` | `string` | `'w-5 h-5'` | Clases de tamaño de todos los íconos. |
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
### File Upload y Download
|
|
306
|
+
_Afecta: `InputFileUploadStyle`, `InputFileDownloadStyle`_
|
|
307
|
+
|
|
308
|
+
| Token | Tipo | Default | Descripción |
|
|
309
|
+
| ----- | ---- | ------- | ----------- |
|
|
310
|
+
| `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). |
|
|
311
|
+
| `FILE_BUTTON_ACTIVE` | `string` | `'border-gray-200 bg-white text-gray-700 hover:border-indigo-400 ...'` | Clases del botón en estado normal/activo. |
|
|
312
|
+
| `FILE_BUTTON_DISABLED` | `string` | `'border-gray-200 bg-gray-100 text-gray-400'` | Clases del botón en estado disabled. |
|
|
313
|
+
| `FILE_ICON_BG` | `string` | `'bg-indigo-300'` | Fondo del círculo de ícono en estado activo. |
|
|
314
|
+
| `FILE_ICON_BG_COMPLETE` | `string` | `'bg-emerald-500'` | Fondo del círculo de ícono cuando la descarga está completa. |
|
|
315
|
+
| `FILE_ICON_BG_DISABLED` | `string` | `'bg-gray-300'` | Fondo del círculo de ícono en estado disabled. |
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
### Time Picker
|
|
320
|
+
_Afecta: `InputTimeStyle`_
|
|
321
|
+
|
|
322
|
+
| Token | Tipo | Default | Descripción |
|
|
323
|
+
| ----- | ---- | ------- | ----------- |
|
|
324
|
+
| `TIME_PICKER_WRAPPER` | `string` | `'absolute z-20 left-0 top-full rounded-lg bg-white'` | Contenedor flotante del picker. |
|
|
325
|
+
| `TIME_PICKER_CONTAINER` | `string` | `'border border-gray-300 rounded-lg p-3'` | Borde interior del picker. |
|
|
326
|
+
| `TIME_PICKER_COLUMN` | `string` | `'h-48 overflow-y-auto border border-gray-200 rounded-md ...'` | Columna scrollable de horas/minutos. |
|
|
327
|
+
| `TIME_PICKER_AMPM_COLUMN` | `string` | `'h-48 overflow-y-auto border border-gray-200 rounded-md ...'` | Columna scrollable AM/PM. |
|
|
328
|
+
| `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"). |
|
|
329
|
+
| `TIME_PICKER_ITEM` | `string` | `'px-3 py-1 text-center cursor-pointer hover:bg-indigo-50 ...'` | Fila base de cada ítem del picker. |
|
|
330
|
+
| `timePickerItemClass` | `function(isActive)` | Ver abajo | Clases dinámicas de cada ítem según si está seleccionado. |
|
|
331
|
+
|
|
332
|
+
------
|
|
333
|
+
|
|
334
|
+
# 🧩 Componentes
|
|
335
|
+
|
|
336
|
+
## Props comunes
|
|
337
|
+
|
|
338
|
+
La mayoría de los componentes comparten las siguientes props:
|
|
339
|
+
|
|
340
|
+
| Prop | Tipo | Default | Descripción |
|
|
341
|
+
| ---- | ---- | ------- | ----------- |
|
|
342
|
+
| `modelValue` | `String \| Number \| Boolean` | — | Valor del campo (v-model). |
|
|
343
|
+
| `id` | `String` | `null` | Id propio del control. Si se omite, se genera automáticamente (uuid) y se mantiene enlazado con el `<label for>`. |
|
|
344
|
+
| `name` | `String` | `null` | Atributo `name` nativo del control (`input` / `textarea` / `file` / `button`). Útil para envío de formularios, autocompletado y accesibilidad. |
|
|
345
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo automáticamente al montarse. |
|
|
346
|
+
| `label` | `String` | `''` | Texto del label del campo. |
|
|
347
|
+
| `description` | `String` | `''` | Texto de ayuda debajo del campo. Cambia de color según el estado de validación. |
|
|
348
|
+
| `placeholder` | `String` | `''` | Placeholder del input. |
|
|
349
|
+
| `disabled` | `Boolean` | `false` | Deshabilita el campo. |
|
|
350
|
+
| `required` | `Boolean` | `false` | Marca el campo como requerido (muestra asterisco `*`). |
|
|
351
|
+
| `validate` | `Boolean \| null` | `null` | Estado de validación: `true` = válido, `false` = inválido, `null` = sin estado. |
|
|
352
|
+
| `mclass` | `String` | `null` | Clases CSS adicionales aplicadas directamente al elemento del input. |
|
|
353
|
+
|
|
354
|
+
## Eventos comunes
|
|
355
|
+
|
|
356
|
+
| Evento | Payload | Descripción |
|
|
357
|
+
| ------ | ------- | ----------- |
|
|
358
|
+
| `update:modelValue` | `value` | Se dispara al cambiar el valor (permite `v-model`). |
|
|
359
|
+
| `change` | `value` | Se dispara al cambiar el valor. |
|
|
360
|
+
| `blur` | `event` | Se dispara al perder el foco. |
|
|
361
|
+
|
|
362
|
+
------
|
|
363
|
+
|
|
364
|
+
## InputTextStyle
|
|
365
|
+
|
|
366
|
+
Input de texto genérico. Soporta tipos `text`, `email`, `search`, `tel`, `url` y `number`.
|
|
367
|
+
|
|
368
|
+
```vue
|
|
369
|
+
<InputTextStyle
|
|
370
|
+
v-model="nombre"
|
|
371
|
+
label="Nombre"
|
|
372
|
+
placeholder="Escribe tu nombre"
|
|
373
|
+
:required="true"
|
|
374
|
+
:validate="validate"
|
|
375
|
+
description="Campo requerido"
|
|
376
|
+
/>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
| Prop | Tipo | Default | Descripción |
|
|
380
|
+
| ---- | ---- | ------- | ----------- |
|
|
381
|
+
| `modelValue` | `String \| Number` | `''` | Valor del campo. |
|
|
382
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
383
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
384
|
+
| `autocomplete` | `String` | `null` | Atributo `autocomplete` nativo (ej: `email`, `username`, `off`). |
|
|
385
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
386
|
+
| `readonly` | `Boolean` | `false` | Solo lectura: no editable, pero se envía en el formulario. |
|
|
387
|
+
| `label` | `String` | `''` | |
|
|
388
|
+
| `description` | `String` | `''` | |
|
|
389
|
+
| `placeholder` | `String` | `''` | |
|
|
390
|
+
| `type` | `String` | `'text'` | Tipo del input: `text`, `email`, `search`, `tel`, `url`, `number`. |
|
|
391
|
+
| `maxlength` | `String` | `null` | Longitud máxima de caracteres. |
|
|
392
|
+
| `minlength` | `String` | `null` | Longitud mínima de caracteres. |
|
|
393
|
+
| `min` | `String` | `null` | Valor mínimo (solo cuando `type="number"`, aplicado al perder el foco). |
|
|
394
|
+
| `max` | `String` | `null` | Valor máximo (solo cuando `type="number"`, aplicado al perder el foco). |
|
|
395
|
+
| `disabled` | `Boolean` | `false` | |
|
|
396
|
+
| `required` | `Boolean` | `false` | |
|
|
397
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
398
|
+
| `mclass` | `String` | `null` | |
|
|
399
|
+
|
|
400
|
+
------
|
|
401
|
+
|
|
402
|
+
## InputNumberStyle
|
|
403
|
+
|
|
404
|
+
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`.
|
|
405
|
+
|
|
406
|
+
```vue
|
|
407
|
+
<InputNumberStyle
|
|
408
|
+
v-model="monto"
|
|
409
|
+
label="Monto"
|
|
410
|
+
numeric="10,2"
|
|
411
|
+
min="0"
|
|
412
|
+
max="9999999999"
|
|
413
|
+
:required="true"
|
|
414
|
+
:validate="validate"
|
|
415
|
+
/>
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
| Prop | Tipo | Default | Descripción |
|
|
419
|
+
| ---- | ---- | ------- | ----------- |
|
|
420
|
+
| `modelValue` | `String \| Number` | `''` | Valor del campo. |
|
|
421
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
422
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
423
|
+
| `autocomplete` | `String` | `null` | Atributo `autocomplete` nativo. |
|
|
424
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
425
|
+
| `readonly` | `Boolean` | `false` | Solo lectura: bloquea la edición y los botones ▲/▼, pero se envía en el formulario. |
|
|
426
|
+
| `label` | `String` | `''` | |
|
|
427
|
+
| `description` | `String` | `''` | |
|
|
428
|
+
| `placeholder` | `String` | `''` | |
|
|
429
|
+
| `numeric` | `String` | `null` | Formato tipo SQL: `"10,2"` → 10 dígitos enteros, 2 decimales. Si se omite, usa `10,2` por defecto. |
|
|
430
|
+
| `min` | `String` | `null` | Valor mínimo (aplicado al perder el foco). Si es `null` o negativo, permite negativos. |
|
|
431
|
+
| `max` | `String` | `null` | Valor máximo (aplicado al perder el foco). |
|
|
432
|
+
| `alignLeft` | `Boolean` | `false` | Posición de los botones de paso (▲/▼) respecto al valor. `false` = botones a la izquierda, valor a la derecha (`Rows \| Input`); `true` = botones a la derecha, valor a la izquierda (`Input \| Rows`). |
|
|
433
|
+
| `disabled` | `Boolean` | `false` | |
|
|
434
|
+
| `required` | `Boolean` | `false` | |
|
|
435
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
436
|
+
| `mclass` | `String` | `null` | |
|
|
437
|
+
|
|
438
|
+
**Comportamiento:**
|
|
439
|
+
- Incluye botones **caret ▲ / ▼** para aumentar/disminuir el valor en unidades (respetando `min`/`max`). Por defecto se alinean a la izquierda del campo (con el valor a la derecha); con `alignLeft` se mueven a la derecha y el valor pasa a la izquierda. No tienen separador y usan el color global de los iconos (`ICON_STATIC`).
|
|
440
|
+
- Si **mantienes presionado** un botón, tras una breve pausa el valor cambia de forma **continua** hasta soltar.
|
|
441
|
+
- Puedes escribir `0` y luego `.` para empezar los decimales: el punto se conserva a la espera de los dígitos decimales (solo si los decimales están activados en `numeric`).
|
|
442
|
+
- Al **enfocar** el campo, si el valor es `0` (o está vacío) se limpia, para que al escribir reemplaces el valor en lugar de anteponerlo.
|
|
443
|
+
- Al **perder el foco**, si el campo queda vacío o en `0`, se conserva el valor `0` formateado (ej: `"0.00"`), aplicando además los límites `min`/`max`.
|
|
444
|
+
|
|
445
|
+
**Navegación por teclado:**
|
|
446
|
+
- `↑` / `↓` — aumentar/disminuir el valor en unidades, respetando `min`/`max`.
|
|
447
|
+
|
|
448
|
+
------
|
|
449
|
+
|
|
450
|
+
## InputPasswordStyle
|
|
451
|
+
|
|
452
|
+
Input de contraseña con toggle para mostrar/ocultar el texto.
|
|
453
|
+
|
|
454
|
+
```vue
|
|
455
|
+
<InputPasswordStyle
|
|
456
|
+
v-model="password"
|
|
457
|
+
label="Contraseña"
|
|
458
|
+
placeholder="Mínimo 8 caracteres"
|
|
459
|
+
:required="true"
|
|
460
|
+
:validate="validate"
|
|
461
|
+
/>
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
| Prop | Tipo | Default | Descripción |
|
|
465
|
+
| ---- | ---- | ------- | ----------- |
|
|
466
|
+
| `modelValue` | `String \| Number` | `''` | Valor del campo. |
|
|
467
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
468
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
469
|
+
| `autocomplete` | `String` | `null` | Atributo `autocomplete` nativo (ej: `current-password`, `new-password`). |
|
|
470
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
471
|
+
| `readonly` | `Boolean` | `false` | Solo lectura: no editable, pero se envía en el formulario. |
|
|
472
|
+
| `label` | `String` | `''` | |
|
|
473
|
+
| `description` | `String` | `''` | |
|
|
474
|
+
| `placeholder` | `String` | `''` | |
|
|
475
|
+
| `maxlength` | `String` | `null` | Longitud máxima. |
|
|
476
|
+
| `disabled` | `Boolean` | `false` | |
|
|
477
|
+
| `required` | `Boolean` | `false` | |
|
|
478
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
479
|
+
| `mclass` | `String` | `null` | |
|
|
480
|
+
|
|
481
|
+
------
|
|
482
|
+
|
|
483
|
+
## TextAreaStyle
|
|
484
|
+
|
|
485
|
+
Área de texto multi-línea.
|
|
486
|
+
|
|
487
|
+
```vue
|
|
488
|
+
<TextAreaStyle
|
|
489
|
+
v-model="comentario"
|
|
490
|
+
label="Comentario"
|
|
491
|
+
placeholder="Escribe aquí..."
|
|
492
|
+
row="5"
|
|
493
|
+
:maxlength="500"
|
|
494
|
+
:validate="validate"
|
|
495
|
+
/>
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
| Prop | Tipo | Default | Descripción |
|
|
499
|
+
| ---- | ---- | ------- | ----------- |
|
|
500
|
+
| `modelValue` | `String` | `''` | Valor del campo. |
|
|
501
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<textarea>`. |
|
|
502
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
503
|
+
| `autocomplete` | `String` | `null` | Atributo `autocomplete` nativo. |
|
|
504
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
505
|
+
| `readonly` | `Boolean` | `false` | Solo lectura: no editable, pero se envía en el formulario. |
|
|
506
|
+
| `label` | `String` | `''` | |
|
|
507
|
+
| `description` | `String` | `''` | |
|
|
508
|
+
| `placeholder` | `String` | `''` | |
|
|
509
|
+
| `row` | `String` | `'3'` | Número de filas visibles del textarea. |
|
|
510
|
+
| `maxlength` | `String` | `null` | Longitud máxima de caracteres. |
|
|
511
|
+
| `disabled` | `Boolean` | `false` | |
|
|
512
|
+
| `required` | `Boolean` | `false` | |
|
|
513
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
514
|
+
| `mclass` | `String` | `null` | |
|
|
515
|
+
|
|
516
|
+
------
|
|
517
|
+
|
|
518
|
+
## SelectStyle
|
|
519
|
+
|
|
520
|
+
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.
|
|
521
|
+
|
|
522
|
+
```vue
|
|
523
|
+
<SelectStyle
|
|
524
|
+
v-model="pais"
|
|
525
|
+
label="País"
|
|
526
|
+
:list="paises"
|
|
527
|
+
return-value="value"
|
|
528
|
+
:required="true"
|
|
529
|
+
:validate="validate"
|
|
530
|
+
/>
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
```js
|
|
534
|
+
// Formato del array `list` — lista plana
|
|
535
|
+
const paises = [
|
|
536
|
+
{ value: 1, text: 'México' },
|
|
537
|
+
{ value: 2, text: 'España' },
|
|
538
|
+
{ value: 3, text: 'Argentina' },
|
|
539
|
+
]
|
|
540
|
+
|
|
541
|
+
// El `value` es opcional: si se omite, se usa el `text` como valor
|
|
542
|
+
const colores = [
|
|
543
|
+
{ text: 'Rojo' },
|
|
544
|
+
{ text: 'Verde' },
|
|
545
|
+
]
|
|
546
|
+
|
|
547
|
+
// Lista agrupada — cada grupo tiene un `label` y sus `options`
|
|
548
|
+
const ubicaciones = [
|
|
549
|
+
{ label: 'América', options: [{ value: 1, text: 'México' }, { value: 2, text: 'Argentina' }] },
|
|
550
|
+
{ label: 'Europa', options: [{ value: 3, text: 'España' }, { value: 4, text: 'Francia' }] },
|
|
551
|
+
]
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
| Prop | Tipo | Default | Descripción |
|
|
555
|
+
| ---- | ---- | ------- | ----------- |
|
|
556
|
+
| `modelValue` | `String \| Number \| Object` | — | Valor seleccionado. |
|
|
557
|
+
| `list` | `Array` | `[]` | Array de opciones. Acepta lista plana `{ value, text }` o agrupada `{ label, options: [...] }`. El `value` es opcional: si se omite, se usa el `text` como valor. |
|
|
558
|
+
| `returnValue` | `String` | `'value'` | Qué se emite al seleccionar: `'value'` (item.value), `'text'` (item.text) u `'object'` (el item completo). |
|
|
559
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
560
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
561
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
562
|
+
| `label` | `String` | `''` | |
|
|
563
|
+
| `description` | `String` | `''` | |
|
|
564
|
+
| `wrapOptions` | `Boolean` | `false` | `true` = permite que el texto de cada opción haga salto de línea; `false` = lo trunca con elipsis. |
|
|
565
|
+
| `disabled` | `Boolean` | `false` | |
|
|
566
|
+
| `required` | `Boolean` | `false` | |
|
|
567
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
568
|
+
| `mclass` | `String` | `null` | |
|
|
569
|
+
|
|
570
|
+
**Navegación por teclado:**
|
|
571
|
+
- `↑` / `↓` — navegar opciones
|
|
572
|
+
- `Enter` — seleccionar la opción resaltada
|
|
573
|
+
- `Escape` — cerrar el dropdown
|
|
574
|
+
- Tipear letras — búsqueda inmediata en la lista
|
|
575
|
+
|
|
576
|
+
------
|
|
577
|
+
|
|
578
|
+
## InputAutocompleteStyle
|
|
579
|
+
|
|
580
|
+
Autocomplete basado en `SelectStyle`, pero con el **input editable**: el usuario escribe para filtrar las opciones en vivo. Mantiene el mismo formato de `list` (plana o agrupada) y la misma navegación por teclado y posicionamiento automático del dropdown.
|
|
581
|
+
|
|
582
|
+
Incluye un estado de **carga/búsqueda** controlado por la prop `loading`: cuando es `true`, oculta las opciones y muestra el mensaje _"Buscando coincidencias..."_ — pensado para búsquedas asíncronas donde el listado se resuelve en el servidor.
|
|
583
|
+
|
|
584
|
+
```vue
|
|
585
|
+
<InputAutocompleteStyle
|
|
586
|
+
v-model="pais"
|
|
587
|
+
label="País"
|
|
588
|
+
:list="paises"
|
|
589
|
+
placeholder="Escribe para buscar"
|
|
590
|
+
:loading="buscando"
|
|
591
|
+
return-value="value"
|
|
592
|
+
:validate="validate"
|
|
593
|
+
@search="onSearch"
|
|
594
|
+
/>
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
```js
|
|
598
|
+
// El evento @search se emite en cada tecleo; úsalo para disparar una
|
|
599
|
+
// búsqueda asíncrona y controlar la prop `loading`.
|
|
600
|
+
function onSearch(query) {
|
|
601
|
+
buscando.value = true
|
|
602
|
+
fetchPaises(query).then(res => {
|
|
603
|
+
paises.value = res
|
|
604
|
+
buscando.value = false
|
|
605
|
+
})
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
```js
|
|
610
|
+
// Formato del array `list` — idéntico a SelectStyle (plana o agrupada)
|
|
611
|
+
const paises = [
|
|
612
|
+
{ value: 1, text: 'México' },
|
|
613
|
+
{ value: 2, text: 'España' },
|
|
614
|
+
{ value: 3, text: 'Argentina' },
|
|
615
|
+
]
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
| Prop | Tipo | Default | Descripción |
|
|
619
|
+
| ---- | ---- | ------- | ----------- |
|
|
620
|
+
| `modelValue` | `String \| Number \| Object` | — | Valor seleccionado. |
|
|
621
|
+
| `list` | `Array` | `[]` | Array de opciones. Acepta lista plana `{ value, text }` o agrupada `{ label, options: [...] }`. El `value` es opcional: si se omite, se usa el `text` como valor. |
|
|
622
|
+
| `returnValue` | `String` | `'value'` | Qué se emite al seleccionar: `'value'` (item.value), `'text'` (item.text) u `'object'` (el item completo). |
|
|
623
|
+
| `loading` | `Boolean` | `false` | Cuando es `true`, oculta las opciones y muestra "Buscando coincidencias...". Úsalo mientras resuelves una búsqueda asíncrona. |
|
|
624
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
625
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
626
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
627
|
+
| `label` | `String` | `''` | |
|
|
628
|
+
| `description` | `String` | `''` | |
|
|
629
|
+
| `placeholder` | `String` | `''` | |
|
|
630
|
+
| `wrapOptions` | `Boolean` | `false` | `true` = permite que el texto de cada opción haga salto de línea; `false` = lo trunca con elipsis. |
|
|
631
|
+
| `disabled` | `Boolean` | `false` | |
|
|
632
|
+
| `required` | `Boolean` | `false` | |
|
|
633
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
634
|
+
| `mclass` | `String` | `null` | |
|
|
635
|
+
|
|
636
|
+
**Eventos:**
|
|
637
|
+
- `search` — se emite en cada cambio del texto escrito, con el `query` actual como payload. Ideal para búsquedas asíncronas.
|
|
638
|
+
- `update:modelValue` / `change` — emiten el valor al seleccionar una opción (según `returnValue`).
|
|
639
|
+
- `blur` — al cerrarse el dropdown.
|
|
640
|
+
|
|
641
|
+
**Comportamiento:**
|
|
642
|
+
- Al abrir (foco o clic en el chevron) muestra todas las opciones; al teclear, filtra por coincidencia de texto (sin distinguir mayúsculas).
|
|
643
|
+
- Al seleccionar una opción, el input muestra su `text`.
|
|
644
|
+
- Si se cierra el dropdown sin seleccionar, el input vuelve a reflejar la selección real (descarta el texto escrito sin confirmar).
|
|
645
|
+
|
|
646
|
+
**Navegación por teclado:**
|
|
647
|
+
- `↑` / `↓` — navegar opciones
|
|
648
|
+
- `Enter` — seleccionar la opción resaltada
|
|
649
|
+
- `Escape` — cerrar el dropdown
|
|
650
|
+
|
|
651
|
+
------
|
|
652
|
+
|
|
653
|
+
## InputCheckStyle
|
|
654
|
+
|
|
655
|
+
Checkbox estilizado con label y descripción.
|
|
656
|
+
|
|
657
|
+
```vue
|
|
658
|
+
<InputCheckStyle
|
|
659
|
+
v-model="aceptaTerminos"
|
|
660
|
+
label="Acepto los términos y condiciones"
|
|
661
|
+
:required="true"
|
|
662
|
+
/>
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
| Prop | Tipo | Default | Descripción |
|
|
666
|
+
| ---- | ---- | ------- | ----------- |
|
|
667
|
+
| `modelValue` | `Boolean \| Array \| String \| Number` | `false` | Estado del check (modo simple) o array de valores seleccionados (modo grupo). |
|
|
668
|
+
| `value` | `String \| Number \| Boolean` | `null` | Valor que aporta este checkbox al grupo. Se usa cuando `modelValue` es un `Array` (checkbox múltiple nativo). |
|
|
669
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. Comparte el mismo `name` entre las casillas del grupo. |
|
|
670
|
+
| `id` | `String` | `null` | Id propio del `<input>`; si se omite se genera automáticamente. |
|
|
671
|
+
| `label` | `String` | `''` | |
|
|
672
|
+
| `description` | `String` | `''` | |
|
|
673
|
+
| `disabled` | `Boolean` | `false` | |
|
|
674
|
+
| `required` | `Boolean` | `false` | |
|
|
675
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
676
|
+
| `mclass` | `String` | `null` | Clases adicionales del cuadro del checkbox. |
|
|
677
|
+
|
|
678
|
+
**Dos modos de uso:**
|
|
679
|
+
|
|
680
|
+
- **Modo simple (por defecto):** con `modelValue` booleano, se comporta como un check `true`/`false`.
|
|
681
|
+
|
|
682
|
+
```vue
|
|
683
|
+
<InputCheckStyle v-model="acepto" label="Acepto los términos" />
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
- **Modo grupo nativo:** enlaza varias casillas a un `v-model` de tipo **array**, cada una con su `value` y el mismo `name`. Marcar/desmarcar agrega o quita el `value` del array, y en un `<form>` nativo el navegador envía un `name=<value>` por cada casilla marcada (`FormData.getAll`).
|
|
687
|
+
|
|
688
|
+
```vue
|
|
689
|
+
<form @submit.prevent="onSubmit">
|
|
690
|
+
<InputCheckStyle v-model="perms" name="perm" value="read" label="Leer" />
|
|
691
|
+
<InputCheckStyle v-model="perms" name="perm" value="write" label="Escribir" />
|
|
692
|
+
<InputCheckStyle v-model="perms" name="perm" value="delete" label="Eliminar" />
|
|
693
|
+
</form>
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
```js
|
|
697
|
+
// perms === ['read', 'write'] → FormData del <form>: perm=read, perm=write
|
|
698
|
+
data() { return { perms: ['read', 'write'] } },
|
|
699
|
+
onSubmit(e) { console.log(new FormData(e.target).getAll('perm')) }
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
**Eventos:** `update:modelValue` y `change` emiten el array actualizado (modo grupo) o el booleano (modo simple).
|
|
703
|
+
|
|
704
|
+
------
|
|
705
|
+
|
|
706
|
+
## InputRadioStyle
|
|
707
|
+
|
|
708
|
+
Radio button estilizado con label y descripción.
|
|
709
|
+
|
|
710
|
+
```vue
|
|
711
|
+
<InputRadioStyle
|
|
712
|
+
v-model="opcionA"
|
|
713
|
+
label="Opción A"
|
|
714
|
+
/>
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
| Prop | Tipo | Default | Descripción |
|
|
718
|
+
| ---- | ---- | ------- | ----------- |
|
|
719
|
+
| `modelValue` | `String \| Number \| Boolean` | `false` | Valor seleccionado del grupo (modo grupo) o estado del toggle (modo booleano). |
|
|
720
|
+
| `value` | `String \| Number \| Boolean` | `null` | Valor que representa este radio dentro del grupo. Si se define, actúa como radio nativo real (`type="radio"`); si se omite, se comporta como toggle booleano. |
|
|
721
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. **Requerido** para agrupar varios radios en modo nativo. |
|
|
722
|
+
| `id` | `String` | `null` | Id propio del `<input>`; si se omite se genera automáticamente. |
|
|
723
|
+
| `label` | `String` | `''` | |
|
|
724
|
+
| `description` | `String` | `''` | |
|
|
725
|
+
| `disabled` | `Boolean` | `false` | |
|
|
726
|
+
| `required` | `Boolean` | `false` | |
|
|
727
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
728
|
+
| `mclass` | `String` | `null` | Clases adicionales del círculo del radio. |
|
|
729
|
+
|
|
730
|
+
**Dos modos de uso:**
|
|
731
|
+
|
|
732
|
+
- **Modo booleano (por defecto):** sin `value`, se comporta como un toggle `true`/`false`. Útil para una sola opción.
|
|
733
|
+
|
|
734
|
+
```vue
|
|
735
|
+
<InputRadioStyle v-model="acepto" label="Acepto" />
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
- **Modo grupo nativo:** al definir `value` en cada radio y compartir el mismo `name`, se comportan como un grupo de radios reales (`type="radio"`): seleccionar uno deselecciona los demás, `v-model` guarda el `value` elegido y en un `<form>` nativo el navegador envía `name=<value seleccionado>`.
|
|
739
|
+
|
|
740
|
+
```vue
|
|
741
|
+
<form @submit.prevent="onSubmit">
|
|
742
|
+
<InputRadioStyle v-model="plan" name="plan" value="free" label="Free" />
|
|
743
|
+
<InputRadioStyle v-model="plan" name="plan" value="pro" label="Pro" />
|
|
744
|
+
<InputRadioStyle v-model="plan" name="plan" value="enterprise" label="Enterprise" />
|
|
745
|
+
</form>
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
```js
|
|
749
|
+
// plan === 'pro' → FormData del <form> contiene plan=pro
|
|
750
|
+
onSubmit(e) { console.log(new FormData(e.target).get('plan')) }
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
**Eventos:** `update:modelValue` y `change` emiten el `value` seleccionado (modo grupo) o el booleano (modo toggle).
|
|
754
|
+
|
|
755
|
+
------
|
|
756
|
+
|
|
757
|
+
## InputSwitchStyle
|
|
758
|
+
|
|
759
|
+
Toggle switch estilizado.
|
|
760
|
+
|
|
761
|
+
```vue
|
|
762
|
+
<InputSwitchStyle
|
|
763
|
+
v-model="activo"
|
|
764
|
+
label="Activar notificaciones"
|
|
765
|
+
/>
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
| Prop | Tipo | Default | Descripción |
|
|
769
|
+
| ---- | ---- | ------- | ----------- |
|
|
770
|
+
| `modelValue` | `Boolean` | `false` | Estado del switch. |
|
|
771
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
772
|
+
| `id` | `String` | `null` | Id propio del `<input>`; si se omite se genera automáticamente. |
|
|
773
|
+
| `label` | `String` | `''` | |
|
|
774
|
+
| `description` | `String` | `''` | |
|
|
775
|
+
| `disabled` | `Boolean` | `false` | |
|
|
776
|
+
| `required` | `Boolean` | `false` | |
|
|
777
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
778
|
+
| `mclass` | `String` | `null` | Clases adicionales de la pista del switch. |
|
|
779
|
+
|
|
780
|
+
------
|
|
781
|
+
|
|
782
|
+
## InputDateStyle
|
|
783
|
+
|
|
784
|
+
Selector de fecha con máscara `dd/mm/aaaa`, navegación por teclado entre secciones y calendario visual nativo (sin dependencias externas). El valor se emite en formato `YYYY-MM-DD`.
|
|
785
|
+
|
|
786
|
+
El calendario incluye vistas de días, meses y años, y un botón **Hoy** para navegar rápidamente a la fecha actual.
|
|
787
|
+
|
|
788
|
+
```vue
|
|
789
|
+
<InputDateStyle
|
|
790
|
+
v-model="fechaNacimiento"
|
|
791
|
+
label="Fecha de nacimiento"
|
|
792
|
+
min="1900-01-01"
|
|
793
|
+
max="2100-12-31"
|
|
794
|
+
:validate="validate"
|
|
795
|
+
/>
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
| Prop | Tipo | Default | Descripción |
|
|
799
|
+
| ---- | ---- | ------- | ----------- |
|
|
800
|
+
| `modelValue` | `String \| Date` | — | Valor de la fecha en formato `YYYY-MM-DD` o `Date`. |
|
|
801
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
802
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
803
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
804
|
+
| `label` | `String` | `''` | |
|
|
805
|
+
| `description` | `String` | `''` | |
|
|
806
|
+
| `min` | `String` | `'1900-01-01'` | Fecha mínima seleccionable en el calendario (formato `YYYY-MM-DD`). |
|
|
807
|
+
| `max` | `String` | `'2100-12-31'` | Fecha máxima seleccionable en el calendario (formato `YYYY-MM-DD`). |
|
|
808
|
+
| `disabledDates` | `Array` | `[]` | Fechas deshabilitadas. Array de strings `'YYYY-MM-DD'` o objetos `Date`. |
|
|
809
|
+
| `disabled` | `Boolean` | `false` | |
|
|
810
|
+
| `readonly` | `Boolean` | `false` | Solo lectura: muestra el valor pero bloquea la edición por teclado. |
|
|
811
|
+
| `required` | `Boolean` | `false` | |
|
|
812
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
813
|
+
| `mclass` | `String` | `null` | |
|
|
814
|
+
|
|
815
|
+
**Valor emitido:** `'YYYY-MM-DD'` (string) o `''` si la fecha es inválida o está vacía.
|
|
816
|
+
|
|
817
|
+
**Navegación por teclado:**
|
|
818
|
+
- Escribe los dígitos y el foco avanza automáticamente entre día → mes → año
|
|
819
|
+
- `↑` / `↓` — incrementar/decrementar la sección activa (la fecha resultante se ajusta a los límites `min`/`max`)
|
|
820
|
+
- `←` / `→` — mover entre secciones
|
|
821
|
+
- `Tab` / `Shift + Tab` — mover entre secciones (al llegar al extremo, el foco sale del campo)
|
|
822
|
+
- `Backspace` / `Delete` — limpiar la sección activa
|
|
823
|
+
- Clic en el ícono 📅 — abre/cierra el calendario visual
|
|
824
|
+
|
|
825
|
+
------
|
|
826
|
+
|
|
827
|
+
## InputTimeStyle
|
|
828
|
+
|
|
829
|
+
Selector de hora con picker de columnas scrollables. Soporta formato 12h (AM/PM) o 24h. El valor se emite en formato `HH:mm`.
|
|
830
|
+
|
|
831
|
+
```vue
|
|
832
|
+
<InputTimeStyle
|
|
833
|
+
v-model="horaInicio"
|
|
834
|
+
label="Hora de inicio"
|
|
835
|
+
min="08:00"
|
|
836
|
+
max="18:00"
|
|
837
|
+
:is24h="true"
|
|
838
|
+
:validate="validate"
|
|
839
|
+
/>
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
| Prop | Tipo | Default | Descripción |
|
|
843
|
+
| ---- | ---- | ------- | ----------- |
|
|
844
|
+
| `modelValue` | `String` | — | Valor de la hora en formato `HH:mm`. |
|
|
845
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
846
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
847
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
848
|
+
| `label` | `String` | `''` | |
|
|
849
|
+
| `description` | `String` | `''` | |
|
|
850
|
+
| `min` | `String` | `null` | Hora mínima (ej: `'08:00'`). |
|
|
851
|
+
| `max` | `String` | `null` | Hora máxima (ej: `'18:00'`). |
|
|
852
|
+
| `is24h` | `Boolean` | `false` | `true` = formato 24h, `false` = formato 12h con selector AM/PM. |
|
|
853
|
+
| `disabled` | `Boolean` | `false` | |
|
|
854
|
+
| `required` | `Boolean` | `false` | |
|
|
855
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
856
|
+
| `mclass` | `String` | `null` | |
|
|
857
|
+
|
|
858
|
+
**Valor emitido:** `'HH:mm'` en formato 24h siempre, independientemente del modo de visualización.
|
|
859
|
+
|
|
860
|
+
------
|
|
861
|
+
|
|
862
|
+
## InputDateTimeStyle
|
|
863
|
+
|
|
864
|
+
Selector combinado de fecha y hora con máscara `dd/mm/aaaa hh:mm` (o `dd/mm/aaaa hh:mm a.m.` en modo 12h), calendario visual nativo y picker de columnas scrollables para la hora. El valor se emite en formato `YYYY-MM-DDTHH:mm:00.000`.
|
|
865
|
+
|
|
866
|
+
```vue
|
|
867
|
+
<InputDateTimeStyle
|
|
868
|
+
v-model="fechaHora"
|
|
869
|
+
label="Fecha y hora"
|
|
870
|
+
min="2000-01-01"
|
|
871
|
+
max="2100-12-31"
|
|
872
|
+
:is24h="true"
|
|
873
|
+
:validate="validate"
|
|
874
|
+
/>
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
| Prop | Tipo | Default | Descripción |
|
|
878
|
+
| ---- | ---- | ------- | ----------- |
|
|
879
|
+
| `modelValue` | `String \| Date` | — | Valor en formato `YYYY-MM-DDTHH:mm:00.000` o `Date`. |
|
|
880
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input>`. |
|
|
881
|
+
| `id` | `String` | `null` | Id propio; si se omite se genera y se enlaza al `<label>`. |
|
|
882
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el campo al montarse. |
|
|
883
|
+
| `label` | `String` | `''` | |
|
|
884
|
+
| `description` | `String` | `''` | |
|
|
885
|
+
| `min` | `String` | `'1900-01-01'` | Fecha mínima seleccionable (formato `YYYY-MM-DD`). |
|
|
886
|
+
| `max` | `String` | `'2100-12-31'` | Fecha máxima seleccionable (formato `YYYY-MM-DD`). |
|
|
887
|
+
| `disabledDates` | `Array` | `[]` | Fechas deshabilitadas. Array de strings `'YYYY-MM-DD'` o `Date`. |
|
|
888
|
+
| `is24h` | `Boolean` | `false` | `true` = formato 24h, `false` = formato 12h con selector a.m./p.m. |
|
|
889
|
+
| `disabled` | `Boolean` | `false` | |
|
|
890
|
+
| `readonly` | `Boolean` | `false` | Solo lectura. |
|
|
891
|
+
| `required` | `Boolean` | `false` | |
|
|
892
|
+
| `validate` | `Boolean \| null` | `null` | |
|
|
893
|
+
| `mclass` | `String` | `null` | |
|
|
894
|
+
|
|
895
|
+
**Valor emitido:** `'YYYY-MM-DDTHH:mm:00.000'` (string) o `''` si la fecha/hora es inválida o está vacía.
|
|
896
|
+
|
|
897
|
+
**Comportamiento del picker:**
|
|
898
|
+
- El calendario permanece abierto al seleccionar la fecha, para que puedas ajustar también la hora.
|
|
899
|
+
- El selector de hora embebido en el picker usa las mismas columnas scrollables que `InputTimeStyle`.
|
|
900
|
+
- Botón **Ahora** — establece la fecha y hora actuales de un solo clic.
|
|
901
|
+
|
|
902
|
+
**Navegación por teclado:**
|
|
903
|
+
- Escribe los dígitos y el foco avanza automáticamente: día → mes → año → hora → minuto → a.m./p.m.
|
|
904
|
+
- `↑` / `↓` — incrementar/decrementar la sección activa (la fecha se ajusta a los límites `min`/`max`)
|
|
905
|
+
- `←` / `→` — mover entre secciones
|
|
906
|
+
- `Tab` / `Shift + Tab` — mover entre secciones (al llegar al extremo, el foco sale del campo)
|
|
907
|
+
- `Backspace` / `Delete` — limpiar la sección activa
|
|
908
|
+
- `a` / `p` — cambiar entre a.m. y p.m. (solo modo 12h)
|
|
909
|
+
- Clic en el ícono 📅 — abre/cierra el picker
|
|
910
|
+
|
|
911
|
+
------
|
|
912
|
+
|
|
913
|
+
## InputFileUploadStyle
|
|
914
|
+
|
|
915
|
+
Botón para adjuntar archivos con validación de tamaño y formato.
|
|
916
|
+
|
|
917
|
+
```vue
|
|
918
|
+
<InputFileUploadStyle
|
|
919
|
+
v-model="archivo"
|
|
920
|
+
:formats="['pdf', 'docx']"
|
|
921
|
+
max-size-m-b="10"
|
|
922
|
+
:state="uploadState"
|
|
923
|
+
/>
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
| Prop | Tipo | Default | Descripción |
|
|
927
|
+
| ---- | ---- | ------- | ----------- |
|
|
928
|
+
| `modelValue` | `File` | `null` | Archivo seleccionado. |
|
|
929
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<input type="file">`. |
|
|
930
|
+
| `id` | `String` | `null` | Id propio del `<input type="file">`. |
|
|
931
|
+
| `disabled` | `Boolean` | `false` | Deshabilita el botón. |
|
|
932
|
+
| `formats` | `Array` | `[]` | Extensiones permitidas (ej: `['pdf', 'xlsx', 'png']`). Array vacío = todos los formatos. |
|
|
933
|
+
| `maxSizeMB` | `String \| Number` | `5` | Tamaño máximo del archivo en MB. |
|
|
934
|
+
| `state` | `String` | `'uphold'` | Estado del botón: `'uphold'` (normal) o `'loader'` (cargando, muestra spinner). |
|
|
935
|
+
| `delay` | `String` | `'1.5'` | Segundos de bloqueo del botón tras un clic, para evitar doble envío. |
|
|
936
|
+
|
|
937
|
+
**Eventos:**
|
|
938
|
+
- `update:modelValue` — emite el `File` seleccionado, o `null` si el archivo no es válido.
|
|
939
|
+
- `change` — igual que `update:modelValue`.
|
|
940
|
+
|
|
941
|
+
El componente valida automáticamente el tamaño y el formato, mostrando un mensaje de error inline si la validación falla.
|
|
942
|
+
|
|
943
|
+
------
|
|
944
|
+
|
|
945
|
+
## InputFileDownloadStyle
|
|
946
|
+
|
|
947
|
+
Botón para descargar archivos con tres estados visuales.
|
|
948
|
+
|
|
949
|
+
```vue
|
|
950
|
+
<InputFileDownloadStyle
|
|
951
|
+
:state="downloadState"
|
|
952
|
+
:disabled="false"
|
|
953
|
+
@click="descargarArchivo"
|
|
954
|
+
/>
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
| Prop | Tipo | Default | Descripción |
|
|
958
|
+
| ---- | ---- | ------- | ----------- |
|
|
959
|
+
| `disabled` | `Boolean` | `false` | Deshabilita el botón. |
|
|
960
|
+
| `state` | `String` | `'download'` | Estado: `'download'` (normal), `'loader'` (descargando, spinner), `'complete'` (completado, check verde). |
|
|
961
|
+
| `delay` | `String` | `'1.5'` | Segundos de bloqueo del botón tras un clic. |
|
|
962
|
+
|
|
963
|
+
**Eventos:**
|
|
964
|
+
- `click` — se dispara al hacer clic (solo si no está deshabilitado).
|
|
965
|
+
|
|
966
|
+
------
|
|
967
|
+
|
|
968
|
+
## ButtonStyle
|
|
969
|
+
|
|
970
|
+
Botón genérico con bloqueo automático anti-doble-clic.
|
|
971
|
+
|
|
972
|
+
```vue
|
|
973
|
+
<ButtonStyle
|
|
974
|
+
class="px-4 py-2 bg-indigo-500 text-white rounded"
|
|
975
|
+
:disabled="cargando"
|
|
976
|
+
@click="guardar"
|
|
977
|
+
>
|
|
978
|
+
Guardar
|
|
979
|
+
</ButtonStyle>
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
| Prop | Tipo | Default | Descripción |
|
|
983
|
+
| ---- | ---- | ------- | ----------- |
|
|
984
|
+
| `type` | `String` | `'button'` | Tipo del botón: `'button'` o `'submit'`. |
|
|
985
|
+
| `name` | `String` | `null` | Atributo `name` nativo del `<button>`. |
|
|
986
|
+
| `id` | `String` | `null` | Id propio del `<button>`. |
|
|
987
|
+
| `autofocus` | `Boolean` | `false` | Enfoca el botón al montarse. |
|
|
988
|
+
| `class` | `String` | `''` | Clases CSS del botón (TailwindCSS). |
|
|
989
|
+
| `disabled` | `Boolean` | `false` | Deshabilita el botón. |
|
|
990
|
+
| `delay` | `String` | `'1.5'` | Segundos de bloqueo automático tras hacer clic (anti-doble-clic). |
|
|
991
|
+
|
|
992
|
+
**Eventos:**
|
|
993
|
+
- `click` — se dispara al hacer clic (solo si no está deshabilitado ni en periodo de bloqueo).
|
|
994
|
+
|
|
995
|
+
Acepta contenido mediante `<slot>` (texto, íconos, etc.).
|
|
996
|
+
|
|
997
|
+
> **Nota:** con `type="submit"` funciona como botón de envío nativo dentro de un `<form>`. El bloqueo anti-doble-clic se aplica de forma diferida para no cancelar el envío nativo del formulario.
|
|
998
|
+
|
|
999
|
+
------
|
|
1000
|
+
|
|
1001
|
+
## LoaderStyle
|
|
1002
|
+
|
|
1003
|
+
Indicador de carga circular animado.
|
|
1004
|
+
|
|
1005
|
+
```vue
|
|
1006
|
+
<LoaderStyle message="Procesando datos..." />
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
| Prop | Tipo | Default | Descripción |
|
|
1010
|
+
| ---- | ---- | ------- | ----------- |
|
|
1011
|
+
| `message` | `String` | `'Cargando...'` | Texto que se muestra debajo del arco animado. |
|
|
1012
|
+
|
|
1013
|
+
El color del arco se controla con el token `LOADER_ARC_STROKE`.
|
|
1014
|
+
|
|
1015
|
+
------
|
|
1016
|
+
|
|
1017
|
+
## PaginationStyle
|
|
1018
|
+
|
|
1019
|
+
Paginador con navegación anterior/siguiente, botones de página y resumen de registros.
|
|
1020
|
+
|
|
1021
|
+
```vue
|
|
1022
|
+
<PaginationStyle
|
|
1023
|
+
:total-pages="totalPaginas"
|
|
1024
|
+
:actual-page="paginaActual"
|
|
1025
|
+
:records="totalRegistros"
|
|
1026
|
+
:limit="registrosPorPagina"
|
|
1027
|
+
:summary="true"
|
|
1028
|
+
@page="cambiarPagina"
|
|
1029
|
+
/>
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
| Prop | Tipo | Default | Descripción |
|
|
1033
|
+
| ---- | ---- | ------- | ----------- |
|
|
1034
|
+
| `totalPages` | `Number` | `0` | Total de páginas. |
|
|
1035
|
+
| `actualPage` | `Number` | `1` | Página actualmente activa. |
|
|
1036
|
+
| `records` | `Number` | `0` | Total de registros (para el resumen). |
|
|
1037
|
+
| `limit` | `Number` | `0` | Registros por página (para calcular el rango del resumen). |
|
|
1038
|
+
| `summary` | `Boolean` | `false` | `true` = muestra el texto "Mostrando X - Y de Z". |
|
|
1039
|
+
|
|
1040
|
+
**Eventos:**
|
|
1041
|
+
- `page` — emite el número de página a la que se desea navegar.
|
|
1042
|
+
|
|
1043
|
+
El paginador muestra hasta 7 botones con elipsis (`...`) inteligentes cuando hay más páginas.
|
|
1044
|
+
|
|
1045
|
+
------
|
|
1046
|
+
|
|
1047
|
+
## ModalStyle
|
|
1048
|
+
|
|
1049
|
+
Ventana modal con `Teleport` al `body`, animaciones de entrada/salida, bloqueo del scroll de fondo y cierre por tecla `Escape`. El estado de apertura se controla con `v-model`.
|
|
1050
|
+
|
|
1051
|
+
```vue
|
|
1052
|
+
<ButtonStyle @click="showModal = true">Abrir modal</ButtonStyle>
|
|
1053
|
+
|
|
1054
|
+
<ModalStyle v-model="showModal" title="Detalles" size="lg">
|
|
1055
|
+
<p>Contenido del modal...</p>
|
|
1056
|
+
|
|
1057
|
+
<template #footer="{ close }">
|
|
1058
|
+
<div class="flex justify-end gap-2">
|
|
1059
|
+
<ButtonStyle class="px-4 py-2 border rounded" @click="close">Cerrar</ButtonStyle>
|
|
1060
|
+
</div>
|
|
1061
|
+
</template>
|
|
1062
|
+
</ModalStyle>
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
| Prop | Tipo | Default | Descripción |
|
|
1066
|
+
| ---- | ---- | ------- | ----------- |
|
|
1067
|
+
| `modelValue` | `Boolean` | `false` | Controla la visibilidad del modal (`v-model`). |
|
|
1068
|
+
| `title` | `String` | `'Sin titulo asignado'` | Título mostrado en el header (si no se usa el slot `title`). |
|
|
1069
|
+
| `size` | `String` | `'lg'` | Ancho máximo: `'sm'`, `'md'`, `'lg'`, `'xl'`, `'2xl'`, `'3xl'`, `'4xl'`, `'5xl'`, `'full'`. |
|
|
1070
|
+
| `showCloseButton` | `Boolean` | `true` | Muestra el botón `✕` de cierre en el header. |
|
|
1071
|
+
| `closeOnEscape` | `Boolean` | `true` | Permite cerrar el modal con la tecla `Escape`. |
|
|
1072
|
+
| `closeOnOverlayClick` | `Boolean` | `true` | Permite cerrar el modal al hacer clic en el fondo. |
|
|
1073
|
+
|
|
1074
|
+
**Slots:**
|
|
1075
|
+
- `title` — reemplaza el título del header.
|
|
1076
|
+
- *default* — contenido principal. Recibe `{ close }` para cerrar desde dentro.
|
|
1077
|
+
- `footer` — pie del modal (solo se renderiza si se provee). Recibe `{ close }`.
|
|
1078
|
+
|
|
1079
|
+
**Eventos:**
|
|
1080
|
+
- `update:modelValue` — emite `false` al cerrarse.
|
|
1081
|
+
|
|
1082
|
+
------
|
|
1083
|
+
|
|
1084
|
+
## AlertStyle (notificaciones tipo toast)
|
|
1085
|
+
|
|
1086
|
+
Utilidad JavaScript (no es un componente) para mostrar notificaciones flotantes que se auto-descartan. Disponible como propiedad global `$alertstyle` tras instalar el plugin, o mediante importación directa.
|
|
1087
|
+
|
|
1088
|
+
```js
|
|
1089
|
+
// Vía global property (Options API)
|
|
1090
|
+
this.$alertstyle.success('Guardado', 'Los cambios se guardaron correctamente')
|
|
1091
|
+
|
|
1092
|
+
// Vía importación directa
|
|
1093
|
+
import { AlertStyle } from '@luis-angel-martin-dzul/input-styles'
|
|
1094
|
+
AlertStyle.error('Error', 'No se pudo completar la operación')
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
| Método | Parámetros | Descripción |
|
|
1098
|
+
| ------ | ---------- | ----------- |
|
|
1099
|
+
| `success(title, message?)` | `String, String` | Notificación verde de éxito. |
|
|
1100
|
+
| `error(title, message?)` | `String, String` | Notificación roja de error. |
|
|
1101
|
+
| `warning(title, message?)` | `String, String` | Notificación de advertencia. |
|
|
1102
|
+
| `info(title, message?)` | `String, String` | Notificación informativa. |
|
|
1103
|
+
| `neutral(title, message?)` | `String, String` | Notificación neutral. |
|
|
1104
|
+
|
|
1105
|
+
Cada notificación se cierra automáticamente a los 4 segundos o manualmente con su botón `×`.
|
|
1106
|
+
|
|
1107
|
+
------
|
|
1108
|
+
|
|
1109
|
+
## DialogStyle (diálogos modales)
|
|
1110
|
+
|
|
1111
|
+
Utilidad JavaScript para diálogos de confirmación, información y carga, con interfaz fluida (encadenable). Disponible como global `$dialogstyle` o por importación directa.
|
|
1112
|
+
|
|
1113
|
+
```js
|
|
1114
|
+
// Confirmación
|
|
1115
|
+
this.$dialogstyle.confirm('¿Eliminar registro?', 'Esta acción no se puede deshacer')
|
|
1116
|
+
.onAccept(() => eliminar())
|
|
1117
|
+
.onCancel(() => console.log('Cancelado'))
|
|
1118
|
+
|
|
1119
|
+
// Información (un solo botón)
|
|
1120
|
+
this.$dialogstyle.info('Operación completada')
|
|
1121
|
+
.onConfirm(() => console.log('Aceptado'))
|
|
1122
|
+
|
|
1123
|
+
// Carga (bloqueante, se cierra manualmente)
|
|
1124
|
+
const loader = this.$dialogstyle.loading('Procesando...', 'Espere un momento')
|
|
1125
|
+
loader.updateMessage('Casi listo...')
|
|
1126
|
+
loader.close()
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
| Método | Retorna | Descripción |
|
|
1130
|
+
| ------ | ------- | ----------- |
|
|
1131
|
+
| `confirm(title, description?)` | controlador con `.onAccept(cb)` / `.onCancel(cb)` | Diálogo con botones Aceptar / Cancelar. |
|
|
1132
|
+
| `info(title, description?)` | controlador con `.onConfirm(cb)` | Diálogo informativo con un solo botón Aceptar. |
|
|
1133
|
+
| `loading(title, description?)` | `{ close, updateTitle, updateMessage }` | Diálogo de carga con spinner; se cierra con `.close()`. |
|
|
1134
|
+
| `finish(immediate?)` | `Promise` | Cierra el diálogo abierto manualmente. |
|
|
1135
|
+
|
|
1136
|
+
> 💡 La tecla `Escape` no cierra el diálogo (hace una animación de "shake"), para forzar una decisión explícita del usuario.
|
|
1137
|
+
|
|
1138
|
+
------
|
|
1139
|
+
|
|
1140
|
+
# 🧭 Directivas
|
|
1141
|
+
|
|
1142
|
+
## `v-title-style`
|
|
1143
|
+
|
|
1144
|
+
Muestra un **tooltip** ("globo de diálogo") sobre **cualquier etiqueta o componente**, reemplazando al atributo `title` nativo del navegador. Su **fondo es sky y semitransparente**, para no ocultar del todo el contenido que queda detrás.
|
|
1145
|
+
|
|
1146
|
+
- **Escritorio (mouse):** aparece al pasar el cursor y se oculta al salir.
|
|
1147
|
+
- **Móvil (touch):** se muestra al tocar el elemento y se oculta al tocar de nuevo o fuera.
|
|
1148
|
+
- Acepta **texto plano** (fijo o desde una variable reactiva).
|
|
1149
|
+
|
|
1150
|
+
Si instalas la librería con `app.use(InputStyles)`, la directiva queda registrada **global** automáticamente. Si la usas en un componente que no instala el plugin, regístrala local: `import { TitleStyle } from '@luis-angel-martin-dzul/input-styles'` y `directives: { titleStyle: TitleStyle }`.
|
|
1151
|
+
|
|
1152
|
+
```vue
|
|
1153
|
+
<!-- Texto fijo (nota las comillas simples internas) -->
|
|
1154
|
+
<button v-title-style="'Guarda los cambios'">Guardar</button>
|
|
1155
|
+
|
|
1156
|
+
<!-- Sobre cualquier etiqueta o componente -->
|
|
1157
|
+
<span v-title-style="'Información adicional'">ⓘ</span>
|
|
1158
|
+
<button-style v-title-style="'Tooltip translúcido sobre un ButtonStyle'">Con tooltip</button-style>
|
|
1159
|
+
|
|
1160
|
+
<!-- Texto dinámico -->
|
|
1161
|
+
<button v-title-style="mensajeAyuda">Enviar</button>
|
|
1162
|
+
```
|
|
1163
|
+
|
|
1164
|
+
------
|
|
1165
|
+
|
|
1166
|
+
## UtilStyle (utilidades)
|
|
1167
|
+
|
|
1168
|
+
Clase con métodos estáticos de utilidad (formateo, validaciones, manejo de archivos, etc.). Disponible como propiedad global `$utilstyle` tras instalar el plugin, o mediante importación directa.
|
|
1169
|
+
|
|
1170
|
+
```js
|
|
1171
|
+
// Vía global property (Options API)
|
|
1172
|
+
this.$utilstyle.formatMoney(1234.5)
|
|
1173
|
+
|
|
1174
|
+
// Vía importación directa
|
|
1175
|
+
import { UtilStyle } from '@luis-angel-martin-dzul/input-styles'
|
|
1176
|
+
UtilStyle.getUUID()
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
| Método | Parámetros | Descripción |
|
|
1180
|
+
| ------ | ---------- | ----------- |
|
|
1181
|
+
| `getUUID()` | — | Genera un UUID v4 (usa `crypto.randomUUID` con fallback manual). |
|
|
1182
|
+
| `formatMoney(valor, dollar?, digit?)` | `Number, String, Number` | Formatea un número como moneda (ej: `$1,234.56`). |
|
|
1183
|
+
| `formatNumber(valor, digit?)` | `Number, Number` | Formatea un número con separadores de miles y decimales fijos. |
|
|
1184
|
+
| `formatBytes(bytes, digit?)` | `Number, Number` | Formatea un tamaño en bytes a `B` / `KB` / `MB` legible (ej: `296.0 KB`). |
|
|
1185
|
+
| `formatDateShort(dateString)` | `String` | Fecha en formato corto en español (ej: `9 jul 2026`). |
|
|
1186
|
+
| `formatDateLong(dateString)` | `String` | Fecha en formato largo en español (ej: `9 de julio de 2026`). |
|
|
1187
|
+
| `formatDateTimeShort(dateString, hour12?)` | `String, Boolean` | Fecha y hora en formato corto en español (ej: `9 jul 2026, 12:00 p. m.`). `hour12` (default `true`) alterna entre 12h y 24h. |
|
|
1188
|
+
| `formatDateTimeLong(dateString, hour12?)` | `String, Boolean` | Fecha y hora en formato largo en español (ej: `9 de julio de 2026, 12:00 p. m.`). `hour12` (default `true`) alterna entre 12h y 24h. |
|
|
1189
|
+
| `getDateTimeNow()` | — | Fecha y hora actual (zona `America/Mexico_City`) en formato `YYYY-MM-DDTHH:mm:ss`. |
|
|
1190
|
+
| `porcentaje(valor, total)` | `Number, Number` | Calcula el porcentaje de `valor` respecto a `total` (ej: `50`). Retorna `0` si `total` es `0` o negativo. |
|
|
1191
|
+
| `blockKeyNumber(event)` | `Event` | Bloquea las teclas `e`, `E`, `+`, `-` en un `@keydown`. |
|
|
1192
|
+
| `blockKeys(event, keys)` | `Event, Array` | Bloquea las teclas indicadas en un `@keydown`. |
|
|
1193
|
+
| `validateTel(value, required?)` | `String, Boolean` | Valida un teléfono con formato `999 9 99 99 99`. Acepta prefijo de región opcional `+XXX 999 9 99 99 99` (XXX = 1 a 3 dígitos). Retorna `true` o mensaje de error. |
|
|
1194
|
+
| `validateEmail(value, required?)` | `String, Boolean` | Valida un correo con las condiciones mínimas `xx@xx.x`. Retorna `true` o mensaje de error. |
|
|
1195
|
+
| `validateFileExtension(file, allowedExtensions?)` | `File, Array` | Valida la extensión del archivo. Retorna `true` o mensaje de error. |
|
|
1196
|
+
| `validateFileType(file, allowedTypes?)` | `File, Array` | Valida el MIME type del archivo. Retorna `true` o mensaje de error. |
|
|
1197
|
+
| `validateFileSize(file, maxSizeMB?)` | `File, Number` | Valida el tamaño del archivo. Retorna `true` o mensaje de error. |
|
|
1198
|
+
| `downloadBlob(blobData, fileName?, mimeType?)` | `Blob, String, String` | Descarga un blob como archivo. |
|
|
1199
|
+
| `fileToBase64(file)` | `File` | Convierte un `File` a base64 (async, retorna `Promise`). |
|
|
1200
|
+
| `base64ToBlob(base64, mimeType?)` | `String, String` | Convierte una cadena base64 a `Blob`. |
|
|
1201
|
+
| `base64ToFile(base64, fileName?, mimeType?)` | `String, String, String` | Convierte una cadena base64 a `File`. |
|
|
1202
|
+
| `fileToImage(file)` | `File` | Carga un `File` de imagen en un `HTMLImageElement` (async, retorna `Promise`). Libera el object URL al terminar. |
|
|
1203
|
+
| `compressToWebp(file, quality?, maxWidth?)` | `File, Number, Number` | Comprime una imagen a **WebP** en el navegador (async). Ver [Compresión de imágenes a WebP](#compresión-de-imágenes-a-webp). |
|
|
1204
|
+
|
|
1205
|
+
> 💡 Los métodos de validación (`validateTel`, `validateEmail`, `validateFile*`) devuelven `true` si el valor es válido, o un `String` con el mensaje de error si no lo es.
|
|
1206
|
+
|
|
1207
|
+
------
|
|
1208
|
+
|
|
1209
|
+
# 🖼️ Compresión de imágenes a WebP
|
|
1210
|
+
|
|
1211
|
+
Convierte imágenes (PNG, JPEG, etc.) a **WebP** directamente en el navegador —sin subir nada al servidor— usando la Canvas API. Útil para reducir el peso de las imágenes **antes** de enviarlas a tu backend.
|
|
1212
|
+
|
|
1213
|
+
El método principal es `UtilStyle.compressToWebp(file, quality, maxWidth)`.
|
|
1214
|
+
|
|
1215
|
+
```js
|
|
1216
|
+
// file: Number, quality: 0 a 1 (ej. 0.8 = 80%), maxWidth: px (opcional)
|
|
1217
|
+
const res = await UtilStyle.compressToWebp(file, 0.8, 1920)
|
|
1218
|
+
```
|
|
1219
|
+
|
|
1220
|
+
| Parámetro | Tipo | Default | Descripción |
|
|
1221
|
+
| --------- | ---- | ------- | ----------- |
|
|
1222
|
+
| `file` | `File` | — | Archivo de imagen original (PNG/JPEG/etc). |
|
|
1223
|
+
| `quality` | `Number` | `0.8` | Calidad de `0` a `1` (ej: `0.8` = 80%). Solo aplica en WebP con pérdida. |
|
|
1224
|
+
| `maxWidth` | `Number \| null` | `null` | Si se indica, redimensiona manteniendo proporción. Recomendado para fotos grandes. |
|
|
1225
|
+
|
|
1226
|
+
**Retorna** una `Promise` que resuelve a un objeto:
|
|
1227
|
+
|
|
1228
|
+
```js
|
|
1229
|
+
{
|
|
1230
|
+
blob, // Blob de la imagen WebP (listo para subir o descargar)
|
|
1231
|
+
originalSize, // Tamaño original en bytes
|
|
1232
|
+
compressedSize, // Tamaño comprimido en bytes
|
|
1233
|
+
ratio, // % de ahorro (positivo = más ligero; negativo = más pesado)
|
|
1234
|
+
width, height, // Dimensiones finales del WebP
|
|
1235
|
+
}
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
## ¿Cuándo usarlo?
|
|
1239
|
+
|
|
1240
|
+
✅ **Úsalo cuando:**
|
|
1241
|
+
- Quieras **reducir el peso** de imágenes que suben tus usuarios antes de enviarlas al servidor (ahorra ancho de banda y almacenamiento).
|
|
1242
|
+
- Trabajes con **fotos** o imágenes con muchos colores/degradados (es donde WebP más ahorra).
|
|
1243
|
+
- Quieras **previsualizar** el ahorro antes de confirmar la subida.
|
|
1244
|
+
|
|
1245
|
+
⚠️ **Evítalo / revísalo cuando:**
|
|
1246
|
+
- Necesites soportar **Safari**: su canvas no codifica WebP de forma fiable y puede devolver un PNG disfrazado. El método **detecta esto y lanza un error explícito** en vez de entregar un archivo "mentiroso". Para soporte universal usa un encoder WASM (p. ej. `@jsquash/webp`) como fallback.
|
|
1247
|
+
- La imagen sea un **ícono/ilustración plana con pocos colores**: el ahorro de WebP con pérdida es mínimo y puede generar ruido en los bordes. Considera dejarla como PNG.
|
|
1248
|
+
- Necesites conservar **metadatos EXIF** (orientación, geolocalización): el canvas los descarta. Pásale `maxWidth` y ten en cuenta que fotos con orientación EXIF podrían rotarse.
|
|
1249
|
+
|
|
1250
|
+
> 💡 **Referencia de ahorro** (cifras oficiales del equipo WebP de Google): lossless ≈ 26% menos que PNG; con pérdida 25–34% menos que JPEG a calidad visual equivalente. No hay un porcentaje fijo: depende del contenido. **Calidad recomendada:** 75–85% para fotos (a partir de 75% la diferencia suele ser imperceptible).
|
|
1251
|
+
|
|
1252
|
+
## Uso básico (un archivo)
|
|
1253
|
+
|
|
1254
|
+
```js
|
|
1255
|
+
import { UtilStyle } from '@luis-angel-martin-dzul/input-styles'
|
|
1256
|
+
|
|
1257
|
+
async function comprimir(file) {
|
|
1258
|
+
try {
|
|
1259
|
+
const res = await UtilStyle.compressToWebp(file, 0.8, 1920)
|
|
1260
|
+
|
|
1261
|
+
console.log(`Ahorro: ${res.ratio}%`)
|
|
1262
|
+
console.log(`${UtilStyle.formatBytes(res.originalSize)} → ${UtilStyle.formatBytes(res.compressedSize)}`)
|
|
1263
|
+
|
|
1264
|
+
// Subir al servidor
|
|
1265
|
+
const formData = new FormData()
|
|
1266
|
+
formData.append('imagen', res.blob, file.name.replace(/\.\w+$/, '.webp'))
|
|
1267
|
+
// await fetch('/api/upload', { method: 'POST', body: formData })
|
|
1268
|
+
|
|
1269
|
+
// O descargar localmente (reutiliza downloadBlob de UtilStyle)
|
|
1270
|
+
UtilStyle.downloadBlob(res.blob, 'imagen.webp', 'image/webp')
|
|
1271
|
+
} catch (e) {
|
|
1272
|
+
console.error(e.message) // p. ej. error de Safari
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
```
|
|
1276
|
+
|
|
1277
|
+
## Uso con validación y múltiples archivos (Options API)
|
|
1278
|
+
|
|
1279
|
+
```vue
|
|
1280
|
+
<template>
|
|
1281
|
+
<input type="file" accept="image/*" multiple @change="onFiles" />
|
|
1282
|
+
<p v-if="error" class="text-red-500">{{ error }}</p>
|
|
1283
|
+
</template>
|
|
1284
|
+
|
|
1285
|
+
<script>
|
|
1286
|
+
export default {
|
|
1287
|
+
data() {
|
|
1288
|
+
return { error: '', resultados: [] }
|
|
1289
|
+
},
|
|
1290
|
+
methods: {
|
|
1291
|
+
async onFiles(e) {
|
|
1292
|
+
this.error = ''
|
|
1293
|
+
const files = Array.from(e.target.files || [])
|
|
1294
|
+
|
|
1295
|
+
for (const file of files) {
|
|
1296
|
+
// Reutiliza las validaciones de UtilStyle
|
|
1297
|
+
const extOk = this.$utilstyle.validateFileExtension(file, ['png', 'jpg', 'jpeg'])
|
|
1298
|
+
if (extOk !== true) { this.error = extOk; continue }
|
|
1299
|
+
|
|
1300
|
+
const sizeOk = this.$utilstyle.validateFileSize(file, 10)
|
|
1301
|
+
if (sizeOk !== true) { this.error = sizeOk; continue }
|
|
1302
|
+
|
|
1303
|
+
try {
|
|
1304
|
+
const res = await this.$utilstyle.compressToWebp(file, 0.8, 1920)
|
|
1305
|
+
this.resultados.push(res)
|
|
1306
|
+
} catch (err) {
|
|
1307
|
+
this.error = err.message
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
</script>
|
|
1314
|
+
```
|
|
1315
|
+
|
|
1316
|
+
> ℹ️ La librería expone **solo los métodos** de compresión en `UtilStyle`; no incluye un componente visual. Si necesitas una UI lista (selector + comparación de tamaños + descarga), puedes construirla sobre estos métodos como en el ejemplo anterior.
|
|
1317
|
+
|
|
1318
|
+
------
|
|
1319
|
+
|
|
1320
|
+
## Ejemplo de uso completo
|
|
1321
|
+
|
|
1322
|
+
```vue
|
|
1323
|
+
<template>
|
|
1324
|
+
<div class="p-6 space-y-4 max-w-md">
|
|
1325
|
+
|
|
1326
|
+
<InputTextStyle
|
|
1327
|
+
v-model="form.nombre"
|
|
1328
|
+
label="Nombre completo"
|
|
1329
|
+
placeholder="Ej: Juan Pérez"
|
|
1330
|
+
:required="true"
|
|
1331
|
+
:validate="validaciones.nombre"
|
|
1332
|
+
/>
|
|
1333
|
+
|
|
1334
|
+
<InputNumberStyle
|
|
1335
|
+
v-model="form.monto"
|
|
1336
|
+
label="Monto"
|
|
1337
|
+
numeric="10,2"
|
|
1338
|
+
min="0"
|
|
1339
|
+
:validate="validaciones.monto"
|
|
1340
|
+
/>
|
|
1341
|
+
|
|
1342
|
+
<InputPasswordStyle
|
|
1343
|
+
v-model="form.password"
|
|
1344
|
+
label="Contraseña"
|
|
1345
|
+
:required="true"
|
|
1346
|
+
:validate="validaciones.password"
|
|
1347
|
+
/>
|
|
1348
|
+
|
|
1349
|
+
<SelectStyle
|
|
1350
|
+
v-model="form.pais"
|
|
1351
|
+
label="País"
|
|
1352
|
+
:list="paises"
|
|
1353
|
+
return-value="value"
|
|
1354
|
+
:validate="validaciones.pais"
|
|
1355
|
+
/>
|
|
1356
|
+
|
|
1357
|
+
<InputDateStyle
|
|
1358
|
+
v-model="form.fecha"
|
|
1359
|
+
label="Fecha"
|
|
1360
|
+
:validate="validaciones.fecha"
|
|
1361
|
+
/>
|
|
1362
|
+
|
|
1363
|
+
<InputDateTimeStyle
|
|
1364
|
+
v-model="form.fechaHora"
|
|
1365
|
+
label="Fecha y hora"
|
|
1366
|
+
:is24h="true"
|
|
1367
|
+
:validate="validaciones.fechaHora"
|
|
1368
|
+
/>
|
|
1369
|
+
|
|
1370
|
+
<InputTimeStyle
|
|
1371
|
+
v-model="form.hora"
|
|
1372
|
+
label="Hora"
|
|
1373
|
+
:is24h="true"
|
|
1374
|
+
/>
|
|
1375
|
+
|
|
1376
|
+
<InputCheckStyle
|
|
1377
|
+
v-model="form.acepta"
|
|
1378
|
+
label="Acepto los términos"
|
|
1379
|
+
:required="true"
|
|
1380
|
+
/>
|
|
1381
|
+
|
|
1382
|
+
<ButtonStyle
|
|
1383
|
+
class="w-full px-4 py-2 bg-indigo-500 text-white rounded hover:bg-indigo-600"
|
|
1384
|
+
@click="enviar"
|
|
1385
|
+
>
|
|
1386
|
+
Enviar
|
|
1387
|
+
</ButtonStyle>
|
|
1388
|
+
|
|
1389
|
+
</div>
|
|
1390
|
+
</template>
|
|
1391
|
+
|
|
1392
|
+
<script setup>
|
|
1393
|
+
import { ref } from 'vue'
|
|
1394
|
+
import {
|
|
1395
|
+
InputTextStyle, InputNumberStyle, InputPasswordStyle,
|
|
1396
|
+
SelectStyle, InputDateStyle, InputDateTimeStyle, InputTimeStyle,
|
|
1397
|
+
InputCheckStyle, ButtonStyle
|
|
1398
|
+
} from '@luis-angel-martin-dzul/input-styles'
|
|
1399
|
+
|
|
1400
|
+
const form = ref({
|
|
1401
|
+
nombre: '', monto: '', password: '',
|
|
1402
|
+
pais: null, fecha: '', fechaHora: '', hora: '', acepta: false
|
|
1403
|
+
})
|
|
1404
|
+
|
|
1405
|
+
const validaciones = ref({
|
|
1406
|
+
nombre: null, monto: null, password: null,
|
|
1407
|
+
pais: null, fecha: null, fechaHora: null
|
|
1408
|
+
})
|
|
1409
|
+
|
|
1410
|
+
const paises = [
|
|
1411
|
+
{ value: 1, text: 'México' },
|
|
1412
|
+
{ value: 2, text: 'España' },
|
|
1413
|
+
]
|
|
1414
|
+
|
|
1415
|
+
function enviar() {
|
|
1416
|
+
validaciones.value.nombre = form.value.nombre.length > 0
|
|
1417
|
+
// ... resto de validaciones
|
|
1418
|
+
}
|
|
1419
|
+
</script>
|
|
1420
|
+
```
|