@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.
@@ -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
- | 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 |
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
- ### Custom Option Label
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
- optionLabel: ({ option }) => (
360
- <div className="flex items-center gap-2">
361
- <span className="font-semibold text-blue-600">🚀</span>
362
- <span>{option.label}</span>
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
- ### Custom Display Value
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
- <span className="font-semibold text-blue-600">{text}</span>
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
- ### Custom Trigger Completo
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: ({ open, displayText, placeholder, hasValue }) => (
395
- <button
396
- type="button"
397
- className="flex items-center justify-between w-full px-4 py-2 text-sm bg-linear-to-r from-purple-500 to-pink-500 text-white rounded-lg shadow-md hover:shadow-lg transition-all"
398
- >
399
- <span>{hasValue ? displayText : placeholder}</span>
400
- <span className={`transition-transform ${open ? "rotate-180" : ""}`}>
401
-
402
- </span>
403
- </button>
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
- ### Custom Empty State
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={values}
437
- onValueChange={setValues}
437
+ value={value}
438
+ onValueChange={setValue}
439
+ selectedFeedback="check"
438
440
  renders={{
439
- selectedFeedback: ({ isSelected }) => (
440
- <span className="text-lg">{isSelected ? "✅" : "⬜"}</span>
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
- ### Custom Placeholder
454
+ ### Mejorar Empty State con Acción
447
455
 
448
456
  ```tsx
449
457
  <Combobox
450
458
  searchable
451
- alwaysShowPlaceholder
452
- options={frameworks}
453
- value={value}
454
- onValueChange={setValue}
459
+ options={[]}
455
460
  renders={{
456
- placeholder: ({ text, hasValue }) => (
457
- <span className={hasValue ? "opacity-50 italic" : ""}>{text}</span>
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 Trigger Icon
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
- triggerIcon: ({ open }) => (
473
- <span className={`transition-transform ${open ? "rotate-90" : ""}`}>
474
-
475
- </span>
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 Search Input
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
- searchInput: ({ placeholder }) => (
491
- <div className="flex items-center px-3 py-2 border-b">
492
- <span className="mr-2">🔍</span>
493
- <input
494
- type="text"
495
- placeholder={placeholder}
496
- className="flex-1 outline-none text-sm"
497
- />
498
- </div>
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 Múltiples Renders
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
- displayValue: ({ text }) => (
525
- <span className="font-semibold text-purple-600">{text}</span>
526
- ),
527
- selectedFeedback: ({ isSelected }) => (
528
- <span className="text-lg">{isSelected ? "✅" : "⬜"}</span>
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adamosuiteservices/ui",
3
- "version": "1.6.7",
3
+ "version": "1.7.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",