draftly 0.1.0-alpha.1 → 1.0.7

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.
Files changed (68) hide show
  1. package/dist/chunk-2B3A3VSQ.cjs +3382 -0
  2. package/dist/chunk-2B3A3VSQ.cjs.map +1 -0
  3. package/dist/{chunk-ZDSZRRUY.cjs → chunk-72ZYRGRT.cjs} +48 -104
  4. package/dist/chunk-72ZYRGRT.cjs.map +1 -0
  5. package/dist/{chunk-MOG6E2LY.js → chunk-CG4M4TC7.js} +46 -103
  6. package/dist/chunk-CG4M4TC7.js.map +1 -0
  7. package/dist/{chunk-LCQALOEI.js → chunk-DFQYXFOP.js} +36 -3
  8. package/dist/chunk-DFQYXFOP.js.map +1 -0
  9. package/dist/{chunk-6LQ2VR4I.js → chunk-HPSMS2WB.js} +38 -22
  10. package/dist/chunk-HPSMS2WB.js.map +1 -0
  11. package/dist/{chunk-7Z3SRTPZ.cjs → chunk-KBQDZ5IW.cjs} +38 -22
  12. package/dist/chunk-KBQDZ5IW.cjs.map +1 -0
  13. package/dist/{chunk-RV2SYFA6.cjs → chunk-KDEDLC3D.cjs} +36 -2
  14. package/dist/chunk-KDEDLC3D.cjs.map +1 -0
  15. package/dist/chunk-N3WL3XPB.js +3360 -0
  16. package/dist/chunk-N3WL3XPB.js.map +1 -0
  17. package/dist/{draftly-Bxu_H4nw.d.ts → draftly-BLnx3uGX.d.cts} +12 -6
  18. package/dist/{draftly-Bxu_H4nw.d.cts → draftly-BLnx3uGX.d.ts} +12 -6
  19. package/dist/editor/index.cjs +20 -12
  20. package/dist/editor/index.d.cts +3 -2
  21. package/dist/editor/index.d.ts +3 -2
  22. package/dist/editor/index.js +2 -2
  23. package/dist/index.cjs +59 -27
  24. package/dist/index.d.cts +3 -3
  25. package/dist/index.d.ts +3 -3
  26. package/dist/index.js +4 -4
  27. package/dist/plugins/index.cjs +35 -11
  28. package/dist/plugins/index.d.cts +321 -3
  29. package/dist/plugins/index.d.ts +321 -3
  30. package/dist/plugins/index.js +3 -3
  31. package/dist/preview/index.cjs +7 -7
  32. package/dist/preview/index.d.cts +9 -4
  33. package/dist/preview/index.d.ts +9 -4
  34. package/dist/preview/index.js +2 -2
  35. package/package.json +2 -1
  36. package/src/editor/draftly.ts +9 -13
  37. package/src/editor/plugin.ts +4 -1
  38. package/src/editor/theme.ts +34 -1
  39. package/src/editor/utils.ts +49 -0
  40. package/src/editor/view-plugin.ts +6 -131
  41. package/src/plugins/code-plugin.ts +1119 -0
  42. package/src/plugins/heading-plugin.ts +23 -11
  43. package/src/plugins/hr-plugin.ts +102 -0
  44. package/src/plugins/image-plugin.ts +96 -2
  45. package/src/plugins/index.ts +57 -39
  46. package/src/plugins/inline-plugin.ts +125 -6
  47. package/src/plugins/link-plugin.ts +509 -0
  48. package/src/plugins/list-plugin.ts +116 -2
  49. package/src/plugins/math-plugin.ts +5 -1
  50. package/src/plugins/mermaid-plugin.ts +500 -0
  51. package/src/plugins/paragraph-plugin.ts +38 -0
  52. package/src/plugins/quote-plugin.ts +146 -0
  53. package/src/preview/context.ts +1 -1
  54. package/src/preview/css-generator.ts +3 -1
  55. package/src/preview/default-renderers.ts +0 -5
  56. package/src/preview/preview.ts +2 -2
  57. package/src/preview/renderer.ts +34 -12
  58. package/src/preview/types.ts +1 -1
  59. package/dist/chunk-6LQ2VR4I.js.map +0 -1
  60. package/dist/chunk-7Z3SRTPZ.cjs.map +0 -1
  61. package/dist/chunk-GA6NYY77.cjs +0 -1400
  62. package/dist/chunk-GA6NYY77.cjs.map +0 -1
  63. package/dist/chunk-LCQALOEI.js.map +0 -1
  64. package/dist/chunk-MOG6E2LY.js.map +0 -1
  65. package/dist/chunk-RV2SYFA6.cjs.map +0 -1
  66. package/dist/chunk-TKZNKWGF.js +0 -1385
  67. package/dist/chunk-TKZNKWGF.js.map +0 -1
  68. package/dist/chunk-ZDSZRRUY.cjs.map +0 -1
