@zikojs/notebook 0.14.1 → 0.15.0
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/package.json +3 -4
- package/src/code-editor/index.js +116 -51
- package/src/compiler/evaluate.js +12 -3
- package/src/compiler/imports.js +69 -6
- package/src/compiler/transform.js +4 -0
- package/src/components/CellItem/index.js +4 -4
- package/src/components/MarkdownView/index.css +2 -1
- package/src/components/MarkdownView/index.js +3 -1
- package/src/index.css +34 -25
- package/src/notebook.js +29 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zikojs/notebook",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "A lightweight, extensible JavaScript notebook component with Markdown, executable cells, persistent state, and pluggable runtimes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -41,16 +41,15 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@codemirror/autocomplete": "^6.20.3",
|
|
43
43
|
"@codemirror/commands": "^6.11.0",
|
|
44
|
-
"@codemirror/lang-javascript": "
|
|
44
|
+
"@codemirror/lang-javascript": "latest",
|
|
45
45
|
"@codemirror/lang-markdown": "^6.5.2",
|
|
46
46
|
"@codemirror/language": "^6.12.4",
|
|
47
47
|
"@codemirror/state": "^6.7.4",
|
|
48
48
|
"@codemirror/view": "^6.43.11",
|
|
49
|
-
"@zikojs/lucide": "^0.2.2",
|
|
50
49
|
"@zikojs/console": "^0.8.0",
|
|
50
|
+
"@zikojs/lucide": "^0.2.2",
|
|
51
51
|
"acorn": "^8.18.0",
|
|
52
52
|
"codemirror": "^6.0.2",
|
|
53
|
-
"lucide": "^1.44.0",
|
|
54
53
|
"rehype-stringify": "^10.0.1",
|
|
55
54
|
"remark": "^15.0.1",
|
|
56
55
|
"remark-rehype": "^11.1.2",
|
package/src/code-editor/index.js
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
EditorView,
|
|
3
|
+
keymap,
|
|
4
|
+
lineNumbers,
|
|
5
|
+
highlightActiveLine,
|
|
6
|
+
} from "@codemirror/view";
|
|
2
7
|
import { EditorState, Compartment } from "@codemirror/state";
|
|
3
|
-
import {
|
|
4
|
-
|
|
8
|
+
import {
|
|
9
|
+
defaultKeymap,
|
|
10
|
+
history,
|
|
11
|
+
historyKeymap,
|
|
12
|
+
indentWithTab,
|
|
13
|
+
} from "@codemirror/commands";
|
|
14
|
+
import {
|
|
15
|
+
bracketMatching,
|
|
16
|
+
indentUnit,
|
|
17
|
+
syntaxHighlighting,
|
|
18
|
+
defaultHighlightStyle,
|
|
19
|
+
} from "@codemirror/language";
|
|
5
20
|
import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
6
21
|
import { javascript } from "@codemirror/lang-javascript";
|
|
7
22
|
import { markdown } from "@codemirror/lang-markdown";
|
|
@@ -9,7 +24,6 @@ import { tags } from "ziko/dom";
|
|
|
9
24
|
|
|
10
25
|
const { div } = tags;
|
|
11
26
|
|
|
12
|
-
|
|
13
27
|
const getRuntimePlugin = (runtime, runtimePlugins = []) =>
|
|
14
28
|
runtimePlugins.find((plugin) => plugin?.name === runtime);
|
|
15
29
|
|
|
@@ -39,7 +53,7 @@ export function createCodeEditor(app, cellData, actions) {
|
|
|
39
53
|
const buildPluginKeymap = () => {
|
|
40
54
|
const bindings = [];
|
|
41
55
|
|
|
42
|
-
app.codeMirrorPlugins.forEach(plugin => {
|
|
56
|
+
app.codeMirrorPlugins.forEach((plugin) => {
|
|
43
57
|
if (plugin && typeof plugin === "object" && plugin.extraKeys) {
|
|
44
58
|
Object.entries(plugin.extraKeys).forEach(([key, run]) => {
|
|
45
59
|
bindings.push({
|
|
@@ -47,7 +61,7 @@ export function createCodeEditor(app, cellData, actions) {
|
|
|
47
61
|
run: () => {
|
|
48
62
|
run();
|
|
49
63
|
return true;
|
|
50
|
-
}
|
|
64
|
+
},
|
|
51
65
|
});
|
|
52
66
|
});
|
|
53
67
|
}
|
|
@@ -60,12 +74,49 @@ export function createCodeEditor(app, cellData, actions) {
|
|
|
60
74
|
if (view) return;
|
|
61
75
|
|
|
62
76
|
const shortcutKeymap = keymap.of([
|
|
77
|
+
{
|
|
78
|
+
key: "Ctrl-ArrowDown",
|
|
79
|
+
run: () => actions.moveToAdjacentCell(1),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
key: "Ctrl-ArrowUp",
|
|
83
|
+
run: () => actions.moveToAdjacentCell(-1),
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
key: "ArrowDown",
|
|
87
|
+
run: (editorView) => {
|
|
88
|
+
const selection = editorView.state.selection.main;
|
|
89
|
+
const line = editorView.state.doc.lineAt(selection.head);
|
|
90
|
+
|
|
91
|
+
if (
|
|
92
|
+
selection.empty &&
|
|
93
|
+
line.number === editorView.state.doc.lines
|
|
94
|
+
) {
|
|
95
|
+
return actions.moveToAdjacentCell(1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return false;
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
key: "ArrowUp",
|
|
103
|
+
run: (editorView) => {
|
|
104
|
+
const selection = editorView.state.selection.main;
|
|
105
|
+
const line = editorView.state.doc.lineAt(selection.head);
|
|
106
|
+
|
|
107
|
+
if (selection.empty && line.number === 1) {
|
|
108
|
+
return actions.moveToAdjacentCell(-1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return false;
|
|
112
|
+
},
|
|
113
|
+
},
|
|
63
114
|
{
|
|
64
115
|
key: "Shift-Enter",
|
|
65
116
|
run: () => {
|
|
66
117
|
actions.runCode(true);
|
|
67
118
|
return true;
|
|
68
|
-
}
|
|
119
|
+
},
|
|
69
120
|
},
|
|
70
121
|
{
|
|
71
122
|
key: "Ctrl-Enter",
|
|
@@ -73,7 +124,7 @@ export function createCodeEditor(app, cellData, actions) {
|
|
|
73
124
|
run: () => {
|
|
74
125
|
actions.runCode(false);
|
|
75
126
|
return true;
|
|
76
|
-
}
|
|
127
|
+
},
|
|
77
128
|
},
|
|
78
129
|
{
|
|
79
130
|
key: "Ctrl-Shift-d",
|
|
@@ -81,7 +132,7 @@ export function createCodeEditor(app, cellData, actions) {
|
|
|
81
132
|
run: () => {
|
|
82
133
|
app.notebookGlobalShortcuts.deleteActive();
|
|
83
134
|
return true;
|
|
84
|
-
}
|
|
135
|
+
},
|
|
85
136
|
},
|
|
86
137
|
{
|
|
87
138
|
key: "Ctrl-Shift-m",
|
|
@@ -89,7 +140,7 @@ export function createCodeEditor(app, cellData, actions) {
|
|
|
89
140
|
run: () => {
|
|
90
141
|
app.notebookGlobalShortcuts.addMdBelow();
|
|
91
142
|
return true;
|
|
92
|
-
}
|
|
143
|
+
},
|
|
93
144
|
},
|
|
94
145
|
{
|
|
95
146
|
key: "Ctrl-Shift-y",
|
|
@@ -97,14 +148,13 @@ export function createCodeEditor(app, cellData, actions) {
|
|
|
97
148
|
run: () => {
|
|
98
149
|
app.notebookGlobalShortcuts.addCodeBelow();
|
|
99
150
|
return true;
|
|
100
|
-
}
|
|
151
|
+
},
|
|
101
152
|
},
|
|
102
153
|
indentWithTab,
|
|
103
154
|
...buildPluginKeymap(),
|
|
104
155
|
...closeBracketsKeymap,
|
|
105
156
|
...defaultKeymap,
|
|
106
157
|
...historyKeymap,
|
|
107
|
-
|
|
108
158
|
]);
|
|
109
159
|
|
|
110
160
|
const extraExtensions = Array.isArray(app.codeMirrorConfig)
|
|
@@ -114,39 +164,38 @@ export function createCodeEditor(app, cellData, actions) {
|
|
|
114
164
|
const state = EditorState.create({
|
|
115
165
|
doc: cellData.code,
|
|
116
166
|
extensions: [
|
|
117
|
-
lineNumbers(),
|
|
167
|
+
// lineNumbers(),
|
|
118
168
|
highlightActiveLine(),
|
|
169
|
+
// EditorView.theme({
|
|
170
|
+
// "&": {
|
|
171
|
+
// fontFamily: '"Fira Code", SFMono-Regular, Consolas, monospace',
|
|
172
|
+
// fontSize: "13px",
|
|
173
|
+
// lineHeight: "17px",
|
|
174
|
+
// },
|
|
175
|
+
// ".cm-scroller, .cm-content, .cm-line, .cm-gutterElement": {
|
|
176
|
+
// lineHeight: "17px",
|
|
177
|
+
// },
|
|
178
|
+
// }),
|
|
119
179
|
|
|
120
180
|
history(),
|
|
121
181
|
bracketMatching(),
|
|
122
182
|
closeBrackets(),
|
|
123
|
-
|
|
124
183
|
syntaxHighlighting(defaultHighlightStyle),
|
|
125
|
-
|
|
126
184
|
shortcutKeymap,
|
|
127
|
-
|
|
128
185
|
EditorView.lineWrapping,
|
|
129
|
-
|
|
130
186
|
indentUnit.of(" "),
|
|
131
187
|
EditorState.tabSize.of(2),
|
|
132
|
-
|
|
133
188
|
languageCompartment.of(
|
|
134
|
-
|
|
135
|
-
),
|
|
189
|
+
languageFor(cellData.type, cellData.runtime, app.runtimePlugins),
|
|
190
|
+
),
|
|
136
191
|
|
|
137
|
-
themeCompartment.of(
|
|
138
|
-
themeFor(cellData.runtime, app.runtimePlugins)
|
|
139
|
-
),
|
|
192
|
+
themeCompartment.of(themeFor(cellData.runtime, app.runtimePlugins)),
|
|
140
193
|
|
|
141
|
-
readOnlyCompartment.of(
|
|
142
|
-
EditorState.readOnly.of(cellData.readonly)
|
|
143
|
-
),
|
|
194
|
+
readOnlyCompartment.of(EditorState.readOnly.of(cellData.readonly)),
|
|
144
195
|
|
|
145
|
-
editableCompartment.of(
|
|
146
|
-
EditorView.editable.of(!cellData.readonly)
|
|
147
|
-
),
|
|
196
|
+
editableCompartment.of(EditorView.editable.of(!cellData.readonly)),
|
|
148
197
|
|
|
149
|
-
EditorView.updateListener.of(update => {
|
|
198
|
+
EditorView.updateListener.of((update) => {
|
|
150
199
|
if (update.docChanged) {
|
|
151
200
|
cellData.code = update.state.doc.toString();
|
|
152
201
|
}
|
|
@@ -155,24 +204,23 @@ themeCompartment.of(
|
|
|
155
204
|
EditorView.domEventHandlers({
|
|
156
205
|
focus: () => {
|
|
157
206
|
actions.setActive();
|
|
158
|
-
}
|
|
207
|
+
},
|
|
159
208
|
}),
|
|
160
209
|
|
|
161
|
-
...extraExtensions
|
|
162
|
-
]
|
|
210
|
+
...extraExtensions,
|
|
211
|
+
],
|
|
163
212
|
});
|
|
164
213
|
|
|
165
214
|
view = new EditorView({
|
|
166
215
|
state,
|
|
167
|
-
parent: editorDom.element
|
|
216
|
+
parent: editorDom.element,
|
|
168
217
|
});
|
|
169
218
|
|
|
170
219
|
const lineHeight = view.defaultLineHeight || 19;
|
|
171
220
|
|
|
172
|
-
view.dom.style.minHeight =
|
|
173
|
-
`${Math.ceil(app.minLines * lineHeight + 8)}px`;
|
|
221
|
+
view.dom.style.minHeight = `${Math.ceil(app.minLines * lineHeight + 8)}px`;
|
|
174
222
|
|
|
175
|
-
app.codeMirrorPlugins.forEach(plugin => {
|
|
223
|
+
app.codeMirrorPlugins.forEach((plugin) => {
|
|
176
224
|
if (typeof plugin === "function") {
|
|
177
225
|
plugin(view);
|
|
178
226
|
}
|
|
@@ -182,10 +230,23 @@ themeCompartment.of(
|
|
|
182
230
|
return {
|
|
183
231
|
dom: editorDom.element,
|
|
184
232
|
|
|
185
|
-
getValue: () =>
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
233
|
+
getValue: () => (view ? view.state.doc.toString() : cellData.code),
|
|
234
|
+
|
|
235
|
+
focusAt: (position) => {
|
|
236
|
+
requestAnimationFrame(() => {
|
|
237
|
+
if (!view) return;
|
|
238
|
+
|
|
239
|
+
const cursor = Math.max(
|
|
240
|
+
0,
|
|
241
|
+
Math.min(position, view.state.doc.length),
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
view.dispatch({
|
|
245
|
+
selection: { anchor: cursor },
|
|
246
|
+
});
|
|
247
|
+
view.focus();
|
|
248
|
+
});
|
|
249
|
+
},
|
|
189
250
|
|
|
190
251
|
sync: (isActive, isMarkdownView) => {
|
|
191
252
|
if (!isMarkdownView) {
|
|
@@ -195,21 +256,25 @@ themeCompartment.of(
|
|
|
195
256
|
view.dispatch({
|
|
196
257
|
effects: [
|
|
197
258
|
languageCompartment.reconfigure(
|
|
198
|
-
languageFor(
|
|
259
|
+
languageFor(
|
|
260
|
+
cellData.type,
|
|
261
|
+
cellData.runtime,
|
|
262
|
+
app.runtimePlugins,
|
|
263
|
+
),
|
|
199
264
|
),
|
|
200
265
|
|
|
201
266
|
themeCompartment.reconfigure(
|
|
202
|
-
themeFor(cellData.runtime, app.runtimePlugins)
|
|
267
|
+
themeFor(cellData.runtime, app.runtimePlugins),
|
|
203
268
|
),
|
|
204
269
|
|
|
205
270
|
readOnlyCompartment.reconfigure(
|
|
206
|
-
EditorState.readOnly.of(cellData.readonly)
|
|
271
|
+
EditorState.readOnly.of(cellData.readonly),
|
|
207
272
|
),
|
|
208
273
|
|
|
209
274
|
editableCompartment.reconfigure(
|
|
210
|
-
EditorView.editable.of(!cellData.readonly)
|
|
211
|
-
)
|
|
212
|
-
]
|
|
275
|
+
EditorView.editable.of(!cellData.readonly),
|
|
276
|
+
),
|
|
277
|
+
],
|
|
213
278
|
});
|
|
214
279
|
|
|
215
280
|
const currentValue = view.state.doc.toString();
|
|
@@ -219,8 +284,8 @@ themeCompartment.of(
|
|
|
219
284
|
changes: {
|
|
220
285
|
from: 0,
|
|
221
286
|
to: currentValue.length,
|
|
222
|
-
insert: cellData.code
|
|
223
|
-
}
|
|
287
|
+
insert: cellData.code,
|
|
288
|
+
},
|
|
224
289
|
});
|
|
225
290
|
}
|
|
226
291
|
}
|
|
@@ -232,6 +297,6 @@ themeCompartment.of(
|
|
|
232
297
|
view.destroy();
|
|
233
298
|
view = null;
|
|
234
299
|
}
|
|
235
|
-
}
|
|
300
|
+
},
|
|
236
301
|
};
|
|
237
|
-
}
|
|
302
|
+
}
|
package/src/compiler/evaluate.js
CHANGED
|
@@ -17,12 +17,14 @@ export const evaluateCodeAsync = async (
|
|
|
17
17
|
importMap = {},
|
|
18
18
|
plugins = [],
|
|
19
19
|
runtime = null,
|
|
20
|
+
cdnFallback = true,
|
|
20
21
|
} = {},
|
|
21
22
|
scope,
|
|
22
23
|
) => {
|
|
23
24
|
const validScope = scope || Object.create(null);
|
|
25
|
+
const importScope = Object.create(null);
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
validScope.console = Console;
|
|
26
28
|
|
|
27
29
|
const context = {
|
|
28
30
|
TARGET,
|
|
@@ -30,6 +32,7 @@ export const evaluateCodeAsync = async (
|
|
|
30
32
|
importMap,
|
|
31
33
|
plugins,
|
|
32
34
|
runtime,
|
|
35
|
+
cdnFallback
|
|
33
36
|
};
|
|
34
37
|
|
|
35
38
|
const selectedPlugin = plugins.find(
|
|
@@ -70,6 +73,8 @@ export const evaluateCodeAsync = async (
|
|
|
70
73
|
{
|
|
71
74
|
importMap,
|
|
72
75
|
plugins,
|
|
76
|
+
cdnFallback,
|
|
77
|
+
importScopeIdentifier: "__imports__",
|
|
73
78
|
},
|
|
74
79
|
);
|
|
75
80
|
// console.log(compiledCode)
|
|
@@ -77,6 +82,7 @@ export const evaluateCodeAsync = async (
|
|
|
77
82
|
const runCell = new Function(
|
|
78
83
|
"TARGET",
|
|
79
84
|
"__scope__",
|
|
85
|
+
"__imports__",
|
|
80
86
|
`
|
|
81
87
|
// Bind the active TARGET for this cell evaluation
|
|
82
88
|
if (typeof __Ziko__ !== "undefined" && __Ziko__.__Config__) {
|
|
@@ -89,9 +95,11 @@ export const evaluateCodeAsync = async (
|
|
|
89
95
|
return (async () => {
|
|
90
96
|
with (__scope__) {
|
|
91
97
|
return await (async () => {
|
|
92
|
-
|
|
98
|
+
with (__imports__) {
|
|
99
|
+
${compiledCode}
|
|
100
|
+
}
|
|
93
101
|
})();
|
|
94
|
-
|
|
102
|
+
}
|
|
95
103
|
})();
|
|
96
104
|
`,
|
|
97
105
|
);
|
|
@@ -99,6 +107,7 @@ export const evaluateCodeAsync = async (
|
|
|
99
107
|
let result = await runCell(
|
|
100
108
|
TARGET,
|
|
101
109
|
validScope,
|
|
110
|
+
importScope,
|
|
102
111
|
);
|
|
103
112
|
|
|
104
113
|
for (const plugin of plugins) {
|
package/src/compiler/imports.js
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
|
|
2
2
|
const CDN = "https://esm.sh/";
|
|
3
|
+
const MANIFEST_FILE = "ziko-notebook-imports.json";
|
|
4
|
+
const isProductionBuild =
|
|
5
|
+
typeof import.meta.env !== "undefined" && import.meta.env.PROD;
|
|
6
|
+
|
|
7
|
+
let buildImportMapPromise;
|
|
8
|
+
|
|
9
|
+
const loadBuildImportMap = () => {
|
|
10
|
+
if (!isProductionBuild || typeof document === "undefined") {
|
|
11
|
+
return Promise.resolve({});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!buildImportMapPromise) {
|
|
15
|
+
const manifestUrl = new URL(MANIFEST_FILE, document.baseURI);
|
|
16
|
+
|
|
17
|
+
buildImportMapPromise = fetch(manifestUrl).then(async (response) => {
|
|
18
|
+
if (response.status === 404) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`Failed to load the notebook import map: ${response.status} ${response.statusText}`,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const imports = await response.json();
|
|
29
|
+
|
|
30
|
+
if (!imports || typeof imports !== "object" || Array.isArray(imports)) {
|
|
31
|
+
throw new TypeError("The notebook import map must be a JSON object.");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return imports;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return buildImportMapPromise;
|
|
39
|
+
};
|
|
3
40
|
|
|
4
41
|
const isURL = (source) =>
|
|
5
42
|
/^(?:https?:\/\/|data:|blob:)/i.test(source);
|
|
@@ -16,8 +53,10 @@ export const resolveImport = async (
|
|
|
16
53
|
importMap = {},
|
|
17
54
|
plugins = [],
|
|
18
55
|
resolverEndpoint = "/__notebook_resolve",
|
|
56
|
+
cdnFallback = true,
|
|
19
57
|
} = {},
|
|
20
58
|
) => {
|
|
59
|
+
// Preserve explicit mappings, including package subpaths.
|
|
21
60
|
if (importMap[source]) {
|
|
22
61
|
return importMap[source];
|
|
23
62
|
}
|
|
@@ -26,6 +65,7 @@ export const resolveImport = async (
|
|
|
26
65
|
return source;
|
|
27
66
|
}
|
|
28
67
|
|
|
68
|
+
// Preserve runtime-specific and custom resolution hooks.
|
|
29
69
|
for (const plugin of plugins) {
|
|
30
70
|
if (typeof plugin.resolveImport !== "function") {
|
|
31
71
|
continue;
|
|
@@ -38,8 +78,17 @@ export const resolveImport = async (
|
|
|
38
78
|
}
|
|
39
79
|
}
|
|
40
80
|
|
|
81
|
+
const buildImportMap = await loadBuildImportMap();
|
|
82
|
+
|
|
83
|
+
if (typeof buildImportMap[source] === "string") {
|
|
84
|
+
return buildImportMap[source];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Ask the host dev server to resolve installed packages.
|
|
41
88
|
try {
|
|
42
|
-
const params = new URLSearchParams({
|
|
89
|
+
const params = new URLSearchParams({
|
|
90
|
+
specifier: source,
|
|
91
|
+
});
|
|
43
92
|
|
|
44
93
|
const response = await fetch(
|
|
45
94
|
`${resolverEndpoint}?${params.toString()}`,
|
|
@@ -56,9 +105,19 @@ export const resolveImport = async (
|
|
|
56
105
|
// The Vite endpoint may not be available outside development.
|
|
57
106
|
}
|
|
58
107
|
|
|
59
|
-
|
|
108
|
+
if (cdnFallback) {
|
|
109
|
+
return `${CDN}${source}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Cannot resolve "${source}" locally. ` +
|
|
114
|
+
`Install the package or provide an importMap entry. ` +
|
|
115
|
+
`CDN fallback is disabled.`,
|
|
116
|
+
);
|
|
60
117
|
};
|
|
61
118
|
|
|
119
|
+
// Keep your existing rewriteImportNode implementation below.
|
|
120
|
+
|
|
62
121
|
export const rewriteImportNode = async (
|
|
63
122
|
node,
|
|
64
123
|
code,
|
|
@@ -68,6 +127,8 @@ export const rewriteImportNode = async (
|
|
|
68
127
|
node.source.value,
|
|
69
128
|
context,
|
|
70
129
|
);
|
|
130
|
+
const importScope =
|
|
131
|
+
context.importScopeIdentifier || "__scope__";
|
|
71
132
|
|
|
72
133
|
// Safely quote the URL in generated JavaScript.
|
|
73
134
|
const url = JSON.stringify(source);
|
|
@@ -96,7 +157,7 @@ export const rewriteImportNode = async (
|
|
|
96
157
|
|
|
97
158
|
if (namespaceId) {
|
|
98
159
|
return (
|
|
99
|
-
|
|
160
|
+
`${importScope}.${namespaceId} = ` +
|
|
100
161
|
`await import(${url});`
|
|
101
162
|
);
|
|
102
163
|
}
|
|
@@ -109,17 +170,19 @@ export const rewriteImportNode = async (
|
|
|
109
170
|
|
|
110
171
|
if (defaultImportName) {
|
|
111
172
|
lines.push(
|
|
112
|
-
|
|
173
|
+
`${importScope}.${defaultImportName} = ` +
|
|
113
174
|
`${tmp}.default ?? ${tmp};`,
|
|
114
175
|
);
|
|
115
176
|
}
|
|
116
177
|
|
|
117
178
|
for (const { imported, local } of namedImports) {
|
|
118
179
|
lines.push(
|
|
119
|
-
|
|
180
|
+
`${importScope}.${local} = ` +
|
|
120
181
|
`${tmp}[${JSON.stringify(imported)}] !== undefined ` +
|
|
121
182
|
`? ${tmp}[${JSON.stringify(imported)}] ` +
|
|
122
|
-
`: (${tmp}.default
|
|
183
|
+
`: (${tmp}.default?.[${JSON.stringify(imported)}] !== undefined ` +
|
|
184
|
+
`? ${tmp}.default[${JSON.stringify(imported)}] ` +
|
|
185
|
+
`: (${tmp}.default ?? ${tmp}));`,
|
|
123
186
|
);
|
|
124
187
|
}
|
|
125
188
|
|
|
@@ -17,6 +17,7 @@ export const transformImportsAndScope = async (
|
|
|
17
17
|
importMap = {},
|
|
18
18
|
plugins = [],
|
|
19
19
|
resolverEndpoint,
|
|
20
|
+
importScopeIdentifier = "__scope__",
|
|
20
21
|
} = {},
|
|
21
22
|
) => {
|
|
22
23
|
try {
|
|
@@ -30,6 +31,7 @@ export const transformImportsAndScope = async (
|
|
|
30
31
|
importMap,
|
|
31
32
|
plugins,
|
|
32
33
|
resolverEndpoint,
|
|
34
|
+
importScopeIdentifier,
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
const modifications = [];
|
|
@@ -95,6 +97,8 @@ export const transformImportsAndScope = async (
|
|
|
95
97
|
transformedCode.slice(modification.end);
|
|
96
98
|
}
|
|
97
99
|
|
|
100
|
+
console.log(transformedCode)
|
|
101
|
+
|
|
98
102
|
return transformedCode;
|
|
99
103
|
} catch (error) {
|
|
100
104
|
if (
|
|
@@ -46,16 +46,16 @@ export function CellItem({ cellData, app, store }) {
|
|
|
46
46
|
runtimePlugins: app.runtimePlugins
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const root = div({ class: "cell" },
|
|
49
|
+
const inputRow = div({ class: "cell-input-row" }, inPrompt, bodySlot);
|
|
50
|
+
const outputRow = div({ class: "cell-output-row" }, outPrompt, div({ class: "output-wrapper" }, outputRef));
|
|
51
|
+
const root = div({ class: "cell" }, inputRow, controlsEl, outputRow);
|
|
52
52
|
root.onClick(() => app.setActiveCell(cellData.id));
|
|
53
53
|
|
|
54
54
|
cellData._dom = root.element;
|
|
55
55
|
cellData._inPrompt = inPrompt.element;
|
|
56
56
|
cellData._outPrompt = outPrompt.element;
|
|
57
57
|
cellData._bodySlot = bodySlot.element;
|
|
58
|
-
cellData.
|
|
58
|
+
cellData._outputRow = outputRow.element;
|
|
59
59
|
cellData._setIn = setIn;
|
|
60
60
|
|
|
61
61
|
app._refreshCell(cellData);
|
package/src/index.css
CHANGED
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
display: flex;
|
|
24
24
|
flex-direction: column;
|
|
25
25
|
gap: 12px;
|
|
26
|
+
overflow: auto;
|
|
27
|
+
/* max-height: 100vh; */
|
|
28
|
+
/* scrollbar-color: rebeccapurple transparent; */
|
|
29
|
+
/* scrollbar-color: var(--prompt-in) transparent; */
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
.ziko-notebook .cell {
|
|
@@ -32,7 +36,7 @@
|
|
|
32
36
|
border-left: 4px solid transparent;
|
|
33
37
|
border-radius: 6px;
|
|
34
38
|
padding: 8px;
|
|
35
|
-
gap:
|
|
39
|
+
gap: 2px;
|
|
36
40
|
background: #ffffff;
|
|
37
41
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
38
42
|
position: relative;
|
|
@@ -43,17 +47,15 @@
|
|
|
43
47
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
.ziko-notebook .cell-input-
|
|
47
|
-
display:
|
|
48
|
-
grid-template-columns: 56px 1fr auto;
|
|
50
|
+
.ziko-notebook .cell-input-row {
|
|
51
|
+
display: flex;
|
|
49
52
|
align-items: flex-start;
|
|
50
53
|
gap: 8px;
|
|
51
54
|
width: 100%;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
.ziko-notebook .cell-output-
|
|
55
|
-
display:
|
|
56
|
-
grid-template-columns: 56px 1fr;
|
|
57
|
+
.ziko-notebook .cell-output-row {
|
|
58
|
+
display: flex;
|
|
57
59
|
align-items: flex-start;
|
|
58
60
|
gap: 8px;
|
|
59
61
|
width: 100%;
|
|
@@ -81,7 +83,9 @@
|
|
|
81
83
|
border-radius: 4px;
|
|
82
84
|
background: var(--bg-editor);
|
|
83
85
|
overflow: hidden;
|
|
84
|
-
|
|
86
|
+
flex: 1 1 0;
|
|
87
|
+
min-width: 0;
|
|
88
|
+
width: auto;
|
|
85
89
|
transition: border-color 0.15s ease;
|
|
86
90
|
}
|
|
87
91
|
|
|
@@ -111,13 +115,10 @@
|
|
|
111
115
|
/* align-items: center; */
|
|
112
116
|
align-items: baseline;
|
|
113
117
|
justify-content: flex-end;
|
|
114
|
-
|
|
115
|
-
gap: 4px;
|
|
116
|
-
flex-shrink: 0;
|
|
118
|
+
gap: 2px;
|
|
117
119
|
flex-wrap: wrap;
|
|
118
|
-
|
|
119
|
-
padding
|
|
120
|
-
margin-bottom: 2px;
|
|
120
|
+
margin: 0;
|
|
121
|
+
padding: 0;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
.ziko-notebook .cm-line{
|
|
@@ -127,7 +128,9 @@
|
|
|
127
128
|
/* --- OUTPUT --- */
|
|
128
129
|
|
|
129
130
|
.ziko-notebook .output-wrapper {
|
|
130
|
-
|
|
131
|
+
flex: 1 1 0;
|
|
132
|
+
min-width: 0;
|
|
133
|
+
width: auto;
|
|
131
134
|
padding: 4px 0;
|
|
132
135
|
}
|
|
133
136
|
|
|
@@ -151,17 +154,23 @@
|
|
|
151
154
|
align-items: baseline;
|
|
152
155
|
}
|
|
153
156
|
|
|
154
|
-
.ziko-notebook .cell-input-grid {
|
|
155
|
-
grid-template-columns: 42px 1fr;
|
|
156
|
-
grid-template-rows: auto auto;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.ziko-notebook .cell-output-grid {
|
|
160
|
-
grid-template-columns: 42px 1fr;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
157
|
.ziko-notebook .prompt {
|
|
164
158
|
font-size: 10px;
|
|
165
159
|
padding-top: 6px;
|
|
166
160
|
}
|
|
167
|
-
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
/* TEMP */
|
|
165
|
+
|
|
166
|
+
.ziko-notebook .cm-editor{
|
|
167
|
+
margin: 1px;
|
|
168
|
+
outline: none;
|
|
169
|
+
}
|
|
170
|
+
.ziko-notebook .cm-scroller{
|
|
171
|
+
margin: 1px;
|
|
172
|
+
outline: none;
|
|
173
|
+
}
|
|
174
|
+
.ziko-notebook .cm-line{
|
|
175
|
+
margin: 1px;
|
|
176
|
+
}
|
package/src/notebook.js
CHANGED
|
@@ -33,6 +33,7 @@ export class UINotebook extends UIElement {
|
|
|
33
33
|
constructor({
|
|
34
34
|
cells: initialCells = [],
|
|
35
35
|
importMap = {},
|
|
36
|
+
cdnFallback = true,
|
|
36
37
|
runCells = true,
|
|
37
38
|
minLines = 3,
|
|
38
39
|
maxCells = Infinity,
|
|
@@ -58,6 +59,7 @@ export class UINotebook extends UIElement {
|
|
|
58
59
|
this.resetScope();
|
|
59
60
|
|
|
60
61
|
this.importMap = importMap;
|
|
62
|
+
this.cdnFallback = cdnFallback;
|
|
61
63
|
this.runtimePlugins = runtimePlugins;
|
|
62
64
|
this.codeMirrorConfig = codeMirrorConfig;
|
|
63
65
|
this.codeMirrorPlugins = codeMirrorPlugins;
|
|
@@ -224,7 +226,7 @@ export class UINotebook extends UIElement {
|
|
|
224
226
|
_inPrompt: null,
|
|
225
227
|
_outPrompt: null,
|
|
226
228
|
_bodySlot: null,
|
|
227
|
-
|
|
229
|
+
_outputRow: null,
|
|
228
230
|
_outputRef: null,
|
|
229
231
|
};
|
|
230
232
|
});
|
|
@@ -312,6 +314,23 @@ export class UINotebook extends UIElement {
|
|
|
312
314
|
return {
|
|
313
315
|
setActive: () => app.setActiveCell(cellData.id),
|
|
314
316
|
|
|
317
|
+
moveToAdjacentCell: (direction) => {
|
|
318
|
+
const cells = app.store.get("cells");
|
|
319
|
+
const index = cells.findIndex(
|
|
320
|
+
(cell) => cell.id === cellData.id
|
|
321
|
+
);
|
|
322
|
+
const target = cells[index + direction];
|
|
323
|
+
|
|
324
|
+
if (!target) return false;
|
|
325
|
+
|
|
326
|
+
app.focusCell(target.id);
|
|
327
|
+
target._editor.focusAt(
|
|
328
|
+
direction > 0 ? 0 : target._editor.getValue().length
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
return true;
|
|
332
|
+
},
|
|
333
|
+
|
|
315
334
|
runCode: async (autoNext = true) => {
|
|
316
335
|
// If this cell's code is still loading, wait for it.
|
|
317
336
|
await app._resolveCellCode(cellData);
|
|
@@ -349,6 +368,7 @@ export class UINotebook extends UIElement {
|
|
|
349
368
|
cellData._outputRef,
|
|
350
369
|
{
|
|
351
370
|
importMap: app.importMap,
|
|
371
|
+
cdnFallback: app.cdnFallback,
|
|
352
372
|
plugins: app.runtimePlugins,
|
|
353
373
|
runtime: cellData.runtime,
|
|
354
374
|
},
|
|
@@ -484,8 +504,8 @@ export class UINotebook extends UIElement {
|
|
|
484
504
|
const showOutput =
|
|
485
505
|
cellData.type === "code" && cellData.hasDomOutput;
|
|
486
506
|
|
|
487
|
-
cellData.
|
|
488
|
-
showOutput ? "
|
|
507
|
+
cellData._outputRow.style.display =
|
|
508
|
+
showOutput ? "flex" : "none";
|
|
489
509
|
|
|
490
510
|
cellData._outPrompt.textContent = `Out ${countText}:`;
|
|
491
511
|
}
|
|
@@ -542,7 +562,11 @@ export class UINotebook extends UIElement {
|
|
|
542
562
|
}
|
|
543
563
|
|
|
544
564
|
this.store.set("activeCellId", id);
|
|
545
|
-
|
|
565
|
+
cells.forEach((currentCell) => {
|
|
566
|
+
if (currentCell._dom) {
|
|
567
|
+
this._refreshCell(currentCell);
|
|
568
|
+
}
|
|
569
|
+
});
|
|
546
570
|
|
|
547
571
|
// Scroll the target cell into view when it is outside the viewport.
|
|
548
572
|
requestAnimationFrame(() => {
|
|
@@ -609,7 +633,7 @@ addCell(type = "code", initialCode = null, afterId = null, readonly = false) {
|
|
|
609
633
|
_inPrompt: null,
|
|
610
634
|
_outPrompt: null,
|
|
611
635
|
_bodySlot: null,
|
|
612
|
-
|
|
636
|
+
_outputRow: null,
|
|
613
637
|
_outputRef: null,
|
|
614
638
|
};
|
|
615
639
|
|