@valyrianjs/terminal 0.1.0 → 0.1.2

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 +4 -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 +8 -1
  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 +8 -3
  43. package/dist/render.d.ts.map +1 -1
  44. package/dist/render.js +840 -67
  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 +215 -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 +729 -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 +183 -18
  74. package/dist/types.d.ts.map +1 -1
  75. package/docs/api-reference.md +302 -136
  76. package/docs/assets/quick-note.svg +13 -0
  77. package/docs/cookbook.md +297 -202
  78. package/docs/core-concepts.md +143 -55
  79. package/docs/getting-started.md +209 -90
  80. package/docs/interaction-model.md +95 -61
  81. package/docs/primitive-gallery.md +365 -0
  82. package/docs/session-runtime.md +132 -363
  83. package/docs/valyrian-modules.md +3196 -0
  84. package/llms-full.txt +5357 -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 +92 -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 +52 -0
  97. package/src/render.ts +1107 -0
  98. package/src/runtime.ts +273 -0
  99. package/src/scheduler.ts +33 -0
  100. package/src/session.ts +1260 -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 +523 -0
  106. package/tsconfig.json +4 -7
  107. package/docs/local-demo.md +0 -28
@@ -1,451 +1,220 @@
1
1
  # Session Runtime
2
2
 
3
- Esta guia documenta el runtime interactivo de `valyrianjs-terminal`: cuando conviene usar `mountTerminal()`, como configurar una sesion y que capacidades expone `TerminalSession` durante su ciclo de vida.
3
+ This guide explains how to use `mountTerminal()` in common cases first, then how to integrate it with host streams and runtime features.
4
4
 
5
- Si vienes desde cero, lee antes `docs/core-concepts.md`. Para el modelo general de interaccion por primitiva, consulta `docs/interaction-model.md`. Aqui el foco es operativo: montaje, rerender, streams, foco, teclado, clipboard y mouse.
5
+ ## When to use the session runtime
6
6
 
7
- ## Cuando usar `mountTerminal()`
7
+ Use `mountTerminal()` when the UI needs one or more of these capabilities:
8
8
 
9
- Usa `mountTerminal()` cuando necesites una sesion viva que:
9
+ - focus and keyboard dispatch
10
+ - repeated renders after state changes
11
+ - clipboard integration
12
+ - mouse and coordinate-based interaction
13
+ - `stdin` and `stdout` connection
14
+ - ANSI output for a real terminal
10
15
 
11
- - reevalua el arbol al cambiar estado externo
12
- - mantiene foco entre renders
13
- - despacha teclado por sesion
14
- - conecta `stdin` y `stdout`
15
- - responde a coordenadas y eventos de mouse
16
+ Use `renderTerminal()` for deterministic static plain text.
16
17
 
17
- Si solo quieres inspeccionar layout, generar snapshots o producir una salida estatica, `renderTerminal()` sigue siendo la opcion mas simple.
18
+ ## Practical recommendations
18
19
 
19
- ```tsx
20
- /** @jsx v */
21
- /** @jsxFrag v.fragment */
20
+ - Start without streams while building examples and scripted flows.
21
+ - Give stable `id` values to focusable primitives you want to control.
22
+ - Keep application state outside the renderer.
23
+ - Valyrian reactive state read by components refreshes the terminal when it changes, including external async changes. Call `session.update()` for non-reactive state or an explicit manual refresh.
24
+ - Call `session.destroy()` when a session is connected to real streams.
25
+ - Design keyboard-first flows and connect resize, modified keys, clipboard, and mouse through the host capabilities available in each terminal environment.
26
+
27
+ ## Common runtime usage
22
28
 
23
- import { v } from "valyrian.js";
24
- import { Input, Screen, Text, mountTerminal } from "valyrianjs-terminal";
29
+ Full example: [`examples/docs/interactive-note.tsx`](../examples/docs/interactive-note.tsx). Run it with `bun examples/docs/interactive-note.tsx`, type a note, press `Enter`, and quit with `Ctrl+C`.
30
+
31
+ ```tsx
32
+ import { Input, Screen, Text, mountTerminal } from "@valyrianjs/terminal";
25
33
 
