@valyrianjs/terminal 0.1.1 → 0.2.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 (107) hide show
  1. package/README.md +105 -55
  2. package/dist/ansi.d.ts +20 -4
  3. package/dist/ansi.d.ts.map +1 -1
  4. package/dist/ansi.js +171 -47
  5. package/dist/ansi.js.map +1 -1
  6. package/dist/editor-state.d.ts +22 -0
  7. package/dist/editor-state.d.ts.map +1 -0
  8. package/dist/editor-state.js +110 -0
  9. package/dist/editor-state.js.map +1 -0
  10. package/dist/events.d.ts +1 -4
  11. package/dist/events.d.ts.map +1 -1
  12. package/dist/events.js +15 -38
  13. package/dist/events.js.map +1 -1
  14. package/dist/index.d.ts +5 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/keymap.d.ts +7 -0
  19. package/dist/keymap.d.ts.map +1 -0
  20. package/dist/keymap.js +133 -0
  21. package/dist/keymap.js.map +1 -0
  22. package/dist/layout.d.ts +10 -1
  23. package/dist/layout.d.ts.map +1 -1
  24. package/dist/layout.js +97 -7
  25. package/dist/layout.js.map +1 -1
  26. package/dist/mouse.d.ts +1 -0
  27. package/dist/mouse.d.ts.map +1 -1
  28. package/dist/mouse.js +24 -1
  29. package/dist/mouse.js.map +1 -1
  30. package/dist/output-writer.d.ts +9 -0
  31. package/dist/output-writer.d.ts.map +1 -0
  32. package/dist/output-writer.js +79 -0
  33. package/dist/output-writer.js.map +1 -0
  34. package/dist/paste.d.ts +7 -0
  35. package/dist/paste.d.ts.map +1 -0
  36. package/dist/paste.js +18 -0
  37. package/dist/paste.js.map +1 -0
  38. package/dist/primitives.d.ts +15 -3
  39. package/dist/primitives.d.ts.map +1 -1
  40. package/dist/primitives.js +9 -1
  41. package/dist/primitives.js.map +1 -1
  42. package/dist/render.d.ts +9 -4
  43. package/dist/render.d.ts.map +1 -1
  44. package/dist/render.js +923 -68
  45. package/dist/render.js.map +1 -1
  46. package/dist/runtime.d.ts +29 -0
  47. package/dist/runtime.d.ts.map +1 -0
  48. package/dist/runtime.js +209 -0
  49. package/dist/runtime.js.map +1 -0
  50. package/dist/scheduler.d.ts +8 -0
  51. package/dist/scheduler.d.ts.map +1 -0
  52. package/dist/scheduler.js +24 -0
  53. package/dist/scheduler.js.map +1 -0
  54. package/dist/session.d.ts.map +1 -1
  55. package/dist/session.js +858 -199
  56. package/dist/session.js.map +1 -1
  57. package/dist/stream-log.d.ts +40 -0
  58. package/dist/stream-log.d.ts.map +1 -0
  59. package/dist/stream-log.js +73 -0
  60. package/dist/stream-log.js.map +1 -0
  61. package/dist/text.d.ts +3 -0
  62. package/dist/text.d.ts.map +1 -0
  63. package/dist/text.js +19 -0
  64. package/dist/text.js.map +1 -0
  65. package/dist/theme.d.ts +7 -0
  66. package/dist/theme.d.ts.map +1 -0
  67. package/dist/theme.js +254 -0
  68. package/dist/theme.js.map +1 -0
  69. package/dist/tree.d.ts +2 -0
  70. package/dist/tree.d.ts.map +1 -1
  71. package/dist/tree.js +42 -1
  72. package/dist/tree.js.map +1 -1
  73. package/dist/types.d.ts +203 -24
  74. package/dist/types.d.ts.map +1 -1
  75. package/docs/api-reference.md +313 -142
  76. package/docs/assets/quick-note.svg +13 -0
  77. package/docs/cookbook.md +296 -201
  78. package/docs/core-concepts.md +143 -55
  79. package/docs/getting-started.md +209 -90
  80. package/docs/interaction-model.md +98 -54
  81. package/docs/primitive-gallery.md +370 -0
  82. package/docs/session-runtime.md +131 -362
  83. package/docs/valyrian-modules.md +3196 -0
  84. package/llms-full.txt +5377 -0
  85. package/package.json +21 -8
  86. package/src/ansi.ts +269 -0
  87. package/src/clipboard.ts +76 -0
  88. package/src/editor-state.ts +162 -0
  89. package/src/events.ts +163 -0
  90. package/src/index.ts +95 -0
  91. package/src/keymap.ts +151 -0
  92. package/src/layout.ts +282 -0
  93. package/src/mouse.ts +68 -0
  94. package/src/output-writer.ts +93 -0
  95. package/src/paste.ts +23 -0
  96. package/src/primitives.ts +55 -0
  97. package/src/render.ts +1204 -0
  98. package/src/runtime.ts +267 -0
  99. package/src/scheduler.ts +33 -0
  100. package/src/session.ts +1408 -0
  101. package/src/stream-log.ts +96 -0
  102. package/src/text.ts +20 -0
  103. package/src/theme.ts +263 -0
  104. package/src/tree.ts +169 -0
  105. package/src/types.ts +541 -0
  106. package/tsconfig.json +4 -7
  107. package/docs/local-demo.md +0 -28
