termcast 1.3.24 → 1.3.26

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 (53) hide show
  1. package/dist/apis/toast.d.ts +5 -0
  2. package/dist/apis/toast.d.ts.map +1 -1
  3. package/dist/apis/toast.js +7 -43
  4. package/dist/apis/toast.js.map +1 -1
  5. package/dist/build.d.ts.map +1 -1
  6. package/dist/build.js +1 -0
  7. package/dist/build.js.map +1 -1
  8. package/dist/cli.d.ts +1 -0
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +21 -10
  11. package/dist/cli.js.map +1 -1
  12. package/dist/compile.d.ts +2 -1
  13. package/dist/compile.d.ts.map +1 -1
  14. package/dist/compile.js +9 -7
  15. package/dist/compile.js.map +1 -1
  16. package/dist/components/form/index.d.ts.map +1 -1
  17. package/dist/components/form/index.js +5 -3
  18. package/dist/components/form/index.js.map +1 -1
  19. package/dist/components/list.d.ts.map +1 -1
  20. package/dist/components/list.js +16 -9
  21. package/dist/components/list.js.map +1 -1
  22. package/dist/examples/toast-variations.d.ts +2 -0
  23. package/dist/examples/toast-variations.d.ts.map +1 -0
  24. package/dist/examples/toast-variations.js +122 -0
  25. package/dist/examples/toast-variations.js.map +1 -0
  26. package/dist/release.d.ts +1 -1
  27. package/dist/release.d.ts.map +1 -1
  28. package/dist/release.js +29 -33
  29. package/dist/release.js.map +1 -1
  30. package/dist/utils/run-command.d.ts +3 -2
  31. package/dist/utils/run-command.d.ts.map +1 -1
  32. package/dist/utils/run-command.js +9 -3
  33. package/dist/utils/run-command.js.map +1 -1
  34. package/package.json +2 -3
  35. package/src/apis/toast.tsx +37 -62
  36. package/src/build.tsx +1 -0
  37. package/src/cli.tsx +23 -11
  38. package/src/compile.tsx +10 -6
  39. package/src/components/form/index.tsx +20 -11
  40. package/src/components/list.tsx +54 -31
  41. package/src/examples/form-basic.vitest.tsx +8 -8
  42. package/src/examples/list-with-detail.vitest.tsx +8 -8
  43. package/src/examples/list-with-sections.vitest.tsx +9 -9
  44. package/src/examples/list-with-toast.vitest.tsx +16 -16
  45. package/src/examples/simple-file-picker.vitest.tsx +12 -8
  46. package/src/examples/simple-grid.vitest.tsx +2 -2
  47. package/src/examples/simple-navigation.vitest.tsx +16 -16
  48. package/src/examples/swift-extension.vitest.tsx +2 -2
  49. package/src/examples/toast-variations.tsx +150 -0
  50. package/src/examples/toast-variations.vitest.tsx +370 -0
  51. package/src/extensions/dev.vitest.tsx +12 -10
  52. package/src/release.tsx +32 -38
  53. package/src/utils/run-command.tsx +10 -3
