@valyrianjs/terminal 0.1.1 → 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 +296 -201
  78. package/docs/core-concepts.md +143 -55
  79. package/docs/getting-started.md +209 -90
  80. package/docs/interaction-model.md +86 -52
  81. package/docs/primitive-gallery.md +365 -0
  82. package/docs/session-runtime.md +131 -362
  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
package/docs/cookbook.md CHANGED
@@ -1,179 +1,304 @@
1
1
  # Cookbook
2
2
 
3
- Short, copyable recipes for `valyrianjs-terminal`. This guide complements `docs/getting-started.md`, `docs/interaction-model.md`, and `docs/api-reference.md`.
3
+ Practical recipes for ValyrianJS Terminal. Start here after [Getting Started](./getting-started.md) when you want copyable patterns for common terminal UI tasks.
4
4
 
5
- ## Static rendering for snapshots
5
+ ## Input handling
6
6
 
7
- Use this when you want to validate layout or generate plain text without opening an interactive session.
7
+ Use `Input` when a single-line field should update app state and optionally submit on `Enter`.
8
+
9
+ 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`.
8
10
 
9
11
  ```tsx
10
- /** @jsx v */
11
- /** @jsxFrag v.fragment */
12
+ import { Input, Screen, Text, mountTerminal } from "@valyrianjs/terminal";
12
13
 
13
- import { v } from "valyrian.js";
14
- import { Screen, Text, renderTerminal } from "valyrianjs-terminal";
14
+ const state = { value: "", submitted: "" };
15
15
 
16
- const output = renderTerminal(
17
- <Screen title="Snapshot Demo">
18
- <Text>Hello terminal</Text>
19
- <Text>Status: ok</Text>
20
- </Screen>
21
- );
16
+ function App() {
17
+ return (
18
+ <Screen title="Input recipe">
19
+ <Input
20
+ id="name"
21
+ value={state.value}
22
+ placeholder="Name"
23
+ onchange={(event) => {
24
+ state.value = event.value;
25
+ }}
26
+ onsubmit={(event) => {
27
+ state.submitted = event.value;
28
+ }}
29
+ />
30
+ <Text>{state.submitted || "Nothing submitted yet"}</Text>
31
+ </Screen>
32
+ );
33
+ }
34
+
35
+ const session = mountTerminal(<App />);
22
36
 
23
- console.log(output);
37
+ session.focus("name");
38
+ session.dispatchKey("A");
39
+ session.dispatchKey("ENTER");
40
+
41
+ console.log(session.output());
42
+ session.destroy();
24
43
  ```
25
44
 
26
- ## Controlled input with submit
45
+ Give the field a stable `id` if you want focus, coordinate lookup, or programmatic dispatch.
27
46
 
28
- Use this when you need an editable field that stores the final value when `Enter` is pressed.
47
+ ## Lists and selection
29
48
 
30
- ```tsx
31
- /** @jsx v */
32
- /** @jsxFrag v.fragment */
49
+ Use `List` when the app needs selection and activation as separate events.
33
50
 
34
- import { v } from "valyrian.js";
35
- import { Input, Screen, Text, mountTerminal } from "valyrianjs-terminal";
51
+ Related example: [`examples/docs/employees-list.tsx`](../examples/docs/employees-list.tsx). Run it with `bun examples/docs/employees-list.tsx`, choose a person with `J/K` or arrows, and quit with `Ctrl+C`.
36
52
 
