Superposiciones
Command Palette
La paleta ⌘K declarativa: grupos de ítems ({ heading, items }) sobre CommandDialog, con carga diferida opcional de los datos.
import { CommandPalette } from "sebs7n-ui/command-palette"Ejemplos
Grupos declarativos
Un grupo por tipo de cosa, con ícono, detalle y palabras clave. Se abre con ⌘K (registrado acá, en la demo) o con el botón; elegir un ítem cierra la paleta.
import { Button } from "sebs7n-ui/button"
import { CommandPalette, type CommandPaletteGroup } from "sebs7n-ui/command-palette"
import { FileTextIcon, HomeIcon, UsersIcon } from "lucide-react"
import { Kbd } from "sebs7n-ui/kbd"
import { useState } from "react"
function Groups() {
const [open, setOpen] = useState(false)
const [chosen, setChosen] = useState("nada todavía")
useCommandShortcut(() => setOpen(true))
const groups: CommandPaletteGroup[] = [
{
heading: "Secciones",
items: [
{ value: "home", label: "Inicio", icon: <HomeIcon />, onSelect: () => setChosen("Inicio") },
{ value: "invoices", label: "Facturas", icon: <FileTextIcon />, keywords: ["cobros"], onSelect: () => setChosen("Facturas") },
{ value: "customers", label: "Clientes", icon: <UsersIcon />, onSelect: () => setChosen("Clientes") },
],
},
{
heading: "Facturas",
items: [
{ value: "F-0042", label: "F-0042", description: "Acme S.A. · Servicio mensual", icon: <FileTextIcon />, keywords: ["Acme"], onSelect: () => setChosen("F-0042") },
{ value: "F-0039", label: "F-0039", description: "Globex SRL · Licencias", icon: <FileTextIcon />, keywords: ["Globex"], onSelect: () => setChosen("F-0039") },
],
},
]
return (
<div className="flex flex-col items-start gap-3">
<Button onClick={() => setOpen(true)} variant="secondary">
Buscar <Kbd size="sm">⌘K</Kbd>
</Button>
<p aria-live="polite" className="text-callout text-label-secondary">
Elegiste: {chosen}
</p>
<CommandPalette groups={groups} onOpenChange={setOpen} open={open} placeholder="Secciones y facturas…" />
</div>
)
}Carga diferida
`loadGroups` trae los clientes la primera vez que se abre, no al montar la pantalla. Mientras llega dice «Cargando…».
import { Button } from "sebs7n-ui/button"
import { CommandPalette } from "sebs7n-ui/command-palette"
import { UsersIcon } from "lucide-react"
import { useState } from "react"
function Deferred() {
const [open, setOpen] = useState(false)
return (
<div className="flex flex-col items-start gap-3">
<Button onClick={() => setOpen(true)} variant="secondary">
Buscar un cliente
</Button>
<CommandPalette
loadGroups={async () => {
await new Promise((resolve) => setTimeout(resolve, 800))
return [
{
heading: "Clientes",
items: ["Acme S.A.", "Globex SRL", "Initech", "Umbrella Corp."].map((name) => ({ value: name, label: name, icon: <UsersIcon />, onSelect: () => {} })),
},
]
}}
onOpenChange={setOpen}
open={open}
placeholder="Clientes…"
/>
</div>
)
}Props
Generadas del TypeScript del paquete. Las propias del componente, más las heredadas del primitivo que tienen algo que explicar —marcadas «heredada de Base UI»—. El resto está en la línea «hereda de».
CommandPalette
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
onOpenChange* | (open: boolean) => void | — | Avisa que se pidió abrirla o cerrarla. |
open* | boolean | — | Si la paleta está abierta. |
closeOnSelect | boolean | true | Cierra la paleta al elegir un ítem. Por defecto, true: «copiar el número» puede querer false. |
groups | readonly CommandPaletteGroup[] | [] | Los grupos, en orden: { heading?, items }. Un grupo sin ítems no se dibuja. |
labels | Partial<CommandPaletteLabels> & Partial<Labels["command"]> | — | Textos: loading y loadError, más los de Command (dialog, placeholder, empty, filters) que se pasan tal cual. |
loadGroups | () => Promise<readonly CommandPaletteGroup[]> | — | Trae más grupos la primera vez que se abre la paleta. Se suman a groups. |
placeholder | string | — | El texto del campo vacío y su nombre. Por defecto, el de Command. |
shouldFilter | boolean | — | Con false no filtra: es para cuando la app ya filtró o ordenó. Ver Command. |
className | string | — | Clases del panel. |
Teclado
- Escribir
- Filtra por título y
keywords, sin distinguir mayúsculas ni tildes. - ↑ ↓
- Mueven el elegido.
- Enter
- Ejecuta el
onSelectdel elegido y cierra la paleta. - Escape
- Cierra.
Accesibilidad
- Es
Commanden un diálogo: campocomboboxy listalistbox, con el foco en el campo. Se nombra conlabels.dialog. - Mientras
loadGroupstrae los datos hay unstatus«Cargando…»; si falla, unalertconlabels.loadError.
Reglas de uso
- No escucha el teclado: ⌘K lo registra la app (un
keydownen el layout) y le pasaopenyonOpenChange. - Cada ítem es
{ value, label, icon?, description?, keywords?, onSelect }; elvaluees único en toda la paleta. Elegir cierra la paleta salvo concloseOnSelect={false}. loadGroupstrae los grupos la primera vez que se abre (los degroupsestán desde el principio); si falla, se reintenta al abrir de nuevo.- Para que el JS de la paleta no entre en el primer bundle, importala con
next/dynamicoReact.lazyy montala recién cuando se pidió por primera vez. - Para filtros (
CommandFilters), ítems propios o una paleta incrustada en la página,Command. Solo por subpath (sebs7n-ui/command-palette).