@jupyterlab/ui-components
Advanced tools
Comparing version 1.2.0-alpha.0 to 1.2.0-alpha.1
@@ -29,2 +29,10 @@ /*----------------------------------------------------------------------------- | ||
import trustedSvg from '../../style/icons/statusbar/trusted.svg'; | ||
import addSvg from '../../style/icons/toolbar/add.svg'; | ||
import copySvg from '../../style/icons/toolbar/copy.svg'; | ||
import cutSvg from '../../style/icons/toolbar/cut.svg'; | ||
import pasteSvg from '../../style/icons/toolbar/paste.svg'; | ||
import refreshSvg from '../../style/icons/toolbar/refresh.svg'; | ||
import runSvg from '../../style/icons/toolbar/run.svg'; | ||
import saveSvg from '../../style/icons/toolbar/save.svg'; | ||
import stopSvg from '../../style/icons/toolbar/stop.svg'; | ||
// defaultIcons definition | ||
@@ -56,5 +64,13 @@ export var IconImports; | ||
{ name: 'terminal', svg: terminalSvg }, | ||
{ name: 'trusted', svg: trustedSvg } | ||
{ name: 'trusted', svg: trustedSvg }, | ||
{ name: 'add', svg: addSvg }, | ||
{ name: 'copy', svg: copySvg }, | ||
{ name: 'cut', svg: cutSvg }, | ||
{ name: 'paste', svg: pasteSvg }, | ||
{ name: 'refresh', svg: refreshSvg }, | ||
{ name: 'run', svg: runSvg }, | ||
{ name: 'save', svg: saveSvg }, | ||
{ name: 'stop', svg: stopSvg } | ||
]; | ||
})(IconImports || (IconImports = {})); | ||
//# sourceMappingURL=iconimports.js.map |
@@ -23,3 +23,5 @@ import React from 'react'; | ||
}): React.ReactElement; | ||
private _resolveName; | ||
resolveName(name: string): string; | ||
resolveSvg(name: string): HTMLElement | null; | ||
svg(name: string): string; | ||
@@ -26,0 +28,0 @@ static iconClassName(name: string): string; |
@@ -47,3 +47,3 @@ // Copyright (c) Jupyter Development Team. | ||
contains(name) { | ||
return name in this._svg || name in this._classNameToName; | ||
return !!this._resolveName(name); | ||
} | ||
@@ -54,15 +54,38 @@ /** | ||
icon(props) { | ||
const { name, className, title, container } = props, propsStyle = __rest(props, ["name", "className", "title", "container"]); | ||
const { name, className, title, fallback, container } = props, propsStyle = __rest(props, ["name", "className", "title", "fallback", "container"]); | ||
// we may have been handed a className in place of name | ||
let resolvedName = this.resolveName(name); | ||
if (!resolvedName || | ||
(container && | ||
container.dataset.icon && | ||
container.dataset.icon === resolvedName)) { | ||
// bail if failing silently or icon node is already set | ||
return; | ||
if (!resolvedName) { | ||
// TODO: remove fallback in jlab 2.0 | ||
if (fallback) { | ||
if (container) { | ||
container.textContent = title || ''; | ||
container.className = classes(name, className); | ||
return container; | ||
} | ||
else { | ||
// the non-container fallback isn't implemented | ||
console.error('unimplemented'); | ||
return null; | ||
} | ||
} | ||
// bail if failing silently | ||
return null; | ||
} | ||
let svgNode = Private.parseSvg(this.svg(resolvedName)); | ||
// check if icon element is already set | ||
if (container && | ||
container.dataset.icon && | ||
container.dataset.icon === resolvedName && | ||
container.children[0]) { | ||
// return the existing icon element | ||
return container.children[0]; | ||
} | ||
// ensure that svg html is valid | ||
const svgElement = this.resolveSvg(resolvedName); | ||
if (!svgElement) { | ||
// bail if failing silently | ||
return null; | ||
} | ||
if (title) { | ||
Private.setTitleSvg(svgNode, title); | ||
Private.setTitleSvg(svgElement, title); | ||
} | ||
@@ -73,3 +96,3 @@ if (container) { | ||
container.dataset.icon = resolvedName; | ||
container.appendChild(svgNode); | ||
container.appendChild(svgElement); | ||
let styleClass = propsStyle ? iconStyle(propsStyle) : ''; | ||
@@ -87,5 +110,5 @@ if (className || className === '') { | ||
// add icon styling class directly to the svg node | ||
svgNode.setAttribute('class', classes(className, propsStyle ? iconStyleFlat(propsStyle) : '')); | ||
svgElement.setAttribute('class', classes(className, propsStyle ? iconStyleFlat(propsStyle) : '')); | ||
} | ||
return svgNode; | ||
return svgElement; | ||
} | ||
@@ -97,15 +120,28 @@ /** | ||
iconReact(props) { | ||
const { name, className, title, tag } = props, propsStyle = __rest(props, ["name", "className", "title", "tag"]); | ||
const { name, className, title, fallback, tag } = props, propsStyle = __rest(props, ["name", "className", "title", "fallback", "tag"]); | ||
const Tag = tag || 'div'; | ||
// we may have been handed a className in place of name | ||
let resolvedName = this.resolveName(name); | ||
const resolvedName = this.resolveName(name); | ||
if (!resolvedName) { | ||
// TODO: remove fallback in jlab 2.0 | ||
if (fallback) { | ||
return React.createElement(Tag, { className: classes(name, className) }, title || ''); | ||
} | ||
// bail if failing silently | ||
return React.createElement(React.Fragment, null); | ||
} | ||
return (React.createElement(Tag, { className: classes(className, propsStyle ? iconStyle(propsStyle) : ''), dangerouslySetInnerHTML: { | ||
__html: resolvedName ? this.svg(resolvedName) : '' | ||
// ensure that svg html is valid | ||
const svgElement = this.resolveSvg(resolvedName); | ||
if (!svgElement) { | ||
// bail if failing silently | ||
return React.createElement(React.Fragment, null); | ||
} | ||
if (title) { | ||
Private.setTitleSvg(svgElement, title); | ||
} | ||
return (React.createElement(Tag, { className: classes(className, propsStyle ? iconStyle(propsStyle) : ''), "data-icon": resolvedName, dangerouslySetInnerHTML: { | ||
__html: svgElement.outerHTML | ||
} })); | ||
} | ||
resolveName(name) { | ||
_resolveName(name) { | ||
if (!(name in this._svg)) { | ||
@@ -121,2 +157,10 @@ // skip resolution if name is not defined | ||
} | ||
// couldn't resolve name, fail silently | ||
return ''; | ||
} | ||
return name; | ||
} | ||
resolveName(name) { | ||
const resolvedName = this._resolveName(name); | ||
if (!resolvedName) { | ||
if (this._debug) { | ||
@@ -132,4 +176,35 @@ // couldn't resolve name, mark as bad and warn | ||
} | ||
return name; | ||
return resolvedName; | ||
} | ||
resolveSvg(name) { | ||
let svgHtml = this.svg(name); | ||
// workaround for 1.0.x versions of Jlab pulling in 1.1.x versions of ui-components | ||
// TODO: delete workaround in v2.0.0 | ||
const bprefix = 'data:image/svg+xml;base64,'; | ||
if (svgHtml.startsWith(bprefix)) { | ||
// slice off the prefix and covert base64 to string | ||
svgHtml = atob(svgHtml.slice(bprefix.length)); | ||
} | ||
const parser = new DOMParser(); | ||
const svgElement = parser.parseFromString(svgHtml, '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; | ||
} | ||
} | ||
svg(name) { | ||
@@ -154,11 +229,6 @@ return this._svg[name]; | ||
(function (Private) { | ||
function parseSvg(svg) { | ||
let parser = new DOMParser(); | ||
return parser.parseFromString(svg, 'image/svg+xml').documentElement; | ||
} | ||
Private.parseSvg = parseSvg; | ||
function setTitleSvg(svgNode, title) { | ||
// add a title node to the top level svg node | ||
let titleNodes = svgNode.getElementsByTagName('title'); | ||
if (titleNodes) { | ||
if (titleNodes.length) { | ||
titleNodes[0].textContent = title; | ||
@@ -165,0 +235,0 @@ } |
@@ -41,4 +41,14 @@ import { Token } from '@phosphor/coreutils'; | ||
interface IModel { | ||
/** | ||
* The icon name. For a 'foo-bar.svg' file, the icon name is 'foo-bar'. | ||
*/ | ||
name: string; | ||
/** | ||
* Manually set the className corresponding to the icon name. By default, | ||
* the className is generated from the name: 'foo-bar' -> 'jp-FooBarIcon' | ||
*/ | ||
className?: string; | ||
/** | ||
* A string containing the html corresponding to an SVG element | ||
*/ | ||
svg: string; | ||
@@ -50,6 +60,27 @@ } | ||
interface INodeOptions extends IIconStyle { | ||
/** | ||
* The icon name. For a 'foo-bar.svg' file, the icon name is 'foo-bar'. | ||
* For backwards compatibility, 'jp-FooBarIcon' is also a valid icon name. | ||
* | ||
* TODO: until Jlab 2.0 | ||
* If fallback is set, the name is added to the className | ||
* of the resulting icon node | ||
*/ | ||
name: string; | ||
/** | ||
* Extra classNames, used in addition to the typestyle className | ||
*/ | ||
className?: string; | ||
/** | ||
* Icon title | ||
*/ | ||
title?: string; | ||
/** | ||
* If true, if icon name resolution fails, fallback to old | ||
* icon handling behavior. | ||
* | ||
* TODO: remove in Jlab 2.0 | ||
*/ | ||
fallback?: boolean; | ||
} | ||
} |
@@ -35,2 +35,3 @@ import { h } from '@phosphor/virtualdom'; | ||
className: '', | ||
title: title.iconLabel, | ||
container: iconNode, | ||
@@ -37,0 +38,0 @@ center: true, |
@@ -13,3 +13,3 @@ import { NestedCSSProperties } from 'typestyle/lib/types'; | ||
*/ | ||
export declare type IconKindType = 'breadCrumb' | 'dockPanelBar' | 'launcherCard' | 'launcherSection' | 'listing' | 'settingsEditor' | 'sideBar' | 'splash' | 'statusBar' | 'tabManager' | 'unset'; | ||
export declare type IconKindType = 'breadCrumb' | 'dockPanelBar' | 'launcherCard' | 'launcherSection' | 'listing' | 'settingsEditor' | 'sideBar' | 'splash' | 'statusBar' | 'tabManager' | 'toolbarButton' | 'unset'; | ||
export interface IIconStyle extends NestedCSSProperties { | ||
@@ -16,0 +16,0 @@ /** |
@@ -14,3 +14,3 @@ // Copyright (c) Jupyter Development Team. | ||
}; | ||
import { cssRule, style } from 'typestyle/lib'; | ||
import { style } from 'typestyle/lib'; | ||
/** | ||
@@ -39,2 +39,3 @@ * styles for centering node inside of containers | ||
verticalAlign: 'middle', | ||
// `&` will be substituted for the generated classname (interpolation) | ||
$nest: { | ||
@@ -47,3 +48,3 @@ '&:hover': { | ||
}, | ||
['.jp-mod-dropTarget']: { | ||
['.jp-mod-dropTarget&']: { | ||
backgroundColor: 'var(--jp-brand-color2)', | ||
@@ -92,2 +93,6 @@ opacity: 0.7 | ||
}; | ||
const iconCSSToolbarButton = { | ||
height: '16px', | ||
width: '16px' | ||
}; | ||
const iconCSSKind = { | ||
@@ -104,2 +109,3 @@ breadCrumb: iconCSSBreadCrumb, | ||
tabManager: iconCSSTabManager, | ||
toolbarButton: iconCSSToolbarButton, | ||
unset: {} | ||
@@ -131,3 +137,29 @@ }; | ||
const containerCSSSideBar = { | ||
transform: 'rotate(90deg)' | ||
// `&` will be substituted for the generated classname (interpolation) | ||
$nest: { | ||
// left sidebar tab divs | ||
'.jp-SideBar.jp-mod-left .p-TabBar-tab &': { | ||
transform: 'rotate(90deg)' | ||
}, | ||
// left sidebar currently selected tab div | ||
'.jp-SideBar.jp-mod-left .p-TabBar-tab.p-mod-current &': { | ||
transform: 'rotate(90deg)\n' + | ||
' translate(\n' + | ||
' calc(-0.5 * var(--jp-border-width)),\n' + | ||
' calc(-0.5 * var(--jp-border-width))\n' + | ||
' )' | ||
}, | ||
// right sidebar tab divs | ||
'.jp-SideBar.jp-mod-right .p-TabBar-tab &': { | ||
transform: 'rotate(-90deg)' | ||
}, | ||
// right sidebar currently selected tab div | ||
'.jp-SideBar.jp-mod-right .p-TabBar-tab.p-mod-current &': { | ||
transform: 'rotate(-90deg)\n' + | ||
' translate(\n' + | ||
' calc(0.5 * var(--jp-border-width)),\n' + | ||
' calc(-0.5 * var(--jp-border-width))\n' + | ||
' )' | ||
} | ||
} | ||
}; | ||
@@ -144,2 +176,7 @@ const containerCSSSplash = { | ||
}; | ||
const containerCSSToolbarButton = { | ||
display: 'inline-block', | ||
margin: 'auto', | ||
verticalAlign: 'middle' | ||
}; | ||
const containerCSSKind = { | ||
@@ -156,2 +193,3 @@ breadCrumb: {}, | ||
tabManager: containerCSSTabManager, | ||
toolbarButton: containerCSSToolbarButton, | ||
unset: {} | ||
@@ -179,5 +217,4 @@ }; | ||
export const iconStyle = (props) => { | ||
return style(Object.assign({}, containerCSS(props), { $nest: { | ||
['svg']: iconCSS(props) | ||
} })); | ||
const conCSS = containerCSS(props); | ||
return style(Object.assign({}, conCSS, { $nest: Object.assign({}, conCSS.$nest, { ['svg']: iconCSS(props) }) })); | ||
}; | ||
@@ -190,13 +227,2 @@ /** | ||
}; | ||
// TODO: Figure out a better cludge for styling current sidebar tab selection | ||
cssRule(`.p-TabBar-tab.p-mod-current .${iconStyle({ | ||
center: true, | ||
kind: 'sideBar' | ||
})}`, { | ||
transform: 'rotate(90deg)\n' + | ||
' translate(\n' + | ||
' calc(-0.5 * var(--jp-border-width)),\n' + | ||
' calc(-0.5 * var(--jp-border-width))\n' + | ||
' )' | ||
}); | ||
//# sourceMappingURL=icon.js.map |
{ | ||
"name": "@jupyterlab/ui-components", | ||
"version": "1.2.0-alpha.0", | ||
"version": "1.2.0-alpha.1", | ||
"description": "JupyterLab - UI components written in React", | ||
@@ -38,7 +38,7 @@ "homepage": "https://github.com/jupyterlab/jupyterlab", | ||
"@blueprintjs/select": "^3.3.0", | ||
"@jupyterlab/coreutils": "^3.2.0-alpha.0", | ||
"@jupyterlab/coreutils": "^3.2.0-alpha.1", | ||
"@phosphor/coreutils": "^1.3.1", | ||
"@phosphor/messaging": "^1.2.3", | ||
"@phosphor/virtualdom": "^1.1.3", | ||
"@phosphor/widgets": "^1.8.0", | ||
"@phosphor/messaging": "^1.3.0", | ||
"@phosphor/virtualdom": "^1.2.0", | ||
"@phosphor/widgets": "^1.9.0", | ||
"react": "~16.8.4", | ||
@@ -68,3 +68,3 @@ "typestyle": "^2.0.1" | ||
}, | ||
"gitHead": "5132f054efca4d76b21dfefe5720a5aec1ec2f3d" | ||
"gitHead": "f687800b475279c3de0eb990fce7f06b8e945427" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
128427
78
1231