# `karaoke/lyrics-display` _(no submodules)_ ## Purpose `` is the karaoke surface that renders a stack of lyric lines with the active line highlighted. It is the visible end-product of the `parseLrc` → `useLyrics` pipeline and the component the player variants compose when their `lrc` prop is populated. The component is clock-agnostic by design: the caller passes `currentSec` (a plain number) and the component renders the highlighted line. The typical wiring is `useTransportTime()` from `@suaveplan/react-audio` when the display sits inside an ``, but standalone preview and test surfaces can hand in any number — Playwright spec runs use a deterministic clock; documentation pages drive a `` input. Keeping the time source explicit removes a hidden provider dependency. ## Features - Renders one `` per lyric line with `data-active="true|false"` for CSS-driven styling; consumers needing structural control can pass `renderLine` for full custom rendering. - Active line carries `aria-live="polite"` by default so screen readers announce lyric changes; togglable via `announceLyrics`. - Wrapping `
` exposes `role="region"` + `aria-label="Lyrics"`. - Re-binds the active index every 100 ms (configurable) regardless of the consumer's render cadence. - Both time-source modes share the same internal render path; the outer dispatch is a one-time component-type pick. ## Usage: Basic ```tsx import { LyricsDisplay } from "@suaveplan/react-audio-player/karaoke/lyrics-display"; import { useTransportTime } from "@suaveplan/react-audio"; function Player({ lrcSource }: { lrcSource: string }) { const seconds = useTransportTime(); return ; } ``` ## Usage: Advanced ```tsx import { LyricsDisplay } from "@suaveplan/react-audio-player/karaoke/lyrics-display"; import { parseLrc } from "@suaveplan/react-audio-player/karaoke/lrc-parser"; import { useMemo } from "react"; function StyledLyrics({ lrc, time }: { lrc: string; time: number }) { const lyrics = useMemo(() => parseLrc(lrc), [lrc]); return ( (

{lyric.text || }

)} /> ); } ``` ## API Reference - `` accepts `LyricsDisplayProps`: - `lyrics?: readonly Lyric[]` — preferred over `lrc`. - `lrc?: string` — parsed once per identity change. - `currentSec: number` — required. - `intervalMs?: number` (default 100). - `announceLyrics?: boolean` (default `true`). - `className?: string`. - `renderLine?: ({ lyric, isActive, index }) => ReactNode`. ## Implementation Notes The component is a single-branch render — no dual-component dispatch — because `currentSec` is always a plain prop. This keeps the Rules of Hooks trivially satisfied (one render path, one hook sequence) and removes a hidden coupling to the surrounding ``. Consumers that want the transport-driven path call `useTransportTime()` themselves and pass the result down. The `data-active="true|false"` attribute is the recommended CSS selector hook. Toggling `aria-live` only on the active line ensures exactly one element narrates per change cycle; without that targeted gating, every line's render would re-announce on every re-mount, which is acoustically unusable. When `renderLine` is supplied, the component delegates to it verbatim and skips the default `` + `data-active` path. The delegated node is wrapped in a keyed `` so consumers can return any element they like — `
  • `, `

    `, `

    ` — without fighting an enclosing wrapper.