CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-theia--core

Core framework for building cloud and desktop IDE applications using modern web technologies with TypeScript and dependency injection.

Pending
Overview
Eval results
Files

widgets-ui.mddocs/

Widgets and UI

Theia's widget system provides comprehensive UI components built on Phosphor/Lumino with React integration, layout management, and extensible widget types for building modern IDE interfaces.

Capabilities

Base Widget

Foundation widget class providing core widget functionality and lifecycle management.

/**
 * Base widget class for all UI components
 */
class Widget {
    /** Unique widget identifier */
    readonly id: string;
    
    /** Widget title with label, icon, and other metadata */
    readonly title: Title<Widget>;
    
    /** Parent widget if this widget is attached */
    readonly parent: Widget | null;
    
    /** True if widget is attached to DOM */
    readonly isAttached: boolean;
    
    /** True if widget is visible */
    readonly isVisible: boolean;
    
    /** True if widget is disposed */
    readonly isDisposed: boolean;
    
    /**
     * Show the widget
     */
    show(): void;
    
    /**
     * Hide the widget
     */
    hide(): void;
    
    /**
     * Close the widget
     */
    close(): void;
    
    /**
     * Dispose the widget and clean up resources
     */
    dispose(): void;
    
    /**
     * Activate the widget (give it focus)
     */
    activate(): void;
    
    /**
     * Update the widget's appearance
     */
    update(): void;
}

React Widget

Widget base class for React-based components with lifecycle integration.

/**
 * Widget that renders React components
 */
class ReactWidget extends Widget {
    /**
     * Create React widget with optional props
     * @param props - React component props
     */
    constructor(props?: any);
    
    /**
     * Render the React component
     * @returns React element to render
     */
    protected render(): React.ReactNode;
    
    /**
     * Called after widget is attached to DOM
     */
    protected onAfterAttach(): void;
    
    /**
     * Called before widget is detached from DOM  
     */
    protected onBeforeDetach(): void;
    
    /**
     * Called when widget is updated
     */
    protected onUpdateRequest(): void;
    
    /**
     * Set React component state
     * @param state - New state object
     * @param callback - Optional callback after state update
     */
    protected setState(state: any, callback?: () => void): void;
}

Usage Example:

import React from "react";
import { ReactWidget } from "@theia/core/lib/browser";

interface MyWidgetState {
    count: number;
}

export class MyCounterWidget extends ReactWidget {
    protected state: MyWidgetState = { count: 0 };
    
    constructor() {
        super();
        this.id = 'counter-widget';
        this.title.label = 'Counter';
        this.title.iconClass = 'fa fa-calculator';
    }
    
    protected render(): React.ReactNode {
        return (
            <div className="counter-widget">
                <h3>Count: {this.state.count}</h3>
                <button onClick={this.increment}>Increment</button>
                <button onClick={this.decrement}>Decrement</button>
            </div>
        );
    }
    
    private increment = (): void => {
        this.setState({ count: this.state.count + 1 });
    };
    
    private decrement = (): void => {
        this.setState({ count: this.state.count - 1 });
    };
}

Application Shell

Main application container that manages widget layout and areas.

/**
 * Main application shell managing widget layout
 */
class ApplicationShell extends Widget {
    /**
     * Add widget to specified area
     * @param widget - Widget to add
     * @param area - Shell area to add to
     * @param options - Optional layout options
     */
    addWidget(widget: Widget, area?: ApplicationShell.Area, options?: ApplicationShell.WidgetOptions): void;
    
    /**
     * Activate a widget
     * @param id - Widget ID to activate
     */
    activateWidget(id: string): Widget | undefined;
    
    /**
     * Close all widgets in area
     * @param area - Shell area to close
     */
    closeAll(area?: ApplicationShell.Area): void;
    
    /**
     * Get all widgets in area
     * @param area - Shell area
     * @returns Array of widgets in area
     */
    getWidgets(area: ApplicationShell.Area): Widget[];
}

namespace ApplicationShell {
    /**
     * Shell areas where widgets can be placed
     */
    enum Area {
        left = 'left',
        right = 'right', 
        main = 'main',
        bottom = 'bottom',
        top = 'top'
    }
    
    /**
     * Options for adding widgets to shell
     */
    interface WidgetOptions {
        /** Area to add widget to */
        area?: Area;
        /** Tab index for ordering */
        rank?: number;
        /** Reference widget for relative positioning */
        ref?: Widget;
        /** Insertion mode relative to reference */
        mode?: 'tab-after' | 'tab-before' | 'split-top' | 'split-bottom' | 'split-left' | 'split-right';
    }
}

/**
 * Service token for ApplicationShell
 */
const ApplicationShell: symbol;

Widget Manager

Manages widget lifecycle, creation, and disposal.

/**
 * Manages widget lifecycle and factories
 */
interface WidgetManager {
    /**
     * Get or create widget by ID
     * @param id - Widget ID
     * @returns Promise resolving to widget
     */
    getOrCreateWidget<T extends Widget>(id: string): Promise<T>;
    
    /**
     * Try to get existing widget
     * @param id - Widget ID
     * @returns Widget if exists, undefined otherwise
     */
    tryGetWidget<T extends Widget>(id: string): T | undefined;
    
    /**
     * Get all widgets of a specific type
     * @param factoryId - Widget factory ID
     * @returns Array of matching widgets
     */
    getWidgets<T extends Widget>(factoryId: string): T[];
}

/**
 * Factory for creating widgets
 */
interface WidgetFactory {
    /** Unique factory identifier */
    readonly id: string;
    
