@pinkpixel/marzipan 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,3212 @@
1
+ const N = class N {
2
+ /**
3
+ * Reset link index (call before parsing a new document)
4
+ */
5
+ static resetLinkIndex() {
6
+ this.linkIndex = 0;
7
+ }
8
+ /**
9
+ * Escape HTML special characters
10
+ * @param {string} text - Raw text to escape
11
+ * @returns {string} Escaped HTML-safe text
12
+ */
13
+ static escapeHtml(e) {
14
+ const t = {
15
+ "&": "&",
16
+ "<": "&lt;",
17
+ ">": "&gt;",
18
+ '"': "&quot;",
19
+ "'": "&#39;"
20
+ };
21
+ return e.replace(/[&<>"']/g, (n) => t[n]);
22
+ }
23
+ /**
24
+ * Preserve leading spaces as non-breaking spaces
25
+ * @param {string} html - HTML string
26
+ * @param {string} originalLine - Original line with spaces
27
+ * @returns {string} HTML with preserved indentation
28
+ */
29
+ static preserveIndentation(e, t) {
30
+ const r = t.match(/^(\s*)/)[1].replace(/ /g, "&nbsp;");
31
+ return e.replace(/^\s*/, r);
32
+ }
33
+ /**
34
+ * Parse headers (h1-h3 only)
35
+ * @param {string} html - HTML line to parse
36
+ * @returns {string} Parsed HTML with header styling
37
+ */
38
+ static parseHeader(e) {
39
+ return e.replace(/^(#{1,3})\s(.+)$/, (t, n, r) => {
40
+ const o = n.length;
41
+ return `<h${o}><span class="syntax-marker">${n} </span>${r}</h${o}>`;
42
+ });
43
+ }
44
+ /**
45
+ * Parse horizontal rules
46
+ * @param {string} html - HTML line to parse
47
+ * @returns {string|null} Parsed horizontal rule or null
48
+ */
49
+ static parseHorizontalRule(e) {
50
+ return e.match(/^(-{3,}|\*{3,}|_{3,})$/) ? `<div><span class="hr-marker">${e}</span></div>` : null;
51
+ }
52
+ /**
53
+ * Parse blockquotes
54
+ * @param {string} html - HTML line to parse
55
+ * @returns {string} Parsed blockquote
56
+ */
57
+ static parseBlockquote(e) {
58
+ return e.replace(/^&gt; (.+)$/, (t, n) => `<span class="blockquote"><span class="syntax-marker">&gt;</span> ${n}</span>`);
59
+ }
60
+ /**
61
+ * Parse bullet lists
62
+ * @param {string} html - HTML line to parse
63
+ * @returns {string} Parsed bullet list item
64
+ */
65
+ static parseBulletList(e) {
66
+ return e.replace(/^((?:&nbsp;)*)([-*])\s(.+)$/, (t, n, r, o) => `${n}<li class="bullet-list"><span class="syntax-marker">${r} </span>${o}</li>`);
67
+ }
68
+ /**
69
+ * Parse numbered lists
70
+ * @param {string} html - HTML line to parse
71
+ * @returns {string} Parsed numbered list item
72
+ */
73
+ static parseNumberedList(e) {
74
+ return e.replace(/^((?:&nbsp;)*)(\d+\.)\s(.+)$/, (t, n, r, o) => `${n}<li class="ordered-list"><span class="syntax-marker">${r} </span>${o}</li>`);
75
+ }
76
+ /**
77
+ * Parse code blocks (markers only)
78
+ * @param {string} html - HTML line to parse
79
+ * @returns {string|null} Parsed code fence or null
80
+ */
81
+ static parseCodeBlock(e) {
82
+ return /^`{3}[^`]*$/.test(e) ? `<div><span class="code-fence">${e}</span></div>` : null;
83
+ }
84
+ /**
85
+ * Parse bold text
86
+ * @param {string} html - HTML with potential bold markdown
87
+ * @returns {string} HTML with bold styling
88
+ */
89
+ static parseBold(e) {
90
+ return e = e.replace(/\*\*(.+?)\*\*/g, '<strong><span class="syntax-marker">**</span>$1<span class="syntax-marker">**</span></strong>'), e = e.replace(/__(.+?)__/g, '<strong><span class="syntax-marker">__</span>$1<span class="syntax-marker">__</span></strong>'), e;
91
+ }
92
+ /**
93
+ * Parse italic text
94
+ * Note: Uses lookbehind assertions - requires modern browsers
95
+ * @param {string} html - HTML with potential italic markdown
96
+ * @returns {string} HTML with italic styling
97
+ */
98
+ static parseItalic(e) {
99
+ return e = e.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, '<em><span class="syntax-marker">*</span>$1<span class="syntax-marker">*</span></em>'), e = e.replace(/(?<=^|\s)_(?!_)(.+?)(?<!_)_(?!_)(?=\s|$)/g, '<em><span class="syntax-marker">_</span>$1<span class="syntax-marker">_</span></em>'), e;
100
+ }
101
+ /**
102
+ * Parse strikethrough text
103
+ * Supports both single (~) and double (~~) tildes, but rejects 3+ tildes
104
+ * @param {string} html - HTML with potential strikethrough markdown
105
+ * @returns {string} HTML with strikethrough styling
106
+ */
107
+ static parseStrikethrough(e) {
108
+ return e = e.replace(/(?<!~)~~(?!~)(.+?)(?<!~)~~(?!~)/g, '<del><span class="syntax-marker">~~</span>$1<span class="syntax-marker">~~</span></del>'), e = e.replace(/(?<!~)~(?!~)(.+?)(?<!~)~(?!~)/g, '<del><span class="syntax-marker">~</span>$1<span class="syntax-marker">~</span></del>'), e;
109
+ }
110
+ /**
111
+ * Check if line is a table row
112
+ * @param {string} html - HTML line to check
113
+ * @returns {boolean} True if table row
114
+ */
115
+ static isTableRow(e) {
116
+ return /^\|.+\|$/.test(e);
117
+ }
118
+ /**
119
+ * Check if line is a table separator row
120
+ * @param {string} html - HTML line to check
121
+ * @returns {boolean} True if table separator
122
+ */
123
+ static isTableSeparator(e) {
124
+ return /^\|\s*[-:]+\s*(?:\|\s*[-:]+\s*)*\|$/.test(e);
125
+ }
126
+ /**
127
+ * Parse a table row into cells
128
+ * @param {string} html - HTML table row
129
+ * @param {string} tag - Tag to use for cells (th or td)
130
+ * @returns {string} HTML table row
131
+ */
132
+ static parseTableRow(e, t = "td") {
133
+ return `<tr>${e.slice(1, -1).split(/(?<!\\)\|/).map((o) => {
134
+ const a = o.trim(), s = this.parseInlineElements(a || "&nbsp;");
135
+ return `<${t}>${s}</${t}>`;
136
+ }).join("")}</tr>`;
137
+ }
138
+ /**
139
+ * Parse inline code
140
+ * @param {string} html - HTML with potential code markdown
141
+ * @returns {string} HTML with code styling
142
+ */
143
+ static parseInlineCode(e) {
144
+ return e.replace(/(?<!`)(`+)(?!`)((?:(?!\1).)+?)(\1)(?!`)/g, '<code><span class="syntax-marker">$1</span>$2<span class="syntax-marker">$3</span></code>');
145
+ }
146
+ /**
147
+ * Parse markdown images
148
+ * @param {string} html - HTML with potential image markdown
149
+ * @returns {string} HTML with image tags
150
+ */
151
+ static parseImages(e) {
152
+ return e.replace(/!\[([^\]]*)\]\(([^\s)]+)(?:\s+"([^"]+)")?\)/g, (t, n, r, o) => {
153
+ const a = this.sanitizeUrl(r), s = this.escapeHtml(n || ""), c = o ? ` title="${this.escapeHtml(o)}"` : "";
154
+ return `<img src="${a}" alt="${s}"${c} class="marzipan-image" />`;
155
+ });
156
+ }
157
+ /**
158
+ * Sanitize URL to prevent XSS attacks
159
+ * @param {string} url - URL to sanitize
160
+ * @returns {string} Safe URL or '#' if dangerous
161
+ */
162
+ static sanitizeUrl(e) {
163
+ const t = e.trim(), n = t.toLowerCase(), o = [
164
+ "http://",
165
+ "https://",
166
+ "mailto:",
167
+ "ftp://",
168
+ "ftps://"
169
+ ].some((s) => n.startsWith(s)), a = t.startsWith("/") || t.startsWith("#") || t.startsWith("?") || t.startsWith(".") || !t.includes(":") && !t.includes("//");
170
+ return o || a ? e : "#";
171
+ }
172
+ /**
173
+ * Parse links
174
+ * @param {string} html - HTML with potential link markdown
175
+ * @returns {string} HTML with link styling
176
+ */
177
+ static parseLinks(e) {
178
+ return e.replace(/\[(.+?)\]\((.+?)\)/g, (t, n, r) => {
179
+ const o = `--link-${this.linkIndex++}`;
180
+ return `<a href="${this.sanitizeUrl(r)}" style="anchor-name: ${o}"><span class="syntax-marker">[</span>${n}<span class="syntax-marker url-part">](${r})</span></a>`;
181
+ });
182
+ }
183
+ /**
184
+ * Identify and protect sanctuaries (code and links) before parsing
185
+ * @param {string} text - Text with potential markdown
186
+ * @returns {Object} Object with protected text and sanctuary map
187
+ */
188
+ static identifyAndProtectSanctuaries(e) {
189
+ const t = /* @__PURE__ */ new Map();
190
+ let n = 0, r = e;
191
+ const o = [], a = /\[([^\]]+)\]\(([^)]+)\)/g;
192
+ let s;
193
+ for (; (s = a.exec(e)) !== null; ) {
194
+ const m = s.index + s[0].indexOf("](") + 2, u = m + s[2].length;
195
+ o.push({ start: m, end: u });
196
+ }
197
+ const c = /(?<!`)(`+)(?!`)((?:(?!\1).)+?)(\1)(?!`)/g;
198
+ let p;
199
+ const d = [];
200
+ for (; (p = c.exec(e)) !== null; ) {
201
+ const l = p.index, m = p.index + p[0].length;
202
+ o.some(
203
+ (h) => l >= h.start && m <= h.end
204
+ ) || d.push({
205
+ match: p[0],
206
+ index: p.index,
207
+ openTicks: p[1],
208
+ content: p[2],
209
+ closeTicks: p[3]
210
+ });
211
+ }
212
+ return d.sort((l, m) => m.index - l.index), d.forEach((l) => {
213
+ const m = `${n++}`;
214
+ t.set(m, {
215
+ type: "code",
216
+ original: l.match,
217
+ openTicks: l.openTicks,
218
+ content: l.content,
219
+ closeTicks: l.closeTicks
220
+ }), r = r.substring(0, l.index) + m + r.substring(l.index + l.match.length);
221
+ }), r = r.replace(/!\[([^\]]*)\]\(([^\s)]+)(?:\s+"([^"]+)")?\)/g, (l, m, u, h) => {
222
+ const f = `${n++}`;
223
+ return t.set(f, {
224
+ type: "image",
225
+ original: l,
226
+ alt: m,
227
+ url: u,
228
+ title: h
229
+ }), f;
230
+ }), r = r.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (l, m, u) => {
231
+ const h = `${n++}`;
232
+ return t.set(h, {
233
+ type: "link",
234
+ original: l,
235
+ linkText: m,
236
+ url: u
237
+ }), h;
238
+ }), { protectedText: r, sanctuaries: t };
239
+ }
240
+ /**
241
+ * Restore and transform sanctuaries back to HTML
242
+ * @param {string} html - HTML with sanctuary placeholders
243
+ * @param {Map} sanctuaries - Map of sanctuaries to restore
244
+ * @returns {string} HTML with sanctuaries restored and transformed
245
+ */
246
+ static restoreAndTransformSanctuaries(e, t) {
247
+ return Array.from(t.keys()).sort((r, o) => {
248
+ const a = e.indexOf(r), s = e.indexOf(o);
249
+ return a - s;
250
+ }).forEach((r) => {
251
+ const o = t.get(r);
252
+ let a;
253
+ if (o.type === "code")
254
+ a = `<code><span class="syntax-marker">${o.openTicks}</span>${this.escapeHtml(o.content)}<span class="syntax-marker">${o.closeTicks}</span></code>`;
255
+ else if (o.type === "image") {
256
+ const s = this.sanitizeUrl(o.url), c = this.escapeHtml(o.alt || ""), p = o.title ? ` title="${this.escapeHtml(o.title)}"` : "";
257
+ a = `<img src="${s}" alt="${c}"${p} class="marzipan-image" />`;
258
+ } else if (o.type === "link") {
259
+ let s = o.linkText;
260
+ t.forEach((d, l) => {
261
+ if (s.includes(l) && d.type === "code") {
262
+ const m = `<code><span class="syntax-marker">${d.openTicks}</span>${this.escapeHtml(d.content)}<span class="syntax-marker">${d.closeTicks}</span></code>`;
263
+ s = s.replace(l, m);
264
+ }
265
+ }), s = this.parseStrikethrough(s), s = this.parseBold(s), s = this.parseItalic(s);
266
+ const c = `--link-${this.linkIndex++}`;
267
+ a = `<a href="${this.sanitizeUrl(o.url)}" style="anchor-name: ${c}"><span class="syntax-marker">[</span>${s}<span class="syntax-marker url-part">](${this.escapeHtml(o.url)})</span></a>`;
268
+ }
269
+ e = e.replace(r, a);
270
+ }), e;
271
+ }
272
+ /**
273
+ * Parse all inline elements in correct order
274
+ * @param {string} text - Text with potential inline markdown
275
+ * @returns {string} HTML with all inline styling
276
+ */
277
+ static parseInlineElements(e) {
278
+ const { protectedText: t, sanctuaries: n } = this.identifyAndProtectSanctuaries(e);
279
+ let r = t;
280
+ return r = this.parseStrikethrough(r), r = this.parseBold(r), r = this.parseItalic(r), r = this.restoreAndTransformSanctuaries(r, n), r;
281
+ }
282
+ /**
283
+ * Parse a single line of markdown
284
+ * @param {string} line - Raw markdown line
285
+ * @returns {string} Parsed HTML line
286
+ */
287
+ static parseLine(e) {
288
+ let t = this.escapeHtml(e);
289
+ t = this.preserveIndentation(t, e);
290
+ const n = this.parseHorizontalRule(t);
291
+ if (n) return n;
292
+ const r = this.parseCodeBlock(t);
293
+ return r || (t = this.parseHeader(t), t = this.parseBlockquote(t), t = this.parseBulletList(t), t = this.parseNumberedList(t), t = this.parseInlineElements(t), t.trim() === "" ? "<div>&nbsp;</div>" : `<div>${t}</div>`);
294
+ }
295
+ /**
296
+ * Parse full markdown text
297
+ * @param {string} text - Full markdown text
298
+ * @param {number} activeLine - Currently active line index (optional)
299
+ * @param {boolean} showActiveLineRaw - Show raw markdown on active line
300
+ * @returns {string} Parsed HTML
301
+ */
302
+ static parse(e, t = -1, n = !1) {
303
+ this.resetLinkIndex();
304
+ const r = e.split(`
305
+ `);
306
+ let o = !1;
307
+ const s = r.map((c, p) => {
308
+ if (n && p === t)
309
+ return `<div class="raw-line">${this.escapeHtml(c) || "&nbsp;"}</div>`;
310
+ if (/^```[^`]*$/.test(c))
311
+ return o = !o, this.parseLine(c);
312
+ if (o) {
313
+ const m = this.escapeHtml(c);
314
+ return `<div>${this.preserveIndentation(m, c) || "&nbsp;"}</div>`;
315
+ }
316
+ const l = this.escapeHtml(c);
317
+ return this.isTableRow(l) ? this.isTableSeparator(l) ? `<div class="table-separator">${l}</div>` : `<div class="table-row">${l}</div>` : this.parseLine(c);
318
+ }).join("");
319
+ return this.postProcessHTML(s);
320
+ }
321
+ /**
322
+ * Post-process HTML to consolidate lists and code blocks
323
+ * @param {string} html - HTML to post-process
324
+ * @returns {string} Post-processed HTML with consolidated lists and code blocks
325
+ */
326
+ static postProcessHTML(e) {
327
+ if (typeof document > "u" || !document)
328
+ return this.postProcessHTMLManual(e);
329
+ const t = document.createElement("div");
330
+ t.innerHTML = e;
331
+ let n = null, r = null, o = null, a = !1, s = null, c = !1;
332
+ const p = Array.from(t.children);
333
+ for (let d = 0; d < p.length; d++) {
334
+ const l = p[d];
335
+ if (!l.parentNode) continue;
336
+ if (l.classList && (l.classList.contains("table-row") || l.classList.contains("table-separator"))) {
337
+ if (l.classList.contains("table-separator")) {
338
+ if (!s) {
339
+ l.remove();
340
+ continue;
341
+ }
342
+ c = !1, l.remove();
343
+ continue;
344
+ }
345
+ s || (s = document.createElement("table"), s.className = "marzipan-table", t.insertBefore(s, l), c = !0);
346
+ const f = l.textContent, g = c ? "th" : "td", b = this.parseTableRow(f, g);
347
+ let v;
348
+ c ? (v = s.querySelector("thead"), v || (v = document.createElement("thead"), s.appendChild(v))) : (v = s.querySelector("tbody"), v || (v = document.createElement("tbody"), s.appendChild(v))), v.innerHTML += b, l.remove();
349
+ continue;
350
+ } else
351
+ s = null, c = !1;
352
+ const m = l.querySelector(".code-fence");
353
+ if (m) {
354
+ const h = m.textContent;
355
+ if (h.startsWith("```"))
356
+ if (a) {
357
+ a = !1, o = null;
358
+ continue;
359
+ } else {
360
+ a = !0, o = document.createElement("pre");
361
+ const f = document.createElement("code");
362
+ o.appendChild(f), o.className = "code-block";
363
+ const g = h.slice(3).trim();
364
+ g && (f.className = `language-${g}`), t.insertBefore(o, l.nextSibling), o._codeElement = f;
365
+ continue;
366
+ }
367
+ }
368
+ if (a && o && l.tagName === "DIV" && !l.querySelector(".code-fence")) {
369
+ const h = o._codeElement || o.querySelector("code");
370
+ h.textContent.length > 0 && (h.textContent += `
371
+ `);
372
+ const f = l.textContent.replace(/\u00A0/g, " ");
373
+ h.textContent += f, l.remove();
374
+ continue;
375
+ }
376
+ let u = null;
377
+ if (l.tagName === "DIV" && (u = l.querySelector("li")), u) {
378
+ const h = u.classList.contains("bullet-list"), f = u.classList.contains("ordered-list");
379
+ if (!h && !f) {
380
+ n = null, r = null;
381
+ continue;
382
+ }
383
+ const g = h ? "ul" : "ol";
384
+ (!n || r !== g) && (n = document.createElement(g), t.insertBefore(n, l), r = g);
385
+ const b = [];
386
+ for (const v of l.childNodes)
387
+ if (v.nodeType === 3 && v.textContent.match(/^\u00A0+$/))
388
+ b.push(v.cloneNode(!0));
389
+ else if (v === u)
390
+ break;
391
+ b.forEach((v) => {
392
+ u.insertBefore(v, u.firstChild);
393
+ }), n.appendChild(u), l.remove();
394
+ } else
395
+ n = null, r = null;
396
+ }
397
+ return t.innerHTML;
398
+ }
399
+ /**
400
+ * Manual post-processing for Node.js environments (without DOM)
401
+ * @param {string} html - HTML to post-process
402
+ * @returns {string} Post-processed HTML
403
+ */
404
+ static postProcessHTMLManual(e) {
405
+ let t = e;
406
+ t = t.replace(/((?:<div>(?:&nbsp;)*<li class="bullet-list">.*?<\/li><\/div>\s*)+)/gs, (r) => {
407
+ const o = r.match(/<div>(?:&nbsp;)*<li class="bullet-list">.*?<\/li><\/div>/gs) || [];
408
+ return o.length > 0 ? "<ul>" + o.map((s) => {
409
+ const c = s.match(/<div>((?:&nbsp;)*)<li/), p = s.match(/<li class="bullet-list">.*?<\/li>/);
410
+ if (c && p) {
411
+ const d = c[1];
412
+ return p[0].replace(/<li class="bullet-list">/, `<li class="bullet-list">${d}`);
413
+ }
414
+ return p ? p[0] : "";
415
+ }).filter(Boolean).join("") + "</ul>" : r;
416
+ }), t = t.replace(/((?:<div>(?:&nbsp;)*<li class="ordered-list">.*?<\/li><\/div>\s*)+)/gs, (r) => {
417
+ const o = r.match(/<div>(?:&nbsp;)*<li class="ordered-list">.*?<\/li><\/div>/gs) || [];
418
+ return o.length > 0 ? "<ol>" + o.map((s) => {
419
+ const c = s.match(/<div>((?:&nbsp;)*)<li/), p = s.match(/<li class="ordered-list">.*?<\/li>/);
420
+ if (c && p) {
421
+ const d = c[1];
422
+ return p[0].replace(/<li class="ordered-list">/, `<li class="ordered-list">${d}`);
423
+ }
424
+ return p ? p[0] : "";
425
+ }).filter(Boolean).join("") + "</ol>" : r;
426
+ });
427
+ const n = /<div><span class="code-fence">(```[^<]*)<\/span><\/div>(.*?)<div><span class="code-fence">(```)<\/span><\/div>/gs;
428
+ return t = t.replace(n, (r, o, a, s) => {
429
+ const p = (a.match(/<div>(.*?)<\/div>/gs) || []).map((u) => u.replace(/<div>(.*?)<\/div>/s, "$1").replace(/&nbsp;/g, " ")).join(`
430
+ `), d = o.slice(3).trim(), l = d ? ` class="language-${d}"` : "";
431
+ let m = `<div><span class="code-fence">${o}</span></div>`;
432
+ return m += `<pre class="code-block"><code${l}>${p}</code></pre>`, m += `<div><span class="code-fence">${s}</span></div>`, m;
433
+ }), t;
434
+ }
435
+ /**
436
+ * Get list context at cursor position
437
+ * @param {string} text - Full text content
438
+ * @param {number} cursorPosition - Current cursor position
439
+ * @returns {Object} List context information
440
+ */
441
+ static getListContext(e, t) {
442
+ const n = e.split(`
443
+ `);
444
+ let r = 0, o = 0, a = 0;
445
+ for (let m = 0; m < n.length; m++) {
446
+ const u = n[m].length;
447
+ if (r + u >= t) {
448
+ o = m, a = r;
449
+ break;
450
+ }
451
+ r += u + 1;
452
+ }
453
+ const s = n[o], c = a + s.length, p = s.match(this.LIST_PATTERNS.checkbox);
454
+ if (p)
455
+ return {
456
+ inList: !0,
457
+ listType: "checkbox",
458
+ indent: p[1],
459
+ marker: "-",
460
+ checked: p[2] === "x",
461
+ content: p[3],
462
+ lineStart: a,
463
+ lineEnd: c,
464
+ markerEndPos: a + p[1].length + p[2].length + 5
465
+ // indent + "- [ ] "
466
+ };
467
+ const d = s.match(this.LIST_PATTERNS.bullet);
468
+ if (d)
469
+ return {
470
+ inList: !0,
471
+ listType: "bullet",
472
+ indent: d[1],
473
+ marker: d[2],
474
+ content: d[3],
475
+ lineStart: a,
476
+ lineEnd: c,
477
+ markerEndPos: a + d[1].length + d[2].length + 1
478
+ // indent + marker + space
479
+ };
480
+ const l = s.match(this.LIST_PATTERNS.numbered);
481
+ return l ? {
482
+ inList: !0,
483
+ listType: "numbered",
484
+ indent: l[1],
485
+ marker: parseInt(l[2]),
486
+ content: l[3],
487
+ lineStart: a,
488
+ lineEnd: c,
489
+ markerEndPos: a + l[1].length + l[2].length + 2
490
+ // indent + number + ". "
491
+ } : {
492
+ inList: !1,
493
+ listType: null,
494
+ indent: "",
495
+ marker: null,
496
+ content: s,
497
+ lineStart: a,
498
+ lineEnd: c,
499
+ markerEndPos: a
500
+ };
501
+ }
502
+ /**
503
+ * Create a new list item based on context
504
+ * @param {Object} context - List context from getListContext
505
+ * @returns {string} New list item text
506
+ */
507
+ static createNewListItem(e) {
508
+ switch (e.listType) {
509
+ case "bullet":
510
+ return `${e.indent}${e.marker} `;
511
+ case "numbered":
512
+ return `${e.indent}${e.marker + 1}. `;
513
+ case "checkbox":
514
+ return `${e.indent}- [ ] `;
515
+ default:
516
+ return "";
517
+ }
518
+ }
519
+ /**
520
+ * Renumber all numbered lists in text
521
+ * @param {string} text - Text containing numbered lists
522
+ * @returns {string} Text with renumbered lists
523
+ */
524
+ static renumberLists(e) {
525
+ const t = e.split(`
526
+ `), n = /* @__PURE__ */ new Map();
527
+ let r = !1;
528
+ return t.map((a) => {
529
+ const s = a.match(this.LIST_PATTERNS.numbered);
530
+ if (s) {
531
+ const c = s[1], p = c.length, d = s[3];
532
+ r || n.clear();
533
+ const l = (n.get(p) || 0) + 1;
534
+ n.set(p, l);
535
+ for (const [m] of n)
536
+ m > p && n.delete(m);
537
+ return r = !0, `${c}${l}. ${d}`;
538
+ } else
539
+ return (a.trim() === "" || !a.match(/^\s/)) && (r = !1, n.clear()), a;
540
+ }).join(`
541
+ `);
542
+ }
543
+ };
544
+ N.linkIndex = 0, N.LIST_PATTERNS = {
545
+ bullet: /^(\s*)([-*+])\s+(.*)$/,
546
+ numbered: /^(\s*)(\d+)\.\s+(.*)$/,
547
+ checkbox: /^(\s*)-\s+\[([ x])\]\s+(.*)$/
548
+ };
549
+ let T = N;
550
+ const S = {
551
+ bold: {
552
+ prefix: "**",
553
+ suffix: "**",
554
+ trimFirst: !0
555
+ },
556
+ italic: {
557
+ prefix: "_",
558
+ suffix: "_",
559
+ trimFirst: !0
560
+ },
561
+ code: {
562
+ prefix: "`",
563
+ suffix: "`",
564
+ blockPrefix: "```",
565
+ blockSuffix: "```"
566
+ },
567
+ link: {
568
+ prefix: "[",
569
+ suffix: "](url)",
570
+ replaceNext: "url",
571
+ scanFor: "https?://"
572
+ },
573
+ bulletList: {
574
+ prefix: "- ",
575
+ multiline: !0,
576
+ unorderedList: !0
577
+ },
578
+ numberedList: {
579
+ prefix: "1. ",
580
+ multiline: !0,
581
+ orderedList: !0
582
+ },
583
+ quote: {
584
+ prefix: "> ",
585
+ multiline: !0,
586
+ surroundWithNewlines: !0
587
+ },
588
+ taskList: {
589
+ prefix: "- [ ] ",
590
+ multiline: !0,
591
+ surroundWithNewlines: !0
592
+ },
593
+ header1: { prefix: "# " },
594
+ header2: { prefix: "## " },
595
+ header3: { prefix: "### " },
596
+ header4: { prefix: "#### " },
597
+ header5: { prefix: "##### " },
598
+ header6: { prefix: "###### " }
599
+ };
600
+ function Le() {
601
+ return {
602
+ prefix: "",
603
+ suffix: "",
604
+ blockPrefix: "",
605
+ blockSuffix: "",
606
+ multiline: !1,
607
+ replaceNext: "",
608
+ prefixSpace: !1,
609
+ scanFor: null,
610
+ surroundWithNewlines: !1,
611
+ orderedList: !1,
612
+ unorderedList: !1,
613
+ trimFirst: !1
614
+ };
615
+ }
616
+ function C(i) {
617
+ const e = {
618
+ ...Le(),
619
+ ...i
620
+ };
621
+ return e.scanFor = i.scanFor ?? null, e;
622
+ }
623
+ let I = !1;
624
+ function ce(i) {
625
+ I = i;
626
+ }
627
+ function V() {
628
+ return I;
629
+ }
630
+ function k(i, e, t) {
631
+ I && (console.group(`🔍 ${i}`), console.log(e), console.groupEnd());
632
+ }
633
+ function R(i, e) {
634
+ if (!I) return;
635
+ const t = i.value.slice(i.selectionStart, i.selectionEnd);
636
+ console.group(`📍 Selection: ${e}`), console.log("Position:", `${i.selectionStart}-${i.selectionEnd}`), console.log("Selected text:", JSON.stringify(t)), console.log("Length:", t.length);
637
+ const n = i.value.slice(Math.max(0, i.selectionStart - 10), i.selectionStart), r = i.value.slice(i.selectionEnd, Math.min(i.value.length, i.selectionEnd + 10));
638
+ console.log("Context:", `${JSON.stringify(n)}[SELECTION]${JSON.stringify(r)}`), console.groupEnd();
639
+ }
640
+ function D(i) {
641
+ I && (console.group("📝 Result"), console.log("Text to insert:", JSON.stringify(i.text)), console.log("New selection:", `${i.selectionStart}-${i.selectionEnd}`), console.groupEnd());
642
+ }
643
+ let y = null;
644
+ function H(i, e) {
645
+ const t = V();
646
+ t && (console.group("🔧 insertText"), console.log("Current selection:", `${i.selectionStart}-${i.selectionEnd}`), console.log("Text to insert:", JSON.stringify(e.text)), console.log("New selection to set:", e.selectionStart, "-", e.selectionEnd)), i.focus();
647
+ const n = i.selectionStart, r = i.selectionEnd, o = i.value.slice(0, n), a = i.value.slice(r);
648
+ t && (console.log("Before text (last 20):", JSON.stringify(o.slice(-20))), console.log("After text (first 20):", JSON.stringify(a.slice(0, 20))), console.log(
649
+ "Selected text being replaced:",
650
+ JSON.stringify(i.value.slice(n, r))
651
+ ));
652
+ const s = i.value;
653
+ if (y === null || y === !0) {
654
+ i.contentEditable = "true";
655
+ try {
656
+ y = document.execCommand("insertText", !1, e.text), t && console.log(
657
+ "execCommand returned:",
658
+ y,
659
+ "for text with",
660
+ e.text.split(`
661
+ `).length,
662
+ "lines"
663
+ );
664
+ } catch (c) {
665
+ y = !1, t && console.log("execCommand threw error:", c);
666
+ }
667
+ i.contentEditable = "false";
668
+ }
669
+ if (t && (console.log("canInsertText before:", y), console.log("execCommand result:", y)), y) {
670
+ const c = o + e.text + a, p = i.value;
671
+ t && (console.log("Expected length:", c.length), console.log("Actual length:", p.length)), p !== c && t && (console.log("execCommand changed the value but not as expected"), console.log("Expected:", JSON.stringify(c.slice(0, 100))), console.log("Actual:", JSON.stringify(p.slice(0, 100))));
672
+ }
673
+ if (!y)
674
+ if (t && console.log("Using manual insertion"), i.value === s) {
675
+ t && console.log("Value unchanged, doing manual replacement");
676
+ try {
677
+ document.execCommand("ms-beginUndoUnit");
678
+ } catch {
679
+ }
680
+ i.value = o + e.text + a;
681
+ try {
682
+ document.execCommand("ms-endUndoUnit");
683
+ } catch {
684
+ }
685
+ i.dispatchEvent(new CustomEvent("input", { bubbles: !0, cancelable: !0 }));
686
+ } else t && console.log("Value was changed by execCommand, skipping manual insertion");
687
+ t && console.log("Setting selection range:", e.selectionStart, e.selectionEnd), e.selectionStart != null && e.selectionEnd != null ? i.setSelectionRange(e.selectionStart, e.selectionEnd) : i.setSelectionRange(n, i.selectionEnd), t && (console.log("Final value length:", i.value.length), console.groupEnd());
688
+ }
689
+ function pe(i) {
690
+ switch (i) {
691
+ case "native":
692
+ y = !0;
693
+ break;
694
+ case "manual":
695
+ y = !1;
696
+ break;
697
+ case "auto":
698
+ default:
699
+ y = null;
700
+ break;
701
+ }
702
+ }
703
+ function Se() {
704
+ return y === !0 ? "native" : y === !1 ? "manual" : "auto";
705
+ }
706
+ function O(i) {
707
+ return i.trim().split(`
708
+ `).length > 1;
709
+ }
710
+ function Ce(i, e) {
711
+ let t = e;
712
+ for (; i[t] && i[t - 1] != null && !/\s/.test(i[t - 1]); )
713
+ t -= 1;
714
+ return t;
715
+ }
716
+ function Ee(i, e, t) {
717
+ let n = e;
718
+ const r = t ? /\n/ : /\s/;
719
+ for (; i[n] && !r.test(i[n]); )
720
+ n += 1;
721
+ return n;
722
+ }
723
+ function de(i) {
724
+ const e = i.value.split(`
725
+ `);
726
+ let t = 0;
727
+ for (let n = 0; n < e.length; n += 1) {
728
+ const r = e[n].length + 1;
729
+ i.selectionStart >= t && i.selectionStart < t + r && (i.selectionStart = t), i.selectionEnd >= t && i.selectionEnd < t + r && (n === e.length - 1 ? i.selectionEnd = Math.min(t + e[n].length, i.value.length) : i.selectionEnd = t + r - 1), t += r;
730
+ }
731
+ }
732
+ function Te(i, e, t, n = !1) {
733
+ if (i.selectionStart === i.selectionEnd)
734
+ i.selectionStart = Ce(i.value, i.selectionStart), i.selectionEnd = Ee(i.value, i.selectionEnd, n);
735
+ else {
736
+ const r = i.selectionStart - e.length, o = i.selectionEnd + t.length, a = i.value.slice(r, i.selectionStart) === e, s = i.value.slice(i.selectionEnd, o) === t;
737
+ a && s && (i.selectionStart = r, i.selectionEnd = o);
738
+ }
739
+ return i.value.slice(i.selectionStart, i.selectionEnd);
740
+ }
741
+ function U(i) {
742
+ const e = i.value.slice(0, i.selectionStart), t = i.value.slice(i.selectionEnd), n = e.match(/\n*$/), r = t.match(/^\n*/), o = n ? n[0].length : 0, a = r ? r[0].length : 0;
743
+ let s = "", c = "";
744
+ return /\S/.test(e) && o < 2 && (s = `
745
+ `.repeat(2 - o)), /\S/.test(t) && a < 2 && (c = `
746
+ `.repeat(2 - a)), { newlinesToAppend: s, newlinesToPrepend: c };
747
+ }
748
+ function me(i, e) {
749
+ const t = i.selectionStart, n = i.selectionEnd, r = i.scrollTop;
750
+ e(), i.selectionStart = t, i.selectionEnd = n, i.scrollTop = r;
751
+ }
752
+ function j(i, e, t = {}) {
753
+ const n = i.selectionStart, r = i.selectionEnd, o = n === r, a = i.value;
754
+ let s = n;
755
+ for (; s > 0 && a[s - 1] !== `
756
+ `; )
757
+ s -= 1;
758
+ if (o) {
759
+ let p = n;
760
+ for (; p < a.length && a[p] !== `
761
+ `; )
762
+ p += 1;
763
+ i.selectionStart = s, i.selectionEnd = p;
764
+ } else
765
+ de(i);
766
+ const c = e(i);
767
+ if (t.adjustSelection) {
768
+ const p = i.value.slice(i.selectionStart, i.selectionEnd), d = t.prefix ?? "", l = d.length > 0 && p.startsWith(d), m = t.adjustSelection(
769
+ l,
770
+ n,
771
+ r,
772
+ s
773
+ );
774
+ return c.selectionStart = m.start, c.selectionEnd = m.end, c;
775
+ }
776
+ if (t.prefix) {
777
+ const d = i.value.slice(i.selectionStart, i.selectionEnd).startsWith(t.prefix);
778
+ if (o)
779
+ if (d) {
780
+ const l = Math.max(n - t.prefix.length, s);
781
+ c.selectionStart = l, c.selectionEnd = l;
782
+ } else {
783
+ const l = n + t.prefix.length;
784
+ c.selectionStart = l, c.selectionEnd = l;
785
+ }
786
+ else d ? (c.selectionStart = Math.max(n - t.prefix.length, s), c.selectionEnd = Math.max(r - t.prefix.length, s)) : (c.selectionStart = n + t.prefix.length, c.selectionEnd = r + t.prefix.length);
787
+ }
788
+ return c;
789
+ }
790
+ function $(i, e) {
791
+ const {
792
+ prefix: t,
793
+ suffix: n,
794
+ blockPrefix: r,
795
+ blockSuffix: o,
796
+ replaceNext: a,
797
+ prefixSpace: s,
798
+ scanFor: c,
799
+ surroundWithNewlines: p,
800
+ trimFirst: d
801
+ } = e, l = i.selectionStart, m = i.selectionEnd;
802
+ let u = i.value.slice(i.selectionStart, i.selectionEnd), h = O(u) && r && r.length > 0 ? `${r}
803
+ ` : t, f = O(u) && o && o.length > 0 ? `
804
+ ${o}` : n;
805
+ if (s) {
806
+ const z = i.value[i.selectionStart - 1];
807
+ i.selectionStart !== 0 && z != null && !/\s/.test(z) && (h = ` ${h}`);
808
+ }
809
+ u = Te(i, h, f, e.multiline);
810
+ let g = i.selectionStart, b = i.selectionEnd;
811
+ const v = !!a && a.length > 0 && f.includes(a) && u.length > 0;
812
+ let x = "", ee = "";
813
+ if (p) {
814
+ const z = U(i);
815
+ x = z.newlinesToAppend, ee = z.newlinesToPrepend, h = x + t, f += ee;
816
+ }
817
+ if (u.startsWith(h) && u.endsWith(f)) {
818
+ const z = u.slice(h.length, u.length - f.length);
819
+ if (l === m) {
820
+ let L = l - h.length;
821
+ L = Math.max(L, g), L = Math.min(L, g + z.length), g = L, b = L;
822
+ } else
823
+ b = g + z.length;
824
+ return { text: z, selectionStart: g, selectionEnd: b };
825
+ }
826
+ if (!v) {
827
+ let z = h + u + f;
828
+ g = l + h.length, b = m + h.length;
829
+ const L = u.match(/^\s*|\s*$/g);
830
+ if (d && L) {
831
+ const te = L[0] ?? "", ne = L[1] ?? "";
832
+ z = te + h + u.trim() + f + ne, g += te.length, b -= ne.length;
833
+ }
834
+ return { text: z, selectionStart: g, selectionEnd: b };
835
+ }
836
+ if (c && (typeof c == "string" ? new RegExp(c) : c).test(u)) {
837
+ const L = h + f.replace(a, u);
838
+ return g = g + h.length, b = g, { text: L, selectionStart: g, selectionEnd: b };
839
+ }
840
+ const ye = h + u + f, ze = f.indexOf(a);
841
+ return g = g + h.length + u.length + ze, b = g + a.length, { text: ye, selectionStart: g, selectionEnd: b };
842
+ }
843
+ function q(i, e) {
844
+ const { prefix: t, suffix: n, surroundWithNewlines: r } = e;
845
+ let o = i.value.slice(i.selectionStart, i.selectionEnd), a = i.selectionStart, s = i.selectionEnd;
846
+ const c = o.split(`
847
+ `);
848
+ if (c.every((d) => d.startsWith(t) && (!n || d.endsWith(n))))
849
+ o = c.map((d) => {
850
+ let l = d.slice(t.length);
851
+ return n && (l = l.slice(0, l.length - n.length)), l;
852
+ }).join(`
853
+ `), s = a + o.length;
854
+ else if (o = c.map((d) => t + d + (n ?? "")).join(`
855
+ `), r) {
856
+ const { newlinesToAppend: d, newlinesToPrepend: l } = U(i);
857
+ a += d.length, s = a + o.length, o = d + o + l;
858
+ }
859
+ return { text: o, selectionStart: a, selectionEnd: s };
860
+ }
861
+ function ie(i) {
862
+ const e = i.split(`
863
+ `), t = /^\d+\.\s+/, n = e.every((o) => t.test(o));
864
+ return {
865
+ text: (n ? e.map((o) => o.replace(t, "")) : e).join(`
866
+ `),
867
+ processed: n
868
+ };
869
+ }
870
+ function re(i) {
871
+ const e = i.split(`
872
+ `), t = "- ", n = e.every((o) => o.startsWith(t));
873
+ return {
874
+ text: (n ? e.map((o) => o.slice(t.length)) : e).join(`
875
+ `),
876
+ processed: n
877
+ };
878
+ }
879
+ function P(i, e) {
880
+ return e ? "- " : `${i + 1}. `;
881
+ }
882
+ function He(i, e) {
883
+ let t, n, r;
884
+ return i.orderedList ? (t = ie(e), n = re(t.text), r = n.text) : (t = re(e), n = ie(t.text), r = n.text), [t, n, r];
885
+ }
886
+ function Me(i, e) {
887
+ const t = i.selectionStart === i.selectionEnd;
888
+ let n = i.selectionStart, r = i.selectionEnd;
889
+ de(i);
890
+ const o = i.value.slice(i.selectionStart, i.selectionEnd), [a, s, c] = He(e, o), p = c.split(`
891
+ `).map((f, g) => `${P(g, e.unorderedList)}${f}`), d = p.reduce((f, g, b) => f + P(b, e.unorderedList).length, 0), l = p.reduce((f, g, b) => f + P(b, !e.unorderedList).length, 0);
892
+ if (a.processed)
893
+ return t ? (n = Math.max(n - P(0, e.unorderedList).length, 0), r = n) : (n = i.selectionStart, r = i.selectionEnd - d), { text: c, selectionStart: n, selectionEnd: r };
894
+ const { newlinesToAppend: m, newlinesToPrepend: u } = U(i), h = m + p.join(`
895
+ `) + u;
896
+ return t ? (n = Math.max(
897
+ n + P(0, e.unorderedList).length + m.length,
898
+ 0
899
+ ), r = n) : s.processed ? (n = Math.max(i.selectionStart + m.length, 0), r = i.selectionEnd + m.length + d - l) : (n = Math.max(i.selectionStart + m.length, 0), r = i.selectionEnd + m.length + d), { text: h, selectionStart: n, selectionEnd: r };
900
+ }
901
+ function he(i, e) {
902
+ const t = j(
903
+ i,
904
+ (n) => Me(n, e),
905
+ {
906
+ adjustSelection: (n, r, o, a) => {
907
+ const s = i.value.slice(a, i.selectionEnd), c = /^\d+\.\s+/, p = /^- /, d = c.test(s), l = p.test(s), m = e.orderedList && d || e.unorderedList && l;
908
+ if (r === o) {
909
+ if (m) {
910
+ const f = s.match(e.orderedList ? c : p), g = f ? f[0].length : 0;
911
+ return {
912
+ start: Math.max(r - g, a),
913
+ end: Math.max(r - g, a)
914
+ };
915
+ }
916
+ if (d || l) {
917
+ const f = s.match(d ? c : p), g = f ? f[0].length : 0, v = (e.unorderedList ? 2 : 3) - g;
918
+ return {
919
+ start: r + v,
920
+ end: r + v
921
+ };
922
+ }
923
+ const h = e.unorderedList ? 2 : 3;
924
+ return {
925
+ start: r + h,
926
+ end: r + h
927
+ };
928
+ }
929
+ if (m) {
930
+ const h = s.match(e.orderedList ? c : p), f = h ? h[0].length : 0;
931
+ return {
932
+ start: Math.max(r - f, a),
933
+ end: Math.max(o - f, a)
934
+ };
935
+ }
936
+ if (d || l) {
937
+ const h = s.match(d ? c : p), f = h ? h[0].length : 0, b = (e.unorderedList ? 2 : 3) - f;
938
+ return {
939
+ start: r + b,
940
+ end: o + b
941
+ };
942
+ }
943
+ const u = e.unorderedList ? 2 : 3;
944
+ return {
945
+ start: r + u,
946
+ end: o + u
947
+ };
948
+ },
949
+ prefix: e.unorderedList ? "- " : "1. "
950
+ }
951
+ );
952
+ H(i, t);
953
+ }
954
+ function Ae(i, e) {
955
+ const t = S[e];
956
+ if (!t) return !1;
957
+ const n = t.prefix ?? "", r = t.suffix ?? "";
958
+ return n ? r ? i.startsWith(n) && i.endsWith(r) : i.startsWith(n) : !1;
959
+ }
960
+ function W(i) {
961
+ if (!i) return [];
962
+ const e = [], { selectionStart: t, selectionEnd: n, value: r } = i, o = r.split(`
963
+ `);
964
+ let a = 0, s = "";
965
+ for (const l of o) {
966
+ if (t >= a && t <= a + l.length) {
967
+ s = l;
968
+ break;
969
+ }
970
+ a += l.length + 1;
971
+ }
972
+ s.startsWith("- ") && (s.startsWith("- [ ] ") || s.startsWith("- [x] ") ? e.push("task-list") : e.push("bullet-list")), /^\d+\.\s/.test(s) && e.push("numbered-list"), s.startsWith("> ") && e.push("quote"), s.startsWith("### ") ? e.push("header-3") : s.startsWith("## ") ? e.push("header-2") : s.startsWith("# ") && e.push("header");
973
+ const c = Math.max(0, t - 10), p = Math.min(r.length, n + 10), d = r.slice(c, p);
974
+ if (d.includes("**")) {
975
+ const l = r.slice(Math.max(0, t - 100), t), m = r.slice(n, Math.min(r.length, n + 100)), u = l.lastIndexOf("**"), h = m.indexOf("**");
976
+ u !== -1 && h !== -1 && e.push("bold");
977
+ }
978
+ if (d.includes("_")) {
979
+ const l = r.slice(Math.max(0, t - 100), t), m = r.slice(n, Math.min(r.length, n + 100)), u = l.lastIndexOf("_"), h = m.indexOf("_");
980
+ u !== -1 && h !== -1 && e.push("italic");
981
+ }
982
+ if (d.includes("`")) {
983
+ const l = r.slice(Math.max(0, t - 100), t), m = r.slice(n, Math.min(r.length, n + 100));
984
+ l.includes("`") && m.includes("`") && e.push("code");
985
+ }
986
+ if (d.includes("[") && d.includes("]")) {
987
+ const l = r.slice(Math.max(0, t - 100), t), m = r.slice(n, Math.min(r.length, n + 100)), u = l.lastIndexOf("["), h = m.indexOf("]");
988
+ u !== -1 && h !== -1 && r.slice(n + h + 1, n + h + 10).startsWith("(") && e.push("link");
989
+ }
990
+ return e;
991
+ }
992
+ function ue(i, e) {
993
+ return W(i).includes(e);
994
+ }
995
+ function fe(i, e = {}) {
996
+ if (!i) return;
997
+ const { toWord: t, toLine: n, toFormat: r } = e, { selectionStart: o, selectionEnd: a, value: s } = i;
998
+ if (n) {
999
+ const c = s.split(`
1000
+ `);
1001
+ let p = 0, d = 0, l = 0;
1002
+ for (const m of c) {
1003
+ if (o >= l && o <= l + m.length) {
1004
+ p = l, d = l + m.length;
1005
+ break;
1006
+ }
1007
+ l += m.length + 1;
1008
+ }
1009
+ i.selectionStart = p, i.selectionEnd = d;
1010
+ return;
1011
+ }
1012
+ if (r && Ae(s.slice(o, a), r)) {
1013
+ const c = S[r], p = (c.prefix ?? "").length, d = (c.suffix ?? "").length;
1014
+ i.selectionStart = Math.max(0, o - p), i.selectionEnd = Math.min(s.length, a + d);
1015
+ return;
1016
+ }
1017
+ if (t && o === a) {
1018
+ let c = o, p = a;
1019
+ for (; c > 0 && !/\s/.test(s[c - 1]); )
1020
+ c -= 1;
1021
+ for (; p < s.length && !/\s/.test(s[p]); )
1022
+ p += 1;
1023
+ i.selectionStart = c, i.selectionEnd = p;
1024
+ }
1025
+ }
1026
+ function E(i) {
1027
+ return !!i && !i.disabled && !i.readOnly;
1028
+ }
1029
+ function K(i) {
1030
+ if (!E(i)) return;
1031
+ k("toggleBold", "Starting"), R(i, "Before");
1032
+ const e = C(S.bold), t = $(i, e);
1033
+ D(t), H(i, t), R(i, "After");
1034
+ }
1035
+ function Z(i) {
1036
+ if (!E(i)) return;
1037
+ const e = C(S.italic), t = $(i, e);
1038
+ H(i, t);
1039
+ }
1040
+ function ge(i) {
1041
+ if (!E(i)) return;
1042
+ const e = C(S.code), t = $(i, e);
1043
+ H(i, t);
1044
+ }
1045
+ function J(i, e = {}) {
1046
+ if (!E(i)) return;
1047
+ const t = i.value.slice(i.selectionStart, i.selectionEnd);
1048
+ let n = C(S.link);
1049
+ if (t && /^https?:\/\//.test(t) && !e.url ? n = {
1050
+ ...n,
1051
+ suffix: `](${t})`,
1052
+ replaceNext: ""
1053
+ } : e.url && (n = {
1054
+ ...n,
1055
+ suffix: `](${e.url})`,
1056
+ replaceNext: ""
1057
+ }), e.text && !t) {
1058
+ const a = i.selectionStart;
1059
+ i.value = i.value.slice(0, a) + e.text + i.value.slice(a), i.selectionStart = a, i.selectionEnd = a + e.text.length;
1060
+ }
1061
+ const o = $(i, n);
1062
+ H(i, o);
1063
+ }
1064
+ function Q(i) {
1065
+ if (!E(i)) return;
1066
+ const e = C(S.bulletList);
1067
+ he(i, e);
1068
+ }
1069
+ function G(i) {
1070
+ if (!E(i)) return;
1071
+ const e = C(S.numberedList);
1072
+ he(i, e);
1073
+ }
1074
+ function X(i) {
1075
+ if (!E(i)) return;
1076
+ k("toggleQuote", "Starting"), R(i, "Initial");
1077
+ const e = C(S.quote), t = j(
1078
+ i,
1079
+ (n) => q(n, e),
1080
+ { prefix: e.prefix }
1081
+ );
1082
+ D(t), H(i, t), R(i, "Final");
1083
+ }
1084
+ function Y(i) {
1085
+ if (!E(i)) return;
1086
+ const e = C(S.taskList), t = j(
1087
+ i,
1088
+ (n) => q(n, e),
1089
+ { prefix: e.prefix }
1090
+ );
1091
+ H(i, t);
1092
+ }
1093
+ function $e(i, e, t) {
1094
+ let n = e;
1095
+ for (; n > 0 && i[n - 1] !== `
1096
+ `; )
1097
+ n -= 1;
1098
+ let r = t;
1099
+ for (; r < i.length && i[r] !== `
1100
+ `; )
1101
+ r += 1;
1102
+ return { lineStart: n, lineEnd: r };
1103
+ }
1104
+ function B(i, e = 1, t = !1) {
1105
+ if (!E(i)) return;
1106
+ (e < 1 || e > 6) && (e = 1), k("insertHeader", "============ START ============"), k("insertHeader", `Level: ${e}, Toggle: ${t}`), k("insertHeader", `Initial cursor: ${i.selectionStart}-${i.selectionEnd}`);
1107
+ const n = `header${e === 1 ? "1" : e}`, r = C(S[n] || S.header1);
1108
+ k("insertHeader", `Style prefix: "${r.prefix}"`);
1109
+ const o = i.value, a = i.selectionStart, s = i.selectionEnd, { lineStart: c, lineEnd: p } = $e(o, a, s), d = o.slice(c, p);
1110
+ k("insertHeader", `Current line (before): "${d}"`);
1111
+ const l = d.match(/^(#{1,6})\s*/), m = l ? l[1].length : 0, u = l ? l[0].length : 0;
1112
+ k("insertHeader", `Existing header match: ${l ? l[0] : "none"}`), k("insertHeader", `Existing level: ${m}`), k("insertHeader", `Target level: ${e}`);
1113
+ const h = t && m === e;
1114
+ k("insertHeader", `Should toggle OFF: ${h}`);
1115
+ const f = j(
1116
+ i,
1117
+ (g) => {
1118
+ const b = g.value.slice(g.selectionStart, g.selectionEnd);
1119
+ k("insertHeader", `Line in operation: "${b}"`);
1120
+ const v = b.replace(/^#{1,6}\s*/, "");
1121
+ k("insertHeader", `Cleaned line: "${v}"`);
1122
+ let x;
1123
+ return h ? (k("insertHeader", "ACTION: Toggling OFF - removing header"), x = v) : m > 0 ? (k("insertHeader", `ACTION: Replacing H${m} with H${e}`), x = r.prefix + v) : (k("insertHeader", "ACTION: Adding new header"), x = r.prefix + v), k("insertHeader", `New line: "${x}"`), {
1124
+ text: x,
1125
+ selectionStart: g.selectionStart,
1126
+ selectionEnd: g.selectionEnd
1127
+ };
1128
+ },
1129
+ {
1130
+ prefix: r.prefix,
1131
+ adjustSelection: (g, b, v) => {
1132
+ if (k("insertHeader", `Adjusting selection with existing prefix length ${u}`), h) {
1133
+ const x = Math.max(b - u, c);
1134
+ return {
1135
+ start: x,
1136
+ end: b === v ? x : Math.max(v - u, c)
1137
+ };
1138
+ }
1139
+ if (u > 0) {
1140
+ const x = r.prefix.length - u;
1141
+ return {
1142
+ start: b + x,
1143
+ end: v + x
1144
+ };
1145
+ }
1146
+ return {
1147
+ start: b + r.prefix.length,
1148
+ end: v + r.prefix.length
1149
+ };
1150
+ }
1151
+ }
1152
+ );
1153
+ D(f), k("insertHeader", "============ END ============"), H(i, f);
1154
+ }
1155
+ function be(i) {
1156
+ B(i, 1, !0);
1157
+ }
1158
+ function ve(i) {
1159
+ B(i, 2, !0);
1160
+ }
1161
+ function we(i) {
1162
+ B(i, 3, !0);
1163
+ }
1164
+ function ke(i, e) {
1165
+ if (!E(i)) return;
1166
+ const t = C(e);
1167
+ let n;
1168
+ if (t.multiline) {
1169
+ const r = i.value.slice(i.selectionStart, i.selectionEnd);
1170
+ O(r) ? n = q(i, t) : n = $(i, t);
1171
+ } else
1172
+ n = $(i, t);
1173
+ H(i, n);
1174
+ }
1175
+ const oe = {
1176
+ toggleBold: K,
1177
+ toggleItalic: Z,
1178
+ toggleCode: ge,
1179
+ insertLink: J,
1180
+ toggleBulletList: Q,
1181
+ toggleNumberedList: G,
1182
+ toggleQuote: X,
1183
+ toggleTaskList: Y,
1184
+ insertHeader: B,
1185
+ toggleH1: be,
1186
+ toggleH2: ve,
1187
+ toggleH3: we,
1188
+ getActiveFormats: W,
1189
+ hasFormat: ue,
1190
+ expandSelection: fe,
1191
+ applyCustomFormat: ke,
1192
+ preserveSelection: me,
1193
+ setUndoMethod: pe,
1194
+ setDebugMode: ce,
1195
+ getDebugMode: V
1196
+ }, Pe = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1197
+ __proto__: null,
1198
+ actions: oe,
1199
+ applyCustomFormat: ke,
1200
+ default: oe,
1201
+ expandSelection: fe,
1202
+ getActiveFormats: W,
1203
+ getDebugMode: V,
1204
+ getUndoMethod: Se,
1205
+ hasFormat: ue,
1206
+ insertHeader: B,
1207
+ insertLink: J,
1208
+ preserveSelection: me,
1209
+ setDebugMode: ce,
1210
+ setUndoMethod: pe,
1211
+ toggleBold: K,
1212
+ toggleBulletList: Q,
1213
+ toggleCode: ge,
1214
+ toggleH1: be,
1215
+ toggleH2: ve,
1216
+ toggleH3: we,
1217
+ toggleItalic: Z,
1218
+ toggleNumberedList: G,
1219
+ toggleQuote: X,
1220
+ toggleTaskList: Y
1221
+ }, Symbol.toStringTag, { value: "Module" })), _e = {
1222
+ b: "toggleBold",
1223
+ i: "toggleItalic",
1224
+ k: "insertLink"
1225
+ }, Ie = {
1226
+ Digit7: "toggleNumberedList",
1227
+ Digit8: "toggleBulletList"
1228
+ };
1229
+ class xe {
1230
+ constructor(e) {
1231
+ this.editor = e, this.textarea = e.textarea;
1232
+ }
1233
+ handleKeydown(e) {
1234
+ if (!(navigator.platform.toLowerCase().includes("mac") ? e.metaKey : e.ctrlKey)) return !1;
1235
+ const o = e.key.toLowerCase(), a = Ie[e.code], s = a ?? _e[o];
1236
+ return !s || a && !e.shiftKey || !a && (o === "b" || o === "i" || o === "k") && e.shiftKey ? !1 : (e.preventDefault(), this.editor.toolbar ? this.editor.toolbar.handleAction(s) : this.handleAction(s), !0);
1237
+ }
1238
+ handleAction(e) {
1239
+ const t = this.textarea;
1240
+ if (t) {
1241
+ switch (t.focus(), e) {
1242
+ case "toggleBold":
1243
+ K(t);
1244
+ break;
1245
+ case "toggleItalic":
1246
+ Z(t);
1247
+ break;
1248
+ case "insertLink":
1249
+ J(t);
1250
+ break;
1251
+ case "toggleBulletList":
1252
+ Q(t);
1253
+ break;
1254
+ case "toggleNumberedList":
1255
+ G(t);
1256
+ break;
1257
+ case "toggleQuote":
1258
+ X(t);
1259
+ break;
1260
+ case "toggleTaskList":
1261
+ Y(t);
1262
+ break;
1263
+ }
1264
+ t.dispatchEvent(new Event("input", { bubbles: !0 }));
1265
+ }
1266
+ }
1267
+ destroy() {
1268
+ }
1269
+ }
1270
+ const M = {
1271
+ name: "solar",
1272
+ colors: {
1273
+ bgPrimary: "#faf0ca",
1274
+ // Lemon Chiffon - main background
1275
+ bgSecondary: "#ffffff",
1276
+ // White - editor background
1277
+ text: "#0d3b66",
1278
+ // Yale Blue - main text
1279
+ h1: "#f95738",
1280
+ // Tomato - h1 headers
1281
+ h2: "#ee964b",
1282
+ // Sandy Brown - h2 headers
1283
+ h3: "#3d8a51",
1284
+ // Forest green - h3 headers
1285
+ strong: "#ee964b",
1286
+ // Sandy Brown - bold text
1287
+ em: "#f95738",
1288
+ // Tomato - italic text
1289
+ link: "#0d3b66",
1290
+ // Yale Blue - links
1291
+ code: "#0d3b66",
1292
+ // Yale Blue - inline code
1293
+ codeBg: "rgba(244, 211, 94, 0.4)",
1294
+ // Naples Yellow with transparency
1295
+ blockquote: "#5a7a9b",
1296
+ // Muted blue - blockquotes
1297
+ hr: "#5a7a9b",
1298
+ // Muted blue - horizontal rules
1299
+ syntaxMarker: "rgba(13, 59, 102, 0.52)",
1300
+ // Yale Blue with transparency
1301
+ cursor: "#f95738",
1302
+ // Tomato - cursor
1303
+ selection: "rgba(244, 211, 94, 0.4)",
1304
+ // Naples Yellow with transparency
1305
+ listMarker: "#ee964b",
1306
+ // Sandy Brown - list markers
1307
+ // Toolbar colors
1308
+ toolbarBg: "#ffffff",
1309
+ // White - toolbar background
1310
+ toolbarBorder: "rgba(13, 59, 102, 0.15)",
1311
+ // Yale Blue border
1312
+ toolbarIcon: "#0d3b66",
1313
+ // Yale Blue - icon color
1314
+ toolbarHover: "#f5f5f5",
1315
+ // Light gray - hover background
1316
+ toolbarActive: "#faf0ca"
1317
+ // Lemon Chiffon - active button background
1318
+ }
1319
+ }, se = {
1320
+ name: "cave",
1321
+ colors: {
1322
+ bgPrimary: "#141E26",
1323
+ // Deep ocean - main background
1324
+ bgSecondary: "#1D2D3E",
1325
+ // Darker charcoal - editor background
1326
+ text: "#c5dde8",
1327
+ // Light blue-gray - main text
1328
+ h1: "#d4a5ff",
1329
+ // Rich lavender - h1 headers
1330
+ h2: "#f6ae2d",
1331
+ // Hunyadi Yellow - h2 headers
1332
+ h3: "#9fcfec",
1333
+ // Brighter blue - h3 headers
1334
+ strong: "#f6ae2d",
1335
+ // Hunyadi Yellow - bold text
1336
+ em: "#9fcfec",
1337
+ // Brighter blue - italic text
1338
+ link: "#9fcfec",
1339
+ // Brighter blue - links
1340
+ code: "#c5dde8",
1341
+ // Light blue-gray - inline code
1342
+ codeBg: "#1a232b",
1343
+ // Very dark blue - code background
1344
+ blockquote: "#9fcfec",
1345
+ // Brighter blue - same as italic
1346
+ hr: "#c5dde8",
1347
+ // Light blue-gray - horizontal rules
1348
+ syntaxMarker: "rgba(159, 207, 236, 0.73)",
1349
+ // Brighter blue semi-transparent
1350
+ cursor: "#f26419",
1351
+ // Orange Pantone - cursor
1352
+ selection: "rgba(51, 101, 138, 0.4)",
1353
+ // Lapis Lazuli with transparency
1354
+ listMarker: "#f6ae2d",
1355
+ // Hunyadi Yellow - list markers
1356
+ // Toolbar colors for dark theme
1357
+ toolbarBg: "#1D2D3E",
1358
+ // Darker charcoal - toolbar background
1359
+ toolbarBorder: "rgba(197, 221, 232, 0.1)",
1360
+ // Light blue-gray border
1361
+ toolbarIcon: "#c5dde8",
1362
+ // Light blue-gray - icon color
1363
+ toolbarHover: "#243546",
1364
+ // Slightly lighter charcoal - hover background
1365
+ toolbarActive: "#2a3f52"
1366
+ // Even lighter - active button background
1367
+ }
1368
+ }, ae = {
1369
+ solar: M,
1370
+ cave: se,
1371
+ // Aliases for backward compatibility
1372
+ light: M,
1373
+ dark: se
1374
+ };
1375
+ function _(i) {
1376
+ return typeof i == "string" ? { ...ae[i] || ae.solar, name: i } : i;
1377
+ }
1378
+ function F(i) {
1379
+ const e = [];
1380
+ for (const [t, n] of Object.entries(i)) {
1381
+ const r = t.replace(/([A-Z])/g, "-$1").toLowerCase();
1382
+ e.push(`--${r}: ${n};`);
1383
+ }
1384
+ return e.join(`
1385
+ `);
1386
+ }
1387
+ function Be(i, e = {}) {
1388
+ return {
1389
+ ...i,
1390
+ colors: {
1391
+ ...i.colors,
1392
+ ...e
1393
+ }
1394
+ };
1395
+ }
1396
+ function Re(i = {}) {
1397
+ const {
1398
+ fontSize: e = "14px",
1399
+ lineHeight: t = 1.6,
1400
+ /* System-first, guaranteed monospaced; avoids Android 'ui-monospace' pitfalls */
1401
+ fontFamily: n = '"SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace',
1402
+ padding: r = "20px",
1403
+ theme: o = null,
1404
+ mobile: a = {}
1405
+ } = i, s = Object.keys(a).length > 0 ? `
1406
+ @media (max-width: 640px) {
1407
+ .marzipan-wrapper .marzipan-input,
1408
+ .marzipan-wrapper .marzipan-preview {
1409
+ ${Object.entries(a).map(([p, d]) => `${p.replace(/([A-Z])/g, "-$1").toLowerCase()}: ${d} !important;`).join(`
1410
+ `)}
1411
+ }
1412
+ }
1413
+ ` : "", c = o && o.colors ? F(o.colors) : "";
1414
+ return `
1415
+ /* Marzipan Editor Styles */
1416
+
1417
+ /* Middle-ground CSS Reset - Prevent parent styles from leaking in */
1418
+ .marzipan-container * {
1419
+ /* Box model - these commonly leak */
1420
+ margin: 0 !important;
1421
+ padding: 0 !important;
1422
+ border: 0 !important;
1423
+
1424
+ /* Layout - these can break our layout */
1425
+ /* Don't reset position - it breaks dropdowns */
1426
+ float: none !important;
1427
+ clear: none !important;
1428
+
1429
+ /* Typography - only reset decorative aspects */
1430
+ text-decoration: none !important;
1431
+ text-transform: none !important;
1432
+ letter-spacing: normal !important;
1433
+
1434
+ /* Visual effects that can interfere */
1435
+ box-shadow: none !important;
1436
+ text-shadow: none !important;
1437
+
1438
+ /* Ensure box-sizing is consistent */
1439
+ box-sizing: border-box !important;
1440
+
1441
+ /* Keep inheritance for these */
1442
+ /* font-family, color, line-height, font-size - inherit */
1443
+ }
1444
+
1445
+ /* Container base styles after reset */
1446
+ .marzipan-container {
1447
+ display: grid !important;
1448
+ grid-template-rows: auto 1fr auto !important;
1449
+ width: 100% !important;
1450
+ height: 100% !important;
1451
+ position: relative !important; /* Override reset - needed for absolute children */
1452
+ overflow: visible !important; /* Allow dropdown to overflow container */
1453
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
1454
+ text-align: left !important;
1455
+ ${c ? `
1456
+ /* Theme Variables */
1457
+ ${c}` : ""}
1458
+ }
1459
+
1460
+ /* Force left alignment for all elements in the editor */
1461
+ .marzipan-container .marzipan-wrapper * {
1462
+ text-align: left !important;
1463
+ }
1464
+
1465
+ /* Auto-resize mode styles */
1466
+ .marzipan-container.marzipan-auto-resize {
1467
+ height: auto !important;
1468
+ grid-template-rows: auto auto auto !important;
1469
+ }
1470
+
1471
+ .marzipan-container.marzipan-auto-resize .marzipan-wrapper {
1472
+ height: auto !important;
1473
+ min-height: 60px !important;
1474
+ overflow: visible !important;
1475
+ }
1476
+
1477
+ .marzipan-wrapper {
1478
+ position: relative !important; /* Override reset - needed for absolute children */
1479
+ width: 100% !important;
1480
+ height: 100% !important; /* Take full height of grid cell */
1481
+ min-height: 60px !important; /* Minimum usable height */
1482
+ overflow: hidden !important;
1483
+ background: var(--bg-secondary, #ffffff) !important;
1484
+ grid-row: 2 !important; /* Always second row in grid */
1485
+ z-index: 1; /* Below toolbar and dropdown */
1486
+ }
1487
+
1488
+ /* Critical alignment styles - must be identical for both layers */
1489
+ .marzipan-wrapper .marzipan-input,
1490
+ .marzipan-wrapper .marzipan-preview {
1491
+ /* Positioning - must be identical */
1492
+ position: absolute !important; /* Override reset - required for overlay */
1493
+ top: 0 !important;
1494
+ left: 0 !important;
1495
+ width: 100% !important;
1496
+ height: 100% !important;
1497
+
1498
+ /* Font properties - any difference breaks alignment */
1499
+ font-family: ${n} !important;
1500
+ font-variant-ligatures: none !important; /* keep metrics stable for code */
1501
+ font-size: var(--instance-font-size, ${e}) !important;
1502
+ line-height: var(--instance-line-height, ${t}) !important;
1503
+ font-weight: normal !important;
1504
+ font-style: normal !important;
1505
+ font-variant: normal !important;
1506
+ font-stretch: normal !important;
1507
+ font-kerning: none !important;
1508
+ font-feature-settings: normal !important;
1509
+
1510
+ /* Box model - must match exactly */
1511
+ padding: var(--instance-padding, ${r}) !important;
1512
+ margin: 0 !important;
1513
+ border: none !important;
1514
+ outline: none !important;
1515
+ box-sizing: border-box !important;
1516
+
1517
+ /* Text layout - critical for character positioning */
1518
+ white-space: pre-wrap !important;
1519
+ word-wrap: break-word !important;
1520
+ word-break: normal !important;
1521
+ overflow-wrap: break-word !important;
1522
+ tab-size: 2 !important;
1523
+ -moz-tab-size: 2 !important;
1524
+ text-align: left !important;
1525
+ text-indent: 0 !important;
1526
+ letter-spacing: normal !important;
1527
+ word-spacing: normal !important;
1528
+
1529
+ /* Text rendering */
1530
+ text-transform: none !important;
1531
+ text-rendering: auto !important;
1532
+ -webkit-font-smoothing: auto !important;
1533
+ -webkit-text-size-adjust: 100% !important;
1534
+
1535
+ /* Direction and writing */
1536
+ direction: ltr !important;
1537
+ writing-mode: horizontal-tb !important;
1538
+ unicode-bidi: normal !important;
1539
+ text-orientation: mixed !important;
1540
+
1541
+ /* Visual effects that could shift perception */
1542
+ text-shadow: none !important;
1543
+ filter: none !important;
1544
+ transform: none !important;
1545
+ zoom: 1 !important;
1546
+
1547
+ /* Vertical alignment */
1548
+ vertical-align: baseline !important;
1549
+
1550
+ /* Size constraints */
1551
+ min-width: 0 !important;
1552
+ min-height: 0 !important;
1553
+ max-width: none !important;
1554
+ max-height: none !important;
1555
+
1556
+ /* Overflow */
1557
+ overflow-y: auto !important;
1558
+ overflow-x: auto !important;
1559
+ /* overscroll-behavior removed to allow scroll-through to parent */
1560
+ scrollbar-width: auto !important;
1561
+ scrollbar-gutter: auto !important;
1562
+
1563
+ /* Animation/transition - disabled to prevent movement */
1564
+ animation: none !important;
1565
+ transition: none !important;
1566
+ }
1567
+
1568
+ /* Input layer styles */
1569
+ .marzipan-wrapper .marzipan-input {
1570
+ /* Layer positioning */
1571
+ z-index: 1 !important;
1572
+
1573
+ /* Text visibility */
1574
+ color: transparent !important;
1575
+ caret-color: var(--cursor, #f95738) !important;
1576
+ background-color: transparent !important;
1577
+
1578
+ /* Textarea-specific */
1579
+ resize: none !important;
1580
+ appearance: none !important;
1581
+ -webkit-appearance: none !important;
1582
+ -moz-appearance: none !important;
1583
+
1584
+ /* Prevent mobile zoom on focus */
1585
+ touch-action: manipulation !important;
1586
+
1587
+ /* Disable autofill and spellcheck */
1588
+ autocomplete: off !important;
1589
+ autocorrect: off !important;
1590
+ autocapitalize: off !important;
1591
+ spellcheck: false !important;
1592
+ }
1593
+
1594
+ .marzipan-wrapper .marzipan-input::selection {
1595
+ background-color: var(--selection, rgba(244, 211, 94, 0.4));
1596
+ }
1597
+
1598
+ /* Preview layer styles */
1599
+ .marzipan-wrapper .marzipan-preview {
1600
+ /* Layer positioning */
1601
+ z-index: 0 !important;
1602
+ pointer-events: none !important;
1603
+ color: var(--text, #0d3b66) !important;
1604
+ background-color: transparent !important;
1605
+
1606
+ /* Prevent text selection */
1607
+ user-select: none !important;
1608
+ -webkit-user-select: none !important;
1609
+ -moz-user-select: none !important;
1610
+ -ms-user-select: none !important;
1611
+ }
1612
+
1613
+ /* Defensive styles for preview child divs */
1614
+ .marzipan-wrapper .marzipan-preview div {
1615
+ /* Reset any inherited styles */
1616
+ margin: 0 !important;
1617
+ padding: 0 !important;
1618
+ border: none !important;
1619
+ text-align: left !important;
1620
+ text-indent: 0 !important;
1621
+ display: block !important;
1622
+ position: static !important;
1623
+ transform: none !important;
1624
+ min-height: 0 !important;
1625
+ max-height: none !important;
1626
+ line-height: inherit !important;
1627
+ font-size: inherit !important;
1628
+ font-family: inherit !important;
1629
+ }
1630
+
1631
+ /* Markdown element styling - NO SIZE CHANGES */
1632
+ .marzipan-wrapper .marzipan-preview .header {
1633
+ font-weight: bold !important;
1634
+ }
1635
+
1636
+ /* Header colors */
1637
+ .marzipan-wrapper .marzipan-preview .h1 {
1638
+ color: var(--h1, #f95738) !important;
1639
+ }
1640
+ .marzipan-wrapper .marzipan-preview .h2 {
1641
+ color: var(--h2, #ee964b) !important;
1642
+ }
1643
+ .marzipan-wrapper .marzipan-preview .h3 {
1644
+ color: var(--h3, #3d8a51) !important;
1645
+ }
1646
+
1647
+ /* Semantic headers - flatten in edit mode */
1648
+ .marzipan-wrapper .marzipan-preview h1,
1649
+ .marzipan-wrapper .marzipan-preview h2,
1650
+ .marzipan-wrapper .marzipan-preview h3 {
1651
+ font-size: inherit !important;
1652
+ font-weight: bold !important;
1653
+ margin: 0 !important;
1654
+ padding: 0 !important;
1655
+ display: inline !important;
1656
+ line-height: inherit !important;
1657
+ }
1658
+
1659
+ /* Header colors for semantic headers */
1660
+ .marzipan-wrapper .marzipan-preview h1 {
1661
+ color: var(--h1, #f95738) !important;
1662
+ }
1663
+ .marzipan-wrapper .marzipan-preview h2 {
1664
+ color: var(--h2, #ee964b) !important;
1665
+ }
1666
+ .marzipan-wrapper .marzipan-preview h3 {
1667
+ color: var(--h3, #3d8a51) !important;
1668
+ }
1669
+
1670
+ /* Lists - remove styling in edit mode */
1671
+ .marzipan-wrapper .marzipan-preview ul,
1672
+ .marzipan-wrapper .marzipan-preview ol {
1673
+ list-style: none !important;
1674
+ margin: 0 !important;
1675
+ padding: 0 !important;
1676
+ display: block !important; /* Lists need to be block for line breaks */
1677
+ }
1678
+
1679
+ .marzipan-wrapper .marzipan-preview li {
1680
+ display: block !important; /* Each item on its own line */
1681
+ margin: 0 !important;
1682
+ padding: 0 !important;
1683
+ /* Don't set list-style here - let ul/ol control it */
1684
+ }
1685
+
1686
+ /* Bold text */
1687
+ .marzipan-wrapper .marzipan-preview strong {
1688
+ color: var(--strong, #ee964b) !important;
1689
+ font-weight: bold !important;
1690
+ }
1691
+
1692
+ /* Italic text */
1693
+ .marzipan-wrapper .marzipan-preview em {
1694
+ color: var(--em, #f95738) !important;
1695
+ text-decoration-color: var(--em, #f95738) !important;
1696
+ text-decoration-thickness: 1px !important;
1697
+ font-style: italic !important;
1698
+ }
1699
+
1700
+ /* Strikethrough text */
1701
+ .marzipan-wrapper .marzipan-preview del {
1702
+ color: var(--del, #ee964b) !important;
1703
+ text-decoration: line-through !important;
1704
+ text-decoration-color: var(--del, #ee964b) !important;
1705
+ text-decoration-thickness: 1px !important;
1706
+ }
1707
+
1708
+ /* Inline code */
1709
+ .marzipan-wrapper .marzipan-preview code {
1710
+ background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
1711
+ color: var(--code, #0d3b66) !important;
1712
+ padding: 0 !important;
1713
+ border-radius: 2px !important;
1714
+ font-family: inherit !important;
1715
+ font-size: inherit !important;
1716
+ line-height: inherit !important;
1717
+ font-weight: normal !important;
1718
+ }
1719
+
1720
+ /* Code blocks - consolidated pre blocks */
1721
+ .marzipan-wrapper .marzipan-preview pre {
1722
+ padding: 0 !important;
1723
+ margin: 0 !important;
1724
+ border-radius: 4px !important;
1725
+ overflow-x: auto !important;
1726
+ }
1727
+
1728
+ /* Code block styling in normal mode - yellow background */
1729
+ .marzipan-wrapper .marzipan-preview pre.code-block {
1730
+ background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
1731
+ }
1732
+
1733
+ /* Code inside pre blocks - remove background */
1734
+ .marzipan-wrapper .marzipan-preview pre code {
1735
+ background: transparent !important;
1736
+ color: var(--code, #0d3b66) !important;
1737
+ }
1738
+
1739
+ /* Blockquotes */
1740
+ .marzipan-wrapper .marzipan-preview .blockquote {
1741
+ color: var(--blockquote, #5a7a9b) !important;
1742
+ padding: 0 !important;
1743
+ margin: 0 !important;
1744
+ border: none !important;
1745
+ }
1746
+
1747
+ /* Links */
1748
+ .marzipan-wrapper .marzipan-preview a {
1749
+ color: var(--link, #0d3b66) !important;
1750
+ text-decoration: underline !important;
1751
+ font-weight: normal !important;
1752
+ }
1753
+
1754
+ .marzipan-wrapper .marzipan-preview a:hover {
1755
+ text-decoration: underline !important;
1756
+ color: var(--link, #0d3b66) !important;
1757
+ }
1758
+
1759
+ /* Lists - no list styling */
1760
+ .marzipan-wrapper .marzipan-preview ul,
1761
+ .marzipan-wrapper .marzipan-preview ol {
1762
+ list-style: none !important;
1763
+ margin: 0 !important;
1764
+ padding: 0 !important;
1765
+ }
1766
+
1767
+
1768
+ /* Horizontal rules */
1769
+ .marzipan-wrapper .marzipan-preview hr {
1770
+ border: none !important;
1771
+ color: var(--hr, #5a7a9b) !important;
1772
+ margin: 0 !important;
1773
+ padding: 0 !important;
1774
+ }
1775
+
1776
+ .marzipan-wrapper .marzipan-preview .hr-marker {
1777
+ color: var(--hr, #5a7a9b) !important;
1778
+ opacity: 0.6 !important;
1779
+ }
1780
+
1781
+ /* Code fence markers - with background when not in code block */
1782
+ .marzipan-wrapper .marzipan-preview .code-fence {
1783
+ color: var(--code, #0d3b66) !important;
1784
+ background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
1785
+ }
1786
+
1787
+ /* Code block lines - background for entire code block */
1788
+ .marzipan-wrapper .marzipan-preview .code-block-line {
1789
+ background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
1790
+ }
1791
+
1792
+ /* Remove background from code fence when inside code block line */
1793
+ .marzipan-wrapper .marzipan-preview .code-block-line .code-fence {
1794
+ background: transparent !important;
1795
+ }
1796
+
1797
+ /* Raw markdown line */
1798
+ .marzipan-wrapper .marzipan-preview .raw-line {
1799
+ color: var(--raw-line, #5a7a9b) !important;
1800
+ font-style: normal !important;
1801
+ font-weight: normal !important;
1802
+ }
1803
+
1804
+ /* Syntax markers */
1805
+ .marzipan-wrapper .marzipan-preview .syntax-marker {
1806
+ color: var(--syntax-marker, rgba(13, 59, 102, 0.52)) !important;
1807
+ opacity: 0.7 !important;
1808
+ }
1809
+
1810
+ /* List markers */
1811
+ .marzipan-wrapper .marzipan-preview .list-marker {
1812
+ color: var(--list-marker, #ee964b) !important;
1813
+ }
1814
+
1815
+ /* Stats bar */
1816
+
1817
+ /* Stats bar - positioned by grid, not absolute */
1818
+ .marzipan-stats {
1819
+ height: 40px !important;
1820
+ padding: 0 20px !important;
1821
+ background: #f8f9fa !important;
1822
+ border-top: 1px solid #e0e0e0 !important;
1823
+ display: flex !important;
1824
+ justify-content: space-between !important;
1825
+ align-items: center !important;
1826
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
1827
+ font-size: 0.85rem !important;
1828
+ color: #666 !important;
1829
+ grid-row: 3 !important; /* Always third row in grid */
1830
+ }
1831
+
1832
+ /* Dark theme stats bar */
1833
+ .marzipan-container[data-theme="cave"] .marzipan-stats {
1834
+ background: var(--bg-secondary, #1D2D3E) !important;
1835
+ border-top: 1px solid rgba(197, 221, 232, 0.1) !important;
1836
+ color: var(--text, #c5dde8) !important;
1837
+ }
1838
+
1839
+ .marzipan-stats .marzipan-stat {
1840
+ display: flex !important;
1841
+ align-items: center !important;
1842
+ gap: 5px !important;
1843
+ white-space: nowrap !important;
1844
+ }
1845
+
1846
+ .marzipan-stats .live-dot {
1847
+ width: 8px !important;
1848
+ height: 8px !important;
1849
+ background: #4caf50 !important;
1850
+ border-radius: 50% !important;
1851
+ animation: marzipan-pulse 2s infinite !important;
1852
+ }
1853
+
1854
+ @keyframes marzipan-pulse {
1855
+ 0%, 100% { opacity: 1; transform: scale(1); }
1856
+ 50% { opacity: 0.6; transform: scale(1.2); }
1857
+ }
1858
+
1859
+
1860
+ /* Toolbar Styles */
1861
+ .marzipan-toolbar {
1862
+ display: flex !important;
1863
+ align-items: center !important;
1864
+ gap: 4px !important;
1865
+ padding: 8px !important; /* Override reset */
1866
+ background: var(--toolbar-bg, var(--bg-primary, #f8f9fa)) !important; /* Override reset */
1867
+ border-bottom: 1px solid var(--toolbar-border, rgba(0, 0, 0, 0.08)) !important;
1868
+ overflow-x: auto !important; /* Allow horizontal scrolling */
1869
+ overflow-y: hidden !important; /* Hide vertical overflow */
1870
+ -webkit-overflow-scrolling: touch !important;
1871
+ flex-shrink: 0 !important;
1872
+ height: auto !important;
1873
+ grid-row: 1 !important; /* Always first row in grid */
1874
+ position: relative !important; /* Override reset */
1875
+ z-index: 100 !important; /* Ensure toolbar is above wrapper */
1876
+ scrollbar-width: thin; /* Thin scrollbar on Firefox */
1877
+ }
1878
+
1879
+ /* Thin scrollbar styling */
1880
+ .marzipan-toolbar::-webkit-scrollbar {
1881
+ height: 4px;
1882
+ }
1883
+
1884
+ .marzipan-toolbar::-webkit-scrollbar-track {
1885
+ background: transparent;
1886
+ }
1887
+
1888
+ .marzipan-toolbar::-webkit-scrollbar-thumb {
1889
+ background: rgba(0, 0, 0, 0.2);
1890
+ border-radius: 2px;
1891
+ }
1892
+
1893
+ .marzipan-toolbar-button {
1894
+ display: flex;
1895
+ align-items: center;
1896
+ justify-content: center;
1897
+ width: 32px;
1898
+ height: 32px;
1899
+ padding: 0;
1900
+ border: none;
1901
+ border-radius: 6px;
1902
+ background: transparent;
1903
+ color: var(--toolbar-icon, var(--text-secondary, #666));
1904
+ cursor: pointer;
1905
+ transition: all 0.2s ease;
1906
+ flex-shrink: 0;
1907
+ }
1908
+
1909
+ .marzipan-toolbar-button svg {
1910
+ width: 20px;
1911
+ height: 20px;
1912
+ fill: currentColor;
1913
+ }
1914
+
1915
+ .marzipan-toolbar-button:hover {
1916
+ background: var(--toolbar-hover, var(--bg-secondary, #e9ecef));
1917
+ color: var(--toolbar-icon, var(--text-primary, #333));
1918
+ }
1919
+
1920
+ .marzipan-toolbar-button:active {
1921
+ transform: scale(0.95);
1922
+ }
1923
+
1924
+ .marzipan-toolbar-button.active {
1925
+ background: var(--toolbar-active, var(--primary, #007bff));
1926
+ color: var(--toolbar-icon, var(--text-primary, #333));
1927
+ }
1928
+
1929
+ .marzipan-toolbar-button:disabled {
1930
+ opacity: 0.5;
1931
+ cursor: not-allowed;
1932
+ }
1933
+
1934
+ .marzipan-toolbar-separator {
1935
+ width: 1px;
1936
+ height: 24px;
1937
+ background: var(--border, #e0e0e0);
1938
+ margin: 0 4px;
1939
+ flex-shrink: 0;
1940
+ }
1941
+
1942
+ /* Adjust wrapper when toolbar is present */
1943
+ .marzipan-container .marzipan-toolbar + .marzipan-wrapper {
1944
+ }
1945
+
1946
+ /* Mobile toolbar adjustments */
1947
+ @media (max-width: 640px) {
1948
+ .marzipan-toolbar {
1949
+ padding: 6px;
1950
+ gap: 2px;
1951
+ }
1952
+
1953
+ .marzipan-toolbar-button {
1954
+ width: 36px;
1955
+ height: 36px;
1956
+ }
1957
+
1958
+ .marzipan-toolbar-separator {
1959
+ margin: 0 2px;
1960
+ }
1961
+ }
1962
+
1963
+ /* Plain mode - hide preview and show textarea text */
1964
+ .marzipan-container.plain-mode .marzipan-preview {
1965
+ display: none !important;
1966
+ }
1967
+
1968
+ .marzipan-container.plain-mode .marzipan-input {
1969
+ color: var(--text, #0d3b66) !important;
1970
+ /* Use system font stack for better plain text readability */
1971
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
1972
+ "Helvetica Neue", Arial, sans-serif !important;
1973
+ }
1974
+
1975
+ /* Ensure textarea remains transparent in overlay mode */
1976
+ .marzipan-container:not(.plain-mode) .marzipan-input {
1977
+ color: transparent !important;
1978
+ }
1979
+
1980
+ /* Dropdown menu styles */
1981
+ .marzipan-toolbar-button {
1982
+ position: relative !important; /* Override reset - needed for dropdown */
1983
+ }
1984
+
1985
+ .marzipan-toolbar-button.dropdown-active {
1986
+ background: var(--toolbar-active, var(--hover-bg, #f0f0f0));
1987
+ }
1988
+
1989
+ .marzipan-dropdown-menu {
1990
+ position: fixed !important; /* Fixed positioning relative to viewport */
1991
+ background: var(--bg-secondary, white) !important; /* Override reset */
1992
+ border: 1px solid var(--border, #e0e0e0) !important; /* Override reset */
1993
+ border-radius: 6px;
1994
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important; /* Override reset */
1995
+ z-index: 10000; /* Very high z-index to ensure visibility */
1996
+ min-width: 150px;
1997
+ padding: 4px 0 !important; /* Override reset */
1998
+ /* Position will be set via JavaScript based on button position */
1999
+ }
2000
+
2001
+ .marzipan-dropdown-item {
2002
+ display: flex;
2003
+ align-items: center;
2004
+ width: 100%;
2005
+ padding: 8px 12px;
2006
+ border: none;
2007
+ background: none;
2008
+ text-align: left;
2009
+ cursor: pointer;
2010
+ font-size: 14px;
2011
+ color: var(--text, #333);
2012
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
2013
+ }
2014
+
2015
+ .marzipan-dropdown-item:hover {
2016
+ background: var(--hover-bg, #f0f0f0);
2017
+ }
2018
+
2019
+ .marzipan-dropdown-item.active {
2020
+ font-weight: 600;
2021
+ }
2022
+
2023
+ .marzipan-dropdown-check {
2024
+ width: 16px;
2025
+ margin-right: 8px;
2026
+ color: var(--h1, #007bff);
2027
+ }
2028
+
2029
+ /* Preview mode styles */
2030
+ .marzipan-container.preview-mode .marzipan-input {
2031
+ display: none !important;
2032
+ }
2033
+
2034
+ .marzipan-container.preview-mode .marzipan-preview {
2035
+ pointer-events: auto !important;
2036
+ user-select: text !important;
2037
+ cursor: text !important;
2038
+ }
2039
+
2040
+ /* Hide syntax markers in preview mode */
2041
+ .marzipan-container.preview-mode .syntax-marker {
2042
+ display: none !important;
2043
+ }
2044
+
2045
+ /* Hide URL part of links in preview mode - extra specificity */
2046
+ .marzipan-container.preview-mode .syntax-marker.url-part,
2047
+ .marzipan-container.preview-mode .url-part {
2048
+ display: none !important;
2049
+ }
2050
+
2051
+ /* Hide all syntax markers inside links too */
2052
+ .marzipan-container.preview-mode a .syntax-marker {
2053
+ display: none !important;
2054
+ }
2055
+
2056
+ /* Headers - restore proper sizing in preview mode */
2057
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview h1,
2058
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview h2,
2059
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview h3 {
2060
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
2061
+ font-weight: 600 !important;
2062
+ margin: 0 !important;
2063
+ display: block !important;
2064
+ color: inherit !important; /* Use parent text color */
2065
+ line-height: 1 !important; /* Tight line height for headings */
2066
+ }
2067
+
2068
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview h1 {
2069
+ font-size: 2em !important;
2070
+ }
2071
+
2072
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview h2 {
2073
+ font-size: 1.5em !important;
2074
+ }
2075
+
2076
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview h3 {
2077
+ font-size: 1.17em !important;
2078
+ }
2079
+
2080
+ /* Lists - restore list styling in preview mode */
2081
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview ul {
2082
+ display: block !important;
2083
+ list-style: disc !important;
2084
+ padding-left: 2em !important;
2085
+ margin: 1em 0 !important;
2086
+ }
2087
+
2088
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview ol {
2089
+ display: block !important;
2090
+ list-style: decimal !important;
2091
+ padding-left: 2em !important;
2092
+ margin: 1em 0 !important;
2093
+ }
2094
+
2095
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview li {
2096
+ display: list-item !important;
2097
+ margin: 0 !important;
2098
+ padding: 0 !important;
2099
+ }
2100
+
2101
+ /* Links - make clickable in preview mode */
2102
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview a {
2103
+ pointer-events: auto !important;
2104
+ cursor: pointer !important;
2105
+ color: var(--link, #0066cc) !important;
2106
+ text-decoration: underline !important;
2107
+ }
2108
+
2109
+ /* Code blocks - proper pre/code styling in preview mode */
2110
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview pre.code-block {
2111
+ background: #2d2d2d !important;
2112
+ color: #f8f8f2 !important;
2113
+ padding: 1.2em !important;
2114
+ border-radius: 3px !important;
2115
+ overflow-x: auto !important;
2116
+ margin: 0 !important;
2117
+ display: block !important;
2118
+ }
2119
+
2120
+ /* Cave theme code block background in preview mode */
2121
+ .marzipan-container[data-theme="cave"].preview-mode .marzipan-wrapper .marzipan-preview pre.code-block {
2122
+ background: #11171F !important;
2123
+ }
2124
+
2125
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview pre.code-block code {
2126
+ background: transparent !important;
2127
+ color: inherit !important;
2128
+ padding: 0 !important;
2129
+ font-family: ${n} !important;
2130
+ font-size: 0.9em !important;
2131
+ line-height: 1.4 !important;
2132
+ }
2133
+
2134
+ /* Hide old code block lines and fences in preview mode */
2135
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview .code-block-line {
2136
+ display: none !important;
2137
+ }
2138
+
2139
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview .code-fence {
2140
+ display: none !important;
2141
+ }
2142
+
2143
+ /* Blockquotes - enhanced styling in preview mode */
2144
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview .blockquote {
2145
+ display: block !important;
2146
+ border-left: 4px solid var(--blockquote, #ddd) !important;
2147
+ padding-left: 1em !important;
2148
+ margin: 1em 0 !important;
2149
+ font-style: italic !important;
2150
+ }
2151
+
2152
+ /* Typography improvements in preview mode */
2153
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview {
2154
+ font-family: Georgia, 'Times New Roman', serif !important;
2155
+ font-size: 16px !important;
2156
+ line-height: 1.8 !important;
2157
+ color: var(--text, #333) !important; /* Consistent text color */
2158
+ }
2159
+
2160
+ /* Inline code in preview mode - keep monospace */
2161
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview code {
2162
+ font-family: ${n} !important;
2163
+ font-size: 0.9em !important;
2164
+ background: rgba(135, 131, 120, 0.15) !important;
2165
+ padding: 0.2em 0.4em !important;
2166
+ border-radius: 3px !important;
2167
+ }
2168
+
2169
+ /* Strong and em elements in preview mode */
2170
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview strong {
2171
+ font-weight: 700 !important;
2172
+ color: inherit !important; /* Use parent text color */
2173
+ }
2174
+
2175
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview em {
2176
+ font-style: italic !important;
2177
+ color: inherit !important; /* Use parent text color */
2178
+ }
2179
+
2180
+ /* HR in preview mode */
2181
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview .hr-marker {
2182
+ display: block !important;
2183
+ border-top: 2px solid var(--hr, #ddd) !important;
2184
+ text-indent: -9999px !important;
2185
+ height: 2px !important;
2186
+ }
2187
+
2188
+ /* Tables - GFM-style table rendering */
2189
+ .marzipan-preview .marzipan-table {
2190
+ border-collapse: collapse;
2191
+ margin: 1em 0;
2192
+ width: 100%;
2193
+ overflow: auto;
2194
+ }
2195
+
2196
+ .marzipan-preview .marzipan-table th,
2197
+ .marzipan-preview .marzipan-table td {
2198
+ border: 1px solid var(--border, #ddd);
2199
+ padding: 0.5em 1em;
2200
+ text-align: left;
2201
+ }
2202
+
2203
+ .marzipan-preview .marzipan-table th {
2204
+ background: var(--bgSecondary, #f5f5f5);
2205
+ font-weight: 600;
2206
+ }
2207
+
2208
+ .marzipan-preview .marzipan-table tr:nth-child(even) {
2209
+ background: var(--bgSecondary, #f9f9f9);
2210
+ }
2211
+
2212
+ /* In preview mode - hide table syntax markers */
2213
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview .table-row,
2214
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview .table-separator {
2215
+ display: none !important;
2216
+ }
2217
+
2218
+ /* Images - responsive and styled */
2219
+ .marzipan-preview .marzipan-image {
2220
+ max-width: 100%;
2221
+ height: auto;
2222
+ display: inline-block;
2223
+ border-radius: 4px;
2224
+ margin: 0.5em 0;
2225
+ }
2226
+
2227
+ /* In preview mode - make images fully visible */
2228
+ .marzipan-container.preview-mode .marzipan-wrapper .marzipan-preview .marzipan-image {
2229
+ display: block;
2230
+ margin: 1em auto;
2231
+ }
2232
+
2233
+ ${s}
2234
+ `;
2235
+ }
2236
+ const Ne = `<svg viewBox="0 0 18 18">
2237
+ <path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5,4H9.5A2.5,2.5,0,0,1,12,6.5v0A2.5,2.5,0,0,1,9.5,9H5A0,0,0,0,1,5,9V4A0,0,0,0,1,5,4Z"></path>
2238
+ <path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5,9h5.5A2.5,2.5,0,0,1,13,11.5v0A2.5,2.5,0,0,1,10.5,14H5a0,0,0,0,1,0,0V9A0,0,0,0,1,5,9Z"></path>
2239
+ </svg>`, je = `<svg viewBox="0 0 18 18">
2240
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="13" y1="4" y2="4"></line>
2241
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="5" x2="11" y1="14" y2="14"></line>
2242
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="10" y1="14" y2="4"></line>
2243
+ </svg>`, Oe = `<svg viewBox="0 0 18 18">
2244
+ <path fill="currentColor" d="M10,4V14a1,1,0,0,1-2,0V10H3v4a1,1,0,0,1-2,0V4A1,1,0,0,1,3,4V8H8V4a1,1,0,0,1,2,0Zm6.06787,9.209H14.98975V7.59863a.54085.54085,0,0,0-.605-.60547h-.62744a1.01119,1.01119,0,0,0-.748.29688L11.645,8.56641a.5435.5435,0,0,0-.022.8584l.28613.30762a.53861.53861,0,0,0,.84717.0332l.09912-.08789a1.2137,1.2137,0,0,0,.2417-.35254h.02246s-.01123.30859-.01123.60547V13.209H12.041a.54085.54085,0,0,0-.605.60547v.43945a.54085.54085,0,0,0,.605.60547h4.02686a.54085.54085,0,0,0,.605-.60547v-.43945A.54085.54085,0,0,0,16.06787,13.209Z"></path>
2245
+ </svg>`, Fe = `<svg viewBox="0 0 18 18">
2246
+ <path fill="currentColor" d="M16.73975,13.81445v.43945a.54085.54085,0,0,1-.605.60547H11.855a.58392.58392,0,0,1-.64893-.60547V14.0127c0-2.90527,3.39941-3.42187,3.39941-4.55469a.77675.77675,0,0,0-.84717-.78125,1.17684,1.17684,0,0,0-.83594.38477c-.2749.26367-.561.374-.85791.13184l-.4292-.34082c-.30811-.24219-.38525-.51758-.1543-.81445a2.97155,2.97155,0,0,1,2.45361-1.17676,2.45393,2.45393,0,0,1,2.68408,2.40918c0,2.45312-3.1792,2.92676-3.27832,3.93848h2.79443A.54085.54085,0,0,1,16.73975,13.81445ZM9,3A.99974.99974,0,0,0,8,4V8H3V4A1,1,0,0,0,1,4V14a1,1,0,0,0,2,0V10H8v4a1,1,0,0,0,2,0V4A.99974.99974,0,0,0,9,3Z"></path>
2247
+ </svg>`, Ve = `<svg viewBox="0 0 18 18">
2248
+ <path fill="currentColor" d="M16.65186,12.30664a2.6742,2.6742,0,0,1-2.915,2.68457,3.96592,3.96592,0,0,1-2.25537-.6709.56007.56007,0,0,1-.13232-.83594L11.64648,13c.209-.34082.48389-.36328.82471-.1543a2.32654,2.32654,0,0,0,1.12256.33008c.71484,0,1.12207-.35156,1.12207-.78125,0-.61523-.61621-.86816-1.46338-.86816H13.2085a.65159.65159,0,0,1-.68213-.41895l-.05518-.10937a.67114.67114,0,0,1,.14307-.78125l.71533-.86914a8.55289,8.55289,0,0,1,.68213-.7373V8.58887a3.93913,3.93913,0,0,1-.748.05469H11.9873a.54085.54085,0,0,1-.605-.60547V7.59863a.54085.54085,0,0,1,.605-.60547h3.75146a.53773.53773,0,0,1,.60547.59375v.17676a1.03723,1.03723,0,0,1-.27539.748L14.74854,10.0293A2.31132,2.31132,0,0,1,16.65186,12.30664ZM9,3A.99974.99974,0,0,0,8,4V8H3V4A1,1,0,0,0,1,4V14a1,1,0,0,0,2,0V10H8v4a1,1,0,0,0,2,0V4A.99974.99974,0,0,0,9,3Z"></path>
2249
+ </svg>`, De = `<svg viewBox="0 0 18 18">
2250
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="11" y1="7" y2="11"></line>
2251
+ <path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.9,4.577a3.476,3.476,0,0,1,.36,4.679A3.476,3.476,0,0,1,4.577,8.9C3.185,7.5,2.035,6.4,4.217,4.217S7.5,3.185,8.9,4.577Z"></path>
2252
+ <path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.423,9.1a3.476,3.476,0,0,0-4.679-.36,3.476,3.476,0,0,0,.36,4.679c1.392,1.392,2.5,2.542,4.679.36S14.815,10.5,13.423,9.1Z"></path>
2253
+ </svg>`, Ue = `<svg viewBox="0 0 18 18">
2254
+ <polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="5 7 3 9 5 11"></polyline>
2255
+ <polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="13 7 15 9 13 11"></polyline>
2256
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="10" x2="8" y1="5" y2="13"></line>
2257
+ </svg>`, qe = `<svg viewBox="0 0 18 18">
2258
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="4" y2="4"></line>
2259
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="9" y2="9"></line>
2260
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="14" y2="14"></line>
2261
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="4" y2="4"></line>
2262
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="9" y2="9"></line>
2263
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="14" y2="14"></line>
2264
+ </svg>`, We = `<svg viewBox="0 0 18 18">
2265
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="4" y2="4"></line>
2266
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="9" y2="9"></line>
2267
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="14" y2="14"></line>
2268
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" x1="2.5" x2="4.5" y1="5.5" y2="5.5"></line>
2269
+ <path fill="currentColor" d="M3.5,6A0.5,0.5,0,0,1,3,5.5V3.085l-0.276.138A0.5,0.5,0,0,1,2.053,3c-0.124-.247-0.023-0.324.224-0.447l1-.5A0.5,0.5,0,0,1,4,2.5v3A0.5,0.5,0,0,1,3.5,6Z"></path>
2270
+ <path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M4.5,10.5h-2c0-.234,1.85-1.076,1.85-2.234A0.959,0.959,0,0,0,2.5,8.156"></path>
2271
+ <path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M2.5,14.846a0.959,0.959,0,0,0,1.85-.109A0.7,0.7,0,0,0,3.75,14a0.688,0.688,0,0,0,.6-0.736,0.959,0.959,0,0,0-1.85-.109"></path>
2272
+ </svg>`, Ke = `<svg viewBox="2 2 20 20">
2273
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 10.8182L9 10.8182C8.80222 10.8182 8.60888 10.7649 8.44443 10.665C8.27998 10.5651 8.15181 10.4231 8.07612 10.257C8.00043 10.0909 7.98063 9.90808 8.01922 9.73174C8.0578 9.55539 8.15304 9.39341 8.29289 9.26627C8.43275 9.13913 8.61093 9.05255 8.80491 9.01747C8.99889 8.98239 9.19996 9.00039 9.38268 9.0692C9.56541 9.13801 9.72159 9.25453 9.83147 9.40403C9.94135 9.55353 10 9.72929 10 9.90909L10 12.1818C10 12.664 9.78929 13.1265 9.41421 13.4675C9.03914 13.8084 8.53043 14 8 14"></path>
2274
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 10.8182L15 10.8182C14.8022 10.8182 14.6089 10.7649 14.4444 10.665C14.28 10.5651 14.1518 10.4231 14.0761 10.257C14.0004 10.0909 13.9806 9.90808 14.0192 9.73174C14.0578 9.55539 14.153 9.39341 14.2929 9.26627C14.4327 9.13913 14.6109 9.05255 14.8049 9.01747C14.9989 8.98239 15.2 9.00039 15.3827 9.0692C15.5654 9.13801 15.7216 9.25453 15.8315 9.40403C15.9414 9.55353 16 9.72929 16 9.90909L16 12.1818C16 12.664 15.7893 13.1265 15.4142 13.4675C15.0391 13.8084 14.5304 14 14 14"></path>
2275
+ </svg>`, Ze = `<svg viewBox="0 0 18 18">
2276
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="4" y2="4"></line>
2277
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="9" y2="9"></line>
2278
+ <line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="14" y2="14"></line>
2279
+ <rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="3" width="3" height="3" rx="0.5"></rect>
2280
+ <rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="13" width="3" height="3" rx="0.5"></rect>
2281
+ <polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" points="2.65 9.5 3.5 10.5 5 8.5"></polyline>
2282
+ </svg>`, Je = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2283
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" fill="none"></path>
2284
+ <circle cx="12" cy="12" r="3" fill="none"></circle>
2285
+ </svg>`;
2286
+ class Qe {
2287
+ constructor(e, t = null) {
2288
+ this.container = null, this.buttons = {}, this.actions = Pe, this.editor = e, this.buttonConfig = t;
2289
+ }
2290
+ create() {
2291
+ this.container = document.createElement("div"), this.container.className = "marzipan-toolbar", this.container.setAttribute("role", "toolbar"), this.container.setAttribute("aria-label", "Text formatting"), (this.buttonConfig ?? [
2292
+ { name: "bold", icon: Ne, title: "Bold (Ctrl+B)", action: "toggleBold" },
2293
+ { name: "italic", icon: je, title: "Italic (Ctrl+I)", action: "toggleItalic" },
2294
+ { separator: !0 },
2295
+ { name: "h1", icon: Oe, title: "Heading 1", action: "insertH1" },
2296
+ { name: "h2", icon: Fe, title: "Heading 2", action: "insertH2" },
2297
+ { name: "h3", icon: Ve, title: "Heading 3", action: "insertH3" },
2298
+ { separator: !0 },
2299
+ { name: "link", icon: De, title: "Insert Link (Ctrl+K)", action: "insertLink" },
2300
+ { name: "code", icon: Ue, title: "Code (Ctrl+`)", action: "toggleCode" },
2301
+ { separator: !0 },
2302
+ { name: "quote", icon: Ke, title: "Quote", action: "toggleQuote" },
2303
+ { separator: !0 },
2304
+ { name: "bulletList", icon: qe, title: "Bullet List", action: "toggleBulletList" },
2305
+ { name: "orderedList", icon: We, title: "Numbered List", action: "toggleNumberedList" },
2306
+ { name: "taskList", icon: Ze, title: "Task List", action: "toggleTaskList" },
2307
+ { separator: !0 },
2308
+ { name: "viewMode", icon: Je, title: "View mode", action: "toggle-view-menu", hasDropdown: !0 }
2309
+ ]).forEach((r) => {
2310
+ if (r.separator) {
2311
+ const o = document.createElement("div");
2312
+ o.className = "marzipan-toolbar-separator", o.setAttribute("role", "separator"), this.container.appendChild(o);
2313
+ } else if (r.action && r.icon) {
2314
+ const o = this.createButton(r);
2315
+ r.name && (this.buttons[r.name] = o), this.container.appendChild(o);
2316
+ }
2317
+ });
2318
+ const t = this.editor.element.querySelector(".marzipan-container"), n = this.editor.element.querySelector(".marzipan-wrapper");
2319
+ return t instanceof HTMLElement && n instanceof HTMLElement && t.insertBefore(this.container, n), this.container;
2320
+ }
2321
+ createButton(e) {
2322
+ const t = document.createElement("button");
2323
+ return t.className = "marzipan-toolbar-button", t.type = "button", t.title = e.title ?? "", t.setAttribute("aria-label", e.title ?? ""), e.action && (t.dataset.action = e.action), t.innerHTML = e.icon ?? "", e.hasDropdown && (t.classList.add("has-dropdown"), e.name === "viewMode" && (this.viewModeButton = t)), t.addEventListener("click", (n) => {
2324
+ n.preventDefault(), e.action && this.handleAction(e.action, t);
2325
+ }), t;
2326
+ }
2327
+ handleAction(e, t) {
2328
+ const n = this.editor.textarea;
2329
+ if (n) {
2330
+ if (e === "toggle-view-menu") {
2331
+ t && this.toggleViewDropdown(t);
2332
+ return;
2333
+ }
2334
+ switch (n.focus(), e) {
2335
+ case "toggleBold":
2336
+ this.actions.toggleBold(n);
2337
+ break;
2338
+ case "toggleItalic":
2339
+ this.actions.toggleItalic(n);
2340
+ break;
2341
+ case "insertH1":
2342
+ this.actions.toggleH1(n);
2343
+ break;
2344
+ case "insertH2":
2345
+ this.actions.toggleH2(n);
2346
+ break;
2347
+ case "insertH3":
2348
+ this.actions.toggleH3(n);
2349
+ break;
2350
+ case "insertLink":
2351
+ this.actions.insertLink(n);
2352
+ break;
2353
+ case "toggleCode":
2354
+ this.actions.toggleCode(n);
2355
+ break;
2356
+ case "toggleBulletList":
2357
+ this.actions.toggleBulletList(n);
2358
+ break;
2359
+ case "toggleNumberedList":
2360
+ this.actions.toggleNumberedList(n);
2361
+ break;
2362
+ case "toggleQuote":
2363
+ this.actions.toggleQuote(n);
2364
+ break;
2365
+ case "toggleTaskList":
2366
+ this.actions.toggleTaskList(n);
2367
+ break;
2368
+ case "toggle-plain":
2369
+ this.togglePlainMode();
2370
+ break;
2371
+ default:
2372
+ console.warn(`[Marzipan] Unknown toolbar action: ${e}`);
2373
+ break;
2374
+ }
2375
+ e !== "toggle-view-menu" && n.dispatchEvent(new Event("input", { bubbles: !0 }));
2376
+ }
2377
+ }
2378
+ togglePlainMode() {
2379
+ const e = this.editor.container.classList.contains("plain-mode");
2380
+ this.editor.showPlainTextarea(!e);
2381
+ }
2382
+ updateButtonStates() {
2383
+ const e = this.editor.textarea;
2384
+ if (!e) return;
2385
+ const t = this.actions.getActiveFormats(e);
2386
+ Object.entries(this.buttons).forEach(([n, r]) => {
2387
+ let o = !1;
2388
+ switch (n) {
2389
+ case "bold":
2390
+ o = t.includes("bold");
2391
+ break;
2392
+ case "italic":
2393
+ o = t.includes("italic");
2394
+ break;
2395
+ case "code":
2396
+ o = !1;
2397
+ break;
2398
+ case "bulletList":
2399
+ o = t.includes("bullet-list");
2400
+ break;
2401
+ case "orderedList":
2402
+ o = t.includes("numbered-list");
2403
+ break;
2404
+ case "quote":
2405
+ o = t.includes("quote");
2406
+ break;
2407
+ case "taskList":
2408
+ o = t.includes("task-list");
2409
+ break;
2410
+ case "h1":
2411
+ o = t.includes("header");
2412
+ break;
2413
+ case "h2":
2414
+ o = t.includes("header-2");
2415
+ break;
2416
+ case "h3":
2417
+ o = t.includes("header-3");
2418
+ break;
2419
+ case "togglePlain":
2420
+ o = !this.editor.container.classList.contains("plain-mode");
2421
+ break;
2422
+ }
2423
+ r.classList.toggle("active", o), r.setAttribute("aria-pressed", String(o));
2424
+ });
2425
+ }
2426
+ toggleViewDropdown(e) {
2427
+ const t = document.querySelector(".marzipan-dropdown-menu");
2428
+ if (t instanceof HTMLElement) {
2429
+ t.remove(), e.classList.remove("dropdown-active"), document.removeEventListener("click", this.handleDocumentClick);
2430
+ return;
2431
+ }
2432
+ const n = this.createViewDropdown(), r = e.getBoundingClientRect();
2433
+ n.style.top = `${r.bottom + 4}px`, n.style.left = `${r.left}px`, document.body.appendChild(n), e.classList.add("dropdown-active"), this.handleDocumentClick = (o) => {
2434
+ !e.contains(o.target) && !n.contains(o.target) && (n.remove(), e.classList.remove("dropdown-active"), document.removeEventListener("click", this.handleDocumentClick));
2435
+ }, setTimeout(() => {
2436
+ document.addEventListener("click", this.handleDocumentClick);
2437
+ }, 0);
2438
+ }
2439
+ createViewDropdown() {
2440
+ const e = document.createElement("div");
2441
+ e.className = "marzipan-dropdown-menu";
2442
+ const t = this.editor.container.classList.contains("plain-mode"), r = this.editor.container.classList.contains("preview-mode") ? "preview" : t ? "plain" : "normal";
2443
+ return [
2444
+ { id: "normal", label: "Normal Edit", icon: "✓" },
2445
+ { id: "plain", label: "Plain Textarea", icon: "✓" },
2446
+ { id: "preview", label: "Preview Mode", icon: "✓" }
2447
+ ].forEach((a) => {
2448
+ const s = document.createElement("button");
2449
+ s.className = "marzipan-dropdown-item", s.type = "button";
2450
+ const c = document.createElement("span");
2451
+ c.className = "marzipan-dropdown-check", c.textContent = r === a.id ? a.icon : "";
2452
+ const p = document.createElement("span");
2453
+ p.textContent = a.label, s.appendChild(c), s.appendChild(p), r === a.id && s.classList.add("active"), s.addEventListener("click", (d) => {
2454
+ d.stopPropagation(), this.setViewMode(a.id), e.remove(), this.viewModeButton?.classList.remove("dropdown-active"), this.handleDocumentClick && document.removeEventListener("click", this.handleDocumentClick);
2455
+ }), e.appendChild(s);
2456
+ }), e;
2457
+ }
2458
+ setViewMode(e) {
2459
+ switch (this.editor.container.classList.remove("plain-mode", "preview-mode"), e) {
2460
+ case "plain":
2461
+ this.editor.showPlainTextarea(!0);
2462
+ break;
2463
+ case "preview":
2464
+ this.editor.showPreviewMode?.(!0);
2465
+ break;
2466
+ case "normal":
2467
+ default:
2468
+ this.editor.showPlainTextarea(!1), typeof this.editor.showPreviewMode == "function" && this.editor.showPreviewMode(!1);
2469
+ break;
2470
+ }
2471
+ }
2472
+ destroy() {
2473
+ this.container && (this.handleDocumentClick && document.removeEventListener("click", this.handleDocumentClick), this.container.remove(), this.container = null, this.buttons = {}, this.viewModeButton = void 0, this.handleDocumentClick = void 0);
2474
+ }
2475
+ }
2476
+ let le = !1;
2477
+ function Ge() {
2478
+ if (le || typeof document > "u") return;
2479
+ const i = document.createElement("style");
2480
+ i.className = "marzipan-link-tooltip-styles", i.textContent = `
2481
+ @supports (position-anchor: --x) and (position-area: center) {
2482
+ .marzipan-link-tooltip {
2483
+ position: absolute;
2484
+ position-anchor: var(--target-anchor, --link-0);
2485
+ position-area: block-end center;
2486
+ margin-top: 8px !important;
2487
+ background: #333 !important;
2488
+ color: white !important;
2489
+ padding: 6px 10px !important;
2490
+ border-radius: 16px !important;
2491
+ font-size: 12px !important;
2492
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
2493
+ display: none !important;
2494
+ z-index: 10000 !important;
2495
+ cursor: pointer !important;
2496
+ box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
2497
+ max-width: 300px !important;
2498
+ white-space: nowrap !important;
2499
+ overflow: hidden !important;
2500
+ text-overflow: ellipsis !important;
2501
+ position-try: most-width block-end inline-end, flip-inline, block-start center;
2502
+ position-visibility: anchors-visible;
2503
+ }
2504
+
2505
+ .marzipan-link-tooltip.visible {
2506
+ display: flex !important;
2507
+ }
2508
+ }
2509
+ `, document.head.appendChild(i), le = !0;
2510
+ }
2511
+ class Xe {
2512
+ constructor(e) {
2513
+ this.editor = e, this.tooltip = null, this.currentLink = null, this.hideTimeout = null, this.supportsAnchor = !1, this._selectionHandler = null, this._keyupHandler = null, this._inputHandler = null, this._scrollHandler = null, this._tooltipEnterHandler = null, this._tooltipLeaveHandler = null, this.init();
2514
+ }
2515
+ init() {
2516
+ typeof CSS > "u" || typeof CSS.supports != "function" || !(CSS.supports("position-anchor: --x") && CSS.supports("position-area: center")) || (Ge(), this.supportsAnchor = !0, this.createTooltip(), this.bindListeners());
2517
+ }
2518
+ bindListeners() {
2519
+ !this.supportsAnchor || typeof document > "u" || !this.tooltip || (this._selectionHandler = () => this.handleSelectionChange(), document.addEventListener("selectionchange", this._selectionHandler), this._keyupHandler = (e) => {
2520
+ (e.key.includes("Arrow") || e.key === "Home" || e.key === "End") && this.checkCursorPosition();
2521
+ }, this.editor.textarea.addEventListener("keyup", this._keyupHandler), this._inputHandler = () => this.hide(), this.editor.textarea.addEventListener("input", this._inputHandler), this._scrollHandler = () => this.hide(), this.editor.textarea.addEventListener("scroll", this._scrollHandler), this._tooltipEnterHandler = () => this.cancelHide(), this._tooltipLeaveHandler = () => this.scheduleHide(), this.tooltip.addEventListener("mouseenter", this._tooltipEnterHandler), this.tooltip.addEventListener("mouseleave", this._tooltipLeaveHandler));
2522
+ }
2523
+ createTooltip() {
2524
+ typeof document > "u" || (this.tooltip = document.createElement("div"), this.tooltip.className = "marzipan-link-tooltip", this.tooltip.innerHTML = `
2525
+ <span style="display: flex; align-items: center; gap: 6px;">
2526
+ <svg width="12" height="12" viewBox="0 0 20 20" fill="currentColor" style="flex-shrink: 0;">
2527
+ <path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z"></path>
2528
+ <path d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z"></path>
2529
+ </svg>
2530
+ <span class="marzipan-link-tooltip-url"></span>
2531
+ </span>
2532
+ `, this.tooltip.addEventListener("click", (e) => {
2533
+ e.preventDefault(), e.stopPropagation(), this.currentLink && (window.open(this.currentLink.url, "_blank"), this.hide());
2534
+ }), this.editor.container.appendChild(this.tooltip));
2535
+ }
2536
+ handleSelectionChange() {
2537
+ if (!(typeof document > "u")) {
2538
+ if (document.activeElement !== this.editor.textarea) {
2539
+ this.scheduleHide();
2540
+ return;
2541
+ }
2542
+ this.checkCursorPosition();
2543
+ }
2544
+ }
2545
+ checkCursorPosition() {
2546
+ if (!this.tooltip) return;
2547
+ const e = this.editor.textarea.selectionStart, t = this.editor.textarea.value, n = this.findLinkAtPosition(t, e);
2548
+ n ? (!this.currentLink || this.currentLink.url !== n.url || this.currentLink.index !== n.index) && this.show(n) : this.scheduleHide();
2549
+ }
2550
+ findLinkAtPosition(e, t) {
2551
+ const n = /\[([^\]]+)\]\(([^)]+)\)/g;
2552
+ let r, o = 0;
2553
+ for (; (r = n.exec(e)) !== null; ) {
2554
+ const a = r.index, s = r.index + r[0].length;
2555
+ if (t >= a && t <= s)
2556
+ return {
2557
+ text: r[1],
2558
+ url: r[2],
2559
+ index: o,
2560
+ start: a,
2561
+ end: s
2562
+ };
2563
+ o++;
2564
+ }
2565
+ return null;
2566
+ }
2567
+ show(e) {
2568
+ if (!this.tooltip) return;
2569
+ this.currentLink = e, this.cancelHide();
2570
+ const t = this.tooltip.querySelector(".marzipan-link-tooltip-url");
2571
+ t && (t.textContent = e.url), this.tooltip.style.setProperty("--target-anchor", `--link-${e.index}`), this.tooltip.classList.add("visible");
2572
+ }
2573
+ hide() {
2574
+ this.tooltip && (this.tooltip.classList.remove("visible"), this.currentLink = null);
2575
+ }
2576
+ scheduleHide() {
2577
+ this.cancelHide(), this.hideTimeout = setTimeout(() => this.hide(), 300);
2578
+ }
2579
+ cancelHide() {
2580
+ this.hideTimeout && (clearTimeout(this.hideTimeout), this.hideTimeout = null);
2581
+ }
2582
+ destroy() {
2583
+ this.cancelHide(), this._selectionHandler && typeof document < "u" && (document.removeEventListener("selectionchange", this._selectionHandler), this._selectionHandler = null), this._keyupHandler && (this.editor.textarea.removeEventListener("keyup", this._keyupHandler), this._keyupHandler = null), this._inputHandler && (this.editor.textarea.removeEventListener("input", this._inputHandler), this._inputHandler = null), this._scrollHandler && (this.editor.textarea.removeEventListener("scroll", this._scrollHandler), this._scrollHandler = null), this._tooltipEnterHandler && (this.tooltip?.removeEventListener("mouseenter", this._tooltipEnterHandler), this._tooltipEnterHandler = null), this._tooltipLeaveHandler && (this.tooltip?.removeEventListener("mouseleave", this._tooltipLeaveHandler), this._tooltipLeaveHandler = null), this.tooltip && this.tooltip.parentNode && this.tooltip.parentNode.removeChild(this.tooltip), this.tooltip = null, this.currentLink = null;
2584
+ }
2585
+ }
2586
+ /**
2587
+ * Marzipan - A lightweight markdown editor and viewer
2588
+ * @version 1.0.0
2589
+ * @license Apache-2.0
2590
+ */
2591
+ const w = class w {
2592
+ /**
2593
+ * Constructor - Always returns an array of instances
2594
+ * @param {string|Element|NodeList|Array} target - Target element(s)
2595
+ * @param {Object} options - Configuration options
2596
+ * @returns {Array} Array of Marzipan instances
2597
+ */
2598
+ constructor(e, t = {}) {
2599
+ let n;
2600
+ if (typeof e == "string") {
2601
+ if (n = document.querySelectorAll(e), n.length === 0)
2602
+ throw new Error(`No elements found for selector: ${e}`);
2603
+ n = Array.from(n);
2604
+ } else if (e instanceof Element)
2605
+ n = [e];
2606
+ else if (e instanceof NodeList)
2607
+ n = Array.from(e);
2608
+ else if (Array.isArray(e))
2609
+ n = e;
2610
+ else
2611
+ throw new Error("Invalid target: must be selector string, Element, NodeList, or Array");
2612
+ return n.map((o) => {
2613
+ if (o.MarzipanInstance)
2614
+ return o.MarzipanInstance.reinit(t), o.MarzipanInstance;
2615
+ const a = Object.create(w.prototype);
2616
+ return a._init(o, t), o.MarzipanInstance = a, w.instances.set(o, a), a;
2617
+ });
2618
+ }
2619
+ /**
2620
+ * Internal initialization
2621
+ * @private
2622
+ */
2623
+ _init(e, t = {}) {
2624
+ this.element = e, this.instanceTheme = t.theme || null, this.options = this._mergeOptions(t), this.instanceId = ++w.instanceCount, this.initialized = !1, this._autoResizeInputHandler = null, this._autoResizeResizeHandler = null, this._minAutoHeight = null, this._maxAutoHeight = null, w.injectStyles(), w.initGlobalListeners();
2625
+ const n = e.querySelector(".marzipan-container"), r = e.querySelector(".marzipan-wrapper");
2626
+ if (n || r ? this._recoverFromDOM(n, r) : this._buildFromScratch(), this.shortcuts = new xe(this), this.linkTooltip = new Xe(this), this.options.toolbar) {
2627
+ const a = typeof this.options.toolbar == "object" ? this.options.toolbar.buttons : null;
2628
+ this.toolbar = new Qe(this, a), this.toolbar.create(), this.textarea.addEventListener("selectionchange", () => {
2629
+ this.toolbar?.updateButtonStates?.();
2630
+ }), this.textarea.addEventListener("input", () => {
2631
+ this.toolbar?.updateButtonStates?.();
2632
+ });
2633
+ }
2634
+ this._applyPlugins() && this.updatePreview(), this.initialized = !0, this.options.onChange && this.options.onChange(this.getValue(), this);
2635
+ }
2636
+ /**
2637
+ * Merge user options with defaults
2638
+ * @private
2639
+ */
2640
+ _mergeOptions(e) {
2641
+ const t = {
2642
+ // Typography
2643
+ fontSize: "14px",
2644
+ lineHeight: 1.6,
2645
+ /* System-first, guaranteed monospaced; avoids Android 'ui-monospace' pitfalls */
2646
+ fontFamily: '"SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace',
2647
+ padding: "16px",
2648
+ // Mobile styles
2649
+ mobile: {
2650
+ fontSize: "16px",
2651
+ // Prevent zoom on iOS
2652
+ padding: "12px",
2653
+ lineHeight: 1.5
2654
+ },
2655
+ // Native textarea properties
2656
+ textareaProps: {},
2657
+ // Behavior
2658
+ autofocus: !1,
2659
+ autoResize: !1,
2660
+ // Auto-expand height with content
2661
+ minHeight: "100px",
2662
+ // Minimum height for autoResize mode
2663
+ maxHeight: null,
2664
+ // Maximum height for autoResize mode (null = unlimited)
2665
+ placeholder: "Start typing...",
2666
+ value: "",
2667
+ // Callbacks
2668
+ onChange: null,
2669
+ onKeydown: null,
2670
+ // Features
2671
+ showActiveLineRaw: !1,
2672
+ showStats: !1,
2673
+ toolbar: !1,
2674
+ statsFormatter: null,
2675
+ smartLists: !0
2676
+ // Enable smart list continuation
2677
+ }, { theme: n, colors: r, hooks: o, plugins: a, ...s } = e;
2678
+ return {
2679
+ ...t,
2680
+ ...s,
2681
+ hooks: o ? { ...o } : void 0,
2682
+ plugins: Array.isArray(a) ? [...a] : void 0
2683
+ };
2684
+ }
2685
+ /**
2686
+ * Apply plugins attached to this editor instance
2687
+ * @private
2688
+ */
2689
+ _applyPlugins() {
2690
+ if (!Array.isArray(this.options?.plugins) || !this.options.plugins.length)
2691
+ return !1;
2692
+ this._appliedPlugins || (this._appliedPlugins = /* @__PURE__ */ new Set());
2693
+ let e = !1;
2694
+ for (const t of this.options.plugins)
2695
+ if (typeof t == "function" && !this._appliedPlugins.has(t)) {
2696
+ this._appliedPlugins.add(t);
2697
+ try {
2698
+ t(this);
2699
+ } catch (n) {
2700
+ console.error("[Marzipan] Plugin error:", n);
2701
+ }
2702
+ e = !0;
2703
+ }
2704
+ return e;
2705
+ }
2706
+ /**
2707
+ * Recover from existing DOM structure
2708
+ * @private
2709
+ */
2710
+ _recoverFromDOM(e, t) {
2711
+ if (e && e.classList.contains("marzipan-container"))
2712
+ this.container = e, this.wrapper = e.querySelector(".marzipan-wrapper");
2713
+ else if (t) {
2714
+ this.wrapper = t, this.container = document.createElement("div"), this.container.className = "marzipan-container";
2715
+ const n = this.instanceTheme || w.currentTheme || M, r = typeof n == "string" ? n : n.name;
2716
+ if (r && this.container.setAttribute("data-theme", r), this.instanceTheme) {
2717
+ const o = typeof this.instanceTheme == "string" ? _(this.instanceTheme) : this.instanceTheme;
2718
+ if (o && o.colors) {
2719
+ const a = F(o.colors);
2720
+ this.container.style.cssText += a;
2721
+ }
2722
+ }
2723
+ t.parentNode.insertBefore(this.container, t), this.container.appendChild(t);
2724
+ }
2725
+ if (this.container && this.container.setAttribute("data-marzipan-instance", String(this.instanceId)), !this.wrapper) {
2726
+ e && e.remove(), t && t.remove(), this._buildFromScratch();
2727
+ return;
2728
+ }
2729
+ if (this.textarea = this.wrapper.querySelector(".marzipan-input"), this.preview = this.wrapper.querySelector(".marzipan-preview"), !this.textarea || !this.preview) {
2730
+ this.container.remove(), this._buildFromScratch();
2731
+ return;
2732
+ }
2733
+ this.wrapper._instance = this, this.options.fontSize && this.wrapper.style.setProperty("--instance-font-size", this.options.fontSize), this.options.lineHeight && this.wrapper.style.setProperty("--instance-line-height", String(this.options.lineHeight)), this.options.padding && this.wrapper.style.setProperty("--instance-padding", this.options.padding), this._configureTextarea(), this._applyOptions();
2734
+ }
2735
+ /**
2736
+ * Build editor from scratch
2737
+ * @private
2738
+ */
2739
+ _buildFromScratch() {
2740
+ const e = this._extractContent();
2741
+ this.element.innerHTML = "", this._createDOM(), (e || this.options.value) && this.setValue(e || this.options.value), this._applyOptions();
2742
+ }
2743
+ /**
2744
+ * Extract content from element
2745
+ * @private
2746
+ */
2747
+ _extractContent() {
2748
+ const e = this.element.querySelector(".marzipan-input");
2749
+ return e ? e.value : this.element.textContent || "";
2750
+ }
2751
+ /**
2752
+ * Create DOM structure
2753
+ * @private
2754
+ */
2755
+ _createDOM() {
2756
+ this.container = document.createElement("div"), this.container.className = "marzipan-container", this.container.setAttribute("data-marzipan-instance", String(this.instanceId));
2757
+ const e = this.instanceTheme || w.currentTheme || M, t = typeof e == "string" ? e : e.name;
2758
+ if (t && this.container.setAttribute("data-theme", t), this.instanceTheme) {
2759
+ const n = typeof this.instanceTheme == "string" ? _(this.instanceTheme) : this.instanceTheme;
2760
+ if (n && n.colors) {
2761
+ const r = F(n.colors);
2762
+ this.container.style.cssText += r;
2763
+ }
2764
+ }
2765
+ this.wrapper = document.createElement("div"), this.wrapper.className = "marzipan-wrapper", this.options.fontSize && this.wrapper.style.setProperty("--instance-font-size", this.options.fontSize), this.options.lineHeight && this.wrapper.style.setProperty("--instance-line-height", String(this.options.lineHeight)), this.options.padding && this.wrapper.style.setProperty("--instance-padding", this.options.padding), this.wrapper._instance = this, this.textarea = document.createElement("textarea"), this.textarea.className = "marzipan-input", this.textarea.placeholder = this.options.placeholder, this._configureTextarea(), this.options.textareaProps && Object.entries(this.options.textareaProps).forEach(([n, r]) => {
2766
+ n === "className" || n === "class" ? this.textarea.className += " " + r : n === "style" && typeof r == "object" ? Object.assign(this.textarea.style, r) : this.textarea.setAttribute(n, r);
2767
+ }), this.preview = document.createElement("div"), this.preview.className = "marzipan-preview", this.preview.setAttribute("aria-hidden", "true"), this.wrapper.appendChild(this.textarea), this.wrapper.appendChild(this.preview), this.container.appendChild(this.wrapper), this.options.showStats && (this.statsBar = document.createElement("div"), this.statsBar.className = "marzipan-stats", this.container.appendChild(this.statsBar), this._updateStats()), this.element.appendChild(this.container), this.options.autoResize ? this._setupAutoResize() : this.container.classList.remove("marzipan-auto-resize");
2768
+ }
2769
+ /**
2770
+ * Configure textarea attributes
2771
+ * @private
2772
+ */
2773
+ _configureTextarea() {
2774
+ this.textarea.setAttribute("autocomplete", "off"), this.textarea.setAttribute("autocorrect", "off"), this.textarea.setAttribute("autocapitalize", "off"), this.textarea.setAttribute("spellcheck", "false"), this.textarea.setAttribute("data-gramm", "false"), this.textarea.setAttribute("data-gramm_editor", "false"), this.textarea.setAttribute("data-enable-grammarly", "false");
2775
+ }
2776
+ /**
2777
+ * Apply options to the editor
2778
+ * @private
2779
+ */
2780
+ _applyOptions() {
2781
+ this.options.autofocus && this.textarea.focus(), this.options.autoResize ? this._setupAutoResize() : this._teardownAutoResize(), this.updatePreview();
2782
+ }
2783
+ /**
2784
+ * Update preview with parsed markdown
2785
+ */
2786
+ updatePreview() {
2787
+ const e = this.textarea.value, t = this.textarea.selectionStart, n = this._getCurrentLine(e, t), r = T.parse(e, n, this.options.showActiveLineRaw);
2788
+ if (this.preview.innerHTML = r || '<span style="color: #808080;">Start typing...</span>', this.options?.hooks?.afterPreviewRender)
2789
+ try {
2790
+ this.options.hooks.afterPreviewRender(this.preview, this);
2791
+ } catch (o) {
2792
+ console.error("[Marzipan] afterPreviewRender hook error:", o);
2793
+ }
2794
+ this._applyCodeBlockBackgrounds(), this.options.showStats && this.statsBar && this._updateStats(), this.options.onChange && this.initialized && this.options.onChange(e, this);
2795
+ }
2796
+ /**
2797
+ * Apply background styling to code blocks
2798
+ * @private
2799
+ */
2800
+ _applyCodeBlockBackgrounds() {
2801
+ const e = this.preview.querySelectorAll(".code-fence");
2802
+ for (let t = 0; t < e.length - 1; t += 2) {
2803
+ const n = e[t], r = e[t + 1], o = n.parentElement, a = r.parentElement;
2804
+ !o || !a || (n.style.display = "block", r.style.display = "block", o.classList.add("code-block-line"), a.classList.add("code-block-line"));
2805
+ }
2806
+ }
2807
+ /**
2808
+ * Get current line number from cursor position
2809
+ * @private
2810
+ */
2811
+ _getCurrentLine(e, t) {
2812
+ return e.substring(0, t).split(`
2813
+ `).length - 1;
2814
+ }
2815
+ /**
2816
+ * Handle input events
2817
+ * @private
2818
+ */
2819
+ handleInput(e) {
2820
+ this.updatePreview();
2821
+ }
2822
+ /**
2823
+ * Handle keydown events
2824
+ * @private
2825
+ */
2826
+ handleKeydown(e) {
2827
+ if (e.key === "Tab") {
2828
+ e.preventDefault();
2829
+ const n = this.textarea.selectionStart, r = this.textarea.selectionEnd, o = this.textarea.value;
2830
+ if (n !== r && e.shiftKey) {
2831
+ const a = o.substring(0, n), s = o.substring(n, r), c = o.substring(r), d = s.split(`
2832
+ `).map((l) => l.replace(/^ /, "")).join(`
2833
+ `);
2834
+ document.execCommand ? (this.textarea.setSelectionRange(n, r), document.execCommand("insertText", !1, d)) : (this.textarea.value = a + d + c, this.textarea.selectionStart = n, this.textarea.selectionEnd = n + d.length);
2835
+ } else if (n !== r) {
2836
+ const a = o.substring(0, n), s = o.substring(n, r), c = o.substring(r), d = s.split(`
2837
+ `).map((l) => " " + l).join(`
2838
+ `);
2839
+ document.execCommand ? (this.textarea.setSelectionRange(n, r), document.execCommand("insertText", !1, d)) : (this.textarea.value = a + d + c, this.textarea.selectionStart = n, this.textarea.selectionEnd = n + d.length);
2840
+ } else
2841
+ document.execCommand ? document.execCommand("insertText", !1, " ") : (this.textarea.value = o.substring(0, n) + " " + o.substring(r), this.textarea.selectionStart = this.textarea.selectionEnd = n + 2);
2842
+ this.textarea.dispatchEvent(new Event("input", { bubbles: !0 }));
2843
+ return;
2844
+ }
2845
+ if (e.key === "Enter" && !e.shiftKey && !e.metaKey && !e.ctrlKey && this.options.smartLists && this.handleSmartListContinuation()) {
2846
+ e.preventDefault();
2847
+ return;
2848
+ }
2849
+ !this.shortcuts.handleKeydown(e) && this.options.onKeydown && this.options.onKeydown(e, this);
2850
+ }
2851
+ /**
2852
+ * Handle smart list continuation
2853
+ * @returns {boolean} Whether the event was handled
2854
+ */
2855
+ handleSmartListContinuation() {
2856
+ const e = this.textarea, t = e.selectionStart, n = T.getListContext(e.value, t);
2857
+ return !n || !n.inList ? !1 : n.content.trim() === "" && t >= n.markerEndPos ? (this.deleteListMarker(n), !0) : (t > n.markerEndPos && t < n.lineEnd ? this.splitListItem(n, t) : this.insertNewListItem(n), n.listType === "numbered" && this.scheduleNumberedListUpdate(), !0);
2858
+ }
2859
+ /**
2860
+ * Delete list marker and exit list
2861
+ * @private
2862
+ */
2863
+ deleteListMarker(e) {
2864
+ this.textarea.setSelectionRange(e.lineStart, e.markerEndPos), document.execCommand("delete"), this.textarea.dispatchEvent(new Event("input", { bubbles: !0 }));
2865
+ }
2866
+ /**
2867
+ * Insert new list item
2868
+ * @private
2869
+ */
2870
+ insertNewListItem(e) {
2871
+ const t = T.createNewListItem(e);
2872
+ document.execCommand("insertText", !1, `
2873
+ ` + t), this.textarea.dispatchEvent(new Event("input", { bubbles: !0 }));
2874
+ }
2875
+ /**
2876
+ * Split list item at cursor position
2877
+ * @private
2878
+ */
2879
+ splitListItem(e, t) {
2880
+ const n = e.content.substring(t - e.markerEndPos);
2881
+ this.textarea.setSelectionRange(t, e.lineEnd), document.execCommand("delete");
2882
+ const r = T.createNewListItem(e);
2883
+ document.execCommand("insertText", !1, `
2884
+ ` + r + n);
2885
+ const o = this.textarea.selectionStart - n.length;
2886
+ this.textarea.setSelectionRange(o, o), this.textarea.dispatchEvent(new Event("input", { bubbles: !0 }));
2887
+ }
2888
+ /**
2889
+ * Schedule numbered list renumbering
2890
+ * @private
2891
+ */
2892
+ scheduleNumberedListUpdate() {
2893
+ this.numberUpdateTimeout && clearTimeout(this.numberUpdateTimeout), this.numberUpdateTimeout = setTimeout(() => {
2894
+ this.updateNumberedLists();
2895
+ }, 10);
2896
+ }
2897
+ /**
2898
+ * Update/renumber all numbered lists
2899
+ * @private
2900
+ */
2901
+ updateNumberedLists() {
2902
+ const e = this.textarea.value, t = this.textarea.selectionStart, n = T.renumberLists(e);
2903
+ if (n !== e) {
2904
+ let r = 0;
2905
+ const o = e.split(`
2906
+ `), a = n.split(`
2907
+ `);
2908
+ let s = 0;
2909
+ for (let p = 0; p < o.length && s < t; p++) {
2910
+ if (o[p] !== a[p]) {
2911
+ const d = a[p].length - o[p].length;
2912
+ s + o[p].length < t && (r += d);
2913
+ }
2914
+ s += o[p].length + 1;
2915
+ }
2916
+ this.textarea.value = n;
2917
+ const c = t + r;
2918
+ this.textarea.setSelectionRange(c, c), this.textarea.dispatchEvent(new Event("input", { bubbles: !0 }));
2919
+ }
2920
+ }
2921
+ /**
2922
+ * Handle scroll events
2923
+ * @private
2924
+ */
2925
+ handleScroll(e) {
2926
+ this.preview.scrollTop = this.textarea.scrollTop, this.preview.scrollLeft = this.textarea.scrollLeft;
2927
+ }
2928
+ /**
2929
+ * Get editor content
2930
+ * @returns {string} Current markdown content
2931
+ */
2932
+ getValue() {
2933
+ return this.textarea.value;
2934
+ }
2935
+ /**
2936
+ * Set editor content
2937
+ * @param {string} value - Markdown content to set
2938
+ */
2939
+ setValue(e) {
2940
+ this.textarea.value = e, this.updatePreview(), this.options.autoResize && this._updateAutoHeight();
2941
+ }
2942
+ /**
2943
+ * Get the rendered HTML of the current content
2944
+ * @param {Object} options - Rendering options
2945
+ * @param {boolean} options.cleanHTML - If true, removes syntax markers and Marzipan-specific classes
2946
+ * @returns {string} Rendered HTML
2947
+ */
2948
+ getRenderedHTML(e = {}) {
2949
+ const t = this.getValue();
2950
+ let n = T.parse(t);
2951
+ return e.cleanHTML && (n = n.replace(/<span class="syntax-marker[^"]*">.*?<\/span>/g, ""), n = n.replace(/\sclass="(bullet-list|ordered-list|code-fence|hr-marker|blockquote|url-part)"/g, ""), n = n.replace(/\sclass=""/g, "")), n;
2952
+ }
2953
+ /**
2954
+ * Get the current preview element's HTML
2955
+ * This includes all syntax markers and Marzipan styling
2956
+ * @returns {string} Current preview HTML (as displayed)
2957
+ */
2958
+ getPreviewHTML() {
2959
+ return this.preview.innerHTML;
2960
+ }
2961
+ /**
2962
+ * Get clean HTML without any Marzipan-specific markup
2963
+ * Useful for exporting to other formats or storage
2964
+ * @returns {string} Clean HTML suitable for export
2965
+ */
2966
+ getCleanHTML() {
2967
+ return this.getRenderedHTML({ cleanHTML: !0 });
2968
+ }
2969
+ /**
2970
+ * Focus the editor
2971
+ */
2972
+ focus() {
2973
+ this.textarea.focus();
2974
+ }
2975
+ /**
2976
+ * Blur the editor
2977
+ */
2978
+ blur() {
2979
+ this.textarea.blur();
2980
+ }
2981
+ /**
2982
+ * Check if editor is initialized
2983
+ * @returns {boolean}
2984
+ */
2985
+ isInitialized() {
2986
+ return this.initialized;
2987
+ }
2988
+ /**
2989
+ * Re-initialize with new options
2990
+ * @param {Object} options - New options to apply
2991
+ */
2992
+ reinit(e = {}) {
2993
+ this.options = this._mergeOptions({ ...this.options, ...e }), this._applyOptions(), this._applyPlugins(), this.updatePreview();
2994
+ }
2995
+ /**
2996
+ * Update stats bar
2997
+ * @private
2998
+ */
2999
+ _updateStats() {
3000
+ if (!this.statsBar) return;
3001
+ const e = this.textarea.value, t = e.split(`
3002
+ `), n = e.length, r = e.split(/\s+/).filter((d) => d.length > 0).length, o = this.textarea.selectionStart, s = e.substring(0, o).split(`
3003
+ `), c = s.length, p = s[s.length - 1].length + 1;
3004
+ this.options.statsFormatter ? this.statsBar.innerHTML = this.options.statsFormatter({
3005
+ chars: n,
3006
+ words: r,
3007
+ lines: t.length,
3008
+ line: c,
3009
+ column: p
3010
+ }) : this.statsBar.innerHTML = `
3011
+ <div class="marzipan-stat">
3012
+ <span class="live-dot"></span>
3013
+ <span>${n} chars, ${r} words, ${t.length} lines</span>
3014
+ </div>
3015
+ <div class="marzipan-stat">Line ${c}, Col ${p}</div>
3016
+ `;
3017
+ }
3018
+ /**
3019
+ * Setup auto-resize functionality
3020
+ * @private
3021
+ */
3022
+ _setupAutoResize() {
3023
+ !this.container || !this.textarea || !this.preview || !this.wrapper || (this._teardownAutoResize(), this.container.classList.add("marzipan-auto-resize"), this.previousHeight = null, this._refreshAutoResizeConstraints(), this._autoResizeInputHandler = () => this._updateAutoHeight(), this.textarea.addEventListener("input", this._autoResizeInputHandler), typeof window < "u" ? (this._autoResizeResizeHandler = () => this._updateAutoHeight(), window.addEventListener("resize", this._autoResizeResizeHandler)) : this._autoResizeResizeHandler = null, this._updateAutoHeight());
3024
+ }
3025
+ _teardownAutoResize() {
3026
+ this.container && this.container.classList.remove("marzipan-auto-resize"), this._autoResizeInputHandler && this.textarea && this.textarea.removeEventListener("input", this._autoResizeInputHandler), this._autoResizeInputHandler = null, this._autoResizeResizeHandler && typeof window < "u" && window.removeEventListener("resize", this._autoResizeResizeHandler), this._autoResizeResizeHandler = null, this.textarea && (this.textarea.style.removeProperty("height"), this.textarea.style.removeProperty("overflow-y")), this.preview && (this.preview.style.removeProperty("height"), this.preview.style.removeProperty("overflow-y")), this.wrapper && this.wrapper.style.removeProperty("height"), this.previousHeight = null, this._minAutoHeight = null, this._maxAutoHeight = null;
3027
+ }
3028
+ /**
3029
+ * Update height based on scrollHeight
3030
+ * @private
3031
+ */
3032
+ _updateAutoHeight() {
3033
+ if (!this.options.autoResize) return;
3034
+ const e = this.textarea, t = this.preview, n = this.wrapper, r = e.scrollTop;
3035
+ e.style.setProperty("height", "auto", "important");
3036
+ let o = e.scrollHeight, a = "hidden";
3037
+ const s = this._minAutoHeight;
3038
+ typeof s == "number" && s > 0 && (o = Math.max(o, s));
3039
+ const c = this._maxAutoHeight;
3040
+ typeof c == "number" && c > 0 && o > c && (o = c, a = "auto");
3041
+ const p = o + "px";
3042
+ e.style.setProperty("height", p, "important"), e.style.setProperty("overflow-y", a, "important"), t.style.setProperty("height", p, "important"), t.style.setProperty("overflow-y", a, "important"), n.style.setProperty("height", p, "important"), e.scrollTop = r, t.scrollTop = r, this.previousHeight !== o && (this.previousHeight = o);
3043
+ }
3044
+ _refreshAutoResizeConstraints() {
3045
+ this._minAutoHeight = this._resolveSizeToPixels(this.options.minHeight), this._maxAutoHeight = this._resolveSizeToPixels(this.options.maxHeight);
3046
+ }
3047
+ _resolveSizeToPixels(e) {
3048
+ if (e == null || e === "")
3049
+ return null;
3050
+ if (typeof e == "number")
3051
+ return e > 0 ? e : null;
3052
+ const t = String(e).trim();
3053
+ if (!t)
3054
+ return null;
3055
+ const n = Number(t);
3056
+ if (Number.isFinite(n) && n > 0)
3057
+ return n;
3058
+ if (typeof document > "u" || !document.body)
3059
+ return null;
3060
+ const r = document.createElement("div");
3061
+ r.style.position = "absolute", r.style.visibility = "hidden", r.style.height = t, r.style.pointerEvents = "none", document.body.appendChild(r);
3062
+ const o = r.getBoundingClientRect().height;
3063
+ return r.remove(), !Number.isFinite(o) || o <= 0 ? null : o;
3064
+ }
3065
+ /**
3066
+ * Show or hide stats bar
3067
+ * @param {boolean} show - Whether to show stats
3068
+ */
3069
+ showStats(e) {
3070
+ this.options.showStats = e, e && !this.statsBar ? (this.statsBar = document.createElement("div"), this.statsBar.className = "marzipan-stats", this.container.appendChild(this.statsBar), this._updateStats()) : !e && this.statsBar && (this.statsBar.remove(), this.statsBar = null);
3071
+ }
3072
+ /**
3073
+ * Show or hide the plain textarea (toggle overlay visibility)
3074
+ * @param {boolean} show - true to show plain textarea (hide overlay), false to show overlay
3075
+ * @returns {boolean} Current plain textarea state
3076
+ */
3077
+ showPlainTextarea(e) {
3078
+ if (e ? this.container.classList.add("plain-mode") : this.container.classList.remove("plain-mode"), this.toolbar) {
3079
+ const t = this.container.querySelector('[data-action="toggle-plain"]');
3080
+ t && (t.classList.toggle("active", !e), t.title = e ? "Show markdown preview" : "Show plain textarea");
3081
+ }
3082
+ return e;
3083
+ }
3084
+ /**
3085
+ * Show/hide preview mode
3086
+ * @param {boolean} show - Show preview mode if true, edit mode if false
3087
+ * @returns {boolean} Current preview mode state
3088
+ */
3089
+ showPreviewMode(e) {
3090
+ return e ? this.container.classList.add("preview-mode") : this.container.classList.remove("preview-mode"), e;
3091
+ }
3092
+ /**
3093
+ * Destroy the editor instance
3094
+ */
3095
+ destroy() {
3096
+ if (this.element.MarzipanInstance = null, w.instances.delete(this.element), this._teardownAutoResize(), this.linkTooltip && (this.linkTooltip.destroy(), this.linkTooltip = null), this.toolbar && (this.toolbar.destroy(), this.toolbar = null), this.shortcuts && this.shortcuts.destroy(), this.wrapper) {
3097
+ const e = this.getValue();
3098
+ this.wrapper.remove(), this.element.textContent = e;
3099
+ }
3100
+ this.container && this.container.removeAttribute("data-marzipan-instance"), this.initialized = !1;
3101
+ }
3102
+ // ===== Static Methods =====
3103
+ /**
3104
+ * Initialize multiple editors (static convenience method)
3105
+ * @param {string|Element|NodeList|Array} target - Target element(s)
3106
+ * @param {Object} options - Configuration options
3107
+ * @returns {Array} Array of Marzipan instances
3108
+ */
3109
+ static init(e, t = {}) {
3110
+ return new w(e, t);
3111
+ }
3112
+ /**
3113
+ * Get instance from element
3114
+ * @param {Element} element - DOM element
3115
+ * @returns {Marzipan|null} Marzipan instance or null
3116
+ */
3117
+ static getInstance(e) {
3118
+ return e.MarzipanInstance || w.instances.get(e) || null;
3119
+ }
3120
+ /**
3121
+ * Destroy all instances
3122
+ */
3123
+ static destroyAll() {
3124
+ document.querySelectorAll("[data-marzipan-instance]").forEach((t) => {
3125
+ const n = w.getInstance(t);
3126
+ n && n.destroy();
3127
+ });
3128
+ }
3129
+ /**
3130
+ * Inject styles into the document
3131
+ * @param {boolean} force - Force re-injection
3132
+ */
3133
+ static injectStyles(e = !1) {
3134
+ if (w.stylesInjected && !e) return;
3135
+ const t = document.querySelector("style.marzipan-styles");
3136
+ t && t.remove();
3137
+ const n = w.currentTheme || M, r = Re({ theme: n }), o = document.createElement("style");
3138
+ o.className = "marzipan-styles", o.textContent = r, document.head.appendChild(o), w.stylesInjected = !0;
3139
+ }
3140
+ /**
3141
+ * Set global theme for all Marzipan instances
3142
+ * @param {string|Object} theme - Theme name or custom theme object
3143
+ * @param {Object} customColors - Optional color overrides
3144
+ */
3145
+ static setTheme(e, t = null) {
3146
+ let n = typeof e == "string" ? _(e) : e;
3147
+ t && (n = Be(n, t)), w.currentTheme = n, w.injectStyles(!0), document.querySelectorAll(".marzipan-container").forEach((r) => {
3148
+ const o = typeof n == "string" ? n : n.name;
3149
+ o && r.setAttribute("data-theme", o);
3150
+ }), document.querySelectorAll(".marzipan-wrapper").forEach((r) => {
3151
+ if (!r.closest(".marzipan-container")) {
3152
+ const a = typeof n == "string" ? n : n.name;
3153
+ a && r.setAttribute("data-theme", a);
3154
+ }
3155
+ const o = r._instance;
3156
+ o && o.updatePreview();
3157
+ });
3158
+ }
3159
+ /**
3160
+ * Initialize global event listeners
3161
+ */
3162
+ static initGlobalListeners() {
3163
+ w.globalListenersInitialized || (document.addEventListener("input", (e) => {
3164
+ if (e.target && e.target.classList && e.target.classList.contains("marzipan-input")) {
3165
+ const n = e.target.closest(".marzipan-wrapper")?._instance;
3166
+ n && n.handleInput(e);
3167
+ }
3168
+ }), document.addEventListener("keydown", (e) => {
3169
+ if (e.target && e.target.classList && e.target.classList.contains("marzipan-input")) {
3170
+ const n = e.target.closest(".marzipan-wrapper")?._instance;
3171
+ n && n.handleKeydown(e);
3172
+ }
3173
+ }), document.addEventListener("scroll", (e) => {
3174
+ if (e.target && e.target.classList && e.target.classList.contains("marzipan-input")) {
3175
+ const n = e.target.closest(".marzipan-wrapper")?._instance;
3176
+ n && n.handleScroll(e);
3177
+ }
3178
+ }, !0), document.addEventListener("selectionchange", (e) => {
3179
+ const t = document.activeElement;
3180
+ if (t && t.classList.contains("marzipan-input")) {
3181
+ const r = t.closest(".marzipan-wrapper")?._instance;
3182
+ r && (r.options.showStats && r.statsBar && r._updateStats(), clearTimeout(r._selectionTimeout), r._selectionTimeout = setTimeout(() => {
3183
+ r.updatePreview();
3184
+ }, 50));
3185
+ }
3186
+ }), w.globalListenersInitialized = !0);
3187
+ }
3188
+ };
3189
+ w.instances = /* @__PURE__ */ new WeakMap(), w.stylesInjected = !1, w.globalListenersInitialized = !1, w.instanceCount = 0;
3190
+ let A = w;
3191
+ A.MarkdownParser = T;
3192
+ A.ShortcutsManager = xe;
3193
+ A.themes = { solar: M, cave: _("cave") };
3194
+ A.getTheme = _;
3195
+ A.currentTheme = M;
3196
+ export {
3197
+ Xe as LinkTooltip,
3198
+ T as MarkdownParser,
3199
+ A as Marzipan,
3200
+ xe as ShortcutsManager,
3201
+ Qe as Toolbar,
3202
+ Pe as actions,
3203
+ se as cave,
3204
+ A as default,
3205
+ Re as generateStyles,
3206
+ _ as getTheme,
3207
+ Be as mergeTheme,
3208
+ M as solar,
3209
+ F as themeToCSSVars,
3210
+ ae as themes
3211
+ };
3212
+ //# sourceMappingURL=index.js.map