26
34
  const state = { value: "" };
27
35
 
28
- const session = mountTerminal(() => (
29
- <Screen title="Runtime Demo">
30
- <Input
31
- id="name"
32
- value={state.value}
33
- onchange={(event) => {
34
- state.value = event.value;
35
- }}
36
- />
37
- <Text>Current: {state.value || "(empty)"}</Text>
38
- </Screen>
39
- ));
36
+ function App() {
37
+ return (
38
+ <Screen title="Runtime demo">
39
+ <Input
40
+ id="name"
41
+ value={state.value}
42
+ placeholder="Name"
43
+ onchange={(event) => {
44
+ state.value = event.value;
45
+ }}
46
+ />
47
+ <Text>Current: {state.value || "(empty)"}</Text>
48
+ </Screen>
49
+ );
50
+ }
51
+
52
+ const session = mountTerminal(<App />);
40
53
 
41
54
  session.focus("name");
42
55
  session.dispatchKey("A");
43
56
  session.dispatchKey("B");
44
57
 
45
58
  console.log(session.output());
59
+ session.destroy();
46
60
  ```
47
61
 
48
- ## `TerminalMountOptions`
49
-
50
- `mountTerminal(input, options?)` acepta un `TerminalMountOptions` con cuatro puntos de integracion:
51
-
52
- ### `ansi?: boolean`
53
-
54
- Activa salida ANSI incremental hacia `stdout`. `session.ansiOutput()` sigue disponible aunque no actives esta opcion; lo que cambia es la escritura automatica de la sesion cuando hace rerender. Si no lo activas, la salida principal enviada a `stdout` es texto plano.
55
-
56
- ### `clipboard?: TerminalClipboardAdapter | false`
57
-
58
- - si pasas un adapter, la sesion usa `readText()` y `writeText()` cuando ejecuta atajos como `CTRL_C` o `CTRL_V`
59
- - si pasas `false`, desactivas la integracion con clipboard del sistema
60
- - aun con `clipboard: false`, `session.clipboard()` y `session.setClipboard()` siguen funcionando como buffer de la sesion
61
-
62
- ```tsx
63
- /** @jsx v */
64
- /** @jsxFrag v.fragment */
65
-
66
- import { v } from "valyrian.js";
67
- import { Screen, mountTerminal } from "valyrianjs-terminal";
68
-
69
- const app = () => <Screen title="Clipboard Demo" />;
70
-
71
- const session = mountTerminal(app, {
72
- clipboard: {
73
- readText() {
74
- return "pasted value";
75
- },
76
- writeText(value) {
77
- console.log("copied:", value);
78
- }
79
- }
80
- });
81
- ```
82
-
83
- ```tsx
84
- /** @jsx v */
85
- /** @jsxFrag v.fragment */
62
+ The session lifecycle is:
86
63
 
87
- import { v } from "valyrian.js";
88
- import { Screen, mountTerminal } from "valyrianjs-terminal";
89
-
90
- const app = () => <Screen title="Clipboard Disabled" />;
91
-
92
- const session = mountTerminal(app, { clipboard: false });
93
- session.setClipboard("fallback value");
94
- ```
64
+ 1. mount with `mountTerminal()`
65
+ 2. read `output()` or `ansiOutput()`
66
+ 3. dispatch input or update external state
67
+ 4. rerender with `update()` when needed
68
+ 5. close with `destroy()`
95
69
 
96
- ### `stdin?`
70
+ ## Input, output, and cleanup
97
71
 
98
- Stream de entrada para teclado y mouse. La sesion se suscribe a `data`, intenta activar `raw mode` si existe `setRawMode(true)` y llama `resume()` si el stream lo soporta.
99
-
100
- Contrato esperado:
72
+ ### `output()`
101
73
 
102
- - `on("data", listener)` obligatorio
103
- - `off(...)` o `removeListener(...)` opcional para cleanup
104
- - `setRawMode?(boolean)` opcional
105
- - `resume?()` y `pause?()` opcionales
74
+ Returns the current plain-text frame. Use it for snapshots, examples, and content inspection.
106
75
 
107
- ### `stdout?`
76
+ ### `ansiOutput()`
108
77
 
109
- Destino de escritura para la salida producida en cada rerender.
78
+ Returns the current frame serialized with ANSI cursor movement and style spans.
110
79
 
111
- - con `ansi: false`, escribe texto plano
112
- - con `ansi: true`, escribe diffs ANSI incrementales
80
+ Related example: [`examples/docs/theme-colors.tsx`](../examples/docs/theme-colors.tsx). Run it with `bun examples/docs/theme-colors.tsx`, press `Tab`, and quit with `Ctrl+C`.
113
81
 
114
82
  ```tsx
