Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds JLIcon, an easier way to consume icons as SVG nodes #7299

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d5dbfbe
starting work on JLIcon, to be used as an icon class wrapper
telamonian Oct 7, 2019
9a5ed5f
dynamically create JLIcon class within a function
telamonian Oct 7, 2019
e865999
added static JLIcon.element, returns an HTMLElement
telamonian Oct 7, 2019
c47b74f
set up ref forwarding in JLIcon
telamonian Oct 7, 2019
bcf2ac0
simplified typing of createIcon return type
telamonian Oct 7, 2019
b7f63c1
all of the wrapped icons now get autogenerated by `integrity`
telamonian Oct 7, 2019
d633c97
added explicitly declared return type to `createIcon`
telamonian Oct 9, 2019
9891483
simplified createIcon function by refactoring it into JLIcon class
telamonian Oct 11, 2019
d9157b9
refactored JLIcon.react from accessor => property
telamonian Oct 12, 2019
a42ebe4
fixed up docstrings in JLIcon namespace
telamonian Oct 12, 2019
5d53122
experimenting with blending phosphor/react vdom
telamonian Oct 12, 2019
29696b4
all tabbar icons now rendered by blended react/phosphor vdom elements
telamonian Oct 13, 2019
5cd5b01
fixed sidebar tab icons; styling still isn't right
telamonian Oct 13, 2019
0150060
integrity
telamonian Oct 13, 2019
c169aa7
fixing up the text editor icon
telamonian Oct 14, 2019
f219143
fixed text editor icon name
telamonian Oct 14, 2019
01bf019
progress fixing text editor icon
telamonian Oct 14, 2019
13636c6
finished fixing text editor icon
telamonian Oct 14, 2019
3207458
human readability formatting pass of filetype icon svg
telamonian Oct 14, 2019
637cac5
switch filebrowser to newest JLIcon icon handling
telamonian Oct 14, 2019
48b0b82
finally got react to parse/render bare svg element without outer div
telamonian Oct 14, 2019
5eb653d
bugfix for camelCase function
telamonian Oct 14, 2019
5667d2e
fixed container handling by JLIcon methods
telamonian Oct 14, 2019
b53f50e
fixed styling of tab manager tab icons
telamonian Oct 14, 2019
0168548
fixed memory leak in browser icons; updates for latest version of hpass
telamonian Oct 14, 2019
8931a8f
fixed memory leak; JLIcon nows cleans up after itself when passed to …
telamonian Oct 14, 2019
70da61c
post phosphor => lumino rebase cleanup
telamonian Dec 19, 2019
7e0808c
progress
telamonian Dec 24, 2019
28cdc46
progress
telamonian Dec 24, 2019
55a2966
JLIcon prototype is now feature complete and lumino vdom friendly
telamonian Dec 25, 2019
1bec1ee
type/signature fixes
telamonian Dec 25, 2019
21f8d65
fixed bug in static Map init
telamonian Dec 25, 2019
74c818c
fixed tabmanager icon styling
telamonian Dec 25, 2019
7a8361b
fixed style for dockpanel tab icons
telamonian Dec 25, 2019
09132cb
signature cleanup
telamonian Dec 25, 2019
7004dd5
simplified JLIcon styling for lumino; moved all tab icons to JLIcon
telamonian Dec 25, 2019
6b997b3
docs and integrity
telamonian Dec 25, 2019
6d38176
post-rebase cleanup and bugfixes
telamonian Dec 25, 2019
c05e50f
integrity
telamonian Dec 25, 2019
a5a05ae
picked lint
telamonian Dec 25, 2019
247b1cd
configure all linters to ignore generated iconimports.ts
telamonian Dec 25, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 15 additions & 14 deletions .eslintignore
@@ -1,24 +1,25 @@
node_modules
**/node_modules
**/lib
**/build
**/lib
**/node_modules
**/static
jupyterlab/schemas
jupyterlab/themes
jupyterlab/geckodriver
jupyterlab/staging/yarn.js
jupyterlab/chrome-test.js
jupyterlab/staging/index.js
tests/**/coverage

