Views
Views are an important part of a VSCode extension. There are two types of views in VSCode: Tree View and Webview. Please read the official UX guidelines for a basic understanding.
Define in Manifest Non-Proprietary
As described in the official documentation, first, you need view containers to be defined in the contributes.viewsContainers.[viewContainerType] section in the package.json. Then you can define your views in the contributes.views.[viewContainerId] section.
{
"contributes": {
"viewsContainers": {
"activitybar": [
{
"id": "package-explorer",
"title": "Package Explorer",
"icon": "resources/package-explorer.svg"
}
]
},
"views": {
"package-explorer": [
{
"id": "package-dependencies",
"name": "Dependencies"
},
{
"id": "package-outline",
"name": "Outline"
}
]
}
}
}
Register Tree View
Tree views are used to display hierarchical data. You can define a tree view by using the useTreeView function.
Here is an example of a tree view:
import type { TreeViewNode } from 'reactive-vscode'
import { computed, defineService, useTreeView } from 'reactive-vscode'
import { TreeItemCollapsibleState } from 'vscode'
export const useDemoTreeView = defineService(() => {
function getRootNode(index: number) {
return {
children: [
getChildNode(index * 10 + 1),
getChildNode(index * 10 + 2),
],
treeItem: {
label: `Root ${index}`,
collapsibleState: TreeItemCollapsibleState.Expanded,
},
}
}
function getChildNode(index: number) {
return {
treeItem: {
label: `Child ${index}`,
collapsibleState: TreeItemCollapsibleState.None,
},
}
}
const treeData = computed(() => {
const roots: TreeViewNode[] = []
for (let i = 1; i < 5; i++)
roots.push(getRootNode(i))
return roots
})
const view = useTreeView(
'reactive-tree-view',
treeData,
{
title: () => `Tree with ${treeData.value.length} roots`,
},
)
// return anything you want to expose
return view
})Then you can call the useDemoTreeView function every where to register the tree view and get the returned value:
import { defineExtension } from 'reactive-vscode'
import { useDemoTreeView } from './treeView'
export = defineExtension(() => {
const demoTreeView = useDemoTreeView()
// ...
})The children property in nodes is used to define the children of the node. The treeItem property is required and is used to define the tree item of the node. It should be a TreeItem object, or a promise that resolves to a TreeItem object.
If you want to trigger an update based on some reactive values that aren't tracked in treeData, you can pass them to the watchSource option.
About defineService
defineService defines a logic that should only be executed once, and can be used in multiple places. The function passed todefineService will be executed in a detached effect scope when it is called the first time, and the result will be cached and returned in subsequent calls. When the extension is deactivated, the effect scope created by defineService will be stopped automatically.WARNING
For the above example, useDemoTreeView should not be called at the top-level in the module, because the extension context is not available at that time. Instead, you should call it from the setup function of defineExtension (i.e. when the extension is activated).
Register Webview
Webviews are used to display web content in the editor. You can define a webview by using the useWebviewView function.
Here is an example of a webview:
import { computed, defineService, ref, useWebviewView } from 'reactive-vscode'
export const useDemoWebviewView = defineService(() => {
const message = ref('')
const html = computed(() => `
<script>
vscode = acquireVsCodeApi()
function updateMessage() {
vscode.postMessage({
type: 'updateMessage',
message: document.querySelector('input').value,
})
}
</script>
<p>${message.value}</p>
<div style="display:flex; flex-wrap:wrap;">
<input type="text" placeholder="Input Message" />
<button onclick="updateMessage()">Update Message</button>
</div>
`)
const { postMessage } = useWebviewView(
'reactive-webview-view',
html,
{
webviewOptions: {
enableScripts: true,
enableCommandUris: true,
},
onDidReceiveMessage(ev) {
if (ev.type === 'updateMessage')
message.value = ev.message
},
},
)
return { message, postMessage }
})The time to call useDemoWebviewView is the same as the tree view in the previous section.
There is also useWebviewPanel composable to create a webview panel. The usage is similar to useWebviewView.