115
- /** @jsx v */
116
- /** @jsxFrag v.fragment */
117
-
118
- import { v } from "valyrian.js";
119
- import { Screen, mountTerminal } from "valyrianjs-terminal";
83
+ import { Screen, mountTerminal } from "@valyrianjs/terminal";
120
84
 
121
- const app = () => <Screen title="ANSI Stream Demo" />;
85
+ function App() {
86
+ return <Screen title="ANSI frame" />;
87
+ }
122
88
 
123
- const writes: string[] = [];
89
+ const session = mountTerminal(<App />, { runtime: "headless" });
124
90
 
125
- const session = mountTerminal(app, {
126
- ansi: true,
127
- stdout: {
128
- write(chunk) {
129
- writes.push(String(chunk));
130
- }
131
- }
132
- });
91
+ console.log(session.ansiOutput());
92
+ session.destroy();
133
93
  ```
134
94
 
135
- ## Lifecycle de `TerminalSession`
136
-
137
- La sesion mantiene un frame actual, una salida actual y el estado interactivo asociado al arbol enfocable. El ciclo practico es:
138
-
139
- 1. montar con `mountTerminal()`
140
- 2. leer con `output()` o `ansiOutput()`
141
- 3. mutar estado externo o despachar interacciones
142
- 4. rerender con `update()` o mediante eventos que ya disparan rerender
143
- 5. cerrar con `destroy()`
95
+ `ansiOutput()` is an explicit inspection/export path. Keep ordinary `Text`, input values, list rows, and log entries as text content. Advanced span serialization tokens are documented in [Advanced: span serialization tokens](./api-reference.md#advanced-span-serialization-tokens) for low-level renderer integrations.
144
96
 
145
97
  ### `update()`
146
98
 
147
- Vuelve a evaluar `input`, recalcula el frame y devuelve la salida plana actual.
99
+ Re-evaluates the session input and returns the current plain-text output.
148
100
 
149
- Usalo cuando mutaste estado fuera de handlers de la sesion.
101
+ Related example: [`examples/docs/component-composition.tsx`](../examples/docs/component-composition.tsx). Run it with `bun examples/docs/component-composition.tsx`, switch cards with `N/P`, and quit with `Ctrl+C`.
150
102
 
151
103
  ```tsx
104
+ import { Screen, Text, mountTerminal } from "@valyrianjs/terminal";
105
+
152
106
  const state = { count: 0 };
153
107
 
154
- const session = mountTerminal(() => (
155
- <Screen>
156
- <Text>Count: {state.count}</Text>
157
- </Screen>
158
- ));
108
+ function App() {
109
+ return (
110
+ <Screen title="Update demo">
111
+ <Text>Count: {state.count}</Text>
112
+ </Screen>
113
+ );
114
+ }
115
+
116
+ const session = mountTerminal(<App />);
159
117
 
160
118
  state.count += 1;
161
119
  session.update();
162
120
 
163
121
  console.log(session.output());
