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.
- package/dist/apis/cache.d.ts.map +1 -1
- package/dist/apis/cache.js +4 -39
- package/dist/apis/cache.js.map +1 -1
- package/dist/apis/hud.d.ts.map +1 -1
- package/dist/apis/hud.js +13 -31
- package/dist/apis/hud.js.map +1 -1
- package/dist/apis/localstorage.d.ts.map +1 -1
- package/dist/apis/localstorage.js +3 -27
- package/dist/apis/localstorage.js.map +1 -1
- package/dist/apis/toast.d.ts +16 -43
- package/dist/apis/toast.d.ts.map +1 -1
- package/dist/apis/toast.js +78 -177
- package/dist/apis/toast.js.map +1 -1
- package/dist/build.d.ts +3 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +52 -2
- package/dist/build.js.map +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +206 -25
- package/dist/cli.js.map +1 -1
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +1 -0
- package/dist/colors.js.map +1 -1
- package/dist/compile.d.ts +0 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +18 -23
- package/dist/compile.js.map +1 -1
- package/dist/components/actions.d.ts.map +1 -1
- package/dist/components/actions.js +30 -15
- package/dist/components/actions.js.map +1 -1
- package/dist/components/animation-tick.d.ts +12 -0
- package/dist/components/animation-tick.d.ts.map +1 -0
- package/dist/components/animation-tick.js +63 -0
- package/dist/components/animation-tick.js.map +1 -0
- package/dist/components/detail.d.ts.map +1 -1
- package/dist/components/detail.js +10 -13
- package/dist/components/detail.js.map +1 -1
- package/dist/components/dropdown.d.ts +1 -0
- package/dist/components/dropdown.d.ts.map +1 -1
- package/dist/components/dropdown.js +27 -26
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/extension-preferences.d.ts.map +1 -1
- package/dist/components/extension-preferences.js +15 -10
- package/dist/components/extension-preferences.js.map +1 -1
- package/dist/components/footer.d.ts +13 -0
- package/dist/components/footer.d.ts.map +1 -0
- package/dist/components/footer.js +106 -0
- package/dist/components/footer.js.map +1 -0
- package/dist/components/form/file-autocomplete.d.ts +19 -4
- package/dist/components/form/file-autocomplete.d.ts.map +1 -1
- package/dist/components/form/file-autocomplete.js +56 -55
- package/dist/components/form/file-autocomplete.js.map +1 -1
- package/dist/components/form/file-picker.d.ts.map +1 -1
- package/dist/components/form/file-picker.js +26 -15
- package/dist/components/form/file-picker.js.map +1 -1
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +17 -15
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/form/with-left-border.d.ts.map +1 -1
- package/dist/components/form/with-left-border.js +4 -12
- package/dist/components/form/with-left-border.js.map +1 -1
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +126 -86
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-bar.d.ts.map +1 -1
- package/dist/components/loading-bar.js +5 -22
- package/dist/components/loading-bar.js.map +1 -1
- package/dist/components/loading-text.d.ts.map +1 -1
- package/dist/components/loading-text.js +3 -22
- package/dist/components/loading-text.js.map +1 -1
- package/dist/components/theme-picker.d.ts +2 -0
- package/dist/components/theme-picker.d.ts.map +1 -0
- package/dist/components/theme-picker.js +37 -0
- package/dist/components/theme-picker.js.map +1 -0
- package/dist/descendants.d.ts +6 -0
- package/dist/descendants.d.ts.map +1 -1
- package/dist/descendants.js +74 -8
- package/dist/descendants.js.map +1 -1
- package/dist/examples/internal/descendants-rerender.d.ts +14 -0
- package/dist/examples/internal/descendants-rerender.d.ts.map +1 -0
- package/dist/examples/internal/descendants-rerender.js +145 -0
- package/dist/examples/internal/descendants-rerender.js.map +1 -0
- package/dist/examples/internal/simple-dialog.js +4 -1
- package/dist/examples/internal/simple-dialog.js.map +1 -1
- package/dist/examples/internal/simple-scrollbox.js +1 -1
- package/dist/examples/internal/simple-scrollbox.js.map +1 -1
- package/dist/examples/list-with-dropdown.js +1 -1
- package/dist/examples/list-with-dropdown.js.map +1 -1
- package/dist/examples/miscellaneous.js +1 -1
- package/dist/examples/miscellaneous.js.map +1 -1
- package/dist/examples/toast-action.d.ts +2 -0
- package/dist/examples/toast-action.d.ts.map +1 -0
- package/dist/examples/toast-action.js +76 -0
- package/dist/examples/toast-action.js.map +1 -0
- package/dist/examples/toast-variations.js +38 -36
- package/dist/examples/toast-variations.js.map +1 -1
- package/dist/extensions/dev.d.ts +1 -1
- package/dist/extensions/dev.d.ts.map +1 -1
- package/dist/extensions/dev.js +62 -30
- package/dist/extensions/dev.js.map +1 -1
- package/dist/extensions/home.d.ts.map +1 -1
- package/dist/extensions/home.js +4 -3
- package/dist/extensions/home.js.map +1 -1
- package/dist/extensions/react-refresh-init.d.ts +5 -0
- package/dist/extensions/react-refresh-init.d.ts.map +1 -0
- package/dist/extensions/react-refresh-init.js +52 -0
- package/dist/extensions/react-refresh-init.js.map +1 -0
- package/dist/internal/date-picker-widget.js +1 -1
- package/dist/internal/date-picker-widget.js.map +1 -1
- package/dist/internal/dialog.d.ts +8 -3
- package/dist/internal/dialog.d.ts.map +1 -1
- package/dist/internal/dialog.js +37 -53
- package/dist/internal/dialog.js.map +1 -1
- package/dist/internal/navigation.d.ts +1 -0
- package/dist/internal/navigation.d.ts.map +1 -1
- package/dist/internal/navigation.js +25 -1
- package/dist/internal/navigation.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +9 -197
- package/dist/internal/providers.js.map +1 -1
- package/dist/internal/scrollbox.d.ts.map +1 -1
- package/dist/internal/scrollbox.js +1 -0
- package/dist/internal/scrollbox.js.map +1 -1
- package/dist/release.d.ts +1 -0
- package/dist/release.d.ts.map +1 -1
- package/dist/release.js +16 -9
- package/dist/release.js.map +1 -1
- package/dist/state.d.ts +27 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +6 -0
- package/dist/state.js.map +1 -1
- package/dist/theme.d.ts +6 -19
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +76 -45
- package/dist/theme.js.map +1 -1
- package/dist/themes/aura.json +69 -0
- package/dist/themes/ayu.json +80 -0
- package/dist/themes/catppuccin-frappe.json +233 -0
- package/dist/themes/catppuccin-macchiato.json +233 -0
- package/dist/themes/catppuccin.json +112 -0
- package/dist/themes/cobalt2.json +228 -0
- package/dist/themes/cursor.json +249 -0
- package/dist/themes/dracula.json +219 -0
- package/dist/themes/everforest.json +241 -0
- package/dist/themes/flexoki.json +237 -0
- package/dist/themes/github-light.json +56 -0
- package/dist/themes/github.json +241 -0
- package/dist/themes/gruvbox.json +95 -0
- package/dist/themes/kanagawa.json +77 -0
- package/dist/themes/lucent-orng.json +227 -0
- package/dist/themes/material.json +235 -0
- package/dist/themes/matrix.json +77 -0
- package/dist/themes/mercury.json +245 -0
- package/dist/themes/monokai.json +221 -0
- package/dist/themes/nightowl.json +221 -0
- package/dist/themes/nord.json +223 -0
- package/dist/themes/one-dark.json +84 -0
- package/dist/themes/opencode-light.json +62 -0
- package/dist/themes/opencode.json +245 -0
- package/dist/themes/orng.json +245 -0
- package/dist/themes/palenight.json +222 -0
- package/dist/themes/rosepine.json +234 -0
- package/dist/themes/solarized.json +223 -0
- package/dist/themes/synthwave84.json +226 -0
- package/dist/themes/termcast.json +226 -0
- package/dist/themes/tokyonight.json +243 -0
- package/dist/themes/vercel.json +255 -0
- package/dist/themes/vesper.json +218 -0
- package/dist/themes/zenburn.json +223 -0
- package/dist/themes.d.ts +57 -0
- package/dist/themes.d.ts.map +1 -0
- package/dist/themes.js +181 -0
- package/dist/themes.js.map +1 -0
- package/dist/utils/run-command.d.ts +2 -1
- package/dist/utils/run-command.d.ts.map +1 -1
- package/dist/utils/run-command.js +20 -10
- package/dist/utils/run-command.js.map +1 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +90 -17
- package/dist/utils.js.map +1 -1
- package/dist/watcher.d.ts +3 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +16 -0
- package/dist/watcher.js.map +1 -0
- package/package.json +16 -10
- package/src/apis/cache.tsx +5 -44
- package/src/apis/hud.tsx +17 -62
- package/src/apis/localstorage.tsx +3 -32
- package/src/apis/toast.tsx +91 -275
- package/src/build.test.tsx +10 -0
- package/src/build.tsx +61 -1
- package/src/cli.tsx +365 -103
- package/src/colors.tsx +1 -0
- package/src/compile.tsx +21 -29
- package/src/compile.vitest.tsx +300 -0
- package/src/components/actions.tsx +64 -45
- package/src/components/animation-tick.tsx +85 -0
- package/src/components/detail.tsx +31 -35
- package/src/components/dropdown.tsx +32 -21
- package/src/components/extension-preferences.tsx +14 -10
- package/src/components/footer.tsx +241 -0
- package/src/components/form/file-autocomplete.tsx +80 -60
- package/src/components/form/file-picker.tsx +37 -25
- package/src/components/form/index.tsx +45 -41
- package/src/components/form/with-left-border.tsx +4 -14
- package/src/components/list.tsx +181 -121
- package/src/components/loading-bar.tsx +5 -25
- package/src/components/loading-text.tsx +4 -23
- package/src/components/theme-picker.tsx +57 -0
- package/src/descendants.tsx +98 -9
- package/src/examples/actions-dialog-layout.vitest.tsx +112 -0
- package/src/examples/file-autocomplete.vitest.tsx +131 -122
- package/src/examples/form-basic.vitest.tsx +463 -644
- package/src/examples/form-dropdown.vitest.tsx +553 -571
- package/src/examples/form-scroll.vitest.tsx +112 -102
- package/src/examples/form-tagpicker.vitest.tsx +364 -338
- package/src/examples/internal/descendants-rerender.tsx +273 -0
- package/src/examples/internal/descendants-rerender.vitest.tsx +194 -0
- package/src/examples/internal/simple-dialog.tsx +4 -4
- package/src/examples/internal/simple-scrollbox.tsx +2 -2
- package/src/examples/internal/simple-scrollbox.vitest.tsx +43 -31
- package/src/examples/list-detail-metadata.vitest.tsx +34 -30
- package/src/examples/list-dropdown-default.vitest.tsx +84 -72
- package/src/examples/list-empty-view.vitest.tsx +93 -0
- package/src/examples/list-fetch-data.vitest.tsx +36 -30
- package/src/examples/list-scrollbox.vitest.tsx +59 -39
- package/src/examples/list-with-detail.vitest.tsx +339 -314
- package/src/examples/list-with-dropdown.tsx +1 -0
- package/src/examples/list-with-dropdown.vitest.tsx +176 -150
- package/src/examples/list-with-sections.vitest.tsx +289 -270
- package/src/examples/list-with-toast.vitest.tsx +44 -44
- package/src/examples/miscellaneous.tsx +10 -0
- package/src/examples/simple-file-picker.vitest.tsx +90 -86
- package/src/examples/simple-grid.vitest.tsx +275 -249
- package/src/examples/simple-navigation.vitest.tsx +192 -168
- package/src/examples/store.vitest.tsx +6 -4
- package/src/examples/swift-extension.vitest.tsx +31 -19
- package/src/examples/synonyms.vitest.tsx +93 -83
- package/src/examples/toast-action.tsx +160 -0
- package/src/examples/toast-action.vitest.tsx +404 -0
- package/src/examples/toast-variations.tsx +58 -57
- package/src/examples/toast-variations.vitest.tsx +186 -166
- package/src/extensions/dev.tsx +74 -33
- package/src/extensions/dev.vitest.tsx +162 -69
- package/src/extensions/home.tsx +5 -6
- package/src/extensions/react-refresh-init.tsx +59 -0
- package/src/internal/date-picker-widget.tsx +1 -1
- package/src/internal/dialog.tsx +59 -83
- package/src/internal/navigation.tsx +37 -4
- package/src/internal/providers.tsx +27 -315
- package/src/internal/scrollbox.tsx +1 -0
- package/src/release.tsx +16 -10
- package/src/state.tsx +36 -3
- package/src/theme.tsx +82 -51
- package/src/themes/aura.json +69 -0
- package/src/themes/ayu.json +80 -0
- package/src/themes/catppuccin-frappe.json +233 -0
- package/src/themes/catppuccin-macchiato.json +233 -0
- package/src/themes/catppuccin.json +112 -0
- package/src/themes/cobalt2.json +228 -0
- package/src/themes/cursor.json +249 -0
- package/src/themes/dracula.json +219 -0
- package/src/themes/everforest.json +241 -0
- package/src/themes/flexoki.json +237 -0
- package/src/themes/github-light.json +56 -0
- package/src/themes/github.json +241 -0
- package/src/themes/gruvbox.json +95 -0
- package/src/themes/kanagawa.json +77 -0
- package/src/themes/lucent-orng.json +227 -0
- package/src/themes/material.json +235 -0
- package/src/themes/matrix.json +77 -0
- package/src/themes/mercury.json +252 -0
- package/src/themes/monokai.json +221 -0
- package/src/themes/nightowl.json +221 -0
- package/src/themes/nord.json +223 -0
- package/src/themes/one-dark.json +84 -0
- package/src/themes/opencode-light.json +62 -0
- package/src/themes/opencode.json +245 -0
- package/src/themes/orng.json +245 -0
- package/src/themes/palenight.json +222 -0
- package/src/themes/rosepine.json +234 -0
- package/src/themes/solarized.json +223 -0
- package/src/themes/synthwave84.json +226 -0
- package/src/themes/termcast.json +227 -0
- package/src/themes/tokyonight.json +243 -0
- package/src/themes/vercel.json +255 -0
- package/src/themes/vesper.json +218 -0
- package/src/themes/zenburn.json +223 -0
- package/src/themes.ts +291 -0
- package/src/utils/run-command.tsx +23 -12
- package/src/utils.tsx +115 -18
- 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, {
|
|
1
|
+
import React, { useEffect } from 'react'
|
|
2
2
|
import { List, ActionPanel, Action, renderWithProviders } from 'termcast'
|
|
3
|
-
import { Toast,
|
|
3
|
+
import { Toast, showToast } from 'termcast/src/apis/toast'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
interface ToastVariation {
|
|
6
|
+
name: string
|
|
7
|
+
options: Toast.Options
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const toastVariations: ToastVariation[] = [
|
|
6
11
|
{
|
|
7
12
|
name: 'Simple Success',
|
|
8
|
-
|
|
13
|
+
options: {
|
|
9
14
|
title: 'Success',
|
|
10
15
|
style: Toast.Style.Success,
|
|
11
|
-
}
|
|
16
|
+
},
|
|
12
17
|
},
|
|
13
18
|
{
|
|
14
19
|
name: 'Simple Failure',
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
115
|
-
|
|
118
|
+
// Show first toast on mount
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
showToast(toastVariations[0].options)
|
|
121
|
+
}, [])
|
|
116
122
|
|
|
117
123
|
return (
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
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
|
|