diff --git a/.gitignore b/.gitignore
index d5df56f92..6fa243c24 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,10 +7,12 @@ build
review/api/temp
*.tsbuildinfo
-# jetbrains IDE stuff
+# jetbrains ide stuff
*.iml
.idea/
-# ms IDE stuff
+# ms ide stuff
+*.code-workspace
+.history
.vscode
diff --git a/packages/commands/package.json b/packages/commands/package.json
index cf89fb9d5..3729e6558 100644
--- a/packages/commands/package.json
+++ b/packages/commands/package.json
@@ -34,10 +34,20 @@
"clean": "rimraf lib && rimraf *.tsbuildinfo",
"clean:test": "rimraf tests/build",
"docs": "typedoc --options tdoptions.json src",
+
"test": "npm run test:firefox",
- "test:chrome": "cd tests && karma start --browsers=Chrome",
- "test:firefox": "cd tests && karma start --browsers=Firefox",
- "test:ie": "cd tests && karma start --browsers=IE",
+ "test:chrome": "npm run test:nobrowser -- --browsers=Chrome",
+ "test:chrome-headless": "npm run test:nobrowser -- --browsers=ChromeHeadless",
+ "test:ie": "npm run test:nobrowser -- --browsers=IE",
+ "test:firefox": "npm run test:nobrowser -- --browsers=Firefox",
+ "test:nobrowser": "cd tests && karma start",
+
+ "test:debug": "npm run test:debug:firefox",
+ "test:debug:chrome-headless": "npm run test:debug:nobrowser -- --browsers=ChromeHeadless",
+ "test:debug:chrome": "npm run test:debug:nobrowser -- --browsers=Chrome",
+ "test:debug:firefox": "npm run test:debug:nobrowser -- --browsers=Firefox",
+ "test:debug:nobrowser": "cd tests && karma start --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000",
+
"watch": "tsc --build --watch"
},
"dependencies": {
@@ -46,7 +56,8 @@
"@lumino/disposable": "^1.3.4",
"@lumino/domutils": "^1.1.7",
"@lumino/keyboard": "^1.1.6",
- "@lumino/signaling": "^1.3.4"
+ "@lumino/signaling": "^1.3.4",
+ "@lumino/virtualdom": "^1.5.0"
},
"devDependencies": {
"@microsoft/api-extractor": "^7.6.0",
diff --git a/packages/commands/src/index.ts b/packages/commands/src/index.ts
index 02fcda5cf..b1261dc7b 100644
--- a/packages/commands/src/index.ts
+++ b/packages/commands/src/index.ts
@@ -31,6 +31,9 @@ import {
ISignal, Signal
} from '@lumino/signaling';
+import {
+ VirtualElement
+} from '@lumino/virtualdom';
/**
* An object which manages a collection of commands.
@@ -189,10 +192,25 @@ class CommandRegistry {
}
/**
- * @deprecated Use `iconClass()` instead.
+ * Get the icon renderer for a specific command.
+ *
+ * DEPRECATED: if set to a string value, the .icon field will
+ * function as an alias for the .iconClass field, for backwards
+ * compatibility. In the future when this is removed, the default
+ * return type will become undefined.
+ *
+ * @param id - The id of the command of interest.
+ *
+ * @param args - The arguments for the command.
+ *
+ * @returns The icon renderer for the command, or
+ * an empty string if the command is not registered.
*/
- icon(id: string, args: ReadonlyPartialJSONObject = JSONExt.emptyObject): string {
- return this.iconClass(id, args);
+ icon(id: string, args: ReadonlyPartialJSONObject = JSONExt.emptyObject): VirtualElement.IRenderer | undefined
+ /* */ | string /* */
+ {
+ let cmd = this._commands[id];
+ return cmd ? cmd.icon.call(undefined, args) : /* */ '' /* */ /* undefined */;
}
/**
@@ -647,10 +665,24 @@ namespace CommandRegistry {
mnemonic?: number | CommandFunc;
/**
- * @deprecated Use `iconClass` instead.
+ * The icon renderer for the command.
+ *
+ * #### Notes
+ * This can be an IRenderer object, or a function which returns the
+ * renderer based on the provided command arguments.
+ *
+ * The default value is undefined.
+ *
+ * DEPRECATED: if set to a string value, the .icon field will function as
+ * an alias for the .iconClass field, for backwards compatibility
*/
- icon?: string | CommandFunc;
-
+ icon?: VirtualElement.IRenderer | undefined
+ /* */ | string /* */
+ | CommandFunc<
+ VirtualElement.IRenderer | undefined
+ /* */ | string /* */
+ >;
+
/**
* The icon class for the command.
*
@@ -1165,6 +1197,12 @@ namespace Private {
readonly execute: CommandFunc;
readonly label: CommandFunc;
readonly mnemonic: CommandFunc;
+
+ readonly icon: CommandFunc<
+ VirtualElement.IRenderer | undefined
+ /* */ | string /* */
+ >;
+
readonly iconClass: CommandFunc;
readonly iconLabel: CommandFunc;
readonly caption: CommandFunc;
@@ -1181,11 +1219,30 @@ namespace Private {
*/
export
function createCommand(options: CommandRegistry.ICommandOptions): ICommand {
+ let icon;
+ let iconClass;
+
+ /* */
+ if (!(options.icon) || typeof options.icon === 'string') {
+ // alias icon to iconClass
+ iconClass = asFunc(options.iconClass || options.icon, emptyStringFunc);
+ icon = iconClass;
+ } else {
+ /* / */
+
+ iconClass = asFunc(options.iconClass, emptyStringFunc);
+ icon = asFunc(options.icon, undefinedFunc);
+
+ /* */
+ }
+ /* */
+
return {
execute: options.execute,
label: asFunc(options.label, emptyStringFunc),
mnemonic: asFunc(options.mnemonic, negativeOneFunc),
- iconClass: asFunc(options.iconClass || options.icon, emptyStringFunc),
+ icon,
+ iconClass,
iconLabel: asFunc(options.iconLabel, emptyStringFunc),
caption: asFunc(options.caption, emptyStringFunc),
usage: asFunc(options.usage, emptyStringFunc),
@@ -1325,6 +1382,11 @@ namespace Private {
*/
const emptyDatasetFunc = () => ({});
+ /**
+ * A singleton undefined function
+ */
+ const undefinedFunc = () => undefined;
+
/**
* Cast a value or command func to a command func.
*/
diff --git a/packages/commands/tests/src/index.spec.ts b/packages/commands/tests/src/index.spec.ts
index 4f7b43f49..822877e5e 100644
--- a/packages/commands/tests/src/index.spec.ts
+++ b/packages/commands/tests/src/index.spec.ts
@@ -275,13 +275,21 @@ describe('@lumino/commands', () => {
describe('#icon()', () => {
+ const iconRenderer = {
+ render: (host: HTMLElement, options?: any) => {
+ const renderNode = document.createElement('div');
+ renderNode.className = 'p-render';
+ host.appendChild(renderNode);
+ }
+ };
+
it('should get the icon for a specific command', () => {
let cmd = {
execute: (args: JSONObject) => { return args; },
- icon: 'foo'
+ icon: iconRenderer
};
registry.addCommand('test', cmd);
- expect(registry.icon('test')).to.equal('foo');
+ expect(registry.icon('test')).to.equal(iconRenderer);
});
it('should give the appropriate icon given arguments', () => {
@@ -302,6 +310,25 @@ describe('@lumino/commands', () => {
expect(registry.icon('test')).to.equal('');
});
+ /* */
+ it('should be able to return a string value', () => {
+ let cmd = {
+ execute: (args: JSONObject) => { return args; },
+ icon: 'foo'
+ };
+ registry.addCommand('test', cmd);
+ expect(registry.icon('test')).to.equal('foo');
+ });
+
+ it('should alias .iconClass() if cmd.icon is unset', () => {
+ let cmd = {
+ execute: (args: JSONObject) => { return args; },
+ iconClass: 'foo'
+ };
+ registry.addCommand('test', cmd);
+ expect(registry.icon('test')).to.equal('foo');
+ });
+ /* */
});
describe('#caption()', () => {
diff --git a/packages/commands/tsconfig.json b/packages/commands/tsconfig.json
index 4720810f0..8ba3a68c0 100644
--- a/packages/commands/tsconfig.json
+++ b/packages/commands/tsconfig.json
@@ -40,6 +40,9 @@
},
{
"path": "../signaling"
+ },
+ {
+ "path": "../virtualdom"
}
]
}
diff --git a/packages/virtualdom/package.json b/packages/virtualdom/package.json
index b5fdd6650..2be8925c3 100644
--- a/packages/virtualdom/package.json
+++ b/packages/virtualdom/package.json
@@ -34,13 +34,20 @@
"clean": "rimraf lib && rimraf *.tsbuildinfo",
"clean:test": "rimraf tests/build",
"docs": "typedoc --options tdoptions.json src",
+
"test": "npm run test:firefox",
- "test:chrome": "cd tests && karma start --browsers=Chrome",
- "test:chrome-headless": "cd tests && karma start --browsers=ChromeHeadless",
- "test:debug": "cd tests && karma start --browsers=Chrome --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000",
- "test:debug:chrome-headless": "cd tests && karma start --browsers=ChromeHeadless --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000",
- "test:firefox": "cd tests && karma start --browsers=Firefox",
- "test:ie": "cd tests && karma start --browsers=IE",
+ "test:chrome": "npm run test:nobrowser -- --browsers=Chrome",
+ "test:chrome-headless": "npm run test:nobrowser -- --browsers=ChromeHeadless",
+ "test:ie": "npm run test:nobrowser -- --browsers=IE",
+ "test:firefox": "npm run test:nobrowser -- --browsers=Firefox",
+ "test:nobrowser": "cd tests && karma start",
+
+ "test:debug": "npm run test:debug:firefox",
+ "test:debug:chrome-headless": "npm run test:debug:nobrowser -- --browsers=ChromeHeadless",
+ "test:debug:chrome": "npm run test:debug:nobrowser -- --browsers=Chrome",
+ "test:debug:firefox": "npm run test:debug:nobrowser -- --browsers=Firefox",
+ "test:debug:nobrowser": "cd tests && karma start --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000",
+
"watch": "tsc --build --watch"
},
"dependencies": {
diff --git a/packages/virtualdom/src/index.ts b/packages/virtualdom/src/index.ts
index 087d15852..c77dc09bc 100644
--- a/packages/virtualdom/src/index.ts
+++ b/packages/virtualdom/src/index.ts
@@ -801,11 +801,15 @@ namespace VirtualElement {
*
* For example, if render calls `ReactDOM.render(..., host)`, then
* there has to also be a corresponding implementation of unrender that
- * calls `ReactDOM.unmountComponentAtNode(host)`.
+ * calls `ReactDOM.unmountComponentAtNode(host)` in order to prevent
+ * a memory leak.
*
* @param host - the DOM element to be removed.
+ *
+ * @param options - Will be populated with the .attrs and .children fields
+ * set on the VirtualElement being unrendered.
*/
- unrender?: (host: HTMLElement) => void;
+ unrender?: (host: HTMLElement, options?: {attrs?: ElementAttrs, children?: ReadonlyArray}) => void;
};
}
@@ -1312,7 +1316,7 @@ namespace Private {
// Update the element content.
if (newVNode.renderer) {
- newVNode.renderer.render(currElem as HTMLElement);
+ newVNode.renderer.render(currElem as HTMLElement, {attrs: newVNode.attrs, children: newVNode.children});
} else {
updateContent(currElem as HTMLElement, oldVNode.children, newVNode.children);
}
@@ -1341,7 +1345,7 @@ namespace Private {
// recursively clean up host children
if (oldNode.type === 'text') {} else if (oldNode.renderer && oldNode.renderer.unrender) {
- oldNode.renderer.unrender(child!);
+ oldNode.renderer.unrender(child!, {attrs: oldNode.attrs, children: oldNode.children});
} else {
removeContent(child!, oldNode.children, 0, false);
}
diff --git a/packages/widgets/package.json b/packages/widgets/package.json
index 4f0753b66..2db0fba68 100644
--- a/packages/widgets/package.json
+++ b/packages/widgets/package.json
@@ -36,15 +36,20 @@
"clean": "rimraf lib && rimraf *.tsbuildinfo",
"clean:test": "rimraf tests/build",
"docs": "typedoc --options tdoptions.json src",
+
"test": "npm run test:firefox",
- "test:chrome": "cd tests && karma start --browsers=Chrome",
- "test:chrome-headless": "cd tests && karma start --browsers=ChromeHeadless",
+ "test:chrome": "npm run test:nobrowser -- --browsers=Chrome",
+ "test:chrome-headless": "npm run test:nobrowser -- --browsers=ChromeHeadless",
+ "test:ie": "npm run test:nobrowser -- --browsers=IE",
+ "test:firefox": "npm run test:nobrowser -- --browsers=Firefox",
+ "test:nobrowser": "cd tests && karma start",
+
"test:debug": "npm run test:debug:firefox",
- "test:debug:chrome": "cd tests && karma start --browsers=Chrome --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000",
- "test:debug:chrome-headless": "cd tests && karma start --browsers=ChromeHeadless --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000",
- "test:debug:firefox": "cd tests && karma start --browsers=Firefox --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000",
- "test:firefox": "cd tests && karma start --browsers=Firefox",
- "test:ie": "cd tests && karma start --browsers=IE",
+ "test:debug:chrome-headless": "npm run test:debug:nobrowser -- --browsers=ChromeHeadless",
+ "test:debug:chrome": "npm run test:debug:nobrowser -- --browsers=Chrome",
+ "test:debug:firefox": "npm run test:debug:nobrowser -- --browsers=Firefox",
+ "test:debug:nobrowser": "cd tests && karma start --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000",
+
"watch": "tsc --build --watch"
},
"dependencies": {
diff --git a/packages/widgets/src/commandpalette.ts b/packages/widgets/src/commandpalette.ts
index d11053720..079f839b2 100644
--- a/packages/widgets/src/commandpalette.ts
+++ b/packages/widgets/src/commandpalette.ts
@@ -587,6 +587,12 @@ namespace CommandPalette {
*/
readonly caption: string;
+ /**
+ * The icon renderer for the command item.
+ */
+ readonly icon: VirtualElement.IRenderer | undefined
+ /* */ | string /* */;
+
/**
* The icon class for the command item.
*/
@@ -779,7 +785,15 @@ namespace CommandPalette {
*/
renderItemIcon(data: IItemRenderData): VirtualElement {
let className = this.createIconClass(data);
- return h.div({ className }, data.item.iconLabel);
+
+ /* */
+ if (typeof data.item.icon === 'string') {
+ return h.div({className}, data.item.iconLabel);
+ }
+ /* */
+
+ // if data.item.icon is undefined, it will be ignored
+ return h.div({className}, data.item.icon!, data.item.iconLabel);
}
/**
@@ -1446,6 +1460,15 @@ namespace Private {
return this._commands.label(this.command, this.args);
}
+ /**
+ * The icon renderer for the command item.
+ */
+ get icon(): VirtualElement.IRenderer | undefined
+ /* */ | string /* */
+ {
+ return this._commands.icon(this.command, this.args);
+ }
+
/**
* The icon class for the command item.
*/
diff --git a/packages/widgets/src/menu.ts b/packages/widgets/src/menu.ts
index 48bd97dbe..49c3d19d1 100644
--- a/packages/widgets/src/menu.ts
+++ b/packages/widgets/src/menu.ts
@@ -1039,9 +1039,10 @@ namespace Menu {
readonly mnemonic: number;
/**
- * @deprecated Use `iconClass` instead.
+ * The icon renderer for the menu item.
*/
- readonly icon: string;
+ readonly icon: VirtualElement.IRenderer | undefined
+ /* */ | string /* */;
/**
* The icon class for the menu item.
@@ -1167,7 +1168,15 @@ namespace Menu {
*/
renderIcon(data: IRenderData): VirtualElement {
let className = this.createIconClass(data);
- return h.div({ className }, data.item.iconLabel);
+
+ /* */
+ if (typeof data.item.icon === 'string') {
+ return h.div({className}, data.item.iconLabel);
+ }
+ /* */
+
+ // if data.item.icon is undefined, it will be ignored
+ return h.div({className}, data.item.icon!, data.item.iconLabel);
}
/**
@@ -1745,10 +1754,26 @@ namespace Private {
}
/**
- * @deprecated Use `iconClass` instead.
+ * The icon renderer for the menu item.
*/
- get icon(): string {
+ get icon(): VirtualElement.IRenderer | undefined
+ /* */ | string /* */
+ {
+ if (this.type === 'command') {
+ return this._commands.icon(this.command, this.args);
+ }
+ if (this.type === 'submenu' && this.submenu) {
+ return this.submenu.title.icon;
+ }
+
+ /* */
+ // alias to icon class if not otherwise defined
return this.iconClass;
+ /* */
+
+ /*
+ return undefined;
+ */
}
/**
@@ -1777,6 +1802,7 @@ namespace Private {
return '';
}
+
/**
* The display caption for the menu item.
*/
diff --git a/packages/widgets/src/menubar.ts b/packages/widgets/src/menubar.ts
index 71fdaef81..88a8cffc2 100644
--- a/packages/widgets/src/menubar.ts
+++ b/packages/widgets/src/menubar.ts
@@ -787,7 +787,15 @@ namespace MenuBar {
*/
renderIcon(data: IRenderData): VirtualElement {
let className = this.createIconClass(data);
- return h.div({ className }, data.title.iconLabel);
+
+ /* */
+ if (typeof data.title.icon === 'string') {
+ return h.div({className}, data.title.iconLabel);
+ }
+ /* */
+
+ // if data.title.icon is undefined, it will be ignored
+ return h.div({className}, data.title.icon!, data.title.iconLabel);
}
/**
diff --git a/packages/widgets/src/tabbar.ts b/packages/widgets/src/tabbar.ts
index 137b2bff2..66c693dbb 100644
--- a/packages/widgets/src/tabbar.ts
+++ b/packages/widgets/src/tabbar.ts
@@ -1360,7 +1360,14 @@ namespace TabBar {
const { title } = data;
let className = this.createIconClass(data);
- return h.div({className}, title.iconRenderer, title.iconLabel);
+ /* */
+ if (typeof title.icon === 'string') {
+ return h.div({className}, title.iconLabel);
+ }
+ /* */
+
+ // if title.icon is undefined, it will be ignored
+ return h.div({className}, title.icon!, title.iconLabel);
}
/**
diff --git a/packages/widgets/src/title.ts b/packages/widgets/src/title.ts
index 151b1263c..556587867 100644
--- a/packages/widgets/src/title.ts
+++ b/packages/widgets/src/title.ts
@@ -38,8 +38,28 @@ class Title {
this._mnemonic = options.mnemonic;
}
if (options.icon !== undefined) {
- this._iconClass = options.icon;
+ /* */
+ if (typeof options.icon === "string") {
+ // when ._icon is null, the .icon getter will alias .iconClass
+ this._icon = null;
+ this._iconClass = options.icon;
+ } else {
+ /* */
+
+ this._icon = options.icon;
+
+ /* */
+ }
+ /* */
}
+
+ /* */
+ else {
+ // if unset, default to aliasing .iconClass
+ this._icon = null;
+ }
+ /* */
+
if (options.iconClass !== undefined) {
this._iconClass = options.iconClass;
}
@@ -47,7 +67,7 @@ class Title {
this._iconLabel = options.iconLabel;
}
if (options.iconRenderer !== undefined) {
- this._iconRenderer = options.iconRenderer;
+ this._icon = options.iconRenderer;
}
if (options.caption !== undefined) {
this._caption = options.caption;
@@ -116,17 +136,56 @@ class Title {
}
/**
- * @deprecated Use `iconClass` instead.
+ * Get the icon renderer for the title.
+ *
+ * #### Notes
+ * The default value is undefined.
+ *
+ * DEPRECATED: if set to a string value, the .icon field will function as
+ * an alias for the .iconClass field, for backwards compatibility
*/
- get icon(): string {
- return this.iconClass;
+ get icon(): VirtualElement.IRenderer| undefined
+ /* */ | string /* */
+ {
+ /* */
+ if (this._icon === null) {
+ // only alias .iconClass if ._icon has been explicitly nulled
+ return this.iconClass
+ }
+ /* */
+
+ return this._icon;
}
/**
- * @deprecated Use `iconClass` instead.
+ * Set the icon renderer for the title.
+ *
+ * #### Notes
+ * A renderer is an object that supplies a render and unrender function.
+ *
+ * DEPRECATED: if set to a string value, the .icon field will function as
+ * an alias for the .iconClass field, for backwards compatibility
*/
- set icon(value: string) {
- this.iconClass = value;
+ set icon(value: VirtualElement.IRenderer | undefined
+ /* */ | string /* */
+ ) {
+ /* */
+ if (typeof value === "string") {
+ // when ._icon is null, the .icon getter will alias .iconClass
+ this._icon = null;
+ this.iconClass = value;
+ } else {
+ /* */
+
+ if (this._icon === value) {
+ return;
+ }
+ this._icon = value;
+ this._changed.emit(undefined);
+
+ /* */
+ }
+ /* */
}
/**
@@ -178,27 +237,17 @@ class Title {
}
/**
- * Get the icon renderer for the title.
- *
- * #### Notes
- * The default value is undefined.
+ * @deprecated Use `icon` instead.
*/
- get iconRenderer(): VirtualElement.IRenderer {
- return this._iconRenderer;
+ get iconRenderer(): VirtualElement.IRenderer | undefined {
+ return this._icon || undefined;
}
/**
- * Set the icon renderer for the title.
- *
- * #### Notes
- * A renderer is an object that supplies a render and unrender function.
+ * @deprecated Use `icon` instead.
*/
- set iconRenderer(value: VirtualElement.IRenderer) {
- if (this._iconRenderer === value) {
- return;
- }
- this._iconRenderer = value;
- this._changed.emit(undefined);
+ set iconRenderer(value: VirtualElement.IRenderer | undefined) {
+ this.icon = value;
}
/**
@@ -297,9 +346,12 @@ class Title {
private _label = '';
private _caption = '';
private _mnemonic = -1;
+
+ private _icon: VirtualElement.IRenderer | undefined
+ /* */ | null /* */;
+
private _iconClass = '';
private _iconLabel = '';
- private _iconRenderer: VirtualElement.IRenderer;
private _className = '';
private _closable = false;
private _dataset: Title.Dataset;
@@ -339,9 +391,12 @@ namespace Title {
mnemonic?: number;
/**
- * @deprecated Use `iconClass` instead.
+ * The icon renderer for the title.
+ *
+ * DEPRECATED: if set to a string value, the .icon field will function as
+ * an alias for the .iconClass field, for backwards compatibility
*/
- icon?: string;
+ icon?: VirtualElement.IRenderer | string;
/**
* The icon class name for the title.
@@ -354,8 +409,7 @@ namespace Title {
iconLabel?: string;
/**
- * An object that supplies render and unrender functions used
- * to create and cleanup the icon of the title.
+ * @deprecated Use `icon` instead.
*/
iconRenderer?: VirtualElement.IRenderer;
diff --git a/packages/widgets/tests/src/tabbar.spec.ts b/packages/widgets/tests/src/tabbar.spec.ts
index 32334842e..573c193aa 100644
--- a/packages/widgets/tests/src/tabbar.spec.ts
+++ b/packages/widgets/tests/src/tabbar.spec.ts
@@ -1297,10 +1297,17 @@ describe('@lumino/widgets', () => {
expect(node.classList.contains('lm-mod-closable')).to.equal(true);
expect(node.title).to.equal(title.caption);
- let icon = node.getElementsByClassName('lm-TabBar-tabIcon')[0] as HTMLElement;
let label = node.getElementsByClassName('lm-TabBar-tabLabel')[0] as HTMLElement;
- expect(icon.classList.contains(title.icon)).to.equal(true);
expect(label.textContent).to.equal(title.label);
+
+ let icon = node.getElementsByClassName('lm-TabBar-tabIcon')[0] as HTMLElement;
+ expect(icon.classList.contains(title.iconClass)).to.equal(true);
+
+ /* */
+ // since a string was assigned to .icon, it should alias .iconClass
+ expect(icon.classList.contains(title.icon as string)).to.equal(true);
+ expect(title.icon).to.equal(title.iconClass);
+ /* */
});
});
@@ -1312,7 +1319,13 @@ describe('@lumino/widgets', () => {
let vNode = renderer.renderIcon({ title, current: true, zIndex: 1 });
let node = VirtualDOM.realize(vNode as VirtualElement);
expect(node.className).to.contain('lm-TabBar-tabIcon');
- expect(node.classList.contains(title.icon)).to.equal(true);
+ expect(node.classList.contains(title.iconClass)).to.equal(true);
+
+ /* */
+ // make sure that icon and iconClass match
+ expect(node.classList.contains(title.icon as string)).to.equal(true);
+ expect(title.icon).to.equal(title.iconClass);
+ /* */
});
});
@@ -1383,7 +1396,13 @@ describe('@lumino/widgets', () => {
title, current: true, zIndex: 1
});
expect(className).to.contain('lm-TabBar-tabIcon');
- expect(className).to.contain(title.icon);
+ expect(className).to.contain(title.iconClass);
+
+ /* */
+ // make sure that icon and iconClass match
+ expect(className).to.contain(title.icon as string);
+ expect(title.icon).to.equal(title.iconClass);
+ /* */
});
});
diff --git a/packages/widgets/tests/src/title.spec.ts b/packages/widgets/tests/src/title.spec.ts
index d38f6f738..18e924e33 100644
--- a/packages/widgets/tests/src/title.spec.ts
+++ b/packages/widgets/tests/src/title.spec.ts
@@ -143,6 +143,14 @@ describe('@lumino/widgets', () => {
describe('#icon', () => {
+ const iconRenderer = {
+ render: (host: HTMLElement, options?: any) => {
+ const renderNode = document.createElement('div');
+ renderNode.className = 'p-render';
+ host.appendChild(renderNode);
+ }
+ };
+
it('should default to an empty string', () => {
let title = new Title({ owner });
expect(title.icon).to.equal('');
@@ -181,6 +189,34 @@ describe('@lumino/widgets', () => {
expect(called).to.equal(false);
});
+ /* */
+ it('should be able to switch string => renderer', () => {
+ let title = new Title({ owner, icon: 'foo' });
+ expect(title.icon).to.equal('foo');
+
+ // when initialized with string, should alias .iconClass
+ expect(title.icon).to.equal(title.iconClass);
+
+ title.icon = iconRenderer;
+ expect(title.icon).to.equal(iconRenderer);
+ });
+
+ it('should be able to switch renderer => string', () => {
+ let title = new Title({ owner, icon: iconRenderer });
+ expect(title.icon).to.equal(iconRenderer);
+ title.icon = 'foo';
+ expect(title.icon).to.equal('foo');
+
+ // when switched to string, should alias .iconClass
+ expect(title.icon).to.equal(title.iconClass);
+ });
+
+ it('should alias .iconClass if unset', () => {
+ let title = new Title({ owner, iconClass: 'foo' });
+ expect(title.icon).to.equal('foo');
+ });
+ /* */
+
});
describe('#caption', () => {