37
- const state = { value: "", submitted: "" };
53
+ ```tsx
54
+ import { List, Screen, Text, mountTerminal } from "@valyrianjs/terminal";
55
+
56
+ const state = { selected: "", opened: "" };
38
57
 
39
- const session = mountTerminal(() => (
40
- <Screen>
41
- <Input
42
- id="name"
43
- value={state.value}
44
- placeholder="Write a quick note"
45
- onchange={(event) => {
46
- state.value = event.value;
47
- }}
48
- onsubmit={(event) => {
49
- state.submitted = event.value;
50
- }}
51
- />
52
- <Text>{state.submitted || "Nothing submitted yet"}</Text>
53
- </Screen>
54
- ));
58
+ function App() {
59
+ return (
60
+ <Screen title="List recipe">
61
+ <List
62
+ id="menu"
63
+ items={["Inbox", "Today", "Done"]}
64
+ onchange={(event) => {
65
+ state.selected = event.value;
66
+ }}
67
+ onpress={(event) => {
68
+ state.opened = event.value;
69
+ }}
70
+ />
71
+ <Text>Selected: {state.selected || "-"}</Text>
72
+ <Text>Opened: {state.opened || "-"}</Text>
73
+ </Screen>
74
+ );
75
+ }
76
+
77
+ const session = mountTerminal(<App />);
55
78
 
56
- session.focus("name");
57
- session.dispatchKey("H");
58
- session.dispatchKey("i");
79
+ session.focus("menu");
80
+ session.dispatchKey("DOWN");
59
81
  session.dispatchKey("ENTER");
60
82
 
61
- console.log(state.submitted);
62
83
  console.log(session.output());
84
+ session.destroy();
63
85
  ```
64
86
 
65
- ## Button that mutates state
87
+ For large lists, add `virtualized` and place the list in a bounded region such as a filled pane or split.
88
+
89
+ ## Local state to Valyrian state module bridge
90
+
91
+ Start with local objects for small examples. Use Valyrian state modules such as `createPulseStore` when shared state and named transitions make the UI easier to maintain.
66
92
 
67
- Use this when you want to trigger simple actions from the keyboard or by programmatic click.
93
+ 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`.
68
94
 
69
95
  ```tsx
70
- /** @jsx v */
71
- /** @jsxFrag v.fragment */
72
-
73
- import { v } from "valyrian.js";
74
- import { Button, Screen, Text, mountTerminal } from "valyrianjs-terminal";
75
-
76
- const state = { count: 0 };
77
-
78
- const session = mountTerminal(() => (
79
- <Screen>
80
- <Button
81
- id="increment"
82
- onpress={() => {
83
- state.count += 1;
84
- }}
85
- >
86
- Increment
87
- </Button>
88
- <Text>{`Count: ${state.count}`}</Text>
89
- </Screen>
90
- ));
91
-
92
- session.click("increment");
93
- session.click("increment");
96
+ import { createPulseStore } from "valyrian.js/pulses";
97
+ import { Button, Screen, Text, mountTerminal } from "@valyrianjs/terminal";
98
+
99
+ const counter = createPulseStore(
100
+ { count: 0 },
101
+ {
102
+ increment(state) {
103
+ state.count += 1;
104
+ }
105
+ }
106
+ );
107
+
108
+ function App() {
109
+ return (
110
+ <Screen title="State recipe">
111
+ <Text>Count: {counter.state.count}</Text>
112
+ <Button id="increment" onpress={() => counter.increment()}>
113
+ Increment
114
+ </Button>
115
+ </Screen>
116
+ );
117
+ }
118
+
119
+ const session = mountTerminal(<App />);
120
+
121
+ session.focus("increment");
122
+ session.dispatchKey("ENTER");
94
123
 
95
124
  console.log(session.output());
125
+ session.destroy();
96
126
  ```
97
127
 
98
- ## Interactive list with `onchange` and `onpress`
128
+ The app owns the store. The terminal session renders the current state and dispatches interaction events.
99
129
 
100
- Use this when you want to separate the currently selected item from the item activated with `Enter`.
101
130
 
102
- ```tsx
103
- /** @jsx v */
104
- /** @jsxFrag v.fragment */
131
+ ## Primitive Gallery mini apps
105
132
 
106
- import { v } from "valyrian.js";
107
- import { List, Screen, Text, mountTerminal } from "valyrianjs-terminal";
133
+ Use [Primitive Gallery](./primitive-gallery.md) when you want to pick the right primitive before copying a recipe. The gallery shows what each primitive is, where it fits, core props, a short example, and a complete mini app.
108
134
 
109
- const state = { selected: "", opened: "" };
135
+ Complete primitive demos:
110
136
 