dev_mode/index.js
dev_mode/schemas
!dev_mode/static/index.out.js
dev_mode/static
dev_mode/themes
dev_mode/workspaces
docs/_build
docs/api
examples/app/build
examples/app/themes
examples/app/schemas
examples/app/themes
examples/chrome-example-test.js
tests/**/coverage
docs/_build
docs/api
!dev_mode/static/index.out.js
jupyterlab/chrome-test.js
jupyterlab/geckodriver
jupyterlab/schemas
jupyterlab/staging/index.js
jupyterlab/staging/yarn.js
jupyterlab/themes
packages/ui-components/src/icon/iconimports.ts
25 changes: 13 additions & 12 deletions .prettierignore
@@ -1,23 +1,24 @@
node_modules
**/build
**/node_modules
**/lib
**/build
**/package.json
**/static
jupyterlab/schemas
jupyterlab/themes
jupyterlab/geckodriver
jupyterlab/staging/yarn.js
jupyterlab/staging/index.js
tests/**/coverage

.eggs
dev_mode/index.js
dev_mode/schemas
dev_mode/static
dev_mode/themes
dev_mode/workspaces
docs/_build
docs/api
examples/app/build
examples/app/themes
examples/app/schemas
tests/**/coverage
docs/_build
docs/api
**/package.json
.eggs
jupyterlab/schemas
jupyterlab/themes
jupyterlab/geckodriver
jupyterlab/staging/yarn.js
jupyterlab/staging/index.js
packages/ui-components/src/icon/iconimports.ts
20 changes: 15 additions & 5 deletions buildutils/src/ensure-package.ts
Expand Up @@ -21,6 +21,7 @@ const HEADER_TEMPLATE = `
`;

const ICON_IMPORTS_TEMPLATE = `
import { JLIcon } from './jlicon';
import { Icon } from './interfaces';

// icon svg import statements
Expand All @@ -32,6 +33,9 @@ export namespace IconImports {
{{iconModelDeclarations}}
];
}

// wrapped icon definitions
{{wrappedIconDefs}}
`;

