|
@@ -1,6 +1,11 @@
|
|
// Copyright (c) Jupyter Development Team.
|
|
// Copyright (c) Jupyter Development Team.
|
|
// Distributed under the terms of the Modified BSD License.
|
|
// Distributed under the terms of the Modified BSD License.
|
|
|
|
|
|
|
|
+import React from 'react';
|
|
|
|
+import { classes } from 'typestyle/lib';
|
|
|
|
+
|
|
|
|
+import { IIconStyle, iconStyle, iconNestedStyle } from '../style/icon';
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* To add an icon to the defaultIconRegistry requires two lines of code:
|
|
* To add an icon to the defaultIconRegistry requires two lines of code:
|
|
* 1. import the icon's .svg
|
|
* 1. import the icon's .svg
|
|
@@ -47,9 +52,27 @@ export class IconRegistry {
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
- icon(name: string, title?: string): HTMLElement {
|
|
|
|
|
|
+ svg(name: string): string {
|
|
|
|
+ if (!(name in this._svgs)) {
|
|
|
|
+ console.error(`Invalid icon name: ${name}`);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return this._svgs[name];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Get the icon as an HTMLElement of tag <svg><svg/>
|
|
|
|
+ */
|
|
|
|
+ icon(props: IconRegistry.IIcon): HTMLElement {
|
|
|
|
+ const { name, title, parent, ...propStyle } = props;
|
|
|
|
+
|
|
|
|
+ let svgNode = Private.parseSvg(this.svg(name));
|
|
|
|
+
|
|
|
|
+ // style the svg node
|
|
|
|
+ svgNode.className = iconStyle(propStyle);
|
|
|
|
+
|
|
if (title) {
|
|
if (title) {
|
|
- let svgNode = Private.parseSvg(this.svg(name));
|
|
|
|
|
|
+ // add a title node to the top level svg node
|
|
let titleNodes = svgNode.getElementsByTagName('title');
|
|
let titleNodes = svgNode.getElementsByTagName('title');
|
|
if (titleNodes) {
|
|
if (titleNodes) {
|
|
titleNodes[0].textContent = title;
|
|
titleNodes[0].textContent = title;
|
|
@@ -58,28 +81,32 @@ export class IconRegistry {
|
|
titleNode.textContent = title;
|
|
titleNode.textContent = title;
|
|
svgNode.appendChild(titleNode);
|
|
svgNode.appendChild(titleNode);
|
|
}
|
|
}
|
|
- return svgNode;
|
|
|
|
- } else {
|
|
|
|
- return Private.parseSvg(this.svg(name));
|
|
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- svg(name: string): string {
|
|
|
|
- if (!(name in this._svgs)) {
|
|
|
|
- console.error(`Invalid icon name: ${name}`);
|
|
|
|
|
|
+ if (parent) {
|
|
|
|
+ // clear any existing icon in parent (and all other child elements)
|
|
|
|
+ parent.textContent = '';
|
|
|
|
+ parent.appendChild(svgNode);
|
|
}
|
|
}
|
|
|
|
|
|
- return this._svgs[name];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- attachIcon(node: HTMLElement, name: string, title?: string): void {
|
|
|
|
- node.appendChild(this.icon(name, title));
|
|
|
|
|
|
+ return svgNode;
|
|
}
|
|
}
|
|
|
|
|
|
- setIcon(node: HTMLElement, name: string, title?: string): void {
|
|
|
|
- // clear any existing icon (and all other child elements)
|
|
|
|
- node.textContent = '';
|
|
|
|
- this.attachIcon(node, name, title);
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Get the icon as a ReactElement of tag <tag><svg><svg/><tag/>
|
|
|
|
+ * TODO: figure out how to remove the unnecessary outer <tag>
|
|
|
|
+ */
|
|
|
|
+ iconReact(
|
|
|
|
+ props: IconRegistry.IIcon & { tag?: 'div' | 'span'; className?: string }
|
|
|
|
+ ): React.ReactElement {
|
|
|
|
+ const { name, className, tag, ...propStyle } = props;
|
|
|
|
+ const Tag = tag || 'div';
|
|
|
|
+ return (
|
|
|
|
+ <Tag
|
|
|
|
+ className={classes(className, iconNestedStyle(propStyle))}
|
|
|
|
+ dangerouslySetInnerHTML={{ __html: this.svg(name) }}
|
|
|
|
+ />
|
|
|
|
+ );
|
|
}
|
|
}
|
|
|
|
|
|
private _svgs: { [key: string]: string } = Object.create(null);
|
|
private _svgs: { [key: string]: string } = Object.create(null);
|
|
@@ -90,12 +117,27 @@ export class IconRegistry {
|
|
*/
|
|
*/
|
|
export const defaultIconRegistry: IconRegistry = new IconRegistry();
|
|
export const defaultIconRegistry: IconRegistry = new IconRegistry();
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Alias for defaultIconRegistry.iconReact that can be used as a React component
|
|
|
|
+ */
|
|
|
|
+export const IconReact = (
|
|
|
|
+ props: IconRegistry.IIcon & { tag?: 'div' | 'span'; className?: string }
|
|
|
|
+): React.ReactElement => {
|
|
|
|
+ return defaultIconRegistry.iconReact(props);
|
|
|
|
+};
|
|
|
|
+
|
|
export namespace IconRegistry {
|
|
export namespace IconRegistry {
|
|
export interface IModel {
|
|
export interface IModel {
|
|
name: string;
|
|
name: string;
|
|
svg: string;
|
|
svg: string;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ export interface IIcon extends IIconStyle {
|
|
|
|
+ name: string;
|
|
|
|
+ title?: string;
|
|
|
|
+ parent?: HTMLElement;
|
|
|
|
+ }
|
|
|
|
+
|
|
export const defaultIcons = _defaultIcons;
|
|
export const defaultIcons = _defaultIcons;
|
|
}
|
|
}
|
|
|
|
|