164
- ```
165
-
166
- ### `output()`
167
-
168
- Devuelve el frame actual en texto plano. Es la forma mas directa de:
169
-
170
- - inspeccionar estado actual
171
- - validar snapshots
172
- - probar foco y contenido sin ANSI
173
-
174
- ### `ansiOutput()`
175
-
176
- Devuelve el frame actual serializado como ANSI completo, incluyendo cursor y spans visuales. Es util cuando quieres:
177
-
178
- - inspeccionar posicion de cursor
179
- - validar seleccion o foco en una terminal ANSI
180
- - integrar una capa que consume escape sequences completas
181
-
182
- ```tsx
183
- /** @jsx v */
184
- /** @jsxFrag v.fragment */
185
-
186
- import { v } from "valyrian.js";
187
- import { Screen, mountTerminal } from "valyrianjs-terminal";
188
-
189
- const app = () => <Screen title="ANSI Frame Demo" />;
190
-
191
- const session = mountTerminal(app, { ansi: true });
192
- const ansi = session.ansiOutput();
193
- console.log(ansi);
194
- ```
195
-
196
- ### `destroy()`
197
-
198
- Desmonta listeners de `stdin`, intenta salir de raw mode con `setRawMode(false)` y llama `pause()` si existe.
199
-
200
- Llamalo siempre cuando montaste la sesion con `stdin` real o un emisor conectado.
201
-
202
- ```ts
203
122
  session.destroy();
204
123
  ```
205
124
 
206
- ## Foco y coordenadas
207
-
208
- El foco vive a nivel de sesion. Para participar en este flujo, los nodos interactivos necesitan `id`.
209
-
210
- ### `focus(id)`
211
-
212
- Enfoca un nodo por `id`. Devuelve `true` si lo encontro.
213
-
214
- ### `focusNext()` y `focusPrev()`
215
-
216
- Recorren el orden actual de elementos enfocables. `dispatchKey("TAB")` y `dispatchKey("SHIFT_TAB")` usan este mismo flujo.
217
-
218
- ### `focusAt(x, y)`
219
-
220
- Busca el hitbox en las coordenadas actuales, actualiza hover semantico cuando aplica y enfoca ese nodo.
221
-
222
- ### `clickAt(x, y)`
223
-
224
- - si cae sobre un `Button`, dispara su accion
225
- - si cae sobre un `Input`, enfoca y coloca cursor segun la coordenada
226
- - si cae sobre otra superficie enfocable, mueve el foco
227
-
228
- ```tsx
229
- const session = mountTerminal(() => (
230
- <Screen>
231
- <Input id="name" value="abc" />
232
- <Button id="save">Save</Button>
233
- </Screen>
234
- ));
235
-
236
- session.focusAt(2, 1);
237
- session.clickAt(3, 2);
238
- ```
239
-
240
- ## Keyboard dispatch por sesion
241
-
242
- `dispatchKey(key)` procesa una tecla ya normalizada contra el nodo enfocado y devuelve la salida plana actual.
243
-
244
- Atajos soportados por la API publica observables en pruebas:
245
-
246
- - globales: `TAB`, `SHIFT_TAB`
247
- - `Input`: caracteres de un solo byte, `ENTER`, `LEFT`, `RIGHT`, `SHIFT_LEFT`, `SHIFT_RIGHT`, `ALT_LEFT`, `ALT_RIGHT`, `HOME`, `END`, `CTRL_A`, `CTRL_C`, `CTRL_X`, `CTRL_V`, `BACKSPACE`, `DELETE`
248
- - `Button`: `ENTER`, `SPACE`
249
- - `List`: `UP`, `DOWN`, `LEFT`, `RIGHT`, `ENTER`
250
- - `ScrollView`: `UP`, `DOWN`
251
-
252
- ```tsx
253
- const state = { value: "", saved: "" };
254
-
255
- const session = mountTerminal(() => (
256
- <Screen>
257
- <Input
258
- id="name"
259
- value={state.value}
260
- onchange={(event) => {
261
- state.value = event.value;
262
- }}
263
- onsubmit={(event) => {
264
- state.saved = event.value;
265
- }}
266
- />
267
- </Screen>
268
- ));
269
-
270
- session.focus("name");
271
- session.dispatchKey("A");
272
- session.dispatchKey("B");
273
- session.dispatchKey("LEFT");
274
- session.dispatchKey("C");
275
- session.dispatchKey("ENTER");
276
- ```
277
-
278
- ## Clipboard adapter y `clipboard: false`
279
-
280
- La sesion separa dos conceptos:
281
-
282
- - buffer de clipboard de la sesion: `clipboard()` y `setClipboard()`
283
- - integracion con el sistema: `options.clipboard`
125
+ ### `destroy()`
284
126
 
285
- Con un adapter, los atajos de input leen y escriben contra ese adapter. Sin adapter, la sesion conserva un valor local. Con `clipboard: false`, desactivas la integracion externa pero puedes seguir usando el buffer local de la sesion para pruebas o integraciones manuales.
127
+ Removes listeners and restores supported terminal state when a session connected to streams changed it. Always call it when the session owns real input or output resources.
286
128
 
287
- ```tsx
288
- const state = { value: "abcd" };
289
-
290
- const session = mountTerminal(() => (
291
- <Screen>
292
- <Input
293
- id="name"
294
- value={state.value}
295
- onchange={(event) => {
296
- state.value = event.value;
297
- }}
298
- />
299
- </Screen>
300
- ), { clipboard: false });
129
+ ## Advanced host integration
301
130
 