@@ -1,273 +1,444 @@
1
1
  # API Reference
2
2
 
3
- Reference for the actual public surface published by `valyrianjs-terminal`.
3
+ Reference for the public surface published by `@valyrianjs/terminal`. For a guided first project, start with [Getting Started](./getting-started.md). For practical primitive selection, use [Primitive Gallery](./primitive-gallery.md).
4
4
 
5
- ## Published Entrypoints
5
+ ## Published entrypoints
6
6
 
7
- ### `valyrianjs-terminal`
7
+ ### `@valyrianjs/terminal`
8
8
 
9
- Main entrypoint. At a high level, it exposes:
9
+ Main entrypoint for terminal primitives, rendering, sessions, props, payloads, and types.
10
10
 
11
- - `renderTerminal()`
12
- - `mountTerminal()`
13
- - primitives `Screen`, `Box`, `View`, `Text`, `Input`, `Button`, `ScrollView`, `List`, `Table`, `Row`, `Td`
14
- - prop, event, node, and session types
11
+ Common imports:
15
12
 
16
- ### `valyrianjs-terminal/render`
13
+ ```tsx
14
+ import { Screen, Text, mountTerminal, renderTerminal } from "@valyrianjs/terminal";
15
+ ```
17
16
 
18
- Published subpath for lower-level rendering utilities.
17
+ ### `@valyrianjs/terminal/render`
19
18
 
20
- - `renderTerminal(input): string`
21
- - `renderTerminalNode(node): string`
22
- - `renderTerminalFrame(node): TerminalFrame`
19
+ Rendering-only subpath for lower-level rendering utilities:
23
20
 
24
- Use this subpath when you only need to transform terminal nodes into text or a `TerminalFrame`, without mounting an interactive session.
21
+ - `renderTerminal(input, context?): string`
22
+ - `renderTerminalNode(node, context?): string`
23
+ - `renderTerminalFrame(node, context?): TerminalFrame`
25
24
 
26
- ## Main Functions
25
+ Use this subpath for rendering-focused integrations that produce output without mounting an interactive session.
27
26
 
28
- ### `renderTerminal(input): string`
27
+ ## Root exports overview
29
28
 
30
- Resolves the provided root and returns terminal output as plain text.
29
+ The root entrypoint exports the public primitives (`Screen`, `Box`, `View`, `Pane`, `Split`, `Fixed`, `Overlay`, `FocusScope`, `Text`, `Input`, `Editor`, `Button`, `List`, `ScrollView`, `LogView`, `Table`, `Row`, and `Td`), the main functions `renderTerminal()` and `mountTerminal()`, public prop and payload types, keymap helpers, and theme helpers.
31
30
 
32
- Use cases supported by the current implementation:
31
+ ## Main functions
33
32
 
34
- - snapshots and tests
35
- - layout validation without `stdin` or `stdout`
36
- - content inspection in non-interactive mode
33
+ ### `renderTerminal(input, context?): string`
37
34
 
38
- Notes:
35
+ Resolves the provided terminal tree and returns plain text. Pass `{ cols, rows }` when the root tree uses viewport-dependent primitives such as standalone `Overlay` with `margin` or standalone `Fixed`.
39
36
 
40
- - concatenates root nodes with newlines
41
- - removes only trailing whitespace with `trimEnd()`
42
- - does not create listeners or interactive state
37
+ Use it for:
38
+
39
+ - snapshots
40
+ - static examples
41
+ - non-interactive command output
42
+ - layout checks without session state
43
+
44
+ `context` accepts exact terminal dimensions as positive integers and an optional theme: `{ cols, rows, theme? }`. Mounted sessions infer dimensions from `mountTerminal()` options or the host terminal.
43
45
 
44
46
  ### `mountTerminal(input, options?): TerminalSession`
45
47
 
46
- Mounts an interactive session on the terminal tree and returns a `TerminalSession`.
48
+ Creates an interactive session around a terminal tree.
47
49
 
48
- High-level behavior:
50
+ The session can:
49
51
 
50
- - resolves the current tree and re-renders it with `session.update()`
51
- - manages focus by `id`
52
- - handles keyboard, mouse, selection, and clipboard interaction
53
- - can write to `stdout` automatically when provided
54
- - if it receives `stdin`, it enables raw mode on mount and restores it in `destroy()`
52
+ - rerender with `update()`
53
+ - preserve and move focus
54
+ - dispatch keyboard input
55
+ - handle mouse and coordinate interaction
56
+ - use clipboard integration
57
+ - write ANSI diffs to `stdout` in app runtime
58
+ - clean up connected streams with `destroy()`
55
59
 
56
60
  ## `TerminalMountOptions`
57
61
 
