modern-monaco 0.3.6 → 0.3.8

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) 2025 Je Xia <i@jex.me>
3
+ Copyright (c) 2026 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
@@ -68,10 +68,10 @@ const workspace = new Workspace({
68
68
  });
69
69
 
70
70
  // initialize the editor lazily
71
- await lazy({ workspace });
71
+ lazy({ workspace });
72
72
 
73
73
  // write a file and open it in the editor
74
- workspace.fs.writeFile("util.js", "export function add(a, b) { return a + b; }");
74
+ await workspace.fs.writeFile("util.js", "export function add(a, b) { return a + b; }");
75
75
  workspace.openTextDocument("util.js");
76
76
  ```
77
77
 
@@ -193,24 +193,64 @@ To set the editor theme, you can add a `theme` attribute to the `<monaco-editor>
193
193
  <monaco-editor theme="vitesse-dark"></monaco-editor>
194
194
  ```
195
195
 
196
- Or set it in the `lazy`, `init`, or `hydrate` function.
196
+ Or add a `defaultTheme` option to the `lazy`, `init`, or `hydrate` function.
197
197
 
198
198
  ```js
199
199
  lazy({
200
- theme: "vitesse-dark",
200
+ defaultTheme: "one-dark-pro",
201
201
  });
202
202
  ```
203
203
 
204
204
  > [!Note]
205
205
  > The theme ID should be one of the [Shiki Themes](https://shiki.style/themes).
206
206
 
207
- modern-monaco loads the theme data from the CDN when a theme ID is provided. You can also use a theme from the `tm-themes` package:
207
+ You can also load multiple themes by passing an array of theme inputs to the `themes` option.
208
+
209
+ ```js
210
+ const monaco = await init({
211
+ themes: [
212
+ "one-light",
213
+ "one-dark-pro",
214
+ ],
215
+ });
216
+
217
+ monaco.editor.create(document.getElementById("editor"), {
218
+ theme: "one-light",
219
+ })
220
+ // update the editor theme
221
+ monaco.editor.setTheme("one-dark-pro");
222
+ ```
223
+
224
+ modern-monaco loads the theme data from the CDN when a theme ID is provided. You can also load a theme from a JSON file:
208
225
 
209
226
  ```js
210
- import OneDark from "tm-themes/themes/vitesse-dark.json" with { type: "json" };
227
+ import OneDarkPro from "tm-themes/themes/one-dark-pro.json" with { type: "json" };
211
228
 
212
229
  lazy({
213
- theme: OneDark,
230
+ themes: [
231
+ // load language grammars from CDN, these language ids must be defined in the `tm-grammars` package
232
+ "one-light",
233
+
234
+ // import theme from `tm-themes` package without extra HTTP requests, but increases the bundle size
235
+ OneDarkPro,
236
+
237
+ // load theme from a URL
238
+ "https://example.com/themes/mytheme.json",
239
+
240
+ // load theme from an asset file
241
+ "/assets/mytheme.json",
242
+
243
+ // dynamically import
244
+ () => import("tm-themes/one-light.json", { with: { type: "json" } }),
245
+
246
+ // hand-crafted theme
247
+ {
248
+ name: "mytheme",
249
+ base: "vs-dark",
250
+ colors: {/* ... */},
251
+ tokenColors: [/* ... */],
252
+ },
253
+ ],
214
254
  });
