componentes / menu
Menu
Botón de menú desplegable con navegación por flechas, búsqueda al escribir, íconos, separadores e ítems peligrosos.
Cómo usar
La lista es `role="menu"` con botones `menuitem`. Flechas, Home y End mueven entre ítems (los deshabilitados se saltan), escribir una letra salta a una coincidencia, Enter/Espacio selecciona, Esc cierra y devuelve el foco al disparador. `onSelect` corre al hacer clic y con teclado; llama `event.preventDefault()` ahí para mantener el menú abierto. Se compone con `MenuItem`, `MenuLabel` y `MenuSeparator`.
preview
Menu.tsx
import { Button, Menu, MenuItem, MenuLabel, MenuSeparator } from "vaiperui"; <Menu trigger={<Button variant="outlined">Acciones</Button>} label="Acciones"> <MenuLabel>Proyecto</MenuLabel> <MenuItem icon="✎" onSelect={() => rename()}>Renombrar</MenuItem> <MenuItem disabled>Archivar</MenuItem> <MenuSeparator /> <MenuItem destructive icon="✕">Eliminar</MenuItem></Menu>Alineación
preview
alineacion.tsx
<Menu align="start" trigger={<Button>start</Button>}>...</Menu><Menu align="center" trigger={<Button>center</Button>}>...</Menu><Menu align="end" trigger={<Button>end</Button>}>...</Menu>Props
| Prop | Valores | Predeterminado | Descripción |
|---|---|---|---|
| trigger | ReactElement | ninguno | Botón que abre el menú (necesita ref, foco y onClick) |
| label | string | ninguno | Nombre accesible del menú |
| side / align | top | right | bottom | left / start | center | end | bottom / start | Lado del disparador y alineación |
| open / defaultOpen / onOpenChange | boolean / boolean / (open) => void | ninguno | Estado abierto controlado o no controlado |
| size | sm | md | lg | md | Tamaño del texto de los ítems |
| radius / animation | none | sm | md | lg | full / none | smooth | fast | bounce | lg / fast | Redondeo y velocidad de la transición de entrada |
| MenuItem | onSelect, icon, destructive, disabled | ninguno | Ítem; `onSelect` corre con clic/teclado y el menú se cierra salvo que se impida |
Accesibilidad
- La lista es `role="menu"` nombrada por `label`; cada `MenuItem` es un `button` con `role="menuitem"`.
- El disparador recibe `aria-haspopup="menu"`, `aria-expanded` y, mientras está abierto, `aria-controls`.
- Al abrir, el foco va al primer ítem habilitado; los ítems deshabilitados se saltan con las flechas.
- La navegación con flechas es circular, y escribir letras en menos de 500ms salta al siguiente ítem cuyo texto empieza con ellas.
- Seleccionar un ítem cierra el menú y devuelve el foco al disparador, salvo que `onSelect` llame a `event.preventDefault()`.
- `MenuSeparator` es `role="separator"`, `MenuLabel` es `role="presentation"` y los íconos de los ítems son `aria-hidden`.
Teclado
| Tecla | Acción |
|---|---|
| ArrowDown | En el disparador cerrado, abre el menú; dentro, va al siguiente ítem |
| ArrowUp | Va al ítem anterior |
| Home / End | Va al primer / último ítem |
| A-Z | Búsqueda al escribir: salta al ítem cuyo texto empieza con las letras escritas |
| Enter / Space | Activa el ítem enfocado |
| Esc | Cierra el menú y enfoca el disparador |
| Tab | Cierra el menú y deja que el foco siga |
Ten en cuenta
- Los ítems deben ser acciones simples; no es una barra de menú y no hay ítems marcables (`menuitemcheckbox`/`menuitemradio`) ni submenús.
- Pasa `label` para que el menú tenga nombre accesible; el disparador necesita texto visible o su propio `aria-label`.