componente · @solu30/ui-kit/feedback
CommandPalette
Paleta de comandos ya armada a partir de grupos de ítems, con atajos y navegación por teclado.
Todavía no la importa ninguno de los 15 verticales medidos.
El componente, montado
Cargando el espécimen…
export function CommandPaletteMatrix() {
const [open, setOpen] = useState(false)
const [lastCommand, setLastCommand] = useState<string | null>(null)
const focus = useFocusReturnCheck()
const close = () => {
setOpen(false)
focus.notifyClosed()
}
const runCommand = (label: string) => {
setLastCommand(label)
close()
}
const groups: CommandPaletteGroup[] = [
{
heading: 'Salón de eventos',
items: [
{
id: 'venue-new',
label: 'Nueva reserva de salón',
icon: <IconPlus className="h-4 w-4" />,
shortcut: '⌘N',
onSelect: () => runCommand('Nueva reserva de salón'),
},
{
id: 'venue-cal',
label: 'Ver calendario de eventos',
icon: <IconGrid className="h-4 w-4" />,
onSelect: () => runCommand('Ver calendario de eventos'),
},
],
},
{
heading: 'Heladería',
items: [
{
id: 'ice-order',
label: 'Nuevo pedido de heladería',
icon: <IconCuisine className="h-4 w-4" />,
onSelect: () => runCommand('Nuevo pedido de heladería'),
},
{
id: 'ice-stock',
label: 'Ver stock de sabores',
icon: <IconClipboard className="h-4 w-4" />,
onSelect: () => runCommand('Ver stock de sabores'),
},
],
},
{
heading: 'Charter náutico',
items: [
{
id: 'charter-quote',
label: 'Nueva consulta de charter',
icon: <IconAnchor className="h-4 w-4" />,
onSelect: () => runCommand('Nueva consulta de charter'),
},
{
id: 'charter-fleet',
label: 'Ver flota disponible',
icon: <IconCompass className="h-4 w-4" />,
onSelect: () => runCommand('Ver flota disponible'),
},
],
},
]
return (
<Stage label="CommandPalette · portal de pantalla completa" tall wide>
<div className="flex flex-col items-center gap-1.5">
<TriggerButton onClick={(e) => focus.openFrom(e, () => setOpen(true))}>⌘K Buscar comando</TriggerButton>
<FocusReturnNote result={focus.result} />
{lastCommand && <p className="text-[11px] text-content/50">último comando: {lastCommand}</p>}
</div>
<CommandPalette
isOpen={open}
onOpenChange={(next) => (next ? setOpen(true) : close())}
groups={groups}
placeholder="Buscar en salón, heladería o charter…"
emptyMessage="Sin resultados"
/>
</Stage>
)
}De specimens/feedback.tsx · CommandPaletteMatrix: el espécimen del Muestrario, no un ejemplo oficial del paquete. Muestra cómo se usa la pieza de verdad, montada contra los tipos instalados —eso es lo que vale— pero no es documentación del kit.
Cómo se usa
import { CommandPalette } from '@solu30/ui-kit/feedback'Props
| Prop | Requerida | Tipo | Qué hace |
|---|---|---|---|
| isOpen | sí | boolean | — |
| onOpenChange | sí | (open: boolean) => void | — |
| groups | sí | CommandGroup[] | — |
| placeholder | opcional | string | — |
| emptyMessage | opcional | string | — |
| manageHistory | opcional | boolean | Si esta paleta maneja su propia entrada de `window.history` (pushState al abrir, "atrás" la cierra). Default `true` — sin cambios de comportamiento para consumidores existentes. Poné `false` cuando `isOpen`/`onOpenChange` YA están sincronizados con la URL de la app (Next.js App Router: `?param=` + `router.push`/`searchParams`), o cuando la paleta se abre ANIDADA dentro de un overlay URL-driven — en ambos casos el pushState propio del kit mete una entrada espuria en el historial y "atrás" necesita un press de más para cerrar lo de afuera (ADR-262). @default true |