@valyrianjs/terminal 0.1.0 → 0.1.1
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.
- package/README.md +22 -22
- package/docs/api-reference.md +103 -103
- package/docs/cookbook.md +23 -23
- package/docs/core-concepts.md +50 -50
- package/docs/getting-started.md +22 -22
- package/docs/interaction-model.md +55 -55
- package/docs/local-demo.md +10 -10
- package/docs/session-runtime.md +97 -97
- package/package.json +1 -1
package/docs/core-concepts.md
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
1
1
|
# Core Concepts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This guide explains the package mental model before going into runtime details or the API reference.
|
|
4
4
|
|
|
5
|
-
## 1.
|
|
5
|
+
## 1. Terminal-First Primitives
|
|
6
6
|
|
|
7
|
-
`valyrianjs-terminal`
|
|
7
|
+
`valyrianjs-terminal` does not render HTML or browser components. Its primitives generate their own terminal nodes, which are then converted into plain text or an ANSI frame.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The core pieces are grouped like this:
|
|
10
10
|
|
|
11
11
|
- layout: `Screen`, `Box`, `View`, `Text`, `Table`, `Row`, `Td`
|
|
12
|
-
-
|
|
12
|
+
- interaction: `Input`, `Button`, `List`, `ScrollView`
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Think of it as a text UI DSL, not as a visual adaptation of the DOM.
|
|
15
15
|
|
|
16
|
-
## 2.
|
|
16
|
+
## 2. Two Working Modes
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
There are two main entrypoints:
|
|
19
19
|
|
|
20
|
-
- `renderTerminal()`
|
|
21
|
-
- `mountTerminal()`
|
|
20
|
+
- `renderTerminal()` to generate plain text from a terminal tree
|
|
21
|
+
- `mountTerminal()` to create an interactive session with focus, keyboard, mouse, and optional writes to streams
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Simple rule:
|
|
24
24
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
25
|
+
- if you only want to inspect content, use `renderTerminal()`
|
|
26
|
+
- if you need interaction or a live runtime, use `mountTerminal()`
|
|
27
27
|
|
|
28
|
-
## 3.
|
|
28
|
+
## 3. State Lives Outside the Library
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
The library renders whatever your UI function returns with the current state. It does not manage an application store for you.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
That means:
|
|
33
33
|
|
|
34
|
-
-
|
|
35
|
-
- `mountTerminal()`
|
|
36
|
-
- `session.update()`
|
|
34
|
+
- your handlers mutate external state
|
|
35
|
+
- `mountTerminal()` re-evaluates the render function
|
|
36
|
+
- `session.update()` is only needed when you mutated state outside a handler that already triggers a rerender
|
|
37
37
|
|
|
38
|
-
## 4. `id`
|
|
38
|
+
## 4. `id` Is the Key to Interaction
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Interactive nodes can render without an `id`, but you lose much of the programmatic control.
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
You need a stable `id` if you want to:
|
|
43
43
|
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
44
|
+
- focus with `session.focus(id)`
|
|
45
|
+
- activate with `session.click(id)`
|
|
46
|
+
- participate in coordinate-based hitboxes
|
|
47
|
+
- get consistent focus and navigation flows
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Practical recommendation: give an `id` to every `Input`, `Button`, `List`, and `ScrollView` that will live beyond a trivial test.
|
|
50
50
|
|
|
51
|
-
## 5.
|
|
51
|
+
## 5. Focus and Hitboxes
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
The session computes hitboxes from the current rendered frame. This enables two kinds of interaction:
|
|
54
54
|
|
|
55
|
-
-
|
|
56
|
-
-
|
|
55
|
+
- by identifier: `focus(id)`, `click(id)`
|
|
56
|
+
- by coordinates: `focusAt(x, y)`, `clickAt(x, y)`
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Sequential focus also comes from the current tree:
|
|
59
59
|
|
|
60
60
|
- `focusNext()`
|
|
61
61
|
- `focusPrev()`
|
|
62
62
|
- `dispatchKey("TAB")`
|
|
63
63
|
- `dispatchKey("SHIFT_TAB")`
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
If the tree changes, focus order and geometry change as well.
|
|
66
66
|
|
|
67
|
-
## 6.
|
|
67
|
+
## 6. Plain Output vs ANSI Output
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
The package works with two useful representations:
|
|
70
70
|
|
|
71
|
-
-
|
|
72
|
-
-
|
|
71
|
+
- plain output: returned by `renderTerminal()` and `session.output()`
|
|
72
|
+
- ANSI output: returned by `session.ansiOutput()` and, if you enable `ansi: true`, also written to `stdout`
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
Use plain output for snapshots and tests. Use ANSI when you need cursor control, visual spans, focus, or integration with a real terminal.
|
|
75
75
|
|
|
76
|
-
## 7. Streams
|
|
76
|
+
## 7. Streams and Cleanup
|
|
77
77
|
|
|
78
|
-
`mountTerminal()`
|
|
78
|
+
`mountTerminal()` can work without streams, but if you connect `stdin` and `stdout` the session enters real runtime mode.
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
When you mount with `stdin`:
|
|
81
81
|
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
82
|
+
- the session listens for `data`
|
|
83
|
+
- it tries to enable raw mode if the stream supports it
|
|
84
|
+
- it tries to restore it when you call `destroy()`
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
That is why `destroy()` is not optional when you connect real streams.
|
|
87
87
|
|
|
88
|
-
## 8.
|
|
88
|
+
## 8. Where to Go Next
|
|
89
89
|
|
|
90
|
-
- `docs/interaction-model.md`
|
|
91
|
-
- `docs/session-runtime.md`
|
|
92
|
-
- `docs/cookbook.md`
|
|
93
|
-
- `docs/api-reference.md`
|
|
90
|
+
- `docs/interaction-model.md` explains what each interactive primitive does
|
|
91
|
+
- `docs/session-runtime.md` explains lifecycle, streams, clipboard, coordinates, and mouse support
|
|
92
|
+
- `docs/cookbook.md` shows short recipes for common tasks
|
|
93
|
+
- `docs/api-reference.md` works as a point reference
|
package/docs/getting-started.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Getting Started
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This guide covers the minimum happy path to get started with `valyrianjs-terminal`.
|
|
4
4
|
|
|
5
|
-
## 1.
|
|
5
|
+
## 1. Install the Packages
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install valyrianjs-terminal valyrian.js
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
## 2.
|
|
11
|
+
## 2. Start with Static Rendering
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
First validate layout and content without streams or the interactive runtime.
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
16
|
/** @jsx v */
|
|
@@ -29,15 +29,15 @@ const output = renderTerminal(
|
|
|
29
29
|
console.log(output);
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Use this path when you want to:
|
|
33
33
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
34
|
+
- generate snapshots
|
|
35
|
+
- validate layout
|
|
36
|
+
- test plain output without connecting `stdin` or `stdout`
|
|
37
37
|
|
|
38
|
-
## 3.
|
|
38
|
+
## 3. Move to a Minimal Interactive Session
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Once you need text editing, focus management, or keyboard handling, switch to `mountTerminal()`.
|
|
41
41
|
|
|
42
42
|
```tsx
|
|
43
43
|
/** @jsx v */
|
|
@@ -80,11 +80,11 @@ session.dispatchKey("i");
|
|
|
80
80
|
console.log(session.output());
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
Practical rule: give stable `id` values to `Input`, `Button`, `List`, and `ScrollView` if you want to use focus, coordinates, or programmatic interaction.
|
|
84
84
|
|
|
85
|
-
## 4.
|
|
85
|
+
## 4. Understand the Minimum Lifecycle
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
The session does not store your application state; it re-evaluates the render function with the current external state.
|
|
88
88
|
|
|
89
89
|
```tsx
|
|
90
90
|
/** @jsx v */
|
|
@@ -108,16 +108,16 @@ console.log(session.output());
|
|
|
108
108
|
session.destroy();
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
Quick summary:
|
|
112
112
|
|
|
113
|
-
- `output()`
|
|
114
|
-
- `ansiOutput()`
|
|
115
|
-
- `update()`
|
|
116
|
-
- `destroy()`
|
|
113
|
+
- `output()` returns the current frame as plain text
|
|
114
|
+
- `ansiOutput()` returns the current frame as full ANSI output
|
|
115
|
+
- `update()` re-evaluates the render function
|
|
116
|
+
- `destroy()` removes listeners and cleans up `stdin` when applicable
|
|
117
117
|
|
|
118
|
-
## 5.
|
|
118
|
+
## 5. When to Connect Streams
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
Connect `stdin`, `stdout`, and `ansi: true` only when you are ready to run a real terminal UI.
|
|
121
121
|
|
|
122
122
|
```tsx
|
|
123
123
|
/** @jsx v */
|
|
@@ -137,9 +137,9 @@ const session = mountTerminal(() => (
|
|
|
137
137
|
});
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
For tests or snapshots, `renderTerminal()` or `mountTerminal()` without streams is usually enough.
|
|
141
141
|
|
|
142
|
-
##
|
|
142
|
+
## Next Reading
|
|
143
143
|
|
|
144
144
|
- `docs/core-concepts.md`
|
|
145
145
|
- `docs/interaction-model.md`
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
# Interaction Model
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This guide describes how the package's interactive primitives respond. If the base model is not clear yet, start with `docs/core-concepts.md`. If you need session lifecycle, streams, or runtime details, continue with `docs/session-runtime.md`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Shared rules
|
|
6
6
|
|
|
7
|
-
- `Tab`
|
|
8
|
-
- `Shift+Tab`
|
|
9
|
-
-
|
|
10
|
-
- `focusAt(x, y)`
|
|
7
|
+
- `Tab` moves to the next focusable element.
|
|
8
|
+
- `Shift+Tab` moves back to the previous one.
|
|
9
|
+
- Interactive nodes need an `id` if you want to focus or activate them programmatically.
|
|
10
|
+
- `focusAt(x, y)` and `clickAt(x, y)` depend on the hitboxes in the current frame.
|
|
11
11
|
|
|
12
12
|
## `Input`
|
|
13
13
|
|
|
14
|
-
`Input`
|
|
14
|
+
`Input` is a single-line editing primitive with a cursor, selection, and submit support.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Observable behavior:
|
|
17
17
|
|
|
18
|
-
-
|
|
19
|
-
- `Enter`:
|
|
20
|
-
- `Left` / `Right`:
|
|
21
|
-
- `Shift+Left` / `Shift+Right`:
|
|
22
|
-
- `Alt+Left` / `Alt+Right`:
|
|
23
|
-
- `Home` / `End`:
|
|
24
|
-
- `Ctrl+A`:
|
|
25
|
-
- `Ctrl+C`:
|
|
26
|
-
- `Ctrl+X`:
|
|
27
|
-
- `Ctrl+V`:
|
|
28
|
-
- `Backspace` / `Delete`:
|
|
18
|
+
- regular text: inserts characters
|
|
19
|
+
- `Enter`: triggers `onsubmit`
|
|
20
|
+
- `Left` / `Right`: moves the cursor
|
|
21
|
+
- `Shift+Left` / `Shift+Right`: extends the selection
|
|
22
|
+
- `Alt+Left` / `Alt+Right`: moves by word
|
|
23
|
+
- `Home` / `End`: jumps to the start or end
|
|
24
|
+
- `Ctrl+A`: selects all
|
|
25
|
+
- `Ctrl+C`: copies the selection
|
|
26
|
+
- `Ctrl+X`: cuts the selection
|
|
27
|
+
- `Ctrl+V`: pastes from the clipboard
|
|
28
|
+
- `Backspace` / `Delete`: removes content
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Main handlers:
|
|
31
31
|
|
|
32
32
|
- `onchange`
|
|
33
33
|
- `oninput`
|
|
@@ -36,15 +36,15 @@ Handlers principales:
|
|
|
36
36
|
|
|
37
37
|
## `Button`
|
|
38
38
|
|
|
39
|
-
`Button`
|
|
39
|
+
`Button` represents a discrete action.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Observable behavior:
|
|
42
42
|
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
43
|
+
- responds to `Enter` and `Space` when focused
|
|
44
|
+
- responds to `session.click(id)`
|
|
45
|
+
- responds to `session.clickAt(x, y)` when the hitbox lands on the button
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Main handlers:
|
|
48
48
|
|
|
49
49
|
- `onpress`
|
|
50
50
|
- `onclick`
|
|
@@ -53,16 +53,16 @@ Handlers principales:
|
|
|
53
53
|
|
|
54
54
|
## `List`
|
|
55
55
|
|
|
56
|
-
`List`
|
|
56
|
+
`List` models row selection and activation.
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Observable behavior:
|
|
59
59
|
|
|
60
|
-
- `Up` / `Left`:
|
|
61
|
-
- `Down` / `Right`:
|
|
62
|
-
- `Enter`:
|
|
63
|
-
-
|
|
60
|
+
- `Up` / `Left`: moves selection up
|
|
61
|
+
- `Down` / `Right`: moves selection down
|
|
62
|
+
- `Enter`: triggers `onpress`
|
|
63
|
+
- mouse hover exposes the current row, index, and value
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Main handlers:
|
|
66
66
|
|
|
67
67
|
- `onchange`
|
|
68
68
|
- `onpress`
|
|
@@ -72,21 +72,21 @@ Handlers principales:
|
|
|
72
72
|
- `oncapturestart`
|
|
73
73
|
- `oncaptureend`
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
With `pointerCapture`, the list keeps the interaction during a drag even if the pointer leaves the initial hitbox.
|
|
76
76
|
|
|
77
77
|
## `ScrollView`
|
|
78
78
|
|
|
79
|
-
`ScrollView`
|
|
79
|
+
`ScrollView` clips vertical content and exposes viewport-based interaction.
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
Observable behavior:
|
|
82
82
|
|
|
83
|
-
- `Up`:
|
|
84
|
-
- `Down`:
|
|
85
|
-
- `height`:
|
|
86
|
-
- `highlightRows`:
|
|
87
|
-
-
|
|
83
|
+
- `Up`: scrolls up
|
|
84
|
+
- `Down`: scrolls down
|
|
85
|
+
- `height`: defines the visible viewport
|
|
86
|
+
- `highlightRows`: highlights specific visible rows
|
|
87
|
+
- mouse hover exposes the visible row and rendered text
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
Main handlers:
|
|
90
90
|
|
|
91
91
|
- `onhover`
|
|
92
92
|
- `onrowenter`
|
|
@@ -94,22 +94,22 @@ Handlers principales:
|
|
|
94
94
|
- `oncapturestart`
|
|
95
95
|
- `oncaptureend`
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
With `pointerCapture`, scrolling keeps the interaction during a drag even if the pointer leaves the viewport.
|
|
98
98
|
|
|
99
|
-
## Mouse
|
|
99
|
+
## Mouse and pointer capture
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
When the session receives SGR mouse events:
|
|
102
102
|
|
|
103
|
-
- `press`:
|
|
104
|
-
- `drag`:
|
|
105
|
-
- `release`:
|
|
106
|
-
- `wheel-up` / `wheel-down`:
|
|
103
|
+
- `press`: focuses and activates the matching hitbox
|
|
104
|
+
- `drag`: extends selection in `Input` or updates hover in `List` and `ScrollView`
|
|
105
|
+
- `release`: ends capture and clears hover when needed
|
|
106
|
+
- `wheel-up` / `wheel-down`: translate to vertical navigation
|
|
107
107
|
|
|
108
|
-
`pointerCapture`
|
|
108
|
+
`pointerCapture` currently applies only to `List` and `ScrollView`.
|
|
109
109
|
|
|
110
|
-
##
|
|
110
|
+
## Where to go next
|
|
111
111
|
|
|
112
|
-
- `docs/core-concepts.md`
|
|
113
|
-
- `docs/session-runtime.md`
|
|
114
|
-
- `docs/cookbook.md`
|
|
115
|
-
- `docs/api-reference.md`
|
|
112
|
+
- `docs/core-concepts.md` for the package mental model
|
|
113
|
+
- `docs/session-runtime.md` for lifecycle, streams, clipboard, and runtime
|
|
114
|
+
- `docs/cookbook.md` for practical recipes
|
|
115
|
+
- `docs/api-reference.md` for quick lookup of props, payloads, and types
|
package/docs/local-demo.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Local Demo
|
|
2
2
|
|
|
3
|
-
`examples/`
|
|
3
|
+
`examples/` exists only to support local development. It is not part of the package published to npm, it does not appear in `exports`, and `valyrianjs-terminal` does not publish a CLI.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Files
|
|
6
6
|
|
|
7
|
-
- `examples/demo.tsx`:
|
|
8
|
-
- `examples/basic.tsx`:
|
|
9
|
-
- `examples/cli.tsx`:
|
|
7
|
+
- `examples/demo.tsx`: defines `createDemoState()` and `DemoApp`; validates primitive composition (`Screen`, `Box`, `View`, `Text`, `Input`, `Button`, `List`, `ScrollView`, `Table`, `Row`, `Td`) and basic event payloads.
|
|
8
|
+
- `examples/basic.tsx`: validates the minimum path for using `renderTerminal()` in snapshot mode and `mountTerminal()` with local `stdin`/`stdout`.
|
|
9
|
+
- `examples/cli.tsx`: validates the local launcher with `--help`, `--snapshot`, initial focus, exit via `Esc` or `Ctrl+C`, and ANSI cleanup on close.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Commands
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
bun run examples/basic.tsx
|
|
@@ -21,8 +21,8 @@ bun run typecheck
|
|
|
21
21
|
bun run build
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Scope
|
|
25
25
|
|
|
26
|
-
- `--snapshot`
|
|
27
|
-
-
|
|
28
|
-
-
|
|
26
|
+
- `--snapshot` prints the example UI as plain text.
|
|
27
|
+
- without `--snapshot`, the examples mount a local session connected to `process.stdin` and `process.stdout`.
|
|
28
|
+
- these files are not a distributed interface for package consumers; they are manual fixtures for validating the adapter on a local machine.
|