modern-monaco 0.0.0-beta.1 → 0.0.0-beta.3

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020-2024 Je Xia <i@jex.me>
3
+ Copyright (c) 2025 Je Xia <i@jex.me>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  > [!WARNING]
2
- > **This project is currently under active development and is not ready for production use.**
2
+ > **This project is currently under active development, the API may change at any time. Use at your own risk.**
3
+ > Please report any issues or feature requests on the [issues](https://github.com/esm-dev/modern-monaco/issues) page.
3
4
 
4
5
  # Modern Monaco
5
6
 
@@ -8,7 +9,7 @@ Meeting the modern version of [Monaco Editor](https://www.npmjs.com/package/mona
8
9
  - Easy to use, no `MonacoEnvironment` setup and web-worker/css loader needed.
9
10
  - Using [Shiki](https://shiki.style) for syntax highlighting with tons of grammars and themes.
10
11
  - Lazy loading: pre-highlighting code with Shiki while loading `monaco-editor-core` in background.
11
- - Support **server-side rendering(SSR)**.
12
+ - Support server-side rendering(SSR).
12
13
  - Workspace (edit history, file system provider, persist protocol, etc).
13
14
  - Automatically loading `.d.ts` from [esm.sh](https://esm.sh) CDN for type checking.
14
15
  - Using [import maps](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) for resolving **bare specifier** imports in JavaScript/TypeScript.
@@ -17,25 +18,9 @@ Meeting the modern version of [Monaco Editor](https://www.npmjs.com/package/mona
17
18
  - Inline `html` and `css` in JavaScript/TypeScript.
18
19
  - Auto-closing HTML/JSX tags.
19
20
 
20
- Planned features:
21
-
22
- - [ ] Built-in sidebar
23
- - [ ] file explorer
24
- - [ ] chat
25
- - [ ] Workspace persist API
26
- - [ ] Show a loading indicator while loading the editor
27
- - [ ] Quick open menu (only if a workspace is provided)
28
- - [ ] Drag and drop file (only if a workspace is provided)
29
- - [ ] Display non-code files, like images, videos, etc
30
- - [ ] VSCode `window.show<XXX>Message` APIs
31
- - [ ] Emmet
32
- - [ ] Markdown language service
33
- - [ ] [Volar](https://github.com/volarjs/volar.js) integration
34
- - [ ] Support [Shiki JS RegExp Engine](https://shiki.style/guide/regex-engines#javascript-regexp-engine-experimental)
35
-
36
21
  ## Installation
37
22
 
38
- You can install the package from NPM in your node project with a bundler like [vite](http://vitejs.dev).
23
+ You can install `modern-monaco` from NPM:
39
24
 
40
25
  ```bash
41
26
  npm i modern-monaco typescript
@@ -44,7 +29,7 @@ npm i modern-monaco typescript
44
29
  > [!Note]
45
30
  > The `typescript` package is required by JavaScript/TypeScript LSP worker. We recommend `typescript@5.5.x` or later.
46
31
 
47
- or import it from [esm.sh](https://esm.sh/) in browser without build step:
32
+ or import it from [esm.sh](https://esm.sh/) CDN in browser without build step:
48
33
 
49
34
  ```js
50
35
  import * from "https://esm.sh/modern-monaco"
@@ -237,7 +222,7 @@ lazy({
237
222
 
238
223
  > [!Note]
239
224
  > By default, `modern-monaco` uses `react` or `preact` in the `importmap` script as the `jsxImportSource` option for typescript worker.
240
- > To use a custom `jsxImportSource` option, add `@jsxRuntime` specifier in the `importmap` script. For example, [solid-js](https://esm.sh/solid-js/jsx-runtime).
225
+ > To use a custom `jsxImportSource` option, add `@jsxRuntime` specifier in the `importmap` script.
241
226
 
242
227
  ## Editor Theme & Language Grammars
243
228
 
@@ -345,17 +330,17 @@ For manual mode, check [here](https://microsoft.github.io/monaco-editor/docs.htm
345
330
 
346
331
  `modern-monaco` by default supports full LSP features for the following languages:
347
332
 
348
- - **HTML**
349
- - **CSS/SCSS/LESS**
350
- - **JavaScript/TypeScript**
351
- - **JSON**
333
+ - HTML
334
+ - CSS/SCSS/LESS
335
+ - JavaScript/TypeScript
336
+ - JSON
352
337
 
353
338
  Plus, `modern-monaco` also supports features like:
354
339
 
355
- - **File System Provider for import completions**
356
- - **Embedded languages in HTML**
357
- - **Inline `html` and `css` in JavaScript/TypeScript.**
358
- - **Auto-closing HTML/JSX tags**
340
+ - File System Provider for import completions
341
+ - Embedded languages in HTML
342
+ - Inline `html` and `css` in JavaScript/TypeScript.
343
+ - Auto-closing HTML/JSX tags
359
344
 
360
345
  > [!Note]
361
346
  > You don't need to set the `MonacoEnvironment.getWorker` for LSP support.
@@ -401,11 +386,7 @@ export interface LSPLanguageConfig {
401
386
  }
402
387
  ```
403
388
 
404
- ### Custom LSP
405
-
406
- [TODO]
407
-
408
- ### Using `core` module
389
+ ## Using `core` module
409
390
 
410
391
  `modern-monaco` includes built-in grammars and LSP providers for HTML, CSS, JavaScript/TypeScript, and JSON. If you don't need these features, you can use the `modern-monaco/core` sub-module to reduce the bundle size.
411
392
 
@@ -414,3 +395,7 @@ import { lazy } from "modern-monaco/core";
414
395
 
415
396
  lazy();
416
397
  ```
398
+
399
+ ## License
400
+
401
+ [MIT License](https://opensource.org/licenses/MIT)
package/dist/core.js CHANGED
@@ -22,7 +22,10 @@ var dec = /* @__PURE__ */ new TextDecoder();
22
22
  function decode(data) {
23
23
  return data instanceof Uint8Array ? dec.decode(data) : data;
24
24
  }
25
- function debunce(fn, delay = 500) {
25
+ function isDigital(v) {
26
+ return typeof v === "number" || typeof v === "string" && /^\d+$/.test(v);
27
+ }
28
+ function debunce(fn, delay) {
26
29
  let timer = null;
27
30
  return () => {
28
31
  if (timer !== null) {
@@ -34,6 +37,15 @@ function debunce(fn, delay = 500) {
34
37
  }, delay);
35
38
  };
36
39
  }
40
+ function promiseWithResolvers() {
41
+ let resolve;
42
+ let reject;
43
+ const promise = new Promise((res, rej) => {
44
+ resolve = res;
45
+ reject = rej;
46
+ });
47
+ return { promise, resolve, reject };
48
+ }
37
49
 
38
50
  // src/core.ts
39
51
  import { init as initLS } from "./lsp/language-service.js";
@@ -80,20 +92,20 @@ async function init(options) {
80
92
  }
81
93
  async function lazy(options, hydrate2) {
82
94
  const workspace = options?.workspace;
95
+ const { promise: editorWorkerPromise, resolve: onDidEditorWorkerResolve } = promiseWithResolvers();
83
96
  let monacoCore = null;
84
- let onDidEditorWorkerReady;
85
- let editorWorkerPromise = new Promise((resolve) => {
86
- onDidEditorWorkerReady = resolve;
87
- });
88
97
  function load(highlighter) {
89
98
  if (monacoCore) {
90
99
  return monacoCore;
91
100
  }
92
- return monacoCore = loadMonaco(highlighter, workspace, options?.lsp, onDidEditorWorkerReady).then((m) => monacoCore = m);
101
+ return monacoCore = loadMonaco(highlighter, workspace, options?.lsp, onDidEditorWorkerResolve).then((m) => monacoCore = m);
93
102
  }
94
103
  function setStyle(el, style) {
95
104
  Object.assign(el.style, style);
96
105
  }
106
+ function getAttr(el, name) {
107
+ return el.getAttribute(name);
108
+ }
97
109
  customElements.define(
98
110
  "monaco-editor",
99
111
  class extends HTMLElement {
@@ -102,7 +114,7 @@ async function lazy(options, hydrate2) {
102
114
  for (const attrName of this.getAttributeNames()) {
103
115
  const key = editorProps.find((k) => k.toLowerCase() === attrName);
104
116
  if (key) {
105
- let value = this.getAttribute(attrName);
117
+ let value = getAttr(this, attrName);
106
118
  if (value === "") {
107
119
  value = key === "minimap" || key === "stickyScroll" ? { enabled: true } : true;
108
120
  } else {
@@ -169,18 +181,26 @@ async function lazy(options, hydrate2) {
169
181
  }
170
182
  }
171
183
  setStyle(this, { display: "block", position: "relative" });
172
- const width = Number(this.getAttribute("width"));
173
- const height = Number(this.getAttribute("height"));
174
- if (width > 0 && height > 0) {
175
- setStyle(this, { width: `${width}px`, height: `${height}px` });
184
+ let widthAttr = getAttr(this, "width");
185
+ let heightAttr = getAttr(this, "height");
186
+ if (isDigital(widthAttr) && isDigital(heightAttr)) {
187
+ const width = Number(widthAttr);
188
+ const height = Number(heightAttr);
189
+ setStyle(this, { width: width + "px", height: height + "px" });
176
190
  renderOptions.dimension = { width, height };
177
191
  } else {
178
- setStyle(this, { width: "100%", height: "100%" });
192
+ if (isDigital(widthAttr)) {
193
+ widthAttr += "px";
194
+ }
195
+ if (isDigital(heightAttr)) {
196
+ heightAttr += "px";
197
+ }
198
+ this.style.width ||= widthAttr ?? "100%";
199
+ this.style.height ||= heightAttr ?? "100%";
179
200
  }
180
201
  const containerEl = document.createElement("div");
181
202
  containerEl.className = "monaco-editor-container";
182
- containerEl.style.width = "100%";
183
- containerEl.style.height = "100%";
203
+ setStyle(containerEl, { width: "100%", height: "100%" });
184
204
  this.appendChild(containerEl);
185
205
  if (!filename && workspace) {
186
206
  if (workspace.history.state.current) {
@@ -240,7 +260,7 @@ async function lazy(options, hydrate2) {
240
260
  }
241
261
  }
242
262
  }
243
- async function createMonaco() {
263
+ async function createEditor() {
244
264
  const monaco = await load(highlighter);
245
265
  const editor = monaco.editor.create(containerEl, renderOptions);
246
266
  if (workspace) {
@@ -254,8 +274,8 @@ async function lazy(options, hydrate2) {
254
274
  }
255
275
  }
256
276
  };
257
- editor.onDidChangeCursorSelection(debunce(storeViewState));
258
- editor.onDidScrollChange(debunce(storeViewState));
277
+ editor.onDidChangeCursorSelection(debunce(storeViewState, 500));
278
+ editor.onDidScrollChange(debunce(storeViewState, 500));
259
279
  workspace.history.onChange((state) => {
260
280
  if (editor.getModel()?.uri.toString() !== state.current) {
261
281
  workspace._openTextDocument(state.current, editor);
@@ -299,7 +319,7 @@ async function lazy(options, hydrate2) {
299
319
  });
300
320
  }
301
321
  }
302
- await createMonaco();
322
+ await createEditor();
303
323
  }
304
324
  }
305
325
  );
@@ -311,7 +331,7 @@ async function lazy(options, hydrate2) {
311
331
  function hydrate(options) {
312
332
  return lazy(options, true);
313
333
  }
314
- async function loadMonaco(highlighter, workspace, lsp, onDidEditorWorkerReady) {
334
+ async function loadMonaco(highlighter, workspace, lsp, onDidEditorWorkerResolve) {
315
335
  const monaco = await import("./editor-core.js");
316
336
  const lspProviders = { ...builtinLSPProviders, ...lsp?.providers };
317
337
  workspace?.setupMonaco(monaco);
@@ -341,7 +361,7 @@ async function loadMonaco(highlighter, workspace, lsp, onDidEditorWorkerReady) {
341
361
  const worker = createWebWorker(url, void 0);
342
362
  if (!provider) {
343
363
  const onMessage = (e) => {
344
- onDidEditorWorkerReady?.();
364
+ onDidEditorWorkerResolve?.();
345
365
  worker.removeEventListener("message", onMessage);
346
366
  };
347
367
  worker.addEventListener("message", onMessage);
package/dist/util.js CHANGED
@@ -27,7 +27,10 @@ function filenameToURL(filename) {
27
27
  function isPlainObject(v) {
28
28
  return typeof v === "object" && v !== null && v.constructor === Object;
29
29
  }
30
- function debunce(fn, delay = 500) {
30
+ function isDigital(v) {
31
+ return typeof v === "number" || typeof v === "string" && /^\d+$/.test(v);
32
+ }
33
+ function debunce(fn, delay) {
31
34
  let timer = null;
32
35
  return () => {
33
36
  if (timer !== null) {
@@ -182,6 +185,7 @@ export {
182
185
  defineProperty,
183
186
  encode,
184
187
  filenameToURL,
188
+ isDigital,
185
189
  isPlainObject,
186
190
  openIDB,
187
191
  openIDBCursor,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modern-monaco",
3
3
  "description": "A modern version of Monaco Editor",
4
- "version": "0.0.0-beta.1",
4
+ "version": "0.0.0-beta.3",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -37,8 +37,8 @@
37
37
  "./shiki": {
38
38
  "import": "./dist/shiki.js"
39
39
  },
40
- "./utils": {
41
- "import": "./dist/utils.js"
40
+ "./util": {
41
+ "import": "./dist/util.js"
42
42
  },
43
43
  "./lsp/*": {
44
44
  "import": "./dist/lsp/*.js"