@markii/ansi 0.15.0 → 0.17.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ansi.d.ts +26 -0
  3. package/dist/ansi.js +51 -0
  4. package/dist/components/badge.d.ts +1 -1
  5. package/dist/components/badge.js +5 -4
  6. package/dist/components/callout.d.ts +38 -13
  7. package/dist/components/callout.js +68 -31
  8. package/dist/components/card.d.ts +34 -2
  9. package/dist/components/card.js +55 -18
  10. package/dist/components/cell.d.ts +5 -11
  11. package/dist/components/cell.js +11 -15
  12. package/dist/components/chart.d.ts +4 -10
  13. package/dist/components/chart.js +16 -24
  14. package/dist/components/details-string.d.ts +26 -0
  15. package/dist/components/details-string.js +39 -0
  16. package/dist/components/details.d.ts +32 -10
  17. package/dist/components/details.js +28 -25
  18. package/dist/components/divider.js +12 -16
  19. package/dist/components/figure.d.ts +5 -16
  20. package/dist/components/figure.js +9 -19
  21. package/dist/components/index.d.ts +14 -10
  22. package/dist/components/index.js +19 -16
  23. package/dist/components/kbd.d.ts +1 -1
  24. package/dist/components/kbd.js +3 -2
  25. package/dist/components/layout-wrapper.d.ts +7 -22
  26. package/dist/components/layout-wrapper.js +9 -23
  27. package/dist/components/progress.d.ts +3 -11
  28. package/dist/components/progress.js +8 -17
  29. package/dist/components/rating.d.ts +1 -2
  30. package/dist/components/rating.js +3 -4
  31. package/dist/components/row.d.ts +35 -20
  32. package/dist/components/row.js +35 -51
  33. package/dist/components/stat.d.ts +3 -8
  34. package/dist/components/stat.js +5 -11
  35. package/dist/components/tab.d.ts +9 -8
  36. package/dist/components/tab.js +12 -10
  37. package/dist/components/table-grid.d.ts +2 -1
  38. package/dist/components/table-grid.js +14 -12
  39. package/dist/components/table.d.ts +5 -10
  40. package/dist/components/table.js +8 -13
  41. package/dist/components/tabs-string.d.ts +17 -0
  42. package/dist/components/tabs-string.js +30 -0
  43. package/dist/components/tabs.d.ts +31 -14
  44. package/dist/components/tabs.js +55 -30
  45. package/dist/failure-presentation.d.ts +15 -0
  46. package/dist/failure-presentation.js +22 -0
  47. package/dist/glyphs.d.ts +73 -0
  48. package/dist/glyphs.js +88 -0
  49. package/dist/index.d.ts +6 -4
  50. package/dist/index.js +10 -7
  51. package/dist/ink-string.d.ts +23 -0
  52. package/dist/ink-string.js +65 -0
  53. package/dist/interactive.d.ts +66 -0
  54. package/dist/interactive.js +207 -0
  55. package/dist/layout.js +1 -2
  56. package/dist/pack-loader.d.ts +64 -0
  57. package/dist/pack-loader.js +172 -0
  58. package/dist/pack-script.d.ts +44 -0
  59. package/dist/pack-script.js +135 -0
  60. package/dist/registry.d.ts +106 -100
  61. package/dist/registry.js +17 -9
  62. package/dist/render.d.ts +63 -25
  63. package/dist/render.js +1001 -380
  64. package/dist/text-grid.d.ts +90 -0
  65. package/dist/text-grid.js +300 -0
  66. package/package.json +9 -5
  67. package/dist/box.d.ts +0 -47
  68. package/dist/box.js +0 -209
  69. package/dist/measure.d.ts +0 -25
  70. package/dist/measure.js +0 -108
@@ -1,19 +1,29 @@
1
- /**
2
- * The registry contract for the terminal engine: the string-emitting twin of
3
- * `@markii/html`'s `registry.ts`, itself the string-emitting twin of
4
- * `@markii/react`'s `registry.ts`. A component here is a plain function from
5
- * attributes and already-rendered children TEXT to an output string — no
6
- * hast, no React, no HTML. The alias, merge, and hostile-configuration rules
7
- * are kept identical to both existing renderers, so a note resolves the same
8
- * way in all three.
9
- */
1
+ import type { FC, ReactNode } from 'react';
10
2
  import type { FailureKind, ValueStatus } from './value-types.js';
