Ir al contenido
Contenido y datos

LogViewer

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>.

PropTipoPor defectoDescripción
lines*readonly LogLine[]—Las líneas, de la más vieja a la más nueva: { id?, time?, level?, source?, message }.
aria-labelstring—Qué se está mirando: «Log del despliegue». Por defecto, labels.label.
emptyMessageReact.ReactNode—Lo que se ve sin líneas (por ejemplo, «Ninguna línea coincide con los filtros»). Por defecto, labels.empty.
followbooleantrueSigue la última línea mientras el scroll esté al final; si se sube a leer, se queda ahí. Por defecto, true.
labelsPartial<LogViewerLabels>—Textos: label, empty, loading y los niveles info, warn y error. Por defecto, logViewerLabels.
loadingbooleanfalseTrayendo las líneas: muestra «Cargando…» y marca la región como ocupada.
onScrollUIEventHandler<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.
classNamestring—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: warn y error llevan «Aviso:» / «Error:» a la vista, e info lo dice solo para el lector (sr-only). Nunca solo color.
  • aria-busy mientras 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 una FilterBar.
  • 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 con className (h-[60dvh]).
  • Solo por subpath (sebs7n-ui/log-viewer).

Relacionados