Custom Widgets

Do you want to build your own custom widget? You can do that! Just build your own VSCode extension using the offical VSCode documentation with some Marquee specific settings.

Widget Architecture

While all core Marquee widgets are implemeted in React.js we need 3rd party widgets to be implemented as web components so we can embedd them into the React application. There are various of possible templates here you can use. We recommend to pick a stack with a low footprint to keep bundle size low and Marquee performant.
To add your widget to Marquee add the following to your extension:
  • build your widget based of web components and publish the file as part of your extension
  • define a marquee property in your package.json file that contains a widget property that points to the bundle where your widgets are defined (e.g. "marquee": { "widget": "./dist/widgets.js" },)
  • register your widgets in your bundle via `window.marqueeExtension.defineWidget({ ... }), e.g.:
    1import { faBrain } from "@fortawesome/free-solid-svg-icons/faBrain";
    2
    3class MyAwesomeWidget extends HTMLElement {
    4  // ...
    5}
    6
    7window.marqueeExtension.defineWidget({
    8  name: 'my-awesome-widget',
    9  icon: faBrain,
    10  label: 'My Awesome Widget',
    11  tags: ['productivity'],
    12  description: 'This is an awesome widget you should have.'
    13}, MyAwesomeWidget);
    14
    You can define as many widgets as you like.
  • Publish your VSCode extension to the marketplace, and voilá - once you install the extension, Marquee will automatically pick it up and display its content

Data Communication

If your extension manages state data or other information you want to display, you can send them to your widget using tangle. Tangle is the data communication layer and allows to share state as well as events from your original extension and the Marquee webview. In order to iniate a communication channel return an object within your activate method or your extension entry file, please see below.
Please note that the whenReady hook below is optional and resolves once Marquee (counter-party JS sandbox) is ready to receive state updates. It's only required if sequence of events is important. For more information check out the tangle docs' paragraph about lifecycle hooks.
1// The module 'vscode' contains the VS Code extensibility API
2// Import the module and reference it with the alias vscode in your code below
3import * as vscode from 'vscode';
4import type { Client } from 'tangle';
5
6// this method is called when your extension is activated
7// your extension is activated the very first time the command is executed
8export function activate(context: vscode.ExtensionContext) {
9  // Use the console to output diagnostic information (console.log) and errors (console.error)
10  // This line of code will only be executed once when your extension is activated
11  console.log('Congratulations, your extension "helloworld-sample" is now active!');
12
13  // The command has been defined in the package.json file
14  // Now provide the implementation of the command with registerCommand
15  // The commandId parameter must match the command field in package.json
16  let disposable = vscode.commands.registerCommand('helloworld.helloWorld', () => {
17    // The code you place here will be executed every time your command is executed
18
19    // Display a message box to the user
20    vscode.window.showInformationMessage('Hello World!');
21  });
22
23  context.subscriptions.push(disposable);
24
25  // export interface for Marquee to setup channel
26  return {
27    marquee: {
28      setup: (tangle: Client<{ counter: number }>) => {
29        return tangle.whenReady().then(() => {
30          let i = 0
31          setInterval(() => {
32            tangle.emit('counter', ++i)
33          }, 1000)
34        })
35      },
36    },
37  }
38}
39
The setup method receives an already initialised tangle instance that you can use to exchange data. Read more about state and event sharing in the tangle docs. Next, you can attach to your communication channel within your widget to receive the data, e.g.:
1import Channel from 'tangle/webviews';
2
3// the channel name is always your extension id
4const ch = new Channel<{ counter: number }>('stateful.marquee');
5const client = ch.attach(window.vscode);
6
7class MyAwesomeWidget extends HTMLElement {
8  constructor () {
9    client.on('counter', this.incCounter.bind(this))
10  }
11
12  incCounter (cnt: number) {
13    // ...
14  }
15
16  // ...
17}
18
Note that the channel name you want to attach to is your extension id. Also important: Marquee attaches the VSCodeWebview instance, that you usually acquire through window.acquireVsCodeApi(), to the window scope for you to use.