111
- const session = mountTerminal(() => (
112
- <Screen>
113
- <List
114
- id="menu"
115
- items={["Inbox", "Today", "Done"]}
116
- onchange={(event) => {
117
- state.selected = event.value;
118
- }}
119
- onpress={(event) => {
120
- state.opened = event.value;
121
- }}
122
- />
123
- <Text>{`Selected: ${state.selected || "-"}`}</Text>
124
- <Text>{`Opened: ${state.opened || "-"}`}</Text>
125
- </Screen>
126
- ));
137
+ - **Operations Workspace** ([`examples/docs/primitive-layout-shell.tsx`](../examples/docs/primitive-layout-shell.tsx)). Run it with `bun examples/docs/primitive-layout-shell.tsx`, inspect the shell regions, and quit with `Ctrl+C`.
138
+ - **Ticket Intake** ([`examples/docs/primitive-input-workbench.tsx`](../examples/docs/primitive-input-workbench.tsx)). Run it with `bun examples/docs/primitive-input-workbench.tsx`, type a summary, move focus with `Tab`, save with `Enter`, and quit with `Ctrl+C`.
139
+ - **Service Explorer** ([`examples/docs/primitive-data-explorer.tsx`](../examples/docs/primitive-data-explorer.tsx)). Run it with `bun examples/docs/primitive-data-explorer.tsx`, move through items with `J/K`, and quit with `Ctrl+C`.
140
+ - **Activity Console** ([`examples/docs/primitive-activity-console.tsx`](../examples/docs/primitive-activity-console.tsx)). Run it with `bun examples/docs/primitive-activity-console.tsx`, add events with `Enter`, scroll the viewport with `Up/Down`, and quit with `Ctrl+C`.
141
+ - **Command Panel** ([`examples/docs/primitive-command-panel.tsx`](../examples/docs/primitive-command-panel.tsx)). Run it with `bun examples/docs/primitive-command-panel.tsx`, type a filter, choose commands with arrows, pick with `Enter`, and quit with `Ctrl+C`.
127
142
 
128
- session.focus("menu");
129
- session.dispatchKey("DOWN");
130
- session.dispatchKey("DOWN");
143
+ Use API Reference for prop-level details after you choose the primitive family.
144
+
145
+ ## Valyrian.js modules in terminal apps
146
+
147
+ Valyrian.js modules let terminal apps use the same app-layer tools you would use in Valyrian browser or server apps. The terminal adapter owns rendering, focus, input dispatch, output, and cleanup. Your app owns state, data, persistence, commands, and business rules.
148
+
149
+ Read the dedicated guide at [`docs/valyrian-modules.md`](./valyrian-modules.md) for deeper patterns around `valyrian.js/request`, `valyrian.js/query`, `valyrian.js/tasks`, state modules, forms, persistence, localization, money formatting, and utilities.
150
+
151
+ Complete terminal demos:
152
+
153
+ - **Operations Workbench** ([`examples/docs/module-state-workbench.tsx`](../examples/docs/module-state-workbench.tsx)). Run it with `bun examples/docs/module-state-workbench.tsx`, select jobs with `J/K`, dispatch with `Enter`, mark work with `D` or `B`, reset with `R`, and quit with `Ctrl+C`.
154
+ - **API Operations Dashboard** ([`examples/docs/module-api-dashboard.tsx`](../examples/docs/module-api-dashboard.tsx)). Run it with `bun examples/docs/module-api-dashboard.tsx`, refresh with `R`, toggle a controlled error with `E`, invalidate with `I`, run or cancel the task with `T` or `C`, and quit with `Ctrl+C`.
155
+ - **Billing/Settings Wizard** ([`examples/docs/module-form-workflow.tsx`](../examples/docs/module-form-workflow.tsx)). Run it with `bun examples/docs/module-form-workflow.tsx`, fill values with `N`, switch language with `L`, save with `S` or `Enter`, reset with `R`, clear saved data with `X`, and quit with `Ctrl+C`.
156
+
157
+ ## Overlay or modal-like composition
158
+
159
+ Use `Overlay` and `FocusScope` for app-local popovers or lightweight dialog surfaces. The app owns whether the surface is present and what action is performed.
160
+
161
+ 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`.
162
+
163
+ ```tsx
164
+ import { FocusScope, Input, List, Overlay, Screen, Text, mountTerminal } from "@valyrianjs/terminal";
165
+
166
+ const commands = ["Open file", "Run task", "Toggle panel"];
167
+ const state = { query: "", executed: "" };
168
+
169
+ function App() {
170
+ const visible = commands.filter((command) =>
171
+ command.toLowerCase().includes(state.query.toLowerCase())
172
+ );
173
+
174
+ return (
175
+ <Screen title="Overlay recipe">
176
+ <Text>{state.executed ? `Executed: ${state.executed}` : "Choose a command"}</Text>
177
+ <Overlay x={2} y={2} width={40} height={6} trapFocus>
178
+ <FocusScope>
179
+ <Input
180
+ id="query"
181
+ value={state.query}
182
+ placeholder="Search"
183
+ onchange={(event) => {
184
+ state.query = event.value;
185
+ }}
186
+ />
187
+ <List
188
+ id="results"
189
+ items={visible}
190
+ onpress={(event) => {
191
+ state.executed = event.value;
192
+ }}
193
+ />
194
+ </FocusScope>
195
+ </Overlay>
196
+ </Screen>
197
+ );
198
+ }
199
+
200
+ const session = mountTerminal(<App />);
201
+
202
+ session.focus("query");
203
+ session.dispatchKey("R");
204
+ session.focus("results");
131
205
  session.dispatchKey("ENTER");
