termcast 1.3.30 → 1.3.32

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 (294) hide show
  1. package/dist/apis/cache.d.ts.map +1 -1
  2. package/dist/apis/cache.js +4 -39
  3. package/dist/apis/cache.js.map +1 -1
  4. package/dist/apis/hud.d.ts.map +1 -1
  5. package/dist/apis/hud.js +13 -31
  6. package/dist/apis/hud.js.map +1 -1
  7. package/dist/apis/localstorage.d.ts.map +1 -1
  8. package/dist/apis/localstorage.js +3 -27
  9. package/dist/apis/localstorage.js.map +1 -1
  10. package/dist/apis/toast.d.ts +16 -43
  11. package/dist/apis/toast.d.ts.map +1 -1
  12. package/dist/apis/toast.js +78 -177
  13. package/dist/apis/toast.js.map +1 -1
  14. package/dist/build.d.ts +3 -1
  15. package/dist/build.d.ts.map +1 -1
  16. package/dist/build.js +52 -2
  17. package/dist/build.js.map +1 -1
  18. package/dist/cli.d.ts +1 -0
  19. package/dist/cli.d.ts.map +1 -1
  20. package/dist/cli.js +206 -25
  21. package/dist/cli.js.map +1 -1
  22. package/dist/colors.d.ts.map +1 -1
  23. package/dist/colors.js +1 -0
  24. package/dist/colors.js.map +1 -1
  25. package/dist/compile.d.ts +0 -1
  26. package/dist/compile.d.ts.map +1 -1
  27. package/dist/compile.js +18 -23
  28. package/dist/compile.js.map +1 -1
  29. package/dist/components/actions.d.ts.map +1 -1
  30. package/dist/components/actions.js +30 -15
  31. package/dist/components/actions.js.map +1 -1
  32. package/dist/components/animation-tick.d.ts +12 -0
  33. package/dist/components/animation-tick.d.ts.map +1 -0
  34. package/dist/components/animation-tick.js +63 -0
  35. package/dist/components/animation-tick.js.map +1 -0
  36. package/dist/components/detail.d.ts.map +1 -1
  37. package/dist/components/detail.js +10 -13
  38. package/dist/components/detail.js.map +1 -1
  39. package/dist/components/dropdown.d.ts +1 -0
  40. package/dist/components/dropdown.d.ts.map +1 -1
  41. package/dist/components/dropdown.js +27 -26
  42. package/dist/components/dropdown.js.map +1 -1
  43. package/dist/components/extension-preferences.d.ts.map +1 -1
  44. package/dist/components/extension-preferences.js +15 -10
  45. package/dist/components/extension-preferences.js.map +1 -1
  46. package/dist/components/footer.d.ts +13 -0
  47. package/dist/components/footer.d.ts.map +1 -0
  48. package/dist/components/footer.js +106 -0
  49. package/dist/components/footer.js.map +1 -0
  50. package/dist/components/form/file-autocomplete.d.ts +19 -4
  51. package/dist/components/form/file-autocomplete.d.ts.map +1 -1
  52. package/dist/components/form/file-autocomplete.js +56 -55
  53. package/dist/components/form/file-autocomplete.js.map +1 -1
  54. package/dist/components/form/file-picker.d.ts.map +1 -1
  55. package/dist/components/form/file-picker.js +26 -15
  56. package/dist/components/form/file-picker.js.map +1 -1
  57. package/dist/components/form/index.d.ts.map +1 -1
  58. package/dist/components/form/index.js +17 -15
  59. package/dist/components/form/index.js.map +1 -1
  60. package/dist/components/form/with-left-border.d.ts.map +1 -1
  61. package/dist/components/form/with-left-border.js +4 -12
  62. package/dist/components/form/with-left-border.js.map +1 -1
  63. package/dist/components/list.d.ts.map +1 -1
  64. package/dist/components/list.js +126 -86
  65. package/dist/components/list.js.map +1 -1
  66. package/dist/components/loading-bar.d.ts.map +1 -1
  67. package/dist/components/loading-bar.js +5 -22
  68. package/dist/components/loading-bar.js.map +1 -1
  69. package/dist/components/loading-text.d.ts.map +1 -1
  70. package/dist/components/loading-text.js +3 -22
  71. package/dist/components/loading-text.js.map +1 -1
  72. package/dist/components/theme-picker.d.ts +2 -0
  73. package/dist/components/theme-picker.d.ts.map +1 -0
  74. package/dist/components/theme-picker.js +37 -0
  75. package/dist/components/theme-picker.js.map +1 -0
  76. package/dist/descendants.d.ts +6 -0
  77. package/dist/descendants.d.ts.map +1 -1
  78. package/dist/descendants.js +74 -8
  79. package/dist/descendants.js.map +1 -1
  80. package/dist/examples/internal/descendants-rerender.d.ts +14 -0
  81. package/dist/examples/internal/descendants-rerender.d.ts.map +1 -0
  82. package/dist/examples/internal/descendants-rerender.js +145 -0
  83. package/dist/examples/internal/descendants-rerender.js.map +1 -0
  84. package/dist/examples/internal/simple-dialog.js +4 -1
  85. package/dist/examples/internal/simple-dialog.js.map +1 -1
  86. package/dist/examples/internal/simple-scrollbox.js +1 -1
  87. package/dist/examples/internal/simple-scrollbox.js.map +1 -1
  88. package/dist/examples/list-with-dropdown.js +1 -1
  89. package/dist/examples/list-with-dropdown.js.map +1 -1
  90. package/dist/examples/miscellaneous.js +1 -1
  91. package/dist/examples/miscellaneous.js.map +1 -1
  92. package/dist/examples/toast-action.d.ts +2 -0
  93. package/dist/examples/toast-action.d.ts.map +1 -0
  94. package/dist/examples/toast-action.js +76 -0
  95. package/dist/examples/toast-action.js.map +1 -0
  96. package/dist/examples/toast-variations.js +38 -36
  97. package/dist/examples/toast-variations.js.map +1 -1
  98. package/dist/extensions/dev.d.ts +1 -1
  99. package/dist/extensions/dev.d.ts.map +1 -1
  100. package/dist/extensions/dev.js +62 -30
  101. package/dist/extensions/dev.js.map +1 -1
  102. package/dist/extensions/home.d.ts.map +1 -1
  103. package/dist/extensions/home.js +4 -3
  104. package/dist/extensions/home.js.map +1 -1
  105. package/dist/extensions/react-refresh-init.d.ts +5 -0
  106. package/dist/extensions/react-refresh-init.d.ts.map +1 -0
  107. package/dist/extensions/react-refresh-init.js +52 -0
  108. package/dist/extensions/react-refresh-init.js.map +1 -0
  109. package/dist/internal/date-picker-widget.js +1 -1
  110. package/dist/internal/date-picker-widget.js.map +1 -1
  111. package/dist/internal/dialog.d.ts +8 -3
  112. package/dist/internal/dialog.d.ts.map +1 -1
  113. package/dist/internal/dialog.js +37 -53
  114. package/dist/internal/dialog.js.map +1 -1
  115. package/dist/internal/navigation.d.ts +1 -0
  116. package/dist/internal/navigation.d.ts.map +1 -1
  117. package/dist/internal/navigation.js +25 -1
  118. package/dist/internal/navigation.js.map +1 -1
  119. package/dist/internal/providers.d.ts.map +1 -1
  120. package/dist/internal/providers.js +9 -197
  121. package/dist/internal/providers.js.map +1 -1
  122. package/dist/internal/scrollbox.d.ts.map +1 -1
  123. package/dist/internal/scrollbox.js +1 -0
  124. package/dist/internal/scrollbox.js.map +1 -1
  125. package/dist/release.d.ts +1 -0
  126. package/dist/release.d.ts.map +1 -1
  127. package/dist/release.js +16 -9
  128. package/dist/release.js.map +1 -1
  129. package/dist/state.d.ts +27 -1
  130. package/dist/state.d.ts.map +1 -1
  131. package/dist/state.js +6 -0
  132. package/dist/state.js.map +1 -1
  133. package/dist/theme.d.ts +6 -19
  134. package/dist/theme.d.ts.map +1 -1
  135. package/dist/theme.js +76 -45
  136. package/dist/theme.js.map +1 -1
  137. package/dist/themes/aura.json +69 -0
  138. package/dist/themes/ayu.json +80 -0
  139. package/dist/themes/catppuccin-frappe.json +233 -0
  140. package/dist/themes/catppuccin-macchiato.json +233 -0
  141. package/dist/themes/catppuccin.json +112 -0
  142. package/dist/themes/cobalt2.json +228 -0
  143. package/dist/themes/cursor.json +249 -0
  144. package/dist/themes/dracula.json +219 -0
  145. package/dist/themes/everforest.json +241 -0
  146. package/dist/themes/flexoki.json +237 -0
  147. package/dist/themes/github-light.json +56 -0
  148. package/dist/themes/github.json +241 -0
  149. package/dist/themes/gruvbox.json +95 -0
  150. package/dist/themes/kanagawa.json +77 -0
  151. package/dist/themes/lucent-orng.json +227 -0
  152. package/dist/themes/material.json +235 -0
  153. package/dist/themes/matrix.json +77 -0
  154. package/dist/themes/mercury.json +245 -0
  155. package/dist/themes/monokai.json +221 -0
  156. package/dist/themes/nightowl.json +221 -0
  157. package/dist/themes/nord.json +223 -0
  158. package/dist/themes/one-dark.json +84 -0
  159. package/dist/themes/opencode-light.json +62 -0
  160. package/dist/themes/opencode.json +245 -0
  161. package/dist/themes/orng.json +245 -0
  162. package/dist/themes/palenight.json +222 -0
  163. package/dist/themes/rosepine.json +234 -0
  164. package/dist/themes/solarized.json +223 -0
  165. package/dist/themes/synthwave84.json +226 -0
  166. package/dist/themes/termcast.json +226 -0
  167. package/dist/themes/tokyonight.json +243 -0
  168. package/dist/themes/vercel.json +255 -0
  169. package/dist/themes/vesper.json +218 -0
  170. package/dist/themes/zenburn.json +223 -0
  171. package/dist/themes.d.ts +57 -0
  172. package/dist/themes.d.ts.map +1 -0
  173. package/dist/themes.js +181 -0
  174. package/dist/themes.js.map +1 -0
  175. package/dist/utils/run-command.d.ts +2 -1
  176. package/dist/utils/run-command.d.ts.map +1 -1
  177. package/dist/utils/run-command.js +20 -10
  178. package/dist/utils/run-command.js.map +1 -1
  179. package/dist/utils.d.ts +2 -1
  180. package/dist/utils.d.ts.map +1 -1
  181. package/dist/utils.js +90 -17
  182. package/dist/utils.js.map +1 -1
  183. package/dist/watcher.d.ts +3 -0
  184. package/dist/watcher.d.ts.map +1 -0
  185. package/dist/watcher.js +16 -0
  186. package/dist/watcher.js.map +1 -0
  187. package/package.json +16 -10
  188. package/src/apis/cache.tsx +5 -44
  189. package/src/apis/hud.tsx +17 -62
  190. package/src/apis/localstorage.tsx +3 -32
  191. package/src/apis/toast.tsx +91 -275
  192. package/src/build.test.tsx +10 -0
  193. package/src/build.tsx +61 -1
  194. package/src/cli.tsx +365 -103
  195. package/src/colors.tsx +1 -0
  196. package/src/compile.tsx +21 -29
  197. package/src/compile.vitest.tsx +300 -0
  198. package/src/components/actions.tsx +64 -45
  199. package/src/components/animation-tick.tsx +85 -0
  200. package/src/components/detail.tsx +31 -35
  201. package/src/components/dropdown.tsx +32 -21
  202. package/src/components/extension-preferences.tsx +14 -10
  203. package/src/components/footer.tsx +241 -0
  204. package/src/components/form/file-autocomplete.tsx +80 -60
  205. package/src/components/form/file-picker.tsx +37 -25
  206. package/src/components/form/index.tsx +45 -41
  207. package/src/components/form/with-left-border.tsx +4 -14
  208. package/src/components/list.tsx +181 -121
  209. package/src/components/loading-bar.tsx +5 -25
  210. package/src/components/loading-text.tsx +4 -23
  211. package/src/components/theme-picker.tsx +57 -0
  212. package/src/descendants.tsx +98 -9
  213. package/src/examples/actions-dialog-layout.vitest.tsx +112 -0
  214. package/src/examples/file-autocomplete.vitest.tsx +131 -122
  215. package/src/examples/form-basic.vitest.tsx +463 -644
  216. package/src/examples/form-dropdown.vitest.tsx +553 -571
  217. package/src/examples/form-scroll.vitest.tsx +112 -102
  218. package/src/examples/form-tagpicker.vitest.tsx +364 -338
  219. package/src/examples/internal/descendants-rerender.tsx +273 -0
  220. package/src/examples/internal/descendants-rerender.vitest.tsx +194 -0
  221. package/src/examples/internal/simple-dialog.tsx +4 -4
  222. package/src/examples/internal/simple-scrollbox.tsx +2 -2
  223. package/src/examples/internal/simple-scrollbox.vitest.tsx +43 -31
  224. package/src/examples/list-detail-metadata.vitest.tsx +34 -30
  225. package/src/examples/list-dropdown-default.vitest.tsx +84 -72
  226. package/src/examples/list-empty-view.vitest.tsx +93 -0
  227. package/src/examples/list-fetch-data.vitest.tsx +36 -30
  228. package/src/examples/list-scrollbox.vitest.tsx +59 -39
  229. package/src/examples/list-with-detail.vitest.tsx +339 -314
  230. package/src/examples/list-with-dropdown.tsx +1 -0
  231. package/src/examples/list-with-dropdown.vitest.tsx +176 -150
  232. package/src/examples/list-with-sections.vitest.tsx +289 -270
  233. package/src/examples/list-with-toast.vitest.tsx +44 -44
  234. package/src/examples/miscellaneous.tsx +10 -0
  235. package/src/examples/simple-file-picker.vitest.tsx +90 -86
  236. package/src/examples/simple-grid.vitest.tsx +275 -249
  237. package/src/examples/simple-navigation.vitest.tsx +192 -168
  238. package/src/examples/store.vitest.tsx +6 -4
  239. package/src/examples/swift-extension.vitest.tsx +31 -19
  240. package/src/examples/synonyms.vitest.tsx +93 -83
  241. package/src/examples/toast-action.tsx +160 -0
  242. package/src/examples/toast-action.vitest.tsx +404 -0
  243. package/src/examples/toast-variations.tsx +58 -57
  244. package/src/examples/toast-variations.vitest.tsx +186 -166
  245. package/src/extensions/dev.tsx +74 -33
  246. package/src/extensions/dev.vitest.tsx +162 -69
  247. package/src/extensions/home.tsx +5 -6
  248. package/src/extensions/react-refresh-init.tsx +59 -0
  249. package/src/internal/date-picker-widget.tsx +1 -1
  250. package/src/internal/dialog.tsx +59 -83
  251. package/src/internal/navigation.tsx +37 -4
  252. package/src/internal/providers.tsx +27 -315
  253. package/src/internal/scrollbox.tsx +1 -0
  254. package/src/release.tsx +16 -10
  255. package/src/state.tsx +36 -3
  256. package/src/theme.tsx +82 -51
  257. package/src/themes/aura.json +69 -0
  258. package/src/themes/ayu.json +80 -0
  259. package/src/themes/catppuccin-frappe.json +233 -0
  260. package/src/themes/catppuccin-macchiato.json +233 -0
  261. package/src/themes/catppuccin.json +112 -0
  262. package/src/themes/cobalt2.json +228 -0
  263. package/src/themes/cursor.json +249 -0
  264. package/src/themes/dracula.json +219 -0
  265. package/src/themes/everforest.json +241 -0
  266. package/src/themes/flexoki.json +237 -0
  267. package/src/themes/github-light.json +56 -0
  268. package/src/themes/github.json +241 -0
  269. package/src/themes/gruvbox.json +95 -0
  270. package/src/themes/kanagawa.json +77 -0
  271. package/src/themes/lucent-orng.json +227 -0
  272. package/src/themes/material.json +235 -0
  273. package/src/themes/matrix.json +77 -0
  274. package/src/themes/mercury.json +252 -0
  275. package/src/themes/monokai.json +221 -0
  276. package/src/themes/nightowl.json +221 -0
  277. package/src/themes/nord.json +223 -0
  278. package/src/themes/one-dark.json +84 -0
  279. package/src/themes/opencode-light.json +62 -0
  280. package/src/themes/opencode.json +245 -0
  281. package/src/themes/orng.json +245 -0
  282. package/src/themes/palenight.json +222 -0
  283. package/src/themes/rosepine.json +234 -0
  284. package/src/themes/solarized.json +223 -0
  285. package/src/themes/synthwave84.json +226 -0
  286. package/src/themes/termcast.json +227 -0
  287. package/src/themes/tokyonight.json +243 -0
  288. package/src/themes/vercel.json +255 -0
  289. package/src/themes/vesper.json +218 -0
  290. package/src/themes/zenburn.json +223 -0
  291. package/src/themes.ts +291 -0
  292. package/src/utils/run-command.tsx +23 -12
  293. package/src/utils.tsx +115 -18
  294. package/src/watcher.tsx +19 -0