58
- - `ansi?: boolean` - if `stdout` is present, writes ANSI diffs instead of plain text
59
- - `clipboard?: TerminalClipboardAdapter | false` - custom adapter or disables the system clipboard
60
- - `stdin?` - stream with `on("data")`; `off()`, `removeListener()`, `setRawMode()`, `resume()`, and `pause()` are optional
61
- - `stdout?` - writer with `write(chunk: string)`
62
+ - `runtime?: "app" | "headless"` - selects real app output or scriptable plain output. Omitted runtime becomes app mode for interactive TTY hosts and headless in non-TTY/CI contexts.
63
+ - `alternateScreen?: boolean` - enters alternate screen mode and restores it on destroy by default. Real interactive app mode enables it by default unless overridden.
64
+ - `hideCursor?: boolean` - hides the terminal cursor and restores it on destroy by default. Real interactive app mode enables it by default unless overridden.
65
+ - `restoreOnDestroy?: boolean` - controls restore behavior for cursor and alternate screen state.
66
+ - `clipboard?: TerminalClipboardAdapter | false` - custom clipboard adapter or disabled external clipboard integration.
67
+ - `cols?: number` - initial terminal width in columns.
68
+ - `rows?: number` - initial terminal height in rows.
69
+ - `stdin?` - input stream with `on("data")`; cleanup and raw-mode methods are optional.
70
+ - `stdout?` - output stream with `write(chunk)`; optional dimensions, resize events, and drain events are used when supported.
71
+ - `theme?` - terminal theme for semantic style spans.
72
+ - `keymap?` - custom key bindings for built-in terminal interaction behavior.
73
+
74
+ If no explicit dimensions or stream dimensions are available, sessions default to `80x24`. Dimensions must be positive integers.
75
+
76
+ `hideCursor` and `restoreOnDestroy` describe cursor and terminal-restore intent for sessions connected to compatible hosts. Cursor restore follows the connected terminal and stream capabilities. Run `bun examples/docs/cursor.tsx`, type text, press `C`, and quit with `Ctrl+C`; or open [`examples/docs/cursor.tsx`](../examples/docs/cursor.tsx).
77
+
78
+ ## Keymap helpers
79
+
80
+ - `defaultTerminalKeyBindings` - built-in key bindings for focus traversal, editing, lists, buttons, and scroll views.
81
+ - `createTerminalKeyBindings(bindings?)` - returns a normalized binding list that can extend or replace default behavior.
82
+ - `createResolvedTerminalKeymap(options?)` - creates a keymap object used by sessions.
83
+ - `resolveTerminalKeyBinding(key, context, keymap)` - resolves a normalized key against a context.
84
+ - `validateTerminalKeyBindings(bindings)` - validates key binding shape and rejects ambiguous entries.
85
+
86
+ Use `keymap` in `TerminalMountOptions` when an app needs custom keyboard behavior while keeping predictable focus and primitive events.
87
+
88
+ ## Theme helpers
89
+
90
+ - `defaultTerminalTheme` - bundled app-like recipes for common controls.
91
+ - `highContrastTerminalTheme` - alternate recipes with stronger contrast.
92
+ - `mergeTerminalTheme(base, override)` - combines theme recipes and span tokens.
93
+ - `resolveTerminalStyle(style, theme?)` - resolves dot path recipes or inline style objects.
94
+ - `resolveTerminalStyleToken(kind, theme?)` - resolves semantic span tokens for ANSI/plain serialization.
95
+
96
+ Theme recipes belong in `theme.styles`. Use `color`, `background`, padding, and border values with hex colors for normal app styling.
97
+
98
+ ## Visual style system
99
+
100
+ `theme.styles` stores named style recipes. A recipe may define color, background, padding, border, and nested visual-state recipes. The renderer applies `theme.styles.<element>.base` automatically to public primitives that have a matching `.base` recipe, before any instance `style`. The bundled default theme uses that rule for app-like core controls such as `button.base`, `button.focus`, `input.base`, `input.focus`, `input.selection`, `list.base`, `list.current`, `list.selected`, `list.hover`, and `list.empty`. Components also resolve recipes by dot path, so `style="panel.queue"` reads `theme.styles.panel.queue`. Inline style objects work too when the style belongs to one component instance.
101
+
102
+ Use `style`, `styles`, and `state` for normal component styling:
103
+
104
+ - `style` sets the base recipe or inline style for the component frame.
105
+ - `styles` maps visual states to dot path recipes or inline style objects.
106
+ - `state` declares app-owned states such as `loading`, `warning`, `success`, `muted`, `expanded`, or `dropTarget`.
107
+
108
+ Renderer-owned states come from the runtime when the renderer has the fact itself. Focus, hover, selection, current rows, and pointer capture fall in this group when the primitive supports them. App-owned state should describe product state that the app already knows. Do not mark a ready button as `loading` or an editable field as `readonly`; that teaches a lie to the UI and then the UI repeats it with confidence.
109
+
110
+ Precedence: the renderer starts with the automatic `<element>.base` recipe when the primitive has one, applies the instance `style`, then applies `styles` entries for current states in stable visual-state order. Geometry fields such as supported padding and border come from the automatic base recipe plus the instance `style` so layout, hitboxes, and cursors stay stable across focus, hover, and pressed state changes. State styles affect the rendered spans after layout; later current states override earlier visual fields when they set the same property. Inline style objects and dot path recipes use the same merge path after resolution.
111
+
112
+ Renderer notes:
113
+
114
+ - Raw ANSI escape control is not the normal public styling API. Use semantic styles and let `ansiOutput()` serialize frames.
115
+ - Layout margin is not supported; use padding, `gap`, `Fixed`, `Split`, or explicit text spacing.
116
+ - The renderer owns terminal frame spans, clipping, focus, and selection; the app owns business state and labels.
117
+
118
+ Run `bun examples/docs/style-system.tsx`, try `Tab`, `Enter`, and `W`, and quit with `Ctrl+C`; or open [`examples/docs/style-system.tsx`](../examples/docs/style-system.tsx). Run `bun examples/docs/theme-colors.tsx`, press `Tab`, and quit with `Ctrl+C`; or open [`examples/docs/theme-colors.tsx`](../examples/docs/theme-colors.tsx).
119
+
120
+ ### TerminalStyleSpan
121
+
122
+ `TerminalStyleSpan` is a low-level frame API for renderer integrations and frame serialization. It describes a styled range in a rendered frame and may carry `kind`, coordinates, and `style?` when the renderer resolves an inline style object. App components get their everyday styling surface from semantic styles.
123
+
124
+ Use `style`, `styles`, and `state` for component styling. Use `TerminalStyleSpan` when a low-level frame integration needs styled ranges after render.
125
+
126
+ ### Advanced: span serialization tokens
127
+
128
+ `ansiOpen`, `ansiClose`, `plainPrefix`, and `plainSuffix` are low-level fields for trusted renderer integrations that already own frame spans and need exact serialization behavior. Application components get their styling API from semantic styles.
129
+
130
+ Apps should prefer `theme.styles`, `style`, `styles`, `state`, `color`, `background`, and hex colors. Those fields keep styling semantic, portable, and safe for both `output()` and `ansiOutput()`. When a token defines `color`, `background`, or `style`, ANSI serialization uses the resolved style fields before raw ANSI fallback tokens.
131
+
132
+ Token behavior:
133
+
134
+ - `ansiOpen` writes a raw ANSI opening sequence around the span in ANSI output when no `color`, `background`, or `style` field supplies a safer style.
135
+ - `ansiClose` writes the matching raw ANSI close sequence in ANSI output for the same low-level case.
136
+ - `plainPrefix` adds text before the span only in plain output.
137
+ - `plainSuffix` adds text after the span only in plain output.
138
+
139
+ Prefer semantic styles first: `theme.styles`, `style`, `styles`, `state`, hex `color`, and `background` keep output portable across plain and ANSI render paths. Use raw ANSI tokens for trusted low-level integrations that own frame serialization. Keep token input trusted, pair open and close tokens exactly, verify both `output()` and `ansiOutput()`, and document the integration reason when semantic hex style does not cover the serialization requirement.
140
+
141
+ ## Layout primitives
142
+
143
+ Use [Primitive Gallery](./primitive-gallery.md) for practical composition examples, including [`examples/docs/primitive-layout-shell.tsx`](../examples/docs/primitive-layout-shell.tsx), [`examples/docs/primitive-input-workbench.tsx`](../examples/docs/primitive-input-workbench.tsx), [`examples/docs/primitive-data-explorer.tsx`](../examples/docs/primitive-data-explorer.tsx), [`examples/docs/primitive-activity-console.tsx`](../examples/docs/primitive-activity-console.tsx), and [`examples/docs/primitive-command-panel.tsx`](../examples/docs/primitive-command-panel.tsx). Run them with `bun examples/docs/primitive-layout-shell.tsx`, `bun examples/docs/primitive-input-workbench.tsx`, `bun examples/docs/primitive-data-explorer.tsx`, `bun examples/docs/primitive-activity-console.tsx`, or `bun examples/docs/primitive-command-panel.tsx`; quit with `Ctrl+C`. Use API Reference for prop-level details.
62
144
 
