@jupyterlab/notebook-extension 4.0.0-alpha.20 → 4.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,119 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ import React from 'react';
7
+ import { FieldProps } from '@rjsf/utils';
8
+ import { IEditorLanguageRegistry } from '@jupyterlab/codemirror';
9
+ import { INotebookTracker, NotebookTools } from '@jupyterlab/notebook';
10
+ import { ISharedText } from '@jupyter/ydoc';
11
+ import { PanelLayout, Widget } from '@lumino/widgets';
12
+ import { CodeCellModel, ICellModel, InputPrompt } from '@jupyterlab/cells';
13
+ import { Debouncer } from '@lumino/polling';
14
+
15
+ /**
16
+ * The class name added to the ActiveCellTool.
17
+ */
18
+ const ACTIVE_CELL_TOOL_CLASS = 'jp-ActiveCellTool';
19
+ /**
20
+ * The class name added to the ActiveCellTool content.
21
+ */
22
+ const ACTIVE_CELL_TOOL_CONTENT_CLASS = 'jp-ActiveCellTool-Content';
23
+ /**
24
+ * The class name added to the ActiveCellTool cell content.
25
+ */
26
+ const ACTIVE_CELL_TOOL_CELL_CONTENT_CLASS = 'jp-ActiveCellTool-CellContent';
27
+
28
+ namespace Private {
29
+ /**
30
+ * Custom active cell field options.
31
+ */
32
+ export interface IOptions {
33
+ /**
34
+ * The tracker to the notebook panel.
35
+ */
36
+ tracker: INotebookTracker;
37
+
38
+ /**
39
+ * Editor languages registry
40
+ */
41
+ languages: IEditorLanguageRegistry;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * The active cell field, displaying the first line and execution count of the active cell.
47
+ *
48
+ * ## Note
49
+ * This field does not work as other metadata form fields, as it does not update metadata.
50
+ */
51
+ export class ActiveCellTool extends NotebookTools.Tool {
52
+ constructor(options: Private.IOptions) {
53
+ super();
54
+ const { languages } = options;
55
+ this._tracker = options.tracker;
56
+
57
+ this.addClass(ACTIVE_CELL_TOOL_CLASS);
58
+ this.layout = new PanelLayout();
59
+
60
+ this._inputPrompt = new InputPrompt();
61
+ (this.layout as PanelLayout).addWidget(this._inputPrompt);
62
+
63
+ // First code line container
64
+ const node = document.createElement('div');
65
+ node.classList.add(ACTIVE_CELL_TOOL_CONTENT_CLASS);
66
+ const container = node.appendChild(document.createElement('div'));
67
+ const editor = container.appendChild(document.createElement('pre'));
68
+ container.className = ACTIVE_CELL_TOOL_CELL_CONTENT_CLASS;
69
+ this._editorEl = editor;
70
+ (this.layout as PanelLayout).addWidget(new Widget({ node }));
71
+
72
+ const update = async () => {
73
+ this._editorEl.innerHTML = '';
74
+ if (this._cellModel?.type === 'code') {
75
+ this._inputPrompt.executionCount = `${
76
+ (this._cellModel as CodeCellModel).executionCount ?? ''
77
+ }`;
78
+ this._inputPrompt.show();
79
+ } else {
80
+ this._inputPrompt.executionCount = null;
81
+ this._inputPrompt.hide();
82
+ }
83
+
84
+ if (this._cellModel) {
85
+ await languages.highlight(
86
+ this._cellModel.sharedModel.getSource().split('\n')[0],
87
+ languages.findByMIME(this._cellModel.mimeType),
88
+ this._editorEl
89
+ );
90
+ }
91
+ };
92
+
93
+ this._refreshDebouncer = new Debouncer(update, 150);
94
+ }
95
+
96
+ render(props: FieldProps): JSX.Element {
97
+ const activeCell = this._tracker.activeCell;
98
+ if (activeCell) this._cellModel = activeCell?.model || null;
99
+ (this._cellModel?.sharedModel as ISharedText).changed.connect(
100
+ this.refresh,
101
+ this
102
+ );
103
+ this._cellModel?.mimeTypeChanged.connect(this.refresh, this);
104
+ this.refresh()
105
+ .then(() => undefined)
106
+ .catch(() => undefined);
107
+ return <div ref={ref => ref?.appendChild(this.node)}></div>;
108
+ }
109
+
110
+ private async refresh(): Promise<void> {
111
+ await this._refreshDebouncer.invoke();
112
+ }
113
+
114
+ private _tracker: INotebookTracker;
115
+ private _cellModel: ICellModel | null;
116
+ private _refreshDebouncer: Debouncer<void, void, null[]>;
117
+ private _editorEl: HTMLPreElement;
118
+ private _inputPrompt: InputPrompt;
119
+ }
@@ -0,0 +1,128 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ import React from 'react';
7
+ import { FieldProps } from '@rjsf/utils';
8
+ import { INotebookTracker, NotebookTools } from '@jupyterlab/notebook';
9
+ import { ITranslator } from '@jupyterlab/translation';
10
+ import { CodeEditor } from '@jupyterlab/codeeditor';
11
+ import { ObservableJSON } from '@jupyterlab/observables';
12
+ import { JSONObject } from '@lumino/coreutils';
13
+
14
+ const CELL_METADATA_EDITOR_CLASS = 'jp-CellMetadataEditor';
15
+ const NOTEBOOK_METADATA_EDITOR_CLASS = 'jp-NotebookMetadataEditor';
16
+
17
+ namespace Private {
18
+ /**
19
+ * Custom metadata field options.
20
+ */
21
+ export interface IOptions {
22
+ /**
23
+ * The editor factory used by the tool.
24
+ */
25
+ editorFactory: CodeEditor.Factory;
26
+
27
+ /**
28
+ * The tracker to the notebook panel.
29
+ */
30
+ tracker: INotebookTracker;
31
+
32
+ /**
33
+ * The label of the JSON editor.
34
+ */
35
+ label?: string;
36
+
37
+ /**
38
+ * Language translator.
39
+ */
40
+ translator?: ITranslator;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * The cell metadata field.
46
+ *
47
+ * ## Note
48
+ * This field does not work as other metadata form fields, as it does not use RJSF to update metadata.
49
+ * It extends the MetadataEditorTool which updates itself the metadata.
50
+ * It only renders the node of MetadataEditorTool in a React element instead of displaying a RJSF field.
51
+ */
52
+ export class CellMetadataField extends NotebookTools.MetadataEditorTool {
53
+ constructor(options: Private.IOptions) {
54
+ super(options);
55
+ this._tracker = options.tracker;
56
+
57
+ this.editor.editorHostNode.addEventListener('blur', this.editor, true);
58
+ this.editor.editorHostNode.addEventListener('click', this.editor, true);
59
+ this.editor.headerNode.addEventListener('click', this.editor);
60
+ }
61
+
62
+ private _onSourceChanged() {
63
+ if (this.editor.source) {
64
+ this._tracker.activeCell?.model.sharedModel.setMetadata(
65
+ this.editor.source.toJSON()
66
+ );
67
+ }
68
+ }
69
+
70
+ render(props: FieldProps): JSX.Element {
71
+ const cell = this._tracker.activeCell;
72
+ this.editor.source = cell
73
+ ? new ObservableJSON({ values: cell.model.metadata as JSONObject })
74
+ : null;
75
+ this.editor.source?.changed.connect(this._onSourceChanged, this);
76
+
77
+ return (
78
+ <div className={CELL_METADATA_EDITOR_CLASS}>
79
+ <div ref={ref => ref?.appendChild(this.node)}></div>
80
+ </div>
81
+ );
82
+ }
83
+
84
+ private _tracker: INotebookTracker;
85
+ }
86
+
87
+ /**
88
+ * The notebook metadata field.
89
+ *
90
+ * ## Note
91
+ * This field does not work as other metadata form fields, as it does not use RJSF to update metadata.
92
+ * It extends the MetadataEditorTool which updates itself the metadata.
93
+ * It only renders the node of MetadataEditorTool in a React element instead of displaying a RJSF field.
94
+ */
95
+ export class NotebookMetadataField extends NotebookTools.MetadataEditorTool {
96
+ constructor(options: Private.IOptions) {
97
+ super(options);
98
+ this._tracker = options.tracker;
99
+
100
+ this.editor.editorHostNode.addEventListener('blur', this.editor, true);
101
+ this.editor.editorHostNode.addEventListener('click', this.editor, true);
102
+ this.editor.headerNode.addEventListener('click', this.editor);
103
+ }
104
+
105
+ private _onSourceChanged() {
106
+ if (this.editor.source) {
107
+ this._tracker.currentWidget?.model?.sharedModel.setMetadata(
108
+ this.editor.source.toJSON()
109
+ );
110
+ }
111
+ }
112
+
113
+ render(props: FieldProps): JSX.Element {
114
+ const notebook = this._tracker.currentWidget;
115
+ this.editor.source = notebook
116
+ ? new ObservableJSON({ values: notebook.model?.metadata as JSONObject })
117
+ : null;
118
+ this.editor.source?.changed.connect(this._onSourceChanged, this);
119
+
120
+ return (
121
+ <div className={NOTEBOOK_METADATA_EDITOR_CLASS}>
122
+ <div ref={ref => ref?.appendChild(this.node)}></div>
123
+ </div>
124
+ );
125
+ }
126
+
127
+ private _tracker: INotebookTracker;
128
+ }
package/style/index.css CHANGED
@@ -25,4 +25,5 @@
25
25
  @import url('~@jupyterlab/lsp/style/index.css');
26
26
  @import url('~@jupyterlab/mainmenu/style/index.css');
27
27
  @import url('~@jupyterlab/notebook/style/index.css');
28
+ @import url('~@jupyterlab/metadataform/style/index.css');
28
29
  @import url('~@jupyterlab/property-inspector/style/index.css');
package/style/index.js CHANGED
@@ -25,4 +25,5 @@ import '@jupyterlab/logconsole/style/index.js';
25
25
  import '@jupyterlab/lsp/style/index.js';
26
26
  import '@jupyterlab/mainmenu/style/index.js';
27
27
  import '@jupyterlab/notebook/style/index.js';
28
+ import '@jupyterlab/metadataform/style/index.js';
28
29
  import '@jupyterlab/property-inspector/style/index.js';