@@ -0,0 +1,404 @@
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-action.tsx'],
10
+ cols: 70,
11
+ rows: 20,
12
+ })
13
+ })
14
+
15
+ afterEach(() => {
16
+ session?.close()
17
+ })
18
+
19
+ test('pressing enter triggers primary action on toast', async () => {
20
+ // Wait for list to load
21
+ await session.text({
22
+ waitFor: (text) => text.includes('Show Toast with Action'),
23
+ })
24
+
25
+ // Press enter to trigger the action and show toast
26
+ await session.press('enter')
27
+ await session.text({
28
+ waitFor: (text) => text.includes('Undo ctrl t'),
29
+ })
30
+
31
+ const beforeEnter = await session.text()
32
+ expect(beforeEnter).toMatchInlineSnapshot(`
33
+ "
34
+
35
+
36
+ Toast Action Test ──────────────────────────────────────────────
37
+
38
+ > Search...
39
+
40
+ ›Show Toast with Action
41
+ Form with Toast
42
+ Form with Delayed Toast Action
43
+ Other Item
44
+
45
+
46
+ ✓ File Deleted document.pdf was moved to trash Undo ctrl t
47
+
48
+
49
+
50
+
51
+
52
+
53
+ "
54
+ `)
55
+
56
+ expect(beforeEnter).toContain('Undo ctrl t')
57
+
58
+ // Press Ctrl+T to trigger the primary action
59
+ await session.press(['ctrl', 't'])
60
+ await session.text({
61
+ waitFor: (text) => text.includes('Undone'),
62
+ })
63
+
64
+ const afterEnter = await session.text()
65
+ expect(afterEnter).toMatchInlineSnapshot(`
66
+ "
67
+
68
+
69
+ Toast Action Test ──────────────────────────────────────────────
70
+
71
+ > Search...
72
+
73
+ ›Show Toast with Action
74
+ Form with Toast
75
+ Form with Delayed Toast Action
76
+ Other Item
77
+
78
+
79
+ ✓ Undone File restored
80
+
81
+
82
+
83
+
84
+
85
+
86
+ "
87
+ `)
88
+
89
+ expect(afterEnter).toContain('Undone')
90
+ }, 30000)
91
+
92
+ test('pressing escape hides the toast', async () => {
93
+ // Wait for list to load
94
+ await session.text({
95
+ waitFor: (text) => text.includes('Show Toast with Action'),
96
+ })
97
+
98
+ // Press enter to show toast
99
+ await session.press('enter')
100
+ await session.text({
101
+ waitFor: (text) => text.includes('Undo ctrl t'),
102
+ })
103
+
104
+ const beforeEsc = await session.text()
105
+ expect(beforeEsc).toContain('Undo ctrl t')
106
+
107
+ await session.press('escape')
108
+ await new Promise((r) => setTimeout(r, 300))
109
+
110
+ const afterEsc = await session.text()
111
+ expect(afterEsc).toMatchInlineSnapshot(`
112
+ "
113
+
114
+
115
+ Toast Action Test ──────────────────────────────────────────────
116
+
117
+ > Search...
118
+
119
+ ›Show Toast with Action
120
+ Form with Toast
121
+ Form with Delayed Toast Action
122
+ Other Item
123
+
124
+
125
+ ↵ show toast ↑↓ navigate ^k actions
126
+
127
+
128
+
129
+
130
+
131
+
132
+ "
133
+ `)
134
+
135
+ expect(afterEsc).not.toContain('Undo ctrl t')
136
+ // Verify list is still visible (ESC didn't exit the app)
137
+ expect(afterEsc).toContain('Toast Action Test')
138
+ }, 30000)
139
+
140
+ test('form toast: pressing enter triggers primary action (navigation)', async () => {
141
+ // Wait for list to load
142
+ await session.text({
143
+ waitFor: (text) => text.includes('Form with Toast'),
144
+ })
145
+
146
+ // Navigate to Form with Toast item
147
+ await session.press('down')
148
+ await new Promise((r) => setTimeout(r, 100))
149
+
150
+ // Open form via enter (triggers action)
151
+ await session.press('enter')
152
+ await session.text({
153
+ waitFor: (text) => text.includes('Name') && text.includes('Enter your name'),
154
+ })
155
+
156
+ const formView = await session.text()
157
+ expect(formView).toMatchInlineSnapshot(`
158
+ "
159
+
160
+
161
+
162
+
163
+ ◆ Name
164
+ │ Enter your name
165
+
166
+
167
+
168
+
169
+ ctrl ↵ submit tab navigate ^k actions
170
+
171
+
172
+
173
+
174
+
175
+
176
+
177
+
178
+ "
179
+ `)
180
+
181
+ // Type a name
182
+ await session.type('John')
183
+ await new Promise((r) => setTimeout(r, 100))
184
+
185
+ // Submit the form via action panel (ctrl+k then enter)
186
+ await session.press(['ctrl', 'k'])
187
+ await session.waitIdle()
188
+ await session.press('enter')
189
+ await session.text({
190
+ waitFor: (text) => text.includes('View Details ctrl t'),
191
+ })
192
+
193
+ const toastShown = await session.text()
194
+ expect(toastShown).toMatchInlineSnapshot(`
195
+ "
196
+
197
+
198
+
199
+
200
+ ◆ Name
201
+ │ John
202
+
203
+
204
+
205
+
206
+ ✓ Form Submitted Hello, John! View Details ctrl t
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+ "
216
+ `)
217
+
218
+ // Press Ctrl+T to trigger primary action (navigate to detail view)
219
+ await session.press(['ctrl', 't'])
220
+ await session.text({
221
+ waitFor: (text) => text.includes('Welcome, John!'),
222
+ })
223
+
224
+ const detailView = await session.text()
225
+ expect(detailView).toMatchInlineSnapshot(`
226
+ "
227
+
228
+
229
+ Form Submitted ─────────────────────────────────────────────────
230
+
231
+ > Search...
232
+
233
+ ›Welcome, John! Form submission successful
234
+
235
+
236
+ ↑↓ navigate ^k actions
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+ "
247
+ `)
248
+ }, 30000)
249
+
250
+ test('form toast: pressing escape closes toast but stays on form', async () => {
251
+ // Wait for list to load
252
+ await session.text({
253
+ waitFor: (text) => text.includes('Form with Toast'),
254
+ })
255
+
256
+ // Navigate to Form with Toast item
257
+ await session.press('down')
258
+ await new Promise((r) => setTimeout(r, 100))
259
+
260
+ // Open form
261
+ await session.press('enter')
262
+ await session.text({
263
+ waitFor: (text) => text.includes('Name') && text.includes('Enter your name'),
264
+ })
265
+
266
+ // Type a name
267
+ await session.type('Jane')
268
+ await new Promise((r) => setTimeout(r, 100))
269
+
270
+ // Submit the form via action panel (ctrl+k then enter)
271
+ await session.press(['ctrl', 'k'])
272
+ await session.waitIdle()
273
+ await session.press('enter')
274
+ await session.text({
275
+ waitFor: (text) => text.includes('View Details ctrl t'),
276
+ })
277
+
278
+ const toastShown = await session.text()
279
+ expect(toastShown).toContain('View Details ctrl t')
280
+
281
+ // Press Escape to close toast
282
+ await session.press('escape')
283
+ await new Promise((r) => setTimeout(r, 300))
284
+
285
+ const afterEsc = await session.text()
286
+ expect(afterEsc).toMatchInlineSnapshot(`
287
+ "
288
+
289
+
290
+
291
+
292
+ ◆ Name
293
+ │ Jane
294
+
295
+
296
+
297
+
298
+ ctrl ↵ submit tab navigate ^k actions
299
+
300
+
301
+
302
+
303
+
304
+
305
+
306
+
307
+ "
308
+ `)
309
+
310
+ // Toast should be closed
311
+ expect(afterEsc).not.toContain('View Details ctrl t')
312
+ // Should still be on the form (Name field visible)
313
+ expect(afterEsc).toContain('Name')
314
+ }, 30000)
315
+
316
+ test('delayed toast action: primaryAction set after toast shown works with enter', async () => {
317
+ // Wait for list to load
318
+ await session.text({
319
+ waitFor: (text) => text.includes('Delayed Toast Action'),
320
+ })
321
+
322
+ // Navigate to delayed toast action item
323
+ await session.press('down')
324
+ await session.press('down')
325
+ await new Promise((r) => setTimeout(r, 100))
326
+
327
+ // Open form
328
+ await session.press('enter')
329
+ await session.text({
330
+ waitFor: (text) => text.includes('Name') && text.includes('Enter your name'),
331
+ })
332
+
333
+ // Type a name
334
+ await session.type('Test')
335
+ await new Promise((r) => setTimeout(r, 100))
336
+
337
+ // Submit the form
338
+ await session.press(['ctrl', 'k'])
339
+ await session.waitIdle()
340
+ await session.press('enter')
341
+
342
+ // Wait for delayed toast to show with primaryAction (set after 500ms delay)
343
+ await session.text({
344
+ waitFor: (text) => text.includes('Open ctrl t'),
345
+ timeout: 3000,
346
+ })
347
+
348
+ const toastWithAction = await session.text()
349
+ expect(toastWithAction).toMatchInlineSnapshot(`
350
+ "
351
+
352
+
353
+
354
+
355
+ ◆ Name
356
+ │ Test
357
+
358
+
359
+
360
+
361
+ ✓ Done Hello, Test! Open ctrl t
362
+
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+ "
371
+ `)
372
+
373
+ // Press Ctrl+T to trigger primary action - this should work even though
374
+ // primaryAction was set AFTER the toast was shown
375
+ await session.press(['ctrl', 't'])
376
+ await session.text({
377
+ waitFor: (text) => text.includes('Opened!'),
378
+ })
379
+
380
+ const afterAction = await session.text()
381
+ expect(afterAction).toMatchInlineSnapshot(`
382
+ "
383
+
384
+
385
+
386
+
387
+ ◆ Name
388
+ │ Test
389
+
390
+
391
+
392
+
393
+ ✓ Opened! Action triggered successfully
394
+
395
+
396
+
397
+
398
+
399
+
400
+
401
+
402
+ "
403
+ `)
404
+ }, 30000)
@@ -1,51 +1,56 @@
1
- import React, { useState } from 'react'
1
+ import React, { useEffect } from 'react'
2
2
  import { List, ActionPanel, Action, renderWithProviders } from 'termcast'