63
- ## Layout Primitives
64
145
 
65
146
  ### `Screen`
66
147
 
67
- `TerminalScreenProps` props:
148
+ Props:
68
149
 
69
150
  - `title?: string`
70
151
 
71
- Role: root container. If `title` exists, it renders as the first line of the frame.
152
+ Root container. If `title` is present, it renders as the first line. In a mounted session or render call with dimensions, `Screen` passes the available viewport context to children.
72
153
 
73
154
  ### `Box`
74
155
 
75
- `TerminalBoxProps` props:
156
+ Props:
76
157
 
77
158
  - `direction?: "row" | "column"`
78
159
  - `gap?: number`
79
- - `padding?: number`
80
- - `border?: boolean`
160
+ - `padding?: number | { x?: number; y?: number; top?: number; right?: number; bottom?: number; left?: number }`
161
+ - `style?: string | TerminalStyleDefinition`
162
+ - `styles?: Partial<Record<TerminalVisualState, string | TerminalStyleDefinition>>`
163
+ - `state?: TerminalVisualState | TerminalVisualState[]`
81
164
  - `width?: number`
82
165
  - `height?: number`
166
+ - `fill?: boolean`
83
167
  - `id?: string`
84
168
  - `focusable?: boolean`
85
169
 
86
- Role: layout container. In `row`, it composes horizontally; in `column`, vertically.
170
+ Layout container. `Box`, `View`, and `Pane` behave like block elements in a sized context: they use available width by default and keep content height by default, so stacked containers do not all become full-height. Numeric dimensions constrain the final frame and explicit `width` or `height` wins over context defaults. Use `fill` when a surface should consume the full available height as well as width. Put background fill, border, and padding in `style` or a `theme.styles` recipe. Margin is not supported; compose spacing with layout, padding, and explicit text when needed.
87
171
 
