@adamosuiteservices/ui 1.6.7 → 1.7.7
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/dist/combobox.cjs +2 -2
- package/dist/combobox.js +364 -332
- package/dist/components/ui/combobox/combobox.d.ts +20 -1
- package/dist/components/ui/combobox/combobox.stories.d.ts +5 -0
- package/dist/custom-layered-styles.css +1 -1
- package/dist/styles.css +1 -1
- package/docs/components/ui/combobox.md +118 -95
- package/package.json +1 -1
|
@@ -68,17 +68,19 @@ import { Combobox } from "@adamosuiteservices/ui/combobox";
|
|
|
68
68
|
|
|
69
69
|
Funciones de renderizado personalizadas para control total sobre la UI. Todas son opcionales y reciben props relevantes.
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
71
|
+
**Patrón Original Component**: Cada render prop recibe un componente `Original` que renderiza la implementación por defecto, permitiendo envolver o mejorar el renderizado sin reimplementar toda la lógica.
|
|
72
|
+
|
|
73
|
+
| Prop | Parámetros | Descripción |
|
|
74
|
+
| ------------------ | ----------------------------------------------------------------------- | --------------------------------------- |
|
|
75
|
+
| `trigger` | `{ Original, open, value, displayText, placeholder, hasValue, icon }` | Renderiza el botón trigger completo |
|
|
76
|
+
| `triggerIcon` | `{ Original, open }` | Renderiza el icono del dropdown |
|
|
77
|
+
| `placeholder` | `{ Original, text, hasValue }` | Renderiza el texto del placeholder |
|
|
78
|
+
| `displayValue` | `{ Original, text, value }` | Renderiza el valor seleccionado |
|
|
79
|
+
| `option` | `{ Original, option, isSelected, selectedFeedback }` | Renderiza una opción completa |
|
|
80
|
+
| `optionLabel` | `{ Original, option }` | Renderiza solo la etiqueta de la opción |
|
|
81
|
+
| `selectedFeedback` | `{ Original, option, isSelected, type }` | Renderiza el indicador de selección |
|
|
82
|
+
| `empty` | `{ Original, text }` | Renderiza el estado vacío |
|
|
83
|
+
| `searchInput` | `{ Original, placeholder }` | Renderiza el input de búsqueda |
|
|
82
84
|
|
|
83
85
|
## Patrones de Uso
|
|
84
86
|
|
|
@@ -347,7 +349,16 @@ const [values, setValues] = useState<string[]>([]);
|
|
|
347
349
|
|
|
348
350
|
El prop `renders` permite personalizar completamente la UI usando el patrón render prop. Todas las funciones son opcionales.
|
|
349
351
|
|
|
350
|
-
###
|
|
352
|
+
### Patrón Original Component
|
|
353
|
+
|
|
354
|
+
Cada render prop recibe un componente `Original` que renderiza la implementación por defecto. Esto permite:
|
|
355
|
+
|
|
356
|
+
- **Envolver**: Agregar contenedores o elementos adicionales
|
|
357
|
+
- **Mejorar**: Añadir badges, iconos o decoraciones junto al original
|
|
358
|
+
- **Condicional**: Usar el original como fallback para ciertos estados
|
|
359
|
+
- **Componer**: Mezclar renderizado custom y default según condiciones
|
|
360
|
+
|
|
361
|
+
### Envolver el Trigger con Label
|
|
351
362
|
|
|
352
363
|
```tsx
|
|
353
364
|
<Combobox
|
|
@@ -356,17 +367,19 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
356
367
|
value={value}
|
|
357
368
|
onValueChange={setValue}
|
|
358
369
|
renders={{
|
|
359
|
-
|
|
360
|
-
<div className="
|
|
361
|
-
<
|
|
362
|
-
|
|
370
|
+
trigger: ({ Original }) => (
|
|
371
|
+
<div className="border border-purple-300 p-2 rounded-lg bg-purple-50">
|
|
372
|
+
<label className="text-xs font-medium text-purple-700 mb-1 block">
|
|
373
|
+
Choose your framework:
|
|
374
|
+
</label>
|
|
375
|
+
<Original />
|
|
363
376
|
</div>
|
|
364
377
|
),
|
|
365
378
|
}}
|
|
366
379
|
/>
|
|
367
380
|
```
|
|
368
381
|
|
|
369
|
-
###
|
|
382
|
+
### Mejorar Display Value con Badge
|
|
370
383
|
|
|
371
384
|
```tsx
|
|
372
385
|
<Combobox
|
|
@@ -375,14 +388,21 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
375
388
|
value={value}
|
|
376
389
|
onValueChange={setValue}
|
|
377
390
|
renders={{
|
|
378
|
-
displayValue: ({ text }) => (
|
|
379
|
-
<
|
|
391
|
+
displayValue: ({ Original, text }) => (
|
|
392
|
+
<div className="flex items-center gap-2">
|
|
393
|
+
<Original />
|
|
394
|
+
{text && (
|
|
395
|
+
<span className="px-1.5 py-0.5 text-xs bg-green-100 text-green-700 rounded">
|
|
396
|
+
Active
|
|
397
|
+
</span>
|
|
398
|
+
)}
|
|
399
|
+
</div>
|
|
380
400
|
),
|
|
381
401
|
}}
|
|
382
402
|
/>
|
|
383
403
|
```
|
|
384
404
|
|
|
385
|
-
###
|
|
405
|
+
### Fallback Condicional
|
|
386
406
|
|
|
387
407
|
```tsx
|
|
388
408
|
<Combobox
|
|
@@ -391,76 +411,71 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
391
411
|
value={value}
|
|
392
412
|
onValueChange={setValue}
|
|
393
413
|
renders={{
|
|
394
|
-
trigger: ({
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
414
|
+
trigger: ({ Original, hasValue, displayText }) => {
|
|
415
|
+
// Custom cuando hay valor
|
|
416
|
+
if (hasValue) {
|
|
417
|
+
return (
|
|
418
|
+
<button className="w-full px-4 py-2 bg-green-600 text-white rounded-md">
|
|
419
|
+
✓ {displayText}
|
|
420
|
+
</button>
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Fallback al original cuando está vacío
|
|
425
|
+
return <Original />;
|
|
426
|
+
},
|
|
405
427
|
}}
|
|
406
428
|
/>
|
|
407
429
|
```
|
|
408
430
|
|
|
409
|
-
###
|
|
431
|
+
### Envolver Options con Styling
|
|
410
432
|
|
|
411
433
|
```tsx
|
|
412
434
|
<Combobox
|
|
413
435
|
searchable
|
|
414
|
-
options={[]}
|
|
415
|
-
renders={{
|
|
416
|
-
empty: ({ text }) => (
|
|
417
|
-
<div className="py-8 text-center">
|
|
418
|
-
<div className="text-4xl mb-2">🔍</div>
|
|
419
|
-
<p className="text-sm font-medium text-muted-foreground">{text}</p>
|
|
420
|
-
<p className="text-xs text-muted-foreground mt-1">
|
|
421
|
-
Try adjusting your search criteria
|
|
422
|
-
</p>
|
|
423
|
-
</div>
|
|
424
|
-
),
|
|
425
|
-
}}
|
|
426
|
-
/>
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
### Custom Selected Feedback
|
|
430
|
-
|
|
431
|
-
```tsx
|
|
432
|
-
<Combobox
|
|
433
|
-
searchable
|
|
434
|
-
multiple
|
|
435
436
|
options={frameworks}
|
|
436
|
-
value={
|
|
437
|
-
onValueChange={
|
|
437
|
+
value={value}
|
|
438
|
+
onValueChange={setValue}
|
|
439
|
+
selectedFeedback="check"
|
|
438
440
|
renders={{
|
|
439
|
-
|
|
440
|
-
<
|
|
441
|
+
option: ({ Original, isSelected }) => (
|
|
442
|
+
<div
|
|
443
|
+
className={`border-l-4 ${
|
|
444
|
+
isSelected ? "border-l-blue-500 bg-blue-50" : "border-l-transparent"
|
|
445
|
+
}`}
|
|
446
|
+
>
|
|
447
|
+
<Original />
|
|
448
|
+
</div>
|
|
441
449
|
),
|
|
442
450
|
}}
|
|
443
451
|
/>
|
|
444
452
|
```
|
|
445
453
|
|
|
446
|
-
###
|
|
454
|
+
### Mejorar Empty State con Acción
|
|
447
455
|
|
|
448
456
|
```tsx
|
|
449
457
|
<Combobox
|
|
450
458
|
searchable
|
|
451
|
-
|
|
452
|
-
options={frameworks}
|
|
453
|
-
value={value}
|
|
454
|
-
onValueChange={setValue}
|
|
459
|
+
options={[]}
|
|
455
460
|
renders={{
|
|
456
|
-
|
|
457
|
-
<
|
|
461
|
+
empty: ({ Original }) => (
|
|
462
|
+
<div className="space-y-3">
|
|
463
|
+
<Original />
|
|
464
|
+
<div className="px-4 pb-3">
|
|
465
|
+
<button
|
|
466
|
+
onClick={() => console.log("Add new")}
|
|
467
|
+
className="w-full px-3 py-1.5 text-xs text-blue-600 border border-blue-200 rounded hover:bg-blue-50"
|
|
468
|
+
>
|
|
469
|
+
+ Create new item
|
|
470
|
+
</button>
|
|
471
|
+
</div>
|
|
472
|
+
</div>
|
|
458
473
|
),
|
|
459
474
|
}}
|
|
460
475
|
/>
|
|
461
476
|
```
|
|
462
477
|
|
|
463
|
-
### Custom
|
|
478
|
+
### Custom Option Label (Sin Original)
|
|
464
479
|
|
|
465
480
|
```tsx
|
|
466
481
|
<Combobox
|
|
@@ -469,16 +484,17 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
469
484
|
value={value}
|
|
470
485
|
onValueChange={setValue}
|
|
471
486
|
renders={{
|
|
472
|
-
|
|
473
|
-
<
|
|
474
|
-
|
|
475
|
-
|
|
487
|
+
optionLabel: ({ option }) => (
|
|
488
|
+
<div className="flex items-center gap-2">
|
|
489
|
+
<span className="font-semibold text-blue-600">🚀</span>
|
|
490
|
+
<span>{option.label}</span>
|
|
491
|
+
</div>
|
|
476
492
|
),
|
|
477
493
|
}}
|
|
478
494
|
/>
|
|
479
495
|
```
|
|
480
496
|
|
|
481
|
-
### Custom
|
|
497
|
+
### Custom Trigger Completo (Sin Original)
|
|
482
498
|
|
|
483
499
|
```tsx
|
|
484
500
|
<Combobox
|
|
@@ -487,21 +503,22 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
487
503
|
value={value}
|
|
488
504
|
onValueChange={setValue}
|
|
489
505
|
renders={{
|
|
490
|
-
|
|
491
|
-
<
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
506
|
+
trigger: ({ open, displayText, placeholder, hasValue }) => (
|
|
507
|
+
<button
|
|
508
|
+
type="button"
|
|
509
|
+
className="flex items-center justify-between w-full px-4 py-2 text-sm bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-lg shadow-md hover:shadow-lg transition-all"
|
|
510
|
+
>
|
|
511
|
+
<span>{hasValue ? displayText : placeholder}</span>
|
|
512
|
+
<span className={`transition-transform ${open ? "rotate-180" : ""}`}>
|
|
513
|
+
▼
|
|
514
|
+
</span>
|
|
515
|
+
</button>
|
|
499
516
|
),
|
|
500
517
|
}}
|
|
501
518
|
/>
|
|
502
519
|
```
|
|
503
520
|
|
|
504
|
-
### Combinando
|
|
521
|
+
### Combinando Original y Custom
|
|
505
522
|
|
|
506
523
|
```tsx
|
|
507
524
|
<Combobox
|
|
@@ -510,27 +527,30 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
510
527
|
options={frameworks}
|
|
511
528
|
value={values}
|
|
512
529
|
onValueChange={setValues}
|
|
513
|
-
labels={{
|
|
514
|
-
placeholder: "Select frameworks...",
|
|
515
|
-
searchPlaceholder: "Search...",
|
|
516
|
-
}}
|
|
517
530
|
renders={{
|
|
531
|
+
// Usa Original para envolver
|
|
532
|
+
trigger: ({ Original }) => (
|
|
533
|
+
<div className="relative">
|
|
534
|
+
<Original />
|
|
535
|
+
{values.length > 0 && (
|
|
536
|
+
<span className="absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center">
|
|
537
|
+
{values.length}
|
|
538
|
+
</span>
|
|
539
|
+
)}
|
|
540
|
+
</div>
|
|
541
|
+
),
|
|
542
|
+
// Custom completo sin Original
|
|
518
543
|
optionLabel: ({ option }) => (
|
|
519
544
|
<div className="flex items-center gap-2">
|
|
520
545
|
<span>🚀</span>
|
|
521
546
|
<span className="font-medium">{option.label}</span>
|
|
522
547
|
</div>
|
|
523
548
|
),
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
),
|
|
530
|
-
empty: ({ text }) => (
|
|
531
|
-
<div className="py-6 text-center">
|
|
532
|
-
<div className="text-3xl mb-2">😕</div>
|
|
533
|
-
<p className="text-sm text-gray-500">{text}</p>
|
|
549
|
+
// Mejora el Original
|
|
550
|
+
displayValue: ({ Original, text }) => (
|
|
551
|
+
<div className="flex items-center gap-2">
|
|
552
|
+
<Original />
|
|
553
|
+
{text && <span className="text-xs opacity-50">selected</span>}
|
|
534
554
|
</div>
|
|
535
555
|
),
|
|
536
556
|
}}
|
|
@@ -609,6 +629,7 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
609
629
|
- **icon**: Se muestra con `opacity-50` por defecto cuando se proporciona el prop `icon`
|
|
610
630
|
- **Render props**: Tienen prioridad sobre renderizado por defecto, permiten personalización completa
|
|
611
631
|
- **Composición de renders**: Puedes combinar múltiples render props para personalización granular
|
|
632
|
+
- **Original component**: Cada render prop recibe un componente `Original` para renderizar la implementación por defecto, permitiendo envolver o mejorar sin reimplementar
|
|
612
633
|
|
|
613
634
|
## Troubleshooting
|
|
614
635
|
|
|
@@ -622,7 +643,9 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
622
643
|
**Icon no se muestra**: Asegúrate de pasar el prop `icon` con un componente válido
|
|
623
644
|
**Placeholder desaparece al seleccionar**: Si quieres mantenerlo visible, usa `alwaysShowPlaceholder={true}`
|
|
624
645
|
**Render prop no funciona**: Verifica que el render prop retorne un `ReactNode` válido
|
|
625
|
-
**Custom trigger pierde funcionalidad**: Cuando usas `renders.trigger`, debes manejar el click manualmente o envolver en `PopoverTrigger`
|
|
646
|
+
**Custom trigger pierde funcionalidad**: Cuando usas `renders.trigger`, debes manejar el click manualmente o envolver en `PopoverTrigger`
|
|
647
|
+
**Original component no renderiza**: Asegúrate de usar `<Original />` como componente JSX, no como función
|
|
648
|
+
**Quiero envolver sin reimplementar**: Usa el componente `Original` que recibe cada render prop para mantener la funcionalidad por defecto
|
|
626
649
|
|
|
627
650
|
## Referencias
|
|
628
651
|
|