From e1098d1f8b9968ed03db611c4cbd0c10b2467f29 Mon Sep 17 00:00:00 2001 From: Grant Nestor Date: Thu, 5 Oct 2017 15:57:47 -0700 Subject: [PATCH 1/7] v0.10.1 --- lerna.json | 2 +- packages/geojson-extension/package.json | 2 +- packages/json-extension/package.json | 2 +- packages/plotly-extension/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lerna.json b/lerna.json index 228d7d09b..c0b556e4e 100644 --- a/lerna.json +++ b/lerna.json @@ -3,5 +3,5 @@ "packages": [ "packages/*" ], - "version": "0.10.0" + "version": "0.10.1" } diff --git a/packages/geojson-extension/package.json b/packages/geojson-extension/package.json index 47d2e9031..54d5ea802 100644 --- a/packages/geojson-extension/package.json +++ b/packages/geojson-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/geojson-extension", - "version": "0.10.0", + "version": "0.10.1", "description": "JupyterLab - GeoJSON Renderer", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/json-extension/package.json b/packages/json-extension/package.json index 2818d7250..c4739cea5 100644 --- a/packages/json-extension/package.json +++ b/packages/json-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/json-extension", - "version": "0.10.0", + "version": "0.10.1", "description": "JupyterLab - JSON Renderer", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/plotly-extension/package.json b/packages/plotly-extension/package.json index b1aee307d..4bb435e2d 100644 --- a/packages/plotly-extension/package.json +++ b/packages/plotly-extension/package.json @@ -1,6 +1,6 @@ { "name": "@jupyterlab/plotly-extension", - "version": "0.10.0", + "version": "0.10.1", "description": "JupyterLab - Plotly Renderer", "main": "lib/index.js", "types": "lib/index.d.ts", From fd2d6f8043e73c1ffca387b747c148e126eb4505 Mon Sep 17 00:00:00 2001 From: Grant Nestor Date: Thu, 28 Sep 2017 12:09:41 -0700 Subject: [PATCH 2/7] Add vdom-extension --- packages/vdom-extension/package.json | 45 +++++++ packages/vdom-extension/src/index.tsx | 113 ++++++++++++++++++ .../vdom-extension/src/object-to-react.ts | 83 +++++++++++++ packages/vdom-extension/style/index.css | 34 ++++++ packages/vdom-extension/style/react.svg | 35 ++++++ packages/vdom-extension/tsconfig.json | 16 +++ 6 files changed, 326 insertions(+) create mode 100644 packages/vdom-extension/package.json create mode 100644 packages/vdom-extension/src/index.tsx create mode 100644 packages/vdom-extension/src/object-to-react.ts create mode 100644 packages/vdom-extension/style/index.css create mode 100644 packages/vdom-extension/style/react.svg create mode 100644 packages/vdom-extension/tsconfig.json diff --git a/packages/vdom-extension/package.json b/packages/vdom-extension/package.json new file mode 100644 index 000000000..5ab46e696 --- /dev/null +++ b/packages/vdom-extension/package.json @@ -0,0 +1,45 @@ +{ + "name": "@jupyterlab/vdom-extension", + "version": "0.10.0", + "description": "JupyterLab - VDOM Renderer", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "files": [ + "lib/*.d.ts", + "lib/*.js", + "style/*" + ], + "directories": { + "lib": "lib/" + }, + "jupyterlab": { + "mimeExtension": true + }, + "dependencies": { + "@jupyterlab/rendermime-interfaces": "^0.3.0", + "@phosphor/widgets": "^1.3.0", + "react": "^15.6.1", + "react-dom": "^15.6.1" + }, + "devDependencies": { + "@types/react": "^15.0.33", + "@types/react-dom": "^15.5.1", + "rimraf": "^2.5.2", + "typescript": "~2.3.1" + }, + "scripts": { + "build": "tsc", + "clean": "rimraf lib", + "watch": "tsc -w" + }, + "repository": { + "type": "git", + "url": "https://github.com/jupyterlab/jupyter-renderers.git" + }, + "author": "Project Jupyter", + "license": "BSD-3-Clause", + "bugs": { + "url": "https://github.com/jupyterlab/jupyter-renderers/issues" + }, + "homepage": "https://github.com/jupyterlab/jupyter-renderers" +} diff --git a/packages/vdom-extension/src/index.tsx b/packages/vdom-extension/src/index.tsx new file mode 100644 index 000000000..a6a54fb1f --- /dev/null +++ b/packages/vdom-extension/src/index.tsx @@ -0,0 +1,113 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { + Widget +} from '@phosphor/widgets'; + +import { + IRenderMime +} from '@jupyterlab/rendermime-interfaces'; + +import * as React from 'react'; + +import * as ReactDOM from 'react-dom'; + +import { objectToReactElement } from './object-to-react'; + +import '../style/index.css'; + + +/** + * The CSS class to add to the VDOM Widget. + */ +const CSS_CLASS = 'jp-RenderedVDOM'; + +/** + * The CSS class for a VDOM icon. + */ +const CSS_ICON_CLASS = 'jp-MaterialIcon jp-VDOMIcon'; + +/** + * The MIME type for VDOM. + */ +export +const MIME_TYPE = 'application/vdom.v1+json'; + + +export +class RenderedVDOM extends Widget implements IRenderMime.IRenderer { + /** + * Create a new widget for rendering DOM. + */ + constructor(options: IRenderMime.IRendererOptions) { + super(); + this.addClass(CSS_CLASS); + this._mimeType = options.mimeType; + } + + /** + * Render VDOM into this widget's node. + */ + renderModel(model: IRenderMime.IMimeModel): Promise { + const data = model.data[this._mimeType] as any; + // const metadata = model.metadata[this._mimeType] as any || {}; + return new Promise((resolve, reject) => { + try { + const vdomElement = objectToReactElement({ ...data }) + ReactDOM.render(vdomElement, this.node, () => { + resolve(undefined); + }); + } catch (error) { + const errorElement = ( +
+
+ There was an error rendering VDOM data from the kernel or notebook +
+ {error.message} +
+ ); + ReactDOM.render(errorElement, this.node, () => { + resolve(undefined); + }); + } + }); + } + + private _mimeType: string; +} + + +/** + * A mime renderer factory for VDOM data. + */ +export +const rendererFactory: IRenderMime.IRendererFactory = { + safe: true, + mimeTypes: [MIME_TYPE], + createRenderer: options => new RenderedVDOM(options) +}; + + +const extensions: IRenderMime.IExtension | IRenderMime.IExtension[] = [ + { + name: 'VDOM', + rendererFactory, + rank: 0, + dataType: 'json', + fileTypes: [{ + name: 'vdom', + mimeTypes: [MIME_TYPE], + extensions: ['.vdom', '.vdom.json'], + iconClass: CSS_ICON_CLASS + }], + documentWidgetFactoryOptions: { + name: 'VDOM', + primaryFileType: 'vdom', + fileTypes: ['vdom', 'json'], + defaultFor: ['vdom'] + } + } +]; + +export default extensions; diff --git a/packages/vdom-extension/src/object-to-react.ts b/packages/vdom-extension/src/object-to-react.ts new file mode 100644 index 000000000..2da7ebe1f --- /dev/null +++ b/packages/vdom-extension/src/object-to-react.ts @@ -0,0 +1,83 @@ +import * as React from 'react'; + +export type VDOMNode = VDOMElement | string; + +export type VDOMNodeArray = VDOMNode | Array + +export type VDOMElement = { + tagName: string, // Could be an enum honestly + children: Array, + attributes: Object, + key: number | string | null +}; + +export type ReactArray = Array | string>; + +/** + * Convert an object to React element(s). + * + * The object schema should be similar to React element's. + * Note: The object passed in this function will be mutated. + * + * @param {Object} obj - The element object. + * @return {ReactElement} + */ +export function objectToReactElement(obj: VDOMElement): React.ReactElement { + // Pack args for React.createElement + var args = []; + if (!obj.tagName || typeof obj.tagName !== "string") { + throw new Error(`Invalid tagName on ${JSON.stringify(obj, null, 2)}`); + } + if (!obj.attributes || typeof obj.attributes !== "object") { + throw new Error(`Attributes must exist on a VDOM Object`); + } + // `React.createElement` 1st argument: type + args[0] = obj.tagName; + args[1] = obj.attributes; + const children = obj.children; + if (children) { + if (Array.isArray(children)) { + // to be safe (although this should never happen) + if (args[1] === undefined) { + args[1] = null; + } + args = args.concat(arrayToReactChildren(children)); + } else if (typeof children === "string") { + args[2] = children; + } else if (typeof children === "object") { + args[2] = objectToReactElement(children); + } else { + console.warn("invalid vdom data passed", children); + } + } + return React.createElement.apply({}, args); +} + +/** + * Convert an array of items to React children. + * + * @param {Array} arr - The array. + * @return {Array} - The array of mixed values. + */ +function arrayToReactChildren(arr: Array): Array | string | Array> { + // similar to `props.children` + var result = []; + // child of `props.children` + // iterate through the `children` + for (var i = 0, len = arr.length; i < len; i++) { + // child can have mixed values: text, React element, or array + const item = arr[i]; + if (Array.isArray(item)) { + result.push(arrayToReactChildren(item)); + } else if (typeof item === "string") { + result.push(item); + } else if (typeof item === "object") { + const keyedItem = item; + item.key = i; + result.push(objectToReactElement(keyedItem)); + } else { + console.warn("invalid vdom data passed", item); + } + } + return result; +} diff --git a/packages/vdom-extension/style/index.css b/packages/vdom-extension/style/index.css new file mode 100644 index 000000000..0711698bf --- /dev/null +++ b/packages/vdom-extension/style/index.css @@ -0,0 +1,34 @@ +/** + Copyright (c) Jupyter Development Team. + Distributed under the terms of the Modified BSD License. +*/ + +/* Add CSS variables to :root */ +:root { + --jp-icon-vdom: url('./react.svg'); +} + +/* Base styles */ +.jp-RenderedVDOM { + width: 100%; + height: 100%; + padding: 0; + overflow: auto; +} + +/* Document styles */ +.jp-MimeDocument .jp-RenderedVDOM { + padding: 5px; +} + +/* Output styles */ +.jp-OutputArea .jp-RenderedVDOM { + +} + +/* Document icon */ +.jp-VDOMIcon { + background-image: var(--jp-icon-vdom); + background-size: 24px; + background-position: center !important; +} diff --git a/packages/vdom-extension/style/react.svg b/packages/vdom-extension/style/react.svg new file mode 100644 index 000000000..5592ebec6 --- /dev/null +++ b/packages/vdom-extension/style/react.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + diff --git a/packages/vdom-extension/tsconfig.json b/packages/vdom-extension/tsconfig.json new file mode 100644 index 000000000..3e7427e47 --- /dev/null +++ b/packages/vdom-extension/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "declaration": true, + "noImplicitAny": true, + "noEmitOnError": true, + "noUnusedLocals": true, + "module": "commonjs", + "moduleResolution": "node", + "target": "ES5", + "outDir": "./lib", + "lib": ["ES5", "ES2015.Promise", "DOM", "ES2015.Collection", "es2016"], + "jsx": "react", + "types": [] + }, + "include": ["src/*"] +} From c2420b06fa9fe664e38abc7893644dfb0964a5c5 Mon Sep 17 00:00:00 2001 From: Grant Nestor Date: Thu, 28 Sep 2017 12:11:58 -0700 Subject: [PATCH 3/7] Clean up comments --- packages/geojson-extension/src/index.tsx | 8 ++++---- packages/json-extension/src/index.tsx | 9 +++------ packages/plotly-extension/src/index.tsx | 12 +++++------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/geojson-extension/src/index.tsx b/packages/geojson-extension/src/index.tsx index 0de14e17a..456d1d1cb 100644 --- a/packages/geojson-extension/src/index.tsx +++ b/packages/geojson-extension/src/index.tsx @@ -151,16 +151,16 @@ const extensions: IRenderMime.IExtension | IRenderMime.IExtension[] = [ rank: 0, dataType: 'json', fileTypes: [{ - name: 'GeoJSON', + name: 'geojson', mimeTypes: [MIME_TYPE], extensions: ['.geojson', '.geo.json'], iconClass: CSS_ICON_CLASS }], documentWidgetFactoryOptions: { name: 'GeoJSON', - primaryFileType: 'GeoJSON', - fileTypes: ['GeoJSON'], - defaultFor: ['GeoJSON'] + primaryFileType: 'geojson', + fileTypes: ['geojson', 'json'], + defaultFor: ['geojson'] } } ]; diff --git a/packages/json-extension/src/index.tsx b/packages/json-extension/src/index.tsx index d0bebad96..1d70fc488 100644 --- a/packages/json-extension/src/index.tsx +++ b/packages/json-extension/src/index.tsx @@ -26,10 +26,7 @@ import '../style/index.css'; const CSS_CLASS = 'jp-RenderedJSON'; /** - * The MIME type for Vega. - * - * #### Notes - * The version of this follows the major version of Vega. + * The MIME type for JSON. */ export const MIME_TYPE = 'application/json'; @@ -38,7 +35,7 @@ const MIME_TYPE = 'application/json'; export class RenderedJSON extends Widget implements IRenderMime.IRenderer { /** - * Create a new widget for rendering Vega/Vega-Lite. + * Create a new widget for rendering JSON. */ constructor(options: IRenderMime.IRendererOptions) { super(); @@ -65,7 +62,7 @@ class RenderedJSON extends Widget implements IRenderMime.IRenderer { /** - * A mime renderer factory for GeoJSON data. + * A mime renderer factory for JSON data. */ export const rendererFactory: IRenderMime.IRendererFactory = { diff --git a/packages/plotly-extension/src/index.tsx b/packages/plotly-extension/src/index.tsx index 7fe15d987..c9fa81325 100644 --- a/packages/plotly-extension/src/index.tsx +++ b/packages/plotly-extension/src/index.tsx @@ -41,14 +41,12 @@ namespace Private { const CSS_CLASS = 'jp-RenderedPlotly'; /** - * The CSS class for a GeoJSON icon. + * The CSS class for a Plotly icon. */ const CSS_ICON_CLASS = 'jp-MaterialIcon jp-PlotlyIcon'; /** - * The MIME type for Vega. - * - * #### Notes + * The MIME type for Plotly. * The version of this follows the major version of Plotly. */ export @@ -63,7 +61,7 @@ interface PlotlySpec { export class RenderedPlotly extends Widget implements IRenderMime.IRenderer { /** - * Create a new widget for rendering Vega/Vega-Lite. + * Create a new widget for rendering Plotly. */ constructor(options: IRenderMime.IRendererOptions) { super(); @@ -115,7 +113,7 @@ class RenderedPlotly extends Widget implements IRenderMime.IRenderer { /** - * A mime renderer factory for GeoPlotly data. + * A mime renderer factory for Plotly data. */ export const rendererFactory: IRenderMime.IRendererFactory = { @@ -140,7 +138,7 @@ const extensions: IRenderMime.IExtension | IRenderMime.IExtension[] = [ documentWidgetFactoryOptions: { name: 'Plotly', primaryFileType: 'plotly', - fileTypes: ['plotly'], + fileTypes: ['plotly', 'json'], defaultFor: ['plotly'] } } From 8d368ebaeefdb39fe304c4f135fe77f19f7bc040 Mon Sep 17 00:00:00 2001 From: Grant Nestor Date: Fri, 29 Sep 2017 12:28:06 -0700 Subject: [PATCH 4/7] Upgrade to react 15.6.2 --- packages/json-extension/package.json | 4 ++-- packages/vdom-extension/package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/json-extension/package.json b/packages/json-extension/package.json index c4739cea5..198435994 100644 --- a/packages/json-extension/package.json +++ b/packages/json-extension/package.json @@ -18,8 +18,8 @@ "dependencies": { "@jupyterlab/rendermime-interfaces": "^0.3.0", "@phosphor/widgets": "^1.3.0", - "react": "^15.6.1", - "react-dom": "^15.6.1", + "react": "^15.6.2", + "react-dom": "^15.6.2", "react-highlighter": "^0.4.0", "react-json-tree": "^0.10.9" }, diff --git a/packages/vdom-extension/package.json b/packages/vdom-extension/package.json index 5ab46e696..c312741d0 100644 --- a/packages/vdom-extension/package.json +++ b/packages/vdom-extension/package.json @@ -18,8 +18,8 @@ "dependencies": { "@jupyterlab/rendermime-interfaces": "^0.3.0", "@phosphor/widgets": "^1.3.0", - "react": "^15.6.1", - "react-dom": "^15.6.1" + "react": "^15.6.2", + "react-dom": "^15.6.2" }, "devDependencies": { "@types/react": "^15.0.33", From 588d9cfc51e95b2978a159da4066dbde022090a8 Mon Sep 17 00:00:00 2001 From: Grant Nestor Date: Tue, 3 Oct 2017 10:50:24 -0700 Subject: [PATCH 5/7] Add README for vdom-extension --- README.md | 2 + packages/vdom-extension/README.md | 104 ++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 packages/vdom-extension/README.md diff --git a/README.md b/README.md index d46dc2b94..a957c24c6 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,14 @@ This is a [monorepo](https://github.com/lerna/lerna#what-does-a-lerna-repo-look- | [geojson-extension](packages/geojson-extension) | `application/geo+json` | `.geojson`, `.geo.json` | | [json-extension](packages/json-extension) | `application/json` | `.json`, `.ipynb` | | [plotly-extension](packages/plotly-extension) | `application/vnd.plotly.v1+json` | `.plotly`, `.plotly.json` | +| [vdom-extension](packages/vdom-extension) | `application/vdom.v1+json` | `.vdom`, `.vdom.json` | ## Install * geojson-extension: `jupyter labextension install @jupyterlab/geojson-extension` * json-extension: `jupyter labextension install @jupyterlab/json-extension` * plotly-extension: `jupyter labextension install @jupyterlab/plotly-extension` +* vdom-extension: `jupyter labextension install @jupyterlab/vdom-extension` ## Contributing diff --git a/packages/vdom-extension/README.md b/packages/vdom-extension/README.md new file mode 100644 index 000000000..96b81fd19 --- /dev/null +++ b/packages/vdom-extension/README.md @@ -0,0 +1,104 @@ +# vdom-extension + +A JupyterLab extension for rendering VirtualDOM using React + +![demo](http://g.recordit.co/EIwAIBsGBh.gif) + +## Prerequisites + +* JupyterLab ^0.27.0 + +## Usage + +To render VDOM output in IPython: + +```python +from IPython.display import display + +def VDOM(data={}): + bundle = {} + bundle['application/vdom.v1+json'] = data + display(bundle, raw=True) + +VDOM({ + 'tagName': 'div', + 'attributes': {}, + 'children': [{ + 'tagName': 'h1', + 'attributes': {}, + 'children': 'Our Incredibly Declarative Example', + 'key': 0 + }, { + 'tagName': 'p', + 'attributes': {}, + 'children': ['Can you believe we wrote this ', { + 'tagName': 'b', + 'attributes': {}, + 'children': 'in Python', + 'key': 1 + }, '?'], + 'key': 1 + }, { + 'tagName': 'img', + 'attributes': { + 'src': 'https://media.giphy.com/media/xUPGcguWZHRC2HyBRS/giphy.gif' + }, + 'key': 2 + }, { + 'tagName': 'p', + 'attributes': {}, + 'children': ['What will ', { + 'tagName': 'b', + 'attributes': {}, + 'children': 'you', + 'key': 1 + }, ' create next?'], + 'key': 3 + }] +}) +``` + +Using the [vdom Python library](https://github.com/nteract/vdom): + +```python +from vdom import h1, p, img, div, b + +div([ + h1('Our Incredibly Declarative Example'), + p(['Can you believe we wrote this ', b('in Python'), '?']), + img(src="https://media.giphy.com/media/xUPGcguWZHRC2HyBRS/giphy.gif"), + p(['What will ', b('you'), ' create next?']), +]) +``` + +To render a `.vdom` or `.vdom.json` file as a tree, simply open it: + +## Install + +```bash +jupyter labextension install @jupyterlab/vdom-extension +``` + +## Development + +```bash +# Clone the repo to your local environment +git clone https://github.com/jupyterlab/jupyter-renderers.git +cd jupyter-renderers +# Install dependencies +npm install +# Build Typescript source +npm run build +# Link your development version of the extension with JupyterLab +jupyter labextension link packages/vdom-extension +# Rebuild Typescript source after making changes +npm run build +# Rebuild JupyterLab after making any changes +jupyter lab build +``` + +## Uninstall + +```bash +jupyter labextension uninstall @jupyterlab/vdom-extension +``` From 6ae319f2ed4645365faf5da8c4571c4ec432b698 Mon Sep 17 00:00:00 2001 From: Grant Nestor Date: Fri, 6 Oct 2017 08:59:05 -0700 Subject: [PATCH 6/7] Add local type definitions for @nteract/transform-vdom Fix type definitions for `@nteract/transform-vdom` --- packages/vdom-extension/package.json | 1 + packages/vdom-extension/src/index.tsx | 23 +---- .../vdom-extension/src/object-to-react.ts | 83 ------------------- .../vdom-extension/src/transform-vdom.d.ts | 23 +++++ 4 files changed, 28 insertions(+), 102 deletions(-) delete mode 100644 packages/vdom-extension/src/object-to-react.ts create mode 100644 packages/vdom-extension/src/transform-vdom.d.ts diff --git a/packages/vdom-extension/package.json b/packages/vdom-extension/package.json index c312741d0..c811e3c1b 100644 --- a/packages/vdom-extension/package.json +++ b/packages/vdom-extension/package.json @@ -18,6 +18,7 @@ "dependencies": { "@jupyterlab/rendermime-interfaces": "^0.3.0", "@phosphor/widgets": "^1.3.0", + "@nteract/transform-vdom": "^1.1.1", "react": "^15.6.2", "react-dom": "^15.6.2" }, diff --git a/packages/vdom-extension/src/index.tsx b/packages/vdom-extension/src/index.tsx index a6a54fb1f..ce9790d87 100644 --- a/packages/vdom-extension/src/index.tsx +++ b/packages/vdom-extension/src/index.tsx @@ -13,7 +13,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { objectToReactElement } from './object-to-react'; +import VDOM from '@nteract/transform-vdom'; import '../style/index.css'; @@ -53,24 +53,9 @@ class RenderedVDOM extends Widget implements IRenderMime.IRenderer { const data = model.data[this._mimeType] as any; // const metadata = model.metadata[this._mimeType] as any || {}; return new Promise((resolve, reject) => { - try { - const vdomElement = objectToReactElement({ ...data }) - ReactDOM.render(vdomElement, this.node, () => { - resolve(undefined); - }); - } catch (error) { - const errorElement = ( -
-
- There was an error rendering VDOM data from the kernel or notebook -
- {error.message} -
- ); - ReactDOM.render(errorElement, this.node, () => { - resolve(undefined); - }); - } + ReactDOM.render(, this.node, () => { + resolve(undefined); + }); }); } diff --git a/packages/vdom-extension/src/object-to-react.ts b/packages/vdom-extension/src/object-to-react.ts deleted file mode 100644 index 2da7ebe1f..000000000 --- a/packages/vdom-extension/src/object-to-react.ts +++ /dev/null @@ -1,83 +0,0 @@ -import * as React from 'react'; - -export type VDOMNode = VDOMElement | string; - -export type VDOMNodeArray = VDOMNode | Array - -export type VDOMElement = { - tagName: string, // Could be an enum honestly - children: Array, - attributes: Object, - key: number | string | null -}; - -export type ReactArray = Array | string>; - -/** - * Convert an object to React element(s). - * - * The object schema should be similar to React element's. - * Note: The object passed in this function will be mutated. - * - * @param {Object} obj - The element object. - * @return {ReactElement} - */ -export function objectToReactElement(obj: VDOMElement): React.ReactElement { - // Pack args for React.createElement - var args = []; - if (!obj.tagName || typeof obj.tagName !== "string") { - throw new Error(`Invalid tagName on ${JSON.stringify(obj, null, 2)}`); - } - if (!obj.attributes || typeof obj.attributes !== "object") { - throw new Error(`Attributes must exist on a VDOM Object`); - } - // `React.createElement` 1st argument: type - args[0] = obj.tagName; - args[1] = obj.attributes; - const children = obj.children; - if (children) { - if (Array.isArray(children)) { - // to be safe (although this should never happen) - if (args[1] === undefined) { - args[1] = null; - } - args = args.concat(arrayToReactChildren(children)); - } else if (typeof children === "string") { - args[2] = children; - } else if (typeof children === "object") { - args[2] = objectToReactElement(children); - } else { - console.warn("invalid vdom data passed", children); - } - } - return React.createElement.apply({}, args); -} - -/** - * Convert an array of items to React children. - * - * @param {Array} arr - The array. - * @return {Array} - The array of mixed values. - */ -function arrayToReactChildren(arr: Array): Array | string | Array> { - // similar to `props.children` - var result = []; - // child of `props.children` - // iterate through the `children` - for (var i = 0, len = arr.length; i < len; i++) { - // child can have mixed values: text, React element, or array - const item = arr[i]; - if (Array.isArray(item)) { - result.push(arrayToReactChildren(item)); - } else if (typeof item === "string") { - result.push(item); - } else if (typeof item === "object") { - const keyedItem = item; - item.key = i; - result.push(objectToReactElement(keyedItem)); - } else { - console.warn("invalid vdom data passed", item); - } - } - return result; -} diff --git a/packages/vdom-extension/src/transform-vdom.d.ts b/packages/vdom-extension/src/transform-vdom.d.ts new file mode 100644 index 000000000..eb223f1a9 --- /dev/null +++ b/packages/vdom-extension/src/transform-vdom.d.ts @@ -0,0 +1,23 @@ +// Type definitions for @nteract/transform-vdom v1.1.1 +// https://github.com/jupyterlab/jupyter-renderers +// Definitions by: Grant Nestor + + +declare module '@nteract/transform-vdom' { + + import * as React from 'react'; + + interface VDOMElement { + tagName: 'string'; + attributes: Object; + children: Array; + key?: number | string | null; + } + + interface VDOMProps extends React.Props { + data: VDOMElement; + } + + export default class VDOM extends React.Component { } + +} From 59637314049bb59f05df8fb02b8b782d29611da3 Mon Sep 17 00:00:00 2001 From: Grant Nestor Date: Fri, 6 Oct 2017 11:11:02 -0700 Subject: [PATCH 7/7] Add vdom-extension to postBuild --- postBuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postBuild b/postBuild index 72214803c..cfff9054d 100755 --- a/postBuild +++ b/postBuild @@ -1,3 +1,3 @@ #!/bin/bash -jupyter labextension install @jupyterlab/geojson-extension @jupyterlab/json-extension @jupyterlab/plotly-extension +jupyter labextension install @jupyterlab/geojson-extension @jupyterlab/json-extension @jupyterlab/plotly-extension @jupyterlab/vdom-extension