88
172
  ### `View`
89
173
 
90
- `TerminalViewProps` props:
174
+ Props: layout props from `Box`, plus `role?: string`.
91
175
 
92
- - all layout props from `Box`
93
- - `role?: string`
176
+ Semantic layout container with the same sizing behavior as `Box`.
94
177
 
95
- Role: semantic container equivalent to `terminal-view`.
178
+ ### `Pane`
96
179
 
97
- ### `Text`
180
+ Props: layout props from `Box`.
98
181
 
99
- `TerminalTextProps` props:
182
+ Named layout boundary for composing terminal regions.
100
183
 
101
- - `value?: any`
184
+ ### `Split`
185
+
186
+ Props:
187
+
188
+ - `direction?: "row" | "column"`
189
+ - `width?: number`
190
+ - `height?: number`
191
+ - `fill?: boolean`
192
+ - `sizes?: Array<number | `${number}%` | `${number}fr`>`
193
+ - `breakpoints?: Array<{ maxCols?: number; maxRows?: number; direction?: "row" | "column"; sizes?: TerminalSplitSize[]; gap?: number }>`
194
+ - `gap?: number`
195
+ - `id?: string`
196
+ - `focusable?: boolean`
197
+
198
+ Split layout. Split uses the available render area when width and height are omitted inside a sized context. In `row`, it divides width; in `column`, it divides height. `sizes` may mix absolute numbers, percentages, and `fr` units. Percentages and fractions use the available axis after gaps. Rounding is deterministic: floor the ideal sizes, then give remaining cells to the largest fractional remainders with index order as the tie breaker. Breakpoints are local to the resolved split width and height, and the first matching breakpoint wins. Run `bun examples/docs/responsive-split.tsx`, resize the terminal to change the layout, and quit with `Ctrl+C`; or open [`examples/docs/responsive-split.tsx`](../examples/docs/responsive-split.tsx).
199
+
200
+ ## Visual states
201
+
202
+ State families:
203
+
204
+ | Family | States |
205
+ | --- | --- |
206
+ | Common | `focus`, `hover`, `disabled`, `loading` |
207
+ | Activation/controls | `pressed`, `checked`, `unchecked`, `indeterminate` |
208
+ | Selection/navigation | `selected`, `current`, `expanded`, `collapsed` |
209
+ | Entry/text | `invalid`, `valid`, `readonly`, `placeholder`, `selection`, `editing`, `submitted` |
210
+ | Data/content | `empty`, `error`, `warning`, `success`, `muted` |
211
+ | Pointer/capture/composition | `dragging`, `dropTarget`, `capturing` |
212
+
213
+ Buttons, inputs, editors, lists, tables, panes, boxes, overlays, scroll views, log views, and text can use `style`, `styles`, and `state` where the style affects their rendered frame. Use renderer-owned states such as focus or selection when the component knows them, and use `state` for app-owned statuses such as loading, warning, success, dragging, or drop target.
102
214
 
103
- Role: renders `value` or the concatenated text from its children. If there are line breaks, they are preserved.
215
+ Shared visual props for styled primitives:
104
216
 
105
- ### `Table`
217
+ - `style?: string | TerminalStyleDefinition` - base style recipe or inline style.
218
+ - `styles?: Partial<Record<TerminalVisualState, string | TerminalStyleDefinition>>` - visual-state style map.
219
+ - `state?: TerminalVisualState | TerminalVisualState[]` - app-owned visual state or states.
106
220
 
107
- `TerminalTableProps` props:
221
+ ### `Fixed`
108
222
 
109
- - `v-for?: any[]`
223
+ Props:
110
224
 
111
- Role: composes rows and automatically calculates the maximum width for each column.
225
+ - `position: "top" | "bottom" | "left" | "right"`
226
+ - `size: number`
112
227
 
113
- ### `Row`
228
+ Reserves stable rows or columns at a frame edge. When `Fixed` is a direct child of `Screen` or `Pane`, that parent supplies the frame and consumes the fixed region before it lays out the remaining content. When `Fixed` is rendered as the root tree passed directly to `renderTerminal()`, it is viewport-dependent and the render call must pass exact dimensions with `{ cols, rows }`. Mounted sessions get those dimensions from `mountTerminal()` options or the host terminal.
114
229
 
115
- `TerminalRowProps` props:
230
+ ### `Overlay`
116
231
 
117
- - `separator?: string`
232
+ Props:
118
233
 
119
- Role: joins cells using `separator` or `" | "` by default.
234
+ - `margin: number | "<number>%" | { x: number | "<number>%"; y: number | "<number>%" }`
235
+ - shared visual props: `style`, `styles`, `state`
236
+ - `trapFocus?: boolean`
237
+ - `id?: string`
238
+ - `focusable?: boolean`
239
+
240
+ Draws a clipped region over the current frame. `margin` sets the distance from the overlay to the frame edges; numbers use cells and percentage strings such as `"10%"` resolve per axis. Use `{ x, y }` when the two axes need different margins. `trapFocus` keeps traversal inside the overlay while it is active.
241
+
242
+ Overlay calculates its size from the available frame, stays centered by its margins, and keeps app routing and pane movement in your app layer.
243
+
244
+ ### `FocusScope`
245
+
246
+ Props:
120
247
 