132
206
 
133
- console.log(state.selected);
134
- console.log(state.opened);
207
+ console.log(session.output());
208
+ session.destroy();
135
209
  ```
136
210
 
137
- ## Scroll view with `height` and `highlightRows`
211
+ This local composition uses public focus, overlay, input, and list primitives. Keep shared command catalogs, permissions, and workflow orchestration in the app layer when the palette grows.
138
212
 
139
- Use this to clip vertical content and mark relevant rows inside the viewport.
213
+ ## Log view / follow-tail behavior with `LogView`
214
+
215
+ Use `LogView` for append-only logs or transcript-like panes. `followTail` is a `LogView` option, not a standalone primitive.
216
+
217
+ 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`.
140
218
 
141
219
  ```tsx
142
- /** @jsx v */
143
- /** @jsxFrag v.fragment */
144
-
145
- import { v } from "valyrian.js";
146
- import { Screen, ScrollView, Text, mountTerminal } from "valyrianjs-terminal";
147
-
148
- const session = mountTerminal(() => (
149
- <Screen>
150
- <ScrollView id="activity" height={3} highlightRows={[2]}>
151
- <Text>Alpha</Text>
152
- <Text>Beta</Text>
153
- <Text>Gamma</Text>
154
- <Text>Delta</Text>
155
- </ScrollView>
156
- </Screen>
157
- ), { ansi: true });
158
-
159
- session.focus("activity");
160
- console.log(session.output());
220
+ import { LogView, Screen, mountTerminal } from "@valyrianjs/terminal";
221
+
222
+ const entries = [
223
+ { id: "1", content: "User: hello" },
224
+ { id: "2", content: "System: ready" },
225
+ { id: "3", content: "User: summarize the latest output" }
226
+ ];
227
+
228
+ function App() {
229
+ return (
230
+ <Screen title="Log recipe">
231
+ <LogView
232
+ height={3}
233
+ entries={entries}
234
+ followTail
235
+ emptyText="No entries yet"
236
+ renderEntry={(entry) => entry.content}
237
+ />
238
+ </Screen>
239
+ );
240
+ }
241
+
242
+ const session = mountTerminal(<App />, { cols: 80, rows: 8 });
161
243
 
162
- session.dispatchKey("DOWN");
163
244
  console.log(session.output());
164
- console.log(session.ansiOutput());
245
+ session.destroy();
165
246
  ```
166
247
 
167
- ## Custom clipboard adapter
248
+ Keep log state in your app and pass entries into `LogView`.
168
249
 
169
- Use this when you want to connect copy and paste to your own clipboard implementation instead of the session's internal state.
250
+ ## Full-terminal layout
251
+
252
+ Use `Screen`, `Fixed`, `Split`, and `Pane` when a session should fill the available terminal size. `Split` uses the available body area from context, and panes take available width by default. Use `fill` when a surface should consume the full available height; block containers otherwise stack at content height.
253
+
254
+ Full 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`.
170
255
 
171
256
  ```tsx
