Toolbar
La toolbar de iCloud: a todo el ancho, 44 de alto, botones de ícono de 28, y una sola parada de tabulación para toda la barra.
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarInput, … } from "sebs7n-ui/toolbar"Ejemplos
La barra de una app
La toolbar de iCloud: a todo el ancho, 44 de alto, botones de ícono de 28 con el glifo en el acento y un cuadrado gris al pasar el puntero. A la izquierda la vista, en el centro lo que actúa sobre la selección —apagado a .4 mientras no hay nada elegido— y a la derecha buscar y crear.
import { PanelLeftIcon, SearchIcon, ShareIcon, SquarePenIcon, Trash2Icon } from "lucide-react"
import { Toolbar, ToolbarButton, ToolbarGroup } from "sebs7n-ui/toolbar"
function Barra() {
return (
<div className="w-full overflow-hidden rounded-surface border border-separator">
<Toolbar aria-label="Acciones de la lista">
<ToolbarButton aria-label="Mostrar la barra lateral">
<PanelLeftIcon />
</ToolbarButton>
<ToolbarGroup aria-label="Selección" className="mx-auto">
<ToolbarButton aria-label="Compartir" disabled>
<ShareIcon />
</ToolbarButton>
<ToolbarButton aria-label="Eliminar" disabled>
<Trash2Icon />
</ToolbarButton>
</ToolbarGroup>
<ToolbarButton aria-label="Buscar">
<SearchIcon />
</ToolbarButton>
<ToolbarButton aria-label="Nuevo">
<SquarePenIcon />
</ToolbarButton>
</Toolbar>
<div className="h-24 bg-background" />
</div>
)
}La barra del editor de texto
Ocho controles y una sola parada de tabulación: se entra con Tab, se recorre con ← →, se sale con Tab. Sin la barra, llegar del título al cuerpo del artículo cuesta ocho teclas.
import { AlignCenterIcon, AlignLeftIcon, AlignRightIcon, BoldIcon, ItalicIcon, LinkIcon, UnderlineIcon } from "lucide-react"
import { ToggleGroup, ToggleGroupItem } from "sebs7n-ui/toggle-group"
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarLink, ToolbarSeparator } from "sebs7n-ui/toolbar"
function Formato() {
return (
<Toolbar aria-label="Formato del artículo">
<ToggleGroup aria-label="Estilo" className="gap-0.5">
<ToolbarButton aria-label="Negrita" render={<ToggleGroupItem value="bold" />}>
<BoldIcon />
</ToolbarButton>
<ToolbarButton aria-label="Cursiva" render={<ToggleGroupItem value="italic" />}>
<ItalicIcon />
</ToolbarButton>
<ToolbarButton aria-label="Subrayado" render={<ToggleGroupItem value="underline" />}>
<UnderlineIcon />
</ToolbarButton>
</ToggleGroup>
<ToolbarSeparator />
<ToolbarGroup aria-label="Alineación">
<ToolbarButton aria-label="Alinear a la izquierda">
<AlignLeftIcon />
</ToolbarButton>
<ToolbarButton aria-label="Centrar">
<AlignCenterIcon />
</ToolbarButton>
<ToolbarButton aria-label="Alinear a la derecha">
<AlignRightIcon />
</ToolbarButton>
</ToolbarGroup>
<ToolbarSeparator />
<ToolbarButton aria-label="Insertar enlace">
<LinkIcon />
</ToolbarButton>
<ToolbarLink className="ml-auto" href="#">
Editado hace 5 min
</ToolbarLink>
</Toolbar>
)
}Un menú y un campo adentro de la barra
`render` mete el trigger de un `DropdownMenu` en el recorrido con flechas — el `DropdownMenu` envuelve la barra porque no renderiza ningún elemento propio. `ToolbarInput` deja que ← → muevan el cursor dentro del texto en vez de saltar al control de al lado.
import { Button } from "sebs7n-ui/button"
import { ChevronDownIcon } from "lucide-react"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "sebs7n-ui/dropdown-menu"
import { Toolbar, ToolbarButton, ToolbarInput, ToolbarSeparator } from "sebs7n-ui/toolbar"
function Lienzo() {
return (
<DropdownMenu>
<Toolbar aria-label="Herramientas del lienzo">
<ToolbarButton render={<DropdownMenuTrigger render={<Button size="sm" variant="ghost" />} />}>
Insertar
<ChevronDownIcon />
</ToolbarButton>
<ToolbarSeparator />
<label className="flex items-center gap-2 pl-1 text-callout text-label-secondary">
Zoom
<ToolbarInput className="w-16" defaultValue="100" inputMode="numeric" />
</label>
<ToolbarSeparator />
<ToolbarButton render={<Button size="sm" variant="default" />}>Publicar</ToolbarButton>
</Toolbar>
<DropdownMenuContent align="start">
<DropdownMenuItem>Imagen</DropdownMenuItem>
<DropdownMenuItem>Tabla</DropdownMenuItem>
<DropdownMenuItem>Gráfico</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}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».
Toolbar
Hereda las props de Toolbar.Root.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
onKeyDown | KeyboardEventHandler<T> | — | Corre antes que el manejador propio de la barra. Si hacés preventDefault(), Home y End no mueven el foco. |
variant | "plain" | "bar" | "glass" | "bar" | bar (default): la toolbar de iCloud, a todo el ancho con surface-bar y el separador abajo · plain sin fondo ni borde, para una barra adentro de otra superficie · glass: obsoleta, alias de bar (se borra en 3.0). |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
loopFocus | boolean | — | Heredada de Base UI. Si al pasar del último control se vuelve al primero. |
orientation | "horizontal" | "vertical" | — | Heredada de Base UI. vertical cambia las flechas a ↑ ↓ y da vuelta los separadores. |
ToolbarButton
Hereda las props de Toolbar.Button.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
aria-label | string | — | Nombre accesible del elemento. |
render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | — | El componente que pone los estilos. Por defecto, <Button size="icon-sm" variant="plain" />. |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
focusableWhenDisabled | boolean | — | Heredada de Base UI. Deshabilitado pero todavía en el recorrido con flechas. Dejalo en true. |
ToolbarGroup
Hereda las props de Toolbar.Group.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
ToolbarInput
Hereda las props de Toolbar.Input.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
ToolbarLink
Hereda las props de Toolbar.Link.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
ToolbarSeparator
Hereda las props de Toolbar.Separator.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
Teclado
- Tab
- Entra a la barra y sale. Veinte botones adentro siguen siendo una parada.
- ← →
- Mueve entre controles en una barra horizontal.
- ↑ ↓
- Lo mismo con
orientation="vertical". - Home · End
- Primer y último control. Lo agrega sebs7n-ui: Base UI las deja apagadas en
Toolbar. - Enter · Espacio
- Activa el control enfocado.
- ← → · Home · End dentro de un `ToolbarInput`
- Mueven el cursor en el texto, no saltan de control.
Accesibilidad
- Base UI emite
role="toolbar"conaria-orientationy maneja el roving tabindex: un solo hijo tienetabIndex=0a la vez. - Home y End las pone el componente. El patrón toolbar de la WAI las pide y el composite de Base UI las trae detrás de un flag que
Menubarprende yToolbarno; en una barra larga son la diferencia entre una tecla y quince flechas. ToolbarGroupexige `aria-label` o `aria-labelledby` en el tipo: sin él el lector anuncia «grupo» y nada más.focusableWhenDisabledviene entrue: un control apagado sigue en el recorrido, así se puede leer por qué está apagado y la barra no se mueve abajo de los dedos.- Los
ToolbarButtonde ícono necesitanaria-label: no hay texto que leer.
Reglas de uso
- El roving tabindex es toda la razón del componente. Veinte botones sueltos son veinte paradas de Tab entre el contenido de arriba y el de abajo; quien navega con teclado o con un switch los atraviesa todos cada vez. La barra ya se veía bien con un
<div className="flex gap-1">. - Todo hijo interactivo tiene que ser `ToolbarButton`, `ToolbarLink` o `ToolbarInput`. Un
<button>puesto a mano queda fuera del recorrido y se vuelve inalcanzable, porque la barra le sacó el Tab al resto. - `render` en vez de estilos nuevos:
render={<Toggle />},render={<ToggleGroupItem value="bold" />},render={<DropdownMenuTrigger render={<Button />} />}. El default ya es el botón de ícono de iCloud (Button plain size="icon-sm"): 28, glifo en el acento y un cuadrado gris al pasar. - Agrupá por intención, como iCloud: a la izquierda la vista, en el centro lo que actúa sobre la selección (apagado a .4 sin selección,
disabled), a la derecha buscar y crear. ToolbarInputes el campo chico de una barra —zoom, ancho de línea—, no un campo de formulario: para eso estáField+Input, con label, error y descripción.- Menos de tres o cuatro controles no justifica la barra: son botones sueltos y se acabó.
barsobre el wallpaper pasa sola amaterial-translucent;plainsigue sin material.