@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.
@@ -1,22 +1,35 @@
1
1
  import { j as e } from "./jsx-runtime-BzflLqGi.js";
2
- import { B as h } from "./button-B0lWuG-D.js";
3
- import { b as _, C as P, s as O } from "./calendar-CfqtuOWv.js";
4
- import { C as S } from "./combobox-DGuQtXjP.js";
5
- import { P as A, c as B, b as F } from "./popover-DcQ18EVl.js";
6
- import { useRef as v, useState as u } from "react";
7
- function M(n, o, c) {
8
- return _(n, -o, c);
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 H({
11
- dateRange: n,
12
- onDateRangeChange: o,
13
- labels: c,
14
- combobox: b,
15
- calendar: x,
16
- "aria-invalid": C,
17
- disabled: D
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 m = v(null), d = v(void 0), [i, t] = u(void 0), [j, l] = u(!1), [r, g] = u(n), s = { ...{
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
- }, ...c }, R = (a) => {
28
- const y = O(/* @__PURE__ */ new Date()), f = {
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 f ? { from: M(y, f), to: y } : { from: void 0, to: void 0 };
34
- }, p = (a) => {
35
- t(d.current), l(!1);
36
- }, k = (a) => {
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
- d.current = i, t(a), l(!0);
51
+ m.current = p, t(a), c(!0);
39
52
  return;
40
53
  }
41
- t(a), o(R(a));
42
- }, L = () => {
43
- if (r?.from && r?.to) {
44
- o(r), t("custom"), l(!1);
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(d.current), l(!1);
60
+ t(m.current), c(!1);
48
61
  };
49
62
  return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
50
63
  /* @__PURE__ */ e.jsx(
51
- S,
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: i,
64
- onValueChange: k,
65
- "aria-invalid": C,
66
- disabled: D,
76
+ value: p,
77
+ onValueChange: T,
78
+ "aria-invalid": g,
79
+ disabled: _,
67
80
  ref: (a) => {
68
- m.current = a;
81
+ f.current = a;
69
82
  },
70
- ...b
83
+ ...C
71
84
  }
72
85
  ),
73
86
  /* @__PURE__ */ e.jsxs(
74
- A,
87
+ w,
75
88
  {
76
- open: j,
89
+ open: k,
77
90
  onOpenChange: (a) => {
78
- !a && i === "custom" && p();
91
+ !a && p === "custom" && v();
79
92
  },
80
93
  children: [
81
- /* @__PURE__ */ e.jsx(B, { virtualRef: m }),
82
- /* @__PURE__ */ e.jsxs(F, { align: "start", children: [
94
+ /* @__PURE__ */ e.jsx(B, { virtualRef: f }),
95
+ /* @__PURE__ */ e.jsxs(M, { align: "start", children: [
83
96
  /* @__PURE__ */ e.jsx(
84
- P,
97
+ F,
85
98
  {
86
99
  required: !0,
87
100
  mode: "range",
88
- selected: r,
89
- onSelect: g,
101
+ selected: d,
102
+ onSelect: L,
90
103
  captionLayout: "dropdown",
91
104
  classNames: { root: "adm:p-0!" },
92
- ...x
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(h, { variant: "link", onClick: () => p(), children: s.cancel }),
97
- /* @__PURE__ */ e.jsx(h, { variant: "link", onClick: L, children: s.apply })
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
- H as DatePickerSelector
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**: Command component maneja fuzzy search automáticamente
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[]`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adamosuiteservices/ui",
3
- "version": "2.15.1",
3
+ "version": "2.16.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",