import React from 'react'; type Align = 'left' | 'center' | 'right'; interface TableBlock { kind: 'table'; headers: string[]; rows: string[][]; aligns: Align[]; } interface CodeBlock { kind: 'code'; language: string; lines: string[]; } interface HeadingBlock { kind: 'heading'; level: number; text: string; } interface ListBlock { kind: 'list'; items: { marker: string; text: string; }[]; } interface RuleBlock { kind: 'rule'; } interface TextBlock { kind: 'text'; text: string; } type Block = TableBlock | CodeBlock | HeadingBlock | ListBlock | RuleBlock | TextBlock; interface Span { text: string; code?: boolean; bold?: boolean; } /** Splits `code`, **bold** and *italic* out of a line. Markers are consumed, not printed. */ export declare function parseInline(text: string): Span[]; /** Visible width of a line once inline markers are stripped. */ export declare function plainWidth(text: string): number; /** * How many terminal cells a string occupies. * * Not its length. An emoji is one code point and two cells; a flag or a family is many code points * and still two cells; a combining accent is one code point and no cells at all. Measuring with * `.length` made every table holding an emoji draw its right border in the wrong column, because * the header was measured at one width and painted at another. * * This is the same function Ink measures with, which is the property that matters: KONECK's borders * and Ink's layout now agree on where a cell ends. */ export declare function displayWidth(text: string): number; /** * The longest prefix of `text` that fits in `width` cells, and its actual width. * * Slicing by character index cannot work when the budget is in cells: cutting a two-cell emoji at * index n either overshoots the column or splits a surrogate pair into a broken glyph. This walks * whole characters, so a truncated line lands exactly on its budget or one cell short of it — never * over, and never mid-character. */ export declare function sliceToWidth(text: string, width: number): { text: string; width: number; }; /** * Wraps text to a width while keeping inline styling intact. * * Wrapping the raw source instead splits a span's delimiters across lines: `foo(a, b)` becomes * "`foo(a," and "b)`", neither of which contains a matching pair, so the backticks get printed * as literal characters and the styling is lost. Styling is therefore resolved into spans * first, and the wrap happens over styled words. It also makes the width exact, since a * delimiter never counts toward a line's visible length. */ export declare function wrapStyled(text: string, width: number): Span[][]; /** Visible width of one wrapped line. Delimiters are already gone, so it is a plain sum. */ export declare function lineWidth(spans: Span[]): number; export declare function parseBlocks(markdown: string): Block[]; /** Greedy wrap that also hard-splits words longer than the column. */ export declare function wrapCell(text: string, width: number): string[]; /** * Assigns a width to each column, using natural widths when they fit. * * When they do not, the currently widest column gives up one character at a time. Shrinking * proportionally instead starves the narrow columns: a "Role" column holding school_admin * would drop to 8 and split the identifier as "school_a / dmin", while the long prose column * beside it kept space it did not need. Taking from the widest means prose absorbs the loss * and identifier columns stay intact. */ export declare function columnWidths(headers: string[], rows: string[][], available: number): number[]; /** * A bordered panel drawn character by character at an exact width. * * Ink's own borderStyle is correct in isolation, but in a real tree its content rows came out * one cell narrower than its border rows, so the right edge stepped in and out and the boxes * looked torn. Emitting each line as a single Text with the padding computed here removes the * layout engine from the question: every row is the same length by construction. */ export declare function Panel({ width, color, title, children, dim, }: { width: number; color: string; title?: string; /** Pre-wrapped lines. Each is rendered with inline styling applied. */ children: string[]; dim?: string; }): React.JSX.Element; /** * A reply, rendered. * * Memoized on `text` and `width`, both primitives, so a repaint caused by anything else — a * keystroke in the composer, a spinner frame, a token arriving for the reply still being written — * does not re-render a message that was finished minutes ago. Without this every transcript row on * screen was rebuilt and re-laid-out on every frame, which on a Raspberry Pi 5 measured 168ms for a * thirty-row screen: a 6fps interface, where each keystroke waited behind a full repaint. * * The transcript is the right place for this because it is almost entirely immutable. Only the last * row changes while a reply streams; everything above it is settled, and settled rows are now free. */ export declare const Markdown: React.MemoExoticComponent; declare function MarkdownView({ text, width }: { text: string; width: number; }): React.JSX.Element; /** * The width a panel needs for its content, never more than what is available. * * Boxes used to be drawn at the full terminal width whatever they held, so "omni returned no * models." sat in a box stretching 240 columns. A box that hugs its text reads as a remark; one * spanning the screen reads as a section, and most of them are remarks. */ export declare function panelWidth(lines: string[], available: number, min?: number): number; /** * Where a partially streamed reply can be safely cut and rendered. * * Returns the index just past a blank line, or -1 when nothing can be committed yet. This is what * makes it possible to render a reply as it arrives instead of holding it all back: markdown needs * whole blocks to lay out, and a blank line is exactly where one block ends and the next begins. * A table has no blank lines inside it, so a boundary can never split one. * * Fenced code is the exception — a fence may well contain blank lines — so a candidate whose * prefix leaves a fence open is rejected and an earlier boundary tried instead. */ export declare function safeCommitPoint(text: string): number; /** True when every opening code fence in the text has been closed. */ export declare function fencesBalanced(text: string): boolean; export {}; //# sourceMappingURL=markdown-ink.d.ts.map