215
255
  ```
216
256
 
@@ -229,15 +269,15 @@ lazy({
229
269
  "javascript",
230
270
  "json",
231
271
 
272
+ // import language grammar from `tm-grammars` package without extra HTTP requests, but increases the bundle size
273
+ markdown,
274
+
232
275
  // load language grammar from a URL
233
276
  "https://example.com/grammars/mylang.json",
234
277
 
235
- // load language grammar from a local file
278
+ // load language grammar from an asset file
236
279
  "/assets/mylang.json",
237
280
 
238
- // use `tm-grammars` package without extra HTTP requests, but increases the bundle size
239
- markdown,
240
-
241
281
  // dynamically import
242
282
  () => import("tm-grammars/markdown.json", { with: { type: "json" } }),
243
283
 
@@ -339,7 +379,7 @@ export interface LSPConfig {
339
379
  trimFinalNewlines?: boolean;
340
380
  /** Semicolon preference for JavaScript and TypeScript. Default: "insert". */
341
381
  semicolon?: "ignore" | "insert" | "remove";
342
- }
382
+ };
343
383
  /** HTML language configuration. */
344
384
  html?: {
345
385
  attributeDefaultValue?: "empty" | "singlequotes" | "doublequotes";
@@ -356,20 +396,20 @@ export interface LSPConfig {
356
396
  };
357
397
  /** JSON language configuration. */
358
398
  json?: {
359
- /** By default, the validator will return syntax and semantic errors. Set to false to disable the validator. */
360
- validate?: boolean;
361
- /** Defines whether comments are allowed or not. Default is disallowed. */
362
- allowComments?: boolean;
363
- /** A list of known schemas and/or associations of schemas to file names. */
364
- schemas?: JSONSchemaSource[];
365
- /** The severity of reported comments. Default is "error". */
366
- comments?: SeverityLevel;
367
- /** The severity of reported trailing commas. Default is "error". */
368
- trailingCommas?: SeverityLevel;
369
- /** The severity of problems from schema validation. Default is "warning". */
370
- schemaValidation?: SeverityLevel;
371
- /** The severity of problems that occurred when resolving and loading schemas. Default is "warning". */
372
- schemaRequest?: SeverityLevel;
399
+ /** By default, the validator will return syntax and semantic errors. Set to false to disable the validator. */
400
+ validate?: boolean;
401
+ /** Defines whether comments are allowed or not. Default is disallowed. */
402
+ allowComments?: boolean;
403
+ /** A list of known schemas and/or associations of schemas to file names. */
404
+ schemas?: JSONSchemaSource[];
405
+ /** The severity of reported comments. Default is "error". */
406
+ comments?: SeverityLevel;
407
+ /** The severity of reported trailing commas. Default is "error". */
408
+ trailingCommas?: SeverityLevel;
409
+ /** The severity of problems from schema validation. Default is "warning". */
410
+ schemaValidation?: SeverityLevel;
411
+ /** The severity of problems that occurred when resolving and loading schemas. Default is "warning". */
412
+ schemaRequest?: SeverityLevel;
373
413
  };
374
414
  /** TypeScript language configuration. */
375
415
  typescript?: {
@@ -475,6 +515,23 @@ import { lazy } from "modern-monaco/core";
475
515
  lazy();
476
516
  ```
477
517
 
518
+ ## Loading editor modules from a custom CDN
519
+
520
+ By default, modern-monaco loads editor modules from `https://esm.sh`. You can customize the CDN URL by providing an import map in your HTML.
521
+
522
+ ```html
523
+ <script type="importmap">
524
+ {
525
+ "imports": {
526
+ "modern-monaco": "https://mycdn.com/modern-monaco@:version/dist/index.mjs",
527
+ "modern-monaco/editor-core": "https://mycdn.com/modern-monaco@:version/dist/editor-core.mjs",
528
+ "modern-monaco/lsp": "https://mycdn.com/modern-monaco@:version/dist/lsp/index.mjs",
529
+ "typescript": "https://mycdn.com/typescript@:version/lib/typescript.js"
530
+ }
531
+ }
532
+ </script>
533
+ ```
534
+
478
535
  ## License
479
536
 