11
3
  import type { LayoutAxis, OnDiagnostic } from '@markii/stdlib';
12
4
  import type { ColorLevel } from './ansi.js';
13
5
  import type { AnsiTheme, Tier1Token } from './theme.js';
6
+ import type { GlyphSet } from './glyphs.js';
14
7
  import type { ResolvedLayoutAttributes } from './layout.js';
15
8
  import type { ResolveImageSrc } from './image-resolve.js';
16
9
  import type { ResolveHref } from './href-resolve.js';
10
+ /**
11
+ * The registry contract for the terminal engine, batch-10 (the Ink
12
+ * rewrite): a component is a React function component receiving
13
+ * `{ attributes, children, ctx }`, where `children` is ALREADY a built Ink
14
+ * element tree (a `ReactNode`) rather than the lazy string-producing
15
+ * `AnsiChildren` handle the pre-Ink engine used. Building children eagerly
16
+ * is the batch-10 brief's own instruction (`AGENTS.md`'s architecture
17
+ * section is silent on this; the brief is explicit: "Delete... the lazy-
18
+ * children machinery"): Ink/Yoga lays a tree out AFTER it is built, exactly
19
+ * like a browser reflows HTML, so a component no longer needs to ask for a
20
+ * narrower re-render of its own body the way the old string engine did —
21
+ * the one standard component that still needs a per-cell WIDTH NUMBER before
22
+ * it draws (`row`, whose cells may hold a self-drawing box like `card`) gets
23
+ * that from `render.tsx`'s own walk, which still threads `width` top-down
24
+ * exactly as before; see `render.tsx`'s `renderRow` for why that one case is
25
+ * handled at the walk level rather than through a registry-facing API.
26
+ */
17
27
  /**
18
28
  * Attributes parsed off a directive, e.g. `{type=warning title="Careful"}`. A
19
29
  * bare attribute (present but valueless, e.g. `{collapsed}`) arrives as
@@ -32,28 +42,53 @@ export interface ValueResolution {
32
42
  failureKind?: FailureKind;
33
43
  }
34
44
  /**
35
- * The render context handed to every component. Mirrors
36
- * `@markii/html`'s `HtmlRenderContext` field for field, with the HTML-only
37
- * `esc` swapped for `text` (this engine's control-character sanitizer, see
38
- * `./sanitize.js`'s `stripControlCharacters`) and a set of terminal-only
39
- * fields added: `width`/`indent` (the layout budget this directive's own
40
- * output has to work with), `color`/`theme` (what this render resolved),
41
- * and the box/style helpers pre-bound to both.
45
+ * The render context handed to every component. Mirrors the pre-Ink
46
+ * engine's `AnsiRenderContext` for every field EXCEPT the string-layout
47
+ * helpers (`wrap`/`pad`/`columns`/`frame`/`rule`), which are dropped:
48
+ * ordinary prose now wraps through Ink's own layout, and the handful of
49
+ * self-drawing standard components (`card`, `callout`, `divider`, `chart`,
50
+ * `table`) that still need exact box-drawing glyphs use `./text-grid.js`'s
51
+ * private helpers directly rather than through the context.
42
52
  */
