@adamosuiteservices/ui 1.7.8 → 1.7.9
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 +277 -311
- package/dist/components/ui/combobox/combobox.d.ts +0 -20
- package/dist/components/ui/combobox/combobox.stories.d.ts +2 -4
- package/dist/custom-layered-styles.css +1 -1
- package/dist/styles.css +1 -1
- package/docs/components/ui/combobox.md +45 -163
- package/package.json +1 -1
|
@@ -68,19 +68,17 @@ 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
|
-
| `
|
|
82
|
-
| `empty` | `{ Original, text }` | Renderiza el estado vacío |
|
|
83
|
-
| `searchInput` | `{ Original, placeholder }` | Renderiza el input de búsqueda |
|
|
71
|
+
| Prop | Parámetros | Descripción |
|
|
72
|
+
| ------------------ | ----------------------------------------------------------- | --------------------------------------- |
|
|
73
|
+
| `trigger` | `{ open, value, displayText, placeholder, hasValue, icon }` | Renderiza el botón trigger completo |
|
|
74
|
+
| `triggerIcon` | `{ open }` | Renderiza el icono del dropdown |
|
|
75
|
+
| `placeholder` | `{ text, hasValue }` | Renderiza el texto del placeholder |
|
|
76
|
+
| `displayValue` | `{ text, value }` | Renderiza el valor seleccionado |
|
|
77
|
+
| `option` | `{ option, isSelected, selectedFeedback }` | Renderiza una opción completa |
|
|
78
|
+
| `optionLabel` | `{ option }` | Renderiza solo la etiqueta de la opción |
|
|
79
|
+
| `selectedFeedback` | `{ option, isSelected, type }` | Renderiza el indicador de selección |
|
|
80
|
+
| `empty` | `{ text }` | Renderiza el estado vacío |
|
|
81
|
+
| `searchInput` | `{ placeholder }` | Renderiza el input de búsqueda |
|
|
84
82
|
|
|
85
83
|
## Patrones de Uso
|
|
86
84
|
|
|
@@ -347,18 +345,9 @@ const [values, setValues] = useState<string[]>([]);
|
|
|
347
345
|
|
|
348
346
|
## Renderizado Personalizado
|
|
349
347
|
|
|
350
|
-
El prop `renders` permite personalizar completamente la UI usando el patrón render prop. Todas las funciones son opcionales.
|
|
348
|
+
El prop `renders` permite personalizar completamente la UI usando el patrón render prop. Todas las funciones son opcionales y permiten reemplazar completamente el renderizado por defecto de cada parte del componente.
|
|
351
349
|
|
|
352
|
-
###
|
|
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
|
|
350
|
+
### Custom Trigger
|
|
362
351
|
|
|
363
352
|
```tsx
|
|
364
353
|
<Combobox
|
|
@@ -367,13 +356,16 @@ Cada render prop recibe un componente `Original` que renderiza la implementació
|
|
|
367
356
|
value={value}
|
|
368
357
|
onValueChange={setValue}
|
|
369
358
|
renders={{
|
|
370
|
-
trigger: ({
|
|
371
|
-
<
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
<
|
|
376
|
-
|
|
359
|
+
trigger: ({ open, displayText, placeholder, hasValue }) => (
|
|
360
|
+
<button
|
|
361
|
+
type="button"
|
|
362
|
+
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"
|
|
363
|
+
>
|
|
364
|
+
<span>{hasValue ? displayText : placeholder}</span>
|
|
365
|
+
<span className={`transition-transform ${open ? "rotate-180" : ""}`}>
|
|
366
|
+
▼
|
|
367
|
+
</span>
|
|
368
|
+
</button>
|
|
377
369
|
),
|
|
378
370
|
}}
|
|
379
371
|
/>
|
|
@@ -382,53 +374,10 @@ Cada render prop recibe un componente `Original` que renderiza la implementació
|
|
|
382
374
|
### Mejorar Display Value con Badge
|
|
383
375
|
|
|
384
376
|
```tsx
|
|
385
|
-
<Combobox
|
|
386
|
-
searchable
|
|
387
|
-
options={frameworks}
|
|
388
|
-
value={value}
|
|
389
|
-
onValueChange={setValue}
|
|
390
|
-
renders={{
|
|
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>
|
|
400
|
-
),
|
|
401
|
-
}}
|
|
402
|
-
/>
|
|
403
|
-
```
|
|
404
377
|
|
|
405
|
-
### Fallback Condicional
|
|
406
|
-
|
|
407
|
-
```tsx
|
|
408
|
-
<Combobox
|
|
409
|
-
searchable
|
|
410
|
-
options={frameworks}
|
|
411
|
-
value={value}
|
|
412
|
-
onValueChange={setValue}
|
|
413
|
-
renders={{
|
|
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
|
-
},
|
|
427
|
-
}}
|
|
428
|
-
/>
|
|
429
378
|
```
|
|
430
379
|
|
|
431
|
-
###
|
|
380
|
+
### Custom Display Value con Badge
|
|
432
381
|
|
|
433
382
|
```tsx
|
|
434
383
|
<Combobox
|
|
@@ -436,46 +385,22 @@ Cada render prop recibe un componente `Original` que renderiza la implementació
|
|
|
436
385
|
options={frameworks}
|
|
437
386
|
value={value}
|
|
438
387
|
onValueChange={setValue}
|
|
439
|
-
selectedFeedback="check"
|
|
440
388
|
renders={{
|
|
441
|
-
|
|
442
|
-
<div
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
),
|
|
450
|
-
}}
|
|
451
|
-
/>
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
### Mejorar Empty State con Acción
|
|
455
|
-
|
|
456
|
-
```tsx
|
|
457
|
-
<Combobox
|
|
458
|
-
searchable
|
|
459
|
-
options={[]}
|
|
460
|
-
renders={{
|
|
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>
|
|
389
|
+
displayValue: ({ text }) => (
|
|
390
|
+
<div className="flex items-center gap-2">
|
|
391
|
+
<span>{text}</span>
|
|
392
|
+
{text && (
|
|
393
|
+
<span className="px-1.5 py-0.5 text-xs bg-green-100 text-green-700 rounded font-medium">
|
|
394
|
+
Active
|
|
395
|
+
</span>
|
|
396
|
+
)}
|
|
472
397
|
</div>
|
|
473
398
|
),
|
|
474
399
|
}}
|
|
475
400
|
/>
|
|
476
401
|
```
|
|
477
402
|
|
|
478
|
-
### Custom Option Label
|
|
403
|
+
### Custom Option Label
|
|
479
404
|
|
|
480
405
|
```tsx
|
|
481
406
|
<Combobox
|
|
@@ -494,63 +419,23 @@ Cada render prop recibe un componente `Original` que renderiza la implementació
|
|
|
494
419
|
/>
|
|
495
420
|
```
|
|
496
421
|
|
|
497
|
-
### Custom
|
|
422
|
+
### Custom Empty State
|
|
498
423
|
|
|
499
424
|
```tsx
|
|
500
425
|
<Combobox
|
|
501
426
|
searchable
|
|
502
|
-
options={
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
renders={{
|
|
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>
|
|
516
|
-
),
|
|
427
|
+
options={[]}
|
|
428
|
+
labels={{
|
|
429
|
+
noItemsFound: "No items found.",
|
|
517
430
|
}}
|
|
518
|
-
/>
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
### Combinando Original y Custom
|
|
522
|
-
|
|
523
|
-
```tsx
|
|
524
|
-
<Combobox
|
|
525
|
-
searchable
|
|
526
|
-
multiple
|
|
527
|
-
options={frameworks}
|
|
528
|
-
value={values}
|
|
529
|
-
onValueChange={setValues}
|
|
530
431
|
renders={{
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
<
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
</span>
|
|
539
|
-
)}
|
|
540
|
-
</div>
|
|
541
|
-
),
|
|
542
|
-
// Custom completo sin Original
|
|
543
|
-
optionLabel: ({ option }) => (
|
|
544
|
-
<div className="flex items-center gap-2">
|
|
545
|
-
<span>🚀</span>
|
|
546
|
-
<span className="font-medium">{option.label}</span>
|
|
547
|
-
</div>
|
|
548
|
-
),
|
|
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>}
|
|
432
|
+
empty: ({ text }) => (
|
|
433
|
+
<div className="py-8 text-center">
|
|
434
|
+
<div className="text-4xl mb-2">🔍</div>
|
|
435
|
+
<p className="text-sm font-medium text-muted-foreground">{text}</p>
|
|
436
|
+
<p className="text-xs text-muted-foreground mt-1">
|
|
437
|
+
Try adjusting your search criteria
|
|
438
|
+
</p>
|
|
554
439
|
</div>
|
|
555
440
|
),
|
|
556
441
|
}}
|
|
@@ -629,7 +514,6 @@ Cada render prop recibe un componente `Original` que renderiza la implementació
|
|
|
629
514
|
- **icon**: Se muestra con `opacity-50` por defecto cuando se proporciona el prop `icon`
|
|
630
515
|
- **Render props**: Tienen prioridad sobre renderizado por defecto, permiten personalización completa
|
|
631
516
|
- **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
|
|
633
517
|
|
|
634
518
|
## Troubleshooting
|
|
635
519
|
|
|
@@ -643,9 +527,7 @@ Cada render prop recibe un componente `Original` que renderiza la implementació
|
|
|
643
527
|
**Icon no se muestra**: Asegúrate de pasar el prop `icon` con un componente válido
|
|
644
528
|
**Placeholder desaparece al seleccionar**: Si quieres mantenerlo visible, usa `alwaysShowPlaceholder={true}`
|
|
645
529
|
**Render prop no funciona**: Verifica que el render prop retorne un `ReactNode` válido
|
|
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
|
|
530
|
+
**Custom trigger pierde funcionalidad**: Cuando usas `renders.trigger`, debes manejar el click manualmente o envolver en `PopoverTrigger`
|
|
649
531
|
|
|
650
532
|
## Referencias
|
|
651
533
|
|