fix(lit-components): fix rendering and interaction issues in force-graph, html-table, and draggable-dom
Build and Deploy / build-and-deploy (push) Has been cancelled
Build and Deploy / build-and-deploy (push) Has been cancelled
- lit-force-graph: Refactored for instance reuse, better lifecycle management, and added dynamic imports for AR/VR modes. - lit-html-table: Improved visual design, readability of headers, and fixed reactivity in editable mode. - lit-draggable-dom: Fixed clipping issues by switching to relative/absolute positioning and resolved a panning speed bug caused by CSS variable inheritance.
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
import * as vscode from "vscode";
|
||||
|
||||
const WEB_DIR: string = "build";
|
||||
const WEB_SCRIPT: string = "main.js";
|
||||
const TITLE: string = "Lit Example";
|
||||
const TAG: string = "my-element";
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("lit.start", () => {
|
||||
Panel.createOrShow(context.extensionUri);
|
||||
})
|
||||
);
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("lit.reset", () => {
|
||||
if (Panel.currentPanel) {
|
||||
Panel.currentPanel.sendMessage("reset");
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if (vscode.window.registerWebviewPanelSerializer) {
|
||||
vscode.window.registerWebviewPanelSerializer(Panel.viewType, {
|
||||
async deserializeWebviewPanel(
|
||||
webviewPanel: vscode.WebviewPanel,
|
||||
state: any
|
||||
) {
|
||||
console.log(`Received state: ${state}`);
|
||||
webviewPanel.webview.options = getWebviewOptions(context.extensionUri);
|
||||
Panel.revive(webviewPanel, context.extensionUri);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getWebviewOptions(extensionUri: vscode.Uri): vscode.WebviewOptions {
|
||||
return {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, WEB_DIR)],
|
||||
};
|
||||
}
|
||||
|
||||
class Panel {
|
||||
public static currentPanel: Panel | undefined;
|
||||
public static readonly viewType = "litExample";
|
||||
private _disposables: vscode.Disposable[] = [];
|
||||
|
||||
public static createOrShow(extensionUri: vscode.Uri) {
|
||||
const column = vscode.window.activeTextEditor
|
||||
? vscode.window.activeTextEditor.viewColumn
|
||||
: undefined;
|
||||
if (Panel.currentPanel) {
|
||||
Panel.currentPanel.panel.reveal(column);
|
||||
return;
|
||||
}
|
||||
const panel = vscode.window.createWebviewPanel(
|
||||
Panel.viewType,
|
||||
TITLE,
|
||||
column || vscode.ViewColumn.One,
|
||||
getWebviewOptions(extensionUri)
|
||||
);
|
||||
Panel.currentPanel = new Panel(panel, extensionUri);
|
||||
}
|
||||
|
||||
public static revive(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
|
||||
Panel.currentPanel = new Panel(panel, extensionUri);
|
||||
}
|
||||
|
||||
private constructor(
|
||||
public readonly panel: vscode.WebviewPanel,
|
||||
public readonly extensionUri: vscode.Uri
|
||||
) {
|
||||
this._update();
|
||||
this.panel.onDidDispose(() => this.dispose(), null, this._disposables);
|
||||
this.panel.onDidChangeViewState(
|
||||
(_) => {
|
||||
if (this.panel.visible) {
|
||||
this._update();
|
||||
}
|
||||
},
|
||||
null,
|
||||
this._disposables
|
||||
);
|
||||
this.panel.webview.onDidReceiveMessage(
|
||||
(message) => {
|
||||
switch (message.command) {
|
||||
case "alert":
|
||||
vscode.window.showErrorMessage(message.text);
|
||||
return;
|
||||
}
|
||||
},
|
||||
null,
|
||||
this._disposables
|
||||
);
|
||||
}
|
||||
|
||||
public sendMessage(command: string) {
|
||||
this.panel.webview.postMessage({ command: command });
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
Panel.currentPanel = undefined;
|
||||
this.panel.dispose();
|
||||
while (this._disposables.length) {
|
||||
const x = this._disposables.pop();
|
||||
if (x) {
|
||||
x.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _update() {
|
||||
const webview = this.panel.webview;
|
||||
webview.html = this._getHtmlForWebview(webview);
|
||||
}
|
||||
|
||||
private _getHtmlForWebview(webview: vscode.Webview) {
|
||||
const scriptPathOnDisk = vscode.Uri.joinPath(
|
||||
this.extensionUri,
|
||||
WEB_DIR,
|
||||
WEB_SCRIPT
|
||||
);
|
||||
const scriptUri = webview.asWebviewUri(scriptPathOnDisk);
|
||||
const nonce = getNonce();
|
||||
|
||||
const slot = "<p>This is child content</p>";
|
||||
|
||||
const htmlSource = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>${TITLE}</title>
|
||||
</head>
|
||||
<body class="vscode-light">
|
||||
<${TAG} nonce="${nonce}" >
|
||||
${slot}
|
||||
</${TAG}>
|
||||
<script nonce="${nonce}" type="module" src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
return htmlSource;
|
||||
}
|
||||
}
|
||||
|
||||
const possible = [
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
"abcdefghijklmnopqrstuvwxyz",
|
||||
"0123456789",
|
||||
].join("");
|
||||
|
||||
function getNonce() {
|
||||
let text = "";
|
||||
for (let i = 0; i < 32; i++) {
|
||||
const char = possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
text += char;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { html, css, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
|
||||
@customElement("my-element")
|
||||
export class MyElement extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
border: solid 1px gray;
|
||||
padding: 16px;
|
||||
max-width: 800px;
|
||||
}
|
||||
`;
|
||||
|
||||
@property() name = "World";
|
||||
@state() count = 0;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<h1>Hello, ${this.name}!</h1>
|
||||
<button @click=${() => this.modify(1)} part="button">
|
||||
Click Count: ${this.count}
|
||||
</button>
|
||||
<slot></slot>
|
||||
`;
|
||||
}
|
||||
|
||||
modify(val: number) {
|
||||
this.count += val;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.count = 0;
|
||||
}
|
||||
|
||||
async firstUpdated() {
|
||||
window.addEventListener(
|
||||
"message",
|
||||
(e: any) => {
|
||||
const message = e.data;
|
||||
const { command } = message;
|
||||
if (command === "reset") {
|
||||
this.reset();
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import "./my-element";
|
||||
|
||||
describe("VSCode Webview Custom Element", () => {
|
||||
test("registers my-element custom element successfully", () => {
|
||||
expect(customElements.get("my-element")).toBeDefined();
|
||||
});
|
||||
|
||||
test("mounts custom webview element successfully", async () => {
|
||||
document.body.innerHTML = "<my-element></my-element>";
|
||||
await window.happyDOM.whenAsyncComplete();
|
||||
|
||||
const element = document.body.querySelector("my-element");
|
||||
expect(element).toBeDefined();
|
||||
expect(element?.shadowRoot).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user