Skip to content

Commit

Permalink
feat: add useWebviewPanel composable
Browse files Browse the repository at this point in the history
  • Loading branch information
KermanX committed Sep 17, 2024
1 parent cac9954 commit 6364394
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 134 deletions.
2 changes: 2 additions & 0 deletions docs/guide/view.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,5 @@ Here is an example of a webview:
<<< @/snippets/webviewView.ts

The time to call `useDemoWebviewView` is the same as the tree view in the previous section.

There is also `reactive::useWebviewPanel` composable to create a webview panel. The usage is similar to `reactive::useWebviewView`.
109 changes: 55 additions & 54 deletions packages/core/src/composables/index.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,55 @@
export * from './useAbsolutePath'
export * from './useActiveColorTheme'
export * from './useActiveDebugSession'
export * from './useActiveEditorDecorations'
export * from './useActiveNotebookEditor'
export * from './useActiveTerminal'
export * from './useActiveTextEditor'
export * from './useAllExtensions'
export * from './useCommand'
export * from './useCommands'
export * from './useCommentController'
export * from './useControlledTerminal'
export * from './useDefaultShell'
export * from './useDisposable'
export * from './useDocumentText'
export * from './useEditorDecorations'
export * from './useEvent'
export * from './useEventEmitter'
export * from './useExtensionSecret'
export * from './useFetchTasks'
export * from './useFileUri'
export * from './useFoldingRangeProvider'
export * from './useFsWatcher'
export * from './useIsDarkTheme'
export * from './useIsTelemetryEnabled'
export * from './useL10nText'
export * from './useLogger'
export * from './useLogLevel'
export * from './useNotebookEditorSelection'
export * from './useNotebookEditorSelections'
export * from './useNotebookEditorVisibleRanges'
export * from './useOpenedTerminals'
export * from './useOutputChannel'
export * from './useQuickPick'
export * from './useStatusBarItem'
export * from './useTaskExecutions'
export * from './useTerminal'
export * from './useTerminalState'
export * from './useTextEditorCommand'
export * from './useTextEditorCommands'
export * from './useTextEditorSelection'
export * from './useTextEditorSelections'
export * from './useTextEditorViewColumn'
export * from './useTextEditorVisibleRanges'
export * from './useTreeView'
export * from './useViewBadge'
export * from './useViewTitle'
export * from './useViewVisibility'
export * from './useVisibleNotebookEditors'
export * from './useVisibleTextEditors'
export * from './useVscodeContext'
export * from './useWebviewView'
export * from './useWindowState'
export * from './useWorkspaceFolders'
export * from './useAbsolutePath'
export * from './useActiveColorTheme'
export * from './useActiveDebugSession'
export * from './useActiveEditorDecorations'
export * from './useActiveNotebookEditor'
export * from './useActiveTerminal'
export * from './useActiveTextEditor'
export * from './useAllExtensions'
export * from './useCommand'
export * from './useCommands'
export * from './useCommentController'
export * from './useControlledTerminal'
export * from './useDefaultShell'
export * from './useDisposable'
export * from './useDocumentText'
export * from './useEditorDecorations'
export * from './useEvent'
export * from './useEventEmitter'
export * from './useExtensionSecret'
export * from './useFetchTasks'
export * from './useFileUri'
export * from './useFoldingRangeProvider'
export * from './useFsWatcher'
export * from './useIsDarkTheme'
export * from './useIsTelemetryEnabled'
export * from './useL10nText'
export * from './useLogger'
export * from './useLogLevel'
export * from './useNotebookEditorSelection'
export * from './useNotebookEditorSelections'
export * from './useNotebookEditorVisibleRanges'
export * from './useOpenedTerminals'
export * from './useOutputChannel'
export * from './useQuickPick'
export * from './useStatusBarItem'
export * from './useTaskExecutions'
export * from './useTerminal'
export * from './useTerminalState'
export * from './useTextEditorCommand'
export * from './useTextEditorCommands'
export * from './useTextEditorSelection'
export * from './useTextEditorSelections'
export * from './useTextEditorViewColumn'
export * from './useTextEditorVisibleRanges'
export * from './useTreeView'
export * from './useViewBadge'
export * from './useViewTitle'
export * from './useViewVisibility'
export * from './useVisibleNotebookEditors'
export * from './useVisibleTextEditors'
export * from './useVscodeContext'
export * from './useWebviewPanel'
export * from './useWebviewView'
export * from './useWindowState'
export * from './useWorkspaceFolders'
73 changes: 73 additions & 0 deletions packages/core/src/composables/useWebviewPanel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { MaybeRefOrGetter } from '@reactive-vscode/reactivity'
import { ref, shallowRef, toValue, watchEffect } from '@reactive-vscode/reactivity'
import type { WebviewOptions } from 'vscode'
import { window } from 'vscode'
import { useDisposable } from './useDisposable'
import { useViewTitle } from './useViewTitle'

export interface WebviewPanelRegisterOptions {
enableFindWidget?: boolean
retainContextWhenHidden?: boolean
onDidReceiveMessage?: (message: any) => void
webviewOptions?: MaybeRefOrGetter<WebviewOptions>
}

