termcast 1.3.34 → 1.3.36
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/build.d.ts.map +1 -1
- package/dist/build.js +25 -0
- package/dist/build.js.map +1 -1
- package/dist/components/footer.d.ts.map +1 -1
- package/dist/components/footer.js +1 -1
- package/dist/components/footer.js.map +1 -1
- package/dist/components/icon.d.ts.map +1 -1
- package/dist/components/icon.js +386 -23
- package/dist/components/icon.js.map +1 -1
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +70 -7
- package/dist/components/list.js.map +1 -1
- package/dist/extensions/home.js +1 -1
- package/dist/extensions/home.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/dialog.d.ts.map +1 -1
- package/dist/internal/dialog.js +4 -5
- package/dist/internal/dialog.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +18 -5
- package/dist/internal/providers.js.map +1 -1
- package/dist/state.d.ts +1 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +6 -2
- package/dist/theme.js.map +1 -1
- package/dist/utils.d.ts +16 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +28 -1
- package/dist/utils.js.map +1 -1
- package/package.json +8 -4
- package/src/build.tsx +28 -0
- package/src/compile.vitest.tsx +18 -18
- package/src/components/footer.tsx +4 -2
- package/src/components/icon.tsx +385 -23
- package/src/components/list.tsx +84 -13
- package/src/examples/github.vitest.tsx +36 -36
- package/src/examples/list-detail-metadata.vitest.tsx +1 -1
- package/src/examples/list-dropdown-default.vitest.tsx +9 -9
- package/src/examples/list-scrollbox.vitest.tsx +41 -41
- package/src/examples/list-with-detail.vitest.tsx +35 -36
- package/src/examples/list-with-sections.vitest.tsx +117 -117
- package/src/examples/simple-grid.vitest.tsx +44 -44
- package/src/examples/simple-navigation.vitest.tsx +43 -12
- package/src/examples/store.vitest.tsx +1 -1
- package/src/examples/swift-extension.vitest.tsx +3 -3
- package/src/extensions/dev.vitest.tsx +21 -21
- package/src/extensions/home.tsx +1 -1
- package/src/index.tsx +1 -0
- package/src/internal/dialog.tsx +21 -23
- package/src/internal/providers.tsx +18 -5
- package/src/state.tsx +1 -0
- package/src/theme.tsx +6 -2
- package/src/utils.tsx +40 -1
|
@@ -111,7 +111,7 @@ test('navigation between main and detail views', async () => {
|
|
|
111
111
|
> Detail view - Press ESC to go back
|
|
112
112
|
|
|
113
113
|
Details
|
|
114
|
-
›This is the detail view for Second Item Press Enter to go back
|
|
114
|
+
›This is the detail view for Second Item Press Enter to go back o
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
|
|
@@ -153,8 +153,8 @@ test('navigation between main and detail views', async () => {
|
|
|
153
153
|
> Main view
|
|
154
154
|
|
|
155
155
|
Items
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
First Item Navigate to first detail
|
|
157
|
+
›Second Item Navigate to second detail
|
|
158
158
|
Third Item Navigate to third detail
|
|
159
159
|
|
|
160
160
|
|
|
@@ -187,9 +187,9 @@ test('navigation between main and detail views', async () => {
|
|
|
187
187
|
> Main view
|
|
188
188
|
|
|
189
189
|
Items
|
|
190
|
-
|
|
190
|
+
›First Item Navigate to first detail
|
|
191
191
|
Second Item Navigate to second detail
|
|
192
|
-
|
|
192
|
+
Third Item Navigate to third detail
|
|
193
193
|
|
|
194
194
|
|
|
195
195
|
|
|
@@ -215,12 +215,12 @@ test('navigation between main and detail views', async () => {
|
|
|
215
215
|
"
|
|
216
216
|
|
|
217
217
|
|
|
218
|
-
Detail:
|
|
218
|
+
Detail: First Item ─────────────────────────────────────────────
|
|
219
219
|
|
|
220
220
|
> Detail view - Press ESC to go back
|
|
221
221
|
|
|
222
222
|
Details
|
|
223
|
-
›This is the detail view for
|
|
223
|
+
›This is the detail view for First Item Press Enter to go back or
|
|
224
224
|
|
|
225
225
|
|
|
226
226
|
|
|
@@ -412,7 +412,7 @@ test('navigation with actions panel', async () => {
|
|
|
412
412
|
> Detail view - Press ESC to go back
|
|
413
413
|
|
|
414
414
|
Details
|
|
415
|
-
›This is the detail view for Second Item Press Enter to go back
|
|
415
|
+
›This is the detail view for Second Item Press Enter to go back o
|
|
416
416
|
|
|
417
417
|
|
|
418
418
|
|
|
@@ -482,8 +482,8 @@ test('navigation with actions panel', async () => {
|
|
|
482
482
|
> Main view
|
|
483
483
|
|
|
484
484
|
Items
|
|
485
|
-
|
|
486
|
-
|
|
485
|
+
First Item Navigate to first detail
|
|
486
|
+
›Second Item Navigate to second detail
|
|
487
487
|
Third Item Navigate to third detail
|
|
488
488
|
|
|
489
489
|
|
|
@@ -606,7 +606,7 @@ test('search functionality in main and detail views', async () => {
|
|
|
606
606
|
> Detail view - Press ESC to go back
|
|
607
607
|
|
|
608
608
|
Details
|
|
609
|
-
›This is the detail view for First Item Press Enter to go back
|
|
609
|
+
›This is the detail view for First Item Press Enter to go back or
|
|
610
610
|
|
|
611
611
|
|
|
612
612
|
|
|
@@ -644,7 +644,7 @@ test('search functionality in main and detail views', async () => {
|
|
|
644
644
|
|
|
645
645
|
|
|
646
646
|
|
|
647
|
-
|
|
647
|
+
No items found
|
|
648
648
|
|
|
649
649
|
|
|
650
650
|
|
|
@@ -700,3 +700,34 @@ test('search functionality in main and detail views', async () => {
|
|
|
700
700
|
"
|
|
701
701
|
`)
|
|
702
702
|
}, 10000)
|
|
703
|
+
|
|
704
|
+
test('keeps selected item after opening detail and pressing esc', async () => {
|
|
705
|
+
await session.text({
|
|
706
|
+
waitFor: (text) => {
|
|
707
|
+
return /Navigation Example/i.test(text) && /First Item/i.test(text)
|
|
708
|
+
},
|
|
709
|
+
})
|
|
710
|
+
|
|
711
|
+
await session.press('down')
|
|
712
|
+
const selectedSecondSnapshot = await session.text()
|
|
713
|
+
expect(selectedSecondSnapshot).toContain('›Second Item')
|
|
714
|
+
|
|
715
|
+
await session.press('enter')
|
|
716
|
+
await session.text({
|
|
717
|
+
waitFor: (text) => {
|
|
718
|
+
return /Detail: Second Item/i.test(text)
|
|
719
|
+
},
|
|
720
|
+
timeout: 3000,
|
|
721
|
+
})
|
|
722
|
+
|
|
723
|
+
await session.press('esc')
|
|
724
|
+
const backSnapshot = await session.text({
|
|
725
|
+
waitFor: (text) => {
|
|
726
|
+
return /Navigation Example/i.test(text)
|
|
727
|
+
},
|
|
728
|
+
timeout: 3000,
|
|
729
|
+
})
|
|
730
|
+
|
|
731
|
+
expect(backSnapshot).toContain('›Second Item')
|
|
732
|
+
expect(backSnapshot).not.toContain('›First Item')
|
|
733
|
+
}, 10000)
|
|
@@ -50,7 +50,7 @@ test('Store extension - searching for spiceblow shows Database', async () => {
|
|
|
50
50
|
|
|
51
51
|
> spiceblow
|
|
52
52
|
|
|
53
|
-
›Spiceblow - Sql Database Management Search, update, insert and delete
|
|
53
|
+
›Spiceblow - Sql Database Management Search, update, insert and delete rows
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
|
|
@@ -89,13 +89,14 @@ test.skipIf(isLinux)('swift extension dev mode shows command list', async () =>
|
|
|
89
89
|
> Search commands...
|
|
90
90
|
|
|
91
91
|
Commands
|
|
92
|
-
›List Items Displays a simple list with some items
|
|
93
|
-
Swift List Displays a list of items returned by a Swift
|
|
92
|
+
›List Items Displays a simple list with some items view
|
|
93
|
+
Swift List Displays a list of items returned by a Swift fun view
|
|
94
94
|
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
|
|
99
|
+
↵ run command ↑↓ navigate ^k actions
|
|
99
100
|
|
|
100
101
|
|
|
101
102
|
|
|
@@ -104,7 +105,6 @@ test.skipIf(isLinux)('swift extension dev mode shows command list', async () =>
|
|
|
104
105
|
|
|
105
106
|
|
|
106
107
|
|
|
107
|
-
↵ run command ↑↓ navigate ^k actions
|
|
108
108
|
|
|
109
109
|
"
|
|
110
110
|
`)
|
|
@@ -57,12 +57,12 @@ test('dev command shows extension commands list', async () => {
|
|
|
57
57
|
|
|
58
58
|
> Search commands...
|
|
59
59
|
|
|
60
|
-
Commands
|
|
61
|
-
›List Items Displays a simple list with some
|
|
62
|
-
Search Items Search and filter through a list
|
|
63
|
-
Google Oauth
|
|
64
|
-
usePromise Demo Shows how to use the usePromise view
|
|
65
|
-
Show State Shows the current application state
|
|
60
|
+
Commands
|
|
61
|
+
›List Items Displays a simple list with some items view
|
|
62
|
+
Search Items Search and filter through a list of view
|
|
63
|
+
Google Oauth view
|
|
64
|
+
usePromise Demo Shows how to use the usePromise h view
|
|
65
|
+
Show State Shows the current application state in view
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
↵ run command ↑↓ navigate ^k actions
|
|
@@ -93,12 +93,12 @@ test('selecting command with arguments shows arguments form', async () => {
|
|
|
93
93
|
|
|
94
94
|
> Search commands...
|
|
95
95
|
|
|
96
|
-
Google Oauth
|
|
97
|
-
usePromise Demo Shows how to use the usePromise view
|
|
98
|
-
Show State Shows the current application state
|
|
99
|
-
›With Arguments Demonstrates command arguments ( view
|
|
100
|
-
Quick Action Copies current timestamp to
|
|
101
|
-
Throw Error Command that throws an error at
|
|
96
|
+
Google Oauth view
|
|
97
|
+
usePromise Demo Shows how to use the usePromise h view
|
|
98
|
+
Show State Shows the current application state in view
|
|
99
|
+
›With Arguments Demonstrates command arguments (te view
|
|
100
|
+
Quick Action Copies current timestamp to clipb no-view
|
|
101
|
+
Throw Error Command that throws an error at root view
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
↵ run command ↑↓ navigate ^k actions
|
|
@@ -204,9 +204,9 @@ test('can fill arguments and run command', async () => {
|
|
|
204
204
|
> Search...
|
|
205
205
|
|
|
206
206
|
Received Arguments
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
›𝐓 Search Query (empty)
|
|
208
|
+
𝐓 Secret Key (empty)
|
|
209
|
+
𝐓 Category (empty)
|
|
210
210
|
|
|
211
211
|
|
|
212
212
|
|
|
@@ -242,12 +242,12 @@ test('can run simple view command without arguments', async () => {
|
|
|
242
242
|
|
|
243
243
|
> Search...
|
|
244
244
|
|
|
245
|
-
Items
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
Items
|
|
246
|
+
›○ First Item This is the first item
|
|
247
|
+
○ Second Item This is the second item
|
|
248
|
+
○ Third Item This is the third item
|
|
249
|
+
○ Fourth Item This is the fourth item
|
|
250
|
+
○ Fifth Item This is the fifth item
|
|
251
251
|
|
|
252
252
|
|
|
253
253
|
✓ Copied to Clipboard First Item
|
package/src/extensions/home.tsx
CHANGED
|
@@ -181,7 +181,7 @@ function ExtensionsList({
|
|
|
181
181
|
|
|
182
182
|
export async function runHomeCommand(): Promise<void> {
|
|
183
183
|
logger.log(`preparing to render the home command component`)
|
|
184
|
-
await renderWithProviders(<Home
|
|
184
|
+
await renderWithProviders(<Home />, { extensionName: 'termcast-home' })
|
|
185
185
|
logger.log(`rendered home command component`)
|
|
186
186
|
}
|
|
187
187
|
|
package/src/index.tsx
CHANGED
|
@@ -224,6 +224,7 @@ export { TermcastProvider } from 'termcast/src/internal/providers'
|
|
|
224
224
|
|
|
225
225
|
// Helper function for rendering examples
|
|
226
226
|
export { renderWithProviders } from 'termcast/src/utils'
|
|
227
|
+
export type { RenderWithProvidersOptions } from 'termcast/src/utils'
|
|
227
228
|
|
|
228
229
|
// Window Management
|
|
229
230
|
export { closeMainWindow, PopToRootType } from 'termcast/src/apis/window'
|
package/src/internal/dialog.tsx
CHANGED
|
@@ -151,7 +151,6 @@ export function DialogOverlay(): any {
|
|
|
151
151
|
const dialogStack = useStore((state) => state.dialogStack)
|
|
152
152
|
const showActionsDialog = useStore((state) => state.showActionsDialog)
|
|
153
153
|
const navContext = useContext(NavigationContext)
|
|
154
|
-
const theme = useTheme()
|
|
155
154
|
|
|
156
155
|
const setActionsPortalTargetRef = useCallback((node: any) => {
|
|
157
156
|
if (!node) {
|
|
@@ -177,13 +176,33 @@ export function DialogOverlay(): any {
|
|
|
177
176
|
|
|
178
177
|
return (
|
|
179
178
|
<>
|
|
179
|
+
{item && (
|
|
180
|
+
<box position='absolute' width='100%' height='100%' flexDirection='column'>
|
|
181
|
+
<InFocus inFocus={true}>
|
|
182
|
+
<Dialog
|
|
183
|
+
position={item.position}
|
|
184
|
+
onClickOutside={() => {
|
|
185
|
+
const state = useStore.getState()
|
|
186
|
+
if (state.dialogStack.length > 0) {
|
|
187
|
+
useStore.setState({
|
|
188
|
+
dialogStack: state.dialogStack.slice(0, -1),
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
}}
|
|
192
|
+
>
|
|
193
|
+
<NavigationContext.Provider value={navContext}>
|
|
194
|
+
{item.element}
|
|
195
|
+
</NavigationContext.Provider>
|
|
196
|
+
</Dialog>
|
|
197
|
+
</InFocus>
|
|
198
|
+
</box>
|
|
199
|
+
)}
|
|
180
200
|
{showActionsDialog && (
|
|
181
201
|
<box
|
|
182
202
|
position='absolute'
|
|
183
203
|
width='100%'
|
|
184
204
|
height='100%'
|
|
185
205
|
flexDirection='column'
|
|
186
|
-
backgroundColor={theme.background}
|
|
187
206
|
>
|
|
188
207
|
<InFocus inFocus={true}>
|
|
189
208
|
<Dialog
|
|
@@ -201,27 +220,6 @@ export function DialogOverlay(): any {
|
|
|
201
220
|
</InFocus>
|
|
202
221
|
</box>
|
|
203
222
|
)}
|
|
204
|
-
{item && (
|
|
205
|
-
<box position='absolute' width='100%' height='100%' flexDirection='column'>
|
|
206
|
-
<InFocus inFocus={true}>
|
|
207
|
-
<Dialog
|
|
208
|
-
position={item.position}
|
|
209
|
-
onClickOutside={() => {
|
|
210
|
-
const state = useStore.getState()
|
|
211
|
-
if (state.dialogStack.length > 0) {
|
|
212
|
-
useStore.setState({
|
|
213
|
-
dialogStack: state.dialogStack.slice(0, -1),
|
|
214
|
-
})
|
|
215
|
-
}
|
|
216
|
-
}}
|
|
217
|
-
>
|
|
218
|
-
<NavigationContext.Provider value={navContext}>
|
|
219
|
-
{item.element}
|
|
220
|
-
</NavigationContext.Provider>
|
|
221
|
-
</Dialog>
|
|
222
|
-
</InFocus>
|
|
223
|
-
</box>
|
|
224
|
-
)}
|
|
225
223
|
</>
|
|
226
224
|
)
|
|
227
225
|
}
|
|
@@ -35,20 +35,33 @@ const queryClient = new QueryClient({
|
|
|
35
35
|
},
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
|
|
38
|
+
// Lazy-initialized Cache for TanStack Query persistence.
|
|
39
|
+
// Must not be created at module load time because extensionPath may not be set yet
|
|
40
|
+
// (e.g. when renderWithProviders sets state right before rendering).
|
|
41
|
+
// Tracks the extensionPath it was created with so it can be recreated if the path changes.
|
|
42
|
+
let queryCache: Cache | null = null
|
|
43
|
+
let queryCachePath: string | null = null
|
|
44
|
+
|
|
45
|
+
function getQueryCache(): Cache {
|
|
46
|
+
const currentPath = useStore.getState().extensionPath
|
|
47
|
+
if (!queryCache || currentPath !== queryCachePath) {
|
|
48
|
+
queryCache = new Cache({ namespace: 'tanstack-query' })
|
|
49
|
+
queryCachePath = currentPath
|
|
50
|
+
}
|
|
51
|
+
return queryCache
|
|
52
|
+
}
|
|
40
53
|
|
|
41
54
|
const persister = {
|
|
42
55
|
persistClient: async (client: any) => {
|
|
43
56
|
const serialized = JSON.stringify(client)
|
|
44
|
-
|
|
57
|
+
getQueryCache().set('query-client-data', serialized)
|
|
45
58
|
},
|
|
46
59
|
restoreClient: async () => {
|
|
47
|
-
const data =
|
|
60
|
+
const data = getQueryCache().get('query-client-data')
|
|
48
61
|
return data ? JSON.parse(data) : undefined
|
|
49
62
|
},
|
|
50
63
|
removeClient: async () => {
|
|
51
|
-
|
|
64
|
+
getQueryCache().remove('query-client-data')
|
|
52
65
|
},
|
|
53
66
|
}
|
|
54
67
|
|
package/src/state.tsx
CHANGED
package/src/theme.tsx
CHANGED
|
@@ -3,12 +3,16 @@ import { getResolvedTheme, type ResolvedTheme, defaultThemeName, themeNames } fr
|
|
|
3
3
|
import { useStore } from './state'
|
|
4
4
|
import { Cache } from './apis/cache'
|
|
5
5
|
|
|
6
|
-
// Global cache for theme persistence (no namespace = global storage)
|
|
6
|
+
// Global cache for theme persistence (no namespace = global storage).
|
|
7
|
+
// Tracks extensionPath so the cache is recreated if the path changes.
|
|
7
8
|
let globalCache: Cache | null = null
|
|
9
|
+
let globalCachePath: string | null = null
|
|
8
10
|
|
|
9
11
|
function getGlobalCache(): Cache {
|
|
10
|
-
|
|
12
|
+
const currentPath = useStore.getState().extensionPath
|
|
13
|
+
if (!globalCache || currentPath !== globalCachePath) {
|
|
11
14
|
globalCache = new Cache()
|
|
15
|
+
globalCachePath = currentPath
|
|
12
16
|
}
|
|
13
17
|
return globalCache
|
|
14
18
|
}
|
package/src/utils.tsx
CHANGED
|
@@ -12,8 +12,47 @@ import {
|
|
|
12
12
|
type CommandWithFile,
|
|
13
13
|
} from './package-json'
|
|
14
14
|
import { logger } from './logger'
|
|
15
|
+
import { useStore } from './state'
|
|
16
|
+
|
|
17
|
+
export interface RenderWithProvidersOptions {
|
|
18
|
+
extensionName?: string
|
|
19
|
+
extensionPath?: string
|
|
20
|
+
packageJson?: RaycastPackageJson
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Render a React element wrapped in TermcastProvider with all necessary state initialized.
|
|
25
|
+
*
|
|
26
|
+
* Sets up extensionPath (for LocalStorage, Cache, assets) and extensionPackageJson
|
|
27
|
+
* (for preferences, environment metadata, action panel config) before rendering.
|
|
28
|
+
*
|
|
29
|
+
* - extensionName defaults to 'termcast-app'
|
|
30
|
+
* - extensionPath defaults to ~/.termcast/compiled/{extensionName}
|
|
31
|
+
* - packageJson defaults to a minimal { name, title, commands: [] }
|
|
32
|
+
*/
|
|
33
|
+
export async function renderWithProviders(
|
|
34
|
+
element: ReactNode,
|
|
35
|
+
options?: RenderWithProvidersOptions,
|
|
36
|
+
): Promise<void> {
|
|
37
|
+
const extensionName = options?.extensionName || 'termcast-app'
|
|
38
|
+
const extensionPath =
|
|
39
|
+
options?.extensionPath ||
|
|
40
|
+
path.join(os.homedir(), '.termcast', 'compiled', extensionName)
|
|
41
|
+
const packageJson: RaycastPackageJson = options?.packageJson || {
|
|
42
|
+
name: extensionName,
|
|
43
|
+
title: extensionName,
|
|
44
|
+
description: '',
|
|
45
|
+
commands: [],
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Reset store to initial state then set extension fields, matching
|
|
49
|
+
// startDevMode/startCompiledExtension behavior to avoid stale navigation/dialog state
|
|
50
|
+
useStore.setState({
|
|
51
|
+
...useStore.getInitialState(),
|
|
52
|
+
extensionPath,
|
|
53
|
+
extensionPackageJson: packageJson,
|
|
54
|
+
})
|
|
15
55
|
|
|
16
|
-
export async function renderWithProviders(element: ReactNode): Promise<void> {
|
|
17
56
|
const renderer = await createCliRenderer({
|
|
18
57
|
onDestroy: () => {
|
|
19
58
|
process.exit(0)
|