121
- ### `Td`
248
+ - `active?: boolean`
122
249
 
123
- `TerminalTdProps` props:
250
+ Bounds sequential focus traversal to descendants when focus is already inside the scope.
124
251
 
125
- - `padding?: number`
252
+ ### `Text`
253
+
254
+ Props:
255
+
256
+ - `value?: any`
257
+ - shared visual props: `style`, `styles`, `state`
258
+
259
+ Renders `value` or child text. Line breaks are preserved.
126
260
 
127
- Role: wraps cell content and applies internal padding when defined.
261
+ ### `Table`, `Row`, and `Td`
128
262
 
129
- ## Interactive Primitives
263
+ `Table` composes rows and calculates column widths. `Row` joins cells with `separator?: string`. `Td` supports `padding?: number` and shared visual props: `style`, `styles`, `state`.
130
264
 
131
- All of them depend on `id` to fully participate in focus, hitboxes, coordinate lookup, and several `TerminalSession` helpers.
265
+ ## Interactive primitives
132
266
 
133
267
  ### `Input`
134
268
 
135
- `TerminalInputProps` props:
269
+ Props:
136
270
 
137
271
  - `id?: string`
138
272
  - `focusable?: boolean`
139
273
  - `value?: string`
140
274
  - `placeholder?: string`
275
+ - shared visual props: `style`, `styles`, `state`
141
276
  - `onchange?(event)`
142
277
  - `oninput?(event)`
143
278
  - `onsubmit?(event)`
144
- - `onChangeText?(value)`
145
-
146
- Current interaction support:
279
+ - `oncontextpress?(event)`
147
280
 
148
- - cursor movement and text selection
149
- - `LEFT`, `RIGHT`, `SHIFT_LEFT`, `SHIFT_RIGHT`
150
- - `ALT_LEFT`, `ALT_RIGHT`, `HOME`, `END`
151
- - `CTRL_A`, `CTRL_C`, `CTRL_X`, `CTRL_V`
152
- - `BACKSPACE`, `DELETE`, character input, and `ENTER`
153
-
154
- Important payloads:
281
+ Payloads:
155
282
 
156
283
  - `TerminalInputChangeEventPayload` - `{ type: "change" | "input", id, value }`
157
284
  - `TerminalInputSubmitEventPayload` - `{ type: "submit", id, value }`
285
+ - `TerminalInputContextPressEventPayload` - `{ type: "contextpress", id, value, cursor, x, y }`
286
+
287
+ Supports single-line editing, cursor movement, selection, copy/cut/paste, deletion, submit, and context press.
288
+
289
+ ### `Editor`
290
+
291
+ Props:
292
+
293
+ - `id?: string`
294
+ - `focusable?: boolean`
295
+ - `value?: string`
296
+ - `placeholder?: string`
297
+ - `height?: number`
298
+ - shared visual props: `style`, `styles`, `state`
299
+ - `onchange?(event)`
300
+ - `oninput?(event)`
301
+ - `onsubmit?(event)`
302
+ - `oncancel?(event)`
303
+
304
+ Payloads:
305
+
306
+ - `TerminalEditorChangeEventPayload` - `{ type: "change" | "input", id, value }`
307
+ - `TerminalEditorSubmitEventPayload` - `{ type: "submit", id, value }`
308
+ - `TerminalEditorCancelEventPayload` - `{ type: "cancel", id, value }`
309
+
310
+ Supports multiline editing, submit, cancel, cursor movement, paste, and deletion. Cursor columns use JavaScript string columns rather than a complete terminal-width model.
158
311
 
159
312
  ### `Button`
160
313
 
161
- `TerminalButtonProps` props:
314
+ Props:
162
315
 
163
316
  - `id?: string`
164
317
  - `focusable?: boolean`
165
318
  - `label?: string`
319
+ - shared visual props: `style`, `styles`, `state`
166
320
  - `onpress?(event)`
167
- - `onclick?(event)`
168
- - `action?(event)`
169
- - `onPress?(event)`
170
-
171
- Current activation paths:
321
+ - `ondoublepress?(event)`
322
+ - `oncontextpress?(event)`
172
323
 
173
- - `session.click(id?)`
174
- - `session.clickAt(x, y)`
175
- - `dispatchKey("ENTER")` or `dispatchKey("SPACE")` when focus is on the button
324
+ Payload:
176
325
 
177
- Important payload:
326
+ - `TerminalButtonPressEventPayload` - `{ type: "press" | "doublepress" | "contextpress", id }`
178
327
 
179
- - `TerminalButtonPressEventPayload` - `{ type: "press" | "click", id }`
328
+ Activation paths include focused `ENTER`, focused `SPACE`, `session.click(id)`, and `session.clickAt(x, y)`. A quick second primary mouse press still dispatches the normal activation path and also dispatches `ondoublepress` when present. A secondary mouse press dispatches `oncontextpress`.
180
329
 
181
330
  ### `List<T>`
182
331
 
183
- `TerminalListProps<T>` props:
332
+ Props:
184
333
 
185
334
  - `id?: string`
186
335
  - `focusable?: boolean`
187
336
  - `pointerCapture?: boolean`
188
337
  - `items?: T[]`