const ICON_CSS_CLASSES_TEMPLATE = `
Expand Down Expand Up @@ -364,6 +368,7 @@ export async function ensureUiComponents(
// build the per-icon import code
let _iconImportStatements: string[] = [];
let _iconModelDeclarations: string[] = [];
let _wrappedIconDefs: string[] = [];
svgs.forEach(svg => {
const name = utils.stem(svg);
const svgpath = path
Expand All @@ -378,22 +383,27 @@ export async function ensureUiComponents(
);
} else {
// load the icon svg using `import`
const nameCamel = utils.camelCase(name) + 'Svg';
const svgname = utils.camelCase(name) + 'Svg';
const iconname = utils.camelCase(name) + 'Icon';

_iconImportStatements.push(`import ${nameCamel} from '${svgpath}';`);
_iconModelDeclarations.push(`{ name: '${name}', svg: ${nameCamel} }`);
_iconImportStatements.push(`import ${svgname} from '${svgpath}';`);
_iconModelDeclarations.push(`{ name: '${name}', svg: ${svgname} }`);
_wrappedIconDefs.push(
`export const ${iconname} = new JLIcon({ name: '${iconname}', svgstr: ${svgname} });`
);
}
});
const iconImportStatements = _iconImportStatements.join('\n');
const iconModelDeclarations = _iconModelDeclarations.join(',\n');
const wrappedIconDefs = _wrappedIconDefs.join('\n');

// generate the actual contents of the iconImports file
const iconImportsPath = path.join(iconSrcDir, 'iconimports.ts');
const iconImportsContents = utils.fromTemplate(
HEADER_TEMPLATE + ICON_IMPORTS_TEMPLATE,
{ funcName, iconImportStatements, iconModelDeclarations }
{ funcName, iconImportStatements, iconModelDeclarations, wrappedIconDefs }
);
messages.push(...ensureFile(iconImportsPath, iconImportsContents));
messages.push(...ensureFile(iconImportsPath, iconImportsContents, false));

/* support for deprecated icon CSS classes */
const iconCSSDir = path.join(pkgPath, 'style');
Expand Down
1 change: 1 addition & 0 deletions packages/application-extension/package.json
Expand Up @@ -42,6 +42,7 @@
"@jupyterlab/property-inspector": "^2.0.0-alpha.4",
"@jupyterlab/settingregistry": "^2.0.0-alpha.4",
"@jupyterlab/statedb": "^2.0.0-alpha.4",
"@jupyterlab/ui-components": "^2.0.0-alpha.4",
"@lumino/algorithm": "^1.2.1",
"@lumino/coreutils": "^1.4.0",
"@lumino/disposable": "^1.3.2",
Expand Down
20 changes: 11 additions & 9 deletions packages/application-extension/src/index.tsx
Expand Up @@ -26,15 +26,17 @@ import {

import { PathExt, URLExt } from '@jupyterlab/coreutils';

import { IStateDB } from '@jupyterlab/statedb';

import { ISettingRegistry } from '@jupyterlab/settingregistry';

import {
IPropertyInspectorProvider,
SideBarPropertyInspectorProvider
} from '@jupyterlab/property-inspector';

import { ISettingRegistry } from '@jupyterlab/settingregistry';

import { IStateDB } from '@jupyterlab/statedb';

import { buildIcon } from '@jupyterlab/ui-components';

import { each, iter, toArray } from '@lumino/algorithm';

import { PromiseDelegate } from '@lumino/coreutils';
Expand Down Expand Up @@ -584,7 +586,7 @@ function addCommands(app: JupyterLab, palette: ICommandPalette): void {
commands.addCommand(CommandIDs.close, {
label: () => 'Close Tab',
isEnabled: () =>
!!shell.currentWidget && !!shell.currentWidget.title.closable,
!!shell.currentWidget && shell.currentWidget.title.closable,
execute: () => {
if (shell.currentWidget) {
shell.currentWidget.close();
Expand Down Expand Up @@ -652,7 +654,7 @@ function addCommands(app: JupyterLab, palette: ICommandPalette): void {
});

app.commands.addCommand(CommandIDs.toggleLeftArea, {
label: args => 'Show Left Sidebar',
label: () => 'Show Left Sidebar',
execute: () => {
if (shell.leftCollapsed) {
shell.expandLeft();
Expand All @@ -669,7 +671,7 @@ function addCommands(app: JupyterLab, palette: ICommandPalette): void {
palette.addItem({ command: CommandIDs.toggleLeftArea, category });

app.commands.addCommand(CommandIDs.toggleRightArea, {
label: args => 'Show Right Sidebar',
label: () => 'Show Right Sidebar',
execute: () => {
if (shell.rightCollapsed) {
shell.expandRight();
Expand All @@ -686,7 +688,7 @@ function addCommands(app: JupyterLab, palette: ICommandPalette): void {
palette.addItem({ command: CommandIDs.toggleRightArea, category });

app.commands.addCommand(CommandIDs.togglePresentationMode, {
label: args => 'Presentation Mode',
label: () => 'Presentation Mode',
execute: () => {
shell.presentationMode = !shell.presentationMode;
},
Expand Down Expand Up @@ -799,7 +801,7 @@ const propertyInspector: JupyterFrontEndPlugin<IPropertyInspectorProvider> = {
provides: IPropertyInspectorProvider,
activate: (app: JupyterFrontEnd, labshell: ILabShell) => {
const widget = new SideBarPropertyInspectorProvider(labshell);
widget.title.iconClass = 'jp-BuildIcon jp-SideBar-tabIcon';
widget.title.iconRenderer = buildIcon;
widget.title.caption = 'Property Inspector';
widget.id = 'jp-property-inspector';
labshell.add(widget, 'left');
Expand Down
1 change: 1 addition & 0 deletions packages/application-extension/style/index.css
Expand Up @@ -5,6 +5,7 @@

/* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */
@import url('~@lumino/widgets/style/index.css');
@import url('~@jupyterlab/ui-components/style/index.css');
@import url('~@jupyterlab/application/style/index.css');
@import url('~@jupyterlab/property-inspector/style/index.css');

Expand Down
3 changes: 3 additions & 0 deletions packages/application-extension/tsconfig.json
Expand Up @@ -23,6 +23,9 @@
},
{
"path": "../statedb"
},
{
"path": "../ui-components"
}
]
}
31 changes: 24 additions & 7 deletions packages/application/src/shell.ts
Expand Up @@ -3,7 +3,7 @@

import { DocumentRegistry } from '@jupyterlab/docregistry';

import { DockPanelSvg, TabBarSvg } from '@jupyterlab/ui-components';
import { JLIcon } from '@jupyterlab/ui-components';

import { ArrayExt, find, IIterator, iter, toArray } from '@lumino/algorithm';

Expand Down Expand Up @@ -179,9 +179,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
let topHandler = (this._topHandler = new Private.PanelHandler());
let bottomPanel = (this._bottomPanel = new BoxPanel());
let hboxPanel = new BoxPanel();
let dockPanel = (this._dockPanel = new DockPanelSvg({
kind: 'dockPanelBar'
}));
let dockPanel = (this._dockPanel = new DockPanel());
MessageLoop.installMessageHook(dockPanel, this._dockChildHook);

let hsplitPanel = new SplitPanel();
Expand Down Expand Up @@ -745,9 +743,19 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
ref = find(dock.widgets(), value => value.id === options!.ref!) || null;
}

const { title } = widget;
// Add widget ID to tab so that we can get a handle on the tab's widget
// (for context menu support)
widget.title.dataset = { ...widget.title.dataset, id: widget.id };
title.dataset = { ...title.dataset, id: widget.id };

// set an appropriate style class for the iconRenderer
if (title.iconRenderer instanceof JLIcon) {
title.iconClass = title.iconRenderer.class({
className: title.iconClass,
center: true,
kind: 'mainAreaTab'
});
}

dock.addWidget(widget, { mode, ref });

Expand Down Expand Up @@ -1062,8 +1070,7 @@ namespace Private {
* Construct a new side bar handler.
*/
constructor() {
this._sideBar = new TabBarSvg<Widget>({
kind: 'sideBar',
this._sideBar = new TabBar<Widget>({
insertBehavior: 'none',
removeBehavior: 'none',
allowDeselect: true
Expand Down Expand Up @@ -1152,6 +1159,16 @@ namespace Private {
// Store the parent id in the title dataset
// in order to dispatch click events to the right widget.
title.dataset = { id: widget.id };

// set an appropriate style class for the iconRenderer
if (title.iconRenderer instanceof JLIcon) {
title.iconClass = title.iconRenderer.class({
className: title.iconClass,
center: true,
kind: 'sideBar'
});
}

this._refreshVisibility();
}

Expand Down
4 changes: 0 additions & 4 deletions packages/application/style/icons.css
Expand Up @@ -356,10 +356,6 @@
background-image: var(--jp-icon-settings);
}

.jp-TextEditorIcon {
background-image: var(--jp-icon-text-editor);
}

.jp-UndoIcon {
background-image: var(--jp-icon-undo);
}
Expand Down
6 changes: 0 additions & 6 deletions packages/application/style/tabs.css
Expand Up @@ -125,12 +125,6 @@
transform: translateX(-1px);
}

.p-DockPanel-tabBar .p-TabBar-tabIcon,
.p-DockPanel-tabBar .p-TabBar-tabLabel,
.p-DockPanel-tabBar .p-TabBar-tabCloseIcon {
display: inline-block;
}

.p-DockPanel-tabBar .p-TabBar-tab .p-TabBar-tabIcon,
.p-TabBar-tab.p-mod-drag-image .p-TabBar-tabIcon {
width: 14px;
Expand Down
7 changes: 3 additions & 4 deletions packages/apputils-extension/src/palette.ts
Expand Up @@ -4,15 +4,13 @@
|----------------------------------------------------------------------------*/

import { find } from '@lumino/algorithm';

import { CommandRegistry } from '@lumino/commands';
import { DisposableDelegate, IDisposable } from '@lumino/disposable';

import { CommandPalette } from '@lumino/widgets';

import { ILayoutRestorer, JupyterFrontEnd } from '@jupyterlab/application';

import { ICommandPalette, IPaletteItem } from '@jupyterlab/apputils';
import { paletteIcon } from '@jupyterlab/ui-components';

/**
* The command IDs used by the apputils extension.
Expand All @@ -31,7 +29,7 @@ export class Palette implements ICommandPalette {
*/
constructor(palette: CommandPalette) {
this._palette = palette;
this._palette.title.iconClass = 'jp-PaletteIcon jp-SideBar-tabIcon';
this._palette.title.iconRenderer = paletteIcon;
this._palette.title.label = '';
this._palette.title.caption = 'Command Palette';
}
Expand Down Expand Up @@ -145,6 +143,7 @@ namespace Private {
if (!palette) {
palette = new CommandPalette({ commands: app.commands });
palette.id = 'command-palette';
palette.title.iconRenderer = paletteIcon;
palette.title.label = 'Commands';
}

Expand Down
2 changes: 2 additions & 0 deletions packages/apputils/src/mainareawidget.ts
Expand Up @@ -179,6 +179,7 @@ export class MainAreaWidget<T extends Widget = Widget> extends Widget
this.title.mnemonic = content.title.mnemonic;
this.title.iconClass = content.title.iconClass;
this.title.iconLabel = content.title.iconLabel;
this.title.iconRenderer = content.title.iconRenderer;
this.title.caption = content.title.caption;
this.title.className = content.title.className;
this.title.dataset = content.title.dataset;
Expand All @@ -198,6 +199,7 @@ export class MainAreaWidget<T extends Widget = Widget> extends Widget
content.title.mnemonic = this.title.mnemonic;
content.title.iconClass = this.title.iconClass;
content.title.iconLabel = this.title.iconLabel;
content.title.iconRenderer = this.title.iconRenderer;
content.title.caption = this.title.caption;
content.title.className = this.title.className;
content.title.dataset = this.title.dataset;
Expand Down
14 changes: 6 additions & 8 deletions packages/coreutils/src/text.ts
Expand Up @@ -72,8 +72,8 @@ export namespace Text {
}

/**
* Given a 'snake-case', 'snake_case', or 'snake case' string,
* will return the camel case version: 'snakeCase'.
* Given a 'snake-case', 'snake_case', 'snake:case', or
* 'snake case' string, will return the camel case version: 'snakeCase'.
*
* @param str: the snake-case input string.
*
Expand All @@ -83,13 +83,11 @@ export namespace Text {
* @returns the camel case version of the input string.
*/
export function camelCase(str: string, upper: boolean = false): string {
return str.replace(/(?:^\w|[A-Z]|\b\w|\s+|-+|_+)/g, function(match, index) {
if (+match === 0 || match[0] === '-') {
return '';
} else if (index === 0 && !upper) {
return match.toLowerCase();
return str.replace(/^(\w)|[\s-_:]+(\w)/g, function(match, p1, p2) {
if (p2) {
return p2.toUpperCase();
} else {
return match.toUpperCase();
return upper ? p1.toUpperCase() : p1.toLowerCase();
}
});
}
Expand Down