@adamosuiteservices/ui 1.2.4 → 1.3.5
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/README.md +4 -0
- package/dist/accordion-rounded.cjs +1 -1
- package/dist/accordion-rounded.js +1 -1
- package/dist/accordion.cjs +1 -1
- package/dist/accordion.js +1 -1
- package/dist/avatar.cjs +1 -1
- package/dist/avatar.js +1 -1
- package/dist/badge.cjs +1 -1
- package/dist/badge.js +1 -1
- package/dist/breadcrumb.cjs +1 -0
- package/dist/breadcrumb.js +105 -0
- package/dist/{button-C1n6snOY.js → button-2GdKenQI.js} +1 -1
- package/dist/{button-BV-_FVKZ.cjs → button-DEQVHMrX.cjs} +1 -1
- package/dist/button-group.cjs +1 -1
- package/dist/button-group.js +2 -2
- package/dist/button.cjs +1 -1
- package/dist/button.js +1 -1
- package/dist/calendar.cjs +1 -1
- package/dist/calendar.js +1 -1
- package/dist/{checkbox-BrmXPKTn.js → checkbox-Dr487kAg.js} +3 -3
- package/dist/{checkbox-Lq-HvSgc.cjs → checkbox-YWAnswaW.cjs} +1 -1
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/collapsible.cjs +1 -1
- package/dist/collapsible.js +1 -1
- package/dist/combobox.cjs +1 -1
- package/dist/combobox.js +6 -6
- package/dist/components/ui/breadcrumb/breadcrumb.d.ts +11 -0
- package/dist/components/ui/breadcrumb/breadcrumb.stories.d.ts +26 -0
- package/dist/components/ui/breadcrumb/index.d.ts +1 -0
- package/dist/components/ui/dialog/dialog.d.ts +2 -1
- package/dist/context-menu.cjs +1 -1
- package/dist/context-menu.js +2 -2
- package/dist/custom-layered-styles.css +1 -1
- package/dist/dialog.cjs +1 -1
- package/dist/dialog.js +33 -19
- package/dist/dropdown-menu.cjs +1 -1
- package/dist/dropdown-menu.js +3 -3
- package/dist/ellipsis-CryjZKZn.js +15 -0
- package/dist/ellipsis-Ct9VTDOG.cjs +6 -0
- package/dist/field.cjs +1 -1
- package/dist/field.js +2 -2
- package/dist/hover-card.cjs +1 -1
- package/dist/hover-card.js +6 -6
- package/dist/{index-CAOY367Y.js → index-B0M7VOwp.js} +2 -2
- package/dist/{index-B-ZRqW0J.js → index-BBoIAjAs.js} +3 -3
- package/dist/{index-gO_QEiaK.cjs → index-BDs8lUfq.cjs} +1 -1
- package/dist/index-BFyr34mw.cjs +5 -0
- package/dist/index-BMWt1NBG.js +79 -0
- package/dist/{index-yR-v1A4G.js → index-BX9hz-JD.js} +1 -1
- package/dist/{index-BGiGvaq8.cjs → index-BcGMAmWE.cjs} +1 -1
- package/dist/{index-IKJMQref.cjs → index-Bd0gQB0k.cjs} +1 -1
- package/dist/{index-VIUqZjyP.cjs → index-BeWgla7c.cjs} +1 -1
- package/dist/{index-EUea2gfp.js → index-BpWB3aFK.js} +1 -1
- package/dist/index-BvLQnI56.js +59 -0
- package/dist/{index-CwUFT-GQ.js → index-C0YiLSjW.js} +4 -4
- package/dist/{index-o0sNTcKe.js → index-CBjZooac.js} +2 -2
- package/dist/{index-DnS_sBBe.cjs → index-COuvjZLM.cjs} +1 -1
- package/dist/index-CTjlbbt9.cjs +1 -0
- package/dist/index-CUWMxxKG.js +97 -0
- package/dist/{index-C329e3yQ.js → index-CZZ3llmi.js} +2 -2
- package/dist/index-CjyiloO7.cjs +1 -0
- package/dist/{index-D3wSWKST.cjs → index-Cmx9M9cZ.cjs} +1 -1
- package/dist/index-CocSS1YK.cjs +1 -0
- package/dist/index-CzRiuk60.cjs +1 -0
- package/dist/index-DFPDUUq7.js +658 -0
- package/dist/{index-D3S7dBDI.cjs → index-DIwmXz1u.cjs} +1 -1
- package/dist/index-DLcqcWxM.js +29 -0
- package/dist/index-DMLQL2aG.js +286 -0
- package/dist/{index-DXQ-7kNJ.cjs → index-DMs8RL3E.cjs} +1 -1
- package/dist/{index-Ce3QBKyj.cjs → index-Dbj9vHNq.cjs} +1 -1
- package/dist/{index-BRLtxFFr.cjs → index-DmGzwG2z.cjs} +1 -1
- package/dist/{index-P1sVIHE3.js → index-PYkEXTqJ.js} +1 -1
- package/dist/{index-DulPG3F9.js → index-Se4vRnIO.js} +3 -3
- package/dist/index-_XxjJPRD.cjs +1 -0
- package/dist/{index-B-cHTKrs.js → index-yWvyIlmA.js} +4 -4
- package/dist/input-group.cjs +1 -1
- package/dist/input-group.js +1 -1
- package/dist/{label-Cne2J57f.cjs → label-BjXORCBM.cjs} +1 -1
- package/dist/{label-Ky8qBEC3.js → label-CmwGvhy1.js} +1 -1
- package/dist/label.cjs +1 -1
- package/dist/label.js +1 -1
- package/dist/pagination.cjs +1 -6
- package/dist/pagination.js +58 -69
- package/dist/popover-3rIoNCXs.js +306 -0
- package/dist/popover-FCKBtFo-.cjs +1 -0
- package/dist/popover.cjs +1 -1
- package/dist/popover.js +1 -1
- package/dist/progress.cjs +1 -1
- package/dist/progress.js +1 -1
- package/dist/radio-group.cjs +1 -1
- package/dist/radio-group.js +5 -5
- package/dist/select.cjs +2 -2
- package/dist/select.js +585 -542
- package/dist/{separator-CGnu_jIu.cjs → separator-BaZqZZ9R.cjs} +1 -1
- package/dist/{separator-BH73A90k.js → separator-DR7lQjv9.js} +1 -1
- package/dist/separator.cjs +1 -1
- package/dist/separator.js +1 -1
- package/dist/{sheet-CcxnJ6LH.cjs → sheet-CU-sFSaJ.cjs} +1 -1
- package/dist/{sheet-_DVpQIVF.js → sheet-UZWAbdXr.js} +1 -1
- package/dist/sheet.cjs +1 -1
- package/dist/sheet.js +1 -1
- package/dist/sidebar.cjs +1 -1
- package/dist/sidebar.js +4 -4
- package/dist/slider.cjs +1 -1
- package/dist/slider.js +3 -3
- package/dist/styles.css +1 -1
- package/dist/switch.cjs +1 -1
- package/dist/switch.js +2 -2
- package/dist/tabs-underline.cjs +1 -1
- package/dist/tabs-underline.js +1 -1
- package/dist/tabs.cjs +1 -1
- package/dist/tabs.js +1 -1
- package/dist/toaster.cjs +1 -1
- package/dist/toaster.js +1 -1
- package/dist/toggle.cjs +1 -1
- package/dist/toggle.js +1 -1
- package/dist/tooltip.cjs +1 -1
- package/dist/tooltip.js +114 -108
- package/dist/typography.cjs +1 -1
- package/dist/typography.js +16 -16
- package/docs/AI-GUIDE.md +321 -0
- package/docs/components/layout/sidebar.md +330 -0
- package/docs/components/layout/toaster.md +436 -0
- package/docs/components/ui/accordion-rounded.md +583 -0
- package/docs/components/ui/accordion.md +267 -0
- package/docs/components/ui/alert.md +671 -0
- package/docs/components/ui/avatar.md +588 -0
- package/docs/components/ui/badge.md +1024 -0
- package/docs/components/ui/breadcrumb.md +614 -0
- package/docs/components/ui/button-group.md +1002 -0
- package/docs/components/ui/button.md +1078 -0
- package/docs/components/ui/calendar.md +1159 -0
- package/docs/components/ui/card.md +1265 -0
- package/docs/components/ui/checkbox.md +292 -0
- package/docs/components/ui/collapsible.md +320 -0
- package/docs/components/ui/combobox.md +328 -0
- package/docs/components/ui/command.md +454 -0
- package/docs/components/ui/context-menu.md +540 -0
- package/docs/components/ui/dialog.md +628 -0
- package/docs/components/ui/dropdown-menu.md +731 -0
- package/docs/components/ui/field.md +706 -0
- package/docs/components/ui/hover-card.md +446 -0
- package/docs/components/ui/input-group.md +509 -0
- package/docs/components/ui/input.md +362 -0
- package/docs/components/ui/kbd.md +434 -0
- package/docs/components/ui/label.md +359 -0
- package/docs/components/ui/pagination.md +650 -0
- package/docs/components/ui/popover.md +536 -0
- package/docs/components/ui/progress.md +182 -0
- package/docs/components/ui/radio-group.md +311 -0
- package/docs/components/ui/select.md +352 -0
- package/docs/components/ui/separator.md +214 -0
- package/docs/components/ui/sheet.md +142 -0
- package/docs/components/ui/skeleton.md +140 -0
- package/docs/components/ui/slider.md +341 -0
- package/docs/components/ui/spinner.md +170 -0
- package/docs/components/ui/switch.md +402 -0
- package/docs/components/ui/table.md +183 -0
- package/docs/components/ui/tabs-underline.md +106 -0
- package/docs/components/ui/tabs.md +122 -0
- package/docs/components/ui/textarea.md +243 -0
- package/docs/components/ui/toggle.md +243 -0
- package/docs/components/ui/tooltip.md +320 -0
- package/docs/components/ui/typography.md +191 -0
- package/package.json +11 -5
- package/dist/index-6oTEokEx.js +0 -82
- package/dist/index-B-NyefE0.js +0 -243
- package/dist/index-BKbK2GzY.cjs +0 -1
- package/dist/index-BMitW9UR.cjs +0 -1
- package/dist/index-BpvjJ_T6.cjs +0 -5
- package/dist/index-C5wjudc-.js +0 -36
- package/dist/index-CezwiPd_.js +0 -615
- package/dist/index-D02K8KOB.js +0 -54
- package/dist/index-D7hQvndv.cjs +0 -1
- package/dist/index-DQvx1rG_.cjs +0 -1
- package/dist/popover-BjdTqaB8.cjs +0 -1
- package/dist/popover-EnVfE0YA.js +0 -263
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# Combobox
|
|
2
|
+
|
|
3
|
+
Componente de selección avanzado que combina Popover + Command para búsqueda y selección. Soporta selección simple/múltiple, búsqueda filtrable, opciones deshabilitadas, y feedback visual con checkbox o check.
|
|
4
|
+
|
|
5
|
+
## Importación
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Combobox } from "@adamosuiteservices/ui/combobox";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Anatomía
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<Combobox
|
|
15
|
+
options={[
|
|
16
|
+
{ value: "option1", label: "Option 1" },
|
|
17
|
+
{ value: "option2", label: "Option 2", disabled: true },
|
|
18
|
+
]}
|
|
19
|
+
value={selectedValue}
|
|
20
|
+
onValueChange={setSelectedValue}
|
|
21
|
+
/>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Componente único**: Internamente usa Popover, Command, Button, Checkbox
|
|
25
|
+
|
|
26
|
+
## Props Principales
|
|
27
|
+
|
|
28
|
+
| Prop | Tipo | Default | Descripción |
|
|
29
|
+
| ------------------ | ------------------------------------- | ------------ | ---------------------------------------------------------- |
|
|
30
|
+
| `options` | `ComboboxOption[]` | **required** | Array de opciones `{ value, label, disabled? }` |
|
|
31
|
+
| `value` | `string \| string[]` | - | Valor controlado (string para single, array para multiple) |
|
|
32
|
+
| `onValueChange` | `(value: string \| string[]) => void` | - | Callback al cambiar selección |
|
|
33
|
+
| `searchable` | `boolean` | `false` | Habilita input de búsqueda |
|
|
34
|
+
| `multiple` | `boolean` | `false` | Permite selección múltiple |
|
|
35
|
+
| `selectedFeedback` | `"checkbox" \| "check"` | `"checkbox"` | Tipo de indicador visual |
|
|
36
|
+
| `labels` | `ComboboxLabels` | - | Textos personalizables (ver tabla abajo) |
|
|
37
|
+
| `classNames` | `ComboboxClassNames` | - | Clases CSS por sección (ver tabla abajo) |
|
|
38
|
+
|
|
39
|
+
### ComboboxLabels
|
|
40
|
+
|
|
41
|
+
| Prop | Tipo | Default | Descripción |
|
|
42
|
+
| ------------------- | --------------------------- | ---------------------- | ----------------------------------------------- |
|
|
43
|
+
| `placeholder` | `string` | `"Select options..."` | Texto cuando no hay selección |
|
|
44
|
+
| `searchPlaceholder` | `string` | `"Search options..."` | Placeholder del input de búsqueda |
|
|
45
|
+
| `noItemsFound` | `string` | `"No options found."` | Mensaje cuando búsqueda no encuentra resultados |
|
|
46
|
+
| `multipleSelected` | `(count: number) => string` | `"X options selected"` | Función para texto de múltiples seleccionados |
|
|
47
|
+
|
|
48
|
+
### ComboboxClassNames
|
|
49
|
+
|
|
50
|
+
| Prop | Descripción |
|
|
51
|
+
| ---------- | -------------------------------------------------------- |
|
|
52
|
+
| `trigger` | Button trigger del popover |
|
|
53
|
+
| `popover` | Contenedor del popover |
|
|
54
|
+
| `command` | Componente Command root |
|
|
55
|
+
| `input` | Input de búsqueda |
|
|
56
|
+
| `list` | Lista de opciones |
|
|
57
|
+
| `empty` | Mensaje de no resultados |
|
|
58
|
+
| `group` | Grupo de items |
|
|
59
|
+
| `item` | Cada opción individual |
|
|
60
|
+
| `checkbox` | Checkbox de selección (si `selectedFeedback="checkbox"`) |
|
|
61
|
+
| `check` | Icono de check (si `selectedFeedback="check"`) |
|
|
62
|
+
|
|
63
|
+
## Patrones de Uso
|
|
64
|
+
|
|
65
|
+
### Básico (Sin Búsqueda)
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
const frameworks = [
|
|
69
|
+
{ value: "next", label: "Next.js" },
|
|
70
|
+
{ value: "remix", label: "Remix" },
|
|
71
|
+
{ value: "astro", label: "Astro" },
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
<Combobox
|
|
75
|
+
options={frameworks}
|
|
76
|
+
labels={{ placeholder: "Select framework..." }}
|
|
77
|
+
/>;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Con Búsqueda
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<Combobox
|
|
84
|
+
searchable
|
|
85
|
+
options={frameworks}
|
|
86
|
+
labels={{
|
|
87
|
+
placeholder: "Select framework...",
|
|
88
|
+
searchPlaceholder: "Search frameworks...",
|
|
89
|
+
noItemsFound: "No framework found.",
|
|
90
|
+
}}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Selección Simple Controlada
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
const [value, setValue] = useState("");
|
|
98
|
+
|
|
99
|
+
<Combobox
|
|
100
|
+
searchable
|
|
101
|
+
options={frameworks}
|
|
102
|
+
value={value}
|
|
103
|
+
onValueChange={(newValue) => setValue(newValue as string)}
|
|
104
|
+
labels={{ placeholder: "Select framework..." }}
|
|
105
|
+
/>;
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Selección Múltiple
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
const [values, setValues] = useState<string[]>([]);
|
|
112
|
+
|
|
113
|
+
<Combobox
|
|
114
|
+
searchable
|
|
115
|
+
multiple
|
|
116
|
+
options={frameworks}
|
|
117
|
+
value={values}
|
|
118
|
+
onValueChange={(newValues) => setValues(newValues as string[])}
|
|
119
|
+
labels={{
|
|
120
|
+
placeholder: "Select frameworks...",
|
|
121
|
+
multipleSelected: (count) => `${count} frameworks selected`,
|
|
122
|
+
}}
|
|
123
|
+
/>;
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Con Feedback de Check
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
<Combobox
|
|
130
|
+
searchable
|
|
131
|
+
options={frameworks}
|
|
132
|
+
selectedFeedback="check"
|
|
133
|
+
labels={{ placeholder: "Select option..." }}
|
|
134
|
+
/>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Diferencia**: `"checkbox"` muestra checkboxes a la izquierda, `"check"` muestra ícono check a la derecha.
|
|
138
|
+
|
|
139
|
+
### Opciones Deshabilitadas
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
const options = [
|
|
143
|
+
{ value: "us", label: "United States" },
|
|
144
|
+
{ value: "ca", label: "Canada" },
|
|
145
|
+
{ value: "mx", label: "Mexico", disabled: true },
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
<Combobox
|
|
149
|
+
searchable
|
|
150
|
+
options={options}
|
|
151
|
+
labels={{ placeholder: "Select country..." }}
|
|
152
|
+
/>;
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Labels Personalizadas
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
<Combobox
|
|
159
|
+
searchable
|
|
160
|
+
multiple
|
|
161
|
+
options={frameworks}
|
|
162
|
+
labels={{
|
|
163
|
+
placeholder: "Choose your stack...",
|
|
164
|
+
searchPlaceholder: "Type to filter...",
|
|
165
|
+
noItemsFound: "No matching technologies found.",
|
|
166
|
+
multipleSelected: (count) =>
|
|
167
|
+
`${count} ${count === 1 ? "tech" : "techs"} selected`,
|
|
168
|
+
}}
|
|
169
|
+
/>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Styling Personalizado
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
<Combobox
|
|
176
|
+
searchable
|
|
177
|
+
options={frameworks}
|
|
178
|
+
classNames={{
|
|
179
|
+
trigger: "border-2 border-blue-500 w-64",
|
|
180
|
+
popover: "border-blue-200 shadow-lg",
|
|
181
|
+
item: "rounded px-3 py-2 hover:bg-blue-50",
|
|
182
|
+
check: "text-blue-600",
|
|
183
|
+
}}
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### En Formulario
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
import { Field, FieldLabel } from "@adamosuiteservices/ui/field";
|
|
191
|
+
|
|
192
|
+
function FormExample() {
|
|
193
|
+
const [framework, setFramework] = useState("");
|
|
194
|
+
const [country, setCountry] = useState("");
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<form className="space-y-4">
|
|
198
|
+
<Field>
|
|
199
|
+
<FieldLabel>Framework</FieldLabel>
|
|
200
|
+
<Combobox
|
|
201
|
+
searchable
|
|
202
|
+
options={frameworks}
|
|
203
|
+
value={framework}
|
|
204
|
+
onValueChange={(value) => setFramework(value as string)}
|
|
205
|
+
labels={{ placeholder: "Select framework..." }}
|
|
206
|
+
/>
|
|
207
|
+
</Field>
|
|
208
|
+
|
|
209
|
+
<Field>
|
|
210
|
+
<FieldLabel>Country</FieldLabel>
|
|
211
|
+
<Combobox
|
|
212
|
+
searchable
|
|
213
|
+
options={countries}
|
|
214
|
+
value={country}
|
|
215
|
+
onValueChange={(value) => setCountry(value as string)}
|
|
216
|
+
selectedFeedback="check"
|
|
217
|
+
labels={{ placeholder: "Select country..." }}
|
|
218
|
+
/>
|
|
219
|
+
</Field>
|
|
220
|
+
|
|
221
|
+
<button type="submit">Submit</button>
|
|
222
|
+
</form>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Multiple con Clear All
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
const [values, setValues] = useState<string[]>([]);
|
|
231
|
+
|
|
232
|
+
<div className="space-y-2">
|
|
233
|
+
<Combobox
|
|
234
|
+
searchable
|
|
235
|
+
multiple
|
|
236
|
+
options={frameworks}
|
|
237
|
+
value={values}
|
|
238
|
+
onValueChange={(newValues) => setValues(newValues as string[])}
|
|
239
|
+
/>
|
|
240
|
+
|
|
241
|
+
{values.length > 0 && (
|
|
242
|
+
<button
|
|
243
|
+
onClick={() => setValues([])}
|
|
244
|
+
className="text-xs text-blue-600 hover:text-blue-800 underline"
|
|
245
|
+
>
|
|
246
|
+
Clear all
|
|
247
|
+
</button>
|
|
248
|
+
)}
|
|
249
|
+
</div>;
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Modos de Operación
|
|
253
|
+
|
|
254
|
+
### Single Selection
|
|
255
|
+
|
|
256
|
+
- `multiple={false}` (default)
|
|
257
|
+
- `value` es `string`
|
|
258
|
+
- Click en opción cierra el popover automáticamente
|
|
259
|
+
- Seleccionar opción ya seleccionada la deselecciona
|
|
260
|
+
|
|
261
|
+
### Multiple Selection
|
|
262
|
+
|
|
263
|
+
- `multiple={true}`
|
|
264
|
+
- `value` es `string[]`
|
|
265
|
+
- Click en opción NO cierra el popover
|
|
266
|
+
- Checkboxes permiten toggle de múltiples opciones
|
|
267
|
+
- Display muestra contador cuando >1 seleccionado
|
|
268
|
+
|
|
269
|
+
## Casos de Uso Comunes
|
|
270
|
+
|
|
271
|
+
**Framework selector**: Selección de tecnología con búsqueda
|
|
272
|
+
**Country/City picker**: Selección geográfica con opciones deshabilitadas
|
|
273
|
+
**Tags/Categories**: Selección múltiple de categorías
|
|
274
|
+
**Settings filters**: Filtros multi-selección en dashboards
|
|
275
|
+
**User assignment**: Asignar múltiples usuarios a tarea
|
|
276
|
+
**Language selector**: Selección de idioma con búsqueda
|
|
277
|
+
|
|
278
|
+
## Estados Internos
|
|
279
|
+
|
|
280
|
+
### Display Text
|
|
281
|
+
|
|
282
|
+
- **Sin selección**: Muestra `labels.placeholder`
|
|
283
|
+
- **Single selection**: Muestra `label` de la opción seleccionada
|
|
284
|
+
- **Multiple (1 item)**: Muestra `label` del único item seleccionado
|
|
285
|
+
- **Multiple (>1 items)**: Muestra resultado de `labels.multipleSelected(count)`
|
|
286
|
+
|
|
287
|
+
### Popover State
|
|
288
|
+
|
|
289
|
+
- Controlado internamente con `useState`
|
|
290
|
+
- Se cierra automáticamente en single selection
|
|
291
|
+
- Permanece abierto en multiple selection
|
|
292
|
+
|
|
293
|
+
## Accesibilidad
|
|
294
|
+
|
|
295
|
+
- ✅ **ARIA**: Button tiene `role="combobox"` y `aria-expanded`
|
|
296
|
+
- ✅ **Navegación teclado**: Arrow keys para navegar opciones, Enter para seleccionar, Escape para cerrar
|
|
297
|
+
- ✅ **Screen readers**: Anuncia opciones y estado seleccionado
|
|
298
|
+
- ✅ **Focus management**: Focus automático en input cuando searchable
|
|
299
|
+
- ✅ **Disabled options**: No seleccionables, estilo visual diferente
|
|
300
|
+
|
|
301
|
+
## Notas de Implementación
|
|
302
|
+
|
|
303
|
+
- **Composición**: Usa Popover + Command + Button + Checkbox internamente
|
|
304
|
+
- **Búsqueda**: Command component maneja fuzzy search automáticamente
|
|
305
|
+
- **Estado interno**: Soporta modo controlado y no controlado
|
|
306
|
+
- **Tipo de value**: Cambia según `multiple` (string vs string[])
|
|
307
|
+
- **selectedFeedback**:
|
|
308
|
+
- `"checkbox"`: Muestra Checkbox a la izquierda de cada opción
|
|
309
|
+
- `"check"`: Muestra CheckIcon a la derecha (agrega `pr-8` automáticamente)
|
|
310
|
+
- **Popover alignment**: `align="start"` por defecto para alinear con trigger
|
|
311
|
+
- **ChevronDownIcon**: Se muestra en trigger con `opacity-50`
|
|
312
|
+
- **No animation**: Selección instantánea, sin delays
|
|
313
|
+
|
|
314
|
+
## Troubleshooting
|
|
315
|
+
|
|
316
|
+
**Value no cambia**: Verifica que uses `onValueChange` en modo controlado
|
|
317
|
+
**Búsqueda no funciona**: Asegúrate de pasar `searchable={true}`
|
|
318
|
+
**Multiple selection cierra popover**: Verifica que `multiple={true}` esté activo
|
|
319
|
+
**Labels incorrectas en multiple**: Usa función `multipleSelected` para pluralización
|
|
320
|
+
**Tipo de value incorrecto**: Single usa `string`, Multiple usa `string[]`
|
|
321
|
+
**Checkboxes no aparecen**: Solo aparecen cuando `selectedFeedback="checkbox"` (default)
|
|
322
|
+
**Check icon no visible**: Solo aparece cuando `selectedFeedback="check"`
|
|
323
|
+
|
|
324
|
+
## Referencias
|
|
325
|
+
|
|
326
|
+
- **Radix UI Popover**: https://www.radix-ui.com/primitives/docs/components/popover
|
|
327
|
+
- **Command Component**: Ver documentación de Command
|
|
328
|
+
- **ARIA Combobox**: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/
|