302
- session.focus("name");
303
- session.setClipboard("XY");
304
- session.dispatchKey("END");
305
- session.dispatchKey("CTRL_V");
306
- ```
131
+ ### Mount options
307
132
 
308
- ## Streams `stdin` y `stdout`
133
+ `mountTerminal(input, options?)` accepts options for host integration. `mountTerminal(<App />)` is the normal interactive path; it uses process stdio, ANSI diffs, alternate screen, and a hidden cursor only when called from a real interactive TTY. Imports and non-TTY/test runs do not auto-attach stdio.
309
134
 
310
- Conectar streams vuelve a la sesion util como runtime de CLI, no solo como helper de pruebas.
135
+ - `runtime?: "app" | "headless"` - selects interactive app behavior or scriptable plain output. Omitted runtime uses app mode only for interactive TTY hosts and stays headless in non-TTY/CI contexts.
136
+ - `alternateScreen?: boolean` - enters the terminal alternate screen and restores it on destroy by default. Real interactive app mode enables it by default unless overridden.
137
+ - `hideCursor?: boolean` - expresses that the session should hide the terminal cursor while it owns the screen when the host supports it. Real interactive app mode enables it by default unless overridden.
138
+ - `restoreOnDestroy?: boolean` - controls whether destroy should restore supported cursor and alternate-screen state.
139
+ - `clipboard?: TerminalClipboardAdapter | false` - connects a custom clipboard adapter or disables external clipboard integration.
140
+ - `cols?: number` and `rows?: number` - set the initial terminal size.
141
+ - `stdin?` - receives keyboard, paste, and mouse input.
142
+ - `stdout?` - receives rendered output.
311
143
 
312
- Comportamiento observable:
144
+ ### Clipboard adapter
313
145
 
314
- - al montar, la sesion se suscribe a `stdin.on("data", listener)`
315
- - si `stdin.setRawMode` existe, intenta `setRawMode(true)`
316
- - si `stdin.resume` existe, intenta `resume()`
317
- - en cada rerender, si existe `stdout.write`, la sesion escribe el frame actual
318
- - al destruir, intenta desuscribirse y restaurar `raw mode`
146
+ Related example: [`examples/docs/interactive-note.tsx`](../examples/docs/interactive-note.tsx). Run it with `bun examples/docs/interactive-note.tsx`, type a note, press `Enter`, and quit with `Ctrl+C`.
319
147
 
320
148
  ```tsx
321
- /** @jsx v */
322
- /** @jsxFrag v.fragment */
149
+ import { Screen, mountTerminal } from "@valyrianjs/terminal";
323
150
 
324
- import { EventEmitter } from "node:events";
325
- import { v } from "valyrian.js";
326
- import { Screen, mountTerminal } from "valyrianjs-terminal";
151
+ function App() {
152
+ return <Screen title="Clipboard" />;
153
+ }
327
154
 
