Skip to content

Commit 60be174

Browse files
committed
Allow Application.shell to be Widget or HTMLElement
1 parent 2d8f82e commit 60be174

File tree

2 files changed

+54
-11
lines changed

2 files changed

+54
-11
lines changed

packages/application/src/index.ts

+18-11
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export { type IPlugin };
3939
* UI applications with the ability to be safely extended by third
4040
* party code via plugins.
4141
*/
42-
export class Application<T extends Widget = Widget> {
42+
export class Application<T extends Widget | HTMLElement = Widget> {
4343
/**
4444
* Construct a new application.
4545
*
@@ -57,6 +57,7 @@ export class Application<T extends Widget = Widget> {
5757
renderer: options.contextMenuRenderer
5858
});
5959
this.shell = options.shell;
60+
this._hasShellWidget = this.shell instanceof Widget;
6061
}
6162

6263
/**
@@ -196,7 +197,7 @@ export class Application<T extends Widget = Widget> {
196197
* If the plugin provides a service which has already been provided
197198
* by another plugin, the new service will override the old service.
198199
*/
199-
registerPlugin(plugin: IPlugin<this, any>): void {
200+
registerPlugin(plugin: IPlugin<Application<Widget | HTMLElement>, any>): void {
200201
this.pluginRegistry.registerPlugin(plugin);
201202
}
202203

@@ -208,7 +209,7 @@ export class Application<T extends Widget = Widget> {
208209
* #### Notes
209210
* This calls `registerPlugin()` for each of the given plugins.
210211
*/
211-
registerPlugins(plugins: IPlugin<this, any>[]): void {
212+
registerPlugins(plugins: IPlugin<Application<Widget | HTMLElement>, any>[]): void {
212213
this.pluginRegistry.registerPlugins(plugins);
213214
}
214215

@@ -339,10 +340,16 @@ export class Application<T extends Widget = Widget> {
339340
* A subclass may reimplement this method as needed.
340341
*/
341342
protected attachShell(id: string): void {
343+
if (this._hasShellWidget){
342344
Widget.attach(
343-
this.shell,
345+
this.shell as Widget,
344346
(id && document.getElementById(id)) || document.body
345-
);
347+
);} else {
348+
const host = (id && document.getElementById(id)) || document.body;
349+
if(!host.contains(this.shell as HTMLElement)) {
350+
host.appendChild(this.shell as HTMLElement)
351+
}
352+
}
346353
}
347354

348355
/**
@@ -419,7 +426,7 @@ export class Application<T extends Widget = Widget> {
419426
* A subclass may reimplement this method as needed.
420427
*/
421428
protected evtResize(event: Event): void {
422-
this.shell.update();
429+
if(this._hasShellWidget){(this.shell as Widget).update()}
423430
}
424431

425432
/**
@@ -429,6 +436,7 @@ export class Application<T extends Widget = Widget> {
429436
private _delegate = new PromiseDelegate<void>();
430437
private _started = false;
431438
private _bubblingKeydown = false;
439+
private _hasShellWidget = true;
432440
}
433441

434442
/**
@@ -438,13 +446,12 @@ export namespace Application {
438446
/**
439447
* An options object for creating an application.
440448
*/
441-
export interface IOptions<T extends Widget> extends PluginRegistry.IOptions {
449+
export interface IOptions<T extends Widget | HTMLElement> extends PluginRegistry.IOptions {
442450
/**
443-
* The shell widget to use for the application.
444-
*
445-
* This should be a newly created and initialized widget.
451+
* The shell element to use for the application.
446452
*
447-
* The application will attach the widget to the DOM.
453+
* If it is a {@link Widget}, this should be a newly created and initialized widget.
454+
* and the application will attach the widget to the DOM.
448455
*/
449456
shell: T;
450457

packages/application/tests/src/index.spec.ts

+36
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ describe('@lumino/application', () => {
5757
expect(app.hasPlugin(id1)).to.be.true;
5858
expect(app.isPluginActivated(id2)).to.be.true;
5959
});
60+
61+
it('should instantiate an application with a HTMLElement as shell', () => {
62+
const shell = document.createElement('div');
63+
const app = new Application<HTMLDivElement>({
64+
shell
65+
});
66+
67+
expect(app).to.be.instanceOf(Application);
68+
expect(app.commands).to.be.instanceOf(CommandRegistry);
69+
expect(app.contextMenu).to.be.instanceOf(ContextMenu);
70+
expect(app.shell).to.equal(shell);
71+
});
6072
});
6173

6274
describe('#getPluginDescription', () => {
@@ -624,5 +636,29 @@ describe('@lumino/application', () => {
624636
expect(app.isPluginActivated(id3)).to.be.false;
625637
});
626638
});
639+
640+
describe('#start', () => {
641+
it('should attach the shell widget to the document body', async () => {
642+
const shell = new Widget();
643+
const app = new Application({
644+
shell
645+
});
646+
647+
await app.start();
648+
649+
expect(document.body.contains(shell.node)).to.be.true;
650+
})
651+
652+
it('should attach the shell HTML element to the document body', async () => {
653+
const shell = document.createElement('div');
654+
const app = new Application<HTMLDivElement>({
655+
shell
656+
});
657+
658+
await app.start();
659+
660+
expect(document.body.contains(shell)).to.be.true;
661+
})
662+
})
627663
});
628664
});

0 commit comments

Comments
 (0)