338
+ - `virtualized?: boolean`
339
+ - `itemHeight?: 1`
340
+ - `overscan?: number`
341
+ - shared visual props: `style`, `styles`, `state`
189
342
  - `renderItem?(item, index): string`
190
343
  - `onchange?(event)`
191
344
  - `onpress?(event)`
345
+ - `ondoublepress?(event)`
346
+ - `oncontextpress?(event)`
192
347
  - `onhover?(event)`
193
348
  - `onrowenter?(event)`
194
349
  - `onrowleave?(event)`
195
350
  - `oncapturestart?(event)`
196
351
  - `oncaptureend?(event)`
197
352
 
198
- Current interaction:
199
-
200
- - `UP` and `LEFT` move selection up
201
- - `DOWN` and `RIGHT` move selection down
202
- - `ENTER` triggers `onpress`
203
- - mouse hover exposes row, index, and value
204
-
205
- Important payloads:
353
+ Payloads:
206
354
 
207
355
  - `TerminalListChangeEventPayload<T>` - `{ type: "change", id, index, value }`
208
- - `TerminalListPressEventPayload<T>` - `{ type: "press", id, index, value }`
356
+ - `TerminalListPressEventPayload<T>` - `{ type: "press" | "doublepress" | "contextpress", id, index, value }`
209
357
  - `TerminalListPointerEventPayload<T>` - `{ type: "hover" | "rowenter" | "rowleave", id, row, index, value, x, y }`
210
358
  - `TerminalCaptureEventPayload` - `{ type: "capturestart" | "captureend", id, source, row, x, y }`
211
359
 
360
+ Supports selection, activation, double press on the same row, context press for the target row, hover payloads, optional virtualization, and pointer capture.
361
+
212
362
  ### `ScrollView`
213
363
 
214
- `TerminalScrollViewProps` props:
364
+ Props:
215
365
 
216
- - layout props (`direction`, `gap`, `padding`, `border`, `width`, `height`, `id`, `focusable`)
366
+ - layout props: `direction`, `gap`, `padding`, `width`, `height`, `fill`, `id`, `focusable`, `style`, `styles`, `state`
217
367
  - `pointerCapture?: boolean`
218
368
  - `highlightRows?: number[]`
219
369
  - `onhover?(event)`
220
370
  - `onrowenter?(event)`
221
371
  - `onrowleave?(event)`
372
+ - `oncontextpress?(event)`
222
373
  - `oncapturestart?(event)`
223
374
  - `oncaptureend?(event)`
224
375
 
225
- Current interaction:
226
-
227
- - `UP` and `DOWN` adjust the vertical offset when it has focus
228
- - rendering clips visible content based on `height`
229
- - `highlightRows` marks specific visible rows
230
- - mouse hover exposes the visible row and rendered text
231
-
232
- Important payloads:
376
+ Payloads:
233
377
 
234
378
  - `TerminalScrollPointerEventPayload` - `{ type: "hover" | "rowenter" | "rowleave", id, row, value, x, y }`
379
+ - `TerminalScrollContextPressEventPayload` - `{ type: "contextpress", id, row, value, x, y }`
235
380
  - `TerminalCaptureEventPayload` - `{ type: "capturestart" | "captureend", id, source, row, x, y }`
236
381
 
382
+ Clips vertical content and supports keyboard scrolling, highlighted rows, hover payloads, context press for the target visible row, and pointer capture.
383
+
384
+ ### `LogView`
385
+
386
+ Props:
387
+
388
+ - layout props: `direction`, `gap`, `padding`, `width`, `height`, `fill`, `id`, `focusable`, `style`, `styles`, `state`
389
+ - `entries?: readonly TerminalLogViewEntry[]`
390
+ - `followTail?: boolean`
391
+ - `emptyText?: string`
392
+ - `renderEntry?(entry, index): string`
393
+
394
+ Entry shape:
395
+
396
+ - `TerminalLogViewEntry` - `{ id: string, content: string }`
397
+
398
+ Renders append-only logs and transcript-like panes. `followTail` keeps the visible frame at the bottom of the rendered entries. Use `followTail` as the `LogView` option for bottom-pinned transcript views while log storage and export stay in the app layer.
399
+
400
+ ## Render subpath exports
401
+
402
+ The `@valyrianjs/terminal/render` subpath exports:
403
+
404
+ - `renderTerminal(input, context?): string`
405
+ - `renderTerminalNode(node, context?): string`
406
+ - `renderTerminalFrame(node, context?): TerminalFrame`
407
+
408
+ These functions are useful for render-only integrations that should not import session runtime helpers.
409
+
237
410
  ## `TerminalSession`
238
411
 
