@jupyter-notebook/notebook-extension 7.0.0-alpha.1 → 7.0.0-alpha.11

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.
package/lib/index.js CHANGED
@@ -1,15 +1,14 @@
1
1
  // Copyright (c) Jupyter Development Team.
2
2
  // Distributed under the terms of the Modified BSD License.
3
- import { DOMUtils } from '@jupyterlab/apputils';
3
+ import { DOMUtils, IToolbarWidgetRegistry } from '@jupyterlab/apputils';
4
4
  import { Text, Time } from '@jupyterlab/coreutils';
5
5
  import { IDocumentManager } from '@jupyterlab/docmanager';
6
- import { IMainMenu } from '@jupyterlab/mainmenu';
7
- import { NotebookPanel, INotebookTracker } from '@jupyterlab/notebook';
6
+ import { NotebookPanel, INotebookTracker, INotebookTools } from '@jupyterlab/notebook';
8
7
  import { ISettingRegistry } from '@jupyterlab/settingregistry';
9
8
  import { ITranslator } from '@jupyterlab/translation';
10
9
  import { INotebookShell } from '@jupyter-notebook/application';
11
10
  import { Poll } from '@lumino/polling';
12
- import { Menu, Widget } from '@lumino/widgets';
11
+ import { Widget } from '@lumino/widgets';
13
12
  /**
14
13
  * The class for kernel status errors.
15
14
  */
