termcast 1.3.21 → 1.3.22
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/compile.d.ts.map +1 -1
- package/dist/compile.js +2 -0
- package/dist/compile.js.map +1 -1
- package/dist/components/actions.d.ts.map +1 -1
- package/dist/components/actions.js +7 -1
- package/dist/components/actions.js.map +1 -1
- package/dist/components/detail.d.ts.map +1 -1
- package/dist/components/detail.js +2 -0
- package/dist/components/detail.js.map +1 -1
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +3 -1
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +11 -5
- package/dist/components/list.js.map +1 -1
- package/dist/examples/simple-navigation.js +10 -4
- package/dist/examples/simple-navigation.js.map +1 -1
- package/dist/internal/dialog.d.ts +1 -0
- package/dist/internal/dialog.d.ts.map +1 -1
- package/dist/internal/dialog.js +23 -14
- package/dist/internal/dialog.js.map +1 -1
- package/dist/internal/navigation.d.ts +9 -1
- package/dist/internal/navigation.d.ts.map +1 -1
- package/dist/internal/navigation.js +5 -5
- package/dist/internal/navigation.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +2 -2
- package/dist/internal/providers.js.map +1 -1
- package/dist/internal/scrollbox.d.ts.map +1 -1
- package/dist/internal/scrollbox.js +2 -1
- package/dist/internal/scrollbox.js.map +1 -1
- package/dist/state.d.ts +1 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +2 -0
- package/dist/state.js.map +1 -1
- package/package.json +2 -2
- package/src/compile.tsx +2 -0
- package/src/components/actions.tsx +8 -1
- package/src/components/detail.tsx +2 -0
- package/src/components/form/index.tsx +3 -1
- package/src/components/list.tsx +17 -9
- package/src/examples/file-autocomplete.vitest.tsx +7 -7
- package/src/examples/form-basic.vitest.tsx +222 -22
- package/src/examples/form-scroll.vitest.tsx +12 -12
- package/src/examples/internal/simple-scrollbox.vitest.tsx +7 -5
- package/src/examples/list-fetch-data.vitest.tsx +1 -1
- package/src/examples/list-scrollbox.vitest.tsx +59 -0
- package/src/examples/list-with-detail.vitest.tsx +15 -15
- package/src/examples/list-with-dropdown.vitest.tsx +14 -14
- package/src/examples/list-with-sections.vitest.tsx +2 -2
- package/src/examples/simple-grid.vitest.tsx +70 -70
- package/src/examples/simple-navigation.tsx +15 -7
- package/src/examples/simple-navigation.vitest.tsx +3 -3
- package/src/extensions/dev.vitest.tsx +22 -22
- package/src/internal/dialog.tsx +39 -26
- package/src/internal/navigation.tsx +3 -1
- package/src/internal/providers.tsx +4 -2
- package/src/internal/scrollbox.tsx +2 -0
- package/src/keyboard.test.tsx +69 -0
- package/src/state.tsx +4 -0
|
@@ -39,19 +39,19 @@ test('grid navigation and display', async () => {
|
|
|
39
39
|
Search items...
|
|
40
40
|
|
|
41
41
|
Fruits ▲
|
|
42
|
-
|
|
43
|
-
Banana
|
|
44
|
-
Cherry
|
|
42
|
+
›? Apple █
|
|
43
|
+
? Banana █
|
|
44
|
+
? Cherry
|
|
45
45
|
|
|
46
46
|
Animals
|
|
47
|
-
Dog
|
|
48
|
-
Cat
|
|
49
|
-
Rabbit
|
|
47
|
+
? Dog
|
|
48
|
+
? Cat
|
|
49
|
+
? Rabbit
|
|
50
50
|
|
|
51
51
|
Others
|
|
52
|
-
House
|
|
53
|
-
Car
|
|
54
|
-
Rocket
|
|
52
|
+
? House
|
|
53
|
+
? Car
|
|
54
|
+
? Rocket ▼
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
↵ select ↑↓ navigate ^k actions"
|
|
@@ -70,19 +70,19 @@ test('grid navigation and display', async () => {
|
|
|
70
70
|
Search items...
|
|
71
71
|
|
|
72
72
|
Fruits ▲
|
|
73
|
-
Apple
|
|
74
|
-
|
|
75
|
-
Cherry
|
|
73
|
+
? Apple █
|
|
74
|
+
›? Banana █
|
|
75
|
+
? Cherry
|
|
76
76
|
|
|
77
77
|
Animals
|
|
78
|
-
Dog
|
|
79
|
-
Cat
|
|
80
|
-
Rabbit
|
|
78
|
+
? Dog
|
|
79
|
+
? Cat
|
|
80
|
+
? Rabbit
|
|
81
81
|
|
|
82
82
|
Others
|
|
83
|
-
House
|
|
84
|
-
Car
|
|
85
|
-
Rocket
|
|
83
|
+
? House
|
|
84
|
+
? Car
|
|
85
|
+
? Rocket ▼
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
↵ select ↑↓ navigate ^k actions"
|
|
@@ -102,19 +102,19 @@ test('grid navigation and display', async () => {
|
|
|
102
102
|
Search items...
|
|
103
103
|
|
|
104
104
|
Fruits ▲
|
|
105
|
-
Apple
|
|
106
|
-
Banana
|
|
107
|
-
Cherry
|
|
105
|
+
? Apple █
|
|
106
|
+
? Banana █
|
|
107
|
+
? Cherry
|
|
108
108
|
|
|
109
109
|
Animals
|
|
110
|
-
|
|
111
|
-
Cat
|
|
112
|
-
Rabbit
|
|
110
|
+
›? Dog
|
|
111
|
+
? Cat
|
|
112
|
+
? Rabbit
|
|
113
113
|
|
|
114
114
|
Others
|
|
115
|
-
House
|
|
116
|
-
Car
|
|
117
|
-
Rocket
|
|
115
|
+
? House
|
|
116
|
+
? Car
|
|
117
|
+
? Rocket ▼
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
↵ select ↑↓ navigate ^k actions"
|
|
@@ -166,19 +166,19 @@ test('grid navigation and display', async () => {
|
|
|
166
166
|
Search items...
|
|
167
167
|
|
|
168
168
|
Fruits ▲
|
|
169
|
-
Apple
|
|
170
|
-
Banana
|
|
171
|
-
Cherry
|
|
169
|
+
? Apple █
|
|
170
|
+
? Banana █
|
|
171
|
+
? Cherry
|
|
172
172
|
|
|
173
173
|
Animals
|
|
174
|
-
|
|
175
|
-
Cat
|
|
176
|
-
Rabbit
|
|
174
|
+
›? Dog
|
|
175
|
+
? Cat
|
|
176
|
+
? Rabbit
|
|
177
177
|
|
|
178
178
|
Others
|
|
179
|
-
House
|
|
180
|
-
Car
|
|
181
|
-
Rocket
|
|
179
|
+
? House
|
|
180
|
+
? Car
|
|
181
|
+
? Rocket ▼
|
|
182
182
|
|
|
183
183
|
|
|
184
184
|
↵ select ↑↓ navigate ^k actions"
|
|
@@ -209,8 +209,8 @@ test('grid search functionality', async () => {
|
|
|
209
209
|
|
|
210
210
|
cat
|
|
211
211
|
|
|
212
|
+
? Cat
|
|
212
213
|
|
|
213
|
-
Cat
|
|
214
214
|
|
|
215
215
|
|
|
216
216
|
|
|
@@ -247,12 +247,12 @@ test('grid search functionality', async () => {
|
|
|
247
247
|
|
|
248
248
|
space
|
|
249
249
|
|
|
250
|
+
? Rocket
|
|
251
|
+
? Star
|
|
252
|
+
? Moon
|
|
253
|
+
? Sun
|
|
250
254
|
|
|
251
255
|
|
|
252
|
-
Rocket
|
|
253
|
-
Star
|
|
254
|
-
Moon
|
|
255
|
-
Sun
|
|
256
256
|
|
|
257
257
|
|
|
258
258
|
|
|
@@ -283,19 +283,19 @@ test('grid search functionality', async () => {
|
|
|
283
283
|
Search items...
|
|
284
284
|
|
|
285
285
|
Fruits ▲
|
|
286
|
-
|
|
287
|
-
Banana
|
|
288
|
-
Cherry
|
|
286
|
+
›? Apple █
|
|
287
|
+
? Banana █
|
|
288
|
+
? Cherry
|
|
289
289
|
|
|
290
290
|
Animals
|
|
291
|
-
Dog
|
|
292
|
-
Cat
|
|
293
|
-
Rabbit
|
|
291
|
+
? Dog
|
|
292
|
+
? Cat
|
|
293
|
+
? Rabbit
|
|
294
294
|
|
|
295
295
|
Others
|
|
296
|
-
House
|
|
297
|
-
Car
|
|
298
|
-
Rocket
|
|
296
|
+
? House
|
|
297
|
+
? Car
|
|
298
|
+
? Rocket ▼
|
|
299
299
|
|
|
300
300
|
|
|
301
301
|
↵ select ↑↓ navigate ^k actions"
|
|
@@ -424,19 +424,19 @@ test('grid item selection and actions', async () => {
|
|
|
424
424
|
Search items...
|
|
425
425
|
|
|
426
426
|
Fruits ▲
|
|
427
|
-
|
|
428
|
-
Banana
|
|
429
|
-
Cherry
|
|
427
|
+
›? Apple █
|
|
428
|
+
? Banana █
|
|
429
|
+
? Cherry
|
|
430
430
|
|
|
431
431
|
Animals
|
|
432
|
-
Dog
|
|
433
|
-
Cat
|
|
434
|
-
Rabbit
|
|
432
|
+
? Dog
|
|
433
|
+
? Cat
|
|
434
|
+
? Rabbit
|
|
435
435
|
|
|
436
436
|
Others
|
|
437
|
-
House
|
|
438
|
-
Car
|
|
439
|
-
Rocket
|
|
437
|
+
? House
|
|
438
|
+
? Car
|
|
439
|
+
? Rocket ▼
|
|
440
440
|
|
|
441
441
|
|
|
442
442
|
↵ select ↑↓ navigate ^k actions"
|
|
@@ -464,19 +464,19 @@ test('grid mouse interaction', async () => {
|
|
|
464
464
|
Search items...
|
|
465
465
|
|
|
466
466
|
Fruits ▲
|
|
467
|
-
Apple
|
|
468
|
-
Banana
|
|
469
|
-
Cherry
|
|
467
|
+
? Apple █
|
|
468
|
+
? Banana █
|
|
469
|
+
? Cherry
|
|
470
470
|
|
|
471
471
|
Animals
|
|
472
|
-
|
|
473
|
-
Cat
|
|
474
|
-
Rabbit
|
|
472
|
+
›? Dog
|
|
473
|
+
? Cat
|
|
474
|
+
? Rabbit
|
|
475
475
|
|
|
476
476
|
Others
|
|
477
|
-
House
|
|
478
|
-
Car
|
|
479
|
-
Rocket
|
|
477
|
+
? House
|
|
478
|
+
? Car
|
|
479
|
+
? Rocket ▼
|
|
480
480
|
|
|
481
481
|
|
|
482
482
|
↵ select ↑↓ navigate ^k actions"
|
|
@@ -503,7 +503,7 @@ test('grid mouse interaction', async () => {
|
|
|
503
503
|
|
|
504
504
|
Search items...
|
|
505
505
|
|
|
506
|
-
Apple
|
|
506
|
+
? Apple ▲
|
|
507
507
|
┃ ┃
|
|
508
508
|
┃ esc ┃
|
|
509
509
|
┃ ┃
|
|
@@ -536,7 +536,7 @@ test('grid mouse interaction', async () => {
|
|
|
536
536
|
|
|
537
537
|
Search items...
|
|
538
538
|
|
|
539
|
-
Apple
|
|
539
|
+
? Apple ▲
|
|
540
540
|
┃ ┃
|
|
541
541
|
┃ esc ┃
|
|
542
542
|
┃ ┃
|
|
@@ -6,9 +6,12 @@ import { Action, ActionPanel } from 'termcast'
|
|
|
6
6
|
import { useNavigation } from 'termcast/src/internal/navigation'
|
|
7
7
|
import { TermcastProvider } from 'termcast/src/internal/providers'
|
|
8
8
|
|
|
9
|
-
function
|
|
9
|
+
function GoBackAction(): any {
|
|
10
10
|
const { pop } = useNavigation()
|
|
11
|
+
return <Action title='Go Back' onAction={() => pop()} />
|
|
12
|
+
}
|
|
11
13
|
|
|
14
|
+
function DetailView({ title }: { title: string }): any {
|
|
12
15
|
return (
|
|
13
16
|
<List
|
|
14
17
|
searchBarPlaceholder='Detail view - Press ESC to go back'
|
|
@@ -21,7 +24,7 @@ function DetailView({ title }: { title: string }): any {
|
|
|
21
24
|
subtitle='Press Enter to go back or ESC to navigate back'
|
|
22
25
|
actions={
|
|
23
26
|
<ActionPanel>
|
|
24
|
-
<
|
|
27
|
+
<GoBackAction />
|
|
25
28
|
<Action.CopyToClipboard content={title} title='Copy Title' />
|
|
26
29
|
</ActionPanel>
|
|
27
30
|
}
|
|
@@ -31,9 +34,17 @@ function DetailView({ title }: { title: string }): any {
|
|
|
31
34
|
)
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
function
|
|
37
|
+
function OpenDetailsAction({ title }: { title: string }): any {
|
|
35
38
|
const { push } = useNavigation()
|
|
39
|
+
return (
|
|
40
|
+
<Action
|
|
41
|
+
title='Open Details'
|
|
42
|
+
onAction={() => push(<DetailView title={title} />)}
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
36
46
|
|
|
47
|
+
function MainView(): any {
|
|
37
48
|
const items = [
|
|
38
49
|
{
|
|
39
50
|
id: 'first',
|
|
@@ -62,10 +73,7 @@ function MainView(): any {
|
|
|
62
73
|
subtitle={item.subtitle}
|
|
63
74
|
actions={
|
|
64
75
|
<ActionPanel>
|
|
65
|
-
<
|
|
66
|
-
title='Open Details'
|
|
67
|
-
onAction={() => push(<DetailView title={item.title} />)}
|
|
68
|
-
/>
|
|
76
|
+
<OpenDetailsAction title={item.title} />
|
|
69
77
|
<Action.CopyToClipboard
|
|
70
78
|
content={item.title}
|
|
71
79
|
title='Copy Title'
|
|
@@ -535,9 +535,9 @@ test('navigation with actions panel', async () => {
|
|
|
535
535
|
┃ ┃
|
|
536
536
|
┃ ┃
|
|
537
537
|
┃ ┃
|
|
538
|
-
┃
|
|
539
|
-
┃ ↵ select
|
|
540
|
-
┃
|
|
538
|
+
┃ ┌────────────────────────────────────┐ ┃
|
|
539
|
+
┃ ↵ select │↓✓nCopiedeto Clipboard - First Item │ ┃
|
|
540
|
+
┃ └────────────────────────────────────┘ ┃"
|
|
541
541
|
`)
|
|
542
542
|
|
|
543
543
|
// Select Go Back action
|
|
@@ -93,19 +93,19 @@ test('selecting command with arguments shows arguments form', async () => {
|
|
|
93
93
|
"
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
│
|
|
99
|
-
◆ Search query
|
|
100
|
-
┃ Search query
|
|
96
|
+
■ With Arguments █
|
|
97
|
+
┃ Enter the arguments to run this command. ▀
|
|
101
98
|
┃
|
|
99
|
+
◇ Search query
|
|
100
|
+
│ Search query
|
|
101
|
+
│
|
|
102
102
|
◇ Secret key
|
|
103
103
|
│ Secret key
|
|
104
104
|
◇ Category
|
|
105
105
|
│ Category
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
ctrl ↵ submit ↑↓ navigate ^k actions"
|
|
109
109
|
`)
|
|
110
110
|
}, 30000)
|
|
111
111
|
|
|
@@ -137,19 +137,19 @@ test('can fill arguments and run command', async () => {
|
|
|
137
137
|
"
|
|
138
138
|
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
│
|
|
143
|
-
◆ Search query
|
|
144
|
-
┃ my search term
|
|
140
|
+
■ With Arguments █
|
|
141
|
+
┃ Enter the arguments to run this command. ▀
|
|
145
142
|
┃
|
|
143
|
+
◇ Search query
|
|
144
|
+
│ Search query
|
|
145
|
+
│
|
|
146
146
|
◇ Secret key
|
|
147
147
|
│ Secret key
|
|
148
148
|
◇ Category
|
|
149
149
|
│ Category
|
|
150
150
|
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
ctrl ↵ submit ↑↓ navigate ^k actions"
|
|
153
153
|
`)
|
|
154
154
|
|
|
155
155
|
// Submit the form with Alt+Enter (opens action panel), then Enter (selects submit)
|
|
@@ -171,15 +171,15 @@ test('can fill arguments and run command', async () => {
|
|
|
171
171
|
Search...
|
|
172
172
|
|
|
173
173
|
Received Arguments
|
|
174
|
-
|
|
175
|
-
Secret Key (empty)
|
|
176
|
-
Category (empty)
|
|
174
|
+
›♣ Search Query (empty)
|
|
175
|
+
♣ Secret Key (empty)
|
|
176
|
+
♣ Category (empty)
|
|
177
177
|
|
|
178
178
|
|
|
179
179
|
|
|
180
|
-
↵
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
↵ select ┌─────────────────────────────────┐
|
|
181
|
+
│ ✓ Copied to Clipboard - (empty) │
|
|
182
|
+
└─────────────────────────────────┘"
|
|
183
183
|
`)
|
|
184
184
|
}, 30000)
|
|
185
185
|
|
|
@@ -208,10 +208,10 @@ test('can run simple view command without arguments', async () => {
|
|
|
208
208
|
Search...
|
|
209
209
|
|
|
210
210
|
Items ▲
|
|
211
|
-
|
|
212
|
-
Second Item This is the second item
|
|
213
|
-
Third Item This is the third item
|
|
214
|
-
Fourth Item This is the fourth item
|
|
211
|
+
›♠ First Item This is the first item █
|
|
212
|
+
♠ Second Item This is the second item
|
|
213
|
+
♠ Third Item This is the third item
|
|
214
|
+
♠ Fourth Item This is the fourth item
|
|
215
215
|
▼
|
|
216
216
|
|
|
217
217
|
|
package/src/internal/dialog.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useKeyboard, useTerminalDimensions } from '@opentui/react'
|
|
2
|
-
import React, { type ReactNode, useRef } from 'react'
|
|
2
|
+
import React, { type ReactNode, useRef, useContext } from 'react'
|
|
3
3
|
import { Theme } from 'termcast/src/theme'
|
|
4
4
|
import { InFocus, useIsInFocus } from 'termcast/src/internal/focus-context'
|
|
5
5
|
import { CommonProps } from 'termcast/src/utils'
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from 'termcast/src/state'
|
|
11
11
|
import { logger } from '../logger'
|
|
12
12
|
import { ToastOverlay } from 'termcast/src/apis/toast'
|
|
13
|
+
import { NavigationContext } from 'termcast/src/internal/navigation'
|
|
13
14
|
|
|
14
15
|
const Border = {
|
|
15
16
|
topLeft: '',
|
|
@@ -145,31 +146,6 @@ export function DialogProvider(props: DialogProviderProps): any {
|
|
|
145
146
|
return (
|
|
146
147
|
<>
|
|
147
148
|
<InFocus inFocus={!dialogStack?.length}>{props.children}</InFocus>
|
|
148
|
-
{dialogStack.length > 0 && (
|
|
149
|
-
<box position='absolute'>
|
|
150
|
-
{dialogStack.map((item, index) => {
|
|
151
|
-
const isLastItem = index === dialogStack.length - 1
|
|
152
|
-
return (
|
|
153
|
-
<InFocus key={'dialog' + String(index)} inFocus={isLastItem}>
|
|
154
|
-
<Dialog
|
|
155
|
-
position={item.position}
|
|
156
|
-
onClickOutside={() => {
|
|
157
|
-
if (!isLastItem) return
|
|
158
|
-
const state = useStore.getState()
|
|
159
|
-
if (state.dialogStack.length > 0) {
|
|
160
|
-
useStore.setState({
|
|
161
|
-
dialogStack: state.dialogStack.slice(0, -1),
|
|
162
|
-
})
|
|
163
|
-
}
|
|
164
|
-
}}
|
|
165
|
-
>
|
|
166
|
-
{item.element}
|
|
167
|
-
</Dialog>
|
|
168
|
-
</InFocus>
|
|
169
|
-
)
|
|
170
|
-
})}
|
|
171
|
-
</box>
|
|
172
|
-
)}
|
|
173
149
|
<InFocus inFocus={false}>
|
|
174
150
|
<ToastOverlay />
|
|
175
151
|
</InFocus>
|
|
@@ -177,6 +153,43 @@ export function DialogProvider(props: DialogProviderProps): any {
|
|
|
177
153
|
)
|
|
178
154
|
}
|
|
179
155
|
|
|
156
|
+
export function DialogOverlay(): any {
|
|
157
|
+
const dialogStack = useStore((state) => state.dialogStack)
|
|
158
|
+
const navContext = useContext(NavigationContext)
|
|
159
|
+
|
|
160
|
+
if (dialogStack.length === 0) {
|
|
161
|
+
return null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<box position='absolute'>
|
|
166
|
+
{dialogStack.map((item, index) => {
|
|
167
|
+
const isLastItem = index === dialogStack.length - 1
|
|
168
|
+
return (
|
|
169
|
+
<InFocus key={'dialog' + String(index)} inFocus={isLastItem}>
|
|
170
|
+
<Dialog
|
|
171
|
+
position={item.position}
|
|
172
|
+
onClickOutside={() => {
|
|
173
|
+
if (!isLastItem) return
|
|
174
|
+
const state = useStore.getState()
|
|
175
|
+
if (state.dialogStack.length > 0) {
|
|
176
|
+
useStore.setState({
|
|
177
|
+
dialogStack: state.dialogStack.slice(0, -1),
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
}}
|
|
181
|
+
>
|
|
182
|
+
<NavigationContext.Provider value={navContext}>
|
|
183
|
+
{item.element}
|
|
184
|
+
</NavigationContext.Provider>
|
|
185
|
+
</Dialog>
|
|
186
|
+
</InFocus>
|
|
187
|
+
)
|
|
188
|
+
})}
|
|
189
|
+
</box>
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
180
193
|
export function useDialog() {
|
|
181
194
|
const dialogStack = useStore((state) => state.dialogStack)
|
|
182
195
|
|
|
@@ -26,12 +26,13 @@ interface NavigationContextType {
|
|
|
26
26
|
isPending: boolean
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const NavigationContext = createContext<NavigationContextType | undefined>(
|
|
29
|
+
export const NavigationContext = createContext<NavigationContextType | undefined>(
|
|
30
30
|
undefined,
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
interface NavigationProviderProps extends CommonProps {
|
|
34
34
|
children: ReactNode
|
|
35
|
+
overlay?: ReactNode
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
export function NavigationProvider(props: NavigationProviderProps): any {
|
|
@@ -139,6 +140,7 @@ export function NavigationProvider(props: NavigationProviderProps): any {
|
|
|
139
140
|
{React.cloneElement(currentItem?.element as React.ReactElement, {
|
|
140
141
|
key: stack.length,
|
|
141
142
|
})}
|
|
143
|
+
{props.overlay}
|
|
142
144
|
</NavigationContext.Provider>
|
|
143
145
|
)
|
|
144
146
|
}
|
|
@@ -6,7 +6,7 @@ import React, {
|
|
|
6
6
|
} from 'react'
|
|
7
7
|
import { QueryClient } from '@tanstack/react-query'
|
|
8
8
|
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'
|
|
9
|
-
import { DialogProvider } from 'termcast/src/internal/dialog'
|
|
9
|
+
import { DialogProvider, DialogOverlay } from 'termcast/src/internal/dialog'
|
|
10
10
|
import { NavigationProvider } from 'termcast/src/internal/navigation'
|
|
11
11
|
import { CommonProps } from 'termcast/src/utils'
|
|
12
12
|
import { Cache } from 'termcast/src/apis/cache'
|
|
@@ -420,7 +420,9 @@ export function TermcastProvider(props: ProvidersProps): any {
|
|
|
420
420
|
<DialogProvider>
|
|
421
421
|
<box padding={2}>
|
|
422
422
|
{/* NavigationProvider must be last to ensure parent providers remain in the tree when navigation changes */}
|
|
423
|
-
<NavigationProvider
|
|
423
|
+
<NavigationProvider overlay={<DialogOverlay />}>
|
|
424
|
+
{props.children}
|
|
425
|
+
</NavigationProvider>
|
|
424
426
|
</box>
|
|
425
427
|
</DialogProvider>
|
|
426
428
|
</PersistQueryClientProvider>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import Theme from '../theme'
|
|
3
|
+
import { MacOSScrollAccel } from '@opentui/core'
|
|
3
4
|
|
|
4
5
|
interface ScrollBoxProps {
|
|
5
6
|
children?: React.ReactNode
|
|
@@ -23,6 +24,7 @@ export function ScrollBox({
|
|
|
23
24
|
<scrollbox
|
|
24
25
|
ref={ref}
|
|
25
26
|
focused={focused}
|
|
27
|
+
scrollAcceleration={new MacOSScrollAccel()}
|
|
26
28
|
flexGrow={flexGrow}
|
|
27
29
|
flexShrink={flexShrink}
|
|
28
30
|
style={{
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test'
|
|
2
|
+
import { Keyboard } from 'termcast/src/keyboard'
|
|
3
|
+
import type {
|
|
4
|
+
KeyboardKeyEquivalent,
|
|
5
|
+
KeyboardKeyModifier,
|
|
6
|
+
KeyboardShortcut,
|
|
7
|
+
} from 'termcast/src/keyboard'
|
|
8
|
+
|
|
9
|
+
describe('Keyboard', () => {
|
|
10
|
+
test('Keyboard.Shortcut.Common has all expected shortcuts', () => {
|
|
11
|
+
const commonShortcuts = Object.keys(Keyboard.Shortcut.Common)
|
|
12
|
+
expect(commonShortcuts).toMatchInlineSnapshot(`
|
|
13
|
+
[
|
|
14
|
+
"Copy",
|
|
15
|
+
"CopyDeeplink",
|
|
16
|
+
"CopyName",
|
|
17
|
+
"CopyPath",
|
|
18
|
+
"Save",
|
|
19
|
+
"Duplicate",
|
|
20
|
+
"Edit",
|
|
21
|
+
"MoveDown",
|
|
22
|
+
"MoveUp",
|
|
23
|
+
"New",
|
|
24
|
+
"Open",
|
|
25
|
+
"OpenWith",
|
|
26
|
+
"Pin",
|
|
27
|
+
"Refresh",
|
|
28
|
+
"Remove",
|
|
29
|
+
"RemoveAll",
|
|
30
|
+
"ToggleQuickLook",
|
|
31
|
+
]
|
|
32
|
+
`)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('Keyboard.Shortcut.Common.Open has correct structure', () => {
|
|
36
|
+
expect(Keyboard.Shortcut.Common.Open).toMatchInlineSnapshot(`
|
|
37
|
+
{
|
|
38
|
+
"key": "o",
|
|
39
|
+
"modifiers": [
|
|
40
|
+
"cmd",
|
|
41
|
+
],
|
|
42
|
+
}
|
|
43
|
+
`)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('Keyboard.Shortcut.Common.Copy has correct structure', () => {
|
|
47
|
+
expect(Keyboard.Shortcut.Common.Copy).toMatchInlineSnapshot(`
|
|
48
|
+
{
|
|
49
|
+
"key": "c",
|
|
50
|
+
"modifiers": [
|
|
51
|
+
"cmd",
|
|
52
|
+
"shift",
|
|
53
|
+
],
|
|
54
|
+
}
|
|
55
|
+
`)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('Keyboard.Shortcut.Common.Remove uses ctrl modifier', () => {
|
|
59
|
+
expect(Keyboard.Shortcut.Common.Remove).toMatchInlineSnapshot(`
|
|
60
|
+
{
|
|
61
|
+
"key": "x",
|
|
62
|
+
"modifiers": [
|
|
63
|
+
"ctrl",
|
|
64
|
+
],
|
|
65
|
+
}
|
|
66
|
+
`)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
})
|
package/src/state.tsx
CHANGED
|
@@ -30,6 +30,8 @@ interface AppState {
|
|
|
30
30
|
// OAuth state
|
|
31
31
|
googleAccessToken?: string
|
|
32
32
|
googleIdToken?: string
|
|
33
|
+
// Actions overlay state
|
|
34
|
+
forceShowActionsOverlay: boolean
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export const useStore = create<AppState>(() => ({
|
|
@@ -48,4 +50,6 @@ export const useStore = create<AppState>(() => ({
|
|
|
48
50
|
// OAuth state
|
|
49
51
|
googleAccessToken: undefined,
|
|
50
52
|
googleIdToken: undefined,
|
|
53
|
+
// Actions overlay state
|
|
54
|
+
forceShowActionsOverlay: false,
|
|
51
55
|
}))
|