328
- const app = () => <Screen title="Stream Demo" />;
329
-
330
- const stdin = new EventEmitter() as EventEmitter & {
331
- setRawMode?: (value: boolean) => void;
332
- resume?: () => void;
333
- pause?: () => void;
334
- };
335
-
336
- const writes: string[] = [];
337
-
338
- const session = mountTerminal(app, {
339
- stdin,
340
- stdout: {
341
- write(chunk) {
342
- writes.push(String(chunk));
155
+ const session = mountTerminal(<App />, {
156
+ clipboard: {
157
+ readText() {
158
+ return "pasted value";
159
+ },
160
+ writeText(value) {
161
+ console.log("copied:", value);
343
162
  }
344
163
  }
345
164
  });
346
165
 
347
- stdin.emit("data", "A");
348
- stdin.emit("data", "\r");
349
166
  session.destroy();
350
167
  ```
351
168
 
352
- ## ANSI output
169
+ Passing `clipboard: false` disables external clipboard integration while preserving the session clipboard buffer through `clipboard()` and `setClipboard()`.
353
170
 
354
- Hay dos formas practicas de trabajar con ANSI:
171
+ ### Streams
355
172
 
356
- - `ansi: true` + `stdout`: la sesion emite diffs incrementales en cada rerender
357
- - `session.ansiOutput()`: recupera el frame ANSI completo del estado actual
173
+ `stdin` should provide `on("data", listener)`. Cleanup methods such as `off(...)` or `removeListener(...)` are used when available. `setRawMode`, `resume`, and `pause` are optional.
358
174
 
359
- Esto es especialmente util cuando la terminal consumidora necesita minimizar repaints o cuando quieres verificar cursor, foco y seleccion con escape sequences reales.
175
+ `stdout` should provide `write(chunk: string)`. Optional `columns` and `rows` can provide initial dimensions. Optional `resize` and `drain` events are used only when the stream also provides listener cleanup.
360
176
 
361
- ```tsx
362
- const state = { value: "AB" };
363
-
364
- const session = mountTerminal(() => (
365
- <Screen title="ANSI Demo">
366
- <Input
367
- id="name"
368
- value={state.value}
369
- onchange={(event) => {
370
- state.value = event.value;
371
- }}
372
- />
373
- </Screen>
374
- ), { ansi: true });
177
+ ### Size and resize
375
178
 
376
- session.focus("name");
377
- session.dispatchKey("LEFT");
179
+ `size()` returns `{ cols, rows }`. `resize(cols, rows)` validates positive integer dimensions, stores them, and rerenders once.
378
180
 
379
- console.log(session.ansiOutput());
380
- ```
381
-
382
- ## Mouse SGR, wheel y pointer capture
383
-
384
- Cuando conectas `stdin`, la sesion acepta secuencias SGR de mouse y las traduce a interaccion practica sobre el frame actual.
385
-
386
- ### Press, drag y release
387
-
388
- - `press`: enfoca y activa el hitbox en la coordenada
389
- - `drag`: si hay un `Input` activo por mouse, extiende seleccion; en `List` y `ScrollView`, actualiza hover por fila
390
- - `release`: termina seleccion por mouse y cierra captura cuando aplica
391
-
392
- ```ts
393
- stdin.emit("data", "\u001b[<0;4;1M");
394
- stdin.emit("data", "\u001b[<32;7;1M");
395
- stdin.emit("data", "\u001b[<0;7;1m");
396
- ```
397
-
398
- Ese patron es suficiente para seleccionar texto dentro de un `Input` por coordenadas.
181
+ Related example: [`examples/docs/background-fill.tsx`](../examples/docs/background-fill.tsx). Run it with `bun examples/docs/background-fill.tsx`, switch surfaces with `B`, and quit with `Ctrl+C`.
399
182
 
400
- ### Wheel
183
+ ```tsx
184
+ import { Screen, mountTerminal } from "@valyrianjs/terminal";
401
185
 
402
- El wheel se despacha como navegacion vertical sobre el nodo bajo el puntero:
186
+ function App() {
187
+ return <Screen title="Resizable" />;
188
+ }
403
189
 
404
- - `wheel-up` equivale a `dispatchKey("UP")`
405
- - `wheel-down` equivale a `dispatchKey("DOWN")`
190
+ const session = mountTerminal(<App />, { cols: 80, rows: 24 });
406
191
 
407
- ```ts
408
- stdin.emit("data", "\u001b[<65;2;1M");
192
+ console.log(session.size());
193
+ session.resize(100, 30);
194
+ console.log(session.size());
195
+ session.destroy();
409
196
  ```
410
197
 
411
- En un `ScrollView` enfocado o localizado por coordenadas, eso desplaza el viewport.
198
+ Automatic resize works with compatible output sources that emit supported resize events after updating their `columns` and `rows` values.
412
199
 
413
- ### Pointer capture a nivel practico
200
+ ### Keyboard, paste, and mouse input
414
201
 
415
- `pointerCapture` hoy aplica a `List` y `ScrollView`.
202
+ `dispatchKey(key)` injects a normalized key directly. Connected `stdin` can also deliver keyboard input, terminal paste input, and supported SGR mouse input.
416
203
 
417
- Sin `pointerCapture`, el hover semantico depende de que el drag siga dentro del hitbox visible. Con `pointerCapture`, la sesion mantiene la interaccion durante el drag aunque el puntero salga del area inicial, y dispara:
204
+ Bracketed paste is handled as terminal input: pasted text is inserted into the focused `Input` or `Editor` as content instead of being treated as separate key commands. Multiline `Editor` cursor columns are reported as JavaScript UTF-16 string columns, not as a complete terminal grapheme-width model.
418
205
 
419
- - `oncapturestart`
420
- - `oncaptureend`
206
+ Mouse input can focus or activate hitboxes, update hover state, and map wheel input to vertical navigation. Keep keyboard alternatives for important actions so every terminal workflow has a reliable input path.
421
207
 
422
- Esto es util para:
208
+ ## Host integration behavior
423
209
 
424
- - listas que deben seguir rastreando la fila activa durante drag
425
- - scroll views que conservan hover o release aunque el puntero termine fuera del viewport
426
-
427
- ```tsx
428
- const session = mountTerminal(() => (
429
- <Screen>
430
- <List
431
- id="menu"
432
- pointerCapture
433
- items={["Open", "Save", "Exit"]}
434
- oncapturestart={(event) => console.log(event)}
435
- oncaptureend={(event) => console.log(event)}
436
- />
437
- </Screen>
438
- ), { stdin, clipboard: false });
439
-
440
- stdin.emit("data", "\u001b[<0;2;1M");
441
- stdin.emit("data", "\u001b[<32;99;99M");
442
- stdin.emit("data", "\u001b[<0;99;99m");
443
- ```
210
+ - Modified keys follow sequences reported by the connected terminal.
211
+ - Clipboard behavior uses the provided adapter or the session clipboard buffer.
212
+ - Mouse behavior uses supported terminal input sequences.
213
+ - Automatic resize works with compatible output sources and cleanup-capable listeners.
214
+ - Use session runtime for terminal rendering, focus, input, output, and cleanup. Keep routing, persistence, command orchestration, and process management in the app layer.
444
215
 
445
- ## Recomendaciones practicas
216
+ ## Where to go next
446
217
 
447
- - usa `renderTerminal()` para snapshots y `mountTerminal()` para runtime interactivo
448
- - da `id` estables a `Input`, `Button`, `List` y `ScrollView` si vas a usar foco, coordenadas o dispatch programatico
449
- - llama `update()` solo cuando mutaste estado fuera de handlers ya conectados a la sesion
450
- - llama `destroy()` siempre que montes con `stdin`
451
- - usa `clipboard: false` en pruebas o entornos donde no quieres depender del clipboard del sistema
218
+ - [Getting Started](./getting-started.md) for the first project.
219
+ - [Interaction Model](./interaction-model.md) for per-primitive behavior.
220
+ - [API Reference](./api-reference.md) for exact methods, props, and payloads.