172
- /** @jsx v */
173
- /** @jsxFrag v.fragment */
257
+ import { Fixed, Pane, Screen, Split, Text, mountTerminal } from "@valyrianjs/terminal";
258
+
259
+ function App() {
260
+ return (
261
+ <Screen title="Workspace">
262
+ <Fixed position="top" size={3}>
263
+ <Pane fill style={{ background: "#111111", padding: 1 }}>
264
+ <Text>Header</Text>
265
+ </Pane>
266
+ </Fixed>
267
+ <Split direction="row" gap={1}>
268
+ <Pane fill style={{ background: "#111111", padding: 1 }}>
269
+ <Text>Main content</Text>
270
+ </Pane>
271
+ <Pane fill style={{ background: "#111111", padding: 1 }}>
272
+ <Text>Side panel</Text>
273
+ </Pane>
274
+ </Split>
275
+ <Fixed position="bottom" size={3}>
276
+ <Pane fill style={{ background: "#111111", padding: 1 }}>
277
+ <Text>Ready</Text>
278
+ </Pane>
279
+ </Fixed>
280
+ </Screen>
281
+ );
282
+ }
283
+
284
+ const session = mountTerminal(<App />, { cols: 80, rows: 24 });
285
+
286
+ console.log(session.output());
287
+ session.destroy();
288
+ ```
289
+
290
+ Styles are expressed as recipes or inline style objects. The renderer translates those styles to supported terminal output for the current session, so avoid depending on raw ANSI sequences in rendered content. For style recipes in a runnable ANSI app, run `bun examples/docs/style-system.tsx`, use `Tab`, `Enter`, and `W` to change state, and quit with `Ctrl+C`; or open [`examples/docs/style-system.tsx`](../examples/docs/style-system.tsx). For responsive split sizing, 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).
291
+
292
+ For a full-screen responsive pizza builder with ingredient selection, `Split` fractions, a running total, and simulated checkout, run `bun examples/docs/pizza-builder.tsx`, choose toppings with `Up/Down` and `Space`, press `Enter`, resize with `R`, clear with `C`, and quit with `Ctrl+C`; or open [`examples/docs/pizza-builder.tsx`](../examples/docs/pizza-builder.tsx).
293
+
294
+ ## Clipboard adapter
174
295
 
175
- import { v } from "valyrian.js";
176
- import { Input, Screen, mountTerminal } from "valyrianjs-terminal";
296
+ Use a clipboard adapter when copy and paste should go through an application-provided clipboard implementation.
297
+
298
+ 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`.
299
+
300
+ ```tsx
301
+ import { Input, Screen, mountTerminal } from "@valyrianjs/terminal";
177
302
 
178
303
  const state = { value: "abcd" };
179
304
  const clipboard = {
@@ -186,101 +311,71 @@ const clipboard = {
186
311
  }
187
312
  };
188
313
 
189
- const session = mountTerminal(() => (
190
- <Screen>
191
- <Input
192
- id="name"
193
- value={state.value}
194
- onchange={(event) => {
195
- state.value = event.value;
196
- }}
197
- />
198
- </Screen>
199
- ), { clipboard });
314
+ function App() {
315
+ return (
316
+ <Screen title="Clipboard recipe">
317
+ <Input
318
+ id="name"
319
+ value={state.value}
320
+ onchange={(event) => {
321
+ state.value = event.value;
322
+ }}
323
+ />
324
+ </Screen>
325
+ );
326
+ }
327
+
328
+ const session = mountTerminal(<App />, { clipboard });
200
329
 
201
330
  session.focus("name");
202
- session.dispatchKey("HOME");
203
- session.dispatchKey("SHIFT_RIGHT");
204
- session.dispatchKey("SHIFT_RIGHT");
331
+ session.dispatchKey("CTRL_A");
205
332
  session.dispatchKey("CTRL_C");
206
333
 
207
- clipboard.value = "XY";
208
- session.dispatchKey("END");
209
- session.dispatchKey("CTRL_V");
210
-
211
334
  console.log(session.clipboard());
212
- console.log(state.value);
335
+ session.destroy();
213
336
  ```
