Contenido y datos
Log Viewer
El visor de logs: monoespaciado, una línea por renglón, con el nivel en color y en texto, que sigue la última línea.
import { LogViewer } from "sebs7n-ui/log-viewer"Ejemplos
Niveles
`warn` y `error` llevan el nivel escrito además del color; `info` lo dice solo el lector. El visor se recorre con el teclado.
import { LogViewer } from "sebs7n-ui/log-viewer"
function Levels() {
return <LogViewer aria-label="Registro de envíos" className="w-full" lines={LINES} />
}En vivo
Sigue la última línea mientras el scroll esté al final; si subís a leer, se queda donde estás. Pausar es un botón de la app.
import { Button } from "sebs7n-ui/button"
import { LogViewer, type LogLine } from "sebs7n-ui/log-viewer"
import { PauseIcon, PlayIcon } from "lucide-react"
import { useEffect, useState } from "react"
function Live() {
const [lines, setLines] = useState<LogLine[]>(LINES)
const [paused, setPaused] = useState(false)
useEffect(() => {
if (paused) return
const timer = setInterval(() => {
setLines((previous) => [...previous, { id: previous.length + 1, time: new Date().toTimeString().slice(0, 8), message: `Cobro conciliado ${previous.length + 1}` }].slice(-200))
}, 1000)
return () => clearInterval(timer)
}, [paused])
return (
<div className="flex w-full flex-col gap-2">
<div>
<Button onClick={() => setPaused((value) => !value)} size="sm" variant="secondary">
{paused ? <PlayIcon /> : <PauseIcon />}
{paused ? "Reanudar" : "Pausar"}
</Button>
</div>
<LogViewer aria-label="Cobros en vivo" lines={lines} variant="terminal" />
</div>
)
}Cargando y vacío
Cargando dice «Cargando…» y marca la región como ocupada; sin líneas, por qué no hay.
import { LogViewer } from "sebs7n-ui/log-viewer"
function States() {
return (
<div className="flex w-full flex-col gap-3">
<LogViewer aria-label="Cargando registro" className="h-24" lines={[]} loading />
<LogViewer aria-label="Registro vacío" className="h-24" emptyMessage="Ninguna línea coincide con los filtros." lines={[]} />
</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».
LogViewer
Hereda las props de <div>.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
lines* | readonly LogLine[] | — | Las líneas, de la más vieja a la más nueva: { id?, time?, level?, source?, message }. |
aria-label | string | — | Qué se está mirando: «Log del despliegue». Por defecto, labels.label. |
emptyMessage | React.ReactNode | — | Lo que se ve sin líneas (por ejemplo, «Ninguna línea coincide con los filtros»). Por defecto, labels.empty. |
follow | boolean | true | Sigue la última línea mientras el scroll esté al final; si se sube a leer, se queda ahí. Por defecto, true. |
labels | Partial<LogViewerLabels> | — | Textos: label, empty, loading y los niveles info, warn y error. Por defecto, logViewerLabels. |
loading | boolean | false | Trayendo las líneas: muestra «Cargando…» y marca la región como ocupada. |
onScroll | UIEventHandler<T> | — | Corre en cada scroll del visor, después de que el componente anota si quedó al final. |
variant | "default" | "terminal" | "default" | terminal: fondo oscuro en los dos temas, como una terminal. Por defecto, default: el relleno gris de la superficie. |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
Teclado
- Tab
- Entra al visor, que es enfocable para recorrerlo.
- ↑ ↓ · Re Pág · Av Pág · Inicio · Fin
- Se desplazan por las líneas (el scroll nativo del navegador).
Accesibilidad
- Es una región
role="log"con nombre (aria-label: «Log del despliegue»): el lector anuncia las líneas nuevas sin robar el foco.tabIndex={0}permite recorrerlo con el teclado. - El nivel va en color y en texto:
warnyerrorllevan «Aviso:» / «Error:» a la vista, einfolo dice solo para el lector (sr-only). Nunca solo color. aria-busymientras carga; sin líneas dice por qué (emptyMessage).
Reglas de uso
lines:{ id?, time?, level?, source?, message }, de la más vieja a la más nueva, ya filtradas y acotadas por la app (los últimos 500, por ejemplo). Pausar, buscar y descargar son botones de la app, en unaFilterBar.follow(por defecto) baja solo cuando llegan líneas, pero solo si el scroll estaba al final: quien subió a leer no pierde el lugar.variant="terminal"lo pone oscuro en los dos temas, como una terminal. La altura se fija conclassName(h-[60dvh]).- Solo por subpath (
sebs7n-ui/log-viewer).