Skip to content

Commit f875fb9

Browse files
committed
feat: add useQuickPick
1 parent 8236a24 commit f875fb9

File tree

2 files changed

+163
-1
lines changed

2 files changed

+163
-1
lines changed

packages/core/src/composables/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ export * from './useFsWatcher'
2323
export * from './useIsDarkTheme'
2424
export * from './useIsTelemetryEnabled'
2525
export * from './useL10nText'
26-
export * from './useLogLevel'
2726
export * from './useLogger'
27+
export * from './useLogLevel'
2828
export * from './useNotebookEditorSelection'
2929
export * from './useNotebookEditorSelections'
3030
export * from './useNotebookEditorVisibleRanges'
3131
export * from './useOpenedTerminals'
3232
export * from './useOutputChannel'
33+
export * from './useQuickPick'
3334
export * from './useStatusBarItem'
3435
export * from './useTaskExecutions'
3536
export * from './useTerminal'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import type { QuickInputButton, QuickPickItem } from 'vscode'
2+
import { window } from 'vscode'
3+
import type { MaybeRefOrGetter } from '@reactive-vscode/reactivity'
4+
import { shallowRef, toValue, watchEffect } from '@reactive-vscode/reactivity'
5+
import { useDisposable } from './useDisposable'
6+
import { useEvent } from './useEvent'
7+
8+
export interface QuickPickOptions<T extends QuickPickItem> {
9+
/**
10+
* Items to pick from. This can be read and updated by the extension.
11+
*/
12+
items?: MaybeRefOrGetter<readonly T[]>
13+
14+
/**
15+
* Buttons for actions in the UI.
16+
*/
17+
buttons?: MaybeRefOrGetter<readonly QuickInputButton[]>
18+
19+
/**
20+
* An optional title.
21+
*/
22+
title?: MaybeRefOrGetter<string | undefined>
23+
24+
/**
25+
* An optional current step count.
26+
*/
27+
step?: MaybeRefOrGetter<number | undefined>
28+
29+
/**
30+
* An optional total step count.
31+
*/
32+
totalSteps?: MaybeRefOrGetter<number | undefined>
33+
34+
/**
35+
* If the UI should allow for user input. Defaults to true.
36+
*
37+
* Change this to false, e.g., while validating user input or
38+
* loading data for the next step in user input.
39+
*/
40+
enabled?: MaybeRefOrGetter<boolean>
41+
42+
/**
43+
* If the UI should show a progress indicator. Defaults to false.
44+
*
45+
* Change this to true, e.g., while loading more data or validating
46+
* user input.
47+
*/
48+
busy?: MaybeRefOrGetter<boolean>
49+
50+
/**
51+
* If the UI should stay open even when loosing UI focus. Defaults to false.
52+
* This setting is ignored on iPad and is always false.
53+
*/
54+
ignoreFocusOut?: MaybeRefOrGetter<boolean>
55+
56+
/**
57+
* Optional placeholder shown in the filter textbox when no filter has been entered.
58+
*/
59+
placeholder?: MaybeRefOrGetter<string | undefined>
60+
61+
/**
62+
* If multiple items can be selected at the same time. Defaults to false.
63+
*/
64+
canSelectMany?: MaybeRefOrGetter<boolean>
65+
66+
/**
67+
* If the filter text should also be matched against the description of the items. Defaults to false.
68+
*/
69+
matchOnDescription?: MaybeRefOrGetter<boolean>
70+
71+
/**
72+
* If the filter text should also be matched against the detail of the items. Defaults to false.
73+
*/
74+
matchOnDetail?: MaybeRefOrGetter<boolean>
75+
76+
/**
77+
* An optional flag to maintain the scroll position of the quick pick when the quick pick items are updated. Defaults to false.
78+
*/
79+
keepScrollPosition?: MaybeRefOrGetter<boolean>
80+
81+
/**
82+
* Initial value of the filter text.
83+
*/
84+
value?: string
85+
86+
/**
87+
* Initial active items. This can be read and updated by the extension.
88+
*/
89+
activeItems?: readonly T[]
90+
91+
/**
92+
* Initial selected items. This can be read and updated by the extension.
93+
*/
94+
selectedItems?: readonly T[]
95+
}
96+
97+
/**
98+
* Creates a customizable quick pick UI.
99+
*
100+
* @reactive `window.createQuickPick`
101+
*/
102+
export function useQuickPick<T extends QuickPickItem>(
103+
options: QuickPickOptions<T> = {},
104+
) {
105+
const quickPick = useDisposable(window.createQuickPick<T>())
106+
107+
const onDidChangeActive = useEvent(quickPick.onDidChangeActive)
108+
const onDidChangeSelection = useEvent(quickPick.onDidChangeSelection)
109+
const onDidAccept = useEvent(quickPick.onDidAccept)
110+
const onDidHide = useEvent(quickPick.onDidHide)
111+
const onDidTriggerButton = useEvent(quickPick.onDidTriggerButton)
112+
const onDidChangeValue = useEvent(quickPick.onDidChangeValue)
113+
114+
;([
115+
'items',
116+
'buttons',
117+
'title',
118+
'step',
119+
'totalSteps',
120+
'enabled',
121+
'busy',
122+
'ignoreFocusOut',
123+
'placeholder',
124+
'canSelectMany',
125+
'matchOnDescription',
126+
'matchOnDetail',
127+
'keepScrollPosition',
128+
] as const).forEach((key) => {
129+
if (options[key])
130+
// @ts-expect-error index signature
131+
watchEffect(() => quickPick[key] = toValue(options[key]))
132+
})
133+
134+
if (options.value)
135+
quickPick.value = options.value
136+
const value = shallowRef<string>(quickPick.value)
137+
onDidChangeValue(v => value.value = v)
138+
139+
if (options.activeItems)
140+
quickPick.activeItems = options.activeItems
141+
const activeItems = shallowRef<readonly T[]>(quickPick.activeItems)
142+
onDidChangeActive(items => activeItems.value = items)
143+
144+
if (options.selectedItems)
145+
quickPick.selectedItems = options.selectedItems
146+
const selectedItems = shallowRef<readonly T[]>(quickPick.selectedItems)
147+
onDidChangeSelection(items => selectedItems.value = items)
148+
149+
return {
150+
...quickPick,
151+
onDidChangeActive,
152+
onDidChangeSelection,
153+
onDidAccept,
154+
onDidHide,
155+
onDidTriggerButton,
156+
onDidChangeValue,
157+
value,
158+
activeItems,
159+
selectedItems,
160+
}
161+
}

0 commit comments

Comments
 (0)