/**
* Register a webview panel. See `vscode::window.createWebviewPanel`.
*
* @category view
*/
export function useWebviewPanel(
viewType: string,
title: MaybeRefOrGetter<string>,
html: MaybeRefOrGetter<string>,
showOptions: Parameters<typeof window.createWebviewPanel>[2],
options?: WebviewPanelRegisterOptions,
) {
const context = shallowRef<unknown>()
const panel = useDisposable(window.createWebviewPanel(
viewType,
toValue(title),
showOptions,
{
enableFindWidget: options?.enableFindWidget,
retainContextWhenHidden: options?.retainContextWhenHidden,
...toValue(options?.webviewOptions),
},
))

if (options?.onDidReceiveMessage)
panel.webview.onDidReceiveMessage(options.onDidReceiveMessage)

const forceRefreshId = ref(0)

function forceRefresh() {
forceRefreshId.value++
}

watchEffect(() => {
panel.webview.html = `${toValue(html)}<!--${forceRefreshId.value}-->`
})

if (options?.webviewOptions) {
const webviewOptions = options.webviewOptions
watchEffect(() => {
panel.webview.options = toValue(webviewOptions)
})
}

useViewTitle(panel, title)

function postMessage(message: any) {
return panel.webview.postMessage(message)
}

const active = ref(panel.active)
const visible = ref(panel.visible)
useDisposable(panel.onDidChangeViewState(() => {
active.value = panel.active
visible.value = panel.visible
}))

return { panel, context, active, visible, postMessage, forceRefresh }
}
160 changes: 80 additions & 80 deletions packages/core/src/composables/useWebviewView.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
import type { MaybeRefOrGetter } from '@reactive-vscode/reactivity'
import { ref, shallowRef, toValue, watchEffect } from '@reactive-vscode/reactivity'
import type { ViewBadge, WebviewOptions, WebviewView } from 'vscode'
import { window } from 'vscode'
import { createKeyedComposable } from '../utils'
import { useDisposable } from './useDisposable'
import { useViewBadge } from './useViewBadge'
import { useViewTitle } from './useViewTitle'

interface WebviewRegisterOptions {
retainContextWhenHidden?: boolean
onDidReceiveMessage?: (message: any) => void
webviewOptions?: MaybeRefOrGetter<WebviewOptions>
title?: MaybeRefOrGetter<string | undefined>
badge?: MaybeRefOrGetter<ViewBadge | undefined>
}

/**
* Register a webview view. See `vscode::window.registerWebviewViewProvider`.
*
* @category view
*/
export const useWebviewView = createKeyedComposable(
(
viewId: string,
html: MaybeRefOrGetter<string>,
options?: WebviewRegisterOptions,
) => {
const view = shallowRef<WebviewView>()
const context = shallowRef<unknown>()
useDisposable(window.registerWebviewViewProvider(
viewId,
{
resolveWebviewView(viewArg, contextArg) {
view.value = viewArg
context.value = contextArg
if (options?.onDidReceiveMessage)
viewArg.webview.onDidReceiveMessage(options.onDidReceiveMessage)
},
},
{
webviewOptions: {
retainContextWhenHidden: options?.retainContextWhenHidden,
},
},
))

const forceRefreshId = ref(0)

function forceRefresh() {
forceRefreshId.value++
}

watchEffect(() => {
if (view.value)
view.value.webview.html = `${toValue(html)}<!--${forceRefreshId.value}-->`
})

if (options?.webviewOptions) {
const webviewOptions = options.webviewOptions
watchEffect(() => {
if (view.value)
view.value.webview.options = toValue(webviewOptions)
})
}

if (options?.title)
useViewTitle(view, options.title)

if (options?.badge)
useViewBadge(view, options.badge)

function postMessage(message: any) {
return view.value?.webview.postMessage(message)
}

return { view, context, postMessage, forceRefresh }
},
viewId => viewId,
)
import type { MaybeRefOrGetter } from '@reactive-vscode/reactivity'
import { ref, shallowRef, toValue, watchEffect } from '@reactive-vscode/reactivity'
import type { ViewBadge, WebviewOptions, WebviewView, WebviewViewResolveContext } from 'vscode'
import { window } from 'vscode'
import { createKeyedComposable } from '../utils'
import { useDisposable } from './useDisposable'
import { useViewBadge } from './useViewBadge'
import { useViewTitle } from './useViewTitle'

export interface WebviewViewRegisterOptions {
retainContextWhenHidden?: boolean
onDidReceiveMessage?: (message: any) => void
webviewOptions?: MaybeRefOrGetter<WebviewOptions>
title?: MaybeRefOrGetter<string | undefined>
badge?: MaybeRefOrGetter<ViewBadge | undefined>
}

/**
* Register a webview view. See `vscode::window.registerWebviewViewProvider`.
*
* @category view
*/
export const useWebviewView = createKeyedComposable(
(
viewId: string,
html: MaybeRefOrGetter<string>,
options?: WebviewViewRegisterOptions,
) => {
const view = shallowRef<WebviewView>()
const context = shallowRef<WebviewViewResolveContext>()
useDisposable(window.registerWebviewViewProvider(
viewId,
{
resolveWebviewView(viewArg, contextArg) {
view.value = viewArg
context.value = contextArg
if (options?.onDidReceiveMessage)
viewArg.webview.onDidReceiveMessage(options.onDidReceiveMessage)
},
},
{
webviewOptions: {
retainContextWhenHidden: options?.retainContextWhenHidden,
},
},
))

const forceRefreshId = ref(0)

function forceRefresh() {
forceRefreshId.value++
}

watchEffect(() => {
if (view.value)
view.value.webview.html = `${toValue(html)}<!--${forceRefreshId.value}-->`
})

if (options?.webviewOptions) {
const webviewOptions = options.webviewOptions
watchEffect(() => {
if (view.value)
view.value.webview.options = toValue(webviewOptions)
})
}

if (options?.title)
useViewTitle(view, options.title)

if (options?.badge)
useViewBadge(view, options.badge)

function postMessage(message: any) {
return view.value?.webview.postMessage(message)
}

return { view, context, postMessage, forceRefresh }
},
viewId => viewId,
)

0 comments on commit 6364394

Please sign in to comment.