239
- Public contract for the interactive session.
240
-
241
- - `update(): string` - resolves the root again and returns the current plain-text output
242
- - `output(): string` - returns the last rendered plain frame
243
- - `ansiOutput(): string` - returns the current frame serialized as ANSI
244
- - `tree(): TerminalNode[]` - exposes the current resolved terminal tree
245
- - `focus(id: string): boolean` - focuses an interactive node by `id`
246
- - `focusAt(x: number, y: number): boolean` - focuses by computed hitbox
247
- - `focusNext(): boolean` - moves focus forward in render order
248
- - `focusPrev(): boolean` - moves focus backward in render order
249
- - `dispatchKey(key: string): string` - injects a normalized key and returns the current output
250
- - `click(id?: string): string` - activates the focused button or a specific one by `id`
251
- - `clickAt(x: number, y: number): string` - activates or focuses using coordinates
252
- - `clipboard(): string` - returns the last clipboard value known by the session
253
- - `setClipboard(value: string): string` - updates the internal clipboard and, if present, the adapter
254
- - `selectAll(): string` - selects all content in the focused `Input`
255
- - `destroy(): void` - removes `stdin` listeners, exits raw mode, and pauses the stream when applicable
256
-
257
- ## Relevant Utility Types
258
-
259
- - `TerminalMountOptions` - options for mounting the session
260
- - `TerminalClipboardAdapter` - minimum contract for integrating an external clipboard
261
- - `TerminalFrame` - rendered frame with `lines`, `hitboxes`, `cursor`, and `spans`
262
- - `TerminalHitbox` - computed interactive region for focus and coordinate-based clicks
263
- - `TerminalStyleSpan` - visual marker such as `selection`, `focus`, or `highlight`
264
- - `TerminalNode`, `TerminalElementNode`, `TerminalTextNode` - resolved terminal tree
265
- - `TerminalLayoutProps` - shared base for `Box`, `View`, and `ScrollView`
266
- - `TerminalFocusableProps` - `id` and `focusable`
267
- - `TerminalPointerCaptureProps` - `pointerCapture` for lists and scroll views
268
- - `InputInteractionState` - cursor position and selection anchor
269
- - `TerminalChangeEventPayload` - union of `Input` and `List` change events
270
- - `TerminalPressEventPayload` - union of `Button` and `List` press events
271
- - `TerminalPointerCoordinates` - optional `x` and `y` coordinates in mouse payloads
272
- - `TerminalMouseEventType` - `"hover" | "rowenter" | "rowleave"`
273
- - `TerminalPointerSource` - `"press" | "drag" | "release"`
412
+ - `size(): TerminalSize` - returns `{ cols, rows }`.
413
+ - `resize(cols: number, rows: number): void` - validates and stores a new size, then rerenders.
414
+ - `update(): string` - rerenders and returns plain text.
415
+ - `output(): string` - returns the current plain-text frame.
416
+ - `ansiOutput(): string` - returns the current ANSI frame.
417
+ - `tree(): TerminalNode[]` - returns the current resolved terminal tree.
418
+ - `focus(id: string): boolean` - focuses a node by id.
419
+ - `focusAt(x: number, y: number): boolean` - focuses by coordinates.
420
+ - `focusNext(): boolean` - moves focus forward.
421
+ - `focusPrev(): boolean` - moves focus backward.
422
+ - `dispatchKey(key: string): string` - dispatches a normalized key and returns plain text.
423
+ - `click(id?: string): string` - activates the focused button or a button by id.
424
+ - `clickAt(x: number, y: number): string` - activates or focuses by coordinates.
425
+ - `clipboard(): string` - returns the session clipboard buffer.
426
+ - `setClipboard(value: string): string` - updates the session clipboard buffer and adapter when present.
427
+ - `selectAll(): string` - selects all content in the focused `Input`.
428
+ - `destroy(): void` - removes listeners and restores supported terminal state.
429
+
430
+ ## Package scope
431
+
432
+ - Use the package for terminal primitives, rendering, sessions, focus, input, and output.
433
+ - Compose command-palette surfaces with `Overlay`, `FocusScope`, `Input`, `List`, and `Button`.
434
+ - Keep log storage, export, routing, and business rules in your app layer.
435
+ - Use semantic text and styles for rendered content; reserve terminal escape control for documented integration paths.
436
+ - Host features such as resize, mouse input, and modified keys follow the terminal/runtime environment.
437
+
438
+ ## Related docs
439
+
440
+ - [Getting Started](./getting-started.md) for the first project.
441
+ - [Core Concepts](./core-concepts.md) for the mental model.
442
+ - [Cookbook](./cookbook.md) for practical recipes.
443
+ - [Interaction Model](./interaction-model.md) for behavior by primitive.
444
+ - [Session Runtime](./session-runtime.md) for host integration.
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="640" height="220" viewBox="0 0 640 220" role="img" aria-labelledby="title desc">
2
+ <title id="title">Quick note terminal result</title>
3
+ <desc id="desc">A terminal window with a quick note app, an input hint, and Ctrl+C exit guidance.</desc>
4
+ <rect width="640" height="220" rx="18" fill="#0d1117"/>
5
+ <rect x="24" y="24" width="592" height="172" rx="12" fill="#161b22" stroke="#30363d"/>
6
+ <circle cx="52" cy="52" r="6" fill="#ff7b72"/>
7
+ <circle cx="72" cy="52" r="6" fill="#f2cc60"/>
8
+ <circle cx="92" cy="52" r="6" fill="#56d364"/>
9
+ <text x="44" y="92" fill="#e6edf3" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="18">Quick note</text>
10
+ <text x="44" y="124" fill="#8b949e" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="16">Type a note. Ctrl+C: exit.</text>
11
+ <rect x="44" y="144" width="360" height="28" rx="6" fill="#0d1117" stroke="#58a6ff"/>
12
+ <text x="58" y="164" fill="#c9d1d9" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="15">Write a note</text>
13
+ </svg>