/
index.tsx
127 lines (108 loc) · 3.22 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/**
* @packageDocumentation
* @module vdom
*/
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { ISessionContext, IWidgetTracker } from '@jupyterlab/apputils';
import { DocumentRegistry, MimeDocument } from '@jupyterlab/docregistry';
import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
import { Kernel } from '@jupyterlab/services';
import VDOM, { SerializedEvent } from '@nteract/transform-vdom';
import { Token } from '@lumino/coreutils';
import { Message } from '@lumino/messaging';
import { Widget } from '@lumino/widgets';
/**
* The CSS class to add to the VDOM Widget.
*/
const CSS_CLASS = 'jp-RenderedVDOM';
/**
* A class that tracks VDOM widgets.
*/
export interface IVDOMTracker extends IWidgetTracker<MimeDocument> {}
/**
* The VDOM tracker token.
*/
export const IVDOMTracker = new Token<IVDOMTracker>(
'@jupyterlab/vdom:IVDOMTracker'
);
/**
* A renderer for declarative virtual DOM content.
*/
export class RenderedVDOM extends Widget implements IRenderMime.IRenderer {
/**
* Create a new widget for rendering DOM.
*/
constructor(
options: IRenderMime.IRendererOptions,
context?: DocumentRegistry.IContext<DocumentRegistry.IModel>
) {
super();
this.addClass(CSS_CLASS);
this.addClass('jp-RenderedHTML');
this.addClass('jp-RenderedHTMLCommon');
this._mimeType = options.mimeType;
if (context) {
this._sessionContext = context.sessionContext;
}
}
/**
* Dispose of the widget.
*/
dispose(): void {
// Dispose of comm disposables
for (const targetName in this._comms) {
this._comms[targetName].dispose();
}
super.dispose();
}
/**
* Called before the widget is detached from the DOM.
*/
protected onBeforeDetach(msg: Message): void {
// Dispose of React component(s).
ReactDOM.unmountComponentAtNode(this.node);
}
/**
* Render VDOM into this widget's node.
*/
renderModel(model: IRenderMime.IMimeModel): Promise<void> {
return new Promise((resolve, reject) => {
const data = model.data[this._mimeType] as any;
ReactDOM.render(
<VDOM data={data} onVDOMEvent={this.handleVDOMEvent} />,
this.node,
() => {
resolve();
}
);
});
}
/**
* Handle events for VDOM element.
*/
handleVDOMEvent = (targetName: string, event: SerializedEvent<any>): void => {
// When a VDOM element's event handler is called, send a serialized
// representation of the event to the registered comm channel for the
// kernel to handle
if (this._timer) {
window.clearTimeout(this._timer);
}
const kernel = this._sessionContext?.session?.kernel;
if (kernel) {
this._timer = window.setTimeout(() => {
if (!this._comms[targetName]) {
this._comms[targetName] = kernel.createComm(targetName);
this._comms[targetName].open();
}
this._comms[targetName].send(JSON.stringify(event));
}, 16);
}
};
private _mimeType: string;
private _sessionContext?: ISessionContext;
private _comms: { [targetName: string]: Kernel.IComm } = {};
private _timer: number;
}