@@ -37,14 +36,19 @@ const checkpoints = {
37
36
  id: '@jupyter-notebook/notebook-extension:checkpoints',
38
37
  autoStart: true,
39
38
  requires: [IDocumentManager, ITranslator],
40
- optional: [INotebookShell],
41
- activate: (app, docManager, translator, notebookShell) => {
39
+ optional: [INotebookShell, IToolbarWidgetRegistry],
40
+ activate: (app, docManager, translator, notebookShell, toolbarRegistry) => {
42
41
  const { shell } = app;
43
42
  const trans = translator.load('notebook');
44
- const widget = new Widget();
45
- widget.id = DOMUtils.createDomID();
46
- widget.addClass('jp-NotebookCheckpoint');
47
- app.shell.add(widget, 'top', { rank: 100 });
43
+ const node = document.createElement('div');
44
+ if (toolbarRegistry) {
45
+ toolbarRegistry.addFactory('TopBar', 'checkpoint', toolbar => {
46
+ const widget = new Widget({ node });
47
+ widget.id = DOMUtils.createDomID();
48
+ widget.addClass('jp-NotebookCheckpoint');
49
+ return widget;
50
+ });
51
+ }
48
52
  const onChange = async () => {
49
53
  const current = shell.currentWidget;
50
54
  if (!current) {
@@ -58,7 +62,7 @@ const checkpoints = {
58
62
  return;
59
63
  }
60
64
  const checkpoint = checkpoints[checkpoints.length - 1];
61
- widget.node.textContent = trans.__('Last Checkpoint: %1', Time.formatHuman(new Date(checkpoint.last_modified)));
65
+ node.textContent = trans.__('Last Checkpoint: %1', Time.formatHuman(new Date(checkpoint.last_modified)));
62
66
  };
63
67
  if (notebookShell) {
64
68
  notebookShell.currentChanged.connect(onChange);
@@ -81,15 +85,14 @@ const kernelLogo = {
81
85
  id: '@jupyter-notebook/notebook-extension:kernel-logo',
82
86
  autoStart: true,
83
87
  requires: [INotebookShell],
84
- activate: (app, shell) => {
88
+ optional: [IToolbarWidgetRegistry],
89
+ activate: (app, shell, toolbarRegistry) => {
85
90
  const { serviceManager } = app;
86
- let widget;
91
+ const node = document.createElement('div');
92
+ const img = document.createElement('img');
93
+ node.appendChild(img);
87
94
  const onChange = async () => {
88
95
  var _a, _b, _c, _d, _e;
89
- if (widget) {
90
- widget.dispose();
91
- widget.parent = null;
92
- }
93
96
  const current = shell.currentWidget;
94
97
  if (!(current instanceof NotebookPanel)) {
95
98
  return;
@@ -106,15 +109,16 @@ const kernelLogo = {
106
109
  if (!kernelIconUrl) {
107
110
  return;
108
111
  }
109
- const node = document.createElement('div');
110
- const img = document.createElement('img');
111
112
  img.src = kernelIconUrl;
112
113
  img.title = spec.display_name;
113
- node.appendChild(img);
114
- widget = new Widget({ node });
115
- widget.addClass('jp-NotebookKernelLogo');
116
- app.shell.add(widget, 'top', { rank: 10010 });
117
114
  };
115
+ if (toolbarRegistry) {
116
+ toolbarRegistry.addFactory('TopBar', 'kernelLogo', toolbar => {
117
+ const widget = new Widget({ node });
118
+ widget.addClass('jp-NotebookKernelLogo');
119
+ return widget;
120
+ });
121
+ }
118
122
  app.started.then(() => {
119
123
  shell.currentChanged.connect(onChange);
120
124
  });
@@ -173,36 +177,6 @@ const kernelStatus = {
173
177
  shell.currentChanged.connect(onChange);
174
178
  }
175
179
  };
176
- /**
177
- * A plugin to customize notebook related menu entries
178
- * TODO: switch to settings define menus when fixed upstream: https://github.com/jupyterlab/jupyterlab/issues/11754
179
- */
180
- const menuPlugin = {
181
- id: '@jupyter-notebook/notebook-extension:menu-plugin',
182
- autoStart: true,
183
- requires: [IMainMenu, ITranslator],
184
- activate: (app, mainMenu, translator) => {
185
- const { commands } = app;
186
- const trans = translator.load('notebook');
187
- const cellTypeSubmenu = new Menu({ commands });
188
- cellTypeSubmenu.title.label = trans._p('menu', 'Cell Type');
189
- [
190
- 'notebook:change-cell-to-code',
191
- 'notebook:change-cell-to-markdown',
192
- 'notebook:change-cell-to-raw'
193
- ].forEach(command => {
194
- cellTypeSubmenu.addItem({
195
- command
196
- });
197
- });
198
- mainMenu.runMenu.addItem({ type: 'separator', rank: 1000 });
199
- mainMenu.runMenu.addItem({
200
- type: 'submenu',
201
- submenu: cellTypeSubmenu,
202
- rank: 1010
203
- });
204
- }
205
- };
206
180
  /**
207
181
  * A plugin to enable scrolling for outputs by default.
208
182
  * Mimic the logic from the classic notebook, as found here:
@@ -224,7 +198,7 @@ const scrollOutput = {
224
198
  }
225
199
  const { outputArea } = cell;
226
200
  // respect cells with an explicit scrolled state
227
- const scrolled = cell.model.metadata.get('scrolled');
201
+ const scrolled = cell.model.getMetadata('scrolled');
228
202
  if (scrolled !== undefined) {
229
203
  return;
230
204
  }
@@ -237,29 +211,27 @@ const scrollOutput = {
237
211
  const scroll = height > lineHeight * autoScrollThreshold;
238
212
  cell.toggleClass(SCROLLED_OUTPUTS_CLASS, scroll);
239
213
  };
214
+ const handlers = {};
215
+ const setAutoScroll = (cell) => {
216
+ if (cell.model.type === 'code') {
217
+ const codeCell = cell;
218
+ const id = codeCell.model.id;
219
+ autoScroll(codeCell);
220
+ if (handlers[id]) {
221
+ codeCell.outputArea.model.changed.disconnect(handlers[id]);
222
+ }
223
+ handlers[id] = () => autoScroll(codeCell);
224
+ codeCell.outputArea.model.changed.connect(handlers[id]);
225
+ }
226
+ };
240
227
  tracker.widgetAdded.connect((sender, notebook) => {
241
228
  var _a;
242
- (_a = notebook.model) === null || _a === void 0 ? void 0 : _a.cells.changed.connect((sender, changed) => {
243
- // process new cells only
244
- if (!(changed.type === 'add')) {
245
- return;
246
- }
247
- const [cellModel] = changed.newValues;
248
- notebook.content.widgets.forEach(cell => {
249
- if (cell.model.id === cellModel.id && cell.model.type === 'code') {
250
- const codeCell = cell;
251
- codeCell.outputArea.model.changed.connect(() => autoScroll(codeCell));
252
- }
253
- });
254
- });
255
229
  // when the notebook widget is created, process all the cells
256
- // TODO: investigate why notebook.content.fullyRendered is not enough
257
230
  notebook.sessionContext.ready.then(() => {
258
- notebook.content.widgets.forEach(cell => {
259
- if (cell.model.type === 'code') {
260
- autoScroll(cell);
261
- }
262
- });
231
+ notebook.content.widgets.forEach(setAutoScroll);
232
+ });
233
+ (_a = notebook.model) === null || _a === void 0 ? void 0 : _a.cells.changed.connect((sender, args) => {
234
+ notebook.content.widgets.forEach(setAutoScroll);
263
235
  });
264
236
  });
265
237
  if (settingRegistry) {
@@ -281,6 +253,28 @@ const scrollOutput = {
281
253
  }
282
254
  }
283
255
  };
256
+ /**
257
+ * A plugin to add the NotebookTools to the side panel;
258
+ */
259
+ const notebookToolsWidget = {
260
+ id: '@jupyter-notebook/notebook-extension:notebook-tools',
261
+ autoStart: true,
262
+ requires: [INotebookShell],
263
+ optional: [INotebookTools],
264
+ activate: (app, shell, notebookTools) => {
265
+ const onChange = async () => {
266
+ const current = shell.currentWidget;
267
+ if (!(current instanceof NotebookPanel)) {
268
+ return;
269
+ }
270
+ // Add the notebook tools in right area.
271
+ if (notebookTools) {
272
+ shell.add(notebookTools, 'right');
273
+ }
274
+ };
275
+ shell.currentChanged.connect(onChange);
276
+ }
277
+ };
284
278
  /**
285
279
  * Export the plugins as default.
286
280
  */
@@ -288,7 +282,7 @@ const plugins = [
288
282
  checkpoints,
289
283
  kernelLogo,
290
284
  kernelStatus,
291
- menuPlugin,
292
- scrollOutput
285
+ scrollOutput,
286
+ notebookToolsWidget
293
287
  ];
294
288
  export default plugins;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyter-notebook/notebook-extension",
3
- "version": "7.0.0-alpha.1",
3
+ "version": "7.0.0-alpha.11",
4
4
  "description": "Jupyter Notebook - Notebook Extension",
5
5
  "homepage": "https://github.com/jupyter/notebook",
6
6
  "bugs": {
@@ -39,20 +39,20 @@
39
39
  "watch": "tsc -b --watch"
40
40
  },
41
41
  "dependencies": {
42
- "@jupyter-notebook/application": "^7.0.0-alpha.1",
43
- "@jupyterlab/application": "^4.0.0-alpha.5",
44
- "@jupyterlab/apputils": "^4.0.0-alpha.5",
45
- "@jupyterlab/cells": "^4.0.0-alpha.5",
46
- "@jupyterlab/docmanager": "^4.0.0-alpha.5",
47
- "@jupyterlab/notebook": "^4.0.0-alpha.5",
48
- "@jupyterlab/settingregistry": "^4.0.0-alpha.5",
49
- "@jupyterlab/translation": "^4.0.0-alpha.4",
50
- "@lumino/polling": "^1.10.0",
51
- "@lumino/widgets": "^1.31.1"
42
+ "@jupyter-notebook/application": "^7.0.0-alpha.11",
43
+ "@jupyterlab/application": "^4.0.0-alpha.17",
44
+ "@jupyterlab/apputils": "^4.0.0-alpha.17",
45
+ "@jupyterlab/cells": "^4.0.0-alpha.17",
46
+ "@jupyterlab/docmanager": "^4.0.0-alpha.17",
47
+ "@jupyterlab/notebook": "^4.0.0-alpha.17",
48
+ "@jupyterlab/settingregistry": "^4.0.0-alpha.17",
49
+ "@jupyterlab/translation": "^4.0.0-alpha.17",
50
+ "@lumino/polling": "^2.0.0-alpha.7",
51
+ "@lumino/widgets": "^2.0.0-alpha.7"
52
52
  },
53
53
  "devDependencies": {
54
- "rimraf": "~3.0.0",
55
- "typescript": "~4.1.3"
54
+ "rimraf": "^3.0.2",
55
+ "typescript": "~4.9.3"
56
56
  },
57
57
  "publishConfig": {
58
58
  "access": "public"
@@ -0,0 +1,10 @@
1
+ {
2
+ "title": "Notebook checkpoint indicator",
3
+ "description": "Notebook checkpoint indicator",
4
+ "jupyter.lab.toolbars": {
5
+ "TopBar": [{ "name": "checkpoint", "rank": 20 }]
6
+ },
7
+ "properties": {},
8
+ "additionalProperties": false,
9
+ "type": "object"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "title": "Kernel logo",
3
+ "description": "Kernel logo in the top area",
4
+ "jupyter.lab.toolbars": {
5
+ "TopBar": [{ "name": "kernelLogo", "rank": 110 }]
6
+ },
7
+ "properties": {},
8
+ "additionalProperties": false,
9
+ "type": "object"
10
+ }
package/style/base.css CHANGED
@@ -6,16 +6,53 @@
6
6
 
7
7
  @import './variables.css';
8
8
 
9
- /* Document oriented look for the notebook (scrollbar to the right of the page) */
9
+ /**
10
+ Document oriented look for the notebook.
11
+ This includes changes to the look and feel of the JupyterLab Notebook
12
+ component like:
13
+ - scrollbar to the right of the page
14
+ - drop shadow on the notebook
15
+ - smaller empty space at the bottom of the notebook
16
+ - compact view on mobile
17
+ */
18
+
19
+ /* Keep the notebook centered on the page */
10
20
 
11
21
  body[data-notebook='notebooks'] .jp-NotebookPanel-toolbar {
12
22
  padding-left: calc(calc(100% - var(--jp-notebook-max-width)) * 0.5);
13
23
  padding-right: calc(calc(100% - var(--jp-notebook-max-width)) * 0.5);
14
24
  }
15
25
 
26
+ body[data-notebook='notebooks'] .jp-Notebook {
27
+ padding-top: unset;
28
+ padding-left: calc(calc(100% - var(--jp-notebook-max-width)) * 0.5);
29
+ padding-right: calc(
30
+ calc(
31
+ 100% - var(--jp-notebook-max-width) - var(--jp-notebook-padding-offset)
32
+ ) * 0.5
33
+ );
34
+ background: var(--jp-layout-color2);
35
+ }
36
+
37
+ body[data-notebook='notebooks'] .jp-WindowedPanel-inner {
38
+ margin-top: var(--jp-notebook-toolbar-margin-bottom);
39
+ }
40
+
41
+ body[data-notebook='notebooks'] .jp-Notebook-cell {
42
+ background: var(--jp-layout-color0);
43
+ padding-left: calc(2 * var(--jp-cell-padding));
44
+ padding-right: calc(2 * var(--jp-cell-padding));
45
+ }
46
+
47
+ /* Empty space at the bottom of the notebook (similar to classic) */
48
+ body[data-notebook='notebooks'] .jp-Notebook.jp-mod-scrollPastEnd::after {
49
+ min-height: 100px;
50
+ }
51
+
52
+ /* Fix background colors */
53
+
16
54
  body[data-notebook='notebooks'] .jp-Notebook > * {
17
55
  background: var(--jp-layout-color0);
18
- padding: var(--jp-notebook-padding);
19
56
  }
20
57
 
21
58
  body[data-notebook='notebooks']
@@ -24,28 +61,119 @@ body[data-notebook='notebooks']
24
61
  background: var(--jp-layout-color0) !important;
25
62
  }
26
63
 
27
- body[data-notebook='notebooks'] .jp-Notebook > *:first-child {
28
- padding-top: var(--jp-notebook-padding-offset);
29
- margin-top: var(--jp-notebook-toolbar-margin-bottom);
64
+ /**
65
+ Extra padding to the first and and last cell of the notebook.
66
+ TODO: revisit when https://github.com/jupyterlab/jupyterlab/issues/13151 is fixed
67
+ */
68
+ .jp-Notebook-cell[data-windowed-list-index='0'] {
69
+ padding-top: calc(2 * var(--jp-notebook-padding));
30
70
  }
31
71
 
32
- body[data-notebook='notebooks'] .jp-Notebook {
33
- padding-top: unset;
34
- padding-bottom: unset;
35
- padding-left: calc(calc(100% - var(--jp-notebook-max-width)) * 0.5);
36
- padding-right: calc(
37
- calc(
38
- 100% - var(--jp-notebook-max-width) - var(--jp-notebook-padding-offset)
39
- ) * 0.5
40
- );
41
- background: var(--jp-layout-color2);
72
+ body[data-notebook='notebooks'] .jp-WindowedPanel-window > *:last-child {
73
+ padding-bottom: calc(2 * var(--jp-notebook-padding));
42
74
  }
43
75
 
44
- body[data-notebook='notebooks'] .jp-Notebook.jp-mod-scrollPastEnd::after {
76
+ body[data-notebook='notebooks']
77
+ .jp-Notebook
78
+ .jp-Notebook-cell:not(:first-child)::before {
79
+ content: ' ';
80
+ height: 100%;
81
+ position: absolute;
82
+ top: 0;
83
+ width: 11px;
84
+ }
85
+
86
+ /* Cell toolbar adjustements */
87
+
88
+ body[data-notebook='notebooks'] .jp-cell-toolbar {
89
+ background: unset;
90
+ box-shadow: unset;
91
+ }
92
+
93
+ body[data-notebook='notebooks']
94
+ .jp-RawCell[data-windowed-list-index='0']
95
+ .jp-cell-toolbar,
96
+ body[data-notebook='notebooks']
97
+ .jp-MarkdownCell[data-windowed-list-index='0']
98
+ .jp-cell-toolbar {
99
+ top: calc(2 * var(--jp-notebook-padding));
100
+ }
101
+
102
+ /** first code cell on mobile
103
+ (keep the selector above the media query)
104
+ */
105
+ body[data-notebook='notebooks']
106
+ .jp-CodeCell[data-windowed-list-index='0']
107
+ .jp-cell-toolbar {
108
+ top: unset;
109
+ }
110
+
111
+ @media only screen and (max-width: 760px) {
112
+ /* first code cell on mobile */
113
+ body[data-notebook='notebooks']
114
+ .jp-CodeCell[data-windowed-list-index='0']
115
+ .jp-cell-toolbar {
116
+ top: var(--jp-notebook-padding);
117
+ }
118
+
119
+ body[data-notebook='notebooks'] .jp-MarkdownCell .jp-cell-toolbar,
120
+ body[data-notebook='notebooks'] .jp-RawCell .jp-cell-toolbar {
121
+ top: calc(0.5 * var(--jp-notebook-padding));
122
+ }
123
+ }
124
+
125
+ /* Mobile View */
126
+
127
+ body[data-format='mobile'] .jp-NotebookCheckpoint {
128
+ display: none;
129
+ }
130
+
131
+ body[data-format='mobile'] .jp-Notebook > *:first-child {
132
+ margin-top: 0;
133
+ }
134
+
135
+ /* Virtual Notebook fixes */
136
+
137
+ body[data-notebook='notebooks'] .jp-WindowedPanel-window {
45
138
  background: var(--jp-layout-color0);
46
139
  }
47
140
 
48
- /* ---- */
141
+ /* Notebook box shadow */
142
+
143
+ body[data-notebook='notebooks'] .jp-Notebook > *:first-child:not(:last-child) {
144
+ box-shadow: 0px 0px 12px 1px var(--jp-shadow-umbra-color);
145
+ }
146
+
147
+ body[data-notebook='notebooks'] .jp-Notebook > *:first-child:not(:last-child) {
148
+ box-shadow: 0px 0px 12px 1px var(--jp-shadow-umbra-color);
149
+ }
150
+
151
+ body[data-notebook='notebooks']
152
+ .jp-Notebook
153
+ > *:first-child:last-child::before {
154
+ content: '';
155
+ position: absolute;
156
+ top: 0;
157
+ bottom: 0;
158
+ left: 0;
159
+ right: 0;
160
+ box-shadow: 0px 0px 12px 1px var(--jp-shadow-umbra-color);
161
+ }
162
+
163
+ body[data-notebook='notebooks']
164
+ .jp-Notebook
165
+ .jp-Notebook-cell:not(:first-child)::after,
166
+ body[data-notebook='notebooks']
167
+ .jp-Notebook
168
+ .jp-Notebook-cell:not(:first-child)::before {
169
+ content: ' ';
170
+ height: 100%;
171
+ position: absolute;
172
+ top: 0;
173
+ width: 11px;
174
+ }
175
+
176
+ /* Additional customizations of the components on the notebook page */
49
177
 
50
178
  .jp-NotebookKernelLogo {
51
179
  flex: 0 0 auto;
@@ -126,13 +254,3 @@ body[data-notebook='notebooks'] .jp-Notebook.jp-mod-scrollPastEnd::after {
126
254
  overflow: hidden;
127
255
  white-space: nowrap;
128
256
  }
129
-
130
- /* Mobile View */
131
-
132
- body[data-format='mobile'] .jp-NotebookCheckpoint {
133
- display: none;
134
- }
135
-
136
- body[data-format='mobile'] .jp-Notebook > *:first-child {
137
- margin-top: 0;
138
- }