@adamosuiteservices/ui 2.15.1 → 2.16.1
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-BalI1GHE.cjs +40 -0
- package/dist/combobox-CtSJw4m1.js +614 -0
- package/dist/combobox.cjs +1 -1
- package/dist/combobox.js +1 -1
- package/dist/components/ui/combobox/combobox.d.ts +5 -1
- package/dist/date-picker-selector.cjs +1 -1
- package/dist/date-picker-selector.js +60 -47
- package/docs/components/ui/combobox.md +98 -3
- package/package.json +1 -1
- package/dist/combobox-DGuQtXjP.js +0 -608
- package/dist/combobox-hTCtPMUL.cjs +0 -40
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
import { j as e } from "./jsx-runtime-BzflLqGi.js";
|
|
2
|
-
import { B as
|
|
3
|
-
import { b as
|
|
4
|
-
import { C as
|
|
5
|
-
import { P as
|
|
6
|
-
import { useRef as
|
|
7
|
-
function
|
|
8
|
-
return
|
|
2
|
+
import { B as b } from "./button-B0lWuG-D.js";
|
|
3
|
+
import { b as A, C as F, s as i } from "./calendar-CfqtuOWv.js";
|
|
4
|
+
import { C as V } from "./combobox-CtSJw4m1.js";
|
|
5
|
+
import { P as w, c as B, b as M } from "./popover-DcQ18EVl.js";
|
|
6
|
+
import { useRef as x, useState as y } from "react";
|
|
7
|
+
function D(l, n, u) {
|
|
8
|
+
return A(l, -n, u);
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
dateRange:
|
|
12
|
-
onDateRangeChange:
|
|
13
|
-
labels:
|
|
14
|
-
combobox:
|
|
15
|
-
calendar:
|
|
16
|
-
"aria-invalid":
|
|
17
|
-
disabled:
|
|
10
|
+
function J({
|
|
11
|
+
dateRange: l,
|
|
12
|
+
onDateRangeChange: n,
|
|
13
|
+
labels: u,
|
|
14
|
+
combobox: C,
|
|
15
|
+
calendar: j,
|
|
16
|
+
"aria-invalid": g,
|
|
17
|
+
disabled: _
|
|
18
18
|
}) {
|
|
19
|
-
const
|
|
19
|
+
const f = x(null), m = x(void 0), R = (a) => {
|
|
20
|
+
if (!a.from || !a.to) return;
|
|
21
|
+
const o = i(/* @__PURE__ */ new Date()), h = [
|
|
22
|
+
{ value: "7_days", days: 7 },
|
|
23
|
+
{ value: "30_days", days: 30 },
|
|
24
|
+
{ value: "90_days", days: 90 }
|
|
25
|
+
];
|
|
26
|
+
for (const r of h) {
|
|
27
|
+
const S = D(o, r.days);
|
|
28
|
+
if (i(a.from).getTime() === S.getTime() && i(a.to).getTime() === o.getTime())
|
|
29
|
+
return r.value;
|
|
30
|
+
}
|
|
31
|
+
return "custom";
|
|
32
|
+
}, [p, t] = y(() => R(l)), [k, c] = y(!1), [d, L] = y(l), s = { ...{
|
|
20
33
|
last7Days: "Last 7 days",
|
|
21
34
|
last30Days: "Last 30 days",
|
|
22
35
|
last90Days: "Last 90 days",
|
|
@@ -24,31 +37,31 @@ function H({
|
|
|
24
37
|
placeholder: "Date",
|
|
25
38
|
cancel: "Cancel",
|
|
26
39
|
apply: "Apply"
|
|
27
|
-
}, ...
|
|
28
|
-
const
|
|
40
|
+
}, ...u }, P = (a) => {
|
|
41
|
+
const o = i(/* @__PURE__ */ new Date()), r = {
|
|
29
42
|
"7_days": 7,
|
|
30
43
|
"30_days": 30,
|
|
31
44
|
"90_days": 90
|
|
32
45
|
}[a];
|
|
33
|
-
return
|
|
34
|
-
},
|
|
35
|
-
t(
|
|
36
|
-
},
|
|
46
|
+
return r ? { from: D(o, r), to: o } : { from: void 0, to: void 0 };
|
|
47
|
+
}, v = (a) => {
|
|
48
|
+
t(m.current), c(!1);
|
|
49
|
+
}, T = (a) => {
|
|
37
50
|
if (a === "custom") {
|
|
38
|
-
|
|
51
|
+
m.current = p, t(a), c(!0);
|
|
39
52
|
return;
|
|
40
53
|
}
|
|
41
|
-
t(a),
|
|
42
|
-
},
|
|
43
|
-
if (
|
|
44
|
-
|
|
54
|
+
t(a), n(P(a));
|
|
55
|
+
}, O = () => {
|
|
56
|
+
if (d?.from && d?.to) {
|
|
57
|
+
n(d), t("custom"), c(!1);
|
|
45
58
|
return;
|
|
46
59
|
}
|
|
47
|
-
t(
|
|
60
|
+
t(m.current), c(!1);
|
|
48
61
|
};
|
|
49
62
|
return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
|
|
50
63
|
/* @__PURE__ */ e.jsx(
|
|
51
|
-
|
|
64
|
+
V,
|
|
52
65
|
{
|
|
53
66
|
alwaysShowPlaceholder: !0,
|
|
54
67
|
selectedFeedback: "check",
|
|
@@ -60,41 +73,41 @@ function H({
|
|
|
60
73
|
{ label: s.custom, value: "custom" }
|
|
61
74
|
],
|
|
62
75
|
labels: { placeholder: s.placeholder },
|
|
63
|
-
value:
|
|
64
|
-
onValueChange:
|
|
65
|
-
"aria-invalid":
|
|
66
|
-
disabled:
|
|
76
|
+
value: p,
|
|
77
|
+
onValueChange: T,
|
|
78
|
+
"aria-invalid": g,
|
|
79
|
+
disabled: _,
|
|
67
80
|
ref: (a) => {
|
|
68
|
-
|
|
81
|
+
f.current = a;
|
|
69
82
|
},
|
|
70
|
-
...
|
|
83
|
+
...C
|
|
71
84
|
}
|
|
72
85
|
),
|
|
73
86
|
/* @__PURE__ */ e.jsxs(
|
|
74
|
-
|
|
87
|
+
w,
|
|
75
88
|
{
|
|
76
|
-
open:
|
|
89
|
+
open: k,
|
|
77
90
|
onOpenChange: (a) => {
|
|
78
|
-
!a &&
|
|
91
|
+
!a && p === "custom" && v();
|
|
79
92
|
},
|
|
80
93
|
children: [
|
|
81
|
-
/* @__PURE__ */ e.jsx(B, { virtualRef:
|
|
82
|
-
/* @__PURE__ */ e.jsxs(
|
|
94
|
+
/* @__PURE__ */ e.jsx(B, { virtualRef: f }),
|
|
95
|
+
/* @__PURE__ */ e.jsxs(M, { align: "start", children: [
|
|
83
96
|
/* @__PURE__ */ e.jsx(
|
|
84
|
-
|
|
97
|
+
F,
|
|
85
98
|
{
|
|
86
99
|
required: !0,
|
|
87
100
|
mode: "range",
|
|
88
|
-
selected:
|
|
89
|
-
onSelect:
|
|
101
|
+
selected: d,
|
|
102
|
+
onSelect: L,
|
|
90
103
|
captionLayout: "dropdown",
|
|
91
104
|
classNames: { root: "adm:p-0!" },
|
|
92
|
-
...
|
|
105
|
+
...j
|
|
93
106
|
}
|
|
94
107
|
),
|
|
95
108
|
/* @__PURE__ */ e.jsxs("div", { className: "adm:mt-2 adm:flex adm:justify-end adm:gap-2", children: [
|
|
96
|
-
/* @__PURE__ */ e.jsx(
|
|
97
|
-
/* @__PURE__ */ e.jsx(
|
|
109
|
+
/* @__PURE__ */ e.jsx(b, { variant: "link", onClick: () => v(), children: s.cancel }),
|
|
110
|
+
/* @__PURE__ */ e.jsx(b, { variant: "link", onClick: O, children: s.apply })
|
|
98
111
|
] })
|
|
99
112
|
] })
|
|
100
113
|
]
|
|
@@ -103,5 +116,5 @@ function H({
|
|
|
103
116
|
] });
|
|
104
117
|
}
|
|
105
118
|
export {
|
|
106
|
-
|
|
119
|
+
J as DatePickerSelector
|
|
107
120
|
};
|
|
@@ -42,6 +42,8 @@ import { Combobox } from "@adamosuiteservices/ui/combobox";
|
|
|
42
42
|
| `ref` | `React.Ref<HTMLButtonElement>` | - | Ref al botón trigger para posicionamiento externo |
|
|
43
43
|
| `aria-invalid` | `"true" \| "false" \| boolean` | - | Indica estado inválido (borde rojo) |
|
|
44
44
|
| `disabled` | `boolean` | `false` | Deshabilita el combobox |
|
|
45
|
+
| `searchBy` | `"label" \| "value" \| "both"` | `"both"` | Define qué campos se usan para búsqueda |
|
|
46
|
+
| `filter` | `(value, search, keywords) => number` | - | Función personalizada de filtrado para búsqueda avanzada |
|
|
45
47
|
|
|
46
48
|
### ComboboxLabels
|
|
47
49
|
|
|
@@ -227,6 +229,90 @@ Cuando `alwaysShowPlaceholder` es true, puedes controlar dónde aparece el valor
|
|
|
227
229
|
/>
|
|
228
230
|
```
|
|
229
231
|
|
|
232
|
+
**Comportamiento de búsqueda por defecto**:
|
|
233
|
+
|
|
234
|
+
- La búsqueda es **case-insensitive** (sin distinguir mayúsculas/minúsculas)
|
|
235
|
+
- Por defecto busca en **ambos campos**: `label` y `value` (`searchBy="both"`)
|
|
236
|
+
- Ejemplo: Al buscar "nex" encuentra "Next.js" (por label), al buscar "ne" también lo encuentra (por value)
|
|
237
|
+
|
|
238
|
+
### Personalizar Búsqueda
|
|
239
|
+
|
|
240
|
+
Puedes controlar qué campos se usan para búsqueda con el prop `searchBy`:
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
// Buscar solo por label (texto visible)
|
|
244
|
+
<Combobox
|
|
245
|
+
searchable
|
|
246
|
+
searchBy="label"
|
|
247
|
+
options={frameworks}
|
|
248
|
+
labels={{ placeholder: "Select framework..." }}
|
|
249
|
+
/>
|
|
250
|
+
|
|
251
|
+
// Buscar solo por value (ID interno)
|
|
252
|
+
<Combobox
|
|
253
|
+
searchable
|
|
254
|
+
searchBy="value"
|
|
255
|
+
options={frameworks}
|
|
256
|
+
labels={{ placeholder: "Select framework..." }}
|
|
257
|
+
/>
|
|
258
|
+
|
|
259
|
+
// Buscar por ambos (default)
|
|
260
|
+
<Combobox
|
|
261
|
+
searchable
|
|
262
|
+
searchBy="both"
|
|
263
|
+
options={frameworks}
|
|
264
|
+
labels={{ placeholder: "Select framework..." }}
|
|
265
|
+
/>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Filtro Personalizado
|
|
269
|
+
|
|
270
|
+
Para casos de búsqueda avanzada, puedes proporcionar tu propia función de filtrado:
|
|
271
|
+
|
|
272
|
+
```tsx
|
|
273
|
+
// Función de filtrado con ranking por calidad de coincidencia
|
|
274
|
+
const customFilter = (value: string, search: string, keywords?: string[]) => {
|
|
275
|
+
const normalizedSearch = search.toLowerCase().trim();
|
|
276
|
+
const normalizedValue = value.toLowerCase().trim();
|
|
277
|
+
const normalizedLabel = keywords?.[0]?.toLowerCase().trim() ?? "";
|
|
278
|
+
|
|
279
|
+
// Coincidencia exacta = prioridad más alta
|
|
280
|
+
if (normalizedLabel === normalizedSearch || normalizedValue === normalizedSearch) {
|
|
281
|
+
return 10;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Comienza con búsqueda = prioridad media
|
|
285
|
+
if (normalizedLabel.startsWith(normalizedSearch) || normalizedValue.startsWith(normalizedSearch)) {
|
|
286
|
+
return 5;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Contiene búsqueda = prioridad baja
|
|
290
|
+
if (normalizedLabel.includes(normalizedSearch) || normalizedValue.includes(normalizedSearch)) {
|
|
291
|
+
return 1;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return 0; // Sin coincidencia
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
<Combobox
|
|
298
|
+
searchable
|
|
299
|
+
filter={customFilter}
|
|
300
|
+
options={frameworks}
|
|
301
|
+
labels={{ placeholder: "Select framework..." }}
|
|
302
|
+
/>;
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Parámetros de la función filter**:
|
|
306
|
+
|
|
307
|
+
- `value` (string): El valor interno de la opción (ej: "ne", "sv")
|
|
308
|
+
- `search` (string): El texto que el usuario está escribiendo
|
|
309
|
+
- `keywords` (string[] | undefined): Array con el label de la opción como primer elemento
|
|
310
|
+
|
|
311
|
+
**Valor de retorno**:
|
|
312
|
+
|
|
313
|
+
- `0`: Sin coincidencia (la opción se oculta)
|
|
314
|
+
- `> 0`: Hay coincidencia, el número indica el ranking (mayor = más relevante)
|
|
315
|
+
|
|
230
316
|
### Selección Simple Controlada
|
|
231
317
|
|
|
232
318
|
```tsx
|
|
@@ -560,7 +646,7 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
560
646
|
|
|
561
647
|
## Casos de Uso Comunes
|
|
562
648
|
|
|
563
|
-
**Framework selector**: Selección de tecnología con búsqueda
|
|
649
|
+
**Framework selector**: Selección de tecnología con búsqueda case-insensitive
|
|
564
650
|
**Country/City picker**: Selección geográfica con opciones deshabilitadas
|
|
565
651
|
**Tags/Categories**: Selección múltiple de categorías
|
|
566
652
|
**Settings filters**: Filtros multi-selección en dashboards
|
|
@@ -568,7 +654,9 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
568
654
|
**Language selector**: Selección de idioma con búsqueda
|
|
569
655
|
**Status selector con icono**: Usar `icon` + `alwaysShowPlaceholder` para selectores etiquetados
|
|
570
656
|
**Rich options**: Usar `renders.optionLabel` para mostrar avatares, badges, etc.
|
|
571
|
-
**Custom UI**: Usar `renders.trigger` para triggers completamente personalizados
|
|
657
|
+
**Custom UI**: Usar `renders.trigger` para triggers completamente personalizados
|
|
658
|
+
**Search by ID**: Usar `searchBy="value"` cuando necesites buscar por IDs internos
|
|
659
|
+
**Smart search**: Usar función `filter` personalizada para implementar búsqueda fuzzy, ranking, o lógica compleja
|
|
572
660
|
|
|
573
661
|
## Estados Internos
|
|
574
662
|
|
|
@@ -599,7 +687,12 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
599
687
|
## Notas de Implementación
|
|
600
688
|
|
|
601
689
|
- **Composición**: Usa Popover + Command + Button + Checkbox internamente
|
|
602
|
-
- **Búsqueda**:
|
|
690
|
+
- **Búsqueda**:
|
|
691
|
+
- Usa función de filtrado personalizada que busca por label y/o value
|
|
692
|
+
- Case-insensitive por defecto
|
|
693
|
+
- Configurable con `searchBy` prop (`"label"`, `"value"`, o `"both"`)
|
|
694
|
+
- Extensible con función `filter` personalizada para casos avanzados
|
|
695
|
+
- El label se pasa como keyword al CommandItem para que cmdk pueda filtrarlo
|
|
603
696
|
- **Estado interno**: Soporta modo controlado y no controlado
|
|
604
697
|
- **Tipo de value**: Cambia según `multiple` (string vs string[])
|
|
605
698
|
- **selectedFeedback**:
|
|
@@ -650,6 +743,8 @@ Hereda estilos de Command component:
|
|
|
650
743
|
|
|
651
744
|
**Value no cambia**: Verifica que uses `onValueChange` en modo controlado
|
|
652
745
|
**Búsqueda no funciona**: Asegúrate de pasar `searchable={true}`
|
|
746
|
+
**Búsqueda solo encuentra por código (value)**: El comportamiento por defecto busca por ambos, si usaste `searchBy="value"`, cámbialo a `searchBy="both"` o `searchBy="label"`
|
|
747
|
+
**Búsqueda distingue mayúsculas**: El filtro por defecto es case-insensitive, si usas función `filter` personalizada, asegúrate de normalizar con `.toLowerCase()`
|
|
653
748
|
**Multiple selection cierra popover**: Verifica que `multiple={true}` esté activo
|
|
654
749
|
**Labels incorrectas en multiple**: Usa función `multipleSelected` para pluralización
|
|
655
750
|
**Tipo de value incorrecto**: Single usa `string`, Multiple usa `string[]`
|