43
53
  export interface AnsiRenderContext {
44
- /** The columns available to this directive's own output. A component wraps its own text to this width. */
54
+ /** The columns available to this directive's own output. A self-drawing component sizes its own frame to this width (or to `layout`'s resolved preset of it). */
45
55
  width: number;
46
56
  /**
47
57
  * The prefix an enclosing block (a blockquote, a nested list) has already
48
- * applied to every line above this directive. Informational only: a
49
- * component emits its own block UNINDENTED, and the walk applies the
50
- * prefix afterward, exactly as `width` is already the post-indent budget.
58
+ * applied to every line above this directive, informational only: a
59
+ * component draws its own content at `width` and the walk applies the
60
+ * enclosing indent as an Ink `Box` wrapper, not as a string prefix.
51
61
  */
52
62
  indent: string;
53
63
  /** The resolved color depth for this render. */
54
64
  color: ColorLevel;
55
65
  /** The resolved theme for this render. */
56
66
  theme: AnsiTheme;
67
+ /**
68
+ * The glyphs for this render's box style (`./glyphs.ts`). A component that
69
+ * draws a frame, rule, bar, or symbol takes it from here, never from a
70
+ * literal, so `box: 'ascii'` reaches it.
71
+ */
72
+ glyphs: GlyphSet;
73
+ /**
74
+ * Whether this render is in INTERACTIVE mode (a live viewer), as opposed
75
+ * to the default render-once mode. NAME COLLISION, documented at both
76
+ * declarations: this is UNRELATED to Ink's own `render()` option also
77
+ * spelled `interactive` (`ink-string.ts`'s doc comment) — that one
78
+ * controls which escape sequences Ink emits around a frame; this one
79
+ * controls which CONTENT a component renders (`tabs` shows only the
80
+ * active panel, `details` starts closed unless `open` is present) and
81
+ * whether it registers a keyboard handler at all.
82
+ */
83
+ interactive: boolean;
84
+ /**
85
+ * A stable, document-order identity for a FOCUSABLE component (currently
86
+ * `tabs` and `details`) when `interactive` is true; `undefined` when not
87
+ * interactive, or for any other component. Assigned once by `render.tsx`
88
+ * as it walks the tree (see `render.tsx`'s `WalkContext.nextFocusId`), so
89
+ * a component never has to compute its own position in document order.
90
+ */
91
+ focusId?: number;
57
92
  /** Applies `theme`'s color for `token` at this render's `color` level. Unchanged at `'none'` or for a `null` theme entry. */
58
93
  style(text: string, token: Tier1Token): string;
59
94
  /** SGR bold, pre-bound to this render's color level. */
@@ -66,26 +101,11 @@ export interface AnsiRenderContext {
66
101
  underline(text: string): string;
67
102
  /** SGR inverse/reverse video, pre-bound to this render's color level. */
68
103
  inverse(text: string): string;
69
- /** Greedy word wrap, pre-bound to nothing (width is explicit here since a component may wrap narrower than its own `ctx.width`, e.g. inside its own frame). */
70
- wrap(text: string, width: number): string[];
71
- /** Pads `text` to `width` columns, aligned `left`/`center`/`right`. */
72
- pad(text: string, width: number, align: 'left' | 'center' | 'right'): string;
73
- /** Places blocks side by side; see `./box.js`'s `columns`. */
74
- columns(blocks: readonly string[], widths: readonly number[], gutter: number): string;
75
- /** Draws a box around `block`; see `./box.js`'s `frame`. */
76
- frame(block: string, options: {
77
- style: 'solid' | 'dashed';
78
- title?: string;
79
- width: number;
80
- }): string;
81
- /** A full-width horizontal rule; see `./box.js`'s `rule`. */
82
- rule(width: number, char?: string): string;
83
104
  /**
84
105
  * The sanitizer a component MUST run any author-supplied string through
85
- * before printing it (this engine's counterpart to the HTML context's
86
- * `esc`): strips every control character an untrusted note could use to
87
- * move the cursor or smuggle an escape sequence (`./sanitize.js`'s
88
- * `stripControlCharacters`).
106
+ * before printing it: strips every control character an untrusted note
107
+ * could use to move the cursor or smuggle an escape sequence
108
+ * (`./sanitize.js`'s `stripControlCharacters`).
89
109
  */
90
110
  text(value: string): string;
91
111
  /** Resolves a `data=`/`:value[...]` name against the current render's store/vault. Never throws. */
@@ -96,6 +116,14 @@ export interface AnsiRenderContext {
96
116
  dataStatus?: ValueStatus;
97
117
  dataError?: string;
98
118
  dataFailureKind?: FailureKind;
119
+ /**
120
+ * The engine's quiet trailing marker for this binding's state, e.g.
121
+ * ` (script error)` or ` (stale)`, and `''` for a fresh or missing one.
122
+ * Present with `data`. A component that cannot import the engine's
123
+ * failure-presentation module (a terminal pack, which only sees this
124
+ * context) appends it so the wording stays in one place.
125
+ */
126
+ dataSuffix?: string;
99
127
  /**
100
128
  * The resolved width/align presets for the axis a layout-scope entry does
101
129
  * not already own — this engine's counterpart to `@markii/html`'s
@@ -108,76 +136,39 @@ export interface AnsiRenderContext {
108
136
  onDiagnostic?: OnDiagnostic;
109
137
  }
110
138
  /**
111
- * How a component wants ONE render of its children to happen: at a
112
- * narrower `width` than the directive itself was rendered at (a self-layout
113
- * box sizing its own inner budget), and/or a different `indent`. Omitting a
114
- * field inherits the value the enclosing directive was rendered with.
115
- */
116
- export interface AnsiChildrenOptions {
117
- width?: number;
118
- indent?: string;
119
- }
120
- /**
121
- * One top-level child of a directive's own body, independently renderable
122
- * at its own width — the piece `row` needs and no other standard component
123
- * does: it must decide each cell's column width BEFORE that cell's content
124
- * (including a self-drawing box like `card`) is rendered, not re-wrap an
125
- * already-drawn frame afterward. `name` is the child's own resolved
126
- * directive name (e.g. `'cell'`) when the child is itself a directive, and
127
- * `undefined` for a plain block (a paragraph, a list) or a directive with a
128
- * different name — enough for a container to recognize a semantically
129
- * tagged child without ever seeing a hast node.
139
+ * One registry component: a React function component. `attributes` are the
140
+ * directive's raw string attributes (bare attributes as `null`); `children`
141
+ * is the directive's already-rendered inner markdown, an Ink element tree;
142
+ * `ctx` is `AnsiRenderContext` above. Attribute parsing, validation, and
143
+ * defaulting are the component's own job, exactly as in the other two
144
+ * engines' contracts. A component MAY use React hooks (`useState`,
145
+ * `useInput`, ...) since `render.tsx` always invokes it as a JSX element,
146
+ * never as a plain function call — `tabs` and `details` need this for
147
+ * interactive mode.
130
148
  */
131
- export interface AnsiChildPart {
132
- readonly name?: string;
133
- render(options?: AnsiChildrenOptions): string;
149
+ export interface AnsiComponentProps {
150
+ attributes: DirectiveAttributes;
151
+ children: ReactNode;
152
+ ctx: AnsiRenderContext;
134
153
  }
135
- /**
136
- * The children a component receives. Calling it directly renders the
137
- * directive's WHOLE body as one flattened string — what every component
138
- * except `row` wants, and what used to be eagerly computed as a plain
139
- * string before the component ever ran. `options` narrows the width/indent
140
- * for that one call (a self-layout box's inner budget); omitted, it renders
141
- * at the width/indent the directive itself was given.
142
- *
143
- * `.parts` exposes each of the directive's own top-level children
144
- * separately, in document order, each independently renderable at its own
145
- * width via its own `render(options)` — see `AnsiChildPart`.
146
- *
147
- * Laziness is the point: nothing under this directive is rendered until a
148
- * component actually calls `children()` or one of `.parts`' `render()`
149
- * functions, so a container can decide sizes top-down before anything below
150
- * it draws a single character.
151
- */
152
- export type AnsiChildren = ((options?: AnsiChildrenOptions) => string) & {
153
- readonly parts: readonly AnsiChildPart[];
154
- };
155
- /**
156
- * One registry component: receives the directive's raw string attributes
157
- * (bare attributes as `null`), a lazy handle onto its inner markdown
158
- * (`AnsiChildren`, see above), and the render context, and returns the text
159
- * to emit. Attribute parsing, validation, and defaulting are the
160
- * component's own job, exactly as in the other two engines' contracts.
161
- */
162
- export type AnsiComponent = (attributes: DirectiveAttributes, children: AnsiChildren, ctx: AnsiRenderContext) => string;
154
+ export type AnsiComponent = FC<AnsiComponentProps>;
163
155
  /** One registry entry: the component plus whether it is meant to be used inline vs as a block, and whether it is a layout scope. Mirrors `@markii/html`'s `HtmlRegistryEntry`. */
164
156
  export interface AnsiRegistryEntry {
165
157
  component: AnsiComponent;
166
158
  inline?: boolean;
167
159
  layout?: LayoutAxis;
168
160
  /**
169
- * Marks a component that draws its OWN box (a frame, a table grid) rather
170
- * than plain wrapped text — `card`, `callout`, `table`, `chart` in the
171
- * standard set. `applyLayout`'s generic re-wrap/pad would corrupt a
172
- * pre-drawn frame's box-drawing characters if `render.ts` narrowed it
173
- * AFTER the component already drew it at the full width. A `selfLayout`
174
- * component instead receives the resolved `width`/`align` presets as
175
- * `ctx.layout` (the same field a layout-WRAPPER scope receives) and is
176
- * trusted to size its own frame correctly; `render.ts` then skips its
177
- * usual post-render `applyLayout` call for it, exactly as it already does
178
- * for a layout-wrapper scope. Unlike `layout: LayoutAxis`, this is not
179
- * "this directive's name sets an axis" — it is "this directive draws pixels
180
- * that a generic wrap/pad would break."
161
+ * Marks a component that draws its OWN fixed-width block (box-drawing
162
+ * glyphs, a rule, a sparkline) rather than plain wrapped prose — `card`,
163
+ * `callout`, `divider`, `table`, `chart` in the standard set. A generic
164
+ * post-render narrow/align pass would corrupt a pre-drawn frame's
165
+ * box-drawing characters, so a `selfLayout` component instead receives the
166
+ * resolved `width`/`align` presets as `ctx.layout` and is trusted to size
167
+ * its own frame correctly; `render.tsx` skips its usual post-render
168
+ * `applyLayout` wrapping for it. Kept from the pre-Ink engine: Ink's own
169
+ * layout does not solve this, because the content in question is a
170
+ * pre-built STRING (see `text-grid.ts`'s module doc comment), not
171
+ * Ink primitives Yoga can reflow.
181
172
  */
182
173
  selfLayout?: boolean;
183
174
  }
@@ -225,3 +216,18 @@ export interface ResolvedDirective {
225
216
  * throws.
226
217
  */
227
218
  export declare function resolveDirectiveAlias(registry: AnsiRegistry, name: string, attributes: DirectiveAttributes): ResolvedDirective;
219
+ /**
220
+ * Reads a component's `children` prop back as plain text. `render.tsx`
221
+ * always hands most standard components (every one except `row`, `tabs`,
222
+ * `details`) an already-flattened STRING as `children` — see `render.tsx`'s
223
+ * top comment on why those three are the only ones that get a real Ink
224
+ * element tree instead. `children` is still typed `ReactNode` on
225
+ * `AnsiComponentProps` (the honest public contract: "an Ink element tree",
226
+ * per the batch-10 brief, and a string IS a valid `ReactNode`), so a
227
+ * component that needs its body AS TEXT (to measure it, frame it, indent
228
+ * it, or check whether it is empty) reads it through this helper rather
229
+ * than assuming the type; a non-string `children` degrades to `''` rather
230
+ * than throwing, matching this package's never-throw posture everywhere
231
+ * else.
232
+ */
233
+ export declare function childrenText(children: ReactNode): string;
package/dist/registry.js CHANGED
@@ -1,12 +1,3 @@
1
- /**
2
- * The registry contract for the terminal engine: the string-emitting twin of
3
- * `@markii/html`'s `registry.ts`, itself the string-emitting twin of
4
- * `@markii/react`'s `registry.ts`. A component here is a plain function from
5
- * attributes and already-rendered children TEXT to an output string — no
6
- * hast, no React, no HTML. The alias, merge, and hostile-configuration rules
7
- * are kept identical to both existing renderers, so a note resolves the same
8
- * way in all three.
9
- */
10
1
  /** The symbol an alias table hangs off a registry under. Mirrors `@markii/html`'s `REGISTRY_ALIASES`. */
11
2
  export const REGISTRY_ALIASES = Symbol('markii.ansi.registry.aliases');
12
3
  /** Reads a registry's alias table, or `undefined` if it has none. Returned as-is; treat as read-only. */
@@ -119,3 +110,20 @@ export function resolveDirectiveAlias(registry, name, attributes) {
119
110
  attributes: mergeAliasAttributes(alias.attributes, attributes),
120
111
  };
121
112
  }
113
+ /**
114
+ * Reads a component's `children` prop back as plain text. `render.tsx`
115
+ * always hands most standard components (every one except `row`, `tabs`,
116
+ * `details`) an already-flattened STRING as `children` — see `render.tsx`'s
117
+ * top comment on why those three are the only ones that get a real Ink
118
+ * element tree instead. `children` is still typed `ReactNode` on
119
+ * `AnsiComponentProps` (the honest public contract: "an Ink element tree",
120
+ * per the batch-10 brief, and a string IS a valid `ReactNode`), so a
121
+ * component that needs its body AS TEXT (to measure it, frame it, indent
122
+ * it, or check whether it is empty) reads it through this helper rather
123
+ * than assuming the type; a non-string `children` degrades to `''` rather
124
+ * than throwing, matching this package's never-throw posture everywhere
125
+ * else.
126
+ */
127
+ export function childrenText(children) {
128
+ return typeof children === 'string' ? children : '';
129
+ }
package/dist/render.d.ts CHANGED
@@ -1,43 +1,76 @@
1
+ import type { ReactElement, ReactNode } from 'react';
1
2
  import { parse } from '@markii/core';
2
3
  import type { MarkNode } from '@markii/core';
3
4
  import { type ColorOption } from './ansi.js';
4
5
  import { type AnsiTheme } from './theme.js';
5
6
  import type { AnsiRegistry } from './registry.js';
6
- import { type OnDiagnostic } from '@markii/stdlib';
7
+ import { type OnDiagnostic, type UnavailableComponent } from '@markii/stdlib';
7
8
  import { type ResolveImageSrc } from './image-resolve.js';
8
9
  import { type ResolveHref } from './href-resolve.js';
9
10
  import type { AnsiValueStore, AnsiVaultStore } from './value-types.js';
11
+ import { type BoxStyle } from './glyphs.js';
10
12
  type MarkRoot = ReturnType<typeof parse>;
13
+ export interface ElementTabPanel {
14
+ label: string;
15
+ body: ReactNode;
16
+ }
11
17
  /**
12
18
  * Options for `renderMarkToAnsi`/`renderMarkNodeToAnsi`/`renderMarkInlineToAnsi`.
13
19
  * `store`/`vault` are offered both here and as positional parameters; when
14
- * both are given, the option wins (matching `@markii/html`'s
15
- * `RenderMarkOptions`).
20
+ * both are given, the option wins.
16
21
  */
17
22
  export interface RenderMarkOptions {
18
23
  readonly width?: number;
19
24
  readonly color?: ColorOption;
20
25
  readonly theme?: AnsiTheme;
26
+ /**
27
+ * `'unicode'` (the default) draws frames, rules, bars, and markers with
28
+ * box-drawing and symbol characters; `'ascii'` draws every one of them
29
+ * with 7-bit characters, for a terminal that cannot show the others. The
30
+ * engine never chooses this from the environment: the host does.
31
+ */
32
+ readonly box?: BoxStyle;
21
33
  readonly resolveImageSrc?: ResolveImageSrc;
22
34
  readonly resolveHref?: ResolveHref;
23
35
  readonly onDiagnostic?: OnDiagnostic;
36
+ /**
37
+ * Components of installed packs that this render cannot draw, as plain
38
+ * data from the host. A directive named here renders the usual fallback
39
+ * with the label "no terminal view for" instead of "unknown component",
40
+ * and `onDiagnostic` gets a `'no-engine-view'` event. Omitted, the render
41
+ * is unchanged.
42
+ */
43
+ readonly unavailableComponents?: readonly UnavailableComponent[];
24
44
  readonly store?: AnsiValueStore;
25
45
  readonly vault?: AnsiVaultStore;
46
+ /**
47
+ * Renders the document's CONTENT in interactive shape (tabs show only
48
+ * their active panel, details start closed unless `open`) without
49
+ * actually mounting a live keyboard loop — this render-once path always
50
+ * captures exactly one frame (`ink-string.ts`'s own `interactive: false`
51
+ * Ink render option is a SEPARATE thing; see its doc comment for the
52
+ * name collision). Defaults to `false`: unset, `tabs`/`details` render
53
+ * every panel/always-open exactly as the pre-Ink engine did.
54
+ */
55
+ readonly interactive?: boolean;
56
+ /**
57
+ * `buildMarkElement` only: the terminal's row count. Gives the live view
58
+ * a viewport of this many rows minus its one-row status line, scrolled
59
+ * with the keys in the legend. Omitted, the live view is laid out at its
60
+ * full height. The render-once string path never reads it.
61
+ */
62
+ readonly viewportRows?: number;
26
63
  }
27
64
  /**
28
65
  * Renders Markii text to a plain string (optionally carrying ANSI SGR/OSC 8
29
66
  * escapes) using `registry` to resolve directive names. `registry` is
30
67
  * OPTIONAL here, unlike the other two engines' required parameter, and
31
- * defaults to `defaultAnsiRegistry` (empty in this phase; every directive
32
- * therefore renders the unknown-component fallback).
68
+ * defaults to `defaultAnsiRegistry`.
33
69
  *
34
- * Pipeline: `@markii/core`'s `toHast` (parse -> tag directive nodes ->
35
- * remark-rehype -> sanitize URLs) -> a width-aware hast walk that swaps
36
- * directive elements for registry components (or the unknown-directive
37
- * fallback), folds script fences into a one-line marker, and wraps every
38
- * paragraph, heading, and list item to `options.width` (default 80). Pure
39
- * and never-throwing: parsing is tolerant, unknown names always render a
40
- * fallback, and any unexpected internal error degrades to the "failed to
70
+ * `async` since the first call in a process pays Ink/Yoga's one-time module-
71
+ * evaluation cost (`ink-string.ts`'s doc comment; `SPIKE-10-findings.md`'s
72
+ * "Item 3"). Never throws: parsing is tolerant, unknown names always render
73
+ * a fallback, and any unexpected internal error degrades to the "failed to
41
74
  * render document" line.
42
75
  *
43
76
  * `options.color` resolves via `./ansi.js`'s `resolveColorOption`: `'auto'`
@@ -45,25 +78,30 @@ export interface RenderMarkOptions {
45
78
  * environment knowledge of its own — a caller that wants automatic
46
79
  * detection calls `detectColorLevel` itself and passes the result as
47
80
  * `'16'`/`'256'`/`'truecolor'`.
48
- *
49
- * `store`/`vault` and `resolveImageSrc`/`resolveHref`/`onDiagnostic` carry
50
- * the same meaning as `@markii/html`'s identical options.
51
81
  */
52
- export declare function renderMarkToAnsi(text: string, registry?: AnsiRegistry, store?: AnsiValueStore, vault?: AnsiVaultStore, options?: RenderMarkOptions): string;
82
+ export declare function renderMarkToAnsi(text: string, registry?: AnsiRegistry, store?: AnsiValueStore, vault?: AnsiVaultStore, options?: RenderMarkOptions): Promise<string>;
53
83
  /**
54
84
  * The block-level twin of `renderMarkToAnsi`: renders one already-parsed
55
- * mdast node OR a whole already-parsed mdast document (`@markii/core`'s
56
- * `MarkNode`, or the `Root` `parse` itself returns) instead of raw document
57
- * text. Same registry resolution, same fallbacks, same purity and
85
+ * mdast node OR a whole already-parsed mdast document instead of raw
86
+ * document text. Same registry resolution, same fallbacks, same purity and
58
87
  * never-throw guarantees, same options.
59
88
  */
60
- export declare function renderMarkNodeToAnsi(node: MarkNode | MarkRoot, registry?: AnsiRegistry, store?: AnsiValueStore, vault?: AnsiVaultStore, options?: RenderMarkOptions): string;
89
+ export declare function renderMarkNodeToAnsi(node: MarkNode | MarkRoot, registry?: AnsiRegistry, store?: AnsiValueStore, vault?: AnsiVaultStore, options?: RenderMarkOptions): Promise<string>;
61
90
  /**
62
91
  * Renders `text` as a single, standalone inline directive when that is all
63
- * it is, mirroring `@markii/html`'s identical `renderMarkInlineToHtml`: a
64
- * source whose only parsed block is a paragraph holding exactly one text
65
- * directive renders that directive alone. Any other source falls back to
66
- * the exact same rendering `renderMarkToAnsi` would produce.
92
+ * it is. Any other source falls back to the exact same rendering
93
+ * `renderMarkToAnsi` would produce.
94
+ */
95
+ export declare function renderMarkInlineToAnsi(text: string, registry?: AnsiRegistry, store?: AnsiValueStore, vault?: AnsiVaultStore, options?: RenderMarkOptions): Promise<string>;
96
+ /**
97
+ * The live-viewer entry point (phase 3 consumes this): builds the same Ink
98
+ * element tree `renderMarkToAnsi` would render to a string, but returns the
99
+ * element itself so a host (the CLI's `markii view`) can mount it directly
100
+ * with Ink's own `render()` instead of re-rendering a string on every
101
+ * keystroke/resize. `document` accepts raw text OR an already-parsed mdast
102
+ * node/root, mirroring the three string entry points' flexibility.
67
103
  */
68
- export declare function renderMarkInlineToAnsi(text: string, registry?: AnsiRegistry, store?: AnsiValueStore, vault?: AnsiVaultStore, options?: RenderMarkOptions): string;
104
+ export declare function buildMarkElement(document: string | MarkNode | MarkRoot, registry?: AnsiRegistry, options?: RenderMarkOptions & {
105
+ readonly onExit?: () => void;
106
+ }): ReactElement;
69
107
  export {};