Skip to content

Commit 6364394

Browse files
committed
feat: add useWebviewPanel composable
1 parent cac9954 commit 6364394

File tree

4 files changed

+210
-134
lines changed

4 files changed

+210
-134
lines changed

docs/guide/view.md

+2
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,5 @@ Here is an example of a webview:
7777
<<< @/snippets/webviewView.ts
7878

7979
The time to call `useDemoWebviewView` is the same as the tree view in the previous section.
80+
81+
There is also `reactive::useWebviewPanel` composable to create a webview panel. The usage is similar to `reactive::useWebviewView`.
+55-54
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,55 @@
1-
export * from './useAbsolutePath'
2-
export * from './useActiveColorTheme'
3-
export * from './useActiveDebugSession'
4-
export * from './useActiveEditorDecorations'
5-
export * from './useActiveNotebookEditor'
6-
export * from './useActiveTerminal'
7-
export * from './useActiveTextEditor'
8-
export * from './useAllExtensions'
9-
export * from './useCommand'
10-
export * from './useCommands'
11-
export * from './useCommentController'
12-
export * from './useControlledTerminal'
13-
export * from './useDefaultShell'
14-
export * from './useDisposable'
15-
export * from './useDocumentText'
16-
export * from './useEditorDecorations'
17-
export * from './useEvent'
18-
export * from './useEventEmitter'
19-
export * from './useExtensionSecret'
20-
export * from './useFetchTasks'
21-
export * from './useFileUri'
22-
export * from './useFoldingRangeProvider'
23-
export * from './useFsWatcher'
24-
export * from './useIsDarkTheme'
25-
export * from './useIsTelemetryEnabled'
26-
export * from './useL10nText'
27-
export * from './useLogger'
28-
export * from './useLogLevel'
29-
export * from './useNotebookEditorSelection'
30-
export * from './useNotebookEditorSelections'
31-
export * from './useNotebookEditorVisibleRanges'
32-
export * from './useOpenedTerminals'
33-
export * from './useOutputChannel'
34-
export * from './useQuickPick'
35-
export * from './useStatusBarItem'
36-
export * from './useTaskExecutions'
37-
export * from './useTerminal'
38-
export * from './useTerminalState'
39-
export * from './useTextEditorCommand'
40-
export * from './useTextEditorCommands'
41-
export * from './useTextEditorSelection'
42-
export * from './useTextEditorSelections'
43-
export * from './useTextEditorViewColumn'
44-
export * from './useTextEditorVisibleRanges'
45-
export * from './useTreeView'
46-
export * from './useViewBadge'
47-
export * from './useViewTitle'
48-
export * from './useViewVisibility'
49-
export * from './useVisibleNotebookEditors'
50-
export * from './useVisibleTextEditors'
51-
export * from './useVscodeContext'
52-
export * from './useWebviewView'
53-
export * from './useWindowState'
54-
export * from './useWorkspaceFolders'
1+
export * from './useAbsolutePath'
2+
export * from './useActiveColorTheme'
3+
export * from './useActiveDebugSession'
4+
export * from './useActiveEditorDecorations'
5+
export * from './useActiveNotebookEditor'
6+
export * from './useActiveTerminal'
7+
export * from './useActiveTextEditor'
8+
export * from './useAllExtensions'
9+
export * from './useCommand'
10+
export * from './useCommands'
11+
export * from './useCommentController'
12+
export * from './useControlledTerminal'
13+
export * from './useDefaultShell'
14+
export * from './useDisposable'
15+
export * from './useDocumentText'
16+
export * from './useEditorDecorations'
17+
export * from './useEvent'
18+
export * from './useEventEmitter'
19+
export * from './useExtensionSecret'
20+
export * from './useFetchTasks'
21+
export * from './useFileUri'
22+
export * from './useFoldingRangeProvider'
23+
export * from './useFsWatcher'
24+
export * from './useIsDarkTheme'
25+
export * from './useIsTelemetryEnabled'
26+
export * from './useL10nText'
27+
export * from './useLogger'
28+
export * from './useLogLevel'
29+
export * from './useNotebookEditorSelection'
30+
export * from './useNotebookEditorSelections'
31+
export * from './useNotebookEditorVisibleRanges'
32+
export * from './useOpenedTerminals'
33+
export * from './useOutputChannel'
34+
export * from './useQuickPick'
35+
export * from './useStatusBarItem'
36+
export * from './useTaskExecutions'
37+
export * from './useTerminal'
38+
export * from './useTerminalState'
39+
export * from './useTextEditorCommand'
40+
export * from './useTextEditorCommands'
41+
export * from './useTextEditorSelection'
42+
export * from './useTextEditorSelections'
43+
export * from './useTextEditorViewColumn'
44+
export * from './useTextEditorVisibleRanges'
45+
export * from './useTreeView'
46+
export * from './useViewBadge'
47+
export * from './useViewTitle'
48+
export * from './useViewVisibility'
49+
export * from './useVisibleNotebookEditors'
50+
export * from './useVisibleTextEditors'
51+
export * from './useVscodeContext'
52+
export * from './useWebviewPanel'
53+
export * from './useWebviewView'
54+
export * from './useWindowState'
55+
export * from './useWorkspaceFolders'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { MaybeRefOrGetter } from '@reactive-vscode/reactivity'
2+
import { ref, shallowRef, toValue, watchEffect } from '@reactive-vscode/reactivity'
3+
import type { WebviewOptions } from 'vscode'
4+
import { window } from 'vscode'
5+
import { useDisposable } from './useDisposable'
6+
import { useViewTitle } from './useViewTitle'
7+
8+
export interface WebviewPanelRegisterOptions {
9+
enableFindWidget?: boolean
10+
retainContextWhenHidden?: boolean
11+
onDidReceiveMessage?: (message: any) => void
12+
webviewOptions?: MaybeRefOrGetter<WebviewOptions>
13+
}
14+
15+
/**
16+
* Register a webview panel. See `vscode::window.createWebviewPanel`.
17+
*
18+
* @category view
19+
*/
20+
export function useWebviewPanel(
21+
viewType: string,
22+
title: MaybeRefOrGetter<string>,
23+
html: MaybeRefOrGetter<string>,
24+
showOptions: Parameters<typeof window.createWebviewPanel>[2],
25+
options?: WebviewPanelRegisterOptions,
26+
) {
27+
const context = shallowRef<unknown>()
28+
const panel = useDisposable(window.createWebviewPanel(
29+
viewType,
30+
toValue(title),
31+
showOptions,
32+
{
33+
enableFindWidget: options?.enableFindWidget,
34+
retainContextWhenHidden: options?.retainContextWhenHidden,
35+
...toValue(options?.webviewOptions),
36+
},
37+
))
38+
39+
if (options?.onDidReceiveMessage)
40+
panel.webview.onDidReceiveMessage(options.onDidReceiveMessage)
41+
42+
const forceRefreshId = ref(0)
43+
44+
function forceRefresh() {
45+
forceRefreshId.value++
46+
}
47+
48+
watchEffect(() => {
49+
panel.webview.html = `${toValue(html)}<!--${forceRefreshId.value}-->`
50+
})
51+
52+
if (options?.webviewOptions) {
53+
const webviewOptions = options.webviewOptions
54+
watchEffect(() => {
55+
panel.webview.options = toValue(webviewOptions)
56+
})
57+
}
58+
59+
useViewTitle(panel, title)
60+
61+
function postMessage(message: any) {
62+
return panel.webview.postMessage(message)
63+
}
64+
65+
const active = ref(panel.active)
66+
const visible = ref(panel.visible)
67+
useDisposable(panel.onDidChangeViewState(() => {
68+
active.value = panel.active
69+
visible.value = panel.visible
70+
}))
71+
72+
return { panel, context, active, visible, postMessage, forceRefresh }
73+
}
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,80 @@
1-
import type { MaybeRefOrGetter } from '@reactive-vscode/reactivity'
2-
import { ref, shallowRef, toValue, watchEffect } from '@reactive-vscode/reactivity'
3-
import type { ViewBadge, WebviewOptions, WebviewView } from 'vscode'
4-
import { window } from 'vscode'
5-
import { createKeyedComposable } from '../utils'
6-
import { useDisposable } from './useDisposable'
7-
import { useViewBadge } from './useViewBadge'
8-
import { useViewTitle } from './useViewTitle'
9-
10-
interface WebviewRegisterOptions {
11-
retainContextWhenHidden?: boolean
12-
onDidReceiveMessage?: (message: any) => void
13-
webviewOptions?: MaybeRefOrGetter<WebviewOptions>
14-
title?: MaybeRefOrGetter<string | undefined>
15-
badge?: MaybeRefOrGetter<ViewBadge | undefined>
16-
}
17-
18-
/**
19-
* Register a webview view. See `vscode::window.registerWebviewViewProvider`.
20-
*
21-
* @category view
22-
*/
23-
export const useWebviewView = createKeyedComposable(
24-
(
25-
viewId: string,
26-
html: MaybeRefOrGetter<string>,
27-
options?: WebviewRegisterOptions,
28-
) => {
29-
const view = shallowRef<WebviewView>()
30-
const context = shallowRef<unknown>()
31-
useDisposable(window.registerWebviewViewProvider(
32-
viewId,
33-
{
34-
resolveWebviewView(viewArg, contextArg) {
35-
view.value = viewArg
36-
context.value = contextArg
37-
if (options?.onDidReceiveMessage)
38-
viewArg.webview.onDidReceiveMessage(options.onDidReceiveMessage)
39-
},
40-
},
41-
{
42-
webviewOptions: {
43-
retainContextWhenHidden: options?.retainContextWhenHidden,
44-
},
45-
},
46-
))
47-
48-
const forceRefreshId = ref(0)
49-
50-
function forceRefresh() {
51-
forceRefreshId.value++
52-
}
53-
54-
watchEffect(() => {
55-
if (view.value)
56-
view.value.webview.html = `${toValue(html)}<!--${forceRefreshId.value}-->`
57-
})
58-
59-
if (options?.webviewOptions) {
60-
const webviewOptions = options.webviewOptions
61-
watchEffect(() => {
62-
if (view.value)
63-
view.value.webview.options = toValue(webviewOptions)
64-
})
65-
}
66-
67-
if (options?.title)
68-
useViewTitle(view, options.title)
69-
70-
if (options?.badge)
71-
useViewBadge(view, options.badge)
72-
73-
function postMessage(message: any) {
74-
return view.value?.webview.postMessage(message)
75-
}
76-
77-
return { view, context, postMessage, forceRefresh }
78-
},
79-
viewId => viewId,
80-
)
1+
import type { MaybeRefOrGetter } from '@reactive-vscode/reactivity'
2+
import { ref, shallowRef, toValue, watchEffect } from '@reactive-vscode/reactivity'
3+
import type { ViewBadge, WebviewOptions, WebviewView, WebviewViewResolveContext } from 'vscode'
4+
import { window } from 'vscode'
5+
import { createKeyedComposable } from '../utils'
6+
import { useDisposable } from './useDisposable'
7+
import { useViewBadge } from './useViewBadge'
8+
import { useViewTitle } from './useViewTitle'
9+
10+
export interface WebviewViewRegisterOptions {
11+
retainContextWhenHidden?: boolean
12+
onDidReceiveMessage?: (message: any) => void
13+
webviewOptions?: MaybeRefOrGetter<WebviewOptions>
14+
title?: MaybeRefOrGetter<string | undefined>
15+
badge?: MaybeRefOrGetter<ViewBadge | undefined>
16+
}
17+
18+
/**
19+
* Register a webview view. See `vscode::window.registerWebviewViewProvider`.
20+
*
21+
* @category view
22+
*/
23+
export const useWebviewView = createKeyedComposable(
24+
(
25+
viewId: string,
26+
html: MaybeRefOrGetter<string>,
27+
options?: WebviewViewRegisterOptions,
28+
) => {
29+
const view = shallowRef<WebviewView>()
30+
const context = shallowRef<WebviewViewResolveContext>()
31+
useDisposable(window.registerWebviewViewProvider(
32+
viewId,
33+
{
34+
resolveWebviewView(viewArg, contextArg) {
35+
view.value = viewArg
36+
context.value = contextArg
37+
if (options?.onDidReceiveMessage)
38+
viewArg.webview.onDidReceiveMessage(options.onDidReceiveMessage)
39+
},
40+
},
41+
{
42+
webviewOptions: {
43+
retainContextWhenHidden: options?.retainContextWhenHidden,
44+
},
45+
},
46+
))
47+
48+
const forceRefreshId = ref(0)
49+
50+
function forceRefresh() {
51+
forceRefreshId.value++
52+
}
53+
54+
watchEffect(() => {
55+
if (view.value)
56+
view.value.webview.html = `${toValue(html)}<!--${forceRefreshId.value}-->`
57+
})
58+
59+
if (options?.webviewOptions) {
60+
const webviewOptions = options.webviewOptions
61+
watchEffect(() => {
62+
if (view.value)
63+
view.value.webview.options = toValue(webviewOptions)
64+
})
65+
}
66+
67+
if (options?.title)
68+
useViewTitle(view, options.title)
69+
70+
if (options?.badge)
71+
useViewBadge(view, options.badge)
72+
73+
function postMessage(message: any) {
74+
return view.value?.webview.postMessage(message)
75+
}
76+
77+
return { view, context, postMessage, forceRefresh }
78+
},
79+
viewId => viewId,
80+
)

0 commit comments

Comments
 (0)