@@ -43,6 +43,7 @@ test('file picker shows form fields', async () => {
43
43
 
44
44
 
45
45
 
46
+
46
47
  ◆ Your Name
47
48
  │ John Doe
48
49
 
@@ -111,23 +112,24 @@ test('typing opens autocomplete dialog with file list', async () => {
111
112
 
112
113
 
113
114
 
114
- ◇┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
115
- │┃
116
- │┃ Filter: s
115
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
117
116
  ◇┃
118
- │┃ 📁 extensions/
117
+ │┃ Filter: s
118
+ │┃
119
+ ◇┃ 📁 extensions/
119
120
  │┃ 📁 extensions/messages/
120
121
  │┃ 📁 extensions/messages/assets/
121
122
  │┃ 📁 extensions/messages/metadata/
122
- ◆┃ 📁 extensions/messages/src/
123
- │┃ 📁 extensions/messages/src/api/
123
+ │┃ 📁 extensions/messages/src/
124
+ ◆┃ 📁 extensions/messages/src/api/
124
125
  │┃ 📁 extensions/messages/src/components/
125
126
  │┃ 📁 extensions/messages/src/hooks/
126
127
  │┃ 📁 extensions/messages/src/tools/
127
- ◇┃ 📁 extensions/messages/swift/
128
- │┃
128
+ │┃ 📁 extensions/messages/swift/
129
+ ◇┃
129
130
  │┃ ↑↓ navigate ⏎/tab select esc close
130
131
  │━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
132
+ │ Choose exactly one file
131
133
 
132
134
 
133
135
 
@@ -187,6 +189,7 @@ test('escape closes autocomplete without going back', async () => {
187
189
 
188
190
 
189
191
 
192
+
190
193
  ◇ Your Name
191
194
  │ John Doe
192
195
 
@@ -297,6 +300,7 @@ test('selecting first item with enter adds it to the list', async () => {
297
300
 
298
301
 
299
302
 
303
+
300
304
  ctrl ↵ submit tab navigate ^k actions"
301
305
  `)
302
306
  }, 15000)
@@ -70,8 +70,8 @@ test('grid navigation and display', async () => {
70
70
  Search items...
71
71
 
72
72
  Fruits ▲
73
- ›🍎 Apple ▀
74
- 🍌 Banana
73
+ 🍎 Apple ▀
74
+ ›🍌 Banana
75
75
  🍒 Cherry
76
76
 
77
77
  Animals
@@ -367,10 +367,10 @@ test('navigation with actions panel', async () => {
367
367
 
368
368
 
369
369
 
370
-
371
- open detail┌────────────────────────────────────┐
372
- ✓ Copied to Clipboard - First Item
373
- └────────────────────────────────────┘"
370
+ ┌───────────────────────┐
371
+ Copied to Clipboard │
372
+ First Item
373
+ └───────────────────────┘"
374
374
  `)
375
375
 
376
376
  // Wait for toast to clear, then navigate to second item
@@ -412,10 +412,10 @@ test('navigation with actions panel', async () => {
412
412
 
413
413
 
414
414
 
415
-
416
- go back ↑↓┌────────────────────────────────────┐
417
- ✓ Copied to Clipboard - First Item
418
- └────────────────────────────────────┘"
415
+ ┌───────────────────────┐
416
+ Copied to Clipboard │
417
+ First Item
418
+ └───────────────────────┘"
419
419
  `)
420
420
 
421
421
  // Open actions panel in detail view
@@ -445,10 +445,10 @@ test('navigation with actions panel', async () => {
445
445
 
446
446
 
447
447
 
448
-
449
- ┌────────────────────────────────────┐
450
- ✓ Copied to Clipboard - First Item
451
- └────────────────────────────────────┘"
448
+ ┌───────────────────────┐
449
+ │ ✓ Copied to Clipboard │
450
+ First Item
451
+ └───────────────────────┘"
452
452
  `)
453
453
 
454
454
  // Select Go Back action
@@ -482,10 +482,10 @@ test('navigation with actions panel', async () => {
482
482
 
483
483
 
484
484
 
485
-
486
- open detail┌────────────────────────────────────┐
487
- ✓ Copied to Clipboard - First Item
488
- └────────────────────────────────────┘"
485
+ ┌───────────────────────┐
486
+ Copied to Clipboard │
487
+ First Item
488
+ └───────────────────────┘"
489
489
  `)
490
490
  }, 15000)
491
491
 
@@ -81,8 +81,8 @@ test('swift extension dev mode shows command list', async () => {
81
81
  Search commands...
82
82
 
83
83
  Commands
84
- ›List Items Displays a simple list with some items view
85
- Swift List Displays a list of items returned by a Swift f view
84
+ ›List Items Displays a simple list with some items view
85
+ Swift List Displays a list of items returned by a Swift fu view
86
86
 
87
87
 
88
88
 
@@ -0,0 +1,150 @@
1
+ import React, { useState } from 'react'
2
+ import { List, ActionPanel, Action, renderWithProviders } from 'termcast'
3
+ import { Toast, ToastContent } from 'termcast/src/apis/toast'
4
+
5
+ const toastVariations = [
6
+ {
7
+ name: 'Simple Success',
8
+ toast: new Toast({
9
+ title: 'Success',
10
+ style: Toast.Style.Success,
11
+ }),
12
+ },
13
+ {
14
+ name: 'Simple Failure',
15
+ toast: new Toast({
16
+ title: 'Error',
17
+ style: Toast.Style.Failure,
18
+ }),
19
+ },
20
+ {
21
+ name: 'With Short Message',
22
+ toast: new Toast({
23
+ title: 'Copied',
24
+ message: 'Text copied to clipboard',
25
+ style: Toast.Style.Success,
26
+ }),
27
+ },
28
+ {
29
+ name: 'With Long Message',
30
+ toast: new Toast({
31
+ title: 'Error',
32
+ message:
33
+ 'This is a very long error message that should wrap to multiple lines when displayed in the toast component. It contains detailed information about what went wrong during the operation.',
34
+ style: Toast.Style.Failure,
35
+ }),
36
+ },
37
+ {
38
+ name: 'With Super Long Message',
39
+ toast: new Toast({
40
+ title: 'Warning',
41
+ message:
42
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.',
43
+ style: Toast.Style.Failure,
44
+ }),
45
+ },
46
+ {
47
+ name: 'With Primary Action',
48
+ toast: new Toast({
49
+ title: 'File Deleted',
50
+ message: 'document.pdf was moved to trash',
51
+ style: Toast.Style.Success,
52
+ primaryAction: {
53
+ title: 'Undo',
54
+ onAction: () => {},
55
+ },
56
+ }),
57
+ },
58
+ {
59
+ name: 'With Both Actions',
60
+ toast: new Toast({
61
+ title: 'Update Available',
62
+ message: 'Version 2.0 is ready to install',
63
+ style: Toast.Style.Success,
64
+ primaryAction: {
65
+ title: 'Install',
66
+ onAction: () => {},
67
+ },
68
+ secondaryAction: {
69
+ title: 'Later',
70
+ onAction: () => {},
71
+ },
72
+ }),
73
+ },
74
+ {
75
+ name: 'Long Title with Actions',
76
+ toast: new Toast({
77
+ title: 'Operation Completed Successfully',
78
+ message: 'All files have been processed',
79
+ style: Toast.Style.Success,
80
+ primaryAction: {
81
+ title: 'View Results',
82
+ onAction: () => {},
83
+ },
84
+ secondaryAction: {
85
+ title: 'Dismiss',
86
+ onAction: () => {},
87
+ },
88
+ }),
89
+ },
90
+ {
91
+ name: 'Animated Loading',
92
+ toast: new Toast({
93
+ title: 'Processing',
94
+ message: 'Please wait while we process your request...',
95
+ style: Toast.Style.Animated,
96
+ }),
97
+ },
98
+ {
99
+ name: 'Error with Retry',
100
+ toast: new Toast({
101
+ title: 'Connection Failed',
102
+ message:
103
+ 'Unable to connect to the server. Please check your internet connection and try again.',
104
+ style: Toast.Style.Failure,
105
+ primaryAction: {
106
+ title: 'Retry',
107
+ onAction: () => {},
108
+ },
109
+ }),
110
+ },
111
+ ]
112
+
113
+ function ToastVariationsExample(): any {
114
+ const [selectedIndex, setSelectedIndex] = useState(0)
115
+ const selectedToast = toastVariations[selectedIndex]
116
+
117
+ return (
118
+ <box flexDirection="column" width="100%" height="100%">
119
+ <List
120
+ navigationTitle="Toast Variations"
121
+ onSelectionChange={(id) => {
122
+ if (id) {
123
+ const index = toastVariations.findIndex((v) => v.name === id)
124
+ if (index !== -1) {
125
+ setSelectedIndex(index)
126
+ }
127
+ }
128
+ }}
129
+ >
130
+ {toastVariations.map((variation) => (
131
+ <List.Item
132
+ key={variation.name}
133
+ id={variation.name}
134
+ title={variation.name}
135
+ actions={
136
+ <ActionPanel>
137
+ <Action title="Select" onAction={() => {}} />
138
+ </ActionPanel>
139
+ }
140
+ />
141
+ ))}
142
+ </List>
143
+ <box position="absolute" bottom={0} left={0} width="100%">
144
+ <ToastContent toast={selectedToast.toast} onHide={() => {}} />
145
+ </box>
146
+ </box>
147
+ )
148
+ }
149
+
150
+ renderWithProviders(<ToastVariationsExample />)
@@ -0,0 +1,370 @@
1
+ import { test, expect, afterEach, beforeEach } from 'vitest'
2
+ import { launchTerminal, Session } from 'tuistory/src'
3
+
4
+ let session: Session
5
+
6
+ beforeEach(async () => {
7
+ session = await launchTerminal({
8
+ command: 'bun',
9
+ args: ['src/examples/toast-variations.tsx'],
10
+ cols: 80,
11
+ rows: 30,
12
+ })
13
+ })
14
+
15
+ afterEach(() => {
16
+ session?.close()
17
+ })
18
+
19
+ test('toast variations display correctly', async () => {
20
+ // Simple Success
21
+ const simpleSuccess = await session.text({
22
+ waitFor: (text) => text.includes('Simple Success') && text.includes('Success'),
23
+ })
24
+ expect(simpleSuccess).toMatchInlineSnapshot(`
25
+ "
26
+
27
+
28
+ Toast Variations ─────────────────────────────────────────────────────────
29
+
30
+ Search...
31
+
32
+ ›Simple Success
33
+ Simple Failure
34
+ With Short Message
35
+ With Long Message
36
+ With Super Long Message
37
+ With Primary Action
38
+ With Both Actions
39
+ Long Title with Actions
40
+ Animated Loading
41
+ Error with Retry
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+ ┌──────────────────────────────────────────────────────────────────────────┐
52
+ │ ✓ Success │
53
+ └──────────────────────────────────────────────────────────────────────────┘"
54
+ `)
55
+
56
+ // Simple Failure
57
+ await session.press('down')
58
+ const simpleFailure = await session.text()
59
+ expect(simpleFailure).toMatchInlineSnapshot(`
60
+ "
61
+
62
+
63
+ Toast Variations ─────────────────────────────────────────────────────────
64
+
65
+ Search...
66
+
67
+ Simple Success
68
+ ›Simple Failure
69
+ With Short Message
70
+ With Long Message
71
+ With Super Long Message
72
+ With Primary Action
73
+ With Both Actions
74
+ Long Title with Actions
75
+ Animated Loading
76
+ Error with Retry
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+ ┌──────────────────────────────────────────────────────────────────────────┐
87
+ │ ✗ Error │
88
+ └──────────────────────────────────────────────────────────────────────────┘"
89
+ `)
90
+
91
+ // With Short Message
92
+ await session.press('down')
93
+ const shortMessage = await session.text()
94
+ expect(shortMessage).toMatchInlineSnapshot(`
95
+ "
96
+
97
+
98
+ Toast Variations ─────────────────────────────────────────────────────────
99
+
100
+ Search...
101
+
102
+ Simple Success
103
+ Simple Failure
104
+ ›With Short Message
105
+ With Long Message
106
+ With Super Long Message
107
+ With Primary Action
108
+ With Both Actions
109
+ Long Title with Actions
110
+ Animated Loading
111
+ Error with Retry
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+ ┌──────────────────────────────────────────────────────────────────────────┐
121
+ │ ✓ Copied │
122
+ │ Text copied to clipboard │
123
+ └──────────────────────────────────────────────────────────────────────────┘"
124
+ `)
125
+
126
+ // With Long Message
127
+ await session.press('down')
128
+ const longMessage = await session.text()
129
+ expect(longMessage).toMatchInlineSnapshot(`
130
+ "
131
+
132
+
133
+ Toast Variations ─────────────────────────────────────────────────────────
134
+
135
+ Search...
136
+
137
+ Simple Success
138
+ Simple Failure
139
+ With Short Message
140
+ ›With Long Message
141
+ With Super Long Message
142
+ With Primary Action
143
+ With Both Actions
144
+ Long Title with Actions
145
+ Animated Loading
146
+ Error with Retry
147
+
148
+
149
+
150
+
151
+
152
+
153
+ ┌──────────────────────────────────────────────────────────────────────────┐
154
+ │ ✗ Error │
155
+ │ This is a very long error message that should wrap to multiple lines │
156
+ │ when displayed in the toast component. It contains detailed │
157
+ │ information about what went wrong during the operation. │
158
+ └──────────────────────────────────────────────────────────────────────────┘"
159
+ `)
160
+
161
+ // With Super Long Message
162
+ await session.press('down')
163
+ const superLongMessage = await session.text()
164
+ expect(superLongMessage).toMatchInlineSnapshot(`
165
+ "
166
+
167
+
168
+ Toast Variations ─────────────────────────────────────────────────────────
169
+
170
+ Search...
171
+
172
+ Simple Success
173
+ Simple Failure
174
+ With Short Message
175
+ With Long Message
176
+ ›With Super Long Message
177
+ With Primary Action
178
+ With Both Actions
179
+ Long Title with Actions
180
+ Animated Loading
181
+ Error with Retry
182
+
183
+
184
+
185
+ ┌──────────────────────────────────────────────────────────────────────────┐
186
+ │ ✗ Warning │
187
+ │ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do │
188
+ │ eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim │
189
+ │ ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut │
190
+ │ aliquip ex ea commodo consequat. Duis aute irure dolor in │
191
+ │ reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla │
192
+ │ pariatur. │
193
+ └──────────────────────────────────────────────────────────────────────────┘"
194
+ `)
195
+
196
+ // With Primary Action
197
+ await session.press('down')
198
+ const primaryAction = await session.text()
199
+ expect(primaryAction).toMatchInlineSnapshot(`
200
+ "
201
+
202
+
203
+ Toast Variations ─────────────────────────────────────────────────────────
204
+
205
+ Search...
206
+
207
+ Simple Success
208
+ Simple Failure
209
+ With Short Message
210
+ With Long Message
211
+ With Super Long Message
212
+ ›With Primary Action
213
+ With Both Actions
214
+ Long Title with Actions
215
+ Animated Loading
216
+ Error with Retry
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+ ┌──────────────────────────────────────────────────────────────────────────┐
226
+ │ ✓ File Deleted [Undo ↵] │
227
+ │ document.pdf was moved to trash │
228
+ └──────────────────────────────────────────────────────────────────────────┘"
229
+ `)
230
+
231
+ // With Both Actions
232
+ await session.press('down')
233
+ const bothActions = await session.text()
234
+ expect(bothActions).toMatchInlineSnapshot(`
235
+ "
236
+
237
+
238
+ Toast Variations ─────────────────────────────────────────────────────────
239
+
240
+ Search...
241
+
242
+ Simple Success
243
+ Simple Failure
244
+ With Short Message
245
+ With Long Message
246
+ With Super Long Message
247
+ With Primary Action
248
+ ›With Both Actions
249
+ Long Title with Actions
250
+ Animated Loading
251
+ Error with Retry
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+
260
+ ┌──────────────────────────────────────────────────────────────────────────┐
261
+ │ ✓ Update Available [Install ↵] [Later ⇥] │
262
+ │ Version 2.0 is ready to install │
263
+ └──────────────────────────────────────────────────────────────────────────┘"
264
+ `)
265
+
266
+ // Long Title with Actions
267
+ await session.press('down')
268
+ const longTitleActions = await session.text()
269
+ expect(longTitleActions).toMatchInlineSnapshot(`
270
+ "
271
+
272
+
273
+ Toast Variations ─────────────────────────────────────────────────────────
274
+
275
+ Search...
276
+
277
+ Simple Success
278
+ Simple Failure
279
+ With Short Message
280
+ With Long Message
281
+ With Super Long Message
282
+ With Primary Action
283
+ With Both Actions
284
+ ›Long Title with Actions
285
+ Animated Loading
286
+ Error with Retry
287
+
288
+
289
+
290
+
291
+
292
+
293
+
294
+
295
+ ┌──────────────────────────────────────────────────────────────────────────┐
296
+ │ ✓ Operation Completed Successfully [View Results ↵] [Dismiss ⇥] │
297
+ │ All files have been processed │
298
+ └──────────────────────────────────────────────────────────────────────────┘"
299
+ `)
300
+
301
+ // Animated Loading
302
+ await session.press('down')
303
+ const animatedLoading = await session.text()
304
+ expect(animatedLoading).toMatchInlineSnapshot(`
305
+ "
306
+
307
+
308
+ Toast Variations ─────────────────────────────────────────────────────────
309
+
310
+ Search...
311
+
312
+ Simple Success
313
+ Simple Failure
314
+ With Short Message
315
+ With Long Message
316
+ With Super Long Message
317
+ With Primary Action
318
+ With Both Actions
319
+ Long Title with Actions
320
+ ›Animated Loading
321
+ Error with Retry
322
+
323
+
324
+
325
+
326
+
327
+
328
+
329
+
330
+ ┌──────────────────────────────────────────────────────────────────────────┐
331
+ │ ⣽ Processing │
332
+ │ Please wait while we process your request... │
333
+ └──────────────────────────────────────────────────────────────────────────┘"
334
+ `)
335
+
336
+ // Error with Retry
337
+ await session.press('down')
338
+ const errorRetry = await session.text()
339
+ expect(errorRetry).toMatchInlineSnapshot(`
340
+ "
341
+
342
+
343
+ Toast Variations ─────────────────────────────────────────────────────────
344
+
345
+ Search...
346
+
347
+ Simple Success
348
+ Simple Failure
349
+ With Short Message
350
+ With Long Message
351
+ With Super Long Message
352
+ With Primary Action
353
+ With Both Actions
354
+ Long Title with Actions
355
+ Animated Loading
356
+ ›Error with Retry
357
+
358
+
359
+
360
+
361
+
362
+
363
+
364
+ ┌──────────────────────────────────────────────────────────────────────────┐
365
+ │ ✗ Connection Failed [Retry ↵] │
366
+ │ Unable to connect to the server. Please check your internet │
367
+ │ connection and try again. │
368
+ └──────────────────────────────────────────────────────────────────────────┘"
369
+ `)
370
+ }, 30000)