@adamosuiteservices/ui 2.11.17 → 2.11.18
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/accordion-rounded.cjs +1 -1
- package/dist/accordion-rounded.js +1 -1
- package/dist/badge.cjs +3 -3
- package/dist/badge.js +2 -2
- package/dist/breadcrumb.cjs +5 -5
- package/dist/breadcrumb.js +16 -16
- package/dist/components/ui/date-picker-selector/date-picker-selector.d.ts +2 -2
- package/dist/components/ui/sheet/sheet.d.ts +2 -1
- package/dist/date-picker-selector.cjs +1 -1
- package/dist/date-picker-selector.js +29 -30
- package/dist/dialog.cjs +1 -1
- package/dist/dialog.js +1 -1
- package/dist/select.cjs +2 -2
- package/dist/select.js +2 -2
- package/dist/{sheet-DVT_djHX.cjs → sheet-CvcCaGSl.cjs} +11 -11
- package/dist/{sheet-CPf9Guon.js → sheet-IRIc3TJ1.js} +33 -19
- package/dist/sheet.cjs +1 -1
- package/dist/sheet.js +7 -6
- package/dist/sidebar.cjs +1 -1
- package/dist/sidebar.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/tabs-underline.cjs +3 -3
- package/dist/tabs-underline.js +13 -13
- package/dist/tabs.cjs +5 -4
- package/dist/tabs.js +3 -2
- package/dist/themes.css +1 -1
- package/docs/AI-GUIDE.md +321 -321
- package/docs/components/layout/sidebar.md +399 -399
- package/docs/components/layout/toaster.md +436 -436
- package/docs/components/ui/accordion-rounded.md +584 -584
- package/docs/components/ui/accordion.md +269 -269
- package/docs/components/ui/badge.md +2 -1
- package/docs/components/ui/button-group.md +984 -984
- package/docs/components/ui/button.md +1137 -1137
- package/docs/components/ui/calendar.md +1159 -1159
- package/docs/components/ui/card.md +1455 -1455
- package/docs/components/ui/checkbox.md +292 -292
- package/docs/components/ui/collapsible.md +323 -323
- package/docs/components/ui/command.md +454 -454
- package/docs/components/ui/context-menu.md +540 -540
- package/docs/components/ui/date-picker-selector.md +0 -2
- package/docs/components/ui/dialog.md +628 -628
- package/docs/components/ui/dropdown-menu.md +709 -709
- package/docs/components/ui/field.md +706 -706
- package/docs/components/ui/hover-card.md +446 -446
- package/docs/components/ui/input.md +362 -362
- package/docs/components/ui/kbd.md +434 -434
- package/docs/components/ui/label.md +359 -359
- package/docs/components/ui/pagination.md +650 -650
- package/docs/components/ui/popover.md +536 -536
- package/docs/components/ui/progress.md +182 -182
- package/docs/components/ui/radio-group.md +311 -311
- package/docs/components/ui/select.md +352 -352
- package/docs/components/ui/separator.md +214 -214
- package/docs/components/ui/sheet.md +174 -142
- package/docs/components/ui/skeleton.md +140 -140
- package/docs/components/ui/slider.md +341 -341
- package/docs/components/ui/spinner.md +170 -170
- package/docs/components/ui/switch.md +408 -408
- package/docs/components/ui/tabs-underline.md +106 -106
- package/docs/components/ui/tabs.md +122 -122
- package/docs/components/ui/textarea.md +243 -243
- package/docs/components/ui/toggle.md +237 -237
- package/docs/components/ui/tooltip.md +317 -317
- package/docs/components/ui/typography.md +280 -280
- package/package.json +1 -1
|
@@ -1,454 +1,454 @@
|
|
|
1
|
-
# Command
|
|
2
|
-
|
|
3
|
-
Paleta de comandos estilo Cmd+K basada en `cmdk` con búsqueda fuzzy, navegación por teclado, grupos, separadores, y shortcuts. Útil para command palettes, búsqueda rápida, y navegación.
|
|
4
|
-
|
|
5
|
-
## Importación
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import {
|
|
9
|
-
Command,
|
|
10
|
-
CommandInput,
|
|
11
|
-
CommandList,
|
|
12
|
-
CommandEmpty,
|
|
13
|
-
CommandGroup,
|
|
14
|
-
CommandItem,
|
|
15
|
-
CommandSeparator,
|
|
16
|
-
CommandShortcut,
|
|
17
|
-
CommandDialog,
|
|
18
|
-
} from "@adamosuiteservices/ui/command";
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Anatomía
|
|
22
|
-
|
|
23
|
-
```tsx
|
|
24
|
-
<Command>
|
|
25
|
-
<CommandInput placeholder="Search..." />
|
|
26
|
-
<CommandList>
|
|
27
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
28
|
-
<CommandGroup heading="Actions">
|
|
29
|
-
<CommandItem>
|
|
30
|
-
New File
|
|
31
|
-
<CommandShortcut>⌘N</CommandShortcut>
|
|
32
|
-
</CommandItem>
|
|
33
|
-
<CommandItem>Open</CommandItem>
|
|
34
|
-
</CommandGroup>
|
|
35
|
-
<CommandSeparator />
|
|
36
|
-
<CommandGroup heading="Settings">
|
|
37
|
-
<CommandItem>Preferences</CommandItem>
|
|
38
|
-
</CommandGroup>
|
|
39
|
-
</CommandList>
|
|
40
|
-
</Command>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Componentes**: 8 (Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut)
|
|
44
|
-
|
|
45
|
-
## Props Principales
|
|
46
|
-
|
|
47
|
-
### Command (Root)
|
|
48
|
-
|
|
49
|
-
| Prop | Tipo | Default | Descripción |
|
|
50
|
-
| --------------- | ------------------------------------------- | ----------- | -------------------------------------- |
|
|
51
|
-
| `value` | `string` | - | Valor controlado del item seleccionado |
|
|
52
|
-
| `onValueChange` | `(value: string) => void` | - | Callback cuando cambia selección |
|
|
53
|
-
| `filter` | `(value: string, search: string) => number` | Fuzzy match | Función de filtrado custom |
|
|
54
|
-
| `shouldFilter` | `boolean` | `true` | Habilita filtrado automático |
|
|
55
|
-
| `loop` | `boolean` | `false` | Navegación circular con arrow keys |
|
|
56
|
-
| `className` | `string` | - | Clases CSS adicionales |
|
|
57
|
-
|
|
58
|
-
### CommandInput
|
|
59
|
-
|
|
60
|
-
| Prop | Tipo | Descripción |
|
|
61
|
-
| --------------- | -------------------------- | -------------------------- |
|
|
62
|
-
| `placeholder` | `string` | Texto placeholder |
|
|
63
|
-
| `value` | `string` | Valor controlado del input |
|
|
64
|
-
| `onValueChange` | `(search: string) => void` | Callback al escribir |
|
|
65
|
-
| `className` | `string` | Clases CSS adicionales |
|
|
66
|
-
|
|
67
|
-
### CommandList
|
|
68
|
-
|
|
69
|
-
| Prop | Tipo | Default | Descripción |
|
|
70
|
-
| ----------- | ----------- | ------- | -------------------------- |
|
|
71
|
-
| `className` | `string` | - | Clases CSS adicionales |
|
|
72
|
-
| `children` | `ReactNode` | - | Grupos, items, separadores |
|
|
73
|
-
|
|
74
|
-
**Estilos default**: `max-h-[300px]`, scroll vertical automático
|
|
75
|
-
|
|
76
|
-
### CommandItem
|
|
77
|
-
|
|
78
|
-
| Prop | Tipo | Descripción |
|
|
79
|
-
| ----------- | ------------------------- | ------------------------------------------ |
|
|
80
|
-
| `value` | `string` | Valor único del item (usado para búsqueda) |
|
|
81
|
-
| `onSelect` | `(value: string) => void` | Callback al seleccionar |
|
|
82
|
-
| `disabled` | `boolean` | Desactiva selección |
|
|
83
|
-
| `keywords` | `string[]` | Palabras clave adicionales para búsqueda |
|
|
84
|
-
| `className` | `string` | Clases CSS adicionales |
|
|
85
|
-
|
|
86
|
-
### CommandDialog
|
|
87
|
-
|
|
88
|
-
| Prop | Tipo | Default | Descripción |
|
|
89
|
-
| ----------------- | ------------------------- | ------------------- | ------------------------ |
|
|
90
|
-
| `open` | `boolean` | - | Estado del dialog |
|
|
91
|
-
| `onOpenChange` | `(open: boolean) => void` | - | Callback al abrir/cerrar |
|
|
92
|
-
| `title` | `string` | `"Command Palette"` | Título (sr-only) |
|
|
93
|
-
| `description` | `string` | `"Search for..."` | Descripción (sr-only) |
|
|
94
|
-
| `showCloseButton` | `boolean` | `true` | Muestra botón de cerrar |
|
|
95
|
-
| `className` | `string` | - | Clases CSS adicionales |
|
|
96
|
-
|
|
97
|
-
## Patrones de Uso
|
|
98
|
-
|
|
99
|
-
### Básico (Inline)
|
|
100
|
-
|
|
101
|
-
```tsx
|
|
102
|
-
<Command>
|
|
103
|
-
<CommandInput placeholder="Type to search..." />
|
|
104
|
-
<CommandList>
|
|
105
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
106
|
-
<CommandGroup heading="Suggestions">
|
|
107
|
-
<CommandItem>Calendar</CommandItem>
|
|
108
|
-
<CommandItem>Search Emoji</CommandItem>
|
|
109
|
-
<CommandItem>Calculator</CommandItem>
|
|
110
|
-
</CommandGroup>
|
|
111
|
-
</CommandList>
|
|
112
|
-
</Command>
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Command Dialog (Cmd+K)
|
|
116
|
-
|
|
117
|
-
```tsx
|
|
118
|
-
import { useEffect, useState } from "react";
|
|
119
|
-
|
|
120
|
-
function CommandMenu() {
|
|
121
|
-
const [open, setOpen] = useState(false);
|
|
122
|
-
|
|
123
|
-
useEffect(() => {
|
|
124
|
-
const down = (e: KeyboardEvent) => {
|
|
125
|
-
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
126
|
-
e.preventDefault();
|
|
127
|
-
setOpen((open) => !open);
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
document.addEventListener("keydown", down);
|
|
132
|
-
return () => document.removeEventListener("keydown", down);
|
|
133
|
-
}, []);
|
|
134
|
-
|
|
135
|
-
return (
|
|
136
|
-
<CommandDialog open={open} onOpenChange={setOpen}>
|
|
137
|
-
<CommandInput placeholder="Type a command or search..." />
|
|
138
|
-
<CommandList>
|
|
139
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
140
|
-
<CommandGroup heading="Actions">
|
|
141
|
-
<CommandItem>
|
|
142
|
-
New File
|
|
143
|
-
<CommandShortcut>⌘N</CommandShortcut>
|
|
144
|
-
</CommandItem>
|
|
145
|
-
<CommandItem>
|
|
146
|
-
Open File
|
|
147
|
-
<CommandShortcut>⌘O</CommandShortcut>
|
|
148
|
-
</CommandItem>
|
|
149
|
-
</CommandGroup>
|
|
150
|
-
</CommandList>
|
|
151
|
-
</CommandDialog>
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Con Iconos
|
|
157
|
-
|
|
158
|
-
```tsx
|
|
159
|
-
import { Icon } from "@adamosuiteservices/ui/icon";
|
|
160
|
-
|
|
161
|
-
<Command>
|
|
162
|
-
<CommandInput placeholder="Search..." />
|
|
163
|
-
<CommandList>
|
|
164
|
-
<CommandGroup heading="Suggestions">
|
|
165
|
-
<CommandItem>
|
|
166
|
-
<Icon symbol="calendar_month" />
|
|
167
|
-
Calendar
|
|
168
|
-
</CommandItem>
|
|
169
|
-
<CommandItem>
|
|
170
|
-
<Icon symbol="sentiment_satisfied" />
|
|
171
|
-
Search Emoji
|
|
172
|
-
</CommandItem>
|
|
173
|
-
<CommandItem>
|
|
174
|
-
<Icon symbol="rocket_launch" />
|
|
175
|
-
Launch
|
|
176
|
-
</CommandItem>
|
|
177
|
-
</CommandGroup>
|
|
178
|
-
</CommandList>
|
|
179
|
-
</Command>;
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
**Nota**: SVGs tienen `size-4` automático y `text-muted-foreground` si no tienen clase `text-*`.
|
|
183
|
-
|
|
184
|
-
### Múltiples Grupos con Separadores
|
|
185
|
-
|
|
186
|
-
```tsx
|
|
187
|
-
<Command>
|
|
188
|
-
<CommandInput placeholder="Search..." />
|
|
189
|
-
<CommandList>
|
|
190
|
-
<CommandGroup heading="Files">
|
|
191
|
-
<CommandItem>New File</CommandItem>
|
|
192
|
-
<CommandItem>New Folder</CommandItem>
|
|
193
|
-
</CommandGroup>
|
|
194
|
-
|
|
195
|
-
<CommandSeparator />
|
|
196
|
-
|
|
197
|
-
<CommandGroup heading="Edit">
|
|
198
|
-
<CommandItem>Copy</CommandItem>
|
|
199
|
-
<CommandItem>Paste</CommandItem>
|
|
200
|
-
</CommandGroup>
|
|
201
|
-
|
|
202
|
-
<CommandSeparator />
|
|
203
|
-
|
|
204
|
-
<CommandGroup heading="View">
|
|
205
|
-
<CommandItem>Toggle Sidebar</CommandItem>
|
|
206
|
-
<CommandItem>Full Screen</CommandItem>
|
|
207
|
-
</CommandGroup>
|
|
208
|
-
</CommandList>
|
|
209
|
-
</Command>
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### Con Callbacks (Ejecutar Acciones)
|
|
213
|
-
|
|
214
|
-
```tsx
|
|
215
|
-
function App() {
|
|
216
|
-
const runCommand = (command: string) => {
|
|
217
|
-
console.log(`Running: ${command}`);
|
|
218
|
-
// Ejecutar acción
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
return (
|
|
222
|
-
<Command>
|
|
223
|
-
<CommandInput placeholder="Search..." />
|
|
224
|
-
<CommandList>
|
|
225
|
-
<CommandGroup heading="Actions">
|
|
226
|
-
<CommandItem onSelect={() => runCommand("new-file")}>
|
|
227
|
-
New File
|
|
228
|
-
</CommandItem>
|
|
229
|
-
<CommandItem onSelect={() => runCommand("open-file")}>
|
|
230
|
-
Open File
|
|
231
|
-
</CommandItem>
|
|
232
|
-
<CommandItem onSelect={() => runCommand("save")}>Save</CommandItem>
|
|
233
|
-
</CommandGroup>
|
|
234
|
-
</CommandList>
|
|
235
|
-
</Command>
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Items Deshabilitados
|
|
241
|
-
|
|
242
|
-
```tsx
|
|
243
|
-
<Command>
|
|
244
|
-
<CommandList>
|
|
245
|
-
<CommandGroup>
|
|
246
|
-
<CommandItem>Available Option</CommandItem>
|
|
247
|
-
<CommandItem disabled>Coming Soon</CommandItem>
|
|
248
|
-
<CommandItem disabled>Premium Feature</CommandItem>
|
|
249
|
-
</CommandGroup>
|
|
250
|
-
</CommandList>
|
|
251
|
-
</Command>
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
**Estilos**: `opacity-50`, `pointer-events-none`, `data-[disabled=true]`
|
|
255
|
-
|
|
256
|
-
### Con Keywords para Búsqueda
|
|
257
|
-
|
|
258
|
-
```tsx
|
|
259
|
-
<Command>
|
|
260
|
-
<CommandInput placeholder="Search settings..." />
|
|
261
|
-
<CommandList>
|
|
262
|
-
<CommandGroup heading="Settings">
|
|
263
|
-
<CommandItem
|
|
264
|
-
value="theme"
|
|
265
|
-
keywords={["appearance", "dark", "light", "color"]}
|
|
266
|
-
>
|
|
267
|
-
Theme Settings
|
|
268
|
-
</CommandItem>
|
|
269
|
-
<CommandItem
|
|
270
|
-
value="shortcuts"
|
|
271
|
-
keywords={["keyboard", "hotkeys", "bindings"]}
|
|
272
|
-
>
|
|
273
|
-
Keyboard Shortcuts
|
|
274
|
-
</CommandItem>
|
|
275
|
-
</CommandGroup>
|
|
276
|
-
</CommandList>
|
|
277
|
-
</Command>
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
**Búsqueda**: Encuentra items por `value`, `children` text, o `keywords[]`
|
|
281
|
-
|
|
282
|
-
### Navegación de Páginas
|
|
283
|
-
|
|
284
|
-
```tsx
|
|
285
|
-
function PageSearch() {
|
|
286
|
-
const navigate = useNavigate();
|
|
287
|
-
const [open, setOpen] = useState(false);
|
|
288
|
-
|
|
289
|
-
return (
|
|
290
|
-
<CommandDialog open={open} onOpenChange={setOpen}>
|
|
291
|
-
<CommandInput placeholder="Search pages..." />
|
|
292
|
-
<CommandList>
|
|
293
|
-
<CommandGroup heading="Pages">
|
|
294
|
-
<CommandItem
|
|
295
|
-
onSelect={() => {
|
|
296
|
-
navigate("/dashboard");
|
|
297
|
-
setOpen(false);
|
|
298
|
-
}}
|
|
299
|
-
>
|
|
300
|
-
Dashboard
|
|
301
|
-
</CommandItem>
|
|
302
|
-
<CommandItem
|
|
303
|
-
onSelect={() => {
|
|
304
|
-
navigate("/settings");
|
|
305
|
-
setOpen(false);
|
|
306
|
-
}}
|
|
307
|
-
>
|
|
308
|
-
Settings
|
|
309
|
-
</CommandItem>
|
|
310
|
-
<CommandItem
|
|
311
|
-
onSelect={() => {
|
|
312
|
-
navigate("/profile");
|
|
313
|
-
setOpen(false);
|
|
314
|
-
}}
|
|
315
|
-
>
|
|
316
|
-
Profile
|
|
317
|
-
</CommandItem>
|
|
318
|
-
</CommandGroup>
|
|
319
|
-
</CommandList>
|
|
320
|
-
</CommandDialog>
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### Filtrado Custom
|
|
326
|
-
|
|
327
|
-
```tsx
|
|
328
|
-
// Exacto match en lugar de fuzzy
|
|
329
|
-
const exactMatch = (value: string, search: string) => {
|
|
330
|
-
return value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0;
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
<Command filter={exactMatch}>
|
|
334
|
-
<CommandInput placeholder="Search..." />
|
|
335
|
-
<CommandList>
|
|
336
|
-
<CommandGroup>
|
|
337
|
-
<CommandItem>Apple</CommandItem>
|
|
338
|
-
<CommandItem>Banana</CommandItem>
|
|
339
|
-
<CommandItem>Cherry</CommandItem>
|
|
340
|
-
</CommandGroup>
|
|
341
|
-
</CommandList>
|
|
342
|
-
</Command>;
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
### Sin Filtrado Automático
|
|
346
|
-
|
|
347
|
-
```tsx
|
|
348
|
-
// Control manual del filtrado
|
|
349
|
-
function CustomFilter() {
|
|
350
|
-
const [search, setSearch] = useState("");
|
|
351
|
-
const [filteredItems, setFilteredItems] = useState(allItems);
|
|
352
|
-
|
|
353
|
-
useEffect(() => {
|
|
354
|
-
setFilteredItems(
|
|
355
|
-
allItems.filter((item) =>
|
|
356
|
-
item.toLowerCase().includes(search.toLowerCase())
|
|
357
|
-
)
|
|
358
|
-
);
|
|
359
|
-
}, [search]);
|
|
360
|
-
|
|
361
|
-
return (
|
|
362
|
-
<Command shouldFilter={false}>
|
|
363
|
-
<CommandInput
|
|
364
|
-
value={search}
|
|
365
|
-
onValueChange={setSearch}
|
|
366
|
-
placeholder="Search..."
|
|
367
|
-
/>
|
|
368
|
-
<CommandList>
|
|
369
|
-
<CommandGroup>
|
|
370
|
-
{filteredItems.map((item) => (
|
|
371
|
-
<CommandItem key={item}>{item}</CommandItem>
|
|
372
|
-
))}
|
|
373
|
-
</CommandGroup>
|
|
374
|
-
</CommandList>
|
|
375
|
-
</Command>
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
## Casos de Uso Comunes
|
|
381
|
-
|
|
382
|
-
**Command palette (Cmd+K)**: Búsqueda rápida de acciones/comandos
|
|
383
|
-
**Page navigation**: Navegación rápida entre páginas
|
|
384
|
-
**File picker**: Búsqueda de archivos en proyecto
|
|
385
|
-
**Settings search**: Encontrar configuraciones
|
|
386
|
-
**Action menu**: Menú de acciones contextuales
|
|
387
|
-
**Spotlight search**: Búsqueda global tipo macOS
|
|
388
|
-
|
|
389
|
-
## Estados y Data Attributes
|
|
390
|
-
|
|
391
|
-
### CommandItem States
|
|
392
|
-
|
|
393
|
-
- **Selected**: `data-[selected=true]` → `bg-accent`, `text-accent-foreground`
|
|
394
|
-
- **Disabled**: `data-[disabled=true]` → `opacity-50`, `pointer-events-none`
|
|
395
|
-
|
|
396
|
-
### Empty State
|
|
397
|
-
|
|
398
|
-
- Automático cuando búsqueda no encuentra resultados
|
|
399
|
-
- Personalizable con `<CommandEmpty>`
|
|
400
|
-
|
|
401
|
-
## Navegación por Teclado
|
|
402
|
-
|
|
403
|
-
- ✅ **Arrow Up/Down**: Navega entre items
|
|
404
|
-
- ✅ **Enter**: Selecciona item enfocado
|
|
405
|
-
- ✅ **Escape**: Cierra dialog (si CommandDialog)
|
|
406
|
-
- ✅ **Type to search**: Filtrado automático
|
|
407
|
-
- ✅ **Tab**: Sale del Command (no navega items)
|
|
408
|
-
- ✅ **Home/End**: Primer/último item (si `loop={true}`)
|
|
409
|
-
|
|
410
|
-
## Accesibilidad
|
|
411
|
-
|
|
412
|
-
- ✅ **ARIA**: `role="combobox"` en Command, `role="option"` en items
|
|
413
|
-
- ✅ **Screen readers**: Anuncia items y cuenta de resultados
|
|
414
|
-
- ✅ **Keyboard navigation**: Navegación completa por teclado
|
|
415
|
-
- ✅ **Focus management**: Focus visible en items seleccionados
|
|
416
|
-
- ✅ **Live regions**: Anuncia cuando cambian resultados
|
|
417
|
-
- ✅ **Disabled items**: `aria-disabled` en items deshabilitados
|
|
418
|
-
|
|
419
|
-
## Notas de Implementación
|
|
420
|
-
|
|
421
|
-
- **Basado en cmdk**: Librería `cmdk` de Paco Coursey
|
|
422
|
-
- **Fuzzy search**: Búsqueda difusa por defecto (typo-tolerant)
|
|
423
|
-
- **Performance**: Virtualización automática con muchos items
|
|
424
|
-
- **Search icon**: Incluido automáticamente en CommandInput (Material Symbol "search")
|
|
425
|
-
- **CommandDialog**: Wrapper de Command + Dialog con estilos predefinidos
|
|
426
|
-
- **Data slots**: Cada componente tiene `data-slot` para CSS targeting
|
|
427
|
-
- **Icon sizing**: Material Symbol icons automáticamente `text-lg` (18px) con shrink-0 y opacity-50
|
|
428
|
-
- **CommandShortcut**: Elemento visual para shortcuts (no ejecuta código)
|
|
429
|
-
- **Max height**: CommandList tiene `max-h-[300px]` default
|
|
430
|
-
- **Scroll behavior**: `scroll-py-1` para padding al scrollear
|
|
431
|
-
|
|
432
|
-
## Estilos Especiales en CommandDialog
|
|
433
|
-
|
|
434
|
-
Cuando se usa en Dialog, aplica estilos adicionales:
|
|
435
|
-
|
|
436
|
-
- Items con `py-3` (más padding)
|
|
437
|
-
- Input con `h-12`
|
|
438
|
-
- SVGs con `h-5 w-5` (más grandes)
|
|
439
|
-
- Groups con heading más prominente
|
|
440
|
-
|
|
441
|
-
## Troubleshooting
|
|
442
|
-
|
|
443
|
-
**Búsqueda no funciona**: Verifica que `shouldFilter={true}` (default) o implementa filtrado manual
|
|
444
|
-
**Items no se ven**: Asegúrate de envolver en `<CommandList>` y `<CommandGroup>`
|
|
445
|
-
**Cmd+K no abre dialog**: Verifica que el `useEffect` esté ejecutándose y no haya conflictos con otros shortcuts
|
|
446
|
-
**Empty no aparece**: Solo se muestra cuando no hay resultados después de búsqueda
|
|
447
|
-
**Shortcuts no ejecutan**: `CommandShortcut` es solo visual, implementa lógica aparte
|
|
448
|
-
**Dialog no cierra**: Asegúrate de llamar `setOpen(false)` en `onSelect` de items
|
|
449
|
-
**Navegación circular no funciona**: Activa `loop={true}` en Command root
|
|
450
|
-
|
|
451
|
-
## Referencias
|
|
452
|
-
|
|
453
|
-
- **cmdk**: https://cmdk.paco.me
|
|
454
|
-
- **ARIA Combobox**: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/
|
|
1
|
+
# Command
|
|
2
|
+
|
|
3
|
+
Paleta de comandos estilo Cmd+K basada en `cmdk` con búsqueda fuzzy, navegación por teclado, grupos, separadores, y shortcuts. Útil para command palettes, búsqueda rápida, y navegación.
|
|
4
|
+
|
|
5
|
+
## Importación
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import {
|
|
9
|
+
Command,
|
|
10
|
+
CommandInput,
|
|
11
|
+
CommandList,
|
|
12
|
+
CommandEmpty,
|
|
13
|
+
CommandGroup,
|
|
14
|
+
CommandItem,
|
|
15
|
+
CommandSeparator,
|
|
16
|
+
CommandShortcut,
|
|
17
|
+
CommandDialog,
|
|
18
|
+
} from "@adamosuiteservices/ui/command";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Anatomía
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
<Command>
|
|
25
|
+
<CommandInput placeholder="Search..." />
|
|
26
|
+
<CommandList>
|
|
27
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
28
|
+
<CommandGroup heading="Actions">
|
|
29
|
+
<CommandItem>
|
|
30
|
+
New File
|
|
31
|
+
<CommandShortcut>⌘N</CommandShortcut>
|
|
32
|
+
</CommandItem>
|
|
33
|
+
<CommandItem>Open</CommandItem>
|
|
34
|
+
</CommandGroup>
|
|
35
|
+
<CommandSeparator />
|
|
36
|
+
<CommandGroup heading="Settings">
|
|
37
|
+
<CommandItem>Preferences</CommandItem>
|
|
38
|
+
</CommandGroup>
|
|
39
|
+
</CommandList>
|
|
40
|
+
</Command>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Componentes**: 8 (Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut)
|
|
44
|
+
|
|
45
|
+
## Props Principales
|
|
46
|
+
|
|
47
|
+
### Command (Root)
|
|
48
|
+
|
|
49
|
+
| Prop | Tipo | Default | Descripción |
|
|
50
|
+
| --------------- | ------------------------------------------- | ----------- | -------------------------------------- |
|
|
51
|
+
| `value` | `string` | - | Valor controlado del item seleccionado |
|
|
52
|
+
| `onValueChange` | `(value: string) => void` | - | Callback cuando cambia selección |
|
|
53
|
+
| `filter` | `(value: string, search: string) => number` | Fuzzy match | Función de filtrado custom |
|
|
54
|
+
| `shouldFilter` | `boolean` | `true` | Habilita filtrado automático |
|
|
55
|
+
| `loop` | `boolean` | `false` | Navegación circular con arrow keys |
|
|
56
|
+
| `className` | `string` | - | Clases CSS adicionales |
|
|
57
|
+
|
|
58
|
+
### CommandInput
|
|
59
|
+
|
|
60
|
+
| Prop | Tipo | Descripción |
|
|
61
|
+
| --------------- | -------------------------- | -------------------------- |
|
|
62
|
+
| `placeholder` | `string` | Texto placeholder |
|
|
63
|
+
| `value` | `string` | Valor controlado del input |
|
|
64
|
+
| `onValueChange` | `(search: string) => void` | Callback al escribir |
|
|
65
|
+
| `className` | `string` | Clases CSS adicionales |
|
|
66
|
+
|
|
67
|
+
### CommandList
|
|
68
|
+
|
|
69
|
+
| Prop | Tipo | Default | Descripción |
|
|
70
|
+
| ----------- | ----------- | ------- | -------------------------- |
|
|
71
|
+
| `className` | `string` | - | Clases CSS adicionales |
|
|
72
|
+
| `children` | `ReactNode` | - | Grupos, items, separadores |
|
|
73
|
+
|
|
74
|
+
**Estilos default**: `max-h-[300px]`, scroll vertical automático
|
|
75
|
+
|
|
76
|
+
### CommandItem
|
|
77
|
+
|
|
78
|
+
| Prop | Tipo | Descripción |
|
|
79
|
+
| ----------- | ------------------------- | ------------------------------------------ |
|
|
80
|
+
| `value` | `string` | Valor único del item (usado para búsqueda) |
|
|
81
|
+
| `onSelect` | `(value: string) => void` | Callback al seleccionar |
|
|
82
|
+
| `disabled` | `boolean` | Desactiva selección |
|
|
83
|
+
| `keywords` | `string[]` | Palabras clave adicionales para búsqueda |
|
|
84
|
+
| `className` | `string` | Clases CSS adicionales |
|
|
85
|
+
|
|
86
|
+
### CommandDialog
|
|
87
|
+
|
|
88
|
+
| Prop | Tipo | Default | Descripción |
|
|
89
|
+
| ----------------- | ------------------------- | ------------------- | ------------------------ |
|
|
90
|
+
| `open` | `boolean` | - | Estado del dialog |
|
|
91
|
+
| `onOpenChange` | `(open: boolean) => void` | - | Callback al abrir/cerrar |
|
|
92
|
+
| `title` | `string` | `"Command Palette"` | Título (sr-only) |
|
|
93
|
+
| `description` | `string` | `"Search for..."` | Descripción (sr-only) |
|
|
94
|
+
| `showCloseButton` | `boolean` | `true` | Muestra botón de cerrar |
|
|
95
|
+
| `className` | `string` | - | Clases CSS adicionales |
|
|
96
|
+
|
|
97
|
+
## Patrones de Uso
|
|
98
|
+
|
|
99
|
+
### Básico (Inline)
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
<Command>
|
|
103
|
+
<CommandInput placeholder="Type to search..." />
|
|
104
|
+
<CommandList>
|
|
105
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
106
|
+
<CommandGroup heading="Suggestions">
|
|
107
|
+
<CommandItem>Calendar</CommandItem>
|
|
108
|
+
<CommandItem>Search Emoji</CommandItem>
|
|
109
|
+
<CommandItem>Calculator</CommandItem>
|
|
110
|
+
</CommandGroup>
|
|
111
|
+
</CommandList>
|
|
112
|
+
</Command>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Command Dialog (Cmd+K)
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import { useEffect, useState } from "react";
|
|
119
|
+
|
|
120
|
+
function CommandMenu() {
|
|
121
|
+
const [open, setOpen] = useState(false);
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
const down = (e: KeyboardEvent) => {
|
|
125
|
+
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
setOpen((open) => !open);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
document.addEventListener("keydown", down);
|
|
132
|
+
return () => document.removeEventListener("keydown", down);
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<CommandDialog open={open} onOpenChange={setOpen}>
|
|
137
|
+
<CommandInput placeholder="Type a command or search..." />
|
|
138
|
+
<CommandList>
|
|
139
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
140
|
+
<CommandGroup heading="Actions">
|
|
141
|
+
<CommandItem>
|
|
142
|
+
New File
|
|
143
|
+
<CommandShortcut>⌘N</CommandShortcut>
|
|
144
|
+
</CommandItem>
|
|
145
|
+
<CommandItem>
|
|
146
|
+
Open File
|
|
147
|
+
<CommandShortcut>⌘O</CommandShortcut>
|
|
148
|
+
</CommandItem>
|
|
149
|
+
</CommandGroup>
|
|
150
|
+
</CommandList>
|
|
151
|
+
</CommandDialog>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Con Iconos
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
import { Icon } from "@adamosuiteservices/ui/icon";
|
|
160
|
+
|
|
161
|
+
<Command>
|
|
162
|
+
<CommandInput placeholder="Search..." />
|
|
163
|
+
<CommandList>
|
|
164
|
+
<CommandGroup heading="Suggestions">
|
|
165
|
+
<CommandItem>
|
|
166
|
+
<Icon symbol="calendar_month" />
|
|
167
|
+
Calendar
|
|
168
|
+
</CommandItem>
|
|
169
|
+
<CommandItem>
|
|
170
|
+
<Icon symbol="sentiment_satisfied" />
|
|
171
|
+
Search Emoji
|
|
172
|
+
</CommandItem>
|
|
173
|
+
<CommandItem>
|
|
174
|
+
<Icon symbol="rocket_launch" />
|
|
175
|
+
Launch
|
|
176
|
+
</CommandItem>
|
|
177
|
+
</CommandGroup>
|
|
178
|
+
</CommandList>
|
|
179
|
+
</Command>;
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Nota**: SVGs tienen `size-4` automático y `text-muted-foreground` si no tienen clase `text-*`.
|
|
183
|
+
|
|
184
|
+
### Múltiples Grupos con Separadores
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
<Command>
|
|
188
|
+
<CommandInput placeholder="Search..." />
|
|
189
|
+
<CommandList>
|
|
190
|
+
<CommandGroup heading="Files">
|
|
191
|
+
<CommandItem>New File</CommandItem>
|
|
192
|
+
<CommandItem>New Folder</CommandItem>
|
|
193
|
+
</CommandGroup>
|
|
194
|
+
|
|
195
|
+
<CommandSeparator />
|
|
196
|
+
|
|
197
|
+
<CommandGroup heading="Edit">
|
|
198
|
+
<CommandItem>Copy</CommandItem>
|
|
199
|
+
<CommandItem>Paste</CommandItem>
|
|
200
|
+
</CommandGroup>
|
|
201
|
+
|
|
202
|
+
<CommandSeparator />
|
|
203
|
+
|
|
204
|
+
<CommandGroup heading="View">
|
|
205
|
+
<CommandItem>Toggle Sidebar</CommandItem>
|
|
206
|
+
<CommandItem>Full Screen</CommandItem>
|
|
207
|
+
</CommandGroup>
|
|
208
|
+
</CommandList>
|
|
209
|
+
</Command>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Con Callbacks (Ejecutar Acciones)
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
function App() {
|
|
216
|
+
const runCommand = (command: string) => {
|
|
217
|
+
console.log(`Running: ${command}`);
|
|
218
|
+
// Ejecutar acción
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<Command>
|
|
223
|
+
<CommandInput placeholder="Search..." />
|
|
224
|
+
<CommandList>
|
|
225
|
+
<CommandGroup heading="Actions">
|
|
226
|
+
<CommandItem onSelect={() => runCommand("new-file")}>
|
|
227
|
+
New File
|
|
228
|
+
</CommandItem>
|
|
229
|
+
<CommandItem onSelect={() => runCommand("open-file")}>
|
|
230
|
+
Open File
|
|
231
|
+
</CommandItem>
|
|
232
|
+
<CommandItem onSelect={() => runCommand("save")}>Save</CommandItem>
|
|
233
|
+
</CommandGroup>
|
|
234
|
+
</CommandList>
|
|
235
|
+
</Command>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Items Deshabilitados
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
<Command>
|
|
244
|
+
<CommandList>
|
|
245
|
+
<CommandGroup>
|
|
246
|
+
<CommandItem>Available Option</CommandItem>
|
|
247
|
+
<CommandItem disabled>Coming Soon</CommandItem>
|
|
248
|
+
<CommandItem disabled>Premium Feature</CommandItem>
|
|
249
|
+
</CommandGroup>
|
|
250
|
+
</CommandList>
|
|
251
|
+
</Command>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Estilos**: `opacity-50`, `pointer-events-none`, `data-[disabled=true]`
|
|
255
|
+
|
|
256
|
+
### Con Keywords para Búsqueda
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
<Command>
|
|
260
|
+
<CommandInput placeholder="Search settings..." />
|
|
261
|
+
<CommandList>
|
|
262
|
+
<CommandGroup heading="Settings">
|
|
263
|
+
<CommandItem
|
|
264
|
+
value="theme"
|
|
265
|
+
keywords={["appearance", "dark", "light", "color"]}
|
|
266
|
+
>
|
|
267
|
+
Theme Settings
|
|
268
|
+
</CommandItem>
|
|
269
|
+
<CommandItem
|
|
270
|
+
value="shortcuts"
|
|
271
|
+
keywords={["keyboard", "hotkeys", "bindings"]}
|
|
272
|
+
>
|
|
273
|
+
Keyboard Shortcuts
|
|
274
|
+
</CommandItem>
|
|
275
|
+
</CommandGroup>
|
|
276
|
+
</CommandList>
|
|
277
|
+
</Command>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Búsqueda**: Encuentra items por `value`, `children` text, o `keywords[]`
|
|
281
|
+
|
|
282
|
+
### Navegación de Páginas
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
function PageSearch() {
|
|
286
|
+
const navigate = useNavigate();
|
|
287
|
+
const [open, setOpen] = useState(false);
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<CommandDialog open={open} onOpenChange={setOpen}>
|
|
291
|
+
<CommandInput placeholder="Search pages..." />
|
|
292
|
+
<CommandList>
|
|
293
|
+
<CommandGroup heading="Pages">
|
|
294
|
+
<CommandItem
|
|
295
|
+
onSelect={() => {
|
|
296
|
+
navigate("/dashboard");
|
|
297
|
+
setOpen(false);
|
|
298
|
+
}}
|
|
299
|
+
>
|
|
300
|
+
Dashboard
|
|
301
|
+
</CommandItem>
|
|
302
|
+
<CommandItem
|
|
303
|
+
onSelect={() => {
|
|
304
|
+
navigate("/settings");
|
|
305
|
+
setOpen(false);
|
|
306
|
+
}}
|
|
307
|
+
>
|
|
308
|
+
Settings
|
|
309
|
+
</CommandItem>
|
|
310
|
+
<CommandItem
|
|
311
|
+
onSelect={() => {
|
|
312
|
+
navigate("/profile");
|
|
313
|
+
setOpen(false);
|
|
314
|
+
}}
|
|
315
|
+
>
|
|
316
|
+
Profile
|
|
317
|
+
</CommandItem>
|
|
318
|
+
</CommandGroup>
|
|
319
|
+
</CommandList>
|
|
320
|
+
</CommandDialog>
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Filtrado Custom
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
// Exacto match en lugar de fuzzy
|
|
329
|
+
const exactMatch = (value: string, search: string) => {
|
|
330
|
+
return value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0;
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
<Command filter={exactMatch}>
|
|
334
|
+
<CommandInput placeholder="Search..." />
|
|
335
|
+
<CommandList>
|
|
336
|
+
<CommandGroup>
|
|
337
|
+
<CommandItem>Apple</CommandItem>
|
|
338
|
+
<CommandItem>Banana</CommandItem>
|
|
339
|
+
<CommandItem>Cherry</CommandItem>
|
|
340
|
+
</CommandGroup>
|
|
341
|
+
</CommandList>
|
|
342
|
+
</Command>;
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Sin Filtrado Automático
|
|
346
|
+
|
|
347
|
+
```tsx
|
|
348
|
+
// Control manual del filtrado
|
|
349
|
+
function CustomFilter() {
|
|
350
|
+
const [search, setSearch] = useState("");
|
|
351
|
+
const [filteredItems, setFilteredItems] = useState(allItems);
|
|
352
|
+
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
setFilteredItems(
|
|
355
|
+
allItems.filter((item) =>
|
|
356
|
+
item.toLowerCase().includes(search.toLowerCase())
|
|
357
|
+
)
|
|
358
|
+
);
|
|
359
|
+
}, [search]);
|
|
360
|
+
|
|
361
|
+
return (
|
|
362
|
+
<Command shouldFilter={false}>
|
|
363
|
+
<CommandInput
|
|
364
|
+
value={search}
|
|
365
|
+
onValueChange={setSearch}
|
|
366
|
+
placeholder="Search..."
|
|
367
|
+
/>
|
|
368
|
+
<CommandList>
|
|
369
|
+
<CommandGroup>
|
|
370
|
+
{filteredItems.map((item) => (
|
|
371
|
+
<CommandItem key={item}>{item}</CommandItem>
|
|
372
|
+
))}
|
|
373
|
+
</CommandGroup>
|
|
374
|
+
</CommandList>
|
|
375
|
+
</Command>
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Casos de Uso Comunes
|
|
381
|
+
|
|
382
|
+
**Command palette (Cmd+K)**: Búsqueda rápida de acciones/comandos
|
|
383
|
+
**Page navigation**: Navegación rápida entre páginas
|
|
384
|
+
**File picker**: Búsqueda de archivos en proyecto
|
|
385
|
+
**Settings search**: Encontrar configuraciones
|
|
386
|
+
**Action menu**: Menú de acciones contextuales
|
|
387
|
+
**Spotlight search**: Búsqueda global tipo macOS
|
|
388
|
+
|
|
389
|
+
## Estados y Data Attributes
|
|
390
|
+
|
|
391
|
+
### CommandItem States
|
|
392
|
+
|
|
393
|
+
- **Selected**: `data-[selected=true]` → `bg-accent`, `text-accent-foreground`
|
|
394
|
+
- **Disabled**: `data-[disabled=true]` → `opacity-50`, `pointer-events-none`
|
|
395
|
+
|
|
396
|
+
### Empty State
|
|
397
|
+
|
|
398
|
+
- Automático cuando búsqueda no encuentra resultados
|
|
399
|
+
- Personalizable con `<CommandEmpty>`
|
|
400
|
+
|
|
401
|
+
## Navegación por Teclado
|
|
402
|
+
|
|
403
|
+
- ✅ **Arrow Up/Down**: Navega entre items
|
|
404
|
+
- ✅ **Enter**: Selecciona item enfocado
|
|
405
|
+
- ✅ **Escape**: Cierra dialog (si CommandDialog)
|
|
406
|
+
- ✅ **Type to search**: Filtrado automático
|
|
407
|
+
- ✅ **Tab**: Sale del Command (no navega items)
|
|
408
|
+
- ✅ **Home/End**: Primer/último item (si `loop={true}`)
|
|
409
|
+
|
|
410
|
+
## Accesibilidad
|
|
411
|
+
|
|
412
|
+
- ✅ **ARIA**: `role="combobox"` en Command, `role="option"` en items
|
|
413
|
+
- ✅ **Screen readers**: Anuncia items y cuenta de resultados
|
|
414
|
+
- ✅ **Keyboard navigation**: Navegación completa por teclado
|
|
415
|
+
- ✅ **Focus management**: Focus visible en items seleccionados
|
|
416
|
+
- ✅ **Live regions**: Anuncia cuando cambian resultados
|
|
417
|
+
- ✅ **Disabled items**: `aria-disabled` en items deshabilitados
|
|
418
|
+
|
|
419
|
+
## Notas de Implementación
|
|
420
|
+
|
|
421
|
+
- **Basado en cmdk**: Librería `cmdk` de Paco Coursey
|
|
422
|
+
- **Fuzzy search**: Búsqueda difusa por defecto (typo-tolerant)
|
|
423
|
+
- **Performance**: Virtualización automática con muchos items
|
|
424
|
+
- **Search icon**: Incluido automáticamente en CommandInput (Material Symbol "search")
|
|
425
|
+
- **CommandDialog**: Wrapper de Command + Dialog con estilos predefinidos
|
|
426
|
+
- **Data slots**: Cada componente tiene `data-slot` para CSS targeting
|
|
427
|
+
- **Icon sizing**: Material Symbol icons automáticamente `text-lg` (18px) con shrink-0 y opacity-50
|
|
428
|
+
- **CommandShortcut**: Elemento visual para shortcuts (no ejecuta código)
|
|
429
|
+
- **Max height**: CommandList tiene `max-h-[300px]` default
|
|
430
|
+
- **Scroll behavior**: `scroll-py-1` para padding al scrollear
|
|
431
|
+
|
|
432
|
+
## Estilos Especiales en CommandDialog
|
|
433
|
+
|
|
434
|
+
Cuando se usa en Dialog, aplica estilos adicionales:
|
|
435
|
+
|
|
436
|
+
- Items con `py-3` (más padding)
|
|
437
|
+
- Input con `h-12`
|
|
438
|
+
- SVGs con `h-5 w-5` (más grandes)
|
|
439
|
+
- Groups con heading más prominente
|
|
440
|
+
|
|
441
|
+
## Troubleshooting
|
|
442
|
+
|
|
443
|
+
**Búsqueda no funciona**: Verifica que `shouldFilter={true}` (default) o implementa filtrado manual
|
|
444
|
+
**Items no se ven**: Asegúrate de envolver en `<CommandList>` y `<CommandGroup>`
|
|
445
|
+
**Cmd+K no abre dialog**: Verifica que el `useEffect` esté ejecutándose y no haya conflictos con otros shortcuts
|
|
446
|
+
**Empty no aparece**: Solo se muestra cuando no hay resultados después de búsqueda
|
|
447
|
+
**Shortcuts no ejecutan**: `CommandShortcut` es solo visual, implementa lógica aparte
|
|
448
|
+
**Dialog no cierra**: Asegúrate de llamar `setOpen(false)` en `onSelect` de items
|
|
449
|
+
**Navegación circular no funciona**: Activa `loop={true}` en Command root
|
|
450
|
+
|
|
451
|
+
## Referencias
|
|
452
|
+
|
|
453
|
+
- **cmdk**: https://cmdk.paco.me
|
|
454
|
+
- **ARIA Combobox**: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/
|