480
537
  [MIT License](https://opensource.org/licenses/MIT)
package/dist/core.mjs CHANGED
@@ -40,7 +40,7 @@ function isObject(v) {
40
40
  }
41
41
 
42
42
  // package.json
43
- var version = "0.3.6";
43
+ var version = "0.3.8";
44
44
 
45
45
  // src/core.ts
46
46
  import { getExtnameFromLanguageId, getLanguageIdFromPath, grammars, initShiki, setDefaultWasmLoader, themes } from "./shiki.mjs";
@@ -2310,7 +2310,7 @@ var init_event = __esm({
2310
2310
  return fn;
2311
2311
  }
2312
2312
  Event2.chain = chain;
2313
- const HaltChainable = Symbol("HaltChainable");
2313
+ const HaltChainable = /* @__PURE__ */ Symbol("HaltChainable");
2314
2314
  class ChainableSynthesis {
2315
2315
  constructor() {
2316
2316
  this.steps = [];
@@ -3103,7 +3103,7 @@ var init_cancellation = __esm({
3103
3103
  var MicrotaskDelay;
3104
3104
  var init_symbols = __esm({
3105
3105
  "node_modules/monaco-editor-core/esm/vs/base/common/symbols.js"() {
3106
- MicrotaskDelay = Symbol("MicrotaskDelay");
3106
+ MicrotaskDelay = /* @__PURE__ */ Symbol("MicrotaskDelay");
3107
3107
  }
3108
3108
  });
3109
3109
 
@@ -3242,7 +3242,7 @@ function createCancelableAsyncIterableProducer(callback) {
3242
3242
  }
3243
3243
  });
3244
3244
  }
3245
- var Throttler, timeoutDeferred, microtaskDeferred, Delayer, ThrottledDelayer, TaskQueue, TimeoutTimer, IntervalTimer, RunOnceScheduler, runWhenGlobalIdle, _runWhenIdle, AbstractIdleValue, GlobalIdleValue, DeferredPromise, Promises, ProducerConsumer, AsyncIterableProducer, CancelableAsyncIterableProducer, AsyncReaderEndOfStream;
3245
+ var Throttler, timeoutDeferred, microtaskDeferred, Delayer, ThrottledDelayer, TaskQueue, TimeoutTimer, IntervalTimer, RunOnceScheduler, runWhenGlobalIdle, _runWhenIdle, AbstractIdleValue, GlobalIdleValue, DeferredPromise, Promises, ProducerConsumer, AsyncIterableProducer, CancelableAsyncIterableProducer;
3246
3246
  var init_async = __esm({
3247
3247
  "node_modules/monaco-editor-core/esm/vs/base/common/async.js"() {
3248
3248
  init_cancellation();
@@ -3878,7 +3878,6 @@ var init_async = __esm({
3878
3878
  this._source.cancel();
3879
3879
  }
3880
3880
  };
3881
- AsyncReaderEndOfStream = Symbol("AsyncReaderEndOfStream");
3882
3881
  }
3883
3882
  });
3884
3883
 
@@ -28242,7 +28241,7 @@ var init_textModelEditSource = __esm({
28242
28241
  "node_modules/monaco-editor-core/esm/vs/editor/common/textModelEditSource.js"() {
28243
28242
  init_uuid();
28244
28243
  init_textLength();
28245
- privateSymbol = Symbol("TextModelEditSource");
28244
+ privateSymbol = /* @__PURE__ */ Symbol("TextModelEditSource");
28246
28245
  TextModelEditSource = class {
28247
28246
  constructor(metadata, _privateCtorGuard) {
28248
28247
  this.metadata = metadata;
@@ -84709,7 +84708,6 @@ init_observable();
84709
84708
  init_nls();
84710
84709
  init_instantiation();
84711
84710
  var IAccessibilitySignalService = createDecorator("accessibilitySignalService");
84712
- var AcknowledgeDocCommentsToken = Symbol("AcknowledgeDocCommentsToken");
84713
84711
  var Sound = class _Sound {
84714
84712
  static register(options2) {
84715
84713
  const sound = new _Sound(options2.fileName);
@@ -104293,18 +104291,10 @@ registerEditorAction(TransposeLettersAction);
104293
104291
  init_browser();
104294
104292
  init_dom();
104295
104293
  init_platform();
104296
- init_stopwatch();
104297
104294
  init_nls();
104298
104295
  init_actions2();
104299
104296
  init_contextkey();
104300
104297
  init_log();
104301
-
104302
- // node_modules/monaco-editor-core/esm/vs/platform/product/common/productService.js
104303
- init_instantiation();
104304
- var IProductService = createDecorator("productService");
104305
-
104306
- // node_modules/monaco-editor-core/esm/vs/editor/contrib/clipboard/browser/clipboard.js
104307
- init_telemetry();
104308
104298
  init_editorExtensions();
104309
104299
  init_codeEditorService();
104310
104300
  init_editorContextKeys();
@@ -105355,7 +105345,7 @@ var UriIterator = class {
105355
105345
  };
105356
105346
  var Undef = class _Undef {
105357
105347
  static {
105358
- this.Val = Symbol("undefined_placeholder");
105348
+ this.Val = /* @__PURE__ */ Symbol("undefined_placeholder");
105359
105349
  }
105360
105350
  static wrap(value) {
105361
105351
  return value === void 0 ? _Undef.Val : value;
@@ -108947,8 +108937,6 @@ if (PasteAction) {
108947
108937
  logService.trace("registerExecCommandImpl (addImplementation code-editor for : paste)");
108948
108938
  const codeEditorService = accessor.get(ICodeEditorService);
108949
108939
  const clipboardService = accessor.get(IClipboardService);
108950
- const telemetryService = accessor.get(ITelemetryService);
108951
- const productService = accessor.get(IProductService);
108952
108940
  const focusedEditor = codeEditorService.getFocusedCodeEditor();
108953
108941
  if (focusedEditor && focusedEditor.hasModel() && focusedEditor.hasTextFocus()) {
108954
108942
  const editContextEnabled = focusedEditor.getOption(
@@ -108961,17 +108949,12 @@ if (PasteAction) {
108961
108949
  nativeEditContext.onWillPaste();
108962
108950
  }
108963
108951
  }
108964
- const sw = StopWatch.create(true);
108965
108952
  logService.trace("registerExecCommandImpl (before triggerPaste)");
108966
108953
  const triggerPaste = clipboardService.triggerPaste(getActiveWindow().vscodeWindowId);
108967
108954
  if (triggerPaste) {
108968
108955
  logService.trace("registerExecCommandImpl (triggerPaste defined)");
108969
108956
  return triggerPaste.then(async () => {
108970
108957
  logService.trace("registerExecCommandImpl (after triggerPaste)");
108971
- if (productService.quality !== "stable") {
108972
- const duration = sw.elapsed();
108973
- telemetryService.publicLog2("editorAsyncPaste", { duration });
108974
- }
108975
108958
  return CopyPasteController.get(focusedEditor)?.finishedPaste() ?? Promise.resolve();
108976
108959
  });
108977
108960
  } else {
@@ -144865,7 +144848,7 @@ DataChannelForwardingTelemetryService = __decorate103([
144865
144848
  __param97(0, ITelemetryService),
144866
144849
  __param97(1, IDataChannelService)
144867
144850
  ], DataChannelForwardingTelemetryService);
144868
- var shouldForwardToChannel = Symbol("shouldForwardToChannel");
144851
+ var shouldForwardToChannel = /* @__PURE__ */ Symbol("shouldForwardToChannel");
144869
144852
  function forwardToChannelIf(value) {
144870
144853
  return {
144871
144854
  // This will not be sent via telemetry, it is just a marker
@@ -892,7 +892,7 @@ var Event;
892
892
  return fn;
893
893
  }
894
894
  Event2.chain = chain;
895
- const HaltChainable = Symbol("HaltChainable");
895
+ const HaltChainable = /* @__PURE__ */ Symbol("HaltChainable");
896
896
  class ChainableSynthesis {
897
897
  constructor() {
898
898
  this.steps = [];
@@ -13442,9 +13442,6 @@ function getHeaderText(text) {
13442
13442
  return { text, hasSeparatorLine };
13443
13443
  }
13444
13444
 
13445
- // node_modules/monaco-editor-core/esm/vs/base/common/symbols.js
13446
- var MicrotaskDelay = Symbol("MicrotaskDelay");
13447
-
13448
13445
  // node_modules/monaco-editor-core/esm/vs/base/common/async.js
13449
13446
  var runWhenGlobalIdle;
13450
13447
  var _runWhenIdle;
@@ -13712,7 +13709,6 @@ var AsyncIterableProducer = class _AsyncIterableProducer {
13712
13709
  return this._iterator;
13713
13710
  }
13714
13711
  };
13715
- var AsyncReaderEndOfStream = Symbol("AsyncReaderEndOfStream");
13716
13712
 
13717
13713
  // node_modules/monaco-editor-core/esm/vs/editor/common/model/prefixSumComputer.js
13718
13714
  var PrefixSumComputer = class {
@@ -4634,7 +4634,7 @@ var PathCompletionParticipant = class {
4634
4634
  result.isIncomplete = true;
4635
4635
  } else {
4636
4636
  const replaceRange = pathToReplaceRange(attributeCompletion.value, fullValue, attributeCompletion.range);
4637
- const suggestions = await this.providePathSuggestions(attributeCompletion.value, replaceRange, document, documentContext);
4637
+ const suggestions = await this.providePathSuggestions(attributeCompletion.value, replaceRange, document, documentContext, attributeCompletion);
4638
4638
  for (const item of suggestions) {
4639
4639
  result.items.push(item);
4640
4640
  }
@@ -4643,16 +4643,33 @@ var PathCompletionParticipant = class {
4643
4643
  }
4644
4644
  return result;
4645
4645
  }
4646
- async providePathSuggestions(valueBeforeCursor, replaceRange, document, documentContext) {
4646
+ async providePathSuggestions(valueBeforeCursor, replaceRange, document, documentContext, context) {
4647
4647
  const valueBeforeLastSlash = valueBeforeCursor.substring(0, valueBeforeCursor.lastIndexOf("/") + 1);
4648
4648
  let parentDir = documentContext.resolveReference(valueBeforeLastSlash || ".", document.uri);
4649
4649
  if (parentDir) {
4650
4650
  try {
4651
4651
  const result = [];
4652
4652
  const infos = await this.readDirectory(parentDir);
4653
+ const extensionFilter = this.getExtensionFilter(context);
4653
4654
  for (const [name, type] of infos) {
4654
4655
  if (name.charCodeAt(0) !== CharCode_dot) {
4655
- result.push(createCompletionItem(name, type === FileType.Directory, replaceRange));
4656
+ const item = createCompletionItem(name, type === FileType.Directory, replaceRange);
4657
+ if (extensionFilter) {
4658
+ if (type === FileType.Directory) {
4659
+ result.push(item);
4660
+ } else {
4661
+ const matchesFilter = extensionFilter.extensions.some((ext) => name.toLowerCase().endsWith(ext));
4662
+ if (matchesFilter) {
4663
+ item.sortText = "0_" + name;
4664
+ result.push(item);
4665
+ } else if (!extensionFilter.exclusive) {
4666
+ item.sortText = "1_" + name;
4667
+ result.push(item);
4668
+ }
4669
+ }
4670
+ } else {
4671
+ result.push(item);
4672
+ }
4656
4673
  }
4657
4674
  }
4658
4675
  return result;
@@ -4661,6 +4678,36 @@ var PathCompletionParticipant = class {
4661
4678
  }
4662
4679
  return [];
4663
4680
  }
4681
+ /**
4682
+ * Determines which file extensions to filter/prioritize based on the HTML tag and attributes
4683
+ */
4684
+ getExtensionFilter(context) {
4685
+ if (!context) {
4686
+ return void 0;
4687
+ }
4688
+ if (context.tag === "link" && context.attribute === "href" && context.attributes) {
4689
+ const rel = context.attributes["rel"];
4690
+ if (rel === "stylesheet" || rel === '"stylesheet"' || rel === "'stylesheet'") {
4691
+ return { extensions: [".css", ".scss", ".sass", ".less"], exclusive: false };
4692
+ }
4693
+ if (rel === "icon" || rel === '"icon"' || rel === "'icon'" || rel === "apple-touch-icon" || rel === '"apple-touch-icon"' || rel === "'apple-touch-icon'") {
4694
+ return { extensions: [".ico", ".png", ".svg", ".jpg", ".jpeg", ".gif", ".webp"], exclusive: false };
4695
+ }
4696
+ }
4697
+ if (context.tag === "script" && context.attribute === "src") {
4698
+ return { extensions: [".js", ".mjs", ".cjs", ".ts", ".tsx", ".jsx"], exclusive: false };
4699
+ }
4700
+ if (context.tag === "img" && context.attribute === "src") {
4701
+ return { extensions: [".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".bmp", ".ico"], exclusive: false };
4702
+ }
4703
+ if (context.tag === "video" && context.attribute === "src") {
4704
+ return { extensions: [".mp4", ".webm", ".ogg", ".mov", ".avi"], exclusive: false };
4705
+ }
4706
+ if (context.tag === "audio" && context.attribute === "src") {
4707
+ return { extensions: [".mp3", ".wav", ".ogg", ".m4a", ".aac", ".flac"], exclusive: false };
4708
+ }
4709
+ return void 0;
4710
+ }
4664
4711
  };
4665
4712
  var CharCode_dot = ".".charCodeAt(0);
4666
4713
  function stripQuotes(fullValue) {
@@ -4985,7 +5032,7 @@ var HTMLCompletion = class {
4985
5032
  const fullRange = getReplaceRange(valueStart, valueEnd);
4986
5033
  for (const participant of completionParticipants) {
4987
5034
  if (participant.onHtmlAttributeValue) {
4988
- participant.onHtmlAttributeValue({ document, position, tag, attribute, value: valuePrefix, range: fullRange });
5035
+ participant.onHtmlAttributeValue({ document, position, tag, attribute, value: valuePrefix, range: fullRange, attributes: node.attributes });
4989
5036
  }
4990
5037
  }
4991
5038
  }