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
package/src/apis/toast.tsx
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Theme } from 'termcast/src/theme'
|
|
3
|
-
import { TextAttributes } from '@opentui/core'
|
|
4
|
-
import { useStore } from 'termcast/src/state'
|
|
5
|
-
import { useKeyboard, useTerminalDimensions } from '@opentui/react'
|
|
6
|
-
import { useIsInFocus } from 'termcast/src/internal/focus-context'
|
|
1
|
+
import { useStore, ToastData, ToastStyle } from 'termcast/src/state'
|
|
7
2
|
|
|
8
3
|
export namespace Toast {
|
|
9
4
|
export interface Options {
|
|
@@ -20,302 +15,149 @@ export namespace Toast {
|
|
|
20
15
|
onAction: (toast: Toast) => void
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
export type Style =
|
|
18
|
+
export type Style = ToastStyle
|
|
24
19
|
}
|
|
25
20
|
|
|
26
21
|
export class Toast {
|
|
27
|
-
private
|
|
28
|
-
private
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
private _id: string
|
|
23
|
+
private _title: string
|
|
24
|
+
private _message?: string
|
|
25
|
+
private _style: ToastStyle
|
|
26
|
+
private _primaryAction?: Toast.ActionOptions
|
|
27
|
+
private _secondaryAction?: Toast.ActionOptions
|
|
33
28
|
|
|
34
29
|
static Style = {
|
|
35
|
-
Success: 'SUCCESS' as
|
|
36
|
-
Failure: 'FAILURE' as
|
|
37
|
-
Animated: 'ANIMATED' as
|
|
30
|
+
Success: 'SUCCESS' as ToastStyle,
|
|
31
|
+
Failure: 'FAILURE' as ToastStyle,
|
|
32
|
+
Animated: 'ANIMATED' as ToastStyle,
|
|
38
33
|
}
|
|
39
34
|
|
|
40
35
|
constructor(props: Toast.Options) {
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
36
|
+
this._id = Math.random().toString(36).substring(7)
|
|
37
|
+
this._title = props.title
|
|
38
|
+
this._message = props.message
|
|
39
|
+
this._style = props.style || 'SUCCESS'
|
|
40
|
+
this._primaryAction = props.primaryAction
|
|
41
|
+
this._secondaryAction = props.secondaryAction
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private _isShowing(): boolean {
|
|
45
|
+
return useStore.getState().toast?.id === this._id
|
|
46
|
+
}
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
private _updateState(): void {
|
|
49
|
+
if (this._isShowing()) {
|
|
50
|
+
useStore.setState({
|
|
51
|
+
toast: this._toData(),
|
|
52
|
+
toastWithPrimaryAction: Boolean(this._primaryAction),
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private _toData(): ToastData {
|
|
58
|
+
return {
|
|
59
|
+
id: this._id,
|
|
60
|
+
title: this._title,
|
|
61
|
+
message: this._message,
|
|
62
|
+
style: this._style,
|
|
63
|
+
primaryAction: this._primaryAction
|
|
64
|
+
? {
|
|
65
|
+
title: this._primaryAction.title,
|
|
66
|
+
onAction: () => {
|
|
67
|
+
this.hide()
|
|
68
|
+
this._primaryAction?.onAction(this)
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
: undefined,
|
|
72
|
+
secondaryAction: this._secondaryAction
|
|
73
|
+
? {
|
|
74
|
+
title: this._secondaryAction.title,
|
|
75
|
+
onAction: () => {
|
|
76
|
+
this.hide()
|
|
77
|
+
this._secondaryAction?.onAction(this)
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
: undefined,
|
|
81
|
+
onHide: () => {
|
|
82
|
+
this.hide()
|
|
83
|
+
},
|
|
84
|
+
}
|
|
50
85
|
}
|
|
51
86
|
|
|
52
|
-
get style():
|
|
53
|
-
return this.
|
|
87
|
+
get style(): ToastStyle {
|
|
88
|
+
return this._style
|
|
54
89
|
}
|
|
55
90
|
|
|
56
|
-
set style(style:
|
|
57
|
-
this.
|
|
58
|
-
this.
|
|
91
|
+
set style(style: ToastStyle) {
|
|
92
|
+
this._style = style
|
|
93
|
+
this._updateState()
|
|
59
94
|
}
|
|
60
95
|
|
|
61
96
|
get title(): string {
|
|
62
|
-
return this.
|
|
97
|
+
return this._title
|
|
63
98
|
}
|
|
64
99
|
|
|
65
100
|
set title(title: string) {
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
101
|
+
this._title = title
|
|
102
|
+
this._updateState()
|
|
68
103
|
}
|
|
69
104
|
|
|
70
105
|
get message(): string | undefined {
|
|
71
|
-
return this.
|
|
106
|
+
return this._message
|
|
72
107
|
}
|
|
73
108
|
|
|
74
109
|
set message(message: string | undefined) {
|
|
75
|
-
this.
|
|
76
|
-
this.
|
|
110
|
+
this._message = message
|
|
111
|
+
this._updateState()
|
|
77
112
|
}
|
|
78
113
|
|
|
79
114
|
get primaryAction(): Toast.ActionOptions | undefined {
|
|
80
|
-
return this.
|
|
115
|
+
return this._primaryAction
|
|
81
116
|
}
|
|
82
117
|
|
|
83
118
|
set primaryAction(action: Toast.ActionOptions | undefined) {
|
|
84
|
-
this.
|
|
85
|
-
this.
|
|
119
|
+
this._primaryAction = action
|
|
120
|
+
this._updateState()
|
|
86
121
|
}
|
|
87
122
|
|
|
88
123
|
get secondaryAction(): Toast.ActionOptions | undefined {
|
|
89
|
-
return this.
|
|
124
|
+
return this._secondaryAction
|
|
90
125
|
}
|
|
91
126
|
|
|
92
127
|
set secondaryAction(action: Toast.ActionOptions | undefined) {
|
|
93
|
-
this.
|
|
94
|
-
this.
|
|
128
|
+
this._secondaryAction = action
|
|
129
|
+
this._updateState()
|
|
95
130
|
}
|
|
96
131
|
|
|
97
132
|
async show(): Promise<void> {
|
|
98
|
-
|
|
133
|
+
useStore.setState({
|
|
134
|
+
toast: this._toData(),
|
|
135
|
+
toastWithPrimaryAction: Boolean(this._primaryAction),
|
|
136
|
+
})
|
|
99
137
|
}
|
|
100
138
|
|
|
101
139
|
async hide(): Promise<void> {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.callbacks.onHide()
|
|
140
|
+
if (this._isShowing()) {
|
|
141
|
+
useStore.setState({ toast: null, toastWithPrimaryAction: false })
|
|
105
142
|
}
|
|
106
143
|
}
|
|
107
|
-
|
|
108
|
-
private update(): void {
|
|
109
|
-
if (this.callbacks.onUpdate) {
|
|
110
|
-
this.callbacks.onUpdate(this)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
_setCallbacks(callbacks: typeof this.callbacks): void {
|
|
115
|
-
this.callbacks = callbacks
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
_getId(): string {
|
|
119
|
-
return this.id
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export interface ToastContentProps {
|
|
124
|
-
toast: Toast
|
|
125
|
-
onHide: () => void
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function ToastContent({ toast, onHide }: ToastContentProps): any {
|
|
129
|
-
const [, forceUpdate] = useState(0)
|
|
130
|
-
const inFocus = useIsInFocus()
|
|
131
|
-
|
|
132
|
-
useEffect(() => {
|
|
133
|
-
const onUpdate = () => {
|
|
134
|
-
forceUpdate((n) => n + 1)
|
|
135
|
-
}
|
|
136
|
-
toast._setCallbacks({ onUpdate, onHide })
|
|
137
|
-
return () => {
|
|
138
|
-
toast._setCallbacks({})
|
|
139
|
-
}
|
|
140
|
-
}, [toast, onHide])
|
|
141
|
-
|
|
142
|
-
useKeyboard((evt) => {
|
|
143
|
-
if (!inFocus) return
|
|
144
|
-
|
|
145
|
-
if (evt.name === 'escape') {
|
|
146
|
-
onHide()
|
|
147
|
-
} else if (toast.primaryAction && evt.name === 'return') {
|
|
148
|
-
toast.primaryAction.onAction(toast)
|
|
149
|
-
} else if (toast.secondaryAction && evt.name === 'tab') {
|
|
150
|
-
toast.secondaryAction.onAction(toast)
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
const getIcon = () => {
|
|
155
|
-
switch (toast.style) {
|
|
156
|
-
case Toast.Style.Success:
|
|
157
|
-
return '✓'
|
|
158
|
-
case Toast.Style.Failure:
|
|
159
|
-
return '✗'
|
|
160
|
-
case Toast.Style.Animated:
|
|
161
|
-
return '⣾⣽⣻⢿⡿⣟⣯⣷'
|
|
162
|
-
default:
|
|
163
|
-
return '✓'
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const getIconColor = () => {
|
|
168
|
-
switch (toast.style) {
|
|
169
|
-
case Toast.Style.Success:
|
|
170
|
-
return Theme.success
|
|
171
|
-
case Toast.Style.Failure:
|
|
172
|
-
return Theme.error
|
|
173
|
-
case Toast.Style.Animated:
|
|
174
|
-
return Theme.primary
|
|
175
|
-
default:
|
|
176
|
-
return Theme.success
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const [animationFrame, setAnimationFrame] = useState(0)
|
|
181
|
-
|
|
182
|
-
useEffect(() => {
|
|
183
|
-
if (toast.style === Toast.Style.Animated) {
|
|
184
|
-
const interval = setInterval(() => {
|
|
185
|
-
setAnimationFrame((prev) => (prev + 1) % 8)
|
|
186
|
-
}, 100)
|
|
187
|
-
return () => clearInterval(interval)
|
|
188
|
-
}
|
|
189
|
-
}, [toast.style])
|
|
190
|
-
|
|
191
|
-
useEffect(() => {
|
|
192
|
-
if (toast.style !== Toast.Style.Animated) {
|
|
193
|
-
const duration = toast.style === Toast.Style.Failure ? 8000 : 5000
|
|
194
|
-
const timer = setTimeout(() => {
|
|
195
|
-
onHide()
|
|
196
|
-
}, duration)
|
|
197
|
-
return () => clearTimeout(timer)
|
|
198
|
-
}
|
|
199
|
-
}, [toast.style, onHide])
|
|
200
|
-
|
|
201
|
-
const icon =
|
|
202
|
-
toast.style === Toast.Style.Animated ? getIcon()[animationFrame] : getIcon()
|
|
203
|
-
|
|
204
|
-
return (
|
|
205
|
-
<box
|
|
206
|
-
borderColor={Theme.border}
|
|
207
|
-
backgroundColor={Theme.background}
|
|
208
|
-
paddingLeft={1}
|
|
209
|
-
paddingRight={1}
|
|
210
|
-
flexDirection='column'
|
|
211
|
-
>
|
|
212
|
-
<box flexDirection='row' alignItems='center'>
|
|
213
|
-
<text flexShrink={0} fg={getIconColor()}>
|
|
214
|
-
{icon}{' '}
|
|
215
|
-
</text>
|
|
216
|
-
<text flexShrink={0} fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
217
|
-
{toast.title}
|
|
218
|
-
</text>
|
|
219
|
-
{toast.primaryAction && (
|
|
220
|
-
<box
|
|
221
|
-
flexShrink={0}
|
|
222
|
-
onMouseDown={() => {
|
|
223
|
-
toast.primaryAction?.onAction(toast)
|
|
224
|
-
}}
|
|
225
|
-
>
|
|
226
|
-
<text fg={Theme.primary}>
|
|
227
|
-
{' '}
|
|
228
|
-
[{toast.primaryAction.title} ↵]
|
|
229
|
-
</text>
|
|
230
|
-
</box>
|
|
231
|
-
)}
|
|
232
|
-
{toast.secondaryAction && (
|
|
233
|
-
<box
|
|
234
|
-
flexShrink={0}
|
|
235
|
-
onMouseDown={() => {
|
|
236
|
-
toast.secondaryAction?.onAction(toast)
|
|
237
|
-
}}
|
|
238
|
-
>
|
|
239
|
-
<text fg={Theme.textMuted}>
|
|
240
|
-
{' '}
|
|
241
|
-
[{toast.secondaryAction.title} ⇥]
|
|
242
|
-
</text>
|
|
243
|
-
</box>
|
|
244
|
-
)}
|
|
245
|
-
</box>
|
|
246
|
-
{toast.message && (
|
|
247
|
-
<box paddingLeft={2}>
|
|
248
|
-
<text flexShrink={0} fg={Theme.textMuted}>
|
|
249
|
-
{toast.message}
|
|
250
|
-
</text>
|
|
251
|
-
</box>
|
|
252
|
-
)}
|
|
253
|
-
</box>
|
|
254
|
-
)
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export function ToastOverlay(): any {
|
|
258
|
-
const dimensions = useTerminalDimensions()
|
|
259
|
-
const toastElement = useStore((state) => state.toast)
|
|
260
|
-
|
|
261
|
-
if (!toastElement) {
|
|
262
|
-
return null
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return (
|
|
266
|
-
<box
|
|
267
|
-
position='absolute'
|
|
268
|
-
left={0}
|
|
269
|
-
bottom={0}
|
|
270
|
-
width={dimensions.width}
|
|
271
|
-
maxHeight={10}
|
|
272
|
-
justifyContent='flex-end'
|
|
273
|
-
alignItems='center'
|
|
274
|
-
>
|
|
275
|
-
{toastElement}
|
|
276
|
-
</box>
|
|
277
|
-
)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
let currentToastInstance: Toast | null = null
|
|
281
|
-
|
|
282
|
-
export function showToastInternal(toast: Toast): void {
|
|
283
|
-
currentToastInstance = toast
|
|
284
|
-
useStore.setState({
|
|
285
|
-
toast: (
|
|
286
|
-
<ToastContent
|
|
287
|
-
toast={toast}
|
|
288
|
-
onHide={() => {
|
|
289
|
-
useStore.setState({ toast: null })
|
|
290
|
-
currentToastInstance = null
|
|
291
|
-
}}
|
|
292
|
-
/>
|
|
293
|
-
),
|
|
294
|
-
})
|
|
295
144
|
}
|
|
296
145
|
|
|
297
146
|
export async function showToast(options: Toast.Options): Promise<Toast>
|
|
298
147
|
export async function showToast(
|
|
299
148
|
style: Toast.Style,
|
|
300
149
|
title: string,
|
|
301
|
-
message?: string
|
|
150
|
+
message?: string
|
|
302
151
|
): Promise<Toast>
|
|
303
152
|
export async function showToast(
|
|
304
153
|
optionsOrStyle: Toast.Options | Toast.Style,
|
|
305
154
|
title?: string,
|
|
306
|
-
message?: string
|
|
155
|
+
message?: string
|
|
307
156
|
): Promise<Toast> {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
style: optionsOrStyle,
|
|
313
|
-
title: title!,
|
|
314
|
-
message,
|
|
315
|
-
}
|
|
316
|
-
} else {
|
|
317
|
-
options = optionsOrStyle
|
|
318
|
-
}
|
|
157
|
+
const options: Toast.Options =
|
|
158
|
+
typeof optionsOrStyle === 'string'
|
|
159
|
+
? { style: optionsOrStyle, title: title!, message }
|
|
160
|
+
: optionsOrStyle
|
|
319
161
|
|
|
320
162
|
const toast = new Toast(options)
|
|
321
163
|
await toast.show()
|
|
@@ -324,37 +166,13 @@ export async function showToast(
|
|
|
324
166
|
|
|
325
167
|
/**
|
|
326
168
|
* Creates and shows a failure toast for error scenarios.
|
|
327
|
-
*
|
|
328
|
-
* This is a convenience function that automatically creates a toast with failure styling
|
|
329
|
-
* and extracts error messages from various error types.
|
|
330
|
-
*
|
|
331
|
-
* @param error - The error to display. Can be an Error object, string, or any object with a message property
|
|
332
|
-
* @param options - Optional configuration
|
|
333
|
-
* @param options.title - Custom title for the toast (defaults to error name or "Something went wrong")
|
|
334
|
-
* @param options.primaryAction - Optional action button to display on the toast
|
|
335
|
-
* @returns A Promise that resolves to the created Toast instance
|
|
336
|
-
*
|
|
337
|
-
* @example
|
|
338
|
-
* ```typescript
|
|
339
|
-
* try {
|
|
340
|
-
* await riskyOperation()
|
|
341
|
-
* } catch (error) {
|
|
342
|
-
* await showFailureToast(error, {
|
|
343
|
-
* title: "Operation Failed",
|
|
344
|
-
* primaryAction: {
|
|
345
|
-
* title: "Retry",
|
|
346
|
-
* onAction: () => retryOperation()
|
|
347
|
-
* }
|
|
348
|
-
* })
|
|
349
|
-
* }
|
|
350
|
-
* ```
|
|
351
169
|
*/
|
|
352
170
|
export async function showFailureToast(
|
|
353
171
|
error: unknown,
|
|
354
172
|
options?: {
|
|
355
173
|
title?: string
|
|
356
174
|
primaryAction?: Toast.ActionOptions
|
|
357
|
-
}
|
|
175
|
+
}
|
|
358
176
|
): Promise<Toast> {
|
|
359
177
|
let errorMessage: string
|
|
360
178
|
let errorTitle: string
|
|
@@ -373,12 +191,10 @@ export async function showFailureToast(
|
|
|
373
191
|
errorTitle = options?.title || 'Something went wrong'
|
|
374
192
|
}
|
|
375
193
|
|
|
376
|
-
|
|
194
|
+
return showToast({
|
|
377
195
|
title: errorTitle,
|
|
378
196
|
message: errorMessage,
|
|
379
197
|
style: Toast.Style.Failure,
|
|
380
198
|
primaryAction: options?.primaryAction,
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return showToast(toastOptions)
|
|
199
|
+
})
|
|
384
200
|
}
|
package/src/build.test.tsx
CHANGED
|
@@ -121,6 +121,16 @@ describe('buildExtensionCommands', () => {
|
|
|
121
121
|
"filePath": "/BASE_PATH/fixtures/simple-extension/src/quick-action.tsx",
|
|
122
122
|
"exists": true,
|
|
123
123
|
"bundledPath": "/BASE_PATH/fixtures/simple-extension/.termcast-bundle/quick-action.js"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "throw-error",
|
|
127
|
+
"title": "Throw Error",
|
|
128
|
+
"subtitle": "Test error handling",
|
|
129
|
+
"description": "Command that throws an error at root scope",
|
|
130
|
+
"mode": "view",
|
|
131
|
+
"filePath": "/BASE_PATH/fixtures/simple-extension/src/throw-error.tsx",
|
|
132
|
+
"exists": true,
|
|
133
|
+
"bundledPath": "/BASE_PATH/fixtures/simple-extension/.termcast-bundle/throw-error.js"
|
|
124
134
|
}
|
|
125
135
|
],
|
|
126
136
|
"bundleDir": "/BASE_PATH/fixtures/simple-extension/.termcast-bundle"
|
package/src/build.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { execSync } from 'node:child_process'
|
|
4
4
|
import type { BunPlugin } from 'bun'
|
|
5
|
+
import * as swc from '@swc/core'
|
|
5
6
|
import { logger } from './logger'
|
|
6
7
|
import { getCommandsWithFiles, CommandWithFile } from './package-json'
|
|
7
8
|
import * as termcastApi from './index'
|
|
@@ -179,6 +180,58 @@ export const aliasPlugin: BunPlugin = {
|
|
|
179
180
|
},
|
|
180
181
|
}
|
|
181
182
|
|
|
183
|
+
// React Refresh transform plugin for hot reloading using SWC (Rust-based, ~20x faster than Babel)
|
|
184
|
+
// Transforms extension source files to inject $RefreshReg$ and $RefreshSig$ calls
|
|
185
|
+
export const reactRefreshPlugin: BunPlugin = {
|
|
186
|
+
name: 'react-refresh-transform',
|
|
187
|
+
async setup(build) {
|
|
188
|
+
build.onLoad({ filter: /\.[tj]sx?$/ }, async (args) => {
|
|
189
|
+
// Skip node_modules
|
|
190
|
+
if (args.path.includes('node_modules')) {
|
|
191
|
+
return undefined
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const code = await Bun.file(args.path).text()
|
|
195
|
+
|
|
196
|
+
const isTypeScript =
|
|
197
|
+
args.path.endsWith('.ts') || args.path.endsWith('.tsx')
|
|
198
|
+
const hasJsx = args.path.endsWith('.tsx') || args.path.endsWith('.jsx')
|
|
199
|
+
|
|
200
|
+
const result = await swc.transform(code, {
|
|
201
|
+
filename: args.path,
|
|
202
|
+
jsc: {
|
|
203
|
+
parser: isTypeScript
|
|
204
|
+
? {
|
|
205
|
+
syntax: 'typescript',
|
|
206
|
+
tsx: hasJsx,
|
|
207
|
+
}
|
|
208
|
+
: {
|
|
209
|
+
syntax: 'ecmascript',
|
|
210
|
+
jsx: hasJsx,
|
|
211
|
+
},
|
|
212
|
+
transform: {
|
|
213
|
+
react: {
|
|
214
|
+
development: true,
|
|
215
|
+
refresh: true, // Built-in React Refresh support in SWC
|
|
216
|
+
runtime: 'automatic',
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
sourceMaps: 'inline',
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
if (!result?.code) {
|
|
224
|
+
return undefined
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
contents: result.code,
|
|
229
|
+
loader: 'js', // SWC transforms JSX to JS
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
},
|
|
233
|
+
}
|
|
234
|
+
|
|
182
235
|
interface BundledCommand extends CommandWithFile {
|
|
183
236
|
bundledPath: string
|
|
184
237
|
}
|
|
@@ -192,10 +245,12 @@ export async function buildExtensionCommands({
|
|
|
192
245
|
extensionPath,
|
|
193
246
|
format = 'cjs',
|
|
194
247
|
target,
|
|
248
|
+
hotReload = false,
|
|
195
249
|
}: {
|
|
196
250
|
extensionPath: string
|
|
197
251
|
format?: 'cjs' | 'esm'
|
|
198
252
|
target?: 'node' | 'bun'
|
|
253
|
+
hotReload?: boolean
|
|
199
254
|
}): Promise<BuildResult> {
|
|
200
255
|
const resolvedPath = path.resolve(extensionPath)
|
|
201
256
|
const bundleDir = path.join(resolvedPath, '.termcast-bundle')
|
|
@@ -221,13 +276,18 @@ export async function buildExtensionCommands({
|
|
|
221
276
|
|
|
222
277
|
logger.log(`Building ${entrypoints.length} commands...`)
|
|
223
278
|
|
|
279
|
+
const plugins = [aliasPlugin, swiftLoaderPlugin]
|
|
280
|
+
if (hotReload) {
|
|
281
|
+
plugins.push(reactRefreshPlugin)
|
|
282
|
+
}
|
|
283
|
+
|
|
224
284
|
const result = await Bun.build({
|
|
225
285
|
entrypoints,
|
|
226
286
|
outdir: bundleDir,
|
|
227
287
|
target: target || (format === 'cjs' ? 'node' : 'bun'),
|
|
228
288
|
format,
|
|
229
289
|
// external: [],
|
|
230
|
-
plugins
|
|
290
|
+
plugins,
|
|
231
291
|
naming: '[name].js',
|
|
232
292
|
throw: false,
|
|
233
293
|
})
|