214
337
 
215
- ## Coordinate-based interaction with `focusAt` and `clickAt`
338
+ Use `clipboard: false` when a session should rely on its local clipboard buffer.
216
339
 
217
- Use this in tests or adapters where the real entry point is frame coordinates rather than known ids.
340
+ ## Coordinate-based interaction
218
341
 
219
- ```tsx
220
- /** @jsx v */
221
- /** @jsxFrag v.fragment */
342
+ Use `focusAt` and `clickAt` when an adapter receives frame coordinates instead of known ids.
343
+
344
+ Related example: [`examples/docs/cursor.tsx`](../examples/docs/cursor.tsx). Run it with `bun examples/docs/cursor.tsx`, type text, press `C`, and quit with `Ctrl+C`.
222
345
 
223
- import { v } from "valyrian.js";
224
- import { Button, Input, Screen, mountTerminal } from "valyrianjs-terminal";
346
+ ```tsx
347
+ import { Button, Input, Screen, mountTerminal } from "@valyrianjs/terminal";
225
348
 
226
349
  const state = { clicks: 0 };
227
350
 
228
- const session = mountTerminal(() => (
229
- <Screen>
230
- <Input id="name" value="abc" />
231
- <Button id="save" onpress={() => {
232
- state.clicks += 1;
233
- }}>
234
- Save
235
- </Button>
236
- </Screen>
237
- ));
351
+ function App() {
352
+ return (
353
+ <Screen title="Coordinates">
354
+ <Input id="name" value="abc" />
355
+ <Button id="save" onpress={() => {
356
+ state.clicks += 1;
357
+ }}>
358
+ Save
359
+ </Button>
360
+ </Screen>
361
+ );
362
+ }
363
+
364
+ const session = mountTerminal(<App />);
238
365
 
239
366
  session.focusAt(2, 1);
240
367
  session.clickAt(3, 2);
241
368
 
242
369
  console.log(session.output());
243
370
  console.log(state.clicks);
244
- ```
245
-
246
- ## Inspect ANSI output with `ansiOutput`
247
-
248
- Use this when you need to verify cursor position, styles, or ANSI sequences in tests and integrations.
249
-
250
- ```tsx
251
- /** @jsx v */
252
- /** @jsxFrag v.fragment */
253
-
254
- import { v } from "valyrian.js";
255
- import { Input, Screen, mountTerminal } from "valyrianjs-terminal";
256
-
257
- const state = { value: "AB" };
258
-
259
- const session = mountTerminal(() => (
260
- <Screen title="ANSI Demo">
261
- <Input
262
- id="name"
263
- value={state.value}
264
- onchange={(event) => {
265
- state.value = event.value;
266
- }}
267
- />
268
- </Screen>
269
- ), { ansi: true });
270
-
271
- session.focus("name");
272
- session.dispatchKey("LEFT");
273
-
274
- const ansi = session.ansiOutput();
275
-
276
- console.log(ansi);
277
- console.log(/\u001b\[[0-9]+;[0-9]+H/.test(ansi));
371
+ session.destroy();
278
372
  ```
279
373
 
280
374
  ## See also
281
375
 
282
- - `docs/getting-started.md` for the minimal mounting flow
283
- - `docs/core-concepts.md` for the package mental model
284
- - `docs/interaction-model.md` for focus, keyboard, mouse, and clipboard
285
- - `docs/session-runtime.md` for lifecycle, streams, and session runtime
286
- - `docs/api-reference.md` for the full public surface
376
+ - [Getting Started](./getting-started.md) for the first project.
377
+ - [Core Concepts](./core-concepts.md) for the mental model.
378
+ - [Interaction Model](./interaction-model.md) for focus, keyboard, mouse, and event behavior.
379
+ - [Valyrian Modules](./valyrian-modules.md)
380
+ - [Session Runtime](./session-runtime.md) for streams and host integration.
381
+ - [API Reference](./api-reference.md) for props, payloads, and session methods.