    /**
     * Create widget instance
     * @param options - Creation options
     * @returns Promise resolving to widget
     */
    createWidget(options?: any): Promise<Widget>;
}

/**
 * Service tokens
 */
const WidgetManager: symbol;
const WidgetFactory: symbol;

Saveable Widget

Widget mixin for widgets that contain saveable content.

/**
 * Widget that contains saveable content
 */
interface SaveableWidget extends Widget {
    /**
     * Save the widget's content
     * @returns Promise that resolves when save completes
     */
    save(): Promise<void>;
    
    /**
     * True if widget has unsaved changes
     */
    readonly dirty: boolean;
    
    /**
     * Event fired when dirty state changes
     */
    readonly onDirtyChanged: Event<void>;
}

namespace SaveableWidget {
    /**
     * Type guard for saveable widgets
     * @param widget - Widget to check
     * @returns True if widget is saveable
     */
    function is(widget: Widget): widget is SaveableWidget;
}

Usage Example:

import { ReactWidget, SaveableWidget } from "@theia/core/lib/browser";
import { Emitter, Event } from "@theia/core";

export class MyEditorWidget extends ReactWidget implements SaveableWidget {
    private readonly onDirtyChangedEmitter = new Emitter<void>();
    readonly onDirtyChanged: Event<void> = this.onDirtyChangedEmitter.event;
    
    private _dirty = false;
    private content = '';
    
    get dirty(): boolean {
        return this._dirty;
    }
    
    private setDirty(dirty: boolean): void {
        if (this._dirty !== dirty) {
            this._dirty = dirty;
            this.onDirtyChangedEmitter.fire();
            this.title.className = dirty ? 'dirty' : '';
        }
    }
    
    async save(): Promise<void> {
        await this.saveContent(this.content);
        this.setDirty(false);
    }
    
    private updateContent(newContent: string): void {
        this.content = newContent;
        this.setDirty(true);
        this.update();
    }
    
    private async saveContent(content: string): Promise<void> {
        // Save implementation
    }
}

Widget Extensions

Additional widget utilities and extensions for specialized use cases.

/**
 * Widget that can be extracted to separate window
 */
interface ExtractableWidget extends Widget {
    /**
     * True if widget can be extracted
     */
    readonly isExtractable: boolean;
    
    /**
     * Extract widget to separate window
     */
    extractWidget(): void;
}

/**
 * Stateful widget that can save/restore state
 */
interface StatefulWidget extends Widget {
    /**
     * Store widget state
     * @returns State object
     */
    storeState(): any;
    
    /**
     * Restore widget state
     * @param oldState - Previously stored state
     */
    restoreState(oldState: any): void;
}

/**
 * Widget with custom context menu
 */
interface ContextMenuWidget extends Widget {
    /**
     * Create context menu for widget
     * @param event - Mouse event
     * @returns Context menu items
     */
    createContextMenu(event: MouseEvent): ContextMenu;
}

Title and Tabs

Widget title management and tab behavior.

/**
 * Widget title containing label, icon, and metadata
 */
class Title<T> {
    /** Display label */
    label: string;
    
    /** Icon CSS class */
    iconClass: string;
    
    /** Icon label for accessibility */
    iconLabel: string;
    
    /** Caption/tooltip text */
    caption: string;
    
    /** CSS class name */
    className: string;
    
    /** True if title can be closed */
    closable: boolean;
    
    /** Dataset for custom attributes */
    dataset: Record<string, string>;
    
    /** Owner widget */
    readonly owner: T;
    
    /** Event fired when title changes */
    readonly changed: Event<void>;
}

Layout and Styling

CSS Classes

Common CSS classes used by Theia widgets:

/**
 * Standard CSS classes for widgets
 */
namespace WidgetCSS {
    const WIDGET = 'theia-widget';
    const PANEL = 'theia-panel';
    const TOOLBAR = 'theia-toolbar';
    const TAB_BAR = 'theia-tab-bar';
    const DOCK_PANEL = 'theia-dock-panel';
    const SPLIT_PANEL = 'theia-split-panel';
}

Layout Options

/**
 * Layout configuration for widgets
 */
interface LayoutOptions {
    /** Minimum width in pixels */
    minWidth?: number;
    
    /** Minimum height in pixels */
    minHeight?: number;
    
    /** Maximum width in pixels */
    maxWidth?: number;
    
    /** Maximum height in pixels */
    maxHeight?: number;
    
    /** Stretch factor for resizing */
    stretch?: number;
}

Types

/**
 * Widget-related type definitions
 */
type WidgetConstructor = new (...args: any[]) => Widget;

interface WidgetOptions {
    id?: string;
    title?: Partial<Title.Dataset>;
}

namespace Widget {
    /**
     * Widget message types
     */
    enum MessageType {
        BeforeAttach = 'before-attach',
        AfterAttach = 'after-attach',
        BeforeDetach = 'before-detach',
        AfterDetach = 'after-detach',
        BeforeShow = 'before-show',
        AfterShow = 'after-show',
        BeforeHide = 'before-hide',
        AfterHide = 'after-hide',
        CloseRequest = 'close-request',
        Resize = 'resize',
        UpdateRequest = 'update-request',
        FitRequest = 'fit-request',
        ActivateRequest = 'activate-request'
    }
}

Install with Tessl CLI

npx tessl i tessl/npm-theia--core

docs

application-framework.md

commands.md

dependency-injection.md

events-messaging.md

index.md

keybindings.md

menus.md

preferences-configuration.md

resources-files.md

widgets-ui.md

tile.json