From 0f809bb9e43ee4c42e083f9c9218fdaf9f1a2143 Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 7 Oct 2019 03:38:44 -0400 Subject: [PATCH 001/101] starting work on JLIcon, to be used as an icon class wrapper --- packages/ui-components/src/icon/index.ts | 1 + packages/ui-components/src/icon/jlicon.tsx | 90 ++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 packages/ui-components/src/icon/jlicon.tsx diff --git a/packages/ui-components/src/icon/index.ts b/packages/ui-components/src/icon/index.ts index c64a470388c7..17563d1a5285 100644 --- a/packages/ui-components/src/icon/index.ts +++ b/packages/ui-components/src/icon/index.ts @@ -2,6 +2,7 @@ // Distributed under the terms of the Modified BSD License. export * from './iconimports'; +export * from './jlicon'; export * from './iconregistry'; export * from './interfaces'; export * from './tabbarsvg'; diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx new file mode 100644 index 000000000000..a493a57cff12 --- /dev/null +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -0,0 +1,90 @@ +import React from 'react'; +import { classes } from 'typestyle'; +import { iconStyle, IIconStyle } from '../style/icon'; + +export class JLIcon< + P extends JLIcon.IProps & { tag?: 'div' | 'span' } = JLIcon.IProps & { + tag?: 'div' | 'span'; + }, + S extends JLIcon.IState = JLIcon.IState +> extends React.Component { + static resolveSvg(svgstr: string): HTMLElement | null { + const parser = new DOMParser(); + const svgElement = parser.parseFromString(svgstr, 'image/svg+xml') + .documentElement; + + if (svgElement.getElementsByTagName('parsererror').length > 0) { + const errmsg = `SVG HTML was malformed for icon name: ${name}`; + // parse failed, svgElement will be an error box + if (this._debug) { + // fail noisily, render the error box + console.error(errmsg); + return svgElement; + } else { + // bad svg is always a real error, fail silently but warn + console.warn(errmsg); + return null; + } + } else { + // parse succeeded + return svgElement; + } + } + + render() { + const { className, title, tag, ...propsStyle } = this.props; + const Tag: 'div' | 'span' = tag || 'div'; + + // // ensure that svg html is valid + // const svgElement = JLIcon.resolveSvg(this.props.svgstr); + // if (!svgElement) { + // // bail if failing silently + // return <>; + // } + + if (title) { + // TODO: reimplement setTitleSvg here + } + + return ( + + ); + } + + static _debug: boolean = false; +} + +/** + * A namespace for JLIcon statics. + */ +export namespace JLIcon { + /** + * The input props for creating a new JLIcon + */ + export interface IProps extends IIconStyle { + /** + * Extra classNames, used in addition to the typestyle className + */ + className?: string; + + svgstr: string; + + /** + * Icon title + */ + title?: string; + } + + export interface IProps {} + + /** + * The state for a JLIcon component + */ + export interface IState {} +} From efa1d4377e6653f67e22dc6fa01d2cd4468cc722 Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 7 Oct 2019 16:26:05 -0400 Subject: [PATCH 002/101] dynamically create JLIcon class within a function --- packages/ui-components/src/icon/jlicon.tsx | 69 +++++++++++----------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index a493a57cff12..29e7ad2ec8f8 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -2,13 +2,8 @@ import React from 'react'; import { classes } from 'typestyle'; import { iconStyle, IIconStyle } from '../style/icon'; -export class JLIcon< - P extends JLIcon.IProps & { tag?: 'div' | 'span' } = JLIcon.IProps & { - tag?: 'div' | 'span'; - }, - S extends JLIcon.IState = JLIcon.IState -> extends React.Component { - static resolveSvg(svgstr: string): HTMLElement | null { +export function createIcon(svgstr: string, debug: boolean = false) { + function resolveSvg(svgstr: string): HTMLElement | null { const parser = new DOMParser(); const svgElement = parser.parseFromString(svgstr, 'image/svg+xml') .documentElement; @@ -16,7 +11,7 @@ export class JLIcon< if (svgElement.getElementsByTagName('parsererror').length > 0) { const errmsg = `SVG HTML was malformed for icon name: ${name}`; // parse failed, svgElement will be an error box - if (this._debug) { + if (debug) { // fail noisily, render the error box console.error(errmsg); return svgElement; @@ -31,33 +26,39 @@ export class JLIcon< } } - render() { - const { className, title, tag, ...propsStyle } = this.props; - const Tag: 'div' | 'span' = tag || 'div'; - - // // ensure that svg html is valid - // const svgElement = JLIcon.resolveSvg(this.props.svgstr); - // if (!svgElement) { - // // bail if failing silently - // return <>; - // } + return class JLIcon< + P extends JLIcon.IProps = JLIcon.IProps, + S extends JLIcon.IState = JLIcon.IState + > extends React.Component { + render() { + const { className, title, tag, ...propsStyle } = this.props; + const Tag: 'div' | 'span' = tag || 'div'; - if (title) { - // TODO: reimplement setTitleSvg here - } + // ensure that svg html is valid + const svgElement = resolveSvg(svgstr); + if (!svgElement) { + // bail if failing silently + return <>; + } - return ( - - ); - } + if (title) { + // TODO: reimplement setTitleSvg here + } - static _debug: boolean = false; + return ( + + ); + } + }; } /** @@ -73,7 +74,7 @@ export namespace JLIcon { */ className?: string; - svgstr: string; + tag?: 'div' | 'span'; /** * Icon title @@ -81,8 +82,6 @@ export namespace JLIcon { title?: string; } - export interface IProps {} - /** * The state for a JLIcon component */ From 4f1638ce49c0ec704c02718e6a9210f1dc7c28dd Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 7 Oct 2019 16:48:58 -0400 Subject: [PATCH 003/101] added static JLIcon.element, returns an HTMLElement --- packages/ui-components/src/icon/jlicon.tsx | 53 ++++++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 29e7ad2ec8f8..9c24120a8458 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -4,8 +4,7 @@ import { iconStyle, IIconStyle } from '../style/icon'; export function createIcon(svgstr: string, debug: boolean = false) { function resolveSvg(svgstr: string): HTMLElement | null { - const parser = new DOMParser(); - const svgElement = parser.parseFromString(svgstr, 'image/svg+xml') + const svgElement = new DOMParser().parseFromString(svgstr, 'image/svg+xml') .documentElement; if (svgElement.getElementsByTagName('parsererror').length > 0) { @@ -42,7 +41,7 @@ export function createIcon(svgstr: string, debug: boolean = false) { } if (title) { - // TODO: reimplement setTitleSvg here + Private.setTitleSvg(svgElement, title); } return ( @@ -52,12 +51,42 @@ export function createIcon(svgstr: string, debug: boolean = false) { propsStyle ? iconStyle(propsStyle) : '' )} dangerouslySetInnerHTML={{ - __html: svgstr - // __html: svgElement.outerHTML + // __html: svgstr + __html: svgElement.outerHTML }} /> ); } + + /** + * Get the icon as an HTMLElement of tag + */ + static element({ + className, + title, + tag = 'div', + ...propsStyle + }: JLIcon.IProps): HTMLElement | null { + // ensure that svg html is valid + const svgElement = resolveSvg(svgstr); + if (!svgElement) { + // bail if failing silently + return null; + } + + if (title) { + Private.setTitleSvg(svgElement, title); + } + + const container = document.createElement(tag); + container.appendChild(svgElement); + container.className = classes( + className || '', + propsStyle ? iconStyle(propsStyle) : '' + ); + + return container; + } }; } @@ -87,3 +116,17 @@ export namespace JLIcon { */ export interface IState {} } + +namespace Private { + export function setTitleSvg(svgNode: HTMLElement, title: string): void { + // add a title node to the top level svg node + let titleNodes = svgNode.getElementsByTagName('title'); + if (titleNodes.length) { + titleNodes[0].textContent = title; + } else { + let titleNode = document.createElement('title'); + titleNode.textContent = title; + svgNode.appendChild(titleNode); + } + } +} From 8624db8f670b275cd6cab13a7dc7c593795fb94f Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 7 Oct 2019 18:04:35 -0400 Subject: [PATCH 004/101] set up ref forwarding in JLIcon --- packages/ui-components/src/icon/jlicon.tsx | 106 +++++++++++---------- 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 9c24120a8458..368210972bd7 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -2,8 +2,12 @@ import React from 'react'; import { classes } from 'typestyle'; import { iconStyle, IIconStyle } from '../style/icon'; -export function createIcon(svgstr: string, debug: boolean = false) { - function resolveSvg(svgstr: string): HTMLElement | null { +export function createIcon( + svgname: string, + svgstr: string, + debug: boolean = false +) { + function resolveSvg(svgstr: string, title?: string): HTMLElement | null { const svgElement = new DOMParser().parseFromString(svgstr, 'image/svg+xml') .documentElement; @@ -21,73 +25,73 @@ export function createIcon(svgstr: string, debug: boolean = false) { } } else { // parse succeeded + if (title) { + Private.setTitleSvg(svgElement, title); + } + return svgElement; } } - return class JLIcon< - P extends JLIcon.IProps = JLIcon.IProps, - S extends JLIcon.IState = JLIcon.IState - > extends React.Component { - render() { - const { className, title, tag, ...propsStyle } = this.props; - const Tag: 'div' | 'span' = tag || 'div'; + const _JLIcon = React.forwardRef( + (props: JLIcon.IProps, ref: React.RefObject) => { + const { className, title, tag = 'div', ...propsStyle } = props; + const Tag = tag; + const classNames = classes( + className, + propsStyle ? iconStyle(propsStyle) : '' + ); // ensure that svg html is valid - const svgElement = resolveSvg(svgstr); + const svgElement = resolveSvg(svgstr, title); if (!svgElement) { // bail if failing silently return <>; } - if (title) { - Private.setTitleSvg(svgElement, title); - } - return ( ); } + ); - /** - * Get the icon as an HTMLElement of tag - */ - static element({ - className, - title, - tag = 'div', - ...propsStyle - }: JLIcon.IProps): HTMLElement | null { - // ensure that svg html is valid - const svgElement = resolveSvg(svgstr); - if (!svgElement) { - // bail if failing silently - return null; - } - - if (title) { - Private.setTitleSvg(svgElement, title); - } + // widen type to include .element + let JLIcon: typeof _JLIcon & { + element: (props: JLIcon.IProps) => HTMLElement; + } = _JLIcon as any; - const container = document.createElement(tag); - container.appendChild(svgElement); - container.className = classes( - className || '', - propsStyle ? iconStyle(propsStyle) : '' - ); + JLIcon.element = ({ + className, + title, + tag = 'div', + ...propsStyle + }: JLIcon.IProps): HTMLElement | null => { + const classNames = classes( + className, + propsStyle ? iconStyle(propsStyle) : '' + ); - return container; + // ensure that svg html is valid + const svgElement = resolveSvg(svgstr, title); + if (!svgElement) { + // bail if failing silently + return null; } + + const container = document.createElement(tag); + container.appendChild(svgElement); + container.className = classNames; + return container; }; + + // set display name of JLIcon for debugging + JLIcon.displayName = `JLIcon_${svgname}`; + + return JLIcon; } /** @@ -130,3 +134,9 @@ namespace Private { } } } + +// import notTrustedSvg from '../../style/icons/statusbar/not-trusted.svg'; +// import trustedSvg from '../../style/icons/statusbar/trusted.svg'; +// +// export const NotTrustedIcon = createIcon('notTrusted', notTrustedSvg); +// export const TrustedIcon = createIcon('trusted', trustedSvg); From c3266263e08539e43338c7c94b7f3758190de6dc Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 7 Oct 2019 18:55:02 -0400 Subject: [PATCH 005/101] simplified typing of createIcon return type --- packages/ui-components/src/icon/jlicon.tsx | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 368210972bd7..59cd19409fe4 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -33,7 +33,7 @@ export function createIcon( } } - const _JLIcon = React.forwardRef( + const JLIcon: JLIcon.IComponent = React.forwardRef( (props: JLIcon.IProps, ref: React.RefObject) => { const { className, title, tag = 'div', ...propsStyle } = props; const Tag = tag; @@ -59,11 +59,6 @@ export function createIcon( } ); - // widen type to include .element - let JLIcon: typeof _JLIcon & { - element: (props: JLIcon.IProps) => HTMLElement; - } = _JLIcon as any; - JLIcon.element = ({ className, title, @@ -116,9 +111,12 @@ export namespace JLIcon { } /** - * The state for a JLIcon component + * The type of the react component-like object that gets + * returned by createIcon */ - export interface IState {} + export interface IComponent extends ReturnType { + element?: (props: IProps) => HTMLElement; + } } namespace Private { @@ -134,9 +132,3 @@ namespace Private { } } } - -// import notTrustedSvg from '../../style/icons/statusbar/not-trusted.svg'; -// import trustedSvg from '../../style/icons/statusbar/trusted.svg'; -// -// export const NotTrustedIcon = createIcon('notTrusted', notTrustedSvg); -// export const TrustedIcon = createIcon('trusted', trustedSvg); From f762440b9f19f7821b2a6c02644f330ef7f0b11c Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 7 Oct 2019 19:18:20 -0400 Subject: [PATCH 006/101] all of the wrapped icons now get autogenerated by `integrity` also had to revert the cleanup of createIcon's return type. The new way didn't work since some template parameters weren't specified --- buildutils/src/ensure-package.ts | 18 +++++++-- packages/notebook/src/truststatus.tsx | 8 ++-- .../ui-components/src/icon/iconimports.ts | 37 +++++++++++++++++++ packages/ui-components/src/icon/jlicon.tsx | 15 +++----- 4 files changed, 60 insertions(+), 18 deletions(-) diff --git a/buildutils/src/ensure-package.ts b/buildutils/src/ensure-package.ts index e764512769f4..f0293dd4747b 100644 --- a/buildutils/src/ensure-package.ts +++ b/buildutils/src/ensure-package.ts @@ -21,6 +21,7 @@ const HEADER_TEMPLATE = ` `; const ICON_IMPORTS_TEMPLATE = ` +import { createIcon } from './jlicon'; import { Icon } from './interfaces'; // icon svg import statements @@ -32,6 +33,9 @@ export namespace IconImports { {{iconModelDeclarations}} ]; } + +// wrapped icon definitions +{{wrappedIconDefs}} `; const ICON_CSS_CLASSES_TEMPLATE = ` @@ -369,6 +373,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 @@ -383,20 +388,25 @@ 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, true) + '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} = createIcon('${name}', ${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)); diff --git a/packages/notebook/src/truststatus.tsx b/packages/notebook/src/truststatus.tsx index 13241ca524e0..33e6fa84760a 100644 --- a/packages/notebook/src/truststatus.tsx +++ b/packages/notebook/src/truststatus.tsx @@ -6,7 +6,7 @@ import { INotebookModel, Notebook } from '.'; import { Cell } from '@jupyterlab/cells'; -import { DefaultIconReact } from '@jupyterlab/ui-components'; +import { NotTrustedIcon, TrustedIcon } from '@jupyterlab/ui-components'; import { toArray } from '@lumino/algorithm'; @@ -45,11 +45,9 @@ function NotebookTrustComponent( props: NotebookTrustComponent.IProps ): React.ReactElement { if (props.allCellsTrusted) { - return ; + return ; } else { - return ( - - ); + return ; } } diff --git a/packages/ui-components/src/icon/iconimports.ts b/packages/ui-components/src/icon/iconimports.ts index f77f056a98c2..6af0f0500858 100644 --- a/packages/ui-components/src/icon/iconimports.ts +++ b/packages/ui-components/src/icon/iconimports.ts @@ -5,6 +5,7 @@ /* This file was auto-generated by ensureUiComponents() in @jupyterlab/buildutils */ +import { createIcon } from './jlicon'; import { Icon } from './interfaces'; // icon svg import statements @@ -80,3 +81,39 @@ export namespace IconImports { { name: 'stop', svg: stopSvg } ]; } + +// wrapped icon definitions +export const FileIcon = createIcon('file', fileSvg); +export const FolderIcon = createIcon('folder', folderSvg); +export const Html5Icon = createIcon('html5', html5Svg); +export const ImageIcon = createIcon('image', imageSvg); +export const JsonIcon = createIcon('json', jsonSvg); +export const MarkdownIcon = createIcon('markdown', markdownSvg); +export const NotebookIcon = createIcon('notebook', notebookSvg); +export const PythonIcon = createIcon('python', pythonSvg); +export const RKernelIcon = createIcon('r-kernel', rKernelSvg); +export const ReactIcon = createIcon('react', reactSvg); +export const SpreadsheetIcon = createIcon('spreadsheet', spreadsheetSvg); +export const YamlIcon = createIcon('yaml', yamlSvg); +export const BuildIcon = createIcon('build', buildSvg); +export const ExtensionIcon = createIcon('extension', extensionSvg); +export const PaletteIcon = createIcon('palette', paletteSvg); +export const RunningIcon = createIcon('running', runningSvg); +export const TabIcon = createIcon('tab', tabSvg); +export const JupyterFaviconIcon = createIcon( + 'jupyter-favicon', + jupyterFaviconSvg +); +export const KernelIcon = createIcon('kernel', kernelSvg); +export const LineFormIcon = createIcon('line-form', lineFormSvg); +export const NotTrustedIcon = createIcon('not-trusted', notTrustedSvg); +export const TerminalIcon = createIcon('terminal', terminalSvg); +export const TrustedIcon = createIcon('trusted', trustedSvg); +export const AddIcon = createIcon('add', addSvg); +export const CopyIcon = createIcon('copy', copySvg); +export const CutIcon = createIcon('cut', cutSvg); +export const PasteIcon = createIcon('paste', pasteSvg); +export const RefreshIcon = createIcon('refresh', refreshSvg); +export const RunIcon = createIcon('run', runSvg); +export const SaveIcon = createIcon('save', saveSvg); +export const StopIcon = createIcon('stop', stopSvg); diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 59cd19409fe4..a207ff05bcb6 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -33,7 +33,7 @@ export function createIcon( } } - const JLIcon: JLIcon.IComponent = React.forwardRef( + const _JLIcon = React.forwardRef( (props: JLIcon.IProps, ref: React.RefObject) => { const { className, title, tag = 'div', ...propsStyle } = props; const Tag = tag; @@ -59,6 +59,11 @@ export function createIcon( } ); + // widen type to include .element + let JLIcon: typeof _JLIcon & { + element: (props: JLIcon.IProps) => HTMLElement; + } = _JLIcon as any; + JLIcon.element = ({ className, title, @@ -109,14 +114,6 @@ export namespace JLIcon { */ title?: string; } - - /** - * The type of the react component-like object that gets - * returned by createIcon - */ - export interface IComponent extends ReturnType { - element?: (props: IProps) => HTMLElement; - } } namespace Private { From 4539af97fb15f2352ec297cbe4a317342e212b9e Mon Sep 17 00:00:00 2001 From: telamonian Date: Wed, 9 Oct 2019 18:53:00 -0400 Subject: [PATCH 007/101] added explicitly declared return type to `createIcon` also added explicit types to the call to `React.forwardRef` within `createIcon` --- packages/ui-components/src/icon/jlicon.tsx | 28 +++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index a207ff05bcb6..2ae0f793fd13 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -1,4 +1,9 @@ -import React from 'react'; +import React, { + ForwardRefExoticComponent, + PropsWithoutRef, + RefAttributes, + RefObject +} from 'react'; import { classes } from 'typestyle'; import { iconStyle, IIconStyle } from '../style/icon'; @@ -6,7 +11,7 @@ export function createIcon( svgname: string, svgstr: string, debug: boolean = false -) { +): JLIcon.IComponent { function resolveSvg(svgstr: string, title?: string): HTMLElement | null { const svgElement = new DOMParser().parseFromString(svgstr, 'image/svg+xml') .documentElement; @@ -33,8 +38,11 @@ export function createIcon( } } - const _JLIcon = React.forwardRef( - (props: JLIcon.IProps, ref: React.RefObject) => { + const JLIcon: JLIcon.IComponent = React.forwardRef< + HTMLDivElement, + JLIcon.IProps + >( + (props: JLIcon.IProps, ref: RefObject): JSX.Element => { const { className, title, tag = 'div', ...propsStyle } = props; const Tag = tag; const classNames = classes( @@ -59,11 +67,6 @@ export function createIcon( } ); - // widen type to include .element - let JLIcon: typeof _JLIcon & { - element: (props: JLIcon.IProps) => HTMLElement; - } = _JLIcon as any; - JLIcon.element = ({ className, title, @@ -114,6 +117,13 @@ export namespace JLIcon { */ title?: string; } + + export interface IComponent + extends ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes + > { + element?: (props: IProps) => HTMLElement; + } } namespace Private { From 268905dc2763b91faa806a30f6013fb1c8b995cf Mon Sep 17 00:00:00 2001 From: telamonian Date: Fri, 11 Oct 2019 19:06:18 -0400 Subject: [PATCH 008/101] simplified createIcon function by refactoring it into JLIcon class individual icons are now instances of JLIcon class --- buildutils/src/ensure-package.ts | 6 +- packages/notebook/src/truststatus.tsx | 6 +- .../ui-components/src/icon/iconimports.ts | 66 +++++------ packages/ui-components/src/icon/jlicon.tsx | 107 ++++++++---------- 4 files changed, 88 insertions(+), 97 deletions(-) diff --git a/buildutils/src/ensure-package.ts b/buildutils/src/ensure-package.ts index f0293dd4747b..dba9009711fd 100644 --- a/buildutils/src/ensure-package.ts +++ b/buildutils/src/ensure-package.ts @@ -21,7 +21,7 @@ const HEADER_TEMPLATE = ` `; const ICON_IMPORTS_TEMPLATE = ` -import { createIcon } from './jlicon'; +import { JLIcon } from './jlicon'; import { Icon } from './interfaces'; // icon svg import statements @@ -389,12 +389,12 @@ export async function ensureUiComponents( } else { // load the icon svg using `import` const svgname = utils.camelCase(name) + 'Svg'; - const iconname = utils.camelCase(name, true) + 'Icon'; + const iconname = utils.camelCase(name) + 'Icon'; _iconImportStatements.push(`import ${svgname} from '${svgpath}';`); _iconModelDeclarations.push(`{ name: '${name}', svg: ${svgname} }`); _wrappedIconDefs.push( - `export const ${iconname} = createIcon('${name}', ${svgname});` + `export const ${iconname} = new JLIcon('${iconname}', ${svgname});` ); } }); diff --git a/packages/notebook/src/truststatus.tsx b/packages/notebook/src/truststatus.tsx index 33e6fa84760a..d6f265205a82 100644 --- a/packages/notebook/src/truststatus.tsx +++ b/packages/notebook/src/truststatus.tsx @@ -6,7 +6,7 @@ import { INotebookModel, Notebook } from '.'; import { Cell } from '@jupyterlab/cells'; -import { NotTrustedIcon, TrustedIcon } from '@jupyterlab/ui-components'; +import { notTrustedIcon, trustedIcon } from '@jupyterlab/ui-components'; import { toArray } from '@lumino/algorithm'; @@ -45,9 +45,9 @@ function NotebookTrustComponent( props: NotebookTrustComponent.IProps ): React.ReactElement { if (props.allCellsTrusted) { - return ; + return ; } else { - return ; + return ; } } diff --git a/packages/ui-components/src/icon/iconimports.ts b/packages/ui-components/src/icon/iconimports.ts index 6af0f0500858..4dff5c08f4d1 100644 --- a/packages/ui-components/src/icon/iconimports.ts +++ b/packages/ui-components/src/icon/iconimports.ts @@ -5,7 +5,7 @@ /* This file was auto-generated by ensureUiComponents() in @jupyterlab/buildutils */ -import { createIcon } from './jlicon'; +import { JLIcon } from './jlicon'; import { Icon } from './interfaces'; // icon svg import statements @@ -83,37 +83,37 @@ export namespace IconImports { } // wrapped icon definitions -export const FileIcon = createIcon('file', fileSvg); -export const FolderIcon = createIcon('folder', folderSvg); -export const Html5Icon = createIcon('html5', html5Svg); -export const ImageIcon = createIcon('image', imageSvg); -export const JsonIcon = createIcon('json', jsonSvg); -export const MarkdownIcon = createIcon('markdown', markdownSvg); -export const NotebookIcon = createIcon('notebook', notebookSvg); -export const PythonIcon = createIcon('python', pythonSvg); -export const RKernelIcon = createIcon('r-kernel', rKernelSvg); -export const ReactIcon = createIcon('react', reactSvg); -export const SpreadsheetIcon = createIcon('spreadsheet', spreadsheetSvg); -export const YamlIcon = createIcon('yaml', yamlSvg); -export const BuildIcon = createIcon('build', buildSvg); -export const ExtensionIcon = createIcon('extension', extensionSvg); -export const PaletteIcon = createIcon('palette', paletteSvg); -export const RunningIcon = createIcon('running', runningSvg); -export const TabIcon = createIcon('tab', tabSvg); -export const JupyterFaviconIcon = createIcon( - 'jupyter-favicon', +export const fileIcon = new JLIcon('fileIcon', fileSvg); +export const folderIcon = new JLIcon('folderIcon', folderSvg); +export const html5Icon = new JLIcon('html5Icon', html5Svg); +export const imageIcon = new JLIcon('imageIcon', imageSvg); +export const jsonIcon = new JLIcon('jsonIcon', jsonSvg); +export const markdownIcon = new JLIcon('markdownIcon', markdownSvg); +export const notebookIcon = new JLIcon('notebookIcon', notebookSvg); +export const pythonIcon = new JLIcon('pythonIcon', pythonSvg); +export const rKernelIcon = new JLIcon('rKernelIcon', rKernelSvg); +export const reactIcon = new JLIcon('reactIcon', reactSvg); +export const spreadsheetIcon = new JLIcon('spreadsheetIcon', spreadsheetSvg); +export const yamlIcon = new JLIcon('yamlIcon', yamlSvg); +export const buildIcon = new JLIcon('buildIcon', buildSvg); +export const extensionIcon = new JLIcon('extensionIcon', extensionSvg); +export const paletteIcon = new JLIcon('paletteIcon', paletteSvg); +export const runningIcon = new JLIcon('runningIcon', runningSvg); +export const tabIcon = new JLIcon('tabIcon', tabSvg); +export const jupyterFaviconIcon = new JLIcon( + 'jupyterFaviconIcon', jupyterFaviconSvg ); -export const KernelIcon = createIcon('kernel', kernelSvg); -export const LineFormIcon = createIcon('line-form', lineFormSvg); -export const NotTrustedIcon = createIcon('not-trusted', notTrustedSvg); -export const TerminalIcon = createIcon('terminal', terminalSvg); -export const TrustedIcon = createIcon('trusted', trustedSvg); -export const AddIcon = createIcon('add', addSvg); -export const CopyIcon = createIcon('copy', copySvg); -export const CutIcon = createIcon('cut', cutSvg); -export const PasteIcon = createIcon('paste', pasteSvg); -export const RefreshIcon = createIcon('refresh', refreshSvg); -export const RunIcon = createIcon('run', runSvg); -export const SaveIcon = createIcon('save', saveSvg); -export const StopIcon = createIcon('stop', stopSvg); +export const kernelIcon = new JLIcon('kernelIcon', kernelSvg); +export const lineFormIcon = new JLIcon('lineFormIcon', lineFormSvg); +export const notTrustedIcon = new JLIcon('notTrustedIcon', notTrustedSvg); +export const terminalIcon = new JLIcon('terminalIcon', terminalSvg); +export const trustedIcon = new JLIcon('trustedIcon', trustedSvg); +export const addIcon = new JLIcon('addIcon', addSvg); +export const copyIcon = new JLIcon('copyIcon', copySvg); +export const cutIcon = new JLIcon('cutIcon', cutSvg); +export const pasteIcon = new JLIcon('pasteIcon', pasteSvg); +export const refreshIcon = new JLIcon('refreshIcon', refreshSvg); +export const runIcon = new JLIcon('runIcon', runSvg); +export const saveIcon = new JLIcon('saveIcon', saveSvg); +export const stopIcon = new JLIcon('stopIcon', stopSvg); diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 2ae0f793fd13..a6c8ca30ef42 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -1,25 +1,24 @@ -import React, { - ForwardRefExoticComponent, - PropsWithoutRef, - RefAttributes, - RefObject -} from 'react'; +import React, { RefObject } from 'react'; import { classes } from 'typestyle'; import { iconStyle, IIconStyle } from '../style/icon'; -export function createIcon( - svgname: string, - svgstr: string, - debug: boolean = false -): JLIcon.IComponent { - function resolveSvg(svgstr: string, title?: string): HTMLElement | null { - const svgElement = new DOMParser().parseFromString(svgstr, 'image/svg+xml') - .documentElement; +export class JLIcon { + constructor( + readonly name: string, + readonly svgstr: string, + protected _debug: boolean = false + ) {} + + resolveSvg(title?: string): HTMLElement | null { + const svgElement = new DOMParser().parseFromString( + this.svgstr, + 'image/svg+xml' + ).documentElement; if (svgElement.getElementsByTagName('parsererror').length > 0) { const errmsg = `SVG HTML was malformed for icon name: ${name}`; // parse failed, svgElement will be an error box - if (debug) { + if (this._debug) { // fail noisily, render the error box console.error(errmsg); return svgElement; @@ -38,48 +37,19 @@ export function createIcon( } } - const JLIcon: JLIcon.IComponent = React.forwardRef< - HTMLDivElement, - JLIcon.IProps - >( - (props: JLIcon.IProps, ref: RefObject): JSX.Element => { - const { className, title, tag = 'div', ...propsStyle } = props; - const Tag = tag; - const classNames = classes( - className, - propsStyle ? iconStyle(propsStyle) : '' - ); - - // ensure that svg html is valid - const svgElement = resolveSvg(svgstr, title); - if (!svgElement) { - // bail if failing silently - return <>; - } - - return ( - - ); - } - ); - - JLIcon.element = ({ + element({ className, title, tag = 'div', ...propsStyle - }: JLIcon.IProps): HTMLElement | null => { + }: JLIcon.IProps): HTMLElement | null { const classNames = classes( className, propsStyle ? iconStyle(propsStyle) : '' ); // ensure that svg html is valid - const svgElement = resolveSvg(svgstr, title); + const svgElement = this.resolveSvg(title); if (!svgElement) { // bail if failing silently return null; @@ -89,12 +59,40 @@ export function createIcon( container.appendChild(svgElement); container.className = classNames; return container; - }; + } - // set display name of JLIcon for debugging - JLIcon.displayName = `JLIcon_${svgname}`; + get react() { + const component = React.forwardRef( + ( + { className, title, tag = 'div', ...propsStyle }: JLIcon.IProps, + ref: RefObject + ) => { + const Tag = tag; + const classNames = classes( + className, + propsStyle ? iconStyle(propsStyle) : '' + ); + + // ensure that svg html is valid + const svgElement = this.resolveSvg(title); + if (!svgElement) { + // bail if failing silently + return <>; + } + + return ( + + ); + } + ); - return JLIcon; + component.displayName = `JLIcon_${this.name}`; + return component; + } } /** @@ -117,13 +115,6 @@ export namespace JLIcon { */ title?: string; } - - export interface IComponent - extends ForwardRefExoticComponent< - PropsWithoutRef & RefAttributes - > { - element?: (props: IProps) => HTMLElement; - } } namespace Private { From d5b42f988d7de4fc11dc41e108f4b948986c32a7 Mon Sep 17 00:00:00 2001 From: telamonian Date: Fri, 11 Oct 2019 20:20:46 -0400 Subject: [PATCH 009/101] refactored JLIcon.react from accessor => property more efficient, since this way the component returned by .react is created only once (as part of the constructor) and cached. Need to be careful with future changes to JLIcon.constructor, as execution order of initializers is now important --- packages/ui-components/src/icon/jlicon.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index a6c8ca30ef42..3ba6270a9018 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -61,7 +61,7 @@ export class JLIcon { return container; } - get react() { + protected _initReact() { const component = React.forwardRef( ( { className, title, tag = 'div', ...propsStyle }: JLIcon.IProps, @@ -93,6 +93,10 @@ export class JLIcon { component.displayName = `JLIcon_${this.name}`; return component; } + + // NB: this._initReact() will be run after the property initializers + // defined by the constructor signature, but before the constructor body + readonly react = this._initReact(); } /** From b6c3b38fa4c6a0e89a456c9a40ad45106735194a Mon Sep 17 00:00:00 2001 From: telamonian Date: Fri, 11 Oct 2019 20:37:56 -0400 Subject: [PATCH 010/101] fixed up docstrings in JLIcon namespace --- packages/ui-components/src/icon/jlicon.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 3ba6270a9018..55bb7907d246 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -1,4 +1,4 @@ -import React, { RefObject } from 'react'; +import React from 'react'; import { classes } from 'typestyle'; import { iconStyle, IIconStyle } from '../style/icon'; @@ -65,7 +65,7 @@ export class JLIcon { const component = React.forwardRef( ( { className, title, tag = 'div', ...propsStyle }: JLIcon.IProps, - ref: RefObject + ref: React.RefObject ) => { const Tag = tag; const classNames = classes( @@ -108,14 +108,19 @@ export namespace JLIcon { */ export interface IProps extends IIconStyle { /** - * Extra classNames, used in addition to the typestyle className + * Extra classNames. Used in addition to the typestyle className to + * set the className of the icon's outermost container node */ className?: string; + /** + * HTML element tag of the icon's outermost node, which acts as a + * container for the actual svg node + */ tag?: 'div' | 'span'; /** - * Icon title + * Optional title that will be set on the icon's svg node */ title?: string; } From e75530c9117f74b0e24a1ecf246b6de72f3b2bac Mon Sep 17 00:00:00 2001 From: telamonian Date: Sat, 12 Oct 2019 02:54:42 -0400 Subject: [PATCH 011/101] experimenting with blending phosphor/react vdom --- packages/ui-components/package.json | 2 ++ packages/ui-components/src/icon/jlicon.tsx | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/ui-components/package.json b/packages/ui-components/package.json index 4b9c10a0e238..06e7edb699ce 100644 --- a/packages/ui-components/package.json +++ b/packages/ui-components/package.json @@ -42,6 +42,7 @@ "@lumino/virtualdom": "^1.2.1", "@lumino/widgets": "^1.9.4", "react": "~16.9.0", + "react-dom": "~16.9.0", "typestyle": "^2.0.4" }, "devDependencies": { @@ -50,6 +51,7 @@ "@storybook/addon-actions": "^5.2.5", "@storybook/react": "^5.2.5", "@types/react": "~16.9.16", + "@types/react-dom": "^16.9.4", "@types/webpack-env": "^1.14.1", "awesome-typescript-loader": "^5.2.1", "babel-loader": "^8.0.6", diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 55bb7907d246..8ee16751af03 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import ReactDOM from 'react-dom'; import { classes } from 'typestyle'; import { iconStyle, IIconStyle } from '../style/icon'; @@ -10,10 +11,11 @@ export class JLIcon { ) {} resolveSvg(title?: string): HTMLElement | null { - const svgElement = new DOMParser().parseFromString( + const svgDoc = new DOMParser().parseFromString( this.svgstr, 'image/svg+xml' - ).documentElement; + ); + const svgElement = svgDoc.documentElement; if (svgElement.getElementsByTagName('parsererror').length > 0) { const errmsg = `SVG HTML was malformed for icon name: ${name}`; @@ -61,6 +63,13 @@ export class JLIcon { return container; } + phosphor(props: JLIcon.IProps): JLIcon.IPhosphor { + return { + render: (host: HTMLElement) => + ReactDOM.render(, host) + }; + } + protected _initReact() { const component = React.forwardRef( ( @@ -124,6 +133,10 @@ export namespace JLIcon { */ title?: string; } + + export interface IPhosphor { + render: (host: HTMLElement) => void; + } } namespace Private { From 6c23a2d2fbb96bdb0bd286ee188c04d87cfd2a47 Mon Sep 17 00:00:00 2001 From: telamonian Date: Sat, 12 Oct 2019 20:04:00 -0400 Subject: [PATCH 012/101] all tabbar icons now rendered by blended react/phosphor vdom elements requires the changes in the phosphorjs/phosphor#437 PR --- packages/application/package.json | 1 - packages/application/src/shell.ts | 9 +--- packages/application/style/index.css | 1 - packages/application/tsconfig.json | 3 -- packages/apputils/src/mainareawidget.ts | 2 + packages/csvviewer-extension/src/index.ts | 2 + packages/docregistry/package.json | 1 + packages/docregistry/src/default.ts | 6 +++ packages/docregistry/src/mimedocument.ts | 1 + packages/docregistry/src/registry.ts | 51 ++++++++++++++------- packages/docregistry/style/index.css | 1 + packages/docregistry/tsconfig.json | 3 ++ packages/imageviewer-extension/src/index.ts | 1 + packages/markdownviewer/src/widget.ts | 1 + packages/notebook-extension/src/index.ts | 6 ++- packages/ui-components/src/icon/jlicon.tsx | 12 +++-- 16 files changed, 66 insertions(+), 35 deletions(-) diff --git a/packages/application/package.json b/packages/application/package.json index f18ed5eea7f0..822c819faec9 100644 --- a/packages/application/package.json +++ b/packages/application/package.json @@ -42,7 +42,6 @@ "@jupyterlab/rendermime-interfaces": "^2.0.0-alpha.4", "@jupyterlab/services": "^5.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/application": "^1.7.4", "@lumino/commands": "^1.9.0", diff --git a/packages/application/src/shell.ts b/packages/application/src/shell.ts index ed166cfab93d..50ba31cef8f2 100644 --- a/packages/application/src/shell.ts +++ b/packages/application/src/shell.ts @@ -3,8 +3,6 @@ import { DocumentRegistry } from '@jupyterlab/docregistry'; -import { DockPanelSvg, TabBarSvg } from '@jupyterlab/ui-components'; - import { ArrayExt, find, IIterator, iter, toArray } from '@lumino/algorithm'; import { PromiseDelegate, Token } from '@lumino/coreutils'; @@ -179,9 +177,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(); @@ -1086,8 +1082,7 @@ namespace Private { * Construct a new side bar handler. */ constructor() { - this._sideBar = new TabBarSvg({ - kind: 'sideBar', + this._sideBar = new TabBar({ insertBehavior: 'none', removeBehavior: 'none', allowDeselect: true diff --git a/packages/application/style/index.css b/packages/application/style/index.css index 532b4815aab1..9a0a1363305c 100644 --- a/packages/application/style/index.css +++ b/packages/application/style/index.css @@ -5,7 +5,6 @@ /* 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/apputils/style/index.css'); @import url('~@jupyterlab/docregistry/style/index.css'); @import url('~font-awesome/css/font-awesome.min.css'); diff --git a/packages/application/tsconfig.json b/packages/application/tsconfig.json index 08c7b34d8f4c..71a473f8c9fc 100644 --- a/packages/application/tsconfig.json +++ b/packages/application/tsconfig.json @@ -26,9 +26,6 @@ }, { "path": "../statedb" - }, - { - "path": "../ui-components" } ] } diff --git a/packages/apputils/src/mainareawidget.ts b/packages/apputils/src/mainareawidget.ts index e63a2374ddef..1f35a1f86d8c 100644 --- a/packages/apputils/src/mainareawidget.ts +++ b/packages/apputils/src/mainareawidget.ts @@ -179,6 +179,7 @@ export class MainAreaWidget extends Widget this.title.mnemonic = content.title.mnemonic; this.title.iconClass = content.title.iconClass; this.title.iconLabel = content.title.iconLabel; + this.title.iconPass = content.title.iconPass; this.title.caption = content.title.caption; this.title.className = content.title.className; this.title.dataset = content.title.dataset; @@ -198,6 +199,7 @@ export class MainAreaWidget extends Widget content.title.mnemonic = this.title.mnemonic; content.title.iconClass = this.title.iconClass; content.title.iconLabel = this.title.iconLabel; + content.title.iconPass = this.title.iconPass; content.title.caption = this.title.caption; content.title.className = this.title.className; content.title.dataset = this.title.dataset; diff --git a/packages/csvviewer-extension/src/index.ts b/packages/csvviewer-extension/src/index.ts index ad5845f50306..6b3d220993ab 100644 --- a/packages/csvviewer-extension/src/index.ts +++ b/packages/csvviewer-extension/src/index.ts @@ -130,6 +130,7 @@ function activateCsv( if (ft) { widget.title.iconClass = ft.iconClass!; widget.title.iconLabel = ft.iconLabel!; + widget.title.iconPass = ft.iconPass!; } // Set the theme for the new widget. widget.content.style = style; @@ -209,6 +210,7 @@ function activateTsv( if (ft) { widget.title.iconClass = ft.iconClass!; widget.title.iconLabel = ft.iconLabel!; + widget.title.iconPass = ft.iconPass!; } // Set the theme for the new widget. widget.content.style = style; diff --git a/packages/docregistry/package.json b/packages/docregistry/package.json index 3b7722ea7e99..5a76ad5bf2cd 100644 --- a/packages/docregistry/package.json +++ b/packages/docregistry/package.json @@ -43,6 +43,7 @@ "@jupyterlab/rendermime": "^2.0.0-alpha.4", "@jupyterlab/rendermime-interfaces": "^2.0.0-alpha.4", "@jupyterlab/services": "^5.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", diff --git a/packages/docregistry/src/default.ts b/packages/docregistry/src/default.ts index 9251a85525a9..6c09ab7192ff 100644 --- a/packages/docregistry/src/default.ts +++ b/packages/docregistry/src/default.ts @@ -389,6 +389,12 @@ export abstract class ABCWidgetFactory< // Create the new widget const widget = this.createNewWidget(context, source); + const ft = this._fileTypes[0]; + if (ft) { + widget.title.iconClass = ft.iconClass; + widget.title.iconLabel = ft.iconLabel; + widget.title.iconPass = ft.iconPass; + } // Add toolbar items let items: DocumentRegistry.IToolbarItem[]; if (this._toolbarFactory) { diff --git a/packages/docregistry/src/mimedocument.ts b/packages/docregistry/src/mimedocument.ts index 9341ee0cad0e..d1653820b11b 100644 --- a/packages/docregistry/src/mimedocument.ts +++ b/packages/docregistry/src/mimedocument.ts @@ -289,6 +289,7 @@ export class MimeDocumentFactory extends ABCWidgetFactory { content.title.iconClass = ft?.iconClass ?? ''; content.title.iconLabel = ft?.iconLabel ?? ''; + content.title.iconPass = ft.iconPass; const widget = new MimeDocument({ content, context }); diff --git a/packages/docregistry/src/registry.ts b/packages/docregistry/src/registry.ts index 95e8b04f2f0c..a365cbb21898 100644 --- a/packages/docregistry/src/registry.ts +++ b/packages/docregistry/src/registry.ts @@ -1,8 +1,6 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { Contents, Kernel } from '@jupyterlab/services'; - import { ArrayExt, ArrayIterator, @@ -34,6 +32,22 @@ import { IModelDB } from '@jupyterlab/observables'; import { IRenderMime } from '@jupyterlab/rendermime-interfaces'; +import { Contents, Kernel } from '@jupyterlab/services'; + +import { + fileIcon, + folderIcon, + imageIcon, + JLIcon, + jsonIcon, + markdownIcon, + notebookIcon, + pythonIcon, + rKernelIcon, + spreadsheetIcon, + yamlIcon +} from '@jupyterlab/ui-components'; + import { TextModelFactory } from './default'; /** @@ -1171,6 +1185,8 @@ export namespace DocumentRegistry { */ readonly iconLabel?: string; + readonly iconPass?: JLIcon.IPhosphor; + /** * The content type of the new file. */ @@ -1189,7 +1205,7 @@ export namespace DocumentRegistry { name: 'default', extensions: [], mimeTypes: [], - iconClass: 'jp-MaterialIcon jp-FileIcon', + iconPass: fileIcon.phosphor({ kind: 'dockPanelBar', center: true }), iconLabel: '', contentType: 'file', fileFormat: 'text' @@ -1240,7 +1256,7 @@ export namespace DocumentRegistry { extensions: ['.ipynb'], contentType: 'notebook', fileFormat: 'json', - iconClass: 'jp-MaterialIcon jp-NotebookIcon' + iconPass: notebookIcon.phosphor({ kind: 'dockPanelBar', center: true }) }; /** @@ -1252,7 +1268,7 @@ export namespace DocumentRegistry { extensions: [], mimeTypes: ['text/directory'], contentType: 'directory', - iconClass: 'jp-MaterialIcon jp-FolderIcon' + iconPass: folderIcon.phosphor({ kind: 'dockPanelBar', center: true }) }; /** @@ -1267,56 +1283,56 @@ export namespace DocumentRegistry { displayName: 'Markdown File', extensions: ['.md'], mimeTypes: ['text/markdown'], - iconClass: 'jp-MaterialIcon jp-MarkdownIcon' + iconPass: markdownIcon.phosphor({ kind: 'dockPanelBar', center: true }) }, { name: 'python', displayName: 'Python File', extensions: ['.py'], mimeTypes: ['text/x-python'], - iconClass: 'jp-MaterialIcon jp-PythonIcon' + iconPass: pythonIcon.phosphor({ kind: 'dockPanelBar', center: true }) }, { name: 'json', displayName: 'JSON File', extensions: ['.json'], mimeTypes: ['application/json'], - iconClass: 'jp-MaterialIcon jp-JsonIcon' + iconPass: jsonIcon.phosphor({ kind: 'dockPanelBar', center: true }) }, { name: 'csv', displayName: 'CSV File', extensions: ['.csv'], mimeTypes: ['text/csv'], - iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon' + iconPass: spreadsheetIcon.phosphor({ kind: 'dockPanelBar', center: true }) }, { name: 'tsv', displayName: 'TSV File', extensions: ['.tsv'], mimeTypes: ['text/csv'], - iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon' + iconPass: spreadsheetIcon.phosphor({ kind: 'dockPanelBar', center: true }) }, { name: 'r', displayName: 'R File', mimeTypes: ['text/x-rsrc'], extensions: ['.r'], - iconClass: 'jp-MaterialIcon jp-RKernelIcon' + iconPass: rKernelIcon.phosphor({ kind: 'dockPanelBar', center: true }) }, { name: 'yaml', displayName: 'YAML File', mimeTypes: ['text/x-yaml', 'text/yaml'], extensions: ['.yaml', '.yml'], - iconClass: 'jp-MaterialIcon jp-YamlIcon' + iconPass: yamlIcon.phosphor({ kind: 'dockPanelBar', center: true }) }, { name: 'svg', displayName: 'Image', mimeTypes: ['image/svg+xml'], extensions: ['.svg'], - iconClass: 'jp-MaterialIcon jp-ImageIcon', + iconPass: imageIcon.phosphor({ kind: 'dockPanelBar', center: true }), fileFormat: 'base64' }, { @@ -1325,6 +1341,7 @@ export namespace DocumentRegistry { mimeTypes: ['image/tiff'], extensions: ['.tif', '.tiff'], iconClass: 'jp-MaterialIcon jp-ImageIcon', + iconPass: imageIcon.phosphor({ kind: 'dockPanelBar', center: true }), fileFormat: 'base64' }, { @@ -1332,7 +1349,7 @@ export namespace DocumentRegistry { displayName: 'Image', mimeTypes: ['image/jpeg'], extensions: ['.jpg', '.jpeg'], - iconClass: 'jp-MaterialIcon jp-ImageIcon', + iconPass: imageIcon.phosphor({ kind: 'dockPanelBar', center: true }), fileFormat: 'base64' }, { @@ -1340,7 +1357,7 @@ export namespace DocumentRegistry { displayName: 'Image', mimeTypes: ['image/gif'], extensions: ['.gif'], - iconClass: 'jp-MaterialIcon jp-ImageIcon', + iconPass: imageIcon.phosphor({ kind: 'dockPanelBar', center: true }), fileFormat: 'base64' }, { @@ -1348,7 +1365,7 @@ export namespace DocumentRegistry { displayName: 'Image', mimeTypes: ['image/png'], extensions: ['.png'], - iconClass: 'jp-MaterialIcon jp-ImageIcon', + iconPass: imageIcon.phosphor({ kind: 'dockPanelBar', center: true }), fileFormat: 'base64' }, { @@ -1356,7 +1373,7 @@ export namespace DocumentRegistry { displayName: 'Image', mimeTypes: ['image/bmp'], extensions: ['.bmp'], - iconClass: 'jp-MaterialIcon jp-ImageIcon', + iconPass: imageIcon.phosphor({ kind: 'dockPanelBar', center: true }), fileFormat: 'base64' } ]; diff --git a/packages/docregistry/style/index.css b/packages/docregistry/style/index.css index a0544f8765dc..4f80f4f9b81e 100644 --- a/packages/docregistry/style/index.css +++ b/packages/docregistry/style/index.css @@ -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/apputils/style/index.css'); @import url('./base.css'); diff --git a/packages/docregistry/tsconfig.json b/packages/docregistry/tsconfig.json index d23fa25fb132..9aa421935fa8 100644 --- a/packages/docregistry/tsconfig.json +++ b/packages/docregistry/tsconfig.json @@ -29,6 +29,9 @@ }, { "path": "../services" + }, + { + "path": "../ui-components" } ] } diff --git a/packages/imageviewer-extension/src/index.ts b/packages/imageviewer-extension/src/index.ts index 1c05a8249242..d6826af3430c 100644 --- a/packages/imageviewer-extension/src/index.ts +++ b/packages/imageviewer-extension/src/index.ts @@ -107,6 +107,7 @@ function activate( if (types.length > 0) { widget.title.iconClass = types[0].iconClass ?? ''; widget.title.iconLabel = types[0].iconLabel ?? ''; + widget.title.iconPass = types[0].iconPass; } }); diff --git a/packages/markdownviewer/src/widget.ts b/packages/markdownviewer/src/widget.ts index ed7bd542fdc3..0df5be1a95e9 100644 --- a/packages/markdownviewer/src/widget.ts +++ b/packages/markdownviewer/src/widget.ts @@ -311,6 +311,7 @@ export class MarkdownViewerFactory extends ABCWidgetFactory { const content = new MarkdownViewer({ context, renderer }); content.title.iconClass = this._fileType?.iconClass ?? ''; content.title.iconLabel = this._fileType?.iconLabel ?? ''; + content.title.iconPass = this._fileType.iconPass; const widget = new MarkdownDocument({ content, context }); return widget; diff --git a/packages/notebook-extension/src/index.ts b/packages/notebook-extension/src/index.ts index 75ef64fe1e95..821770f2fa6f 100644 --- a/packages/notebook-extension/src/index.ts +++ b/packages/notebook-extension/src/index.ts @@ -569,10 +569,14 @@ function activateNotebookHandler( let id = 0; // The ID counter for notebook panels. + let ft = app.docRegistry.getFileType('notebook'); + factory.widgetCreated.connect((sender, widget) => { // If the notebook panel does not have an ID, assign it one. widget.id = widget.id || `notebook-${++id}`; - widget.title.icon = NOTEBOOK_ICON_CLASS; + widget.title.iconClass = ft.iconClass; + widget.title.iconLabel = ft.iconLabel; + widget.title.iconPass = ft.iconPass; // Notify the widget tracker if restore data needs to update. widget.context.pathChanged.connect(() => { void tracker.save(widget); diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 8ee16751af03..8c191a8eaa38 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -44,7 +44,7 @@ export class JLIcon { title, tag = 'div', ...propsStyle - }: JLIcon.IProps): HTMLElement | null { + }: JLIcon.IProps = {}): HTMLElement | null { const classNames = classes( className, propsStyle ? iconStyle(propsStyle) : '' @@ -63,17 +63,19 @@ export class JLIcon { return container; } - phosphor(props: JLIcon.IProps): JLIcon.IPhosphor { + phosphor(props: JLIcon.IProps = {}): JLIcon.IPhosphor { return { - render: (host: HTMLElement) => - ReactDOM.render(, host) + render: (host: HTMLElement, innerProps: JLIcon.IProps = {}) => { + const comb = { ...props, ...innerProps }; + return ReactDOM.render(, host); + } }; } protected _initReact() { const component = React.forwardRef( ( - { className, title, tag = 'div', ...propsStyle }: JLIcon.IProps, + { className, title, tag = 'div', ...propsStyle }: JLIcon.IProps = {}, ref: React.RefObject ) => { const Tag = tag; From 536d45ed48f381b7648a176cb833c6f5208efbf1 Mon Sep 17 00:00:00 2001 From: telamonian Date: Sat, 12 Oct 2019 23:57:56 -0400 Subject: [PATCH 013/101] fixed sidebar tab icons; styling still isn't right currently can't use two different styles for tab icons passed to phosphor. Also in this commit: an experiment in constructing a bare svg react component from a raw string (contained in jlicon.tsx) --- packages/docregistry/src/default.ts | 6 ---- packages/tabmanager-extension/src/index.ts | 9 ++--- packages/ui-components/src/icon/jlicon.tsx | 41 ++++++++++++++++++++-- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/packages/docregistry/src/default.ts b/packages/docregistry/src/default.ts index 6c09ab7192ff..9251a85525a9 100644 --- a/packages/docregistry/src/default.ts +++ b/packages/docregistry/src/default.ts @@ -389,12 +389,6 @@ export abstract class ABCWidgetFactory< // Create the new widget const widget = this.createNewWidget(context, source); - const ft = this._fileTypes[0]; - if (ft) { - widget.title.iconClass = ft.iconClass; - widget.title.iconLabel = ft.iconLabel; - widget.title.iconPass = ft.iconPass; - } // Add toolbar items let items: DocumentRegistry.IToolbarItem[]; if (this._toolbarFactory) { diff --git a/packages/tabmanager-extension/src/index.ts b/packages/tabmanager-extension/src/index.ts index 567965d3f6e0..c55253e542d6 100644 --- a/packages/tabmanager-extension/src/index.ts +++ b/packages/tabmanager-extension/src/index.ts @@ -8,11 +8,9 @@ import { JupyterFrontEndPlugin } from '@jupyterlab/application'; -import { TabBarSvg } from '@jupyterlab/ui-components'; - import { each } from '@lumino/algorithm'; -import { Widget } from '@lumino/widgets'; +import { TabBar, Widget } from '@lumino/widgets'; /** * The default tab manager extension. @@ -25,10 +23,7 @@ const plugin: JupyterFrontEndPlugin = { restorer: ILayoutRestorer | null ): void => { const { shell } = app; - const tabs = new TabBarSvg({ - kind: 'tabManager', - orientation: 'vertical' - }); + const tabs = new TabBar({ orientation: 'vertical' }); const header = document.createElement('header'); if (restorer) { diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 8c191a8eaa38..b189b5847194 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -41,6 +41,7 @@ export class JLIcon { element({ className, + container, title, tag = 'div', ...propsStyle @@ -57,7 +58,7 @@ export class JLIcon { return null; } - const container = document.createElement(tag); + container = container || document.createElement(tag); container.appendChild(svgElement); container.className = classNames; return container; @@ -73,9 +74,44 @@ export class JLIcon { } protected _initReact() { + // const component = React.forwardRef( + // ( + // { className, container, title, tag = 'div', ...propsStyle }: JLIcon.IProps = {}, + // ref: React.RefObject + // ) => { + // // const Tag = tag; + // // const classNames = classes( + // // className, + // // propsStyle ? iconStyle(propsStyle) : '' + // // ); + // + // // ensure that svg html is valid + // const svgElement = this.resolveSvg(title); + // if (!svgElement) { + // // bail if failing silently + // return <>; + // } + // + // const attrs = svgElement.getAttributeNames().reduce((d, name) => {d[name] = svgElement.getAttribute(name); return d}, ({} as any)); + // + // return ( + // + // ); + // } + // ); + const component = React.forwardRef( ( - { className, title, tag = 'div', ...propsStyle }: JLIcon.IProps = {}, + { + className, + container, + title, + tag = 'div', + ...propsStyle + }: JLIcon.IProps = {}, ref: React.RefObject ) => { const Tag = tag; @@ -124,6 +160,7 @@ export namespace JLIcon { */ className?: string; + container?: HTMLElement; /** * HTML element tag of the icon's outermost node, which acts as a * container for the actual svg node From 0277f0425f643f9ab76d473f2206bd91f176955d Mon Sep 17 00:00:00 2001 From: telamonian Date: Sun, 13 Oct 2019 00:02:28 -0400 Subject: [PATCH 014/101] integrity --- packages/tabmanager-extension/package.json | 1 - packages/tabmanager-extension/style/index.css | 1 - packages/tabmanager-extension/tsconfig.json | 3 -- packages/ui-components/src/icon/jlicon.tsx | 29 ------------------- 4 files changed, 34 deletions(-) diff --git a/packages/tabmanager-extension/package.json b/packages/tabmanager-extension/package.json index bd75e9eee4d0..67554909e2ea 100644 --- a/packages/tabmanager-extension/package.json +++ b/packages/tabmanager-extension/package.json @@ -36,7 +36,6 @@ }, "dependencies": { "@jupyterlab/application": "^2.0.0-alpha.4", - "@jupyterlab/ui-components": "^2.0.0-alpha.4", "@lumino/algorithm": "^1.2.1", "@lumino/widgets": "^1.9.4" }, diff --git a/packages/tabmanager-extension/style/index.css b/packages/tabmanager-extension/style/index.css index bd9f8cebad79..8fe68ab59e76 100644 --- a/packages/tabmanager-extension/style/index.css +++ b/packages/tabmanager-extension/style/index.css @@ -5,6 +5,5 @@ /* 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('./base.css'); diff --git a/packages/tabmanager-extension/tsconfig.json b/packages/tabmanager-extension/tsconfig.json index e390491760f2..f923db8c1492 100644 --- a/packages/tabmanager-extension/tsconfig.json +++ b/packages/tabmanager-extension/tsconfig.json @@ -8,9 +8,6 @@ "references": [ { "path": "../application" - }, - { - "path": "../ui-components" } ] } diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index b189b5847194..d335fbc7c17c 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -74,35 +74,6 @@ export class JLIcon { } protected _initReact() { - // const component = React.forwardRef( - // ( - // { className, container, title, tag = 'div', ...propsStyle }: JLIcon.IProps = {}, - // ref: React.RefObject - // ) => { - // // const Tag = tag; - // // const classNames = classes( - // // className, - // // propsStyle ? iconStyle(propsStyle) : '' - // // ); - // - // // ensure that svg html is valid - // const svgElement = this.resolveSvg(title); - // if (!svgElement) { - // // bail if failing silently - // return <>; - // } - // - // const attrs = svgElement.getAttributeNames().reduce((d, name) => {d[name] = svgElement.getAttribute(name); return d}, ({} as any)); - // - // return ( - // - // ); - // } - // ); - const component = React.forwardRef( ( { From 4e2df2ff33d073e85870319b501efdab03535f32 Mon Sep 17 00:00:00 2001 From: telamonian Date: Sun, 13 Oct 2019 22:43:46 -0400 Subject: [PATCH 015/101] fixing up the text editor icon --- packages/application/style/icons.css | 4 ---- packages/docregistry/src/registry.ts | 1 + packages/fileeditor-extension/src/index.ts | 4 +--- packages/fileeditor/src/widget.ts | 22 +++++++++++++------ .../icons/md/ic_format_align_left_24px.svg | 1 - .../md/ic_format_align_left_24px_selected.svg | 1 - packages/theme-dark-extension/style/urls.css | 2 -- .../md/ic_format_align_left_24px_selected.svg | 1 - packages/theme-light-extension/style/urls.css | 2 -- .../filetype}/ic_format_align_left_24px.svg | 0 10 files changed, 17 insertions(+), 21 deletions(-) delete mode 100644 packages/theme-dark-extension/style/icons/md/ic_format_align_left_24px.svg delete mode 100644 packages/theme-dark-extension/style/icons/md/ic_format_align_left_24px_selected.svg delete mode 100644 packages/theme-light-extension/style/icons/md/ic_format_align_left_24px_selected.svg rename packages/{theme-light-extension/style/icons/md => ui-components/style/icons/filetype}/ic_format_align_left_24px.svg (100%) diff --git a/packages/application/style/icons.css b/packages/application/style/icons.css index 26129c287e68..8969380d8f52 100644 --- a/packages/application/style/icons.css +++ b/packages/application/style/icons.css @@ -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); } diff --git a/packages/docregistry/src/registry.ts b/packages/docregistry/src/registry.ts index a365cbb21898..8b89f2e8d09e 100644 --- a/packages/docregistry/src/registry.ts +++ b/packages/docregistry/src/registry.ts @@ -1205,6 +1205,7 @@ export namespace DocumentRegistry { name: 'default', extensions: [], mimeTypes: [], + iconClass: '', iconPass: fileIcon.phosphor({ kind: 'dockPanelBar', center: true }), iconLabel: '', contentType: 'file', diff --git a/packages/fileeditor-extension/src/index.ts b/packages/fileeditor-extension/src/index.ts index 15efe8fe0ae1..3f81148ccb6b 100644 --- a/packages/fileeditor-extension/src/index.ts +++ b/packages/fileeditor-extension/src/index.ts @@ -40,7 +40,7 @@ import { JSONObject } from '@lumino/coreutils'; import { Menu } from '@lumino/widgets'; -import { Commands, EDITOR_ICON_CLASS, FACTORY } from './commands'; +import { Commands, FACTORY } from './commands'; export { Commands } from './commands'; @@ -205,8 +205,6 @@ function activate( }); factory.widgetCreated.connect((sender, widget) => { - widget.title.icon = EDITOR_ICON_CLASS; - // Notify the widget tracker if restore data needs to update. widget.context.pathChanged.connect(() => { void tracker.save(widget); diff --git a/packages/fileeditor/src/widget.ts b/packages/fileeditor/src/widget.ts index c6b4a25662dd..3edddc6ae2a8 100644 --- a/packages/fileeditor/src/widget.ts +++ b/packages/fileeditor/src/widget.ts @@ -1,7 +1,12 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { StackedLayout, Widget } from '@lumino/widgets'; +import { + CodeEditor, + CodeEditorWrapper, + IEditorServices, + IEditorMimeTypeService +} from '@jupyterlab/codeeditor'; import { ABCWidgetFactory, @@ -10,17 +15,14 @@ import { IDocumentWidget } from '@jupyterlab/docregistry'; -import { - CodeEditor, - IEditorServices, - IEditorMimeTypeService, - CodeEditorWrapper -} from '@jupyterlab/codeeditor'; +import { fileIcon } from '@jupyterlab/ui-components'; import { PromiseDelegate } from '@lumino/coreutils'; import { Message } from '@lumino/messaging'; +import { StackedLayout, Widget } from '@lumino/widgets'; + /** * The data attribute added to a widget that can run code. */ @@ -323,6 +325,12 @@ export class FileEditorFactory extends ABCWidgetFactory< context, mimeTypeService: this._services.mimeTypeService }); + + content.title.iconPass = fileIcon.phosphor({ + kind: 'dockPanelBar', + center: true + }); + const widget = new DocumentWidget({ content, context }); return widget; } diff --git a/packages/theme-dark-extension/style/icons/md/ic_format_align_left_24px.svg b/packages/theme-dark-extension/style/icons/md/ic_format_align_left_24px.svg deleted file mode 100644 index 0a75e3d0c5e5..000000000000 --- a/packages/theme-dark-extension/style/icons/md/ic_format_align_left_24px.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/theme-dark-extension/style/icons/md/ic_format_align_left_24px_selected.svg b/packages/theme-dark-extension/style/icons/md/ic_format_align_left_24px_selected.svg deleted file mode 100644 index ad40e674fa85..000000000000 --- a/packages/theme-dark-extension/style/icons/md/ic_format_align_left_24px_selected.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/theme-dark-extension/style/urls.css b/packages/theme-dark-extension/style/urls.css index fc1e2f5ba40d..25027d89e984 100644 --- a/packages/theme-dark-extension/style/urls.css +++ b/packages/theme-dark-extension/style/urls.css @@ -70,8 +70,6 @@ --jp-icon-settings-selected: url('icons/md/ic_settings_24px_selected.svg'); --jp-icon-settings: url('icons/md/ic_settings_24px.svg'); --jp-icon-stop-circle: url('icons/md/stop-circle.svg'); - --jp-icon-text-editor-selected: url('icons/md/ic_format_align_left_24px_selected.svg'); - --jp-icon-text-editor: url('icons/md/ic_format_align_left_24px.svg'); --jp-icon-undo: url('icons/md/undo.svg'); --jp-icon-vega: url('icons/jupyter/vega.svg'); } diff --git a/packages/theme-light-extension/style/icons/md/ic_format_align_left_24px_selected.svg b/packages/theme-light-extension/style/icons/md/ic_format_align_left_24px_selected.svg deleted file mode 100644 index ad40e674fa85..000000000000 --- a/packages/theme-light-extension/style/icons/md/ic_format_align_left_24px_selected.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/theme-light-extension/style/urls.css b/packages/theme-light-extension/style/urls.css index 36c5c3841128..1f0cd0ab6a20 100644 --- a/packages/theme-light-extension/style/urls.css +++ b/packages/theme-light-extension/style/urls.css @@ -70,8 +70,6 @@ --jp-icon-settings-selected: url('icons/md/ic_settings_24px_selected.svg'); --jp-icon-settings: url('icons/md/ic_settings_24px.svg'); --jp-icon-stop-circle: url('icons/md/stop-circle.svg'); - --jp-icon-text-editor-selected: url('icons/md/ic_format_align_left_24px_selected.svg'); - --jp-icon-text-editor: url('icons/md/ic_format_align_left_24px.svg'); --jp-icon-undo: url('icons/md/undo.svg'); --jp-icon-vega: url('icons/jupyter/vega.svg'); } diff --git a/packages/theme-light-extension/style/icons/md/ic_format_align_left_24px.svg b/packages/ui-components/style/icons/filetype/ic_format_align_left_24px.svg similarity index 100% rename from packages/theme-light-extension/style/icons/md/ic_format_align_left_24px.svg rename to packages/ui-components/style/icons/filetype/ic_format_align_left_24px.svg From 768125ba09d2d58cbf8355e6a30f186fac61d031 Mon Sep 17 00:00:00 2001 From: telamonian Date: Sun, 13 Oct 2019 22:44:57 -0400 Subject: [PATCH 016/101] fixed text editor icon name --- .../filetype/{ic_format_align_left_24px.svg => text-editor.svg} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/ui-components/style/icons/filetype/{ic_format_align_left_24px.svg => text-editor.svg} (100%) diff --git a/packages/ui-components/style/icons/filetype/ic_format_align_left_24px.svg b/packages/ui-components/style/icons/filetype/text-editor.svg similarity index 100% rename from packages/ui-components/style/icons/filetype/ic_format_align_left_24px.svg rename to packages/ui-components/style/icons/filetype/text-editor.svg From cbd67300b2efd3ff7a48c345023b58a12c5d3e75 Mon Sep 17 00:00:00 2001 From: telamonian Date: Sun, 13 Oct 2019 23:36:57 -0400 Subject: [PATCH 017/101] progress fixing text editor icon --- packages/fileeditor/package.json | 1 + packages/fileeditor/src/widget.ts | 4 ++-- packages/fileeditor/tsconfig.json | 3 +++ packages/ui-components/src/icon/iconimports.ts | 3 +++ packages/ui-components/style/deprecated.css | 4 ++++ packages/ui-components/style/deprecatedExtra.css | 1 + .../ui-components/style/icons/filetype/text-editor.svg | 8 +++++++- 7 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/fileeditor/package.json b/packages/fileeditor/package.json index 58d919c28b0f..1c28250a4e01 100644 --- a/packages/fileeditor/package.json +++ b/packages/fileeditor/package.json @@ -39,6 +39,7 @@ "@jupyterlab/codeeditor": "^2.0.0-alpha.4", "@jupyterlab/docregistry": "^2.0.0-alpha.4", "@jupyterlab/statusbar": "^2.0.0-alpha.4", + "@jupyterlab/ui-components": "^2.0.0-alpha.4", "@lumino/coreutils": "^1.4.0", "@lumino/messaging": "^1.3.1", "@lumino/widgets": "^1.9.4", diff --git a/packages/fileeditor/src/widget.ts b/packages/fileeditor/src/widget.ts index 3edddc6ae2a8..c2a3c8fe0eb6 100644 --- a/packages/fileeditor/src/widget.ts +++ b/packages/fileeditor/src/widget.ts @@ -15,7 +15,7 @@ import { IDocumentWidget } from '@jupyterlab/docregistry'; -import { fileIcon } from '@jupyterlab/ui-components'; +import { textEditorIcon } from '@jupyterlab/ui-components'; import { PromiseDelegate } from '@lumino/coreutils'; @@ -326,7 +326,7 @@ export class FileEditorFactory extends ABCWidgetFactory< mimeTypeService: this._services.mimeTypeService }); - content.title.iconPass = fileIcon.phosphor({ + content.title.iconPass = textEditorIcon.phosphor({ kind: 'dockPanelBar', center: true }); diff --git a/packages/fileeditor/tsconfig.json b/packages/fileeditor/tsconfig.json index daa66686b54d..eb2b73b1fb94 100644 --- a/packages/fileeditor/tsconfig.json +++ b/packages/fileeditor/tsconfig.json @@ -17,6 +17,9 @@ }, { "path": "../statusbar" + }, + { + "path": "../ui-components" } ] } diff --git a/packages/ui-components/src/icon/iconimports.ts b/packages/ui-components/src/icon/iconimports.ts index 4dff5c08f4d1..2779a19751e4 100644 --- a/packages/ui-components/src/icon/iconimports.ts +++ b/packages/ui-components/src/icon/iconimports.ts @@ -20,6 +20,7 @@ import pythonSvg from '../../style/icons/filetype/python.svg'; import rKernelSvg from '../../style/icons/filetype/r-kernel.svg'; import reactSvg from '../../style/icons/filetype/react.svg'; import spreadsheetSvg from '../../style/icons/filetype/spreadsheet.svg'; +import textEditorSvg from '../../style/icons/filetype/text-editor.svg'; import yamlSvg from '../../style/icons/filetype/yaml.svg'; import buildSvg from '../../style/icons/sidebar/build.svg'; import extensionSvg from '../../style/icons/sidebar/extension.svg'; @@ -57,6 +58,7 @@ export namespace IconImports { { name: 'r-kernel', svg: rKernelSvg }, { name: 'react', svg: reactSvg }, { name: 'spreadsheet', svg: spreadsheetSvg }, + { name: 'text-editor', svg: textEditorSvg }, { name: 'yaml', svg: yamlSvg }, { name: 'build', svg: buildSvg }, { name: 'extension', svg: extensionSvg }, @@ -94,6 +96,7 @@ export const pythonIcon = new JLIcon('pythonIcon', pythonSvg); export const rKernelIcon = new JLIcon('rKernelIcon', rKernelSvg); export const reactIcon = new JLIcon('reactIcon', reactSvg); export const spreadsheetIcon = new JLIcon('spreadsheetIcon', spreadsheetSvg); +export const textEditorIcon = new JLIcon('textEditorIcon', textEditorSvg); export const yamlIcon = new JLIcon('yamlIcon', yamlSvg); export const buildIcon = new JLIcon('buildIcon', buildSvg); export const extensionIcon = new JLIcon('extensionIcon', extensionSvg); diff --git a/packages/ui-components/style/deprecated.css b/packages/ui-components/style/deprecated.css index 5c1dc7f90a59..a1dd84b259be 100644 --- a/packages/ui-components/style/deprecated.css +++ b/packages/ui-components/style/deprecated.css @@ -23,6 +23,7 @@ --jp-icon-r-kernel: url('icons/filetype/r-kernel.svg'); --jp-icon-react: url('icons/filetype/react.svg'); --jp-icon-spreadsheet: url('icons/filetype/spreadsheet.svg'); + --jp-icon-text-editor: url('icons/filetype/text-editor.svg'); --jp-icon-yaml: url('icons/filetype/yaml.svg'); --jp-icon-build: url('icons/sidebar/build.svg'); --jp-icon-extension: url('icons/sidebar/extension.svg'); @@ -82,6 +83,9 @@ .jp-SpreadsheetIcon { background-image: var(--jp-icon-spreadsheet); } +.jp-TextEditorIcon { + background-image: var(--jp-icon-text-editor); +} .jp-YamlIcon { background-image: var(--jp-icon-yaml); } diff --git a/packages/ui-components/style/deprecatedExtra.css b/packages/ui-components/style/deprecatedExtra.css index 25bd79e43ebb..fc217d992039 100644 --- a/packages/ui-components/style/deprecatedExtra.css +++ b/packages/ui-components/style/deprecatedExtra.css @@ -21,5 +21,6 @@ --jp-icon-python-selected: url('deprecated/selected/python_selected.svg'); --jp-icon-r-selected: url('deprecated/selected/r_selected.svg'); --jp-icon-spreadsheet-selected: url('deprecated/selected/csv_selected.svg'); + --jp-icon-text-editor-selected: url('deprecated/selected/ic_format_align_left_24px_selected.svg'); --jp-icon-yaml-selected: url('deprecated/selected/yml_selected.svg'); } diff --git a/packages/ui-components/style/icons/filetype/text-editor.svg b/packages/ui-components/style/icons/filetype/text-editor.svg index f6c6aed70f4d..4ae4def8aa21 100644 --- a/packages/ui-components/style/icons/filetype/text-editor.svg +++ b/packages/ui-components/style/icons/filetype/text-editor.svg @@ -1 +1,7 @@ - \ No newline at end of file + + + From b845879c1ca4b363393dee20776425c71f1b184c Mon Sep 17 00:00:00 2001 From: telamonian Date: Sun, 13 Oct 2019 23:37:29 -0400 Subject: [PATCH 018/101] finished fixing text editor icon --- .../deprecated/selected/ic_format_align_left_24px_selected.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/ui-components/style/deprecated/selected/ic_format_align_left_24px_selected.svg diff --git a/packages/ui-components/style/deprecated/selected/ic_format_align_left_24px_selected.svg b/packages/ui-components/style/deprecated/selected/ic_format_align_left_24px_selected.svg new file mode 100644 index 000000000000..ad40e674fa85 --- /dev/null +++ b/packages/ui-components/style/deprecated/selected/ic_format_align_left_24px_selected.svg @@ -0,0 +1 @@ + \ No newline at end of file From 79469c6db53e45b7cc2175966bfbff1b75dec3f5 Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 14 Oct 2019 00:12:33 -0400 Subject: [PATCH 019/101] human readability formatting pass of filetype icon svg punted on issue of tabs-vs-spaces for indents --- .../style/icons/filetype/file.svg | 12 +++--- .../style/icons/filetype/folder.svg | 6 ++- .../style/icons/filetype/html5.svg | 32 +++++++++++++--- .../style/icons/filetype/image.svg | 17 ++++++--- .../style/icons/filetype/json.svg | 19 ++++------ .../style/icons/filetype/markdown.svg | 13 +++---- .../style/icons/filetype/notebook.svg | 13 ++++--- .../style/icons/filetype/python.svg | 20 ++++------ .../style/icons/filetype/r-kernel.svg | 15 ++++---- .../style/icons/filetype/react.svg | 37 ++++--------------- .../style/icons/filetype/spreadsheet.svg | 11 +++--- .../style/icons/filetype/text-editor.svg | 10 ++--- .../style/icons/filetype/yaml.svg | 12 +++--- .../style/icons/sidebar/running.svg | 2 +- 14 files changed, 109 insertions(+), 110 deletions(-) diff --git a/packages/ui-components/style/icons/filetype/file.svg b/packages/ui-components/style/icons/filetype/file.svg index 0526ea36ef24..1abcdc155427 100644 --- a/packages/ui-components/style/icons/filetype/file.svg +++ b/packages/ui-components/style/icons/filetype/file.svg @@ -1,7 +1,7 @@ - - - + + diff --git a/packages/ui-components/style/icons/filetype/folder.svg b/packages/ui-components/style/icons/filetype/folder.svg index e4d6d832d610..cade8ee8c10b 100644 --- a/packages/ui-components/style/icons/filetype/folder.svg +++ b/packages/ui-components/style/icons/filetype/folder.svg @@ -1,3 +1,7 @@ - + diff --git a/packages/ui-components/style/icons/filetype/html5.svg b/packages/ui-components/style/icons/filetype/html5.svg index d4c7978c5d4c..00d816b70ef0 100644 --- a/packages/ui-components/style/icons/filetype/html5.svg +++ b/packages/ui-components/style/icons/filetype/html5.svg @@ -1,11 +1,31 @@ - - - + + + - - - > + + + diff --git a/packages/ui-components/style/icons/filetype/image.svg b/packages/ui-components/style/icons/filetype/image.svg index 7035ee0c4747..3fd0165d3973 100644 --- a/packages/ui-components/style/icons/filetype/image.svg +++ b/packages/ui-components/style/icons/filetype/image.svg @@ -1,7 +1,12 @@ - - - - + + + diff --git a/packages/ui-components/style/icons/filetype/json.svg b/packages/ui-components/style/icons/filetype/json.svg index b840e84d4718..4213a11dc954 100644 --- a/packages/ui-components/style/icons/filetype/json.svg +++ b/packages/ui-components/style/icons/filetype/json.svg @@ -1,15 +1,10 @@ - - -
Date: Wed, 25 Dec 2019 01:05:24 -0500 Subject: [PATCH 032/101] fixed bug in static Map init --- packages/ui-components/src/icon/jlicon.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 12c41a3822dd..07e9f3c76e63 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -8,7 +8,7 @@ import { iconStyle, IIconStyle } from '../style/icon'; import { getReactAttrs, classes } from '../utils'; export class JLIcon { - private static _instances: Map = Object.create(null); + private static _instances = new Map(); static get(name: string): JLIcon { return JLIcon._instances.get(name) as JLIcon; From b6786babc770e95522fe005a09a89c5285385a91 Mon Sep 17 00:00:00 2001 From: telamonian Date: Wed, 25 Dec 2019 01:05:45 -0500 Subject: [PATCH 033/101] fixed tabmanager icon styling --- packages/docregistry/src/registry.ts | 1 - packages/tabmanager-extension/style/base.css | 6 ------ 2 files changed, 7 deletions(-) diff --git a/packages/docregistry/src/registry.ts b/packages/docregistry/src/registry.ts index e8c643521505..e122ac17c6f4 100644 --- a/packages/docregistry/src/registry.ts +++ b/packages/docregistry/src/registry.ts @@ -1366,7 +1366,6 @@ export namespace DocumentRegistry { displayName: 'Image', mimeTypes: ['image/tiff'], extensions: ['.tif', '.tiff'], - iconClass: 'jp-MaterialIcon jp-ImageIcon', iconRenderer: imageIcon, fileFormat: 'base64' }, diff --git a/packages/tabmanager-extension/style/base.css b/packages/tabmanager-extension/style/base.css index 4305a3551864..bb9a7f2040f2 100644 --- a/packages/tabmanager-extension/style/base.css +++ b/packages/tabmanager-extension/style/base.css @@ -58,12 +58,6 @@ background: var(--jp-brand-color1); } -#tab-manager .p-TabBar-tabIcon, -#tab-manager .p-TabBar-tabLabel, -#tab-manager .p-TabBar-tabCloseIcon { - display: inline-block; -} - #tab-manager .p-TabBar-tabLabel { line-height: var(--jp-private-tab-manager-tab-height); padding-left: 4px; From db35c74c513875b408c0dfe9955a8c940004131e Mon Sep 17 00:00:00 2001 From: telamonian Date: Wed, 25 Dec 2019 01:17:10 -0500 Subject: [PATCH 034/101] fixed style for dockpanel tab icons --- packages/application/style/tabs.css | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/application/style/tabs.css b/packages/application/style/tabs.css index 0bba59f83761..268ad05b8f77 100644 --- a/packages/application/style/tabs.css +++ b/packages/application/style/tabs.css @@ -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; From 6796d2254643e81ba028bb86cce2f70219450430 Mon Sep 17 00:00:00 2001 From: telamonian Date: Wed, 25 Dec 2019 01:34:01 -0500 Subject: [PATCH 035/101] signature cleanup --- packages/ui-components/src/icon/jlicon.tsx | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 07e9f3c76e63..c7be9c654477 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -41,7 +41,7 @@ export class JLIcon { // create a container if needed container = container || document.createElement(tag); - this._initContainer(container, className, propsStyle, title); + this._initContainer({ container, className, propsStyle, title }); // add the svg node to the container container.appendChild(svgElement); @@ -98,12 +98,17 @@ export class JLIcon { ReactDOM.unmountComponentAtNode(host); } - protected _initContainer( - container: HTMLElement, - className?: string, - propsStyle?: IIconStyle, - title?: string - ) { + protected _initContainer({ + container, + className, + propsStyle, + title + }: { + container: HTMLElement; + className?: string; + propsStyle?: IIconStyle; + title?: string; + }) { const classStyle = this.style(propsStyle); if (className || className === '') { @@ -149,7 +154,7 @@ export class JLIcon { ); if (container) { - this._initContainer(container, className, propsStyle, title); + this._initContainer({ container, className, propsStyle, title }); return svgComponent; } else { From eb5bea35157930d315fd243db91ea01d2ddb1246 Mon Sep 17 00:00:00 2001 From: telamonian Date: Wed, 25 Dec 2019 04:23:16 -0500 Subject: [PATCH 036/101] simplified JLIcon styling for lumino; moved all tab icons to JLIcon All filetype icons in tabs and all extension icons in the sidebar are now JLIcons --- packages/application/package.json | 1 + packages/application/src/shell.ts | 24 +++++++++- packages/application/style/index.css | 1 + packages/application/tsconfig.json | 3 ++ packages/apputils-extension/src/palette.ts | 7 ++- packages/docregistry/src/registry.ts | 33 ++------------ .../extensionmanager-extension/package.json | 3 +- .../extensionmanager-extension/src/index.ts | 10 ++--- .../extensionmanager-extension/tsconfig.json | 3 ++ packages/filebrowser-extension/src/index.ts | 4 +- packages/fileeditor/src/widget.ts | 4 -- packages/htmlviewer-extension/src/index.tsx | 9 ++-- packages/logconsole-extension/src/index.tsx | 4 +- packages/logconsole-extension/src/status.tsx | 11 ++--- packages/notebook-extension/package.json | 1 + packages/notebook-extension/src/index.ts | 44 ++++++++++--------- packages/notebook-extension/tsconfig.json | 3 ++ packages/running-extension/package.json | 1 + packages/running-extension/src/index.ts | 3 +- packages/running-extension/tsconfig.json | 3 ++ packages/tabmanager-extension/package.json | 1 + packages/tabmanager-extension/src/index.ts | 10 ++--- packages/tabmanager-extension/style/index.css | 1 + packages/tabmanager-extension/tsconfig.json | 3 ++ packages/ui-components/src/icon/jlicon.tsx | 15 +++---- .../style/icons/sidebar/build.svg | 10 ++--- .../style/icons/sidebar/extension.svg | 8 ++-- .../style/icons/sidebar/palette.svg | 9 ++-- .../style/icons/sidebar/running.svg | 10 ++--- .../ui-components/style/icons/sidebar/tab.svg | 8 ++-- 30 files changed, 123 insertions(+), 124 deletions(-) diff --git a/packages/application/package.json b/packages/application/package.json index 822c819faec9..f18ed5eea7f0 100644 --- a/packages/application/package.json +++ b/packages/application/package.json @@ -42,6 +42,7 @@ "@jupyterlab/rendermime-interfaces": "^2.0.0-alpha.4", "@jupyterlab/services": "^5.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/application": "^1.7.4", "@lumino/commands": "^1.9.0", diff --git a/packages/application/src/shell.ts b/packages/application/src/shell.ts index 50ba31cef8f2..fd398d3ea87b 100644 --- a/packages/application/src/shell.ts +++ b/packages/application/src/shell.ts @@ -3,6 +3,8 @@ import { DocumentRegistry } from '@jupyterlab/docregistry'; +import { JLIcon } from '@jupyterlab/ui-components'; + import { ArrayExt, find, IIterator, iter, toArray } from '@lumino/algorithm'; import { PromiseDelegate, Token } from '@lumino/coreutils'; @@ -765,9 +767,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 }); @@ -1171,6 +1183,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(); } diff --git a/packages/application/style/index.css b/packages/application/style/index.css index 9a0a1363305c..532b4815aab1 100644 --- a/packages/application/style/index.css +++ b/packages/application/style/index.css @@ -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/apputils/style/index.css'); @import url('~@jupyterlab/docregistry/style/index.css'); @import url('~font-awesome/css/font-awesome.min.css'); diff --git a/packages/application/tsconfig.json b/packages/application/tsconfig.json index 71a473f8c9fc..08c7b34d8f4c 100644 --- a/packages/application/tsconfig.json +++ b/packages/application/tsconfig.json @@ -26,6 +26,9 @@ }, { "path": "../statedb" + }, + { + "path": "../ui-components" } ] } diff --git a/packages/apputils-extension/src/palette.ts b/packages/apputils-extension/src/palette.ts index 421bc3a11935..453df5e76901 100644 --- a/packages/apputils-extension/src/palette.ts +++ b/packages/apputils-extension/src/palette.ts @@ -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. @@ -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'; } @@ -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'; } diff --git a/packages/docregistry/src/registry.ts b/packages/docregistry/src/registry.ts index e122ac17c6f4..bd4e57b78731 100644 --- a/packages/docregistry/src/registry.ts +++ b/packages/docregistry/src/registry.ts @@ -66,7 +66,10 @@ export class DocumentRegistry implements IDisposable { let fts = options.initialFileTypes || DocumentRegistry.defaultFileTypes; fts.forEach(ft => { - let value = new DocumentRegistry.FileType(ft); + let value: DocumentRegistry.IFileType = { + ...DocumentRegistry.fileTypeDefaults, + ...ft + }; this._fileTypes.push(value); }); } @@ -1208,34 +1211,6 @@ export namespace DocumentRegistry { fileFormat: 'text' }; - /** - * A wrapper for IFileTypes - */ - export class FileType implements IFileType { - constructor(options: Partial) { - Object.assign(this, fileTypeDefaults, options); - - if (!this.iconClass && this.iconRenderer) { - // set a default style class for icons - this.iconClass = this.iconRenderer.style({ - kind: 'mainAreaTab', - center: true - }); - } - } - - readonly name: string; - readonly mimeTypes: ReadonlyArray; - readonly extensions: ReadonlyArray; - readonly displayName: string; - readonly pattern: string; - readonly iconClass: string; - readonly iconLabel: string; - readonly iconRenderer: JLIcon; - readonly contentType: Contents.ContentType; - readonly fileFormat: Contents.FileFormat; - } - /** * An arguments object for the `changed` signal. */ diff --git a/packages/extensionmanager-extension/package.json b/packages/extensionmanager-extension/package.json index 565dc243a84f..4b16c952afa9 100644 --- a/packages/extensionmanager-extension/package.json +++ b/packages/extensionmanager-extension/package.json @@ -40,7 +40,8 @@ "@jupyterlab/apputils": "^2.0.0-alpha.4", "@jupyterlab/extensionmanager": "^2.0.0-alpha.4", "@jupyterlab/mainmenu": "^2.0.0-alpha.4", - "@jupyterlab/settingregistry": "^2.0.0-alpha.4" + "@jupyterlab/settingregistry": "^2.0.0-alpha.4", + "@jupyterlab/ui-components": "^2.0.0-alpha.4" }, "devDependencies": { "rimraf": "~3.0.0", diff --git a/packages/extensionmanager-extension/src/index.ts b/packages/extensionmanager-extension/src/index.ts index 72674576edaa..bf3da486b347 100644 --- a/packages/extensionmanager-extension/src/index.ts +++ b/packages/extensionmanager-extension/src/index.ts @@ -7,14 +7,12 @@ import { JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; - import { Dialog, showDialog, ICommandPalette } from '@jupyterlab/apputils'; - -import { IMainMenu } from '@jupyterlab/mainmenu'; - import { ExtensionView } from '@jupyterlab/extensionmanager'; - +import { IMainMenu } from '@jupyterlab/mainmenu'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; +import { extensionIcon } from '@jupyterlab/ui-components'; + /** * IDs of the commands added by this extension. @@ -48,7 +46,7 @@ const plugin: JupyterFrontEndPlugin = { const createView = () => { const v = new ExtensionView(serviceManager); v.id = 'extensionmanager.main-view'; - v.title.iconClass = 'jp-ExtensionIcon jp-SideBar-tabIcon'; + v.title.iconRenderer = extensionIcon; v.title.caption = 'Extension Manager'; if (restorer) { restorer.add(v, v.id); diff --git a/packages/extensionmanager-extension/tsconfig.json b/packages/extensionmanager-extension/tsconfig.json index 538160f60806..1cb64aafdcd8 100644 --- a/packages/extensionmanager-extension/tsconfig.json +++ b/packages/extensionmanager-extension/tsconfig.json @@ -20,6 +20,9 @@ }, { "path": "../settingregistry" + }, + { + "path": "../ui-components" } ] } diff --git a/packages/filebrowser-extension/src/index.ts b/packages/filebrowser-extension/src/index.ts index a4ad42b00aa2..211b5bafc8bf 100644 --- a/packages/filebrowser-extension/src/index.ts +++ b/packages/filebrowser-extension/src/index.ts @@ -42,7 +42,7 @@ import { IStateDB } from '@jupyterlab/statedb'; import { IStatusBar } from '@jupyterlab/statusbar'; -import { IIconRegistry } from '@jupyterlab/ui-components'; +import { folderIcon, IIconRegistry } from '@jupyterlab/ui-components'; import { IIterator, map, reduce, toArray } from '@lumino/algorithm'; @@ -295,7 +295,7 @@ function activateBrowser( mainMenu ); - browser.title.iconClass = 'jp-FolderIcon jp-SideBar-tabIcon'; + browser.title.iconRenderer = folderIcon; browser.title.caption = 'File Browser'; labShell.add(browser, 'left', { rank: 100 }); diff --git a/packages/fileeditor/src/widget.ts b/packages/fileeditor/src/widget.ts index 61f4ea702845..0609061ceb0e 100644 --- a/packages/fileeditor/src/widget.ts +++ b/packages/fileeditor/src/widget.ts @@ -326,10 +326,6 @@ export class FileEditorFactory extends ABCWidgetFactory< mimeTypeService: this._services.mimeTypeService }); - content.title.iconClass = textEditorIcon.style({ - kind: 'mainAreaTab', - center: true - }); content.title.iconRenderer = textEditorIcon; const widget = new DocumentWidget({ content, context }); diff --git a/packages/htmlviewer-extension/src/index.tsx b/packages/htmlviewer-extension/src/index.tsx index a9230506a100..32993b32231f 100644 --- a/packages/htmlviewer-extension/src/index.tsx +++ b/packages/htmlviewer-extension/src/index.tsx @@ -19,10 +19,7 @@ import { IHTMLViewerTracker } from '@jupyterlab/htmlviewer'; -/** - * The name for an HTML5 icon. - */ -const ICON_NAME = 'html5'; +import { html5Icon } from '@jupyterlab/ui-components'; /** * Command IDs used by the plugin. @@ -58,7 +55,7 @@ function activateHTMLViewer( displayName: 'HTML File', extensions: ['.html'], mimeTypes: ['text/html'], - iconClass: ICON_NAME + iconRenderer: html5Icon }; app.docRegistry.addFileType(ft); @@ -98,9 +95,9 @@ function activateHTMLViewer( app.commands.notifyCommandChanged(CommandIDs.trustHTML); }); - // widget.node.appendChild(HTML5Icon); widget.title.iconClass = ft.iconClass ?? ''; widget.title.iconLabel = ft.iconLabel ?? ''; + widget.title.iconRenderer = ft.iconRenderer; }); // Add a command to trust the active HTML document, diff --git a/packages/logconsole-extension/src/index.tsx b/packages/logconsole-extension/src/index.tsx index 10b80be3fdd8..d05cbaa8fe86 100644 --- a/packages/logconsole-extension/src/index.tsx +++ b/packages/logconsole-extension/src/index.tsx @@ -35,7 +35,7 @@ import { ISettingRegistry } from '@jupyterlab/settingregistry'; import { IStatusBar } from '@jupyterlab/statusbar'; -import { HTMLSelect } from '@jupyterlab/ui-components'; +import { HTMLSelect, listIcon } from '@jupyterlab/ui-components'; import { UUID } from '@lumino/coreutils'; @@ -145,7 +145,7 @@ function activateLogConsole( logConsoleWidget.addClass('jp-LogConsole'); logConsoleWidget.title.closable = true; logConsoleWidget.title.label = 'Log Console'; - logConsoleWidget.title.iconClass = 'jp-ListIcon'; + logConsoleWidget.title.iconRenderer = listIcon; const addCheckpointButton = new CommandToolbarButton({ commands: app.commands, diff --git a/packages/logconsole-extension/src/status.tsx b/packages/logconsole-extension/src/status.tsx index b4083ddc43bc..face6e7ed3b4 100644 --- a/packages/logconsole-extension/src/status.tsx +++ b/packages/logconsole-extension/src/status.tsx @@ -11,7 +11,7 @@ import { import { GroupItem, TextItem, interactiveItem } from '@jupyterlab/statusbar'; -import { DefaultIconReact } from '@jupyterlab/ui-components'; +import { listIcon } from '@jupyterlab/ui-components'; import { Signal } from '@lumino/signaling'; @@ -32,15 +32,10 @@ function LogConsoleStatusComponent( title = `${props.newMessages} new messages, `; } title += `${props.logEntries} log entries for ${props.source}`; - // inline conditional doesn't seem to work with strict TS currently... - let cond: JSX.Element = (false as unknown) as JSX.Element; - if (props.newMessages > 0) { - cond = ; - } return ( - - {cond} + + {props.newMessages > 0 ? : <>} ); } diff --git a/packages/notebook-extension/package.json b/packages/notebook-extension/package.json index da5e63f01a31..958d863e61e7 100644 --- a/packages/notebook-extension/package.json +++ b/packages/notebook-extension/package.json @@ -53,6 +53,7 @@ "@jupyterlab/settingregistry": "^2.0.0-alpha.4", "@jupyterlab/statedb": "^2.0.0-alpha.4", "@jupyterlab/statusbar": "^2.0.0-alpha.4", + "@jupyterlab/ui-components": "^2.0.0-alpha.4", "@lumino/algorithm": "^1.2.1", "@lumino/commands": "^1.9.0", "@lumino/coreutils": "^1.4.0", diff --git a/packages/notebook-extension/src/index.ts b/packages/notebook-extension/src/index.ts index 7f45afb3b6dc..c1fe452fb6c7 100644 --- a/packages/notebook-extension/src/index.ts +++ b/packages/notebook-extension/src/index.ts @@ -26,24 +26,6 @@ import { PageConfig, URLExt } from '@jupyterlab/coreutils'; import { IDocumentManager } from '@jupyterlab/docmanager'; -import * as nbformat from '@jupyterlab/nbformat'; - -import { ISettingRegistry } from '@jupyterlab/settingregistry'; - -import { IStateDB } from '@jupyterlab/statedb'; - -import { ArrayExt } from '@lumino/algorithm'; - -import { - UUID, - JSONExt, - JSONObject, - ReadonlyPartialJSONObject, - ReadonlyJSONValue -} from '@lumino/coreutils'; - -import { DisposableSet } from '@lumino/disposable'; - import { IFileBrowserFactory } from '@jupyterlab/filebrowser'; import { ILauncher } from '@jupyterlab/launcher'; @@ -58,6 +40,8 @@ import { IViewMenu } from '@jupyterlab/mainmenu'; +import * as nbformat from '@jupyterlab/nbformat'; + import { NotebookTools, INotebookTools, @@ -78,14 +62,32 @@ import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { ServiceManager } from '@jupyterlab/services'; +import { ISettingRegistry } from '@jupyterlab/settingregistry'; + +import { IStateDB } from '@jupyterlab/statedb'; + import { IStatusBar } from '@jupyterlab/statusbar'; -import { JSONValue } from '@lumino/coreutils'; +import { buildIcon } from '@jupyterlab/ui-components'; + +import { ArrayExt } from '@lumino/algorithm'; + +import { CommandRegistry } from '@lumino/commands'; + +import { + JSONExt, + JSONObject, + JSONValue, + ReadonlyPartialJSONObject, + ReadonlyJSONValue, + UUID +} from '@lumino/coreutils'; + +import { DisposableSet } from '@lumino/disposable'; import { Message, MessageLoop } from '@lumino/messaging'; import { Panel, Menu } from '@lumino/widgets'; -import { CommandRegistry } from '@lumino/commands'; /** * The command IDs used by the notebook plugin. @@ -462,7 +464,7 @@ function activateNotebookTools( notebookTools.addItem({ tool: nbConvert, section: 'common', rank: 3 }); } }); - notebookTools.title.iconClass = 'jp-BuildIcon jp-SideBar-tabIcon'; + notebookTools.title.iconRenderer = buildIcon; notebookTools.title.caption = 'Notebook Tools'; notebookTools.id = id; diff --git a/packages/notebook-extension/tsconfig.json b/packages/notebook-extension/tsconfig.json index 69a64dfa1cc2..e9dff32fd8d3 100644 --- a/packages/notebook-extension/tsconfig.json +++ b/packages/notebook-extension/tsconfig.json @@ -56,6 +56,9 @@ }, { "path": "../statusbar" + }, + { + "path": "../ui-components" } ] } diff --git a/packages/running-extension/package.json b/packages/running-extension/package.json index 28675f8d1433..4a64d0ca56d1 100644 --- a/packages/running-extension/package.json +++ b/packages/running-extension/package.json @@ -39,6 +39,7 @@ "@jupyterlab/coreutils": "^4.0.0-alpha.4", "@jupyterlab/running": "^2.0.0-alpha.4", "@jupyterlab/services": "^5.0.0-alpha.4", + "@jupyterlab/ui-components": "^2.0.0-alpha.4", "@lumino/algorithm": "^1.2.1" }, "devDependencies": { diff --git a/packages/running-extension/src/index.ts b/packages/running-extension/src/index.ts index 189c89f2a5cc..51d9a7e0aad8 100644 --- a/packages/running-extension/src/index.ts +++ b/packages/running-extension/src/index.ts @@ -12,6 +12,7 @@ import { RunningSessionManagers, RunningSessions } from '@jupyterlab/running'; +import { runningIcon } from '@jupyterlab/ui-components'; import { Session } from '@jupyterlab/services'; import { PathExt } from '@jupyterlab/coreutils'; @@ -58,7 +59,7 @@ function activate( let runningSessionManagers = new RunningSessionManagers(); let running = new RunningSessions(runningSessionManagers); running.id = 'jp-running-sessions'; - running.title.iconClass = 'jp-RunningIcon jp-SideBar-tabIcon'; + running.title.iconRenderer = runningIcon; running.title.caption = 'Running Terminals and Kernels'; // Let the application restorer track the running panel for restoration of diff --git a/packages/running-extension/tsconfig.json b/packages/running-extension/tsconfig.json index 63ef53b98914..78f059085961 100644 --- a/packages/running-extension/tsconfig.json +++ b/packages/running-extension/tsconfig.json @@ -17,6 +17,9 @@ }, { "path": "../services" + }, + { + "path": "../ui-components" } ] } diff --git a/packages/tabmanager-extension/package.json b/packages/tabmanager-extension/package.json index 67554909e2ea..bd75e9eee4d0 100644 --- a/packages/tabmanager-extension/package.json +++ b/packages/tabmanager-extension/package.json @@ -36,6 +36,7 @@ }, "dependencies": { "@jupyterlab/application": "^2.0.0-alpha.4", + "@jupyterlab/ui-components": "^2.0.0-alpha.4", "@lumino/algorithm": "^1.2.1", "@lumino/widgets": "^1.9.4" }, diff --git a/packages/tabmanager-extension/src/index.ts b/packages/tabmanager-extension/src/index.ts index c55253e542d6..3f549c3e5684 100644 --- a/packages/tabmanager-extension/src/index.ts +++ b/packages/tabmanager-extension/src/index.ts @@ -1,16 +1,16 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. +import { each } from '@lumino/algorithm'; +import { TabBar, Widget } from '@lumino/widgets'; + import { ILabShell, ILayoutRestorer, JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application'; - -import { each } from '@lumino/algorithm'; - -import { TabBar, Widget } from '@lumino/widgets'; +import { tabIcon } from '@jupyterlab/ui-components'; /** * The default tab manager extension. @@ -31,7 +31,7 @@ const plugin: JupyterFrontEndPlugin = { } tabs.id = 'tab-manager'; - tabs.title.iconClass = 'jp-TabIcon jp-SideBar-tabIcon'; + tabs.title.iconRenderer = tabIcon; tabs.title.caption = 'Open Tabs'; header.textContent = 'Open Tabs'; tabs.node.insertBefore(header, tabs.contentNode); diff --git a/packages/tabmanager-extension/style/index.css b/packages/tabmanager-extension/style/index.css index 8fe68ab59e76..bd9f8cebad79 100644 --- a/packages/tabmanager-extension/style/index.css +++ b/packages/tabmanager-extension/style/index.css @@ -5,5 +5,6 @@ /* 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('./base.css'); diff --git a/packages/tabmanager-extension/tsconfig.json b/packages/tabmanager-extension/tsconfig.json index f923db8c1492..e390491760f2 100644 --- a/packages/tabmanager-extension/tsconfig.json +++ b/packages/tabmanager-extension/tsconfig.json @@ -8,6 +8,9 @@ "references": [ { "path": "../application" + }, + { + "path": "../ui-components" } ] } diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index c7be9c654477..4fd7254d2ba3 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -5,7 +5,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { iconStyle, IIconStyle } from '../style/icon'; -import { getReactAttrs, classes } from '../utils'; +import { getReactAttrs, classes, classesDedupe } from '../utils'; export class JLIcon { private static _instances = new Map(); @@ -24,6 +24,10 @@ export class JLIcon { JLIcon._instances.set(name, this); } + class({ className, ...propsStyle }: { className?: string } & IIconStyle) { + return classesDedupe(className, iconStyle(propsStyle)); + } + element({ className, container, @@ -90,10 +94,6 @@ export class JLIcon { return this._svgstr; } - style(props?: IIconStyle) { - return iconStyle(props); - } - unrender(host: HTMLElement): void { ReactDOM.unmountComponentAtNode(host); } @@ -109,7 +109,7 @@ export class JLIcon { propsStyle?: IIconStyle; title?: string; }) { - const classStyle = this.style(propsStyle); + const classStyle = iconStyle(propsStyle); if (className || className === '') { // override the container class with explicitly passed-in class + style class @@ -159,7 +159,7 @@ export class JLIcon { return svgComponent; } else { return ( - + {svgComponent} ); @@ -191,7 +191,6 @@ export namespace JLIcon { export interface IOptions { name: string; svgstr: string; - style?: IIconStyle; _debug?: boolean; } diff --git a/packages/ui-components/style/icons/sidebar/build.svg b/packages/ui-components/style/icons/sidebar/build.svg index dd026ddd5d1a..a4735c0bac32 100644 --- a/packages/ui-components/style/icons/sidebar/build.svg +++ b/packages/ui-components/style/icons/sidebar/build.svg @@ -1,6 +1,6 @@ - - + + diff --git a/packages/ui-components/style/icons/sidebar/extension.svg b/packages/ui-components/style/icons/sidebar/extension.svg index e7c930bdad64..bd3612a1ae83 100644 --- a/packages/ui-components/style/icons/sidebar/extension.svg +++ b/packages/ui-components/style/icons/sidebar/extension.svg @@ -1,7 +1,5 @@ - + diff --git a/packages/ui-components/style/icons/sidebar/palette.svg b/packages/ui-components/style/icons/sidebar/palette.svg index 8bde140b6abb..e0d9ffd813c0 100644 --- a/packages/ui-components/style/icons/sidebar/palette.svg +++ b/packages/ui-components/style/icons/sidebar/palette.svg @@ -1,7 +1,6 @@ - - -
  • - {defaultIconRegistry.contains(image) ? ( - - ) : ( - - )} + {schema.title || id}
  • ); From 81d9d817bed5f6e6a21c1a059ee5c69700e3b6b7 Mon Sep 17 00:00:00 2001 From: telamonian Date: Thu, 26 Dec 2019 00:53:07 -0500 Subject: [PATCH 048/101] migreated icons in `filebrowser` pkg to JLIcon --- packages/filebrowser/package.json | 3 +- packages/filebrowser/src/listing.ts | 65 +++++++++------------- packages/ui-components/src/icon/jlicon.tsx | 11 +++- 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/packages/filebrowser/package.json b/packages/filebrowser/package.json index a493e34a8f5a..a09785d9529e 100644 --- a/packages/filebrowser/package.json +++ b/packages/filebrowser/package.json @@ -52,8 +52,7 @@ "@lumino/polling": "^1.0.1", "@lumino/signaling": "^1.3.2", "@lumino/widgets": "^1.9.4", - "react": "~16.9.0", - "react-dom": "~16.9.0" + "react": "~16.9.0" }, "devDependencies": { "rimraf": "~3.0.0", diff --git a/packages/filebrowser/src/listing.ts b/packages/filebrowser/src/listing.ts index ec3c0fca4e1c..1e4f897af713 100644 --- a/packages/filebrowser/src/listing.ts +++ b/packages/filebrowser/src/listing.ts @@ -20,7 +20,12 @@ import { DocumentRegistry } from '@jupyterlab/docregistry'; import { Contents } from '@jupyterlab/services'; -import { IIconRegistry } from '@jupyterlab/ui-components'; +import { + classes, + fileIcon, + IIconRegistry, + JLIcon +} from '@jupyterlab/ui-components'; import { ArrayExt, @@ -45,8 +50,6 @@ import { ISignal, Signal } from '@lumino/signaling'; import { Widget } from '@lumino/widgets'; -import ReactDOM from 'react-dom'; - import { FileBrowserModel } from './model'; /** @@ -736,10 +739,7 @@ export class DirListing extends Widget { // Remove any excess item nodes. while (nodes.length > items.length) { - let node = nodes.pop(); - let icon = DOMUtils.findElement(node!, ITEM_ICON_CLASS); - ReactDOM.unmountComponentAtNode(icon); - content.removeChild(node!); + content.removeChild(nodes.pop()!); } // Add any missing item nodes. @@ -1808,41 +1808,28 @@ export namespace DirListing { model: Contents.IModel, fileType?: DocumentRegistry.IFileType ): void { - let icon = DOMUtils.findElement(node, ITEM_ICON_CLASS); - let text = DOMUtils.findElement(node, ITEM_TEXT_CLASS); - let modified = DOMUtils.findElement(node, ITEM_MODIFIED_CLASS); - - if (fileType) { - // TODO: remove workaround if...else/code in else clause in v2.0.0 - // workaround for 1.0.x versions of Jlab pulling in 1.1.x versions of filebrowser - if (fileType.iconRenderer) { - // add icon as svg node. Can be styled using CSS - fileType.iconRenderer.render(icon, { - className: ITEM_ICON_CLASS, - container: icon, - title: fileType.iconLabel, - center: true, - kind: 'listing' - }); - } else { - // cleanup after react - ReactDOM.unmountComponentAtNode(icon); - - // add icon as CSS background image. Can't be styled using CSS - icon.className = `${ITEM_ICON_CLASS} ${fileType.iconClass || ''}`; - icon.textContent = fileType.iconLabel || ''; - } + const iconContainer = DOMUtils.findElement(node, ITEM_ICON_CLASS); + const text = DOMUtils.findElement(node, ITEM_TEXT_CLASS); + const modified = DOMUtils.findElement(node, ITEM_MODIFIED_CLASS); + + let icon: JLIcon; + let iconClass: string | undefined; + + if (fileType?.iconRenderer) { + // use the icon and optional iconClass supplied by the ft + icon = fileType.iconRenderer; + iconClass = classes(ITEM_ICON_CLASS, fileType.iconClass); + } else if (fileType?.iconClass) { + // try to look up the icon based on the ft iconClass + icon = JLIcon.get(fileType.iconClass, fileIcon); } else { - // cleanup after react - ReactDOM.unmountComponentAtNode(icon); - - // use default icon as CSS background image - icon.className = ITEM_ICON_CLASS; - icon.textContent = ''; - // clean up the svg icon annotation, if any - delete icon.dataset.icon; + // fallback to fileIcon + icon = fileIcon; } + // render the icon svg node + icon.element({className: iconClass, container: iconContainer, center: true, kind: 'listing'}); + let hoverText = 'Name: ' + model.name; // add file size to pop up if its available if (model.size !== null && model.size !== undefined) { diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 0ba51db06b93..476f69ae9fe3 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -81,8 +81,15 @@ export class JLIcon { return null; } - // create a container if needed - container = container || document.createElement(tag); + if (container) { + // take ownership by removing any existing children + while (container.firstChild) { + container.firstChild.remove(); + } + } else { + // create a container if needed + container = document.createElement(tag); + } this._initContainer({ container, className, propsStyle, title }); From 836aac3c57cc0f720efd9551e6257dc15a0f35a8 Mon Sep 17 00:00:00 2001 From: telamonian Date: Thu, 26 Dec 2019 17:52:02 -0500 Subject: [PATCH 049/101] prevent redundant rerenders of icons created by JLIcon.element() --- packages/filebrowser/src/listing.ts | 16 ++----------- packages/ui-components/src/icon/jlicon.tsx | 19 +++++++++++++-- packages/ui-components/src/utils.ts | 27 +++++++++++++++++++++- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/packages/filebrowser/src/listing.ts b/packages/filebrowser/src/listing.ts index 1e4f897af713..9c86af671548 100644 --- a/packages/filebrowser/src/listing.ts +++ b/packages/filebrowser/src/listing.ts @@ -1812,20 +1812,8 @@ export namespace DirListing { const text = DOMUtils.findElement(node, ITEM_TEXT_CLASS); const modified = DOMUtils.findElement(node, ITEM_MODIFIED_CLASS); - let icon: JLIcon; - let iconClass: string | undefined; - - if (fileType?.iconRenderer) { - // use the icon and optional iconClass supplied by the ft - icon = fileType.iconRenderer; - iconClass = classes(ITEM_ICON_CLASS, fileType.iconClass); - } else if (fileType?.iconClass) { - // try to look up the icon based on the ft iconClass - icon = JLIcon.get(fileType.iconClass, fileIcon); - } else { - // fallback to fileIcon - icon = fileIcon; - } + let icon = fileType?.iconRenderer ? fileType.iconRenderer : (fileType?.iconClass ? JLIcon.get(fileType.iconClass) : fileIcon); + let iconClass = classes(ITEM_ICON_CLASS, fileType?.iconClass); // render the icon svg node icon.element({className: iconClass, container: iconContainer, center: true, kind: 'listing'}); diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 476f69ae9fe3..3d8a19ef56c8 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -1,6 +1,8 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. +import { UUID } from '@lumino/coreutils'; + import React from 'react'; import ReactDOM from 'react-dom'; @@ -55,7 +57,7 @@ export class JLIcon { constructor({ name, svgstr }: JLIcon.IOptions) { this.name = name; this._className = JLIcon.nameToClassName(name); - this._svgstr = svgstr; + this.svgstr = svgstr; this.react = this._initReact(); @@ -74,6 +76,13 @@ export class JLIcon { tag = 'div', ...propsStyle }: JLIcon.IProps = {}): HTMLElement | null { + // check if icon element is already set + const maybeSvgElement = container?.firstChild as HTMLElement; + if (maybeSvgElement?.dataset?.iconid === this._uuid) { + // return the existing icon element + return maybeSvgElement; + } + // ensure that svg html is valid const svgElement = this.resolveSvg(); if (!svgElement) { @@ -99,8 +108,11 @@ export class JLIcon { return svgElement; } - replaceSvg(svgstr: string) { + set svgstr(svgstr: string) { this._svgstr = svgstr; + + // associate a unique id with this particular svgstr + this._uuid = UUID.uuid4(); } render(host: HTMLElement, props: JLIcon.IProps = {}): void { @@ -128,6 +140,8 @@ export class JLIcon { } } else { // parse succeeded + svgElement.dataset.iconid = this._uuid; + if (title) { Private.setTitleSvg(svgElement, title); } @@ -224,6 +238,7 @@ export class JLIcon { protected _className: string; protected _svgstr: string; + protected _uuid: string; } /** diff --git a/packages/ui-components/src/utils.ts b/packages/ui-components/src/utils.ts index 1fb9b418a782..1933bc176958 100644 --- a/packages/ui-components/src/utils.ts +++ b/packages/ui-components/src/utils.ts @@ -3,6 +3,9 @@ import { Text } from '@jupyterlab/coreutils'; +/** + * Inner works of class combining functions + */ function _classes( classes: (string | false | undefined | null | { [className: string]: any })[] ): string[] { @@ -20,6 +23,10 @@ function _classes( /** * Combines classNames. + * + * @param classes - A list of classNames + * + * @returns A single string with the combined className */ export function classes( ...classes: ( @@ -35,6 +42,10 @@ export function classes( /** * Combines classNames. Removes all duplicates + * + * @param classes - A list of classNames + * + * @returns A single string with the combined className */ export function classesDedupe( ...classes: ( @@ -48,9 +59,23 @@ export function classesDedupe( return [...new Set(_classes(classes))].join(' '); } +/** + * Translates the attributes of a DOM element into attributes that can + * be understood by React. Currently not comprehensive, we will add special + * cases as they become relevant. + * + * @param elem - A DOM element + * + * @returns An object with key:value pairs that are the React-friendly + * translation of elem's attributes + */ export function getReactAttrs(elem: Element) { return elem.getAttributeNames().reduce((d, name) => { - if (name !== 'style') { + if (name === 'style') { + void 0; + } else if (name.startsWith('data')) { + d[name] = elem.getAttribute(name); + } else { d[Text.camelCase(name)] = elem.getAttribute(name); } return d; From 86a1053b626bd5fa4ff0f9148e6fdf0cf0def2cf Mon Sep 17 00:00:00 2001 From: telamonian Date: Thu, 26 Dec 2019 20:14:08 -0500 Subject: [PATCH 050/101] refactor of JLIcon.get into JLIcon.getElement and JLIcon.getReact --- packages/ui-components/src/icon/jlicon.tsx | 81 +++++++++++++++++----- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 3d8a19ef56c8..5a1aa002ab53 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -2,7 +2,6 @@ // Distributed under the terms of the Modified BSD License. import { UUID } from '@lumino/coreutils'; - import React from 'react'; import ReactDOM from 'react-dom'; @@ -28,7 +27,7 @@ export class JLIcon { * * @returns A JLIcon instance */ - static get(name: string, fallback?: JLIcon): JLIcon { + private static _get(name: string, fallback?: JLIcon): JLIcon | undefined { const icon = JLIcon._instances.get(name); if (icon) { @@ -41,10 +40,54 @@ export class JLIcon { } // fail silently - return fallback ?? blankIcon; + return fallback; } } + /** + * Get any existing JLIcon instance by name, construct a DOM element + * from it, then return said element. + * + * @param name - Name of the JLIcon instance to fetch + * + * @param fallback - If left undefined, use automatic fallback to + * icons-as-css-background behavior: elem will be constructed using + * a blank icon with `elem.className = classes(name, props.className)`, + * where elem is the return value. Otherwise, fallback can be used to + * define the default JLIcon instance, returned whenever lookup fails + * + * @param props = passed directly to JLIcon.element + * + * @returns An SVGElement + */ + static getElement({ + name, + fallback, + ...props + }: { name: string; fallback?: JLIcon } & JLIcon.IProps) { + let icon = JLIcon._get(name, fallback); + if (!icon) { + icon = blankIcon; + props.className = classesDedupe(name, props.className); + } + + return icon.element(props); + } + + static getReact({ + name, + fallback, + ...props + }: { name: string; fallback?: JLIcon } & JLIcon.IReactProps) { + let icon = JLIcon._get(name, fallback); + if (!icon) { + icon = blankIcon; + props.className = classesDedupe(name, props.className); + } + + return ; + } + /** * Toggle icon debug from off-to-on, or vice-versa * @@ -56,7 +99,7 @@ export class JLIcon { constructor({ name, svgstr }: JLIcon.IOptions) { this.name = name; - this._className = JLIcon.nameToClassName(name); + this._className = Private.nameToClassName(name); this.svgstr = svgstr; this.react = this._initReact(); @@ -108,13 +151,6 @@ export class JLIcon { return svgElement; } - set svgstr(svgstr: string) { - this._svgstr = svgstr; - - // associate a unique id with this particular svgstr - this._uuid = UUID.uuid4(); - } - render(host: HTMLElement, props: JLIcon.IProps = {}): void { return ReactDOM.render(, host); } @@ -150,10 +186,17 @@ export class JLIcon { } } - string() { + get svgstr() { return this._svgstr; } + set svgstr(svgstr: string) { + this._svgstr = svgstr; + + // associate a unique id with this particular svgstr + this._uuid = UUID.uuid4(); + } + unrender(host: HTMLElement): void { ReactDOM.unmountComponentAtNode(host); } @@ -232,9 +275,7 @@ export class JLIcon { } readonly name: string; - readonly react: React.ForwardRefExoticComponent< - JLIcon.IProps & React.RefAttributes - >; + readonly react: JLIcon.IReact; protected _className: string; protected _svgstr: string; @@ -281,15 +322,19 @@ export namespace JLIcon { title?: string; } - export function nameToClassName(name: string): string { - return 'jp-' + Text.camelCase(name, true) + 'Icon'; - } + export type IReactProps = IProps & React.RefAttributes; + + export type IReact = React.ForwardRefExoticComponent; } export const badIcon = new JLIcon({ name: 'bad', svgstr: badSvg }); export const blankIcon = new JLIcon({ name: 'blank', svgstr: blankSvg }); namespace Private { + export function nameToClassName(name: string): string { + return 'jp-' + Text.camelCase(name, true) + 'Icon'; + } + export function setTitleSvg(svgNode: HTMLElement, title: string): void { // add a title node to the top level svg node let titleNodes = svgNode.getElementsByTagName('title'); From 982a621e2ede9d0bb2564c186cf900ed4ad39aa9 Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 30 Dec 2019 17:12:25 -0500 Subject: [PATCH 051/101] removed all refs to defaultIconRegistry outside of ui-components pkgs --- packages/apputils-extension/src/index.ts | 5 +-- packages/celltags/src/addwidget.ts | 10 ++--- packages/celltags/src/widget.ts | 12 +++-- packages/filebrowser/src/crumbs.ts | 16 +++---- packages/filebrowser/src/listing.ts | 23 ++++++---- packages/launcher/src/index.tsx | 45 +++++++------------ packages/settingeditor/src/pluginlist.tsx | 9 +++- packages/ui-components/src/icon/jlicon.tsx | 51 ++++++++++++++++------ 8 files changed, 90 insertions(+), 81 deletions(-) diff --git a/packages/apputils-extension/src/index.ts b/packages/apputils-extension/src/index.ts index ad68fbe418f3..fa25add3337b 100644 --- a/packages/apputils-extension/src/index.ts +++ b/packages/apputils-extension/src/index.ts @@ -25,7 +25,7 @@ import { URLExt } from '@jupyterlab/coreutils'; import { IStateDB, StateDB } from '@jupyterlab/statedb'; -import { defaultIconRegistry } from '@jupyterlab/ui-components'; +import { jupyterFaviconIcon } from '@jupyterlab/ui-components'; import { PromiseDelegate } from '@lumino/coreutils'; @@ -149,8 +149,7 @@ const splash: JupyterFrontEndPlugin = { galaxy.id = 'galaxy'; logo.id = 'main-logo'; - defaultIconRegistry.icon({ - name: 'jupyter-favicon', + jupyterFaviconIcon.element({ container: logo, center: true, kind: 'splash' diff --git a/packages/celltags/src/addwidget.ts b/packages/celltags/src/addwidget.ts index a8ae0e6b9dcc..5749b5b74138 100644 --- a/packages/celltags/src/addwidget.ts +++ b/packages/celltags/src/addwidget.ts @@ -1,6 +1,6 @@ import { Widget } from '@lumino/widgets'; -import { defaultIconRegistry } from '@jupyterlab/ui-components'; +import { addIcon } from '@jupyterlab/ui-components'; import { TagTool } from './tool'; @@ -31,10 +31,8 @@ export class AddWidget extends Widget { let tag = document.createElement('div'); tag.className = 'tag-holder'; tag.appendChild(text); - let img = document.createElement('span'); - defaultIconRegistry.icon({ - name: 'add', - container: img, + let iconContainer = addIcon.element({ + tag: 'span', center: true, height: '18px', width: '18px', @@ -42,7 +40,7 @@ export class AddWidget extends Widget { marginRight: '-5px' }); this.addClass('unapplied-tag'); - tag.appendChild(img); + tag.appendChild(iconContainer); this.node.appendChild(tag); } diff --git a/packages/celltags/src/widget.ts b/packages/celltags/src/widget.ts index 1f8709933c43..5ce0327229da 100644 --- a/packages/celltags/src/widget.ts +++ b/packages/celltags/src/widget.ts @@ -1,6 +1,6 @@ import { Widget } from '@lumino/widgets'; -import { defaultIconRegistry } from '@jupyterlab/ui-components'; +import { checkIcon } from '@jupyterlab/ui-components'; import { TagTool } from './tool'; @@ -29,10 +29,8 @@ export class TagWidget extends Widget { let tag = document.createElement('div'); tag.className = 'tag-holder'; tag.appendChild(text); - let img = document.createElement('span'); - defaultIconRegistry.icon({ - name: 'check', - container: img, + let iconContainer = checkIcon.element({ + tag: 'span', center: true, height: '18px', width: '18px', @@ -43,9 +41,9 @@ export class TagWidget extends Widget { this.addClass('applied-tag'); } else { this.addClass('unapplied-tag'); - img.style.display = 'none'; + iconContainer.style.display = 'none'; } - tag.appendChild(img); + tag.appendChild(iconContainer); this.node.appendChild(tag); } diff --git a/packages/filebrowser/src/crumbs.ts b/packages/filebrowser/src/crumbs.ts index 96851c48b5d2..77c651b69fb1 100644 --- a/packages/filebrowser/src/crumbs.ts +++ b/packages/filebrowser/src/crumbs.ts @@ -5,19 +5,19 @@ import { ArrayExt } from '@lumino/algorithm'; import { Message } from '@lumino/messaging'; -import { IDragEvent } from '@lumino/dragdrop'; - import { ElementExt } from '@lumino/domutils'; +import { IDragEvent } from '@lumino/dragdrop'; + import { Widget } from '@lumino/widgets'; import { DOMUtils, showErrorMessage } from '@jupyterlab/apputils'; -import { PathExt, PageConfig } from '@jupyterlab/coreutils'; +import { PageConfig, PathExt } from '@jupyterlab/coreutils'; import { renameFile } from '@jupyterlab/docmanager'; -import { defaultIconRegistry } from '@jupyterlab/ui-components'; +import { folderIcon } from '@jupyterlab/ui-components'; import { FileBrowserModel } from './model'; @@ -31,11 +31,6 @@ const MATERIAL_CLASS = 'jp-MaterialIcon'; */ const BREADCRUMB_CLASS = 'jp-BreadCrumbs'; -/** - * The class name for the folder icon for the breadcrumbs home - */ -const BREADCRUMB_HOME = 'jp-FolderIcon'; - /** * The class name for the breadcrumbs home node */ @@ -363,8 +358,7 @@ namespace Private { */ export function createCrumbs(): ReadonlyArray { let home = document.createElement('span'); - defaultIconRegistry.icon({ - name: BREADCRUMB_HOME, + folderIcon.element({ className: BREADCRUMB_HOME_CLASS, container: home, kind: 'breadCrumb' diff --git a/packages/filebrowser/src/listing.ts b/packages/filebrowser/src/listing.ts index 9c86af671548..b256430315bd 100644 --- a/packages/filebrowser/src/listing.ts +++ b/packages/filebrowser/src/listing.ts @@ -20,12 +20,7 @@ import { DocumentRegistry } from '@jupyterlab/docregistry'; import { Contents } from '@jupyterlab/services'; -import { - classes, - fileIcon, - IIconRegistry, - JLIcon -} from '@jupyterlab/ui-components'; +import { fileIcon, IIconRegistry, JLIcon } from '@jupyterlab/ui-components'; import { ArrayExt, @@ -1812,11 +1807,21 @@ export namespace DirListing { const text = DOMUtils.findElement(node, ITEM_TEXT_CLASS); const modified = DOMUtils.findElement(node, ITEM_MODIFIED_CLASS); - let icon = fileType?.iconRenderer ? fileType.iconRenderer : (fileType?.iconClass ? JLIcon.get(fileType.iconClass) : fileIcon); - let iconClass = classes(ITEM_ICON_CLASS, fileType?.iconClass); + const iconProps: JLIcon.IProps = { + className: ITEM_ICON_CLASS, + container: iconContainer, + center: true, + kind: 'listing' + }; // render the icon svg node - icon.element({className: iconClass, container: iconContainer, center: true, kind: 'listing'}); + if (fileType?.iconRenderer) { + fileType.iconRenderer.element(iconProps); + } else if (fileType?.iconClass) { + JLIcon.getElement({ name: fileType.iconClass, ...iconProps }); + } else { + fileIcon.element(iconProps); + } let hoverText = 'Name: ' + model.name; // add file size to pop up if its available diff --git a/packages/launcher/src/index.tsx b/packages/launcher/src/index.tsx index f92da033eb40..dee0350fa5f4 100644 --- a/packages/launcher/src/index.tsx +++ b/packages/launcher/src/index.tsx @@ -7,11 +7,7 @@ import { VDomRenderer } from '@jupyterlab/apputils'; -import { - classes, - DefaultIconReact, - defaultIconRegistry -} from '@jupyterlab/ui-components'; +import { classes, JLIcon } from '@jupyterlab/ui-components'; import { ArrayExt, @@ -203,20 +199,15 @@ export class Launcher extends VDomRenderer { section = (
    - {kernel && defaultIconRegistry.contains(iconClass) ? ( - - ) : ( -
    )}

    {cat}

    @@ -415,7 +406,6 @@ function Card( }; // Return the VDOM element. - const iconClass = kernel ? '' : commands.iconClass(command, args); return (
    - {kernel ? ( -
    - {item.kernelIconUrl ? ( +
    + {kernel ? ( + item.kernelIconUrl ? ( ) : (
    {label[0].toUpperCase()}
    - )} -
    - ) : ( -
    - -
    - )} + )} +

    {label}

    diff --git a/packages/settingeditor/src/pluginlist.tsx b/packages/settingeditor/src/pluginlist.tsx index 88dd441ab43b..7e06fc052e0e 100644 --- a/packages/settingeditor/src/pluginlist.tsx +++ b/packages/settingeditor/src/pluginlist.tsx @@ -261,7 +261,6 @@ namespace Private { const itemTitle = `${schema.description}\n${id}\n${version}`; const iconClass = getHint(ICON_CLASS_KEY, registry, plugin); const iconTitle = getHint(ICON_LABEL_KEY, registry, plugin); - const icon = JLIcon.get(iconClass, settingsIcon); return (
  • - + {schema.title || id}
  • ); diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 5a1aa002ab53..58030e0b743a 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -14,15 +14,15 @@ import badSvg from '../../style/debug/bad.svg'; import blankSvg from '../../style/debug/blank.svg'; export class JLIcon { - private static _instances = new Map(); private static _debug: boolean = false; + private static _instances = new Map(); /** - * Get any existing JLIcon instance by name + * Get any existing JLIcon instance by name. * - * @param name - Name of the JLIcon instance to fetch + * @param name - name of the JLIcon instance to fetch * - * @param fallback - Optional default JLIcon instance to use if + * @param fallback - optional default JLIcon instance to use if * name is not found * * @returns A JLIcon instance @@ -48,17 +48,17 @@ export class JLIcon { * Get any existing JLIcon instance by name, construct a DOM element * from it, then return said element. * - * @param name - Name of the JLIcon instance to fetch + * @param name - name of the JLIcon instance to fetch * - * @param fallback - If left undefined, use automatic fallback to + * @param fallback - if left undefined, use automatic fallback to * icons-as-css-background behavior: elem will be constructed using * a blank icon with `elem.className = classes(name, props.className)`, * where elem is the return value. Otherwise, fallback can be used to * define the default JLIcon instance, returned whenever lookup fails * - * @param props = passed directly to JLIcon.element + * @param props - passed directly to JLIcon.element * - * @returns An SVGElement + * @returns an SVGElement */ static getElement({ name, @@ -74,6 +74,23 @@ export class JLIcon { return icon.element(props); } + /** + * Get any existing JLIcon instance by name, construct a React element + * from it, then return said element. + * + * @param name - name of the JLIcon instance to fetch + * + * @param fallback - if left undefined, use automatic fallback to + * icons-as-css-background behavior: elem will be constructed using + * a blank icon with `elem.className = classes(name, props.className)`, + * where elem is the return value. Otherwise, fallback can be used to + * define the default JLIcon instance, used to construct the return + * elem whenever lookup fails + * + * @param props - passed directly to JLIcon.react + * + * @returns a React element + */ static getReact({ name, fallback, @@ -89,9 +106,9 @@ export class JLIcon { } /** - * Toggle icon debug from off-to-on, or vice-versa + * Toggle icon debug from off-to-on, or vice-versa. * - * @param debug - Optional boolean to force debug on or off + * @param debug - optional boolean to force debug on or off */ static toggleDebug(debug?: boolean) { JLIcon._debug = debug ?? !JLIcon._debug; @@ -133,14 +150,19 @@ export class JLIcon { return null; } + let ret: HTMLElement; if (container) { // take ownership by removing any existing children while (container.firstChild) { container.firstChild.remove(); } + + ret = svgElement; } else { // create a container if needed container = document.createElement(tag); + + ret = container; } this._initContainer({ container, className, propsStyle, title }); @@ -148,7 +170,7 @@ export class JLIcon { // add the svg node to the container container.appendChild(svgElement); - return svgElement; + return ret; } render(host: HTMLElement, props: JLIcon.IProps = {}): void { @@ -327,9 +349,6 @@ export namespace JLIcon { export type IReact = React.ForwardRefExoticComponent; } -export const badIcon = new JLIcon({ name: 'bad', svgstr: badSvg }); -export const blankIcon = new JLIcon({ name: 'blank', svgstr: blankSvg }); - namespace Private { export function nameToClassName(name: string): string { return 'jp-' + Text.camelCase(name, true) + 'Icon'; @@ -347,3 +366,7 @@ namespace Private { } } } + +// need to be at the bottom since constructor depends on Private +export const badIcon = new JLIcon({ name: 'bad', svgstr: badSvg }); +export const blankIcon = new JLIcon({ name: 'blank', svgstr: blankSvg }); From 0630035e6404de04f5a4dbce921effaad1b98475 Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 30 Dec 2019 17:21:44 -0500 Subject: [PATCH 052/101] picked lint --- packages/theme-dark-extension/style/urls.css | 54 +++++++++---------- packages/theme-light-extension/style/urls.css | 1 - 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/packages/theme-dark-extension/style/urls.css b/packages/theme-dark-extension/style/urls.css index 0ca592c7aa37..ca4db0e3c476 100644 --- a/packages/theme-dark-extension/style/urls.css +++ b/packages/theme-dark-extension/style/urls.css @@ -28,31 +28,31 @@ /* Icons used in the application. */ - --jp-about-header-wordmark: url('images/jupyterlab-wordmark.svg'); - --jp-icon-bug: url('icons/md/bug.svg'); - --jp-icon-caretdown: url('icons/md/caretdown.svg'); - --jp-icon-caretleft: url('icons/md/caretleft.svg'); - --jp-icon-caretright: url('icons/md/caretright.svg'); - --jp-icon-caretup: url('icons/md/caretup.svg'); - --jp-icon-checkmark-disabled: url('icons/md/checkmark-disabled.svg'); - --jp-icon-checkmark: url('icons/md/checkmark.svg'); - --jp-icon-circle: url('icons/md/circle.svg'); - --jp-icon-close-circle: url('icons/md/close-circle.svg'); - --jp-icon-close: url('icons/md/close.svg'); - --jp-icon-download: url('icons/md/download.svg'); - --jp-icon-edit: url('icons/md/edit.svg'); - --jp-icon-ellipses: url('icons/md/ellipses.svg'); - --jp-icon-inspector: url('icons/md/baseline-web-24px.svg'); - --jp-icon-inverse-circle: url('icons/md/circle-inverse.svg'); - --jp-icon-inverse-close-circle: url('icons/md/close-circle-inverse.svg'); - --jp-icon-inverse-close: url('icons/md/close-inverse.svg'); - --jp-icon-kernel-running: url('icons/md/panorama_fish_eye.svg'); - --jp-icon-link: url('icons/md/link.svg'); - --jp-icon-more: url('icons/md/more-horiz.svg'); - --jp-icon-search-arrow-up: url('icons/jupyter/search_arrow_up.svg'); - --jp-icon-search-arrow-down: url('icons/jupyter/search_arrow_down.svg'); - --jp-icon-search-case-sensitive: url('icons/jupyter/search_case_sensitive.svg'); - --jp-icon-search-regex: url('icons/jupyter/search_regex.svg'); - --jp-icon-stop-circle: url('icons/md/stop-circle.svg'); - --jp-icon-undo: url('icons/md/undo.svg'); + --jp-about-header-wordmark: url('images/jupyterlab-wordmark.svg'); + --jp-icon-bug: url('icons/md/bug.svg'); + --jp-icon-caretdown: url('icons/md/caretdown.svg'); + --jp-icon-caretleft: url('icons/md/caretleft.svg'); + --jp-icon-caretright: url('icons/md/caretright.svg'); + --jp-icon-caretup: url('icons/md/caretup.svg'); + --jp-icon-checkmark-disabled: url('icons/md/checkmark-disabled.svg'); + --jp-icon-checkmark: url('icons/md/checkmark.svg'); + --jp-icon-circle: url('icons/md/circle.svg'); + --jp-icon-close-circle: url('icons/md/close-circle.svg'); + --jp-icon-close: url('icons/md/close.svg'); + --jp-icon-download: url('icons/md/download.svg'); + --jp-icon-edit: url('icons/md/edit.svg'); + --jp-icon-ellipses: url('icons/md/ellipses.svg'); + --jp-icon-inspector: url('icons/md/baseline-web-24px.svg'); + --jp-icon-inverse-circle: url('icons/md/circle-inverse.svg'); + --jp-icon-inverse-close-circle: url('icons/md/close-circle-inverse.svg'); + --jp-icon-inverse-close: url('icons/md/close-inverse.svg'); + --jp-icon-kernel-running: url('icons/md/panorama_fish_eye.svg'); + --jp-icon-link: url('icons/md/link.svg'); + --jp-icon-more: url('icons/md/more-horiz.svg'); + --jp-icon-search-arrow-up: url('icons/jupyter/search_arrow_up.svg'); + --jp-icon-search-arrow-down: url('icons/jupyter/search_arrow_down.svg'); + --jp-icon-search-case-sensitive: url('icons/jupyter/search_case_sensitive.svg'); + --jp-icon-search-regex: url('icons/jupyter/search_regex.svg'); + --jp-icon-stop-circle: url('icons/md/stop-circle.svg'); + --jp-icon-undo: url('icons/md/undo.svg'); } diff --git a/packages/theme-light-extension/style/urls.css b/packages/theme-light-extension/style/urls.css index 7a2135798ea0..b1616b451583 100644 --- a/packages/theme-light-extension/style/urls.css +++ b/packages/theme-light-extension/style/urls.css @@ -56,7 +56,6 @@ --jp-icon-stop-circle: url('icons/md/stop-circle.svg'); --jp-icon-undo: url('icons/md/undo.svg'); - /*--jp-about-header-logo: url('icons/jupyter/jupyter.svg');*/ /*--jp-icon-console-selected: url('icons/jupyter/console_selected.svg');*/ /*--jp-icon-console: url('icons/jupyter/console.svg');*/ From fc82b8d61c23211343fd807cabe3280fd214f563 Mon Sep 17 00:00:00 2001 From: telamonian Date: Mon, 30 Dec 2019 21:12:17 -0500 Subject: [PATCH 053/101] fix filebrowser unittests --- packages/ui-components/src/icon/jlicon.tsx | 2 +- tests/package.json | 1 + tests/webpack.config.js | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/ui-components/src/icon/jlicon.tsx b/packages/ui-components/src/icon/jlicon.tsx index 58030e0b743a..3c7b10eaee51 100644 --- a/packages/ui-components/src/icon/jlicon.tsx +++ b/packages/ui-components/src/icon/jlicon.tsx @@ -184,7 +184,7 @@ export class JLIcon { ); const svgElement = svgDoc.documentElement; - if (svgElement.getElementsByTagName('parsererror').length > 0) { + if (svgDoc.getElementsByTagName('parsererror').length > 0) { const errmsg = `SVG HTML was malformed for icon name: ${name}`; // parse failed, svgElement will be an error box if (JLIcon._debug) { diff --git a/tests/package.json b/tests/package.json index 665808d68e72..0c8cf53a734e 100644 --- a/tests/package.json +++ b/tests/package.json @@ -66,6 +66,7 @@ "raw-loader": "~4.0.0", "rimraf": "~3.0.0", "style-loader": "~1.0.1", + "svg-url-loader": "~3.0.3", "thread-loader": "^2.1.3", "ts-loader": "^6.2.1", "typescript": "~3.7.3", diff --git a/tests/webpack.config.js b/tests/webpack.config.js index f33e15a46794..a17570094d65 100644 --- a/tests/webpack.config.js +++ b/tests/webpack.config.js @@ -46,8 +46,22 @@ module.exports = { }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, use: 'file-loader' }, { + // in css files, svg is loaded as a url formatted string test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader?limit=10000&mimetype=image/svg+xml' + issuer: { test: /\.css$/ }, + use: { + loader: 'svg-url-loader', + options: { encoding: 'none', limit: 10000 } + } + }, + { + // in ts and tsx files (both of which compile to js), + // svg is loaded as a raw string + test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, + issuer: { test: /\.js$/ }, + use: { + loader: 'raw-loader' + } } ] } From a7566c2a13797e40e43eb9398d724b4352266f8f Mon Sep 17 00:00:00 2001 From: telamonian Date: Tue, 31 Dec 2019 05:57:22 -0500 Subject: [PATCH 054/101] removed refs to defaultIconReact and IIconregistry from non ui-x pkgs --- packages/apputils/src/toolbar.tsx | 60 ++++++++++------- packages/extensionmanager/src/widget.tsx | 18 +++--- packages/filebrowser-extension/src/index.ts | 8 +-- packages/filebrowser/src/browser.ts | 6 +- packages/filebrowser/src/listing.ts | 18 +++--- packages/filebrowser/src/model.ts | 13 ---- packages/filebrowser/src/opendialog.ts | 18 +----- packages/filebrowser/src/upload.ts | 3 +- packages/htmlviewer/package.json | 1 + packages/htmlviewer/src/index.tsx | 4 +- packages/htmlviewer/tsconfig.json | 3 + packages/notebook/src/default-toolbar.tsx | 64 ++++++------------- packages/running/src/index.tsx | 7 +- packages/statusbar/src/defaults/lineCol.tsx | 5 +- .../src/defaults/runningSessions.tsx | 11 +--- packages/ui-components/src/icon/jlicon.tsx | 30 +++++++-- 16 files changed, 123 insertions(+), 146 deletions(-) diff --git a/packages/apputils/src/toolbar.tsx b/packages/apputils/src/toolbar.tsx index a58d84f93505..525d85491f77 100644 --- a/packages/apputils/src/toolbar.tsx +++ b/packages/apputils/src/toolbar.tsx @@ -1,25 +1,24 @@ // Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. -import { UseSignal, ReactWidget } from './vdom'; - -import { Button, DefaultIconReact } from '@jupyterlab/ui-components'; +import { Text } from '@jupyterlab/coreutils'; +import { + Button, + JLIcon, + refreshIcon, + stopIcon +} from '@jupyterlab/ui-components'; import { IIterator, find, map, some } from '@lumino/algorithm'; - import { CommandRegistry } from '@lumino/commands'; - +import { ReadonlyJSONObject } from '@lumino/coreutils'; import { Message, MessageLoop } from '@lumino/messaging'; - import { AttachedProperty } from '@lumino/properties'; - import { PanelLayout, Widget } from '@lumino/widgets'; +import * as React from 'react'; import { ISessionContext, sessionContextDialogs } from './sessioncontext'; - -import * as React from 'react'; -import { ReadonlyJSONObject } from '@lumino/coreutils'; -import { Text } from '@jupyterlab/coreutils'; +import { UseSignal, ReactWidget } from './vdom'; /** * The class name added to toolbars. @@ -372,7 +371,7 @@ export namespace Toolbar { sessionContext: ISessionContext ): Widget { return new ToolbarButton({ - iconClassName: 'jp-StopIcon', + iconRenderer: stopIcon, onClick: () => { void sessionContext.session?.kernel?.interrupt(); }, @@ -388,7 +387,7 @@ export namespace Toolbar { dialogs?: ISessionContext.IDialogs ): Widget { return new ToolbarButton({ - iconClassName: 'jp-RefreshIcon', + iconRenderer: refreshIcon, onClick: () => { void (dialogs ?? sessionContextDialogs).restart(sessionContext); }, @@ -453,8 +452,9 @@ export namespace ToolbarButtonComponent { export interface IProps { className?: string; label?: string; - iconClassName?: string; + iconClass?: string; iconLabel?: string; + iconRenderer?: JLIcon; tooltip?: string; onClick?: () => void; enabled?: boolean; @@ -499,14 +499,20 @@ export function ToolbarButtonComponent(props: ToolbarButtonComponent.IProps) { title={props.tooltip || props.iconLabel} minimal > - {props.iconClassName && ( - + ) : ( + )} {props.label && ( @@ -612,7 +618,7 @@ namespace Private { options: CommandToolbarButtonComponent.IProps ): ToolbarButtonComponent.IProps { let { commands, id, args } = options; - const iconClassName = commands.iconClass(id, args); + const iconClass = commands.iconClass(id, args); const iconLabel = commands.iconLabel(id, args); const label = commands.label(id, args); let className = commands.className(id, args); @@ -628,7 +634,7 @@ namespace Private { void commands.execute(id, args); }; const enabled = commands.isEnabled(id, args); - return { className, iconClassName, tooltip, onClick, enabled, label }; + return { className, iconClass, tooltip, onClick, enabled, label }; } /** @@ -724,6 +730,14 @@ namespace Private { let status = sessionContext.kernelDisplayStatus; + // TODO: use the following to set the kernel status icon + // // set the icon + // if (this._isBusy(status)) { + // circle.element({container: this.node, title: `Kernel ${Text.titleCase(status)}`, center: true, kind: 'toolbarButton'}); + // } else { + // emptyCircleIcon.element({container: this.node, title: `Kernel ${Text.titleCase(status)}`, center: true, kind: 'toolbarButton'}); + // } + const busy = this._isBusy(status); this.toggleClass(TOOLBAR_BUSY_CLASS, busy); this.toggleClass(TOOLBAR_IDLE_CLASS, !busy); diff --git a/packages/extensionmanager/src/widget.tsx b/packages/extensionmanager/src/widget.tsx index 91a78448ad40..0e39415c01ad 100644 --- a/packages/extensionmanager/src/widget.tsx +++ b/packages/extensionmanager/src/widget.tsx @@ -2,19 +2,19 @@ // Distributed under the terms of the Modified BSD License. import { VDomRenderer, ToolbarButtonComponent } from '@jupyterlab/apputils'; - import { ServiceManager } from '@jupyterlab/services'; +import { + Button, + InputGroup, + Collapse, + refreshIcon +} from '@jupyterlab/ui-components'; import { Message } from '@lumino/messaging'; - -import { Button, InputGroup, Collapse } from '@jupyterlab/ui-components'; - import * as React from 'react'; - import ReactPaginate from 'react-paginate'; import { ListModel, IEntry, Action } from './model'; - import { isJupyterOrg } from './query'; // TODO: Replace pagination with lazy loading of lower search results @@ -335,6 +335,7 @@ export class CollapsibleSection extends React.Component< }; } + // TODO: swtich to iconRenderer /** * Render the collapsible section using the virtual DOM. */ @@ -343,7 +344,7 @@ export class CollapsibleSection extends React.Component< <>
    { headerElements={ { model.refreshInstalled(); }} diff --git a/packages/filebrowser-extension/src/index.ts b/packages/filebrowser-extension/src/index.ts index 211b5bafc8bf..d54a2d47ec43 100644 --- a/packages/filebrowser-extension/src/index.ts +++ b/packages/filebrowser-extension/src/index.ts @@ -42,7 +42,7 @@ import { IStateDB } from '@jupyterlab/statedb'; import { IStatusBar } from '@jupyterlab/statusbar'; -import { folderIcon, IIconRegistry } from '@jupyterlab/ui-components'; +import { addIcon, folderIcon } from '@jupyterlab/ui-components'; import { IIterator, map, reduce, toArray } from '@lumino/algorithm'; @@ -133,7 +133,7 @@ const factory: JupyterFrontEndPlugin = { activate: activateFactory, id: '@jupyterlab/filebrowser-extension:factory', provides: IFileBrowserFactory, - requires: [IIconRegistry, IDocumentManager], + requires: [IDocumentManager], optional: [IStateDB, IRouter, JupyterFrontEnd.ITreeResolver] }; @@ -211,7 +211,6 @@ export default plugins; */ async function activateFactory( app: JupyterFrontEnd, - icoReg: IIconRegistry, docManager: IDocumentManager, state: IStateDB | null, router: IRouter | null, @@ -225,7 +224,6 @@ async function activateFactory( ) => { const model = new FileBrowserModel({ auto: options.auto ?? true, - iconRegistry: icoReg, manager: docManager, driveName: options.driveName || '', refreshInterval: options.refreshInterval, @@ -237,7 +235,7 @@ async function activateFactory( // Add a launcher toolbar item. let launcher = new ToolbarButton({ - iconClassName: 'jp-AddIcon', + iconRenderer: addIcon, onClick: () => { return Private.createLauncher(commands, widget); }, diff --git a/packages/filebrowser/src/browser.ts b/packages/filebrowser/src/browser.ts index bc0cc93616f2..a2b8591843c1 100644 --- a/packages/filebrowser/src/browser.ts +++ b/packages/filebrowser/src/browser.ts @@ -7,6 +7,8 @@ import { IDocumentManager } from '@jupyterlab/docmanager'; import { Contents, ServerConnection } from '@jupyterlab/services'; +import { newFolderIcon, refreshIcon } from '@jupyterlab/ui-components'; + import { IIterator } from '@lumino/algorithm'; import { PanelLayout, Widget } from '@lumino/widgets'; @@ -67,7 +69,7 @@ export class FileBrowser extends Widget { this._directoryPending = false; const newFolder = new ToolbarButton({ - iconClassName: 'jp-NewFolderIcon', + iconRenderer: newFolderIcon, onClick: () => { this.createNewDirectory(); }, @@ -75,7 +77,7 @@ export class FileBrowser extends Widget { }); const uploader = new Uploader({ model }); const refresher = new ToolbarButton({ - iconClassName: 'jp-RefreshIcon', + iconRenderer: refreshIcon, onClick: () => { void model.refresh(); }, diff --git a/packages/filebrowser/src/listing.ts b/packages/filebrowser/src/listing.ts index b256430315bd..4408582cdb54 100644 --- a/packages/filebrowser/src/listing.ts +++ b/packages/filebrowser/src/listing.ts @@ -20,7 +20,7 @@ import { DocumentRegistry } from '@jupyterlab/docregistry'; import { Contents } from '@jupyterlab/services'; -import { fileIcon, IIconRegistry, JLIcon } from '@jupyterlab/ui-components'; +import { fileIcon, JLIcon } from '@jupyterlab/ui-components'; import { ArrayExt, @@ -193,9 +193,7 @@ export class DirListing extends Widget { */ constructor(options: DirListing.IOptions) { super({ - node: (options.renderer = - options.renderer || - new DirListing.Renderer(options.model.iconRegistry)).createNode() + node: (options.renderer || DirListing.defaultRenderer).createNode() }); this.addClass(DIR_LISTING_CLASS); this._model = options.model; @@ -205,7 +203,7 @@ export class DirListing extends Widget { this._editNode = document.createElement('input'); this._editNode.className = EDITOR_CLASS; this._manager = this._model.manager; - this._renderer = options.renderer; + this._renderer = options.renderer || DirListing.defaultRenderer; const headerNode = DOMUtils.findElement(this.node, HEADER_CLASS); this._renderer.populateHeaderNode(headerNode); @@ -1685,10 +1683,6 @@ export namespace DirListing { * The default implementation of an `IRenderer`. */ export class Renderer implements IRenderer { - constructor(icoReg: IIconRegistry) { - this._iconRegistry = icoReg; - } - /** * Create the DOM node for a dir listing. */ @@ -1928,8 +1922,12 @@ export namespace DirListing { node.appendChild(icon); return node; } - _iconRegistry: IIconRegistry; } + + /** + * The default `IRenderer` instance. + */ + export const defaultRenderer = new Renderer(); } /** diff --git a/packages/filebrowser/src/model.ts b/packages/filebrowser/src/model.ts index a62d300edc24..403d220dc04c 100644 --- a/packages/filebrowser/src/model.ts +++ b/packages/filebrowser/src/model.ts @@ -11,8 +11,6 @@ import { Contents, KernelSpec, Session } from '@jupyterlab/services'; import { IStateDB } from '@jupyterlab/statedb'; -import { IIconRegistry } from '@jupyterlab/ui-components'; - import { ArrayIterator, each, @@ -69,7 +67,6 @@ export class FileBrowserModel implements IDisposable { * Construct a new file browser model. */ constructor(options: FileBrowserModel.IOptions) { - this.iconRegistry = options.iconRegistry; this.manager = options.manager; this._driveName = options.driveName || ''; let rootPath = this._driveName ? this._driveName + ':' : ''; @@ -113,11 +110,6 @@ export class FileBrowserModel implements IDisposable { }); } - /** - * The icon registry instance used by the file browser model. - */ - readonly iconRegistry: IIconRegistry; - /** * The document manager instance used by the file browser model. */ @@ -670,11 +662,6 @@ export namespace FileBrowserModel { */ driveName?: string; - /** - * An icon registry instance. - */ - iconRegistry: IIconRegistry; - /** * A document manager instance. */ diff --git a/packages/filebrowser/src/opendialog.ts b/packages/filebrowser/src/opendialog.ts index b0a6a03ed75e..2cf0f802ffab 100644 --- a/packages/filebrowser/src/opendialog.ts +++ b/packages/filebrowser/src/opendialog.ts @@ -8,7 +8,6 @@ import { PathExt } from '@jupyterlab/coreutils'; import { Dialog } from '@jupyterlab/apputils'; import { IDocumentManager } from '@jupyterlab/docmanager'; import { Contents } from '@jupyterlab/services'; -import { IIconRegistry } from '@jupyterlab/ui-components'; import { FileBrowser } from './browser'; import { FilterFileBrowserModel } from './model'; @@ -36,11 +35,6 @@ export namespace FileDialog { > > > { - /** - * An icon registry instance. - */ - iconRegistry: IIconRegistry; - /** * Document manager */ @@ -81,11 +75,7 @@ export namespace FileDialog { focusNodeSelector: options.focusNodeSelector, host: options.host, renderer: options.renderer, - body: new OpenDialog( - options.iconRegistry, - options.manager, - options.filter - ) + body: new OpenDialog(options.manager, options.filter) }; let dialog = new Dialog(dialogOptions); return dialog.launch(); @@ -117,7 +107,6 @@ export namespace FileDialog { class OpenDialog extends Widget implements Dialog.IBodyWidget { constructor( - iconRegistry: IIconRegistry, manager: IDocumentManager, filter?: (value: Contents.IModel) => boolean ) { @@ -126,7 +115,6 @@ class OpenDialog extends Widget this._browser = Private.createFilteredFileBrowser( 'filtered-file-browser-dialog', - iconRegistry, manager, filter ); @@ -173,8 +161,6 @@ namespace Private { * * @param id - The widget/DOM id of the file browser. * - * @param iconRegistry - An icon registry instance. - * * @param manager - A document manager instance. * * @param filter - function to filter file browser item. @@ -194,13 +180,11 @@ namespace Private { */ export const createFilteredFileBrowser = ( id: string, - iconRegistry: IIconRegistry, manager: IDocumentManager, filter?: (value: Contents.IModel) => boolean, options: IFileBrowserFactory.IOptions = {} ) => { const model = new FilterFileBrowserModel({ - iconRegistry, manager, filter, driveName: options.driveName, diff --git a/packages/filebrowser/src/upload.ts b/packages/filebrowser/src/upload.ts index 5045066fca5b..b89eb7e14ade 100644 --- a/packages/filebrowser/src/upload.ts +++ b/packages/filebrowser/src/upload.ts @@ -2,6 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { ToolbarButton, showErrorMessage } from '@jupyterlab/apputils'; +import { fileUploadIcon } from '@jupyterlab/ui-components'; import { FileBrowserModel } from './model'; @@ -14,7 +15,7 @@ export class Uploader extends ToolbarButton { */ constructor(options: Uploader.IOptions) { super({ - iconClassName: 'jp-FileUploadIcon', + iconRenderer: fileUploadIcon, onClick: () => { this._input.click(); }, diff --git a/packages/htmlviewer/package.json b/packages/htmlviewer/package.json index 159d335cca4a..ff47bed1c100 100644 --- a/packages/htmlviewer/package.json +++ b/packages/htmlviewer/package.json @@ -35,6 +35,7 @@ "@jupyterlab/apputils": "^2.0.0-alpha.4", "@jupyterlab/coreutils": "^4.0.0-alpha.4", "@jupyterlab/docregistry": "^2.0.0-alpha.4", + "@jupyterlab/ui-components": "^2.0.0-alpha.4", "@lumino/coreutils": "^1.4.0", "@lumino/signaling": "^1.3.2", "react": "~16.9.0" diff --git a/packages/htmlviewer/src/index.tsx b/packages/htmlviewer/src/index.tsx index 2f7347cefabc..87934cca674c 100644 --- a/packages/htmlviewer/src/index.tsx +++ b/packages/htmlviewer/src/index.tsx @@ -21,6 +21,8 @@ import { IDocumentWidget } from '@jupyterlab/docregistry'; +import { refreshIcon } from '@jupyterlab/ui-components'; + import { Token } from '@lumino/coreutils'; import { ISignal, Signal } from '@lumino/signaling'; @@ -87,7 +89,7 @@ export class HTMLViewer extends DocumentWidget