@@ -0,0 +1,3382 @@
1
+ 'use strict';
2
+
3
+ var chunk72ZYRGRT_cjs = require('./chunk-72ZYRGRT.cjs');
4
+ var chunkKDEDLC3D_cjs = require('./chunk-KDEDLC3D.cjs');
5
+ var view = require('@codemirror/view');
6
+ var language = require('@codemirror/language');
7
+ var highlight = require('@lezer/highlight');
8
+ var DOMPurify = require('dompurify');
9
+ var katex = require('katex');
10
+ var katexCss = require('katex/dist/katex.min.css?raw');
11
+ var mermaid = require('mermaid');
12
+ var languageData = require('@codemirror/language-data');
13
+
14
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
+
16
+ var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
17
+ var katex__default = /*#__PURE__*/_interopDefault(katex);
18
+ var katexCss__default = /*#__PURE__*/_interopDefault(katexCss);
19
+ var mermaid__default = /*#__PURE__*/_interopDefault(mermaid);
20
+
21
+ // src/plugins/paragraph-plugin.ts
22
+ var ParagraphPlugin = class extends chunk72ZYRGRT_cjs.DraftlyPlugin {
23
+ name = "paragraph";
24
+ version = "1.0.0";
25
+ requiredNodes = ["Paragraph"];
26
+ /**
27
+ * Plugin theme for preview styling
28
+ */
29
+ get theme() {
30
+ return theme;
31
+ }
32
+ renderToHTML(node, children) {
33
+ if (node.name !== "Paragraph") {
34
+ return null;
35
+ }
36
+ return `<p class="cm-draftly-paragraph">${children}</p>`;
37
+ }
38
+ };
39
+ var theme = chunkKDEDLC3D_cjs.createTheme({
40
+ default: {
41
+ ".cm-draftly-paragraph": {
42
+ paddingTop: "0.5em",
43
+ paddingBottom: "0.5em"
44
+ }
45
+ }
46
+ });
47
+ var HEADING_TYPES = ["ATXHeading1", "ATXHeading2", "ATXHeading3", "ATXHeading4", "ATXHeading5", "ATXHeading6"];
48
+ var headingMarkDecorations = {
49
+ "heading-1": view.Decoration.mark({ class: "cm-draftly-h1" }),
50
+ "heading-2": view.Decoration.mark({ class: "cm-draftly-h2" }),
51
+ "heading-3": view.Decoration.mark({ class: "cm-draftly-h3" }),
52
+ "heading-4": view.Decoration.mark({ class: "cm-draftly-h4" }),
53
+ "heading-5": view.Decoration.mark({ class: "cm-draftly-h5" }),
54
+ "heading-6": view.Decoration.mark({ class: "cm-draftly-h6" }),
55
+ "header-mark-class": view.Decoration.mark({ class: "cm-draftly-header-mark" }),
56
+ "heading-mark": view.Decoration.replace({})
57
+ };
58
+ var headingLineDecorations = {
59
+ "heading-1": view.Decoration.line({ class: "cm-draftly-line-h1" }),
60
+ "heading-2": view.Decoration.line({ class: "cm-draftly-line-h2" }),
61
+ "heading-3": view.Decoration.line({ class: "cm-draftly-line-h3" }),
62
+ "heading-4": view.Decoration.line({ class: "cm-draftly-line-h4" }),
63
+ "heading-5": view.Decoration.line({ class: "cm-draftly-line-h5" }),
64
+ "heading-6": view.Decoration.line({ class: "cm-draftly-line-h6" })
65
+ };
66
+ var HeadingPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
67
+ name = "heading";
68
+ version = "1.0.0";
69
+ decorationPriority = 10;
70
+ requiredNodes = [
71
+ "ATXHeading1",
72
+ "ATXHeading2",
73
+ "ATXHeading3",
74
+ "ATXHeading4",
75
+ "ATXHeading5",
76
+ "ATXHeading6",
77
+ "HeaderMark"
78
+ ];
79
+ /**
80
+ * Constructor - calls super constructor
81
+ */
82
+ constructor() {
83
+ super();
84
+ }
85
+ /**
86
+ * Plugin theme
87
+ */
88
+ get theme() {
89
+ return theme2;
90
+ }
91
+ /**
92
+ * Build heading decorations by iterating the syntax tree
93
+ */
94
+ buildDecorations(ctx) {
95
+ const { view, decorations } = ctx;
96
+ const tree = language.syntaxTree(view.state);
97
+ tree.iterate({
98
+ enter: (node) => {
99
+ const { from, to, name } = node;
100
+ if (!HEADING_TYPES.includes(name)) {
101
+ return;
102
+ }
103
+ const level = parseInt(name.slice(-1), 10);
104
+ const headingClass = `heading-${level}`;
105
+ const lineClass = `heading-${level}`;
106
+ const line = view.state.doc.lineAt(from);
107
+ decorations.push(headingLineDecorations[lineClass].range(line.from));
108
+ decorations.push(headingMarkDecorations[headingClass].range(from, to));
109
+ const headingMark = node.node.getChild("HeaderMark");
110
+ if (headingMark) {
111
+ const markEnd = Math.min(headingMark.to + 1, line.to);
112
+ const cursorInNode = ctx.selectionOverlapsRange(from, to);
113
+ if (!cursorInNode) {
114
+ decorations.push(headingMarkDecorations["heading-mark"].range(headingMark.from, markEnd));
115
+ } else {
116
+ decorations.push(headingMarkDecorations["header-mark-class"].range(headingMark.from, markEnd));
117
+ }
118
+ }
119
+ }
120
+ });
121
+ }
122
+ renderToHTML(node, children) {
123
+ if (node.name === "HeaderMark") {
124
+ return "";
125
+ }
126
+ if (!HEADING_TYPES.includes(node.name)) {
127
+ return null;
128
+ }
129
+ const level = parseInt(node.name.slice(-1), 10);
130
+ const lineClass = headingLineDecorations[`heading-${level}`].spec.class;
131
+ const headingClass = headingMarkDecorations[`heading-${level}`].spec.class;
132
+ return `<div class="${lineClass}">
133
+ <h${level} class="${headingClass}">${children}</h${level}>
134
+ </div>
135
+ `;
136
+ }
137
+ };
138
+ var theme2 = chunkKDEDLC3D_cjs.createTheme({
139
+ default: {
140
+ ".cm-draftly-h1": {
141
+ fontSize: "2em",
142
+ fontWeight: "bold",
143
+ fontFamily: "sans-serif",
144
+ textDecoration: "none"
145
+ },
146
+ ".cm-draftly-h2": {
147
+ fontSize: "1.75em",
148
+ fontWeight: "bold",
149
+ fontFamily: "sans-serif",
150
+ textDecoration: "none"
151
+ },
152
+ ".cm-draftly-h3": {
153
+ fontSize: "1.5em",
154
+ fontWeight: "bold",
155
+ fontFamily: "sans-serif",
156
+ textDecoration: "none"
157
+ },
158
+ ".cm-draftly-h4": {
159
+ fontSize: "1.25em",
160
+ fontWeight: "bold",
161
+ fontFamily: "sans-serif",
162
+ textDecoration: "none"
163
+ },
164
+ ".cm-draftly-h5": {
165
+ fontSize: "1em",
166
+ fontWeight: "bold",
167
+ fontFamily: "sans-serif",
168
+ textDecoration: "none"
169
+ },
170
+ ".cm-draftly-h6": {
171
+ fontSize: "0.75em",
172
+ fontWeight: "bold",
173
+ fontFamily: "sans-serif",
174
+ textDecoration: "none"
175
+ },
176
+ // Heading line styles
177
+ ".cm-draftly-line-h1": {
178
+ paddingTop: "1.5em",
179
+ paddingBottom: "0.5em"
180
+ },
181
+ ".cm-draftly-line-h2": {
182
+ paddingTop: "1.25em",
183
+ paddingBottom: "0.5em"
184
+ },
185
+ ".cm-draftly-line-h3, .cm-draftly-line-h4, .cm-draftly-line-h5, .cm-draftly-line-h6": {
186
+ paddingTop: "1em",
187
+ paddingBottom: "0.5em"
188
+ },
189
+ ".cm-draftly-header-mark": {
190
+ opacity: 0.5
191
+ }
192
+ }
193
+ });
194
+ var INLINE_TYPES = {
195
+ Emphasis: "emphasis",
196
+ StrongEmphasis: "strong",
197
+ Strikethrough: "strikethrough",
198
+ Subscript: "subscript",
199
+ Superscript: "superscript",
200
+ Highlight: "highlight"
201
+ };
202
+ var inlineMarkDecorations = {
203
+ emphasis: view.Decoration.mark({ class: "cm-draftly-emphasis" }),
204
+ strong: view.Decoration.mark({ class: "cm-draftly-strong" }),
205
+ strikethrough: view.Decoration.mark({ class: "cm-draftly-strikethrough" }),
206
+ subscript: view.Decoration.mark({ class: "cm-draftly-subscript" }),
207
+ superscript: view.Decoration.mark({ class: "cm-draftly-superscript" }),
208
+ highlight: view.Decoration.mark({ class: "cm-draftly-highlight" }),
209
+ // Markers (* _ ~~ ^ ~ ==)
210
+ "inline-mark": view.Decoration.replace({})
211
+ };
212
+ var EQUALS = 61;
213
+ var Punctuation = /[!"#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~\xA1\u2010-\u2027]/;
214
+ try {
215
+ Punctuation = new RegExp("[\\p{S}|\\p{P}]", "u");
216
+ } catch {
217
+ }
218
+ var HighlightDelim = { resolve: "Highlight", mark: "HighlightMark" };
219
+ var highlightParser = {
220
+ name: "Highlight",
221
+ parse(cx, next, pos) {
222
+ if (next !== EQUALS || cx.char(pos + 1) !== EQUALS) return -1;
223
+ if (cx.char(pos + 2) === EQUALS) return -1;
224
+ const before = cx.slice(pos - 1, pos);
225
+ const after = cx.slice(pos + 2, pos + 3);
226
+ const sBefore = /\s|^$/.test(before), sAfter = /\s|^$/.test(after);
227
+ const pBefore = Punctuation.test(before), pAfter = Punctuation.test(after);
228
+ return cx.addDelimiter(
229
+ HighlightDelim,
230
+ pos,
231
+ pos + 2,
232
+ !sAfter && (!pAfter || sBefore || pBefore),
233
+ !sBefore && (!pBefore || sAfter || pAfter)
234
+ );
235
+ }
236
+ };
237
+ var InlinePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
238
+ name = "inline";
239
+ version = "1.0.0";
240
+ decorationPriority = 20;
241
+ requiredNodes = [
242
+ "Emphasis",
243
+ "StrongEmphasis",
244
+ "Strikethrough",
245
+ "Subscript",
246
+ "Superscript",
247
+ "Highlight",
248
+ "EmphasisMark",
249
+ "StrikethroughMark",
250
+ "SubscriptMark",
251
+ "SuperscriptMark",
252
+ "HighlightMark"
253
+ ];
254
+ marks = [];
255
+ constructor() {
256
+ super();
257
+ for (const mark of Object.keys(INLINE_TYPES)) {
258
+ this.marks.push(...this.getMarkerNames(mark));
259
+ }
260
+ }
261
+ /**
262
+ * Plugin theme
263
+ */
264
+ get theme() {
265
+ return theme3;
266
+ }
267
+ /**
268
+ * Keyboard shortcuts for inline formatting
269
+ */
270
+ getKeymap() {
271
+ return [
272
+ {
273
+ key: "Mod-b",
274
+ run: chunkKDEDLC3D_cjs.toggleMarkdownStyle("**"),
275
+ preventDefault: true
276
+ },
277
+ {
278
+ key: "Mod-i",
279
+ run: chunkKDEDLC3D_cjs.toggleMarkdownStyle("*"),
280
+ preventDefault: true
281
+ },
282
+ {
283
+ key: "Mod-Shift-s",
284
+ run: chunkKDEDLC3D_cjs.toggleMarkdownStyle("~~"),
285
+ preventDefault: true
286
+ },
287
+ {
288
+ key: "Mod-,",
289
+ run: chunkKDEDLC3D_cjs.toggleMarkdownStyle("~"),
290
+ preventDefault: true
291
+ },
292
+ {
293
+ key: "Mod-.",
294
+ run: chunkKDEDLC3D_cjs.toggleMarkdownStyle("^"),
295
+ preventDefault: true
296
+ },
297
+ {
298
+ key: "Mod-Shift-h",
299
+ run: chunkKDEDLC3D_cjs.toggleMarkdownStyle("=="),
300
+ preventDefault: true
301
+ }
302
+ ];
303
+ }
304
+ /**
305
+ * Return markdown parser extensions for highlight syntax (==text==)
306
+ */
307
+ getMarkdownConfig() {
308
+ return {
309
+ defineNodes: [
310
+ { name: "Highlight", style: highlight.tags.emphasis },
311
+ { name: "HighlightMark", style: highlight.tags.processingInstruction }
312
+ ],
313
+ parseInline: [highlightParser]
314
+ };
315
+ }
316
+ /**
317
+ * Build inline decorations by iterating the syntax tree
318
+ */
319
+ buildDecorations(ctx) {
320
+ const { view, decorations } = ctx;
321
+ const tree = language.syntaxTree(view.state);
322
+ tree.iterate({
323
+ enter: (node) => {
324
+ const { from, to, name } = node;
325
+ const inlineType = INLINE_TYPES[name];
326
+ if (!inlineType) {
327
+ return;
328
+ }
329
+ decorations.push(inlineMarkDecorations[inlineType].range(from, to));
330
+ const cursorInNode = ctx.selectionOverlapsRange(from, to);
331
+ if (!cursorInNode) {
332
+ const markerNames = this.getMarkerNames(name);
333
+ for (const markerName of markerNames) {
334
+ const marks = node.node.getChildren(markerName);
335
+ for (const mark of marks) {
336
+ decorations.push(inlineMarkDecorations["inline-mark"].range(mark.from, mark.to));
337
+ }
338
+ }
339
+ }
340
+ }
341
+ });
342
+ }
343
+ /**
344
+ * Get the marker node names for a given inline type
345
+ */
346
+ getMarkerNames(nodeType) {
347
+ switch (nodeType) {
348
+ case "Emphasis":
349
+ case "StrongEmphasis":
350
+ return ["EmphasisMark"];
351
+ case "Strikethrough":
352
+ return ["StrikethroughMark"];
353
+ case "Subscript":
354
+ return ["SubscriptMark"];
355
+ case "Superscript":
356
+ return ["SuperscriptMark"];
357
+ case "Highlight":
358
+ return ["HighlightMark"];
359
+ default:
360
+ return [];
361
+ }
362
+ }
363
+ renderToHTML(node, children) {
364
+ if (this.marks.includes(node.name)) {
365
+ return "";
366
+ }
367
+ const inlineType = INLINE_TYPES[node.name];
368
+ if (!inlineType) {
369
+ return null;
370
+ }
371
+ const className = inlineMarkDecorations[inlineType].spec.class;
372
+ return `<span class="${className}">${children}</span>`;
373
+ }
374
+ };
375
+ var theme3 = chunkKDEDLC3D_cjs.createTheme({
376
+ default: {
377
+ // Emphasis (italic)
378
+ ".cm-draftly-emphasis": {
379
+ fontStyle: "italic"
380
+ },
381
+ // Strong (bold)
382
+ ".cm-draftly-strong": {
383
+ fontWeight: "bold"
384
+ },
385
+ // Strikethrough
386
+ ".cm-draftly-strikethrough": {
387
+ textDecoration: "line-through",
388
+ opacity: "0.7"
389
+ },
390
+ // Subscript
391
+ ".cm-draftly-subscript": {
392
+ fontSize: "0.75em",
393
+ verticalAlign: "sub"
394
+ },
395
+ // Superscript
396
+ ".cm-draftly-superscript": {
397
+ fontSize: "0.75em",
398
+ verticalAlign: "super"
399
+ },
400
+ // Highlight
401
+ ".cm-draftly-highlight": {
402
+ backgroundColor: "rgba(255, 213, 0, 0.35)",
403
+ borderRadius: "2px",
404
+ padding: "1px 2px"
405
+ }
406
+ }
407
+ });
408
+ var linkMarkDecorations = {
409
+ "link-text": view.Decoration.mark({ class: "cm-draftly-link-text" }),
410
+ "link-marker": view.Decoration.mark({ class: "cm-draftly-link-marker" }),
411
+ "link-url": view.Decoration.mark({ class: "cm-draftly-link-url" }),
412
+ "link-hidden": view.Decoration.mark({ class: "cm-draftly-link-hidden" })
413
+ };
414
+ function parseLinkMarkdown(content) {
415
+ const match = content.match(/^\[([^\]]*)\]\(([^"\s)]+)(?:\s+"([^"]*)")?\s*\)$/);
416
+ if (!match) return null;
417
+ const result = {
418
+ text: match[1] || "",
419
+ url: match[2]
420
+ };
421
+ if (match[3] !== void 0) {
422
+ result.title = match[3];
423
+ }
424
+ return result;
425
+ }
426
+ var LinkTooltipWidget = class extends view.WidgetType {
427
+ constructor(url, from, to) {
428
+ super();
429
+ this.url = url;
430
+ this.from = from;
431
+ this.to = to;
432
+ }
433
+ eq(other) {
434
+ return other.url === this.url && other.from === this.from && other.to === this.to;
435
+ }
436
+ toDOM(view) {
437
+ const wrapper = document.createElement("span");
438
+ wrapper.className = "cm-draftly-link-wrapper";
439
+ wrapper.style.cursor = "pointer";
440
+ const tooltip = document.createElement("span");
441
+ tooltip.className = "cm-draftly-link-tooltip";
442
+ tooltip.textContent = this.url;
443
+ wrapper.appendChild(tooltip);
444
+ wrapper.addEventListener("mouseenter", () => {
445
+ tooltip.classList.add("cm-draftly-link-tooltip-visible");
446
+ });
447
+ wrapper.addEventListener("mouseleave", () => {
448
+ tooltip.classList.remove("cm-draftly-link-tooltip-visible");
449
+ });
450
+ wrapper.addEventListener("click", (e) => {
451
+ if (e.ctrlKey || e.metaKey) {
452
+ e.preventDefault();
453
+ e.stopPropagation();
454
+ window.open(this.url, "_blank", "noopener,noreferrer");
455
+ } else {
456
+ e.preventDefault();
457
+ e.stopPropagation();
458
+ view.dispatch({
459
+ selection: { anchor: this.from, head: this.to },
460
+ scrollIntoView: true
461
+ });
462
+ view.focus();
463
+ }
464
+ });
465
+ return wrapper;
466
+ }
467
+ ignoreEvent(event) {
468
+ return event.type !== "click" && event.type !== "mouseenter" && event.type !== "mouseleave";
469
+ }
470
+ };
471
+ var LinkPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
472
+ name = "link";
473
+ version = "1.0.0";
474
+ decorationPriority = 22;
475
+ requiredNodes = ["Link"];
476
+ constructor() {
477
+ super();
478
+ }
479
+ /**
480
+ * Plugin theme
481
+ */
482
+ get theme() {
483
+ return theme4;
484
+ }
485
+ /**
486
+ * Keyboard shortcuts for link formatting
487
+ */
488
+ getKeymap() {
489
+ return [
490
+ {
491
+ key: "Mod-k",
492
+ run: (view) => this.toggleLink(view),
493
+ preventDefault: true
494
+ }
495
+ ];
496
+ }
497
+ /**
498
+ * URL regex pattern
499
+ */
500
+ urlPattern = /^(https?:\/\/|www\.)[^\s]+$/i;
501
+ /**
502
+ * Toggle link on selection
503
+ * - If text is selected and is a URL: [](url) with cursor in brackets
504
+ * - If text is selected (not URL): [text]() with cursor in parentheses
505
+ * - If nothing selected: []() with cursor in brackets
506
+ * - If already a link: remove syntax, leave plain text
507
+ */
508
+ toggleLink(view) {
509
+ const { state } = view;
510
+ const { from, to, empty } = state.selection.main;
511
+ const selectedText = state.sliceDoc(from, to);
512
+ const linkMatch = selectedText.match(/^\[([^\]]*)\]\(([^)]*)\)$/);
513
+ if (linkMatch) {
514
+ const linkText = linkMatch[1] || "";
515
+ view.dispatch({
516
+ changes: { from, to, insert: linkText },
517
+ selection: { anchor: from, head: from + linkText.length }
518
+ });
519
+ return true;
520
+ }
521
+ const lineStart = state.doc.lineAt(from).from;
522
+ const lineEnd = state.doc.lineAt(to).to;
523
+ const lineText = state.sliceDoc(lineStart, lineEnd);
524
+ const linkRegex = /\[([^\]]*)\]\(([^)]*)\)/g;
525
+ let match;
526
+ while ((match = linkRegex.exec(lineText)) !== null) {
527
+ const matchFrom = lineStart + match.index;
528
+ const matchTo = matchFrom + match[0].length;
529
+ if (from >= matchFrom && to <= matchTo) {
530
+ const linkText = match[1] || "";
531
+ view.dispatch({
532
+ changes: { from: matchFrom, to: matchTo, insert: linkText },
533
+ selection: { anchor: matchFrom, head: matchFrom + linkText.length }
534
+ });
535
+ return true;
536
+ }
537
+ }
538
+ if (empty) {
539
+ view.dispatch({
540
+ changes: { from, insert: "[]()" },
541
+ selection: { anchor: from + 1 }
542
+ });
543
+ } else if (this.urlPattern.test(selectedText)) {
544
+ const newText = `[](${selectedText})`;
545
+ view.dispatch({
546
+ changes: { from, to, insert: newText },
547
+ selection: { anchor: from + 1 }
548
+ });
549
+ } else {
550
+ const newText = `[${selectedText}]()`;
551
+ view.dispatch({
552
+ changes: { from, to, insert: newText },
553
+ selection: { anchor: from + selectedText.length + 3 }
554
+ });
555
+ }
556
+ return true;
557
+ }
558
+ buildDecorations(ctx) {
559
+ const { view: view$1, decorations } = ctx;
560
+ const tree = language.syntaxTree(view$1.state);
561
+ tree.iterate({
562
+ enter: (node) => {
563
+ const { from, to, name } = node;
564
+ if (name === "Link") {
565
+ const content = view$1.state.sliceDoc(from, to);
566
+ const parsed = parseLinkMarkdown(content);
567
+ if (!parsed) return;
568
+ const cursorInRange = ctx.selectionOverlapsRange(from, to);
569
+ if (cursorInRange) {
570
+ this.decorateRawLink(node.node, decorations, view$1);
571
+ } else {
572
+ decorations.push(linkMarkDecorations["link-hidden"].range(from, to));
573
+ decorations.push(
574
+ view.Decoration.widget({
575
+ widget: new LinkTooltipWidget(parsed.url, from, to),
576
+ side: 1
577
+ }).range(to)
578
+ );
579
+ decorations.push(
580
+ view.Decoration.replace({
581
+ widget: new LinkTextWidget(parsed.text, parsed.url, from, to, parsed.title)
582
+ }).range(from, to)
583
+ );
584
+ }
585
+ }
586
+ }
587
+ });
588
+ }
589
+ /**
590
+ * Decorate raw link markdown when cursor is in range
591
+ */
592
+ decorateRawLink(node, decorations, view) {
593
+ const content = view.state.sliceDoc(node.from, node.to);
594
+ decorations.push(linkMarkDecorations["link-marker"].range(node.from, node.from + 1));
595
+ const bracketParen = content.indexOf("](");
596
+ if (bracketParen !== -1) {
597
+ if (bracketParen > 1) {
598
+ decorations.push(linkMarkDecorations["link-text"].range(node.from + 1, node.from + bracketParen));
599
+ }
600
+ decorations.push(
601
+ linkMarkDecorations["link-marker"].range(node.from + bracketParen, node.from + bracketParen + 2)
602
+ );
603
+ const urlChild = node.getChild("URL");
604
+ if (urlChild) {
605
+ decorations.push(linkMarkDecorations["link-url"].range(urlChild.from, urlChild.to));
606
+ }
607
+ decorations.push(linkMarkDecorations["link-marker"].range(node.to - 1, node.to));
608
+ }
609
+ }
610
+ /**
611
+ * Render link to HTML for preview mode
612
+ */
613
+ renderToHTML(node, _children, ctx) {
614
+ if (node.name !== "Link") return null;
615
+ const content = ctx.sliceDoc(node.from, node.to);
616
+ const parsed = parseLinkMarkdown(content);
617
+ if (!parsed) return null;
618
+ const textContent = ctx.sanitize(parsed.text);
619
+ const urlAttr = ctx.sanitize(parsed.url);
620
+ const titleAttr = parsed.title ? ` title="${ctx.sanitize(parsed.title)}"` : "";
621
+ return `<a class="cm-draftly-link" href="${urlAttr}"${titleAttr} target="_blank" rel="noopener noreferrer">${textContent}</a>`;
622
+ }
623
+ };
624
+ var LinkTextWidget = class extends view.WidgetType {
625
+ constructor(text, url, from, to, title) {
626
+ super();
627
+ this.text = text;
628
+ this.url = url;
629
+ this.from = from;
630
+ this.to = to;
631
+ this.title = title;
632
+ }
633
+ eq(other) {
634
+ return other.text === this.text && other.url === this.url && other.from === this.from && other.to === this.to && other.title === this.title;
635
+ }
636
+ toDOM(view) {
637
+ const span = document.createElement("span");
638
+ span.className = "cm-draftly-link-styled";
639
+ span.textContent = this.text;
640
+ span.style.cursor = "pointer";
641
+ if (this.title) {
642
+ span.title = this.title;
643
+ }
644
+ const tooltip = document.createElement("span");
645
+ tooltip.className = "cm-draftly-link-tooltip";
646
+ tooltip.textContent = this.url;
647
+ span.appendChild(tooltip);
648
+ span.addEventListener("mouseenter", () => {
649
+ tooltip.classList.add("cm-draftly-link-tooltip-visible");
650
+ });
651
+ span.addEventListener("mouseleave", () => {
652
+ tooltip.classList.remove("cm-draftly-link-tooltip-visible");
653
+ });
654
+ span.addEventListener("click", (e) => {
655
+ if (e.ctrlKey || e.metaKey) {
656
+ e.preventDefault();
657
+ e.stopPropagation();
658
+ window.open(this.url, "_blank", "noopener,noreferrer");
659
+ } else {
660
+ e.preventDefault();
661
+ e.stopPropagation();
662
+ view.dispatch({
663
+ selection: { anchor: this.from, head: this.to },
664
+ scrollIntoView: true
665
+ });
666
+ view.focus();
667
+ }
668
+ });
669
+ return span;
670
+ }
671
+ ignoreEvent(event) {
672
+ return event.type !== "click" && event.type !== "mouseenter" && event.type !== "mouseleave";
673
+ }
674
+ };
675
+ var theme4 = chunkKDEDLC3D_cjs.createTheme({
676
+ default: {
677
+ // Link text
678
+ ".cm-draftly-link-text": {
679
+ color: "#0366d6"
680
+ },
681
+ // Link markers ([ ] ( ))
682
+ ".cm-draftly-link-marker": {
683
+ color: "#6a737d",
684
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
685
+ },
686
+ // URL in raw markdown
687
+ ".cm-draftly-link-url": {
688
+ color: "#6a737d",
689
+ fontStyle: "italic"
690
+ },
691
+ // Hidden markdown syntax
692
+ ".cm-draftly-link-hidden": {
693
+ display: "none"
694
+ },
695
+ // Styled link when cursor is not in range
696
+ ".cm-draftly-link-styled": {
697
+ color: "#0366d6",
698
+ textDecoration: "underline",
699
+ position: "relative",
700
+ cursor: "pointer"
701
+ },
702
+ ".cm-draftly-link-styled:hover": {
703
+ color: "#0056b3"
704
+ },
705
+ // Preview link styling
706
+ ".cm-draftly-link": {
707
+ color: "#0366d6",
708
+ textDecoration: "underline"
709
+ },
710
+ ".cm-draftly-link:hover": {
711
+ color: "#0056b3"
712
+ },
713
+ // Tooltip styling
714
+ ".cm-draftly-link-tooltip": {
715
+ display: "none",
716
+ position: "absolute",
717
+ bottom: "100%",
718
+ left: "50%",
719
+ transform: "translateX(-50%)",
720
+ backgroundColor: "#24292e",
721
+ color: "#ffffff",
722
+ padding: "4px 8px",
723
+ borderRadius: "4px",
724
+ fontSize: "12px",
725
+ whiteSpace: "nowrap",
726
+ zIndex: "1000",
727
+ pointerEvents: "none",
728
+ marginBottom: "4px",
729
+ maxWidth: "300px",
730
+ overflow: "hidden",
731
+ textOverflow: "ellipsis"
732
+ },
733
+ ".cm-draftly-link-tooltip-visible": {
734
+ display: "block"
735
+ }
736
+ },
737
+ dark: {
738
+ ".cm-draftly-link-text": {
739
+ color: "#58a6ff"
740
+ },
741
+ ".cm-draftly-link-marker": {
742
+ color: "#8b949e"
743
+ },
744
+ ".cm-draftly-link-url": {
745
+ color: "#8b949e"
746
+ },
747
+ ".cm-draftly-link-styled": {
748
+ color: "#58a6ff"
749
+ },
750
+ ".cm-draftly-link-styled:hover": {
751
+ color: "#79c0ff"
752
+ },
753
+ ".cm-draftly-link": {
754
+ color: "#58a6ff"
755
+ },
756
+ ".cm-draftly-link:hover": {
757
+ color: "#79c0ff"
758
+ },
759
+ ".cm-draftly-link-tooltip": {
760
+ backgroundColor: "#30363d",
761
+ color: "#c9d1d9"
762
+ }
763
+ }
764
+ });
765
+ var classes = {
766
+ // Unordered list classes
767
+ lineUL: "cm-draftly-list-line-ul",
768
+ markUL: "cm-draftly-list-mark-ul",
769
+ // Ordered list classes
770
+ lineOL: "cm-draftly-list-line-ol",
771
+ markOL: "cm-draftly-list-mark-ol",
772
+ // Task list classes
773
+ taskLine: "cm-draftly-task-line",
774
+ taskMarker: "cm-draftly-task-marker",
775
+ // Common classes
776
+ content: "cm-draftly-list-content",
777
+ indent: "cm-draftly-list-indent",
778
+ active: " cm-draftly-active",
779
+ preview: "cm-draftly-preview"
780
+ };
781
+ var TaskCheckboxWidget = class extends view.WidgetType {
782
+ constructor(checked) {
783
+ super();
784
+ this.checked = checked;
785
+ }
786
+ eq(other) {
787
+ return other.checked === this.checked;
788
+ }
789
+ toDOM(view) {
790
+ const wrap = document.createElement("span");
791
+ wrap.className = `cm-draftly-task-checkbox ${this.checked ? "checked" : ""}`;
792
+ wrap.setAttribute("aria-hidden", "true");
793
+ const checkbox = document.createElement("input");
794
+ checkbox.type = "checkbox";
795
+ checkbox.checked = this.checked;
796
+ checkbox.tabIndex = -1;
797
+ checkbox.addEventListener("mousedown", (e) => {
798
+ e.preventDefault();
799
+ this.toggleCheckbox(view, wrap);
800
+ });
801
+ wrap.appendChild(checkbox);
802
+ return wrap;
803
+ }
804
+ ignoreEvent() {
805
+ return false;
806
+ }
807
+ /** Toggle the checkbox state in the document */
808
+ toggleCheckbox(view, wrap) {
809
+ const pos = view.posAtDOM(wrap);
810
+ const line = view.state.doc.lineAt(pos);
811
+ const match = line.text.match(/^(\s*(?:[-*+]|\d+\.)\s*)\[([ xX])\]/);
812
+ if (match) {
813
+ const markerStart = line.from + match[1].length + 1;
814
+ const newChar = this.checked ? " " : "x";
815
+ view.dispatch({
816
+ changes: { from: markerStart, to: markerStart + 1, insert: newChar }
817
+ });
818
+ }
819
+ }
820
+ };
821
+ var ListPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
822
+ name = "list";
823
+ version = "1.0.0";
824
+ decorationPriority = 20;
825
+ requiredNodes = [
826
+ "BulletList",
827
+ "OrderedList",
828
+ "ListItem",
829
+ "ListMark",
830
+ "Task",
831
+ "TaskMarker"
832
+ ];
833
+ get theme() {
834
+ return theme5;
835
+ }
836
+ /**
837
+ * Keyboard shortcuts for list formatting
838
+ */
839
+ getKeymap() {
840
+ return [
841
+ {
842
+ key: "Mod-Shift-8",
843
+ run: (view) => this.toggleListOnLines(view, "- "),
844
+ preventDefault: true
845
+ },
846
+ {
847
+ key: "Mod-Shift-7",
848
+ run: (view) => this.toggleListOnLines(view, "1. "),
849
+ preventDefault: true
850
+ },
851
+ {
852
+ key: "Mod-Shift-9",
853
+ run: (view) => this.toggleListOnLines(view, "- [ ] "),
854
+ preventDefault: true
855
+ }
856
+ ];
857
+ }
858
+ /**
859
+ * Toggle list marker on current line or selected lines
860
+ */
861
+ toggleListOnLines(view, marker) {
862
+ const { state } = view;
863
+ const { from, to } = state.selection.main;
864
+ const startLine = state.doc.lineAt(from);
865
+ const endLine = state.doc.lineAt(to);
866
+ const changes = [];
867
+ const listMarkerRegex = /^(\s*)([-*+]|\d+\.)\s(\[[ xX]\]\s)?/;
868
+ const isOrderedMarker = marker === "1. ";
869
+ let orderNum = 1;
870
+ for (let lineNum = startLine.number; lineNum <= endLine.number; lineNum++) {
871
+ const line = state.doc.line(lineNum);
872
+ const match = line.text.match(listMarkerRegex);
873
+ const actualMarker = isOrderedMarker ? `${orderNum}. ` : marker;
874
+ if (match) {
875
+ const existingMarker = match[0];
876
+ const indent = match[1] || "";
877
+ const isUnordered = /^[-*+]$/.test(match[2]);
878
+ const isOrdered = /^\d+\.$/.test(match[2]);
879
+ const hasTask = !!match[3];
880
+ const wantUnordered = marker === "- ";
881
+ const wantOrdered = isOrderedMarker;
882
+ const wantTask = marker === "- [ ] ";
883
+ if (wantUnordered && isUnordered && !hasTask || wantOrdered && isOrdered && !hasTask || wantTask && hasTask) {
884
+ changes.push({
885
+ from: line.from,
886
+ to: line.from + existingMarker.length,
887
+ insert: indent
888
+ });
889
+ } else {
890
+ changes.push({
891
+ from: line.from,
892
+ to: line.from + existingMarker.length,
893
+ insert: indent + actualMarker
894
+ });
895
+ orderNum++;
896
+ }
897
+ } else {
898
+ const indentMatch = line.text.match(/^(\s*)/);
899
+ const indent = indentMatch ? indentMatch[1] : "";
900
+ changes.push({
901
+ from: line.from + indent.length,
902
+ to: line.from + indent.length,
903
+ insert: actualMarker
904
+ });
905
+ orderNum++;
906
+ }
907
+ }
908
+ if (changes.length > 0) {
909
+ view.dispatch({ changes });
910
+ }
911
+ return true;
912
+ }
913
+ buildDecorations(ctx) {
914
+ const { view, decorations } = ctx;
915
+ const tree = language.syntaxTree(view.state);
916
+ tree.iterate({
917
+ enter: (node) => {
918
+ const { from, to, name } = node;
919
+ const line = view.state.doc.lineAt(from);
920
+ const cursorInLine = ctx.cursorInRange(line.from, line.to);
921
+ switch (name) {
922
+ case "ListItem":
923
+ this.decorateListItem(node, line, decorations);
924
+ break;
925
+ case "ListMark":
926
+ this.decorateListMark(node, line, decorations, cursorInLine);
927
+ break;
928
+ case "TaskMarker":
929
+ this.decorateTaskMarker(from, to, view, decorations, cursorInLine);
930
+ break;
931
+ }
932
+ }
933
+ });
934
+ }
935
+ /** Add line decoration for list items with nesting depth */
936
+ decorateListItem(node, line, decorations) {
937
+ const parent = node.node.parent;
938
+ const listType = parent?.name;
939
+ let depth = 0;
940
+ let ancestor = node.node.parent;
941
+ while (ancestor) {
942
+ if (ancestor.name === "ListItem") depth++;
943
+ ancestor = ancestor.parent;
944
+ }
945
+ const hasTask = this.hasTaskChild(node);
946
+ let lineClass;
947
+ if (hasTask) lineClass = classes.taskLine;
948
+ else if (listType === "OrderedList") lineClass = classes.lineOL;
949
+ else lineClass = classes.lineUL;
950
+ decorations.push(
951
+ view.Decoration.line({
952
+ class: lineClass,
953
+ attributes: { style: `--depth: ${depth}` }
954
+ }).range(line.from)
955
+ );
956
+ }
957
+ /** Check if a ListItem node has a Task child */
958
+ hasTaskChild(node) {
959
+ const cursor = node.node.cursor();
960
+ if (cursor.firstChild()) {
961
+ do {
962
+ if (cursor.name === "Task") return true;
963
+ } while (cursor.nextSibling());
964
+ }
965
+ return false;
966
+ }
967
+ /** Decorate list markers (bullets for UL, numbers for OL) */
968
+ decorateListMark(node, line, decorations, cursorInLine) {
969
+ const { from, to } = node;
970
+ const parent = node.node.parent;
971
+ const grandparent = parent?.parent;
972
+ const listType = grandparent?.name;
973
+ const activeClass = cursorInLine ? classes.active : "";
974
+ if (from > line.from) {
975
+ decorations.push(view.Decoration.mark({ class: classes.indent + activeClass }).range(line.from, from));
976
+ }
977
+ const markClass = listType === "OrderedList" ? classes.markOL : classes.markUL;
978
+ decorations.push(view.Decoration.mark({ class: markClass + activeClass }).range(from, to + 1));
979
+ const contentStart = to + 1;
980
+ if (contentStart < line.to) {
981
+ decorations.push(view.Decoration.mark({ class: classes.content }).range(contentStart, line.to));
982
+ }
983
+ }
984
+ /** Decorate task markers - show checkbox widget or raw text based on cursor */
985
+ decorateTaskMarker(from, to, view$1, decorations, cursorInLine) {
986
+ const text = view$1.state.sliceDoc(from, to);
987
+ const isChecked = text.includes("x") || text.includes("X");
988
+ if (cursorInLine) {
989
+ decorations.push(view.Decoration.mark({ class: classes.taskMarker }).range(from, to));
990
+ } else {
991
+ decorations.push(
992
+ view.Decoration.replace({
993
+ widget: new TaskCheckboxWidget(isChecked)
994
+ }).range(from, to)
995
+ );
996
+ }
997
+ }
998
+ /** Render list nodes to HTML */
999
+ renderToHTML(node, children, ctx) {
1000
+ switch (node.name) {
1001
+ case "BulletList":
1002
+ return `<ul class="${classes.lineUL} ${classes.preview}">${children}</ul>
1003
+ `;
1004
+ case "OrderedList":
1005
+ return `<ol class="${classes.lineOL} ${classes.preview}">${children}</ol>
1006
+ `;
1007
+ case "ListItem":
1008
+ return `<li>${children}</li>
1009
+ `;
1010
+ case "Task":
1011
+ return children;
1012
+ case "TaskMarker": {
1013
+ const text = ctx.sliceDoc(node.from, node.to);
1014
+ const isChecked = text.includes("x") || text.includes("X");
1015
+ return `<input type="checkbox" class="cm-draftly-task-checkbox" disabled ${isChecked ? "checked" : ""} />`;
1016
+ }
1017
+ case "ListMark":
1018
+ return "";
1019
+ default:
1020
+ return null;
1021
+ }
1022
+ }
1023
+ };
1024
+ var theme5 = chunkKDEDLC3D_cjs.createTheme({
1025
+ default: {
1026
+ // Indentation marker positioning
1027
+ ".cm-draftly-list-indent": {
1028
+ overflow: "hidden",
1029
+ display: "inline-block",
1030
+ position: "absolute",
1031
+ left: "calc(1rem * (var(--depth, 0) + 1))",
1032
+ transform: "translateX(-100%)"
1033
+ },
1034
+ // List line layout (flexbox for marker alignment)
1035
+ ".cm-draftly-list-line-ul, .cm-draftly-list-line-ol": {
1036
+ position: "relative",
1037
+ paddingLeft: "calc(1rem * (var(--depth, 0) + 1)) !important",
1038
+ display: "flex",
1039
+ alignItems: "start"
1040
+ },
1041
+ ".cm-draftly-list-line-ul > :first-child, .cm-draftly-list-line-ol > :first-child": {
1042
+ flexShrink: 0
1043
+ },
1044
+ // List marker sizing
1045
+ ".cm-draftly-list-line-ul .cm-draftly-list-mark-ul, .cm-draftly-list-line-ol .cm-draftly-list-mark-ol": {
1046
+ whiteSpace: "pre",
1047
+ position: "relative",
1048
+ width: "1rem",
1049
+ flexShrink: 0
1050
+ },
1051
+ // Hide raw marker text when not active
1052
+ ".cm-draftly-list-mark-ul:not(.cm-draftly-active) > span, .cm-draftly-task-line .cm-draftly-list-mark-ol:not(.cm-draftly-active) > span": {
1053
+ visibility: "hidden",
1054
+ display: "none"
1055
+ },
1056
+ // Styled bullet for unordered lists
1057
+ ".cm-draftly-list-line-ul .cm-draftly-list-mark-ul:not(.cm-draftly-active)::after": {
1058
+ content: '"\u2022"',
1059
+ color: "var(--color-link)",
1060
+ fontWeight: "bold",
1061
+ pointerEvents: "none"
1062
+ },
1063
+ // Task marker styling (visible when editing)
1064
+ ".cm-draftly-task-marker": {
1065
+ color: "var(--draftly-highlight, #a4a4a4)",
1066
+ fontFamily: "monospace"
1067
+ },
1068
+ // Task checkbox container
1069
+ ".cm-draftly-task-checkbox": {
1070
+ display: "inline-flex",
1071
+ verticalAlign: "middle",
1072
+ marginRight: "0.3em",
1073
+ cursor: "pointer",
1074
+ userSelect: "none",
1075
+ alignItems: "center",
1076
+ height: "1.2em"
1077
+ },
1078
+ // Task checkbox input styling
1079
+ ".cm-draftly-task-checkbox input": {
1080
+ cursor: "pointer",
1081
+ margin: 0,
1082
+ width: "1.1em",
1083
+ height: "1.1em",
1084
+ appearance: "none",
1085
+ border: "1px solid",
1086
+ borderRadius: "0.25em",
1087
+ backgroundColor: "transparent",
1088
+ position: "relative"
1089
+ },
1090
+ // Checkmark for completed tasks
1091
+ ".cm-draftly-task-checkbox.checked input::after": {
1092
+ content: '"\u2713"',
1093
+ position: "absolute",
1094
+ left: "1px",
1095
+ top: "-3px"
1096
+ },
1097
+ // Preview styles (override editor-specific layout)
1098
+ ".cm-draftly-preview": {
1099
+ display: "block",
1100
+ paddingLeft: "1.5rem",
1101
+ margin: "0.5rem 0"
1102
+ },
1103
+ ".cm-draftly-preview li": {
1104
+ display: "list-item",
1105
+ marginBottom: "0.25rem"
1106
+ },
1107
+ "ul.cm-draftly-preview": {
1108
+ listStyleType: "disc"
1109
+ },
1110
+ "ol.cm-draftly-preview": {
1111
+ listStyleType: "decimal"
1112
+ },
1113
+ // Hide list marker for task items
1114
+ ".cm-draftly-preview li:has(.cm-draftly-task-checkbox)": {
1115
+ listStyleType: "none"
1116
+ },
1117
+ ".cm-draftly-preview li .cm-draftly-paragraph": {
1118
+ padding: "0"
1119
+ }
1120
+ }
1121
+ });
1122
+ var htmlMarkDecorations = {
1123
+ "html-tag": view.Decoration.mark({ class: "cm-draftly-html-tag" }),
1124
+ "html-comment": view.Decoration.mark({ class: "cm-draftly-html-comment" })
1125
+ };
1126
+ var htmlLineDecorations = {
1127
+ "html-block": view.Decoration.line({ class: "cm-draftly-line-html-block" }),
1128
+ "hidden-line": view.Decoration.line({ class: "cm-draftly-hidden-line" })
1129
+ };
1130
+ var HTMLPreviewWidget = class extends view.WidgetType {
1131
+ constructor(html) {
1132
+ super();
1133
+ this.html = html;
1134
+ }
1135
+ eq(other) {
1136
+ return other.html === this.html;
1137
+ }
1138
+ toDOM() {
1139
+ const div = document.createElement("div");
1140
+ div.className = "cm-draftly-html-preview";
1141
+ div.innerHTML = DOMPurify__default.default.sanitize(this.html);
1142
+ return div;
1143
+ }
1144
+ ignoreEvent() {
1145
+ return false;
1146
+ }
1147
+ };
1148
+ var InlineHTMLPreviewWidget = class extends view.WidgetType {
1149
+ constructor(html) {
1150
+ super();
1151
+ this.html = html;
1152
+ }
1153
+ eq(other) {
1154
+ return other.html === this.html;
1155
+ }
1156
+ toDOM() {
1157
+ const span = document.createElement("span");
1158
+ span.className = "cm-draftly-inline-html-preview";
1159
+ span.innerHTML = DOMPurify__default.default.sanitize(this.html);
1160
+ return span;
1161
+ }
1162
+ ignoreEvent() {
1163
+ return false;
1164
+ }
1165
+ };
1166
+ function parseHTMLTag(content) {
1167
+ const match = content.match(/^<\s*(\/?)([a-zA-Z][a-zA-Z0-9-]*)[^>]*(\/?)>$/);
1168
+ if (!match) return null;
1169
+ return {
1170
+ tagName: match[2].toLowerCase(),
1171
+ isClosing: match[1] === "/",
1172
+ isSelfClosing: match[3] === "/" || ["br", "hr", "img", "input", "meta", "link", "area", "base", "col", "embed", "source", "track", "wbr"].includes(
1173
+ match[2].toLowerCase()
1174
+ )
1175
+ };
1176
+ }
1177
+ var HTMLPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
1178
+ name = "html";
1179
+ version = "1.0.0";
1180
+ decorationPriority = 30;
1181
+ constructor() {
1182
+ super();
1183
+ }
1184
+ /**
1185
+ * Plugin theme
1186
+ */
1187
+ get theme() {
1188
+ return theme6;
1189
+ }
1190
+ buildDecorations(ctx) {
1191
+ const { view: view$1, decorations } = ctx;
1192
+ const tree = language.syntaxTree(view$1.state);
1193
+ const htmlGroups = [];
1194
+ const htmlTags = [];
1195
+ tree.iterate({
1196
+ enter: (node) => {
1197
+ const { from, to, name } = node;
1198
+ if (name === "Comment") {
1199
+ decorations.push(htmlMarkDecorations["html-comment"].range(from, to));
1200
+ return;
1201
+ }
1202
+ if (name === "HTMLTag") {
1203
+ const content = view$1.state.sliceDoc(from, to);
1204
+ const parsed = parseHTMLTag(content);
1205
+ if (parsed) {
1206
+ htmlTags.push({
1207
+ from,
1208
+ to,
1209
+ tagName: parsed.tagName,
1210
+ isClosing: parsed.isClosing,
1211
+ isSelfClosing: parsed.isSelfClosing
1212
+ });
1213
+ }
1214
+ }
1215
+ if (name === "HTMLBlock") {
1216
+ const last = htmlGroups[htmlGroups.length - 1];
1217
+ if (last) {
1218
+ const gap = view$1.state.sliceDoc(last.to, from);
1219
+ if (!gap.trim()) {
1220
+ last.to = to;
1221
+ return;
1222
+ }
1223
+ }
1224
+ htmlGroups.push({ from, to });
1225
+ }
1226
+ }
1227
+ });
1228
+ const inlineElements = [];
1229
+ const usedTags = /* @__PURE__ */ new Set();
1230
+ for (let i = 0; i < htmlTags.length; i++) {
1231
+ if (usedTags.has(i)) continue;
1232
+ const openTag = htmlTags[i];
1233
+ if (openTag.isClosing) continue;
1234
+ if (openTag.isSelfClosing) {
1235
+ inlineElements.push({
1236
+ from: openTag.from,
1237
+ to: openTag.to,
1238
+ content: view$1.state.sliceDoc(openTag.from, openTag.to)
1239
+ });
1240
+ usedTags.add(i);
1241
+ continue;
1242
+ }
1243
+ const openLine = view$1.state.doc.lineAt(openTag.from);
1244
+ let depth = 1;
1245
+ let closeTagIndex = null;
1246
+ for (let j = i + 1; j < htmlTags.length && depth > 0; j++) {
1247
+ const tag = htmlTags[j];
1248
+ if (tag.from > openLine.to) break;
1249
+ if (tag.tagName === openTag.tagName) {
1250
+ if (tag.isClosing) {
1251
+ depth--;
1252
+ if (depth === 0) {
1253
+ closeTagIndex = j;
1254
+ }
1255
+ } else if (!tag.isSelfClosing) {
1256
+ depth++;
1257
+ }
1258
+ }
1259
+ }
1260
+ if (closeTagIndex !== null) {
1261
+ const closeTag = htmlTags[closeTagIndex];
1262
+ inlineElements.push({
1263
+ from: openTag.from,
1264
+ to: closeTag.to,
1265
+ content: view$1.state.sliceDoc(openTag.from, closeTag.to)
1266
+ });
1267
+ for (let k = i; k <= closeTagIndex; k++) {
1268
+ usedTags.add(k);
1269
+ }
1270
+ }
1271
+ }
1272
+ inlineElements.sort((a, b) => a.from - b.from);
1273
+ const filteredElements = [];
1274
+ let lastEnd = -1;
1275
+ for (const elem of inlineElements) {
1276
+ if (elem.from >= lastEnd) {
1277
+ filteredElements.push(elem);
1278
+ lastEnd = elem.to;
1279
+ }
1280
+ }
1281
+ for (const elem of filteredElements) {
1282
+ const cursorInRange = ctx.cursorInRange(elem.from, elem.to);
1283
+ if (cursorInRange) {
1284
+ for (const tag of htmlTags) {
1285
+ if (tag.from >= elem.from && tag.to <= elem.to) {
1286
+ decorations.push(htmlMarkDecorations["html-tag"].range(tag.from, tag.to));
1287
+ }
1288
+ }
1289
+ } else {
1290
+ decorations.push(
1291
+ view.Decoration.replace({
1292
+ widget: new InlineHTMLPreviewWidget(elem.content)
1293
+ }).range(elem.from, elem.to)
1294
+ );
1295
+ }
1296
+ }
1297
+ for (let i = 0; i < htmlTags.length; i++) {
1298
+ if (!usedTags.has(i)) {
1299
+ const tag = htmlTags[i];
1300
+ decorations.push(htmlMarkDecorations["html-tag"].range(tag.from, tag.to));
1301
+ }
1302
+ }
1303
+ for (const group of htmlGroups) {
1304
+ const { from, to } = group;
1305
+ const nodeLineStart = view$1.state.doc.lineAt(from);
1306
+ const nodeLineEnd = view$1.state.doc.lineAt(to);
1307
+ const cursorInRange = ctx.cursorInRange(nodeLineStart.from, nodeLineEnd.to);
1308
+ if (cursorInRange) {
1309
+ for (let i = nodeLineStart.number; i <= nodeLineEnd.number; i++) {
1310
+ const line = view$1.state.doc.line(i);
1311
+ decorations.push(htmlLineDecorations["html-block"].range(line.from));
1312
+ }
1313
+ } else {
1314
+ const htmlContent = view$1.state.sliceDoc(from, to);
1315
+ decorations.push(
1316
+ view.Decoration.replace({
1317
+ widget: new HTMLPreviewWidget(htmlContent.trim())
1318
+ }).range(from, nodeLineStart.to)
1319
+ );
1320
+ for (let i = nodeLineStart.number + 1; i <= nodeLineEnd.number; i++) {
1321
+ const line = view$1.state.doc.line(i);
1322
+ decorations.push(htmlLineDecorations["hidden-line"].range(line.from));
1323
+ }
1324
+ }
1325
+ }
1326
+ }
1327
+ };
1328
+ var theme6 = chunkKDEDLC3D_cjs.createTheme({
1329
+ default: {
1330
+ ".cm-draftly-html-tag": {
1331
+ color: "#6a737d",
1332
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
1333
+ fontSize: "0.85em"
1334
+ },
1335
+ ".cm-draftly-html-comment": {
1336
+ color: "#6a737d",
1337
+ fontStyle: "italic",
1338
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
1339
+ fontSize: "0.85em",
1340
+ opacity: 0.5
1341
+ },
1342
+ ".cm-draftly-line-html-block": {
1343
+ backgroundColor: "rgba(0, 0, 0, 0.02)"
1344
+ },
1345
+ ".cm-draftly-hidden-line": {
1346
+ display: "none"
1347
+ },
1348
+ ".cm-draftly-html-preview": {
1349
+ display: "inline-block",
1350
+ width: "100%",
1351
+ verticalAlign: "top",
1352
+ margin: "0",
1353
+ whiteSpace: "normal",
1354
+ lineHeight: "1.4"
1355
+ },
1356
+ ".cm-draftly-html-preview > *:first-child": {
1357
+ marginTop: "0"
1358
+ },
1359
+ ".cm-draftly-html-preview > *:last-child": {
1360
+ marginBottom: "0"
1361
+ },
1362
+ ".cm-draftly-inline-html-preview": {
1363
+ display: "inline",
1364
+ whiteSpace: "normal"
1365
+ }
1366
+ }
1367
+ });
1368
+ var imageMarkDecorations = {
1369
+ "image-block": view.Decoration.line({ class: "cm-draftly-image-block" }),
1370
+ "image-marker": view.Decoration.mark({ class: "cm-draftly-image-marker" }),
1371
+ "image-alt": view.Decoration.mark({ class: "cm-draftly-image-alt" }),
1372
+ "image-url": view.Decoration.mark({ class: "cm-draftly-image-url" }),
1373
+ "image-hidden": view.Decoration.mark({ class: "cm-draftly-image-hidden" })
1374
+ };
1375
+ function parseImageMarkdown(content) {
1376
+ const match = content.match(/^!\[([^\]]*)\]\(([^"\s)]+)(?:\s+"([^"]*)")?\s*\)$/);
1377
+ if (!match) return null;
1378
+ const result = {
1379
+ alt: match[1] || "",
1380
+ url: match[2]
1381
+ };
1382
+ if (match[3] !== void 0) {
1383
+ result.title = match[3];
1384
+ }
1385
+ return result;
1386
+ }
1387
+ var ImageWidget = class extends view.WidgetType {
1388
+ constructor(url, alt, from, to, title) {
1389
+ super();
1390
+ this.url = url;
1391
+ this.alt = alt;
1392
+ this.from = from;
1393
+ this.to = to;
1394
+ this.title = title;
1395
+ }
1396
+ eq(other) {
1397
+ return other.url === this.url && other.alt === this.alt && other.from === this.from && other.to === this.to && other.title === this.title;
1398
+ }
1399
+ toDOM(view) {
1400
+ const figure = document.createElement("figure");
1401
+ figure.className = "cm-draftly-image-figure";
1402
+ figure.setAttribute("role", "figure");
1403
+ figure.style.cursor = "pointer";
1404
+ if (this.title) {
1405
+ figure.setAttribute("aria-label", this.title);
1406
+ }
1407
+ figure.addEventListener("click", (e) => {
1408
+ e.preventDefault();
1409
+ e.stopPropagation();
1410
+ view.dispatch({
1411
+ selection: { anchor: this.from, head: this.to },
1412
+ scrollIntoView: true
1413
+ });
1414
+ view.focus();
1415
+ });
1416
+ const img = document.createElement("img");
1417
+ img.className = "cm-draftly-image";
1418
+ img.src = this.url;
1419
+ img.alt = this.alt;
1420
+ img.setAttribute("loading", "lazy");
1421
+ img.setAttribute("decoding", "async");
1422
+ if (this.title) {
1423
+ img.title = this.title;
1424
+ }
1425
+ img.onerror = () => {
1426
+ img.style.display = "none";
1427
+ const errorSpan = document.createElement("span");
1428
+ errorSpan.className = "cm-draftly-image-error";
1429
+ errorSpan.setAttribute("role", "alert");
1430
+ errorSpan.textContent = `[Image not found: ${this.alt || this.url}]`;
1431
+ figure.appendChild(errorSpan);
1432
+ };
1433
+ figure.appendChild(img);
1434
+ if (this.title) {
1435
+ const figcaption = document.createElement("figcaption");
1436
+ figcaption.className = "cm-draftly-image-caption";
1437
+ figcaption.textContent = this.title;
1438
+ figure.appendChild(figcaption);
1439
+ }
1440
+ return figure;
1441
+ }
1442
+ ignoreEvent(event) {
1443
+ return event.type !== "click";
1444
+ }
1445
+ };
1446
+ var ImagePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
1447
+ name = "image";
1448
+ version = "1.0.0";
1449
+ decorationPriority = 25;
1450
+ requiredNodes = ["Image"];
1451
+ constructor() {
1452
+ super();
1453
+ }
1454
+ /**
1455
+ * Plugin theme
1456
+ */
1457
+ get theme() {
1458
+ return theme7;
1459
+ }
1460
+ /**
1461
+ * Keyboard shortcuts for image formatting
1462
+ */
1463
+ getKeymap() {
1464
+ return [
1465
+ {
1466
+ key: "Mod-Shift-i",
1467
+ run: (view) => this.toggleImage(view),
1468
+ preventDefault: true
1469
+ }
1470
+ ];
1471
+ }
1472
+ /**
1473
+ * URL regex pattern
1474
+ */
1475
+ urlPattern = /^(https?:\/\/|www\.)[^\s]+$/i;
1476
+ /**
1477
+ * Toggle image on selection
1478
+ * - If text selected and is a URL: ![Alt Text](url) with cursor in brackets
1479
+ * - If text selected (not URL): ![text]() with cursor in parentheses
1480
+ * - If nothing selected: ![Alt Text]() with cursor in parentheses
1481
+ * - If already an image: remove syntax, leave just the URL
1482
+ */
1483
+ toggleImage(view) {
1484
+ const { state } = view;
1485
+ const { from, to, empty } = state.selection.main;
1486
+ const selectedText = state.sliceDoc(from, to);
1487
+ const imageMatch = selectedText.match(/^!\[([^\]]*)\]\(([^)]*)\)$/);
1488
+ if (imageMatch) {
1489
+ const imageUrl = imageMatch[2] || "";
1490
+ view.dispatch({
1491
+ changes: { from, to, insert: imageUrl },
1492
+ selection: { anchor: from, head: from + imageUrl.length }
1493
+ });
1494
+ return true;
1495
+ }
1496
+ const lineStart = state.doc.lineAt(from).from;
1497
+ const lineEnd = state.doc.lineAt(to).to;
1498
+ const lineText = state.sliceDoc(lineStart, lineEnd);
1499
+ const imageRegex = /!\[([^\]]*)\]\(([^)]*)\)/g;
1500
+ let match;
1501
+ while ((match = imageRegex.exec(lineText)) !== null) {
1502
+ const matchFrom = lineStart + match.index;
1503
+ const matchTo = matchFrom + match[0].length;
1504
+ if (from >= matchFrom && to <= matchTo) {
1505
+ const imageUrl = match[2] || "";
1506
+ view.dispatch({
1507
+ changes: { from: matchFrom, to: matchTo, insert: imageUrl },
1508
+ selection: { anchor: matchFrom, head: matchFrom + imageUrl.length }
1509
+ });
1510
+ return true;
1511
+ }
1512
+ }
1513
+ if (empty) {
1514
+ const defaultAlt = "Alt Text";
1515
+ const newText = `![${defaultAlt}]()`;
1516
+ view.dispatch({
1517
+ changes: { from, insert: newText },
1518
+ selection: { anchor: from + defaultAlt.length + 4 }
1519
+ // After ![Alt Text](
1520
+ });
1521
+ } else if (this.urlPattern.test(selectedText)) {
1522
+ const defaultAlt = "Alt Text";
1523
+ const newText = `![${defaultAlt}](${selectedText})`;
1524
+ view.dispatch({
1525
+ changes: { from, to, insert: newText },
1526
+ selection: { anchor: from + 2, head: from + 2 + defaultAlt.length }
1527
+ // Select "Alt Text"
1528
+ });
1529
+ } else {
1530
+ const newText = `![${selectedText}]()`;
1531
+ view.dispatch({
1532
+ changes: { from, to, insert: newText },
1533
+ selection: { anchor: from + selectedText.length + 4 }
1534
+ // After ![text](
1535
+ });
1536
+ }
1537
+ return true;
1538
+ }
1539
+ buildDecorations(ctx) {
1540
+ const { view: view$1, decorations } = ctx;
1541
+ const tree = language.syntaxTree(view$1.state);
1542
+ tree.iterate({
1543
+ enter: (node) => {
1544
+ const { from, to, name } = node;
1545
+ if (name === "Image") {
1546
+ const content = view$1.state.sliceDoc(from, to);
1547
+ const parsed = parseImageMarkdown(content);
1548
+ if (!parsed) return;
1549
+ const cursorInRange = ctx.selectionOverlapsRange(from, to);
1550
+ decorations.push(imageMarkDecorations["image-block"].range(from));
1551
+ decorations.push(
1552
+ view.Decoration.widget({
1553
+ widget: new ImageWidget(parsed.url, parsed.alt, from, to, parsed.title),
1554
+ side: 1,
1555
+ // Place after the position
1556
+ block: false
1557
+ // Don't create a new line
1558
+ }).range(to)
1559
+ );
1560
+ if (cursorInRange) {
1561
+ this.decorateRawImage(node.node, decorations, view$1);
1562
+ } else {
1563
+ decorations.push(imageMarkDecorations["image-hidden"].range(from, to));
1564
+ }
1565
+ }
1566
+ }
1567
+ });
1568
+ }
1569
+ /**
1570
+ * Decorate raw image markdown when cursor is in range
1571
+ */
1572
+ decorateRawImage(node, decorations, view) {
1573
+ for (let child = node.firstChild; child; child = child.nextSibling) {
1574
+ if (child.name === "URL") {
1575
+ decorations.push(imageMarkDecorations["image-url"].range(child.from, child.to));
1576
+ }
1577
+ }
1578
+ const content = view.state.sliceDoc(node.from, node.to);
1579
+ const bangBracket = node.from;
1580
+ if (content.startsWith("![")) {
1581
+ decorations.push(imageMarkDecorations["image-marker"].range(bangBracket, bangBracket + 2));
1582
+ }
1583
+ const altEnd = content.indexOf("](");
1584
+ if (altEnd !== -1) {
1585
+ const altStart = 2;
1586
+ if (altEnd > altStart) {
1587
+ decorations.push(imageMarkDecorations["image-alt"].range(node.from + altStart, node.from + altEnd));
1588
+ }
1589
+ decorations.push(imageMarkDecorations["image-marker"].range(node.from + altEnd, node.from + altEnd + 2));
1590
+ decorations.push(imageMarkDecorations["image-marker"].range(node.to - 1, node.to));
1591
+ }
1592
+ }
1593
+ /**
1594
+ * Render image to HTML for preview mode using figure/figcaption
1595
+ */
1596
+ renderToHTML(node, _children, ctx) {
1597
+ if (node.name !== "Image") return null;
1598
+ const content = ctx.sliceDoc(node.from, node.to);
1599
+ const parsed = parseImageMarkdown(content);
1600
+ if (!parsed) return null;
1601
+ const altAttr = ctx.sanitize(parsed.alt);
1602
+ const titleAttr = parsed.title ? ` title="${ctx.sanitize(parsed.title)}"` : "";
1603
+ const ariaLabel = parsed.title ? ` aria-label="${ctx.sanitize(parsed.title)}"` : "";
1604
+ let html = `<figure class="cm-draftly-image-figure" role="figure"${ariaLabel}>`;
1605
+ html += `<img class="cm-draftly-image" src="${ctx.sanitize(parsed.url)}" alt="${altAttr}"${titleAttr} loading="lazy" decoding="async" />`;
1606
+ if (parsed.title) {
1607
+ html += `<figcaption class="cm-draftly-image-caption">${ctx.sanitize(parsed.title)}</figcaption>`;
1608
+ }
1609
+ html += `</figure>`;
1610
+ return html;
1611
+ }
1612
+ };
1613
+ var theme7 = chunkKDEDLC3D_cjs.createTheme({
1614
+ default: {
1615
+ ".cm-draftly-image-block br": {
1616
+ display: "none"
1617
+ },
1618
+ // Image markers (! [ ] ( ))
1619
+ ".cm-draftly-image-marker": {
1620
+ color: "#6a737d",
1621
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
1622
+ },
1623
+ // Alt text
1624
+ ".cm-draftly-image-alt": {
1625
+ color: "#22863a",
1626
+ fontStyle: "italic"
1627
+ },
1628
+ // URL
1629
+ ".cm-draftly-image-url": {
1630
+ color: "#0366d6",
1631
+ textDecoration: "underline"
1632
+ },
1633
+ // Hidden markdown syntax (when cursor is not in range)
1634
+ ".cm-draftly-image-hidden": {
1635
+ display: "none"
1636
+ },
1637
+ // Figure container
1638
+ ".cm-draftly-image-figure": {
1639
+ display: "flex",
1640
+ flexDirection: "column",
1641
+ alignItems: "start",
1642
+ maxWidth: "100%",
1643
+ padding: "0"
1644
+ },
1645
+ // Image element
1646
+ ".cm-draftly-image": {
1647
+ maxWidth: "100%",
1648
+ maxHeight: "800px",
1649
+ height: "auto",
1650
+ borderRadius: "4px"
1651
+ },
1652
+ // Figcaption
1653
+ ".cm-draftly-image-caption": {
1654
+ display: "block",
1655
+ width: "100%",
1656
+ fontSize: "0.875em",
1657
+ color: "#6a737d",
1658
+ marginTop: "0.5em",
1659
+ textAlign: "center",
1660
+ fontStyle: "italic"
1661
+ },
1662
+ // Error state
1663
+ ".cm-draftly-image-error": {
1664
+ display: "inline-block",
1665
+ padding: "0.5em 1em",
1666
+ backgroundColor: "rgba(255, 0, 0, 0.1)",
1667
+ color: "#d73a49",
1668
+ borderRadius: "4px",
1669
+ fontSize: "0.875em",
1670
+ fontStyle: "italic"
1671
+ }
1672
+ },
1673
+ dark: {
1674
+ ".cm-draftly-image-marker": {
1675
+ color: "#8b949e"
1676
+ },
1677
+ ".cm-draftly-image-alt": {
1678
+ color: "#7ee787"
1679
+ },
1680
+ ".cm-draftly-image-url": {
1681
+ color: "#58a6ff"
1682
+ },
1683
+ ".cm-draftly-image-caption": {
1684
+ color: "#8b949e"
1685
+ },
1686
+ ".cm-draftly-image-error": {
1687
+ backgroundColor: "rgba(255, 0, 0, 0.15)",
1688
+ color: "#f85149"
1689
+ }
1690
+ }
1691
+ });
1692
+ function injectKatexStyles() {
1693
+ if (typeof document === "undefined") return;
1694
+ if (document.getElementById("draftly-katex-styles")) return;
1695
+ const style = document.createElement("style");
1696
+ style.id = "draftly-katex-styles";
1697
+ style.textContent = katexCss__default.default;
1698
+ document.head.appendChild(style);
1699
+ }
1700
+ injectKatexStyles();
1701
+ var DOLLAR = 36;
1702
+ var mathMarkDecorations = {
1703
+ "math-block": view.Decoration.line({ class: "cm-draftly-math-block" }),
1704
+ "math-inline": view.Decoration.mark({ class: "cm-draftly-math-inline" }),
1705
+ "math-marker": view.Decoration.mark({ class: "cm-draftly-math-marker" }),
1706
+ "math-hidden": view.Decoration.mark({ class: "cm-draftly-math-hidden" })
1707
+ };
1708
+ function renderMath(latex, displayMode) {
1709
+ try {
1710
+ const html = katex__default.default.renderToString(latex, {
1711
+ displayMode,
1712
+ throwOnError: false,
1713
+ errorColor: "#d73a49",
1714
+ trust: false,
1715
+ strict: false
1716
+ });
1717
+ return { html, error: null };
1718
+ } catch (e) {
1719
+ const errorMsg = e instanceof Error ? e.message : "Unknown error";
1720
+ return { html: "", error: errorMsg };
1721
+ }
1722
+ }
1723
+ var InlineMathWidget = class extends view.WidgetType {
1724
+ constructor(latex, from, to) {
1725
+ super();
1726
+ this.latex = latex;
1727
+ this.from = from;
1728
+ this.to = to;
1729
+ }
1730
+ eq(other) {
1731
+ return other.latex === this.latex && other.from === this.from && other.to === this.to;
1732
+ }
1733
+ toDOM(view) {
1734
+ const span = document.createElement("span");
1735
+ span.className = "cm-draftly-math-rendered cm-draftly-math-rendered-inline";
1736
+ span.style.cursor = "pointer";
1737
+ const { html, error } = renderMath(this.latex, false);
1738
+ if (error) {
1739
+ span.className += " cm-draftly-math-error";
1740
+ span.textContent = `[Math Error: ${error}]`;
1741
+ } else {
1742
+ span.innerHTML = html;
1743
+ }
1744
+ span.addEventListener("click", (e) => {
1745
+ e.preventDefault();
1746
+ e.stopPropagation();
1747
+ view.dispatch({
1748
+ selection: { anchor: this.from, head: this.to },
1749
+ scrollIntoView: true
1750
+ });
1751
+ view.focus();
1752
+ });
1753
+ return span;
1754
+ }
1755
+ ignoreEvent(event) {
1756
+ return event.type !== "click";
1757
+ }
1758
+ };
1759
+ var MathBlockWidget = class extends view.WidgetType {
1760
+ constructor(latex, from, to) {
1761
+ super();
1762
+ this.latex = latex;
1763
+ this.from = from;
1764
+ this.to = to;
1765
+ }
1766
+ eq(other) {
1767
+ return other.latex === this.latex && other.from === this.from && other.to === this.to;
1768
+ }
1769
+ toDOM(view) {
1770
+ const div = document.createElement("div");
1771
+ div.className = "cm-draftly-math-rendered cm-draftly-math-rendered-block";
1772
+ div.style.cursor = "pointer";
1773
+ const { html, error } = renderMath(this.latex, true);
1774
+ if (error) {
1775
+ div.className += " cm-draftly-math-error";
1776
+ div.textContent = `[Math Error: ${error}]`;
1777
+ } else {
1778
+ div.innerHTML = html;
1779
+ }
1780
+ div.addEventListener("click", (e) => {
1781
+ e.preventDefault();
1782
+ e.stopPropagation();
1783
+ view.dispatch({
1784
+ selection: { anchor: this.from, head: this.to },
1785
+ scrollIntoView: true
1786
+ });
1787
+ view.focus();
1788
+ });
1789
+ return div;
1790
+ }
1791
+ ignoreEvent(event) {
1792
+ return event.type !== "click";
1793
+ }
1794
+ };
1795
+ var inlineMathParser = {
1796
+ name: "InlineMath",
1797
+ parse(cx, next, pos) {
1798
+ if (next !== DOLLAR) return -1;
1799
+ if (cx.char(pos + 1) === DOLLAR) return -1;
1800
+ let end = pos + 1;
1801
+ while (end < cx.end) {
1802
+ const char = cx.char(end);
1803
+ if (char === DOLLAR) {
1804
+ if (cx.char(end + 1) !== DOLLAR) {
1805
+ const content = cx.slice(pos + 1, end);
1806
+ if (content.trim().length === 0) return -1;
1807
+ const openMark = cx.elt("InlineMathMark", pos, pos + 1);
1808
+ const closeMark = cx.elt("InlineMathMark", end, end + 1);
1809
+ const inlineMath = cx.elt("InlineMath", pos, end + 1, [openMark, closeMark]);
1810
+ return cx.addElement(inlineMath);
1811
+ }
1812
+ return -1;
1813
+ }
1814
+ if (char === 92) {
1815
+ end += 2;
1816
+ continue;
1817
+ }
1818
+ end++;
1819
+ }
1820
+ return -1;
1821
+ }
1822
+ };
1823
+ var mathBlockParser = {
1824
+ name: "MathBlock",
1825
+ parse(cx, line) {
1826
+ const text = line.text;
1827
+ const trimmed = text.slice(line.pos).trimStart();
1828
+ if (!trimmed.startsWith("$$")) return false;
1829
+ const startLine = cx.lineStart;
1830
+ let endPos = -1;
1831
+ let lastLineEnd = startLine + line.text.length;
1832
+ while (cx.nextLine()) {
1833
+ const currentText = line.text;
1834
+ lastLineEnd = cx.lineStart + currentText.length;
1835
+ if (currentText.trimEnd().endsWith("$$")) {
1836
+ endPos = lastLineEnd;
1837
+ cx.nextLine();
1838
+ break;
1839
+ }
1840
+ }
1841
+ if (endPos === -1) {
1842
+ return false;
1843
+ }
1844
+ const openMark = cx.elt("MathBlockMark", startLine, startLine + text.indexOf("$$") + 2);
1845
+ const closeMark = cx.elt("MathBlockMark", endPos - 2, endPos);
1846
+ cx.addElement(cx.elt("MathBlock", startLine, endPos, [openMark, closeMark]));
1847
+ return true;
1848
+ }
1849
+ };
1850
+ var MathPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
1851
+ name = "math";
1852
+ version = "1.0.0";
1853
+ decorationPriority = 25;
1854
+ requiredNodes = ["InlineMath", "MathBlock", "InlineMathMark", "MathBlockMark"];
1855
+ constructor() {
1856
+ super();
1857
+ }
1858
+ /**
1859
+ * Plugin theme
1860
+ */
1861
+ get theme() {
1862
+ return theme8;
1863
+ }
1864
+ /**
1865
+ * Return markdown parser extensions for math syntax
1866
+ */
1867
+ getMarkdownConfig() {
1868
+ return {
1869
+ defineNodes: [
1870
+ { name: "InlineMath", style: highlight.tags.emphasis },
1871
+ { name: "InlineMathMark", style: highlight.tags.processingInstruction },
1872
+ { name: "MathBlock", block: true },
1873
+ { name: "MathBlockMark", style: highlight.tags.processingInstruction }
1874
+ ],
1875
+ parseInline: [inlineMathParser],
1876
+ parseBlock: [mathBlockParser]
1877
+ };
1878
+ }
1879
+ /**
1880
+ * Build decorations for math expressions
1881
+ */
1882
+ buildDecorations(ctx) {
1883
+ const { view: view$1, decorations } = ctx;
1884
+ const tree = language.syntaxTree(view$1.state);
1885
+ tree.iterate({
1886
+ enter: (node) => {
1887
+ const { from, to, name } = node;
1888
+ if (name === "InlineMath") {
1889
+ const content = view$1.state.sliceDoc(from, to);
1890
+ const latex = content.slice(1, -1);
1891
+ const cursorInRange = ctx.selectionOverlapsRange(from, to);
1892
+ if (cursorInRange) {
1893
+ decorations.push(mathMarkDecorations["math-inline"].range(from, to));
1894
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
1895
+ if (child.name === "InlineMathMark") {
1896
+ decorations.push(mathMarkDecorations["math-marker"].range(child.from, child.to));
1897
+ }
1898
+ }
1899
+ } else {
1900
+ decorations.push(
1901
+ view.Decoration.replace({
1902
+ widget: new InlineMathWidget(latex, from, to)
1903
+ }).range(from, to)
1904
+ );
1905
+ }
1906
+ }
1907
+ if (name === "MathBlock") {
1908
+ const content = view$1.state.sliceDoc(from, to);
1909
+ const lines = content.split("\n");
1910
+ const latex = lines.slice(1, -1).join("\n").trim();
1911
+ const singleLine = !content.includes("\n");
1912
+ const latexContent = singleLine ? content.slice(2, -2).trim() : latex;
1913
+ const nodeLineStart = view$1.state.doc.lineAt(from);
1914
+ const nodeLineEnd = view$1.state.doc.lineAt(to);
1915
+ const cursorInRange = ctx.selectionOverlapsRange(nodeLineStart.from, nodeLineEnd.to);
1916
+ decorations.push(mathMarkDecorations["math-block"].range(from));
1917
+ decorations.push(
1918
+ view.Decoration.widget({
1919
+ widget: new MathBlockWidget(latexContent, from, to),
1920
+ side: 1,
1921
+ block: false
1922
+ }).range(to)
1923
+ );
1924
+ for (let i = nodeLineStart.number; i <= nodeLineEnd.number; i++) {
1925
+ const line = view$1.state.doc.line(i);
1926
+ decorations.push(mathMarkDecorations["math-block"].range(line.from));
1927
+ }
1928
+ if (cursorInRange) {
1929
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
1930
+ if (child.name === "MathBlockMark") {
1931
+ decorations.push(mathMarkDecorations["math-marker"].range(child.from, child.to));
1932
+ }
1933
+ }
1934
+ } else {
1935
+ decorations.push(mathMarkDecorations["math-hidden"].range(from, to));
1936
+ }
1937
+ }
1938
+ }
1939
+ });
1940
+ }
1941
+ /**
1942
+ * Render math to HTML for preview mode
1943
+ */
1944
+ renderToHTML(node, _children, ctx) {
1945
+ if (node.name === "InlineMath") {
1946
+ const content = ctx.sliceDoc(node.from, node.to);
1947
+ const latex = content.slice(1, -1);
1948
+ const { html, error } = renderMath(latex, false);
1949
+ if (error) {
1950
+ return `<span class="cm-draftly-math-error">[Math Error: ${ctx.sanitize(error)}]</span>`;
1951
+ }
1952
+ return `<span class="cm-draftly-math-rendered cm-draftly-math-rendered-inline">${html}</span>`;
1953
+ }
1954
+ if (node.name === "MathBlock") {
1955
+ const content = ctx.sliceDoc(node.from, node.to);
1956
+ const lines = content.split("\n");
1957
+ const latex = lines.length > 1 ? lines.slice(1, -1).join("\n").trim() : content.slice(2, -2).trim();
1958
+ const { html, error } = renderMath(latex, true);
1959
+ if (error) {
1960
+ return `<div class="cm-draftly-math-error">[Math Error: ${ctx.sanitize(error)}]</div>`;
1961
+ }
1962
+ return `<div class="cm-draftly-math-rendered cm-draftly-math-rendered-block">${html}</div>`;
1963
+ }
1964
+ if (node.name === "InlineMathMark" || node.name === "MathBlockMark") {
1965
+ return "";
1966
+ }
1967
+ return null;
1968
+ }
1969
+ };
1970
+ var theme8 = chunkKDEDLC3D_cjs.createTheme({
1971
+ default: {
1972
+ ".cm-draftly-math-block": {
1973
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
1974
+ },
1975
+ ".cm-draftly-math-block br": {
1976
+ display: "none"
1977
+ },
1978
+ // Math markers ($ $$)
1979
+ ".cm-draftly-math-marker": {
1980
+ color: "#6a737d",
1981
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
1982
+ },
1983
+ // Inline math styling when editing
1984
+ ".cm-draftly-math-inline": {
1985
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
1986
+ fontSize: "0.9em"
1987
+ },
1988
+ // Hidden math syntax (when cursor is not in range)
1989
+ ".cm-draftly-math-hidden": {
1990
+ display: "none"
1991
+ },
1992
+ // Hidden line (for multi-line blocks)
1993
+ ".cm-draftly-hidden-line": {
1994
+ display: "none"
1995
+ },
1996
+ // Rendered math container (both inline and block)
1997
+ ".cm-draftly-math-rendered": {
1998
+ fontFamily: "KaTeX_Main, 'Times New Roman', serif"
1999
+ },
2000
+ // Inline rendered math
2001
+ ".cm-draftly-math-rendered-inline": {
2002
+ display: "inline",
2003
+ verticalAlign: "baseline"
2004
+ },
2005
+ // Block rendered math (display mode)
2006
+ ".cm-draftly-math-rendered-block": {
2007
+ display: "flex",
2008
+ justifyContent: "center",
2009
+ alignItems: "center",
2010
+ padding: "1em 0",
2011
+ backgroundColor: "rgba(0, 0, 0, 0.02)",
2012
+ borderRadius: "4px",
2013
+ overflow: "auto"
2014
+ },
2015
+ // Math error styling
2016
+ ".cm-draftly-math-error": {
2017
+ display: "inline-block",
2018
+ padding: "0.25em 0.5em",
2019
+ backgroundColor: "rgba(255, 0, 0, 0.1)",
2020
+ color: "#d73a49",
2021
+ borderRadius: "4px",
2022
+ fontSize: "0.875em",
2023
+ fontStyle: "italic",
2024
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
2025
+ }
2026
+ },
2027
+ dark: {
2028
+ ".cm-draftly-math-marker": {
2029
+ color: "#8b949e"
2030
+ },
2031
+ ".cm-draftly-math-rendered-block": {
2032
+ backgroundColor: "rgba(255, 255, 255, 0.02)"
2033
+ },
2034
+ ".cm-draftly-math-error": {
2035
+ backgroundColor: "rgba(255, 0, 0, 0.15)",
2036
+ color: "#f85149"
2037
+ }
2038
+ }
2039
+ });
2040
+ mermaid__default.default.initialize({
2041
+ startOnLoad: false,
2042
+ theme: "default",
2043
+ suppressErrorRendering: true
2044
+ });
2045
+ var mermaidCounter = 0;
2046
+ async function renderMermaid(definition, options = {}, defaultTheme = "default") {
2047
+ try {
2048
+ const id = `draftly-mermaid-${mermaidCounter++}`;
2049
+ let finalDefinition = definition;
2050
+ const mermaidConfig = {};
2051
+ if (options.theme) {
2052
+ mermaidConfig.theme = options.theme;
2053
+ } else {
2054
+ mermaidConfig.theme = defaultTheme;
2055
+ }
2056
+ if (Object.keys(mermaidConfig).length > 0) {
2057
+ const jsonConfig = JSON.stringify(mermaidConfig);
2058
+ finalDefinition = `%%{init: ${jsonConfig} }%%
2059
+ ${definition}`;
2060
+ }
2061
+ const { svg } = await mermaid__default.default.render(id, finalDefinition);
2062
+ return { svg, error: null };
2063
+ } catch (e) {
2064
+ const errorMsg = e instanceof Error ? e.message : "Unknown error";
2065
+ return { svg: "", error: errorMsg };
2066
+ }
2067
+ }
2068
+ function parseAttributes(fenceLine) {
2069
+ const attributes = {};
2070
+ const regex = /(\w+)=["']([^"']*)["']/g;
2071
+ let match;
2072
+ while ((match = regex.exec(fenceLine)) !== null && match[1] && match[2]) {
2073
+ attributes[match[1]] = match[2];
2074
+ }
2075
+ return attributes;
2076
+ }
2077
+ var mermaidMarkDecorations = {
2078
+ "mermaid-block-start": view.Decoration.line({ class: "cm-draftly-mermaid-block-start" }),
2079
+ "mermaid-block-end": view.Decoration.line({ class: "cm-draftly-mermaid-block-end" }),
2080
+ "mermaid-block": view.Decoration.line({ class: "cm-draftly-mermaid-block" }),
2081
+ "mermaid-block-rendered": view.Decoration.line({ class: "cm-draftly-mermaid-block-rendered" }),
2082
+ "mermaid-marker": view.Decoration.mark({ class: "cm-draftly-mermaid-marker" }),
2083
+ "mermaid-hidden": view.Decoration.mark({ class: "cm-draftly-mermaid-hidden" })
2084
+ };
2085
+ var MermaidBlockWidget = class extends view.WidgetType {
2086
+ constructor(definition, attributes, defaultTheme, from, to) {
2087
+ super();
2088
+ this.definition = definition;
2089
+ this.attributes = attributes;
2090
+ this.defaultTheme = defaultTheme;
2091
+ this.from = from;
2092
+ this.to = to;
2093
+ }
2094
+ eq(other) {
2095
+ return other.definition === this.definition && JSON.stringify(other.attributes) === JSON.stringify(this.attributes) && other.defaultTheme === this.defaultTheme && other.from === this.from && other.to === this.to;
2096
+ }
2097
+ toDOM(view) {
2098
+ const div = document.createElement("div");
2099
+ div.className = "cm-draftly-mermaid-rendered";
2100
+ div.style.cursor = "pointer";
2101
+ div.innerHTML = `<div class="cm-draftly-mermaid-loading">Rendering diagram\u2026</div>`;
2102
+ renderMermaid(this.definition, this.attributes, this.defaultTheme).then(({ svg, error }) => {
2103
+ if (error) {
2104
+ div.className += " cm-draftly-mermaid-error";
2105
+ div.innerHTML = `<span>[Mermaid Error: ${error}]</span>`;
2106
+ } else {
2107
+ div.innerHTML = svg;
2108
+ }
2109
+ });
2110
+ div.addEventListener("click", (e) => {
2111
+ e.preventDefault();
2112
+ e.stopPropagation();
2113
+ view.dispatch({
2114
+ selection: { anchor: this.from, head: this.to },
2115
+ scrollIntoView: true
2116
+ });
2117
+ view.focus();
2118
+ });
2119
+ return div;
2120
+ }
2121
+ ignoreEvent(event) {
2122
+ return event.type !== "click";
2123
+ }
2124
+ };
2125
+ var mermaidBlockParser = {
2126
+ name: "MermaidBlock",
2127
+ before: "FencedCode",
2128
+ parse(cx, line) {
2129
+ const text = line.text;
2130
+ const trimmed = text.slice(line.pos).trimStart();
2131
+ if (!trimmed.startsWith("```mermaid")) return false;
2132
+ const startLine = cx.lineStart;
2133
+ let endPos = -1;
2134
+ let closeBacktickStart = -1;
2135
+ while (cx.nextLine()) {
2136
+ const currentText = line.text;
2137
+ const currentLineStart = cx.lineStart;
2138
+ const lastLineEnd = currentLineStart + currentText.length;
2139
+ const trimmedLine = currentText.trim();
2140
+ if (trimmedLine === "```") {
2141
+ endPos = lastLineEnd;
2142
+ closeBacktickStart = currentLineStart + currentText.indexOf("```");
2143
+ cx.nextLine();
2144
+ break;
2145
+ }
2146
+ }
2147
+ if (endPos === -1) {
2148
+ return false;
2149
+ }
2150
+ const openMarkEnd = startLine + text.indexOf("```mermaid") + 10;
2151
+ const openMark = cx.elt("MermaidBlockMark", startLine, openMarkEnd);
2152
+ const closeMark = cx.elt("MermaidBlockMark", closeBacktickStart, closeBacktickStart + 3);
2153
+ cx.addElement(cx.elt("MermaidBlock", startLine, endPos, [openMark, closeMark]));
2154
+ return true;
2155
+ }
2156
+ };
2157
+ var MermaidPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
2158
+ name = "mermaid";
2159
+ version = "1.0.0";
2160
+ decorationPriority = 25;
2161
+ requiredNodes = ["MermaidBlock", "MermaidBlockMark"];
2162
+ constructor() {
2163
+ super();
2164
+ }
2165
+ /**
2166
+ * Plugin theme
2167
+ */
2168
+ get theme() {
2169
+ return theme9;
2170
+ }
2171
+ /**
2172
+ * Return markdown parser extensions for mermaid syntax
2173
+ */
2174
+ getMarkdownConfig() {
2175
+ return {
2176
+ defineNodes: [
2177
+ { name: "MermaidBlock", block: true },
2178
+ { name: "MermaidBlockMark", style: highlight.tags.processingInstruction }
2179
+ ],
2180
+ parseBlock: [mermaidBlockParser]
2181
+ };
2182
+ }
2183
+ /**
2184
+ * Build decorations for mermaid blocks
2185
+ */
2186
+ buildDecorations(ctx) {
2187
+ const { view: view$1, decorations } = ctx;
2188
+ const tree = language.syntaxTree(view$1.state);
2189
+ const config = this.context?.config;
2190
+ const currentTheme = config?.theme === "dark" /* DARK */ ? "dark" : "default";
2191
+ tree.iterate({
2192
+ enter: (node) => {
2193
+ const { from, to, name } = node;
2194
+ if (name === "MermaidBlock") {
2195
+ const content = view$1.state.sliceDoc(from, to);
2196
+ const lines = content.split("\n");
2197
+ const definition = lines.slice(1, -1).join("\n").trim();
2198
+ const docLines = content.split("\n");
2199
+ const fenceLine = docLines[0] || "";
2200
+ const attributes = parseAttributes(fenceLine);
2201
+ const nodeLineStart = view$1.state.doc.lineAt(from);
2202
+ const nodeLineEnd = view$1.state.doc.lineAt(to);
2203
+ const cursorInRange = ctx.selectionOverlapsRange(nodeLineStart.from, nodeLineEnd.to);
2204
+ const totalCodeLines = nodeLineEnd.number - nodeLineStart.number - 1;
2205
+ const lineNumWidth = String(totalCodeLines).length;
2206
+ let codeLineIndex = 1;
2207
+ for (let i = nodeLineStart.number; i <= nodeLineEnd.number; i++) {
2208
+ const line = view$1.state.doc.line(i);
2209
+ const isFenceLine = i === nodeLineStart.number || i === nodeLineEnd.number;
2210
+ const relativeLineNum = codeLineIndex;
2211
+ decorations.push(mermaidMarkDecorations["mermaid-block"].range(line.from));
2212
+ if (!cursorInRange) decorations.push(mermaidMarkDecorations["mermaid-block-rendered"].range(line.from));
2213
+ if (i === nodeLineStart.number)
2214
+ decorations.push(mermaidMarkDecorations["mermaid-block-start"].range(line.from));
2215
+ if (i === nodeLineEnd.number)
2216
+ decorations.push(mermaidMarkDecorations["mermaid-block-end"].range(line.from));
2217
+ if (!isFenceLine) {
2218
+ decorations.push(
2219
+ view.Decoration.line({
2220
+ attributes: {
2221
+ "data-line-num": String(relativeLineNum),
2222
+ style: `--line-num-width: ${lineNumWidth}ch`
2223
+ }
2224
+ }).range(line.from)
2225
+ );
2226
+ }
2227
+ if (!isFenceLine) {
2228
+ codeLineIndex++;
2229
+ }
2230
+ }
2231
+ decorations.push(
2232
+ view.Decoration.widget({
2233
+ widget: new MermaidBlockWidget(definition, attributes, currentTheme, from, to),
2234
+ side: 1,
2235
+ block: false
2236
+ }).range(to)
2237
+ );
2238
+ if (cursorInRange) {
2239
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
2240
+ if (child.name === "MermaidBlockMark") {
2241
+ decorations.push(mermaidMarkDecorations["mermaid-marker"].range(child.from, child.to));
2242
+ }
2243
+ }
2244
+ } else {
2245
+ decorations.push(mermaidMarkDecorations["mermaid-hidden"].range(from, to));
2246
+ }
2247
+ }
2248
+ }
2249
+ });
2250
+ }
2251
+ /**
2252
+ * Render mermaid to HTML for preview mode
2253
+ *
2254
+ * Renders the actual mermaid diagram to SVG HTML
2255
+ */
2256
+ async renderToHTML(node, _children, ctx) {
2257
+ if (node.name === "MermaidBlock") {
2258
+ const content = ctx.sliceDoc(node.from, node.to);
2259
+ const lines = content.split("\n");
2260
+ const definition = lines.length > 1 ? lines.slice(1, -1).join("\n").trim() : "";
2261
+ const fenceLine = lines[0] || "";
2262
+ const attributes = parseAttributes(fenceLine);
2263
+ const config = this.context?.config;
2264
+ const currentTheme = config?.theme === "dark" /* DARK */ ? "dark" : "default";
2265
+ const { svg, error } = await renderMermaid(definition, attributes, currentTheme);
2266
+ if (error) {
2267
+ return `<div class="cm-draftly-mermaid-error">${ctx.sanitize(`[Mermaid Error: ${error}]`)}</div>`;
2268
+ }
2269
+ return `<div class="cm-draftly-mermaid-rendered">${svg}</div>`;
2270
+ }
2271
+ if (node.name === "MermaidBlockMark") {
2272
+ return "";
2273
+ }
2274
+ return null;
2275
+ }
2276
+ };
2277
+ var theme9 = chunkKDEDLC3D_cjs.createTheme({
2278
+ default: {
2279
+ // Raw mermaid block lines (monospace)
2280
+ ".cm-draftly-mermaid-block:not(.cm-draftly-mermaid-block-rendered)": {
2281
+ "--radius": "0.375rem",
2282
+ position: "relative",
2283
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
2284
+ fontSize: "0.9rem",
2285
+ backgroundColor: "rgba(0, 0, 0, 0.03)",
2286
+ padding: "0 1rem !important",
2287
+ paddingLeft: "calc(var(--line-num-width, 2ch) + 1rem) !important",
2288
+ lineHeight: "1.5",
2289
+ borderLeft: "1px solid var(--color-border)",
2290
+ borderRight: "1px solid var(--color-border)"
2291
+ },
2292
+ ".cm-draftly-mermaid-block-start:not(.cm-draftly-mermaid-block-rendered)": {
2293
+ overflow: "hidden",
2294
+ borderTopLeftRadius: "var(--radius)",
2295
+ borderTopRightRadius: "var(--radius)",
2296
+ borderTop: "1px solid var(--color-border)"
2297
+ },
2298
+ ".cm-draftly-mermaid-block-end:not(.cm-draftly-mermaid-block-rendered)": {
2299
+ overflow: "hidden",
2300
+ borderBottomLeftRadius: "var(--radius)",
2301
+ borderBottomRightRadius: "var(--radius)",
2302
+ borderBottom: "1px solid var(--color-border)"
2303
+ },
2304
+ ".cm-draftly-mermaid-block:not(.cm-draftly-mermaid-block-rendered)::before": {
2305
+ content: "attr(data-line-num)",
2306
+ position: "absolute",
2307
+ left: "0.5rem",
2308
+ top: "0.2rem",
2309
+ width: "var(--line-num-width, 2ch)",
2310
+ textAlign: "right",
2311
+ color: "#6a737d",
2312
+ opacity: "0.6",
2313
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
2314
+ fontSize: "0.85rem",
2315
+ userSelect: "none"
2316
+ },
2317
+ ".cm-draftly-mermaid-block.cm-draftly-mermaid-block-rendered br": {
2318
+ display: "none"
2319
+ },
2320
+ // Mermaid markers (```mermaid / ```)
2321
+ ".cm-draftly-mermaid-marker": {
2322
+ color: "#6a737d",
2323
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
2324
+ },
2325
+ // Hidden mermaid syntax (when cursor is not in range)
2326
+ ".cm-draftly-mermaid-hidden": {
2327
+ display: "none"
2328
+ },
2329
+ // Rendered mermaid container
2330
+ ".cm-draftly-mermaid-rendered": {
2331
+ display: "flex",
2332
+ justifyContent: "center",
2333
+ alignItems: "center",
2334
+ padding: "1em 0",
2335
+ borderRadius: "4px",
2336
+ overflow: "auto"
2337
+ },
2338
+ // SVG inside rendered container
2339
+ ".cm-draftly-mermaid-rendered svg": {
2340
+ maxWidth: "100%",
2341
+ height: "auto",
2342
+ aspectRatio: "auto"
2343
+ },
2344
+ // Loading state
2345
+ ".cm-draftly-mermaid-loading": {
2346
+ display: "inline-block",
2347
+ padding: "0.5em 1em",
2348
+ color: "#6a737d",
2349
+ fontSize: "0.875em",
2350
+ fontStyle: "italic",
2351
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
2352
+ },
2353
+ // Error styling
2354
+ ".cm-draftly-mermaid-error": {
2355
+ display: "inline-block",
2356
+ padding: "0.25em 0.5em",
2357
+ backgroundColor: "rgba(255, 0, 0, 0.1)",
2358
+ color: "#d73a49",
2359
+ borderRadius: "4px",
2360
+ fontSize: "0.875em",
2361
+ fontStyle: "italic",
2362
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
2363
+ }
2364
+ },
2365
+ dark: {
2366
+ ".cm-draftly-mermaid-block:not(.cm-draftly-mermaid-block-rendered)": {
2367
+ backgroundColor: "rgba(255, 255, 255, 0.03)"
2368
+ },
2369
+ ".cm-draftly-mermaid-marker": {
2370
+ color: "#8b949e"
2371
+ },
2372
+ ".cm-draftly-mermaid-loading": {
2373
+ color: "#8b949e"
2374
+ },
2375
+ ".cm-draftly-mermaid-error": {
2376
+ backgroundColor: "rgba(255, 0, 0, 0.15)",
2377
+ color: "#f85149"
2378
+ }
2379
+ }
2380
+ });
2381
+ var COPY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
2382
+ var CHECK_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
2383
+ var COPY_RESET_DELAY = 2e3;
2384
+ var codeMarkDecorations = {
2385
+ // Inline code
2386
+ "inline-code": view.Decoration.mark({ class: "cm-draftly-code-inline" }),
2387
+ "inline-mark": view.Decoration.replace({}),
2388
+ // Fenced code block
2389
+ "code-block-line": view.Decoration.line({ class: "cm-draftly-code-block-line" }),
2390
+ "code-block-line-start": view.Decoration.line({ class: "cm-draftly-code-block-line-start" }),
2391
+ "code-block-line-end": view.Decoration.line({ class: "cm-draftly-code-block-line-end" }),
2392
+ "code-fence": view.Decoration.mark({ class: "cm-draftly-code-fence" }),
2393
+ "code-hidden": view.Decoration.replace({}),
2394
+ // Highlights
2395
+ "code-line-highlight": view.Decoration.line({ class: "cm-draftly-code-line-highlight" }),
2396
+ "code-text-highlight": view.Decoration.mark({ class: "cm-draftly-code-text-highlight" })
2397
+ };
2398
+ var CodeBlockHeaderWidget = class extends view.WidgetType {
2399
+ constructor(props, codeContent) {
2400
+ super();
2401
+ this.props = props;
2402
+ this.codeContent = codeContent;
2403
+ }
2404
+ /** Creates the header DOM element with title/language and optional copy button. */
2405
+ toDOM() {
2406
+ const header = document.createElement("div");
2407
+ header.className = "cm-draftly-code-header";
2408
+ const leftSide = document.createElement("div");
2409
+ leftSide.className = "cm-draftly-code-header-left";
2410
+ if (this.props.title) {
2411
+ const title = document.createElement("span");
2412
+ title.className = "cm-draftly-code-header-title";
2413
+ title.textContent = this.props.title;
2414
+ leftSide.appendChild(title);
2415
+ } else if (this.props.language) {
2416
+ const lang = document.createElement("span");
2417
+ lang.className = "cm-draftly-code-header-lang";
2418
+ lang.textContent = this.props.language;
2419
+ leftSide.appendChild(lang);
2420
+ }
2421
+ header.appendChild(leftSide);
2422
+ if (this.props.copy !== false) {
2423
+ const rightSide = document.createElement("div");
2424
+ rightSide.className = "cm-draftly-code-header-right";
2425
+ const copyBtn = document.createElement("button");
2426
+ copyBtn.className = "cm-draftly-code-copy-btn";
2427
+ copyBtn.type = "button";
2428
+ copyBtn.title = "Copy code";
2429
+ copyBtn.innerHTML = COPY_ICON;
2430
+ copyBtn.addEventListener("click", (e) => {
2431
+ e.preventDefault();
2432
+ e.stopPropagation();
2433
+ navigator.clipboard.writeText(this.codeContent).then(() => {
2434
+ copyBtn.classList.add("copied");
2435
+ copyBtn.innerHTML = CHECK_ICON;
2436
+ setTimeout(() => {
2437
+ copyBtn.classList.remove("copied");
2438
+ copyBtn.innerHTML = COPY_ICON;
2439
+ }, COPY_RESET_DELAY);
2440
+ });
2441
+ });
2442
+ rightSide.appendChild(copyBtn);
2443
+ header.appendChild(rightSide);
2444
+ }
2445
+ return header;
2446
+ }
2447
+ /** Checks equality for widget reuse optimization. */
2448
+ eq(other) {
2449
+ return this.props.title === other.props.title && this.props.language === other.props.language && this.props.copy === other.props.copy && this.codeContent === other.codeContent;
2450
+ }
2451
+ /** Allow click events to propagate for copy button interaction. */
2452
+ ignoreEvent() {
2453
+ return false;
2454
+ }
2455
+ };
2456
+ var CodeBlockCaptionWidget = class extends view.WidgetType {
2457
+ constructor(caption) {
2458
+ super();
2459
+ this.caption = caption;
2460
+ }
2461
+ /** Creates the caption DOM element. */
2462
+ toDOM() {
2463
+ const captionEl = document.createElement("div");
2464
+ captionEl.className = "cm-draftly-code-caption";
2465
+ captionEl.textContent = this.caption;
2466
+ return captionEl;
2467
+ }
2468
+ /** Checks equality for widget reuse optimization. */
2469
+ eq(other) {
2470
+ return this.caption === other.caption;
2471
+ }
2472
+ /** Allow click events to propagate for caption interaction. */
2473
+ ignoreEvent() {
2474
+ return false;
2475
+ }
2476
+ };
2477
+ var CodePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
2478
+ name = "code";
2479
+ version = "1.0.0";
2480
+ decorationPriority = 25;
2481
+ requiredNodes = ["InlineCode", "FencedCode", "CodeMark", "CodeInfo", "CodeText"];
2482
+ /**
2483
+ * Plugin theme
2484
+ */
2485
+ get theme() {
2486
+ return theme10;
2487
+ }
2488
+ /**
2489
+ * Keyboard shortcuts for code formatting
2490
+ */
2491
+ getKeymap() {
2492
+ return [
2493
+ {
2494
+ key: "Mod-e",
2495
+ run: chunkKDEDLC3D_cjs.toggleMarkdownStyle("`"),
2496
+ preventDefault: true
2497
+ },
2498
+ {
2499
+ key: "Mod-Shift-e",
2500
+ run: (view) => this.toggleCodeBlock(view),
2501
+ preventDefault: true
2502
+ }
2503
+ ];
2504
+ }
2505
+ /**
2506
+ * Toggle code block on current line or selected lines
2507
+ */
2508
+ toggleCodeBlock(view) {
2509
+ const { state } = view;
2510
+ const { from, to } = state.selection.main;
2511
+ const startLine = state.doc.lineAt(from);
2512
+ const endLine = state.doc.lineAt(to);
2513
+ const prevLineNum = startLine.number > 1 ? startLine.number - 1 : startLine.number;
2514
+ const nextLineNum = endLine.number < state.doc.lines ? endLine.number + 1 : endLine.number;
2515
+ const prevLine = state.doc.line(prevLineNum);
2516
+ const nextLine = state.doc.line(nextLineNum);
2517
+ const isWrapped = prevLine.text.trim().startsWith("```") && nextLine.text.trim() === "```" && prevLineNum !== startLine.number && nextLineNum !== endLine.number;
2518
+ if (isWrapped) {
2519
+ view.dispatch({
2520
+ changes: [
2521
+ { from: prevLine.from, to: prevLine.to + 1, insert: "" },
2522
+ // Remove opening fence + newline
2523
+ { from: nextLine.from - 1, to: nextLine.to, insert: "" }
2524
+ // Remove newline + closing fence
2525
+ ]
2526
+ });
2527
+ } else {
2528
+ const openFence = "```\n";
2529
+ const closeFence = "\n```";
2530
+ view.dispatch({
2531
+ changes: [
2532
+ { from: startLine.from, insert: openFence },
2533
+ { from: endLine.to, insert: closeFence }
2534
+ ],
2535
+ selection: { anchor: startLine.from + openFence.length, head: endLine.to + openFence.length }
2536
+ });
2537
+ }
2538
+ return true;
2539
+ }
2540
+ /**
2541
+ * Parse CodeInfo string into structured properties
2542
+ *
2543
+ * @param codeInfo - The raw CodeInfo string (e.g., "tsx line-numbers{5} title=\"hello.tsx\" copy {2-4,5} /Hello/3-5")
2544
+ * @returns Parsed CodeBlockProperties object
2545
+ *
2546
+ * @example
2547
+ * ```typescript
2548
+ * parseCodeInfo("tsx line-numbers{5} title=\"hello.tsx\" copy {2-4,5} /Hello/3-5")
2549
+ * ```
2550
+ *
2551
+ * Returns:
2552
+ * ```json
2553
+ * {
2554
+ * language: "tsx",
2555
+ * lineNumbers: 5,
2556
+ * title: "hello.tsx",
2557
+ * copy: true,
2558
+ * highlightLines: [2,3,4,5],
2559
+ * highlightText: [{ pattern: "Hello", instances: [3,4,5] }]
2560
+ * }
2561
+ * ```
2562
+ */
2563
+ parseCodeInfo(codeInfo) {
2564
+ const props = { language: "" };
2565
+ if (!codeInfo || !codeInfo.trim()) {
2566
+ return props;
2567
+ }
2568
+ let remaining = codeInfo.trim();
2569
+ const langMatch = remaining.match(/^(\w+)/);
2570
+ if (langMatch && langMatch[1]) {
2571
+ props.language = langMatch[1];
2572
+ remaining = remaining.slice(langMatch[0].length).trim();
2573
+ }
2574
+ const quotedPattern = /(\w+)="([^"]*)"/g;
2575
+ let quotedMatch;
2576
+ while ((quotedMatch = quotedPattern.exec(remaining)) !== null) {
2577
+ const key = quotedMatch[1]?.toLowerCase();
2578
+ const value = quotedMatch[2];
2579
+ if (key === "title" && value !== void 0) {
2580
+ props.title = value;
2581
+ } else if (key === "caption" && value !== void 0) {
2582
+ props.caption = value;
2583
+ }
2584
+ }
2585
+ remaining = remaining.replace(quotedPattern, "").trim();
2586
+ const lineNumbersMatch = remaining.match(/line-numbers(?:\{(\d+)\})?/);
2587
+ if (lineNumbersMatch) {
2588
+ if (lineNumbersMatch[1]) {
2589
+ props.lineNumbers = parseInt(lineNumbersMatch[1], 10);
2590
+ } else {
2591
+ props.lineNumbers = true;
2592
+ }
2593
+ remaining = remaining.replace(lineNumbersMatch[0], "").trim();
2594
+ }
2595
+ if (/\bcopy\b/.test(remaining)) {
2596
+ props.copy = true;
2597
+ remaining = remaining.replace(/\bcopy\b/, "").trim();
2598
+ }
2599
+ const lineHighlightMatch = remaining.match(/\{([^}]+)\}/);
2600
+ if (lineHighlightMatch && lineHighlightMatch[1]) {
2601
+ const highlightLines = [];
2602
+ const parts = lineHighlightMatch[1].split(",");
2603
+ for (const part of parts) {
2604
+ const trimmed = part.trim();
2605
+ const rangeMatch = trimmed.match(/^(\d+)-(\d+)$/);
2606
+ if (rangeMatch && rangeMatch[1] && rangeMatch[2]) {
2607
+ const start = parseInt(rangeMatch[1], 10);
2608
+ const end = parseInt(rangeMatch[2], 10);
2609
+ for (let i = start; i <= end; i++) {
2610
+ highlightLines.push(i);
2611
+ }
2612
+ } else if (/^\d+$/.test(trimmed)) {
2613
+ highlightLines.push(parseInt(trimmed, 10));
2614
+ }
2615
+ }
2616
+ if (highlightLines.length > 0) {
2617
+ props.highlightLines = highlightLines;
2618
+ }
2619
+ remaining = remaining.replace(lineHighlightMatch[0], "").trim();
2620
+ }
2621
+ const textHighlightPattern = /\/([^/]+)\/(?:(\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*))?/g;
2622
+ let textMatch;
2623
+ const highlightText = [];
2624
+ while ((textMatch = textHighlightPattern.exec(remaining)) !== null) {
2625
+ if (!textMatch[1]) continue;
2626
+ const highlight = {
2627
+ pattern: textMatch[1]
2628
+ };
2629
+ if (textMatch[2]) {
2630
+ const instanceStr = textMatch[2];
2631
+ const instances = [];
2632
+ const instanceParts = instanceStr.split(",");
2633
+ for (const part of instanceParts) {
2634
+ const rangeMatch = part.match(/^(\d+)-(\d+)$/);
2635
+ if (rangeMatch && rangeMatch[1] && rangeMatch[2]) {
2636
+ const start = parseInt(rangeMatch[1], 10);
2637
+ const end = parseInt(rangeMatch[2], 10);
2638
+ for (let i = start; i <= end; i++) {
2639
+ instances.push(i);
2640
+ }
2641
+ } else if (/^\d+$/.test(part)) {
2642
+ instances.push(parseInt(part, 10));
2643
+ }
2644
+ }
2645
+ if (instances.length > 0) {
2646
+ highlight.instances = instances;
2647
+ }
2648
+ }
2649
+ highlightText.push(highlight);
2650
+ }
2651
+ if (highlightText.length > 0) {
2652
+ props.highlightText = highlightText;
2653
+ }
2654
+ return props;
2655
+ }
2656
+ /**
2657
+ * Build decorations for inline code and fenced code blocks.
2658
+ * Handles line numbers, highlights, header/caption widgets, and fence visibility.
2659
+ */
2660
+ buildDecorations(ctx) {
2661
+ const { view: view$1, decorations } = ctx;
2662
+ const tree = language.syntaxTree(view$1.state);
2663
+ tree.iterate({
2664
+ enter: (node) => {
2665
+ const { from, to, name } = node;
2666
+ if (name === "InlineCode") {
2667
+ decorations.push(codeMarkDecorations["inline-code"].range(from, to));
2668
+ const cursorInRange = ctx.selectionOverlapsRange(from, to);
2669
+ if (!cursorInRange) {
2670
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
2671
+ if (child.name === "CodeMark") {
2672
+ decorations.push(codeMarkDecorations["inline-mark"].range(child.from, child.to));
2673
+ }
2674
+ }
2675
+ }
2676
+ }
2677
+ if (name === "FencedCode") {
2678
+ const nodeLineStart = view$1.state.doc.lineAt(from);
2679
+ const nodeLineEnd = view$1.state.doc.lineAt(to);
2680
+ const cursorInRange = ctx.selectionOverlapsRange(nodeLineStart.from, nodeLineEnd.to);
2681
+ let infoProps = { language: "" };
2682
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
2683
+ if (child.name === "CodeInfo") {
2684
+ infoProps = this.parseCodeInfo(view$1.state.sliceDoc(child.from, child.to).trim());
2685
+ break;
2686
+ }
2687
+ }
2688
+ const totalCodeLines = nodeLineEnd.number - nodeLineStart.number - 1;
2689
+ const startLineNum = typeof infoProps.lineNumbers === "number" ? infoProps.lineNumbers : 1;
2690
+ const maxLineNum = startLineNum + totalCodeLines - 1;
2691
+ const lineNumWidth = Math.max(String(maxLineNum).length, String(startLineNum).length);
2692
+ let codeLineIndex = 0;
2693
+ let codeContent = "";
2694
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
2695
+ if (child.name === "CodeText") {
2696
+ codeContent = view$1.state.sliceDoc(child.from, child.to);
2697
+ break;
2698
+ }
2699
+ }
2700
+ const shouldShowHeader = !cursorInRange && (infoProps.title || infoProps.copy || infoProps.language);
2701
+ const shouldShowCaption = !cursorInRange && infoProps.caption;
2702
+ if (shouldShowHeader) {
2703
+ decorations.push(
2704
+ view.Decoration.widget({
2705
+ widget: new CodeBlockHeaderWidget(infoProps, codeContent),
2706
+ block: false
2707
+ }).range(nodeLineStart.from)
2708
+ );
2709
+ }
2710
+ for (let i = nodeLineStart.number; i <= nodeLineEnd.number; i++) {
2711
+ const line = view$1.state.doc.line(i);
2712
+ const isFenceLine = i === nodeLineStart.number || i === nodeLineEnd.number;
2713
+ const relativeLineNum = startLineNum + codeLineIndex;
2714
+ decorations.push(codeMarkDecorations["code-block-line"].range(line.from));
2715
+ if (i === nodeLineStart.number) {
2716
+ decorations.push(codeMarkDecorations["code-block-line-start"].range(line.from));
2717
+ if (shouldShowHeader) {
2718
+ decorations.push(
2719
+ view.Decoration.line({
2720
+ class: "cm-draftly-code-block-has-header"
2721
+ }).range(line.from)
2722
+ );
2723
+ }
2724
+ }
2725
+ if (i === nodeLineEnd.number) {
2726
+ decorations.push(codeMarkDecorations["code-block-line-end"].range(line.from));
2727
+ if (shouldShowCaption) {
2728
+ decorations.push(
2729
+ view.Decoration.line({
2730
+ class: "cm-draftly-code-block-has-caption"
2731
+ }).range(line.from)
2732
+ );
2733
+ }
2734
+ }
2735
+ if (!isFenceLine && infoProps.lineNumbers) {
2736
+ decorations.push(
2737
+ view.Decoration.line({
2738
+ class: "cm-draftly-code-line-numbered",
2739
+ attributes: {
2740
+ "data-line-num": String(relativeLineNum),
2741
+ style: `--line-num-width: ${lineNumWidth}ch`
2742
+ }
2743
+ }).range(line.from)
2744
+ );
2745
+ }
2746
+ if (!isFenceLine && infoProps.highlightLines) {
2747
+ if (infoProps.highlightLines.includes(codeLineIndex + 1)) {
2748
+ decorations.push(codeMarkDecorations["code-line-highlight"].range(line.from));
2749
+ }
2750
+ }
2751
+ if (!isFenceLine && infoProps.highlightText && infoProps.highlightText.length > 0) {
2752
+ const lineText = view$1.state.sliceDoc(line.from, line.to);
2753
+ for (const textHighlight of infoProps.highlightText) {
2754
+ try {
2755
+ const regex = new RegExp(textHighlight.pattern, "g");
2756
+ let match;
2757
+ let matchIndex = 0;
2758
+ while ((match = regex.exec(lineText)) !== null) {
2759
+ matchIndex++;
2760
+ const shouldHighlight = !textHighlight.instances || textHighlight.instances.includes(matchIndex);
2761
+ if (shouldHighlight) {
2762
+ const matchFrom = line.from + match.index;
2763
+ const matchTo = matchFrom + match[0].length;
2764
+ decorations.push(codeMarkDecorations["code-text-highlight"].range(matchFrom, matchTo));
2765
+ }
2766
+ }
2767
+ } catch {
2768
+ }
2769
+ }
2770
+ }
2771
+ if (!isFenceLine) {
2772
+ codeLineIndex++;
2773
+ }
2774
+ }
2775
+ for (let child = node.node.firstChild; child; child = child.nextSibling) {
2776
+ if (child.name === "CodeMark" || child.name === "CodeInfo") {
2777
+ if (cursorInRange) {
2778
+ decorations.push(codeMarkDecorations["code-fence"].range(child.from, child.to));
2779
+ } else {
2780
+ decorations.push(codeMarkDecorations["code-hidden"].range(child.from, child.to));
2781
+ }
2782
+ }
2783
+ }
2784
+ if (!cursorInRange && infoProps.caption) {
2785
+ decorations.push(
2786
+ view.Decoration.widget({
2787
+ widget: new CodeBlockCaptionWidget(infoProps.caption),
2788
+ block: false,
2789
+ side: 1
2790
+ // After the content
2791
+ }).range(nodeLineEnd.to)
2792
+ );
2793
+ }
2794
+ }
2795
+ }
2796
+ });
2797
+ }
2798
+ /**
2799
+ * Render code elements to HTML for static preview.
2800
+ * Applies syntax highlighting using @lezer/highlight.
2801
+ */
2802
+ renderToHTML(node, children, ctx) {
2803
+ if (node.name === "CodeMark") {
2804
+ return "";
2805
+ }
2806
+ if (node.name === "InlineCode") {
2807
+ let content = ctx.sliceDoc(node.from, node.to);
2808
+ const match = content.match(/^`+(.+?)`+$/s);
2809
+ if (match && match[1]) {
2810
+ content = match[1];
2811
+ }
2812
+ return `<code class="cm-draftly-code-inline" style="padding: 0.1rem 0.25rem">${ctx.sanitize(content)}</code>`;
2813
+ }
2814
+ if (node.name === "FencedCode") {
2815
+ const content = ctx.sliceDoc(node.from, node.to);
2816
+ const lines = content.split("\n");
2817
+ const firstLine = lines[0] || "";
2818
+ const infoMatch = firstLine.match(/^```(.*)$/);
2819
+ const infoString = infoMatch?.[1]?.trim() || "";
2820
+ const props = this.parseCodeInfo(infoString);
2821
+ const codeLines = lines.slice(1, -1);
2822
+ const code = codeLines.join("\n");
2823
+ let html = "";
2824
+ html += `<div class="cm-draftly-code-container">`;
2825
+ const showHeader = props.title || props.copy || props.language;
2826
+ if (showHeader) {
2827
+ html += `<div class="cm-draftly-code-header">`;
2828
+ html += `<div class="cm-draftly-code-header-left">`;
2829
+ if (props.title) {
2830
+ html += `<span class="cm-draftly-code-header-title">${ctx.sanitize(props.title)}</span>`;
2831
+ } else if (props.language) {
2832
+ html += `<span class="cm-draftly-code-header-lang">${ctx.sanitize(props.language)}</span>`;
2833
+ }
2834
+ html += `</div>`;
2835
+ if (props.copy !== false) {
2836
+ html += `<div class="cm-draftly-code-header-right">`;
2837
+ const encodedCode = typeof btoa !== "undefined" ? btoa(encodeURIComponent(code)) : Buffer.from(code).toString("base64");
2838
+ html += `<button class="cm-draftly-code-copy-btn" type="button" title="Copy code" data-code="${encodedCode}" data-encoded="true">`;
2839
+ html += `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
2840
+ html += `</button>`;
2841
+ html += `</div>`;
2842
+ }
2843
+ html += `</div>`;
2844
+ }
2845
+ const startLineNum = typeof props.lineNumbers === "number" ? props.lineNumbers : 1;
2846
+ const lineNumWidth = String(startLineNum + codeLines.length - 1).length;
2847
+ const hasHeader = showHeader ? " cm-draftly-code-block-has-header" : "";
2848
+ const hasCaption = props.caption ? " cm-draftly-code-block-has-caption" : "";
2849
+ html += `<pre class="cm-draftly-code-block${hasHeader}${hasCaption}"${props.language ? ` data-lang="${ctx.sanitize(props.language)}"` : ""}>`;
2850
+ html += `<code>`;
2851
+ codeLines.forEach((line, index) => {
2852
+ const lineNum = startLineNum + index;
2853
+ const isHighlighted = props.highlightLines?.includes(index + 1);
2854
+ const lineClasses = ["cm-draftly-code-line"];
2855
+ if (isHighlighted) lineClasses.push("cm-draftly-code-line-highlight");
2856
+ if (props.lineNumbers) lineClasses.push("cm-draftly-code-line-numbered");
2857
+ const lineAttrs = [`class="${lineClasses.join(" ")}"`];
2858
+ if (props.lineNumbers) {
2859
+ lineAttrs.push(`data-line-num="${lineNum}"`);
2860
+ lineAttrs.push(`style="--line-num-width: ${lineNumWidth}ch"`);
2861
+ }
2862
+ let lineContent = this.highlightCodeLine(line, props.language || "", ctx);
2863
+ if (props.highlightText && props.highlightText.length > 0) {
2864
+ lineContent = this.applyTextHighlights(lineContent, props.highlightText);
2865
+ }
2866
+ html += `<span ${lineAttrs.join(" ")}>${lineContent || " "}</span>`;
2867
+ });
2868
+ html += `</code></pre>`;
2869
+ if (props.caption) {
2870
+ html += `<div class="cm-draftly-code-caption">${ctx.sanitize(props.caption)}</div>`;
2871
+ }
2872
+ html += `</div>`;
2873
+ return html;
2874
+ }
2875
+ if (node.name === "CodeInfo" || node.name === "CodeText") {
2876
+ return "";
2877
+ }
2878
+ return null;
2879
+ }
2880
+ /**
2881
+ * Highlight a single line of code using the language's Lezer parser.
2882
+ * Falls back to sanitized plain text if the language is not supported.
2883
+ */
2884
+ highlightCodeLine(line, lang, ctx) {
2885
+ if (!lang || !line) {
2886
+ return ctx.sanitize(line);
2887
+ }
2888
+ const langDesc = languageData.languages.find(
2889
+ (l) => l.name.toLowerCase() === lang.toLowerCase() || l.alias && l.alias.includes(lang.toLowerCase())
2890
+ );
2891
+ if (!langDesc || !langDesc.support) {
2892
+ return ctx.sanitize(line);
2893
+ }
2894
+ try {
2895
+ const parser = langDesc.support.language.parser;
2896
+ const tree = parser.parse(line);
2897
+ let result = "";
2898
+ highlight.highlightCode(
2899
+ line,
2900
+ tree,
2901
+ highlight.classHighlighter,
2902
+ (text, classes2) => {
2903
+ if (classes2) {
2904
+ result += `<span class="${classes2}">${ctx.sanitize(text)}</span>`;
2905
+ } else {
2906
+ result += ctx.sanitize(text);
2907
+ }
2908
+ },
2909
+ () => {
2910
+ }
2911
+ // No newlines for single line
2912
+ );
2913
+ return result;
2914
+ } catch {
2915
+ return ctx.sanitize(line);
2916
+ }
2917
+ }
2918
+ /**
2919
+ * Apply text highlights (regex patterns) to already syntax-highlighted HTML.
2920
+ * Wraps matched patterns in `<mark>` elements.
2921
+ */
2922
+ applyTextHighlights(htmlContent, highlights) {
2923
+ let result = htmlContent;
2924
+ for (const highlight of highlights) {
2925
+ try {
2926
+ const regex = new RegExp(`(${highlight.pattern})`, "g");
2927
+ let matchCount = 0;
2928
+ result = result.replace(regex, (match) => {
2929
+ matchCount++;
2930
+ const shouldHighlight = !highlight.instances || highlight.instances.includes(matchCount);
2931
+ if (shouldHighlight) {
2932
+ return `<mark class="cm-draftly-code-text-highlight">${match}</mark>`;
2933
+ }
2934
+ return match;
2935
+ });
2936
+ } catch {
2937
+ }
2938
+ }
2939
+ return result;
2940
+ }
2941
+ };
2942
+ var theme10 = chunkKDEDLC3D_cjs.createTheme({
2943
+ default: {
2944
+ // Inline code
2945
+ ".cm-draftly-code-inline": {
2946
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
2947
+ fontSize: "0.9rem",
2948
+ backgroundColor: "rgba(0, 0, 0, 0.05)",
2949
+ padding: "0.1rem 0.25rem",
2950
+ border: "1px solid var(--color-border)",
2951
+ borderRadius: "3px"
2952
+ },
2953
+ // Fenced code block lines
2954
+ ".cm-draftly-code-block-line": {
2955
+ "--radius": "0.375rem",
2956
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
2957
+ fontSize: "0.9rem",
2958
+ backgroundColor: "rgba(0, 0, 0, 0.03)",
2959
+ padding: "0 1rem !important",
2960
+ lineHeight: "1.5",
2961
+ borderLeft: "1px solid var(--color-border)",
2962
+ borderRight: "1px solid var(--color-border)"
2963
+ },
2964
+ // First line of code block
2965
+ ".cm-draftly-code-block-line-start": {
2966
+ borderTopLeftRadius: "var(--radius)",
2967
+ borderTopRightRadius: "var(--radius)",
2968
+ position: "relative",
2969
+ overflow: "hidden",
2970
+ borderTop: "1px solid var(--color-border)",
2971
+ paddingBottom: "0.5rem !important"
2972
+ },
2973
+ // Remove top radius when header is present
2974
+ ".cm-draftly-code-block-has-header": {
2975
+ padding: "0 !important",
2976
+ paddingBottom: "0.5rem !important"
2977
+ },
2978
+ // Code block header widget
2979
+ ".cm-draftly-code-header": {
2980
+ display: "flex",
2981
+ justifyContent: "space-between",
2982
+ alignItems: "center",
2983
+ padding: "0.25rem 1rem",
2984
+ backgroundColor: "rgba(0, 0, 0, 0.06)",
2985
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
2986
+ fontSize: "0.85rem"
2987
+ },
2988
+ ".cm-draftly-code-header-left": {
2989
+ display: "flex",
2990
+ alignItems: "center",
2991
+ gap: "0.5rem"
2992
+ },
2993
+ ".cm-draftly-code-header-title": {
2994
+ color: "var(--color-text, inherit)",
2995
+ fontWeight: "500"
2996
+ },
2997
+ ".cm-draftly-code-header-lang": {
2998
+ color: "#6a737d",
2999
+ opacity: "0.8"
3000
+ },
3001
+ ".cm-draftly-code-header-right": {
3002
+ display: "flex",
3003
+ alignItems: "center",
3004
+ gap: "0.5rem"
3005
+ },
3006
+ ".cm-draftly-code-copy-btn": {
3007
+ display: "flex",
3008
+ alignItems: "center",
3009
+ justifyContent: "center",
3010
+ padding: "0.25rem",
3011
+ backgroundColor: "transparent",
3012
+ border: "none",
3013
+ borderRadius: "4px",
3014
+ cursor: "pointer",
3015
+ color: "#6a737d",
3016
+ transition: "color 0.2s, background-color 0.2s"
3017
+ },
3018
+ ".cm-draftly-code-copy-btn:hover": {
3019
+ backgroundColor: "rgba(0, 0, 0, 0.1)",
3020
+ color: "var(--color-text, inherit)"
3021
+ },
3022
+ ".cm-draftly-code-copy-btn.copied": {
3023
+ color: "#22c55e"
3024
+ },
3025
+ // Caption (below code block)
3026
+ ".cm-draftly-code-block-has-caption": {
3027
+ padding: "0 !important",
3028
+ paddingTop: "0.5rem !important"
3029
+ },
3030
+ ".cm-draftly-code-caption": {
3031
+ textAlign: "center",
3032
+ fontSize: "0.85rem",
3033
+ color: "#6a737d",
3034
+ fontStyle: "italic",
3035
+ padding: "0.25rem 1rem",
3036
+ backgroundColor: "rgba(0, 0, 0, 0.06)"
3037
+ },
3038
+ // Last line of code block
3039
+ ".cm-draftly-code-block-line-end": {
3040
+ borderBottomLeftRadius: "var(--radius)",
3041
+ borderBottomRightRadius: "var(--radius)",
3042
+ borderBottom: "1px solid var(--color-border)",
3043
+ paddingTop: "0.5rem !important"
3044
+ },
3045
+ ".cm-draftly-code-block-line-end br": {
3046
+ display: "none"
3047
+ },
3048
+ // Fence markers (```)
3049
+ ".cm-draftly-code-fence": {
3050
+ color: "#6a737d",
3051
+ fontFamily: "var(--font-jetbrains-mono, monospace)"
3052
+ },
3053
+ // Line numbers
3054
+ ".cm-draftly-code-line-numbered": {
3055
+ paddingLeft: "calc(var(--line-num-width, 2ch) + 1rem) !important",
3056
+ position: "relative"
3057
+ },
3058
+ ".cm-draftly-code-line-numbered::before": {
3059
+ content: "attr(data-line-num)",
3060
+ position: "absolute",
3061
+ left: "0.5rem",
3062
+ top: "0.2rem",
3063
+ width: "var(--line-num-width, 2ch)",
3064
+ textAlign: "right",
3065
+ color: "#6a737d",
3066
+ opacity: "0.6",
3067
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
3068
+ fontSize: "0.85rem",
3069
+ userSelect: "none"
3070
+ },
3071
+ // Preview: code lines (need block display for full-width highlights)
3072
+ ".cm-draftly-code-line": {
3073
+ display: "block",
3074
+ position: "relative",
3075
+ paddingLeft: "1rem",
3076
+ paddingRight: "1rem",
3077
+ lineHeight: "1.5",
3078
+ borderLeft: "3px solid transparent"
3079
+ },
3080
+ // Line highlight
3081
+ ".cm-draftly-code-line-highlight": {
3082
+ backgroundColor: "rgba(255, 220, 100, 0.2) !important",
3083
+ borderLeft: "3px solid #f0b429 !important"
3084
+ },
3085
+ // Text highlight
3086
+ ".cm-draftly-code-text-highlight": {
3087
+ backgroundColor: "rgba(255, 220, 100, 0.4)",
3088
+ borderRadius: "2px",
3089
+ padding: "0.1rem 0"
3090
+ },
3091
+ // Preview: container wrapper
3092
+ ".cm-draftly-code-container": {
3093
+ margin: "1rem 0",
3094
+ borderRadius: "var(--radius)",
3095
+ overflow: "hidden",
3096
+ border: "1px solid var(--color-border)"
3097
+ },
3098
+ // Preview: header inside container
3099
+ ".cm-draftly-code-container .cm-draftly-code-header": {
3100
+ borderRadius: "0",
3101
+ border: "none",
3102
+ borderBottom: "1px solid var(--color-border)"
3103
+ },
3104
+ // Preview: code block inside container
3105
+ ".cm-draftly-code-container .cm-draftly-code-block": {
3106
+ margin: "0",
3107
+ borderRadius: "0",
3108
+ border: "none",
3109
+ whiteSpace: "pre-wrap"
3110
+ },
3111
+ // Preview: caption inside container
3112
+ ".cm-draftly-code-container .cm-draftly-code-caption": {
3113
+ borderTop: "1px solid var(--color-border)"
3114
+ },
3115
+ // Preview: standalone code block (not in container)
3116
+ ".cm-draftly-code-block": {
3117
+ fontFamily: "var(--font-jetbrains-mono, monospace)",
3118
+ fontSize: "0.9rem",
3119
+ backgroundColor: "rgba(0, 0, 0, 0.03)",
3120
+ padding: "1rem",
3121
+ overflow: "auto",
3122
+ position: "relative",
3123
+ borderRadius: "var(--radius)",
3124
+ border: "1px solid var(--color-border)"
3125
+ },
3126
+ // Preview: code block with header (remove top radius)
3127
+ ".cm-draftly-code-block.cm-draftly-code-block-has-header": {
3128
+ borderTopLeftRadius: "0",
3129
+ borderTopRightRadius: "0",
3130
+ borderTop: "none",
3131
+ margin: "0",
3132
+ paddingTop: "0.5rem !important"
3133
+ },
3134
+ // Preview: code block with caption (remove bottom radius)
3135
+ ".cm-draftly-code-block.cm-draftly-code-block-has-caption": {
3136
+ borderBottomLeftRadius: "0",
3137
+ borderBottomRightRadius: "0",
3138
+ borderBottom: "none",
3139
+ paddingBottom: "0.5rem !important"
3140
+ }
3141
+ },
3142
+ dark: {
3143
+ ".cm-draftly-code-inline": {
3144
+ backgroundColor: "rgba(255, 255, 255, 0.1)"
3145
+ },
3146
+ ".cm-draftly-code-block-line": {
3147
+ backgroundColor: "rgba(255, 255, 255, 0.05)"
3148
+ },
3149
+ ".cm-draftly-code-fence": {
3150
+ color: "#8b949e"
3151
+ },
3152
+ ".cm-draftly-code-block": {
3153
+ backgroundColor: "rgba(255, 255, 255, 0.05)"
3154
+ },
3155
+ ".cm-draftly-code-header": {
3156
+ backgroundColor: "rgba(255, 255, 255, 0.08)"
3157
+ },
3158
+ ".cm-draftly-code-header-lang": {
3159
+ color: "#8b949e"
3160
+ },
3161
+ ".cm-draftly-code-copy-btn": {
3162
+ color: "#8b949e"
3163
+ },
3164
+ ".cm-draftly-code-copy-btn:hover": {
3165
+ backgroundColor: "rgba(255, 255, 255, 0.1)"
3166
+ },
3167
+ ".cm-draftly-code-caption": {
3168
+ backgroundColor: "rgba(255, 255, 255, 0.05)"
3169
+ },
3170
+ ".cm-draftly-code-line-numbered::before": {
3171
+ color: "#8b949e"
3172
+ },
3173
+ ".cm-draftly-code-line-highlight": {
3174
+ backgroundColor: "rgba(255, 220, 100, 0.15) !important",
3175
+ borderLeft: "3px solid #d9a520 !important"
3176
+ },
3177
+ ".cm-draftly-code-text-highlight": {
3178
+ backgroundColor: "rgba(255, 220, 100, 0.3)"
3179
+ }
3180
+ }
3181
+ });
3182
+ var quoteMarkDecorations = {
3183
+ /** Decoration for the > marker */
3184
+ "quote-mark": view.Decoration.replace({}),
3185
+ /** Decoration for the quote content */
3186
+ "quote-content": view.Decoration.mark({ class: "cm-draftly-quote-content" })
3187
+ };
3188
+ var quoteLineDecorations = {
3189
+ /** Decoration for blockquote lines */
3190
+ "quote-line": view.Decoration.line({ class: "cm-draftly-quote-line" })
3191
+ };
3192
+ var QuotePlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
3193
+ name = "quote";
3194
+ version = "1.0.0";
3195
+ decorationPriority = 10;
3196
+ requiredNodes = ["Blockquote", "QuoteMark"];
3197
+ /**
3198
+ * Constructor - calls super constructor
3199
+ */
3200
+ constructor() {
3201
+ super();
3202
+ }
3203
+ /**
3204
+ * Plugin theme
3205
+ */
3206
+ get theme() {
3207
+ return theme11;
3208
+ }
3209
+ /**
3210
+ * Build blockquote decorations by iterating the syntax tree
3211
+ */
3212
+ buildDecorations(ctx) {
3213
+ const { view, decorations } = ctx;
3214
+ const tree = language.syntaxTree(view.state);
3215
+ tree.iterate({
3216
+ enter: (node) => {
3217
+ const { from, to, name } = node;
3218
+ if (name !== "Blockquote") {
3219
+ return;
3220
+ }
3221
+ const startLine = view.state.doc.lineAt(from);
3222
+ const endLine = view.state.doc.lineAt(to);
3223
+ for (let lineNum = startLine.number; lineNum <= endLine.number; lineNum++) {
3224
+ const line = view.state.doc.line(lineNum);
3225
+ decorations.push(quoteLineDecorations["quote-line"].range(line.from));
3226
+ }
3227
+ decorations.push(quoteMarkDecorations["quote-content"].range(from, to));
3228
+ const cursorInNode = ctx.selectionOverlapsRange(from, to);
3229
+ if (!cursorInNode) {
3230
+ this.hideQuoteMarks(node.node, decorations, view);
3231
+ }
3232
+ }
3233
+ });
3234
+ }
3235
+ /**
3236
+ * Recursively find and hide quote marks
3237
+ */
3238
+ hideQuoteMarks(node, decorations, view) {
3239
+ let child = node.firstChild;
3240
+ while (child) {
3241
+ if (child.name === "QuoteMark") {
3242
+ const line = view.state.doc.lineAt(child.from);
3243
+ const markEnd = Math.min(child.to + 1, line.to);
3244
+ decorations.push(quoteMarkDecorations["quote-mark"].range(child.from, markEnd));
3245
+ }
3246
+ if (child.name === "Blockquote") {
3247
+ this.hideQuoteMarks(child, decorations, view);
3248
+ }
3249
+ child = child.nextSibling;
3250
+ }
3251
+ }
3252
+ renderToHTML(node, children) {
3253
+ if (node.name === "QuoteMark") {
3254
+ return "";
3255
+ }
3256
+ if (node.name !== "Blockquote") {
3257
+ return null;
3258
+ }
3259
+ return `<blockquote class="cm-draftly-quote-line"><div class="cm-draftly-quote-content">${children}</div></blockquote>
3260
+ `;
3261
+ }
3262
+ };
3263
+ var theme11 = chunkKDEDLC3D_cjs.createTheme({
3264
+ default: {
3265
+ // Line styling with left border
3266
+ ".cm-draftly-quote-line": {
3267
+ borderLeft: "3px solid currentColor",
3268
+ paddingLeft: "1em !important",
3269
+ paddingTop: "0.25em !important",
3270
+ paddingBottom: "0.25em !important",
3271
+ marginLeft: "0.25em",
3272
+ opacity: "0.85"
3273
+ },
3274
+ // Quote content styling
3275
+ ".cm-draftly-quote-content": {
3276
+ fontStyle: "italic"
3277
+ }
3278
+ }
3279
+ });
3280
+ var hrLineDecoration = view.Decoration.line({ class: "cm-draftly-hr-line" });
3281
+ var hrMarkDecoration = view.Decoration.replace({});
3282
+ var HRPlugin = class extends chunk72ZYRGRT_cjs.DecorationPlugin {
3283
+ name = "hr";
3284
+ version = "1.0.0";
3285
+ decorationPriority = 10;
3286
+ requiredNodes = ["HorizontalRule"];
3287
+ /**
3288
+ * Constructor - calls super constructor
3289
+ */
3290
+ constructor() {
3291
+ super();
3292
+ }
3293
+ /**
3294
+ * Plugin theme
3295
+ */
3296
+ get theme() {
3297
+ return theme12;
3298
+ }
3299
+ /**
3300
+ * Build horizontal rule decorations by iterating the syntax tree
3301
+ */
3302
+ buildDecorations(ctx) {
3303
+ const { view, decorations } = ctx;
3304
+ const tree = language.syntaxTree(view.state);
3305
+ tree.iterate({
3306
+ enter: (node) => {
3307
+ const { from, to, name } = node;
3308
+ if (name !== "HorizontalRule") {
3309
+ return;
3310
+ }
3311
+ const line = view.state.doc.lineAt(from);
3312
+ decorations.push(hrLineDecoration.range(line.from));
3313
+ const cursorInNode = ctx.selectionOverlapsRange(from, to);
3314
+ if (!cursorInNode) {
3315
+ const markEnd = Math.min(to, line.to);
3316
+ decorations.push(hrMarkDecoration.range(from, markEnd));
3317
+ }
3318
+ }
3319
+ });
3320
+ }
3321
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3322
+ renderToHTML(node, _children) {
3323
+ if (node.name !== "HorizontalRule") {
3324
+ return null;
3325
+ }
3326
+ return `<hr class="cm-draftly-hr-line" />
3327
+ `;
3328
+ }
3329
+ };
3330
+ var theme12 = chunkKDEDLC3D_cjs.createTheme({
3331
+ default: {
3332
+ // Line styling — displays a centered horizontal line
3333
+ ".cm-draftly-hr-line": {
3334
+ display: "flex",
3335
+ alignItems: "center",
3336
+ paddingTop: "0.75em",
3337
+ paddingBottom: "0.75em",
3338
+ border: "none",
3339
+ "&::after": {
3340
+ content: '""',
3341
+ flex: "1",
3342
+ height: "2px",
3343
+ background: "currentColor",
3344
+ opacity: "0.3"
3345
+ }
3346
+ }
3347
+ }
3348
+ });
3349
+
3350
+ // src/plugins/index.ts
3351
+ var essentialPlugins = [
3352
+ new ParagraphPlugin(),
3353
+ new HeadingPlugin(),
3354
+ new InlinePlugin(),
3355
+ new LinkPlugin(),
3356
+ new ListPlugin(),
3357
+ new HTMLPlugin(),
3358
+ new ImagePlugin(),
3359
+ new MathPlugin(),
3360
+ new MermaidPlugin(),
3361
+ new CodePlugin(),
3362
+ new QuotePlugin(),
3363
+ new HRPlugin()
3364
+ ];
3365
+ var allPlugins = [...essentialPlugins];
3366
+
3367
+ exports.CodePlugin = CodePlugin;
3368
+ exports.HRPlugin = HRPlugin;
3369
+ exports.HTMLPlugin = HTMLPlugin;
3370
+ exports.HeadingPlugin = HeadingPlugin;
3371
+ exports.ImagePlugin = ImagePlugin;
3372
+ exports.InlinePlugin = InlinePlugin;
3373
+ exports.LinkPlugin = LinkPlugin;
3374
+ exports.ListPlugin = ListPlugin;
3375
+ exports.MathPlugin = MathPlugin;
3376
+ exports.MermaidPlugin = MermaidPlugin;
3377
+ exports.ParagraphPlugin = ParagraphPlugin;
3378
+ exports.QuotePlugin = QuotePlugin;
3379
+ exports.allPlugins = allPlugins;
3380
+ exports.essentialPlugins = essentialPlugins;
3381
+ //# sourceMappingURL=chunk-2B3A3VSQ.cjs.map
3382
+ //# sourceMappingURL=chunk-2B3A3VSQ.cjs.map