3
- import { Toast, ToastContent } from 'termcast/src/apis/toast'
3
+ import { Toast, showToast } from 'termcast/src/apis/toast'
4
4
 
5
- const toastVariations = [
5
+ interface ToastVariation {
6
+ name: string
7
+ options: Toast.Options
8
+ }
9
+
10
+ const toastVariations: ToastVariation[] = [
6
11
  {
7
12
  name: 'Simple Success',
8
- toast: new Toast({
13
+ options: {
9
14
  title: 'Success',
10
15
  style: Toast.Style.Success,
11
- }),
16
+ },
12
17
  },
13
18
  {
14
19
  name: 'Simple Failure',
15
- toast: new Toast({
20
+ options: {
16
21
  title: 'Error',
17
22
  style: Toast.Style.Failure,
18
- }),
23
+ },
19
24
  },
20
25
  {
21
26
  name: 'With Short Message',
22
- toast: new Toast({
27
+ options: {
23
28
  title: 'Copied',
24
29
  message: 'Text copied to clipboard',
25
30
  style: Toast.Style.Success,
26
- }),
31
+ },
27
32
  },
28
33
  {
29
34
  name: 'With Long Message',
30
- toast: new Toast({
35
+ options: {
31
36
  title: 'Error',
32
37
  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.',
38
+ 'This is a very long error message that should wrap to multiple lines when displayed in the toast component.',
34
39
  style: Toast.Style.Failure,
35
- }),
40
+ },
36
41
  },
37
42
  {
38
43
  name: 'With Super Long Message',
39
- toast: new Toast({
44
+ options: {
40
45
  title: 'Warning',
41
46
  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.',
47
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
43
48
  style: Toast.Style.Failure,
44
- }),
49
+ },
45
50
  },
46
51
  {
47
52
  name: 'With Primary Action',
48
- toast: new Toast({
53
+ options: {
49
54
  title: 'File Deleted',
50
55
  message: 'document.pdf was moved to trash',
51
56
  style: Toast.Style.Success,
@@ -53,11 +58,11 @@ const toastVariations = [
53
58
  title: 'Undo',
54
59
  onAction: () => {},
55
60
  },
56
- }),
61
+ },
57
62
  },
58
63
  {
59
64
  name: 'With Both Actions',
60
- toast: new Toast({
65
+ options: {
61
66
  title: 'Update Available',
62
67
  message: 'Version 2.0 is ready to install',
63
68
  style: Toast.Style.Success,
@@ -69,11 +74,11 @@ const toastVariations = [
69
74
  title: 'Later',
70
75
  onAction: () => {},
71
76
  },
72
- }),
77
+ },
73
78
  },
74
79
  {
75
80
  name: 'Long Title with Actions',
76
- toast: new Toast({
81
+ options: {
77
82
  title: 'Operation Completed Successfully',
78
83
  message: 'All files have been processed',
79
84
  style: Toast.Style.Success,
@@ -85,65 +90,61 @@ const toastVariations = [
85
90
  title: 'Dismiss',
86
91
  onAction: () => {},
87
92
  },
88
- }),
93
+ },
89
94
  },
90
95
  {
91
96
  name: 'Animated Loading',
92
- toast: new Toast({
97
+ options: {
93
98
  title: 'Processing',
94
99
  message: 'Please wait while we process your request...',
95
100
  style: Toast.Style.Animated,
96
- }),
101
+ },
97
102
  },
98
103
  {
99
104
  name: 'Error with Retry',
100
- toast: new Toast({
105
+ options: {
101
106
  title: 'Connection Failed',
102
- message:
103
- 'Unable to connect to the server. Please check your internet connection and try again.',
107
+ message: 'Unable to connect to the server. Please check your internet connection.',
104
108
  style: Toast.Style.Failure,
105
109
  primaryAction: {
106
110
  title: 'Retry',
107
111
  onAction: () => {},
108
112
  },
109
- }),
113
+ },
110
114
  },
111
115
  ]
112
116
 
113
117
  function ToastVariationsExample(): any {
114
- const [selectedIndex, setSelectedIndex] = useState(0)
115
- const selectedToast = toastVariations[selectedIndex]
118
+ // Show first toast on mount
119
+ useEffect(() => {
120
+ showToast(toastVariations[0].options)
121
+ }, [])
116
122
 
117
123
  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
- }
124
+ <List
125
+ navigationTitle="Toast Variations"
126
+ onSelectionChange={(id) => {
127
+ if (id) {
128
+ const variation = toastVariations.find((v) => v.name === id)
129
+ if (variation) {
130
+ showToast(variation.options)
131
+ }
132
+ }
133
+ }}
134
+ >
135
+ {toastVariations.map((variation) => (
136
+ <List.Item
137
+ key={variation.name}
138
+ id={variation.name}
139
+ title={variation.name}
140
+ actions={
141
+ <ActionPanel>
142
+ <Action title="Select" onAction={() => {}} />
143
+ </ActionPanel>
127
144
  }
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>
145
+ />
146
+ ))}
147
+ </List>
147
148
  )
148
149
  }
149
150