/** * Everything `` and `` render and compute identically: * localized label helpers, line addressing (`highlight-lines`/`highlights` parsing, line counting, * `line-range` anchor scrolling), the gutter's roving-tabindex keyboard contract, selection * anchoring, clipboard writes, the shiki transformer plus the `codeToHtml()` call around it, and * the header/body templates themselves. * * The two components differ in exactly one axis -- *which* shiki loader they reach for (the full * ~200-language dynamic-import table vs. `shiki/core` seeded from a pre-supplied `languages` map), * which is why `connectedCallback()` and `syncHighlight()` stay on each class. Everything else was * previously duplicated verbatim across both class files and had already drifted (the lean variant * had silently dropped both of its `super.willUpdate()`/`super.updated()` chain-ups); routing both * through this module is what keeps a fix landing in one place from here on. * * Nothing here may `import` a *value* from `code-loader.js`'s full-table half * (`loadShikiHighlighter`/`loadShikiLanguage`): ``'s build-leanness claim rests * on its own module graph never reaching that call, and this module is in that graph. */ import{type TemplateResult,type PropertyValues}from'lit';import{type LyraClipboardWriteFailure,type LyraClipboardWriteSuccess}from'../../../internal/clipboard.js';import{type ShikiHighlighterCore}from'./shiki-types.js';import type{ShikiTransformer}from'./shiki-types.js';import type{LyraAnchor,LyraHighlight,TextSelectRect}from'../../viewers/document-viewer/anchors.js'; /** Matches `LyraElement.localize()`'s signature so either component's bound * method can be passed straight through. */ type LyraLocalizeFn=(key:string,fallback?:string,values?:Record)=>string; /** One-based line count of `code`, the upper bound every line-addressing helper below clamps to. * A trailing newline still yields the (empty) line after it, matching the rendered line count. */ export declare function codeBlockLineCount(code:string):number; /** Keeps the roving-tabindex gutter's focused line inside `[1, lineCount]` after a `code` change * shrinks the document out from under it. */ export declare function clampCodeBlockFocusedLine(focusedLine:number,lineCount:number):number;export interface CodeBlockLineFocusHost extends HTMLElement{readonly renderRoot:HTMLElement|DocumentFragment;} /** Whether real focus currently sits on one of the rendered roving line controls. */ export declare function codeBlockLineHasFocus(host:CodeBlockLineFocusHost):boolean; /** Restores focus after Lit replaces a focused line node, but never overrides focus that moved * to another internal or external control while the update was pending. */ export declare function restoreCodeBlockLineFocus(host:CodeBlockLineFocusHost,line:number):boolean; /** The merged set of one-based line numbers to emphasize: the `highlight-lines` spec plus the * `line-range` slice of `highlights`. Shared by both the shiki transformer options and the * plain-text fallback path so their emphasis is always identical. */ export declare function codeBlockLineHighlightSet(highlightLines:string,highlights:readonly LyraHighlight[],maxLine:number):Set; /** The line numbers covered by the `highlights` entry matching `activeHighlightId`, if any. */ export declare function codeBlockActiveHighlightLineSet(highlights:readonly LyraHighlight[],activeHighlightId:string|null,maxLine:number):Set; /** The `languages` entry for the *current* `language`, if any -- looked up under both the * shiki-normalized id and the raw property value, so `willUpdate()`/`updated()`/`render()`/ * `syncHighlight()` on either component all agree on whether the fine-grained path applies. * Generic over the entry type so `` can look up a * `ShikiLanguageInput | ShikiLanguageLoader` map through the same function `` * uses for its plain-grammar-only one, without widening the latter's inferred return type. */ export declare function codeBlockPreSuppliedGrammar(languages:Record |undefined,language:string):T|undefined; /** The LitElement surface `scrollCodeBlockToAnchor()` reads -- everything it touches is public on * both components, so neither needs to widen a private field to route through this. */ export interface CodeBlockAnchorHost{readonly code:string;readonly highlights:readonly LyraHighlight[];readonly renderRoot:HTMLElement|DocumentFragment;readonly updateComplete:Promise;} /** Resolves a `line-range` anchor (or a `highlights` id string resolving to one) by scrolling its * start line into view within `[part="body"]`. Resolves `false` when the anchor isn't a * `line-range`, the id isn't found, or the start line is out of bounds. */ export declare function scrollCodeBlockToAnchor(host:CodeBlockAnchorHost,target:LyraAnchor|string):Promise; /** The one-based gutter line an event originated in, or `null` when it didn't come from a line * button at all. */ export declare function codeBlockEventLine(e:Event):number|null; /** An `lr-text-select` payload for a selection ending inside `[part="body"]`. */ interface CodeBlockSelection{readonly text:string;readonly anchor:LyraAnchor;readonly rects:readonly TextSelectRect[];} /** * Whether the `` placeholder stands in for the code this render. Both components gate * it on "a highlighter this instance is actually waiting for hasn't settled yet, and there's a * `language` worth highlighting" -- they differ only in *which* loader that is, which is what * `loaderPending` carries: `` passes `!preSuppliedGrammar` (it is * waiting on the shared full-table singleton), `` passes `!!preSuppliedGrammar` * (it is waiting on the fine-grained `languages` highlighter, its only one). Called from both * `updated()` and `render()` on each class so the `aria-busy` host attribute can never disagree * with what is actually on screen. */ export declare function codeBlockShowsSkeleton(shikiReady:boolean,language:string,loaderPending:boolean):boolean; /** Mirrors the skeleton state onto the host as `aria-busy`, so assistive tech knows the code * region is still resolving. */ export declare function applyCodeBlockAriaBusy(host:Element,showingSkeleton:boolean):void;export interface CodeBlockTokenizeOptions extends CodeBlockLineTransformerOptions{code:string;lang:string;} /** * The `codeToHtml()` call both components make once their own loader has produced a highlighter. * `hl` is deliberately typed as the fine-grained `ShikiHighlighterCore` -- it and * `ShikiHighlighter` are the same structural type (see `code-loader.ts`), and naming the * fine-grained one keeps this module free of any reference to the full-table half. * * shiki's generated per-token colors are theme-specific inline styles/CSS variables (from * `SHIKI_THEMES`'s github-light/github-dark theme data), not this library's `--lr-*` design tokens * -- the one deliberate exception to every other color in these components being a `--lr-*` token. * See the dark-mode override in `code-block.styles.ts` for how the dark half of this activates. * Returns `null` on malformed input for the grammar or any other shiki-internal failure, so the * caller falls back to plain text rather than a blank code block. */ export declare function tokenizeCodeBlock(hl:ShikiHighlighterCore,options:CodeBlockTokenizeOptions):string|null;export declare function parseHighlightLines(spec:string,maxLine?:number):Set;export interface CodeBlockLineTransformerOptions{lineNumbers:boolean;activatableLines:boolean;focusedLine:number;highlightedLines:Set;activeLines:Set;lineLabel:(line:number)=>string;lineNumberText:(line:number)=>string;} /** * A shiki transformer shared by `` and `` — rewrites * shiki's generated `
`/``/per-line hast nodes so the highlighted output carries this
* library's own `part="pre"`/`part="code"` hooks plus, per line, `data-line`, and (only for a
* highlighted/active line) `data-highlighted`/`data-active` and `part="line-highlight"`. Also
* strips shiki's own default `tabindex="0"` from `
` — each component's own `[part="body"]`
* wrapper is the single scrollable/focusable region.
*/
export declare function codeBlockLineTransformer(options:CodeBlockLineTransformerOptions):ShikiTransformer;export interface CodeBlockPlainCodeOptions{code:string;lineNumbers:boolean;activatableLines:boolean;focusedLine:number;highlightedLines:Set;activeLines:Set;localize:LyraLocalizeFn;lineLabel:(line:number)=>string;lineNumberText:(line:number)=>string;onLineActivate:(line:number)=>void;onLineKeyDown:(e:KeyboardEvent,line:number)=>void;}
/**
* The plain-text (non-shiki) fallback `` rendering shared by `` and
* `` -- previously a byte-for-byte-duplicated private method on both classes,
* moved here for the same drift-prevention reason as `codeBlockLineTransformer` above. Always
* splits into per-line spans/buttons (not just while `lineNumbers` is set) -- the per-line wrapper
* is what `highlight-lines`/`highlights`/`activatable-lines` attach to. `.split()` consumes each
* newline character, so a literal `'\n'` text node is re-inserted between lines to keep the
* non-line-numbered case's visual output (relying on `[part='pre']`'s `white-space: pre`) identical
* to a single-text-node rendering. That text node is NOT inert in the line-numbered case, as this
* comment once claimed: inside a block container each whitespace run becomes its own anonymous
* block, which rendered a blank row between every line (a 3-line block laid out 5 rows). The
* container is `display: grid` (`code-block.styles.ts`), which drops whitespace-only runs instead
* of boxing them, so one row is painted per line in both modes. The gutter is a
* separate real button, leaving source text selectable in both plain and highlighted output.
*/
export declare function renderCodeBlockPlainCode(options:CodeBlockPlainCodeOptions):TemplateResult;
/**
* How the header's copy control presents itself. `'text'` (the default) is the labelled button
* this component has always rendered; `'icon'` is the compact glyph form for a dense header, where
* the localized Copy/Copied/failure string becomes the accessible name instead of visible text.
*/
export type LyraCodeBlockCopyAppearance='text'|'icon';export interface CodeBlockShellOptions{filename:string;language:string;copyable:boolean;copyAppearance:LyraCodeBlockCopyAppearance;
/** Whether a light-DOM child is assigned to the `header-actions` slot, so the header renders for
*  a code block that has nothing else to put in it. */
hasHeaderActions:boolean;collapsible:boolean;collapsed:boolean;justCopied:boolean;copyFailed:boolean;bodyId:string;
/** Wins over the filename/language-derived default -- the host's own `aria-label`. */
accessibleLabel:string|null;maxHeight:string;isDarkTheme:boolean;showSkeleton:boolean;
/** shiki's own markup for this render, or `null` for the plain-text fallback path. */
highlightedHtml:string|null;lineNumbers:boolean;localize:LyraLocalizeFn;renderPlainCode:()=>TemplateResult;onToggle:()=>void;onCopy:()=>void;onBodyMouseUp:(e:MouseEvent)=>void;onBodyClick:(e:MouseEvent)=>void;onBodyKeyDown:(e:KeyboardEvent)=>void;onBodyFocusIn:(e:FocusEvent)=>void;}
/**
* The whole rendered tree for both components: the header (only when there's anything to put in
* it) plus the scrollable code body.
*
* `[part="body"]` is `tabindex="0"` because it's the scrollable region for arbitrarily-wide/tall
* code (`max-height`, plus horizontal overflow from long lines) -- a scrollable region with no
* other focusable content of its own is otherwise unreachable by keyboard, the same reasoning
* ``'s own `[part="base"]` documents for its identical tabindex. `role="group"`
* (rather than e.g. `region`, a page landmark role) plus `aria-label` gives it an accessible name
* without claiming landmark/navigation significance for what is, structurally, just one small piece
* of a larger document.
*/
export declare function renderCodeBlockShell(options:CodeBlockShellOptions):TemplateResult;
/** The element surface {@linkcode CodeBlockInteractionController} reads. Every member is either
*  native to `HTMLElement` or already public on both code-block variants, so routing through the
*  controller widens neither component's own API. */
interface CodeBlockInteractionHost extends HTMLElement{readonly renderRoot:HTMLElement|DocumentFragment;readonly updateComplete:Promise;readonly code:string;collapsed:boolean;}
/** The reactive writes and event emissions the controller cannot perform itself: each component
*  keeps `focusedLine`/`justCopied`/`isDarkTheme` as its own `@state()` (they reach its template)
*  and its own typed `emit()`, and hands those in as callbacks. */
export interface CodeBlockInteractionOptions{host:CodeBlockInteractionHost;setFocusedLine:(line:number)=>void;setJustCopied:(value:boolean)=>void;setCopyFailed:(value:boolean)=>void;setDarkTheme:(value:boolean)=>void;emitLineActivate:(line:number)=>void;emitCopy:(outcome:LyraClipboardWriteSuccess)=>void;emitError:()=>void;emitCopyError:(outcome:LyraClipboardWriteFailure)=>void;requestToggle:(collapsed:boolean)=>boolean;emitToggle:(collapsed:boolean)=>void;emitTextSelect:(selection:CodeBlockSelection)=>void;}
/**
* Every interaction behavior `` and `` implement identically:
* the gutter's roving-tabindex focus and keyboard contract, the pointer/keyboard/focus handlers on
* `[part="body"]`, selection anchoring, the copy button and its confirmation timer, the
* collapse/expand toggle, and the dark-theme watcher's lifecycle.
*
* These lived as line-for-line duplicates on both classes, which is exactly the drift this module
* exists to prevent -- and had already bitten this pair once before (`renderPlainCode()`). The
* controller owns the two purely-internal bits of bookkeeping outright (the copy timer and the
* theme-watcher teardown, neither of which reaches either template); the three values that *are*
* rendered stay as each component's own `@state()`, written through the callbacks above so Lit
* still sees them change.
*/
export declare class CodeBlockInteractionController{private readonly options;private copyTimer?;private copyGeneration;private highlightedLocale?;private highlightedLineLabel?;
/** Localized gutter markup is cached with the effective catalog label and number locale. */
needsHighlightResync(changed:PropertyValues,locale:string,lineLabel:string):boolean;constructor(options:CodeBlockInteractionOptions);
/** Re-resolves token colors after an imperative CSSOM/adopted-stylesheet theme change. */
refreshTheme():void;
/** Retires an in-flight copy-confirmation timer against the window that scheduled it. */
cancelCopyTimer():void;
/** Invalidates pending writes and feedback when the host disconnects or changes owner. */
disconnect():void;private setCopyStatus;
/** Moves the roving tab stop to `line`, both in the component's state and on the rendered
*  gutter buttons (which Lit will not have re-rendered yet). */
setFocusedLine(line:number):void;onLineActivate:(line:number)=>void;onLineKeyDown:(e:KeyboardEvent,line:number)=>void;onBodyClick:(e:MouseEvent)=>void;onBodyKeyDown:(e:KeyboardEvent)=>void;onBodyFocusIn:(e:FocusEvent)=>void;
/** Anchors a text selection ending inside `[part="body"]` to the `line-range` it spans, so a
*  host can persist or otherwise act on it. Fires nothing when there's no active selection. */
onBodyMouseUp:()=>void;copy:()=>Promise;toggleCollapsed:()=>void;}export{};