(this);
private _hiddenMode: Widget.HiddenMode = Widget.HiddenMode.Display;
}
/**
* The namespace for the `Widget` class statics.
*/
export namespace Widget {
/**
* An options object for initializing a widget.
*/
export interface IOptions {
/**
* The optional node to use for the widget.
*
* If a node is provided, the widget will assume full ownership
* and control of the node, as if it had created the node itself.
*
* The default is a new ``.
*/
node?: HTMLElement;
/**
* The optional element tag, used for constructing the widget's node.
*
* If a pre-constructed node is provided via the `node` arg, this
* value is ignored.
*/
tag?: keyof HTMLElementTagNameMap;
}
/**
* The method for hiding the widget.
*
* The default is Display.
*
* Using `Scale` will often increase performance as most browsers will not
* trigger style computation for the `transform` action. This should be used
* sparingly and tested, since increasing the number of composition layers
* may slow things down.
*
* To ensure the transformation does not trigger style recomputation, you
* may need to set the widget CSS style `will-change: transform`. This
* should be used only when needed as it may overwhelm the browser with a
* high number of layers. See
* https://developer.mozilla.org/en-US/docs/Web/CSS/will-change
*/
export enum HiddenMode {
/**
* Set a `lm-mod-hidden` CSS class to hide the widget using `display:none`
* CSS from the standard Lumino CSS.
*/
Display = 0,
/**
* Hide the widget by setting the `transform` to `'scale(0)'`.
*/
Scale
}
/**
* An enum of widget bit flags.
*/
export enum Flag {
/**
* The widget has been disposed.
*/
IsDisposed = 0x1,
/**
* The widget is attached to the DOM.
*/
IsAttached = 0x2,
/**
* The widget is hidden.
*/
IsHidden = 0x4,
/**
* The widget is visible.
*/
IsVisible = 0x8,
/**
* A layout cannot be set on the widget.
*/
DisallowLayout = 0x10
}
/**
* A collection of stateless messages related to widgets.
*/
export namespace Msg {
/**
* A singleton `'before-show'` message.
*
* #### Notes
* This message is sent to a widget before it becomes visible.
*
* This message is **not** sent when the widget is being attached.
*/
export const BeforeShow = new Message('before-show');
/**
* A singleton `'after-show'` message.
*
* #### Notes
* This message is sent to a widget after it becomes visible.
*
* This message is **not** sent when the widget is being attached.
*/
export const AfterShow = new Message('after-show');
/**
* A singleton `'before-hide'` message.
*
* #### Notes
* This message is sent to a widget before it becomes not-visible.
*
* This message is **not** sent when the widget is being detached.
*/
export const BeforeHide = new Message('before-hide');
/**
* A singleton `'after-hide'` message.
*
* #### Notes
* This message is sent to a widget after it becomes not-visible.
*
* This message is **not** sent when the widget is being detached.
*/
export const AfterHide = new Message('after-hide');
/**
* A singleton `'before-attach'` message.
*
* #### Notes
* This message is sent to a widget before it is attached.
*/
export const BeforeAttach = new Message('before-attach');
/**
* A singleton `'after-attach'` message.
*
* #### Notes
* This message is sent to a widget after it is attached.
*/
export const AfterAttach = new Message('after-attach');
/**
* A singleton `'before-detach'` message.
*
* #### Notes
* This message is sent to a widget before it is detached.
*/
export const BeforeDetach = new Message('before-detach');
/**
* A singleton `'after-detach'` message.
*
* #### Notes
* This message is sent to a widget after it is detached.
*/
export const AfterDetach = new Message('after-detach');
/**
* A singleton `'parent-changed'` message.
*
* #### Notes
* This message is sent to a widget when its parent has changed.
*/
export const ParentChanged = new Message('parent-changed');
/**
* A singleton conflatable `'update-request'` message.
*
* #### Notes
* This message can be dispatched to supporting widgets in order to
* update their content based on the current widget state. Not all
* widgets will respond to messages of this type.
*
* For widgets with a layout, this message will inform the layout to
* update the position and size of its child widgets.
*/
export const UpdateRequest = new ConflatableMessage('update-request');
/**
* A singleton conflatable `'fit-request'` message.
*
* #### Notes
* For widgets with a layout, this message will inform the layout to
* recalculate its size constraints to fit the space requirements of
* its child widgets, and to update their position and size. Not all
* layouts will respond to messages of this type.
*/
export const FitRequest = new ConflatableMessage('fit-request');
/**
* A singleton conflatable `'activate-request'` message.
*
* #### Notes
* This message should be dispatched to a widget when it should
* perform the actions necessary to activate the widget, which
* may include focusing its node or descendant node.
*/
export const ActivateRequest = new ConflatableMessage('activate-request');
/**
* A singleton conflatable `'close-request'` message.
*
* #### Notes
* This message should be dispatched to a widget when it should close
* and remove itself from the widget hierarchy.
*/
export const CloseRequest = new ConflatableMessage('close-request');
}
/**
* A message class for child related messages.
*/
export class ChildMessage extends Message {
/**
* Construct a new child message.
*
* @param type - The message type.
*
* @param child - The child widget for the message.
*/
constructor(type: string, child: Widget) {
super(type);
this.child = child;
}
/**
* The child widget for the message.
*/
readonly child: Widget;
}
/**
* A message class for `'resize'` messages.
*/
export class ResizeMessage extends Message {
/**
* Construct a new resize message.
*
* @param width - The **offset width** of the widget, or `-1` if
* the width is not known.
*
* @param height - The **offset height** of the widget, or `-1` if
* the height is not known.
*/
constructor(width: number, height: number) {
super('resize');
this.width = width;
this.height = height;
}
/**
* The offset width of the widget.
*
* #### Notes
* This will be `-1` if the width is unknown.
*/
readonly width: number;
/**
* The offset height of the widget.
*
* #### Notes
* This will be `-1` if the height is unknown.
*/
readonly height: number;
}
/**
* The namespace for the `ResizeMessage` class statics.
*/
export namespace ResizeMessage {
/**
* A singleton `'resize'` message with an unknown size.
*/
export const UnknownSize = new ResizeMessage(-1, -1);
}
/**
* Attach a widget to a host DOM node.
*
* @param widget - The widget of interest.
*
* @param host - The DOM node to use as the widget's host.
*
* @param ref - The child of `host` to use as the reference element.
* If this is provided, the widget will be inserted before this
* node in the host. The default is `null`, which will cause the
* widget to be added as the last child of the host.
*
* #### Notes
* This will throw an error if the widget is not a root widget, if
* the widget is already attached, or if the host is not attached
* to the DOM.
*/
export function attach(
widget: Widget,
host: HTMLElement,
ref: HTMLElement | null = null
): void {
if (widget.parent) {
throw new Error('Cannot attach a child widget.');
}
if (widget.isAttached || widget.node.isConnected) {
throw new Error('Widget is already attached.');
}
if (!host.isConnected) {
throw new Error('Host is not attached.');
}
MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
host.insertBefore(widget.node, ref);
MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
}
/**
* Detach the widget from its host DOM node.
*
* @param widget - The widget of interest.
*
* #### Notes
* This will throw an error if the widget is not a root widget,
* or if the widget is not attached to the DOM.
*/
export function detach(widget: Widget): void {
if (widget.parent) {
throw new Error('Cannot detach a child widget.');
}
if (!widget.isAttached || !widget.node.isConnected) {
throw new Error('Widget is not attached.');
}
MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
widget.node.parentNode!.removeChild(widget.node);
MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
}
}
/**
* The namespace for the module implementation details.
*/
namespace Private {
/**
* An attached property for the widget title object.
*/
export const titleProperty = new AttachedProperty>({
name: 'title',
create: owner => new Title({ owner })
});
/**
* Create a DOM node for the given widget options.
*/
export function createNode(options: Widget.IOptions): HTMLElement {
return options.node || document.createElement(options.tag || 'div');
}
}