@suds-cli/tea 0.0.0 → 0.1.0-alpha.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 (49) hide show
  1. package/README.md +260 -0
  2. package/dist/index.cjs +1125 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +337 -0
  5. package/dist/index.d.ts +337 -12
  6. package/dist/index.js +1084 -51
  7. package/dist/index.js.map +1 -1
  8. package/package.json +30 -18
  9. package/dist/commands.d.ts +0 -27
  10. package/dist/commands.d.ts.map +0 -1
  11. package/dist/commands.js +0 -106
  12. package/dist/commands.js.map +0 -1
  13. package/dist/index.d.ts.map +0 -1
  14. package/dist/input.d.ts +0 -8
  15. package/dist/input.d.ts.map +0 -1
  16. package/dist/input.js +0 -98
  17. package/dist/input.js.map +0 -1
  18. package/dist/keys.d.ts +0 -86
  19. package/dist/keys.d.ts.map +0 -1
  20. package/dist/keys.js +0 -317
  21. package/dist/keys.js.map +0 -1
  22. package/dist/messages.d.ts +0 -78
  23. package/dist/messages.d.ts.map +0 -1
  24. package/dist/messages.js +0 -104
  25. package/dist/messages.js.map +0 -1
  26. package/dist/mouse.d.ts +0 -46
  27. package/dist/mouse.d.ts.map +0 -1
  28. package/dist/mouse.js +0 -167
  29. package/dist/mouse.js.map +0 -1
  30. package/dist/program.d.ts +0 -39
  31. package/dist/program.d.ts.map +0 -1
  32. package/dist/program.js +0 -231
  33. package/dist/program.js.map +0 -1
  34. package/dist/renderer.d.ts +0 -19
  35. package/dist/renderer.d.ts.map +0 -1
  36. package/dist/renderer.js +0 -49
  37. package/dist/renderer.js.map +0 -1
  38. package/dist/screen.d.ts +0 -22
  39. package/dist/screen.d.ts.map +0 -1
  40. package/dist/screen.js +0 -35
  41. package/dist/screen.js.map +0 -1
  42. package/dist/terminal.d.ts +0 -32
  43. package/dist/terminal.d.ts.map +0 -1
  44. package/dist/terminal.js +0 -119
  45. package/dist/terminal.js.map +0 -1
  46. package/dist/types.d.ts +0 -36
  47. package/dist/types.d.ts.map +0 -1
  48. package/dist/types.js +0 -3
  49. package/dist/types.js.map +0 -1
package/README.md ADDED
@@ -0,0 +1,260 @@
1
+ # @suds-cli/tea
2
+
3
+ TypeScript port of [Bubble Tea](https://github.com/charmbracelet/bubbletea), the Elm-inspired terminal UI framework from Charm. Build interactive CLIs using a simple, functional architecture: Model-Update-View.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @suds-cli/tea
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```ts
14
+ import { createNodePlatform } from '@suds-cli/machine/node'
15
+ import {
16
+ Program,
17
+ quit,
18
+ KeyMsg,
19
+ KeyType,
20
+ type Model,
21
+ type Cmd,
22
+ type Msg,
23
+ } from '@suds-cli/tea'
24
+
25
+ // Define your message types
26
+ type AppMsg = Msg | { _tag: 'increment' } | { _tag: 'decrement' }
27
+
28
+ // Create a model implementing the Model interface
29
+ class Counter implements Model<AppMsg, Counter> {
30
+ constructor(public readonly count: number = 0) {}
31
+
32
+ init(): Cmd<AppMsg> {
33
+ return null
34
+ }
35
+
36
+ update(msg: AppMsg): [Counter, Cmd<AppMsg>] {
37
+ if (msg instanceof KeyMsg) {
38
+ switch (msg.key.type) {
39
+ case KeyType.Up:
40
+ return [new Counter(this.count + 1), null]
41
+ case KeyType.Down:
42
+ return [new Counter(this.count - 1), null]
43
+ case KeyType.Esc:
44
+ return [this, quit()]
45
+ }
46
+ }
47
+ return [this, null]
48
+ }
49
+
50
+ view(): string {
51
+ return `Count: ${this.count}\n\nPress ↑/↓ to change, Esc to quit`
52
+ }
53
+ }
54
+
55
+ // Create platform adapter and run the program
56
+ const platform = createNodePlatform()
57
+ const program = new Program(new Counter(), {
58
+ platform,
59
+ altScreen: true,
60
+ })
61
+ await program.run()
62
+ ```
63
+
64
+ ## Architecture
65
+
66
+ Tea follows the [Elm Architecture](https://guide.elm-lang.org/architecture/):
67
+
68
+ - **Model** — Your application state, implementing `init()`, `update()`, and `view()`
69
+ - **Msg** — Discriminated union of messages that trigger state changes
70
+ - **Cmd** — Async side effects that produce messages
71
+ - **Program** — Runtime that orchestrates the event loop
72
+
73
+ ### Messages
74
+
75
+ All messages must include a `_tag` discriminant for type-safe matching:
76
+
77
+ ```ts
78
+ type MyMsg =
79
+ | { _tag: 'tick'; time: Date }
80
+ | { _tag: 'data-loaded'; items: string[] }
81
+ ```
82
+
83
+ ### Commands
84
+
85
+ Commands are async functions that return messages. Use the built-in helpers:
86
+
87
+ ```ts
88
+ import { batch, sequence, tick, every, msg, quit } from '@suds-cli/tea'
89
+
90
+ // Lift a value into a command
91
+ const notify = msg({ _tag: 'notify', text: 'Hello' })
92
+
93
+ // Emit after delay
94
+ const delayed = tick(1000, (time) => ({ _tag: 'tick', time }))
95
+
96
+ // Emit aligned to interval boundary (for clocks, animations)
97
+ const interval = every(1000, (time) => ({ _tag: 'tick', time }))
98
+
99
+ // Run commands concurrently
100
+ const parallel = batch(cmd1, cmd2, cmd3)
101
+
102
+ // Run commands sequentially
103
+ const sequential = sequence(cmd1, cmd2, cmd3)
104
+
105
+ // Graceful exit
106
+ const exit = quit()
107
+ ```
108
+
109
+ ## Input Handling
110
+
111
+ ### Keyboard
112
+
113
+ ```ts
114
+ import { KeyMsg, KeyType, keyToString } from "@suds-cli/tea";
115
+
116
+ update(msg: Msg): [Model, Cmd<Msg>] {
117
+ if (msg instanceof KeyMsg) {
118
+ const { key } = msg;
119
+
120
+ // Check key type
121
+ if (key.type === KeyType.Enter) { /* ... */ }
122
+ if (key.type === KeyType.Tab) { /* ... */ }
123
+ if (key.type === KeyType.Up) { /* ... */ }
124
+
125
+ // Check for character input
126
+ if (key.type === KeyType.Runes) {
127
+ console.log(key.runes); // The typed character(s)
128
+ }
129
+
130
+ // Check modifiers
131
+ if (key.alt) { /* Alt+key pressed */ }
132
+ if (key.paste) { /* Pasted text */ }
133
+
134
+ // Get human-readable representation
135
+ console.log(keyToString(key)); // "ctrl+c", "alt+enter", "a"
136
+ }
137
+ return [this, null];
138
+ }
139
+ ```
140
+
141
+ ### Mouse
142
+
143
+ ```ts
144
+ import { MouseMsg, MouseAction, MouseButton } from "@suds-cli/tea";
145
+
146
+ update(msg: Msg): [Model, Cmd<Msg>] {
147
+ if (msg instanceof MouseMsg) {
148
+ const { event } = msg;
149
+
150
+ if (event.action === MouseAction.Press && event.button === MouseButton.Left) {
151
+ // Left click at event.x, event.y
152
+ }
153
+
154
+ if (event.button === MouseButton.WheelUp) {
155
+ // Scroll up
156
+ }
157
+
158
+ // Modifier keys
159
+ if (event.ctrl || event.alt || event.shift) { /* ... */ }
160
+ }
161
+ return [this, null];
162
+ }
163
+ ```
164
+
165
+ Enable mouse with program options:
166
+
167
+ ```ts
168
+ import { createNodePlatform } from '@suds-cli/machine/node'
169
+
170
+ const platform = createNodePlatform()
171
+ const program = new Program(model, {
172
+ platform,
173
+ mouseMode: 'cell', // Track clicks and drags
174
+ // mouseMode: "all", // Track all motion
175
+ })
176
+ ```
177
+
178
+ ## Terminal Control
179
+
180
+ Commands for terminal manipulation:
181
+
182
+ ```ts
183
+ import {
184
+ clearScreen,
185
+ hideCursor,
186
+ showCursor,
187
+ setWindowTitle,
188
+ enableMouseCellMotion,
189
+ enableMouseAllMotion,
190
+ disableMouse,
191
+ windowSize,
192
+ } from '@suds-cli/tea'
193
+
194
+ // In your update function
195
+ return [newModel, clearScreen()]
196
+ return [newModel, setWindowTitle('My App')]
197
+ return [newModel, batch(hideCursor(), clearScreen())]
198
+ ```
199
+
200
+ ## System Messages
201
+
202
+ The program emits these messages automatically:
203
+
204
+ ```ts
205
+ import {
206
+ WindowSizeMsg, // Terminal resized: { width, height }
207
+ FocusMsg, // Terminal gained focus
208
+ BlurMsg, // Terminal lost focus
209
+ InterruptMsg, // Ctrl+C pressed
210
+ QuitMsg, // Graceful shutdown requested
211
+ } from "@suds-cli/tea";
212
+
213
+ update(msg: Msg): [Model, Cmd<Msg>] {
214
+ if (msg instanceof WindowSizeMsg) {
215
+ return [this.withSize(msg.width, msg.height), null];
216
+ }
217
+ return [this, null];
218
+ }
219
+ ```
220
+
221
+ ## Program Options
222
+
223
+ ```ts
224
+ import { createNodePlatform } from '@suds-cli/machine/node'
225
+
226
+ // Create platform adapter with custom streams (optional)
227
+ const platform = createNodePlatform({
228
+ input: customInputStream,
229
+ output: customOutputStream,
230
+ })
231
+
232
+ const program = new Program(model, {
233
+ platform, // Platform adapter for terminal I/O and system signals
234
+ altScreen: true, // Use alternate screen buffer
235
+ mouseMode: 'cell', // "cell" | "all" | false
236
+ fps: 60, // Render frame rate
237
+ reportFocus: true, // Receive focus/blur events
238
+ bracketedPaste: true, // Distinguish pasted text
239
+ })
240
+ ```
241
+
242
+ ### Platform Adapters
243
+
244
+ Tea uses `@suds-cli/machine` for platform abstraction, making it possible to run terminal UIs in different environments:
245
+
246
+ - **Node.js**: `createNodePlatform()` from `@suds-cli/machine/node`
247
+ - **Browser** (with xterm.js): `createBrowserPlatform()` from `@suds-cli/machine/browser`
248
+
249
+ The platform adapter provides terminal I/O, signal handling, environment access, and more.
250
+
251
+ ## Scripts
252
+
253
+ - `pnpm -C packages/tea build`
254
+ - `pnpm -C packages/tea test`
255
+ - `pnpm -C packages/tea lint`
256
+ - `pnpm -C packages/tea generate:api-report`
257
+
258
+ ## License
259
+
260
+ MIT