@yanglingfeng/md-web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1480 @@
1
+ import './style.css';
2
+ import { useCallback as e, useEffect as t, useId as n, useMemo as r, useRef as i, useState as a } from "react";
3
+ import o from "@uiw/react-codemirror";
4
+ import { defaultKeymap as s, historyKeymap as c, indentWithTab as l } from "@codemirror/commands";
5
+ import { markdown as u, markdownKeymap as d } from "@codemirror/lang-markdown";
6
+ import { HighlightStyle as f, syntaxHighlighting as p } from "@codemirror/language";
7
+ import { EditorView as m, keymap as ee } from "@codemirror/view";
8
+ import { tags as h } from "@lezer/highlight";
9
+ import g from "github-slugger";
10
+ import { Bold as _, Braces as v, CircleHelp as te, Clipboard as ne, Code2 as y, Columns2 as b, Download as re, Eye as ie, FileCode2 as ae, GripVertical as oe, Heading1 as se, Heading2 as x, Image as S, Italic as ce, Link as C, List as le, ListOrdered as ue, ListTree as de, Maximize2 as w, Minus as T, Quote as fe, Sigma as pe, SquareCheck as me, Table2 as E, X as D } from "lucide-react";
11
+ import { Group as he, Panel as ge, Separator as _e } from "react-resizable-panels";
12
+ import { createPortal as ve } from "react-dom";
13
+ import ye, { defaultUrlTransform as O } from "react-markdown";
14
+ import k from "rehype-highlight";
15
+ import A from "rehype-katex";
16
+ import be from "rehype-slug";
17
+ import xe from "remark-breaks";
18
+ import j from "remark-gfm";
19
+ import Se from "remark-math";
20
+ import "katex/dist/katex.min.css";
21
+ import { toString as M } from "mdast-util-to-string";
22
+ import { visit as N } from "unist-util-visit";
23
+ import { Fragment as Ce, jsx as P, jsxs as F } from "react/jsx-runtime";
24
+ //#region src/components/MarkdownEditor/editorCommands.ts
25
+ var I = {
26
+ bold: {
27
+ before: "**",
28
+ after: "**",
29
+ placeholder: "加粗文字"
30
+ },
31
+ italic: {
32
+ before: "*",
33
+ after: "*",
34
+ placeholder: "斜体文字"
35
+ },
36
+ inlineCode: {
37
+ before: "`",
38
+ after: "`",
39
+ placeholder: "代码"
40
+ },
41
+ link: {
42
+ before: "[",
43
+ after: "](https://)",
44
+ placeholder: "链接文字"
45
+ },
46
+ image: {
47
+ before: "![",
48
+ after: "](https://)",
49
+ placeholder: "图片描述"
50
+ },
51
+ formula: {
52
+ before: "$",
53
+ after: "$",
54
+ placeholder: "E = mc^2"
55
+ }
56
+ }, L = {
57
+ heading1: "# ",
58
+ heading2: "## ",
59
+ heading3: "### ",
60
+ heading4: "#### ",
61
+ heading5: "##### ",
62
+ quote: "> ",
63
+ bulletList: "- ",
64
+ orderedList: "1. ",
65
+ task: "- [ ] "
66
+ };
67
+ function R(e, t) {
68
+ let n = I[e];
69
+ if (n) {
70
+ if (t.startsWith(n.before) && t.endsWith(n.after)) {
71
+ let e = t.slice(n.before.length, t.length - n.after.length);
72
+ return {
73
+ text: e,
74
+ selectionFrom: 0,
75
+ selectionTo: e.length
76
+ };
77
+ }
78
+ let e = t || n.placeholder;
79
+ return {
80
+ text: `${n.before}${e}${n.after}`,
81
+ selectionFrom: n.before.length,
82
+ selectionTo: n.before.length + e.length
83
+ };
84
+ }
85
+ let r = L[e];
86
+ if (r) {
87
+ let n = (t || "文本").split("\n").map((t, n) => e === "orderedList" ? `${n + 1}. ${t}` : `${r}${t}`).join("\n");
88
+ return {
89
+ text: n,
90
+ selectionFrom: r.length,
91
+ selectionTo: n.length
92
+ };
93
+ }
94
+ if (e === "codeBlock") {
95
+ let e = t || "在这里输入代码";
96
+ return {
97
+ text: `\`\`\`\n${e}\n\`\`\``,
98
+ selectionFrom: 4,
99
+ selectionTo: 4 + e.length
100
+ };
101
+ }
102
+ return e === "divider" ? {
103
+ text: "\n---\n",
104
+ selectionFrom: 5,
105
+ selectionTo: 5
106
+ } : e === "table" ? {
107
+ text: "| 列 1 | 列 2 | 列 3 |\n| --- | --- | --- |\n| 内容 | 内容 | 内容 |",
108
+ selectionFrom: 2,
109
+ selectionTo: 5
110
+ } : {
111
+ text: t,
112
+ selectionFrom: 0,
113
+ selectionTo: t.length
114
+ };
115
+ }
116
+ function z(e, t) {
117
+ if (!e) return !1;
118
+ let { from: n, to: r } = e.state.selection.main, i = e.state.sliceDoc(n, r), a = I[t];
119
+ if (a && i) {
120
+ let t = n - a.before.length, i = r + a.after.length;
121
+ if (t >= 0 && e.state.sliceDoc(t, n) === a.before && e.state.sliceDoc(r, i) === a.after) return e.dispatch({
122
+ changes: [{
123
+ from: t,
124
+ to: n,
125
+ insert: ""
126
+ }, {
127
+ from: r,
128
+ to: i,
129
+ insert: ""
130
+ }],
131
+ selection: {
132
+ anchor: t,
133
+ head: r - a.before.length
134
+ }
135
+ }), e.focus(), !0;
136
+ }
137
+ let o = L[t];
138
+ if (o && n === r) {
139
+ let r = e.state.doc.lineAt(n), i = t.startsWith("heading") ? /^#{1,6}\s*/.exec(r.text)?.[0] : r.text.startsWith(o) ? o : void 0, a = i ? r.text.slice(i.length) : r.text, s = i === o ? a : `${o}${a}`, c = Math.max(0, n - r.from - (i?.length ?? 0)), l = r.from + (i === o ? 0 : o.length) + c;
140
+ return e.dispatch({
141
+ changes: {
142
+ from: r.from,
143
+ to: r.to,
144
+ insert: s
145
+ },
146
+ selection: { anchor: l }
147
+ }), e.focus(), !0;
148
+ }
149
+ let s = R(t, i);
150
+ return e.dispatch({
151
+ changes: {
152
+ from: n,
153
+ to: r,
154
+ insert: s.text
155
+ },
156
+ selection: {
157
+ anchor: n + s.selectionFrom,
158
+ head: n + s.selectionTo
159
+ },
160
+ scrollIntoView: !0
161
+ }), e.focus(), !0;
162
+ }
163
+ //#endregion
164
+ //#region src/components/MarkdownEditor/legacyDiagrams.ts
165
+ var B = {
166
+ start: ["([", "])"],
167
+ end: ["([", "])"],
168
+ operation: ["[", "]"],
169
+ parallel: ["[", "]"],
170
+ inputoutput: ["[/", "/]"],
171
+ subroutine: ["[[", "]]"],
172
+ condition: ["{", "}"]
173
+ }, V = /* @__PURE__ */ new Set([
174
+ "top",
175
+ "right",
176
+ "bottom",
177
+ "left"
178
+ ]);
179
+ function H(e) {
180
+ return `"${e.replace(/"/g, "#quot;").replace(/\\n/g, "<br/>")}"`;
181
+ }
182
+ function U(e, t) {
183
+ return /^[A-Za-z_][\w-]*$/.test(e) ? e : `n${t}`;
184
+ }
185
+ function W(e) {
186
+ let t = /^([^(\s]+)\s*(?:\(([^)]*)\))?$/.exec(e.trim());
187
+ if (!t) return null;
188
+ let n = (t[2] ?? "").split(",").map((e) => e.trim()).filter((e) => e && !V.has(e.toLowerCase())).join(" ");
189
+ return {
190
+ id: t[1],
191
+ label: n || void 0
192
+ };
193
+ }
194
+ function G(e) {
195
+ let t = /* @__PURE__ */ new Map(), n = [], r = [], i = (e) => {
196
+ let n = t.get(e);
197
+ if (n) return n;
198
+ let r = U(e, t.size + 1);
199
+ return t.set(e, r), r;
200
+ };
201
+ for (let t of e.split("\n")) {
202
+ let e = t.trim();
203
+ if (!e || e.startsWith("//")) continue;
204
+ let a = /^([^=\s]+)\s*=>\s*([a-z]+)\s*(?::([\s\S]*))?$/i.exec(e);
205
+ if (a) {
206
+ let e = a[2].toLowerCase(), t = B[e] ?? B.operation, r = (a[3] ?? a[2]).replace(/:>[^|]*$/, "").split("|")[0].trim();
207
+ n.push(` ${i(a[1].trim())}${t[0]}${H(r || e)}${t[1]}`);
208
+ continue;
209
+ }
210
+ if (!e.includes("->")) continue;
211
+ let o = e.split("->");
212
+ for (let e = 0; e < o.length - 1; e += 1) {
213
+ let t = W(o[e]), n = W(o[e + 1]);
214
+ if (!t || !n) continue;
215
+ let a = t.label ? `-->|${H(t.label)}|` : "-->";
216
+ r.push(` ${i(t.id)} ${a} ${i(n.id)}`);
217
+ }
218
+ }
219
+ return [
220
+ "flowchart TB",
221
+ ...n,
222
+ ...r
223
+ ].join("\n");
224
+ }
225
+ var K = {
226
+ "->": "->>",
227
+ "-->": "-->>",
228
+ "->>": "->>",
229
+ "-->>": "-->>"
230
+ };
231
+ function we(e) {
232
+ let t = /* @__PURE__ */ new Map(), n = [], r = [], i = (e) => {
233
+ let r = e.trim(), i = t.get(r);
234
+ if (i) return i;
235
+ let a = /^[A-Za-z_][\w-]*$/.test(r) ? r : `P${t.size + 1}`;
236
+ return t.set(r, a), n.push(a === r ? ` participant ${a}` : ` participant ${a} as ${r}`), a;
237
+ }, a = (e) => e.trim().replace(/\\n/g, "<br/>");
238
+ for (let t of e.split("\n")) {
239
+ let e = t.trim();
240
+ if (!e || e.startsWith("#")) continue;
241
+ let n = /^title:?\s+(.+)$/i.exec(e);
242
+ if (n) {
243
+ r.push(` title: ${a(n[1])}`);
244
+ continue;
245
+ }
246
+ let o = /^participant\s+(.+?)(?:\s+as\s+(.+))?$/i.exec(e);
247
+ if (o) {
248
+ i(o[2] ?? o[1]);
249
+ continue;
250
+ }
251
+ let s = /^note\s+(left of|right of|over)\s+([^:]+):\s*(.*)$/i.exec(e);
252
+ if (s) {
253
+ let e = s[2].split(",").map((e) => i(e)).join(",");
254
+ r.push(` Note ${s[1].toLowerCase()} ${e}: ${a(s[3])}`);
255
+ continue;
256
+ }
257
+ let c = /^(.+?)\s*(-{1,2}>{1,2})\s*([^:]+):\s*(.*)$/.exec(e);
258
+ if (c) {
259
+ let e = K[c[2]] ?? "->>";
260
+ r.push(` ${i(c[1])}${e}${i(c[3])}: ${a(c[4])}`);
261
+ }
262
+ }
263
+ return [
264
+ "sequenceDiagram",
265
+ ...n,
266
+ ...r
267
+ ].join("\n");
268
+ }
269
+ //#endregion
270
+ //#region src/components/MarkdownEditor/remarkPlugins.ts
271
+ var q = /@\(([^()\n]{1,120})\)\[([^\][\n]{0,240})\]/g, J = /^\[toc\]$/i;
272
+ function Y(e, t) {
273
+ return {
274
+ type: "emphasis",
275
+ data: {
276
+ hName: "span",
277
+ hProperties: { className: [e] }
278
+ },
279
+ children: [{
280
+ type: "text",
281
+ value: t
282
+ }]
283
+ };
284
+ }
285
+ function Te() {
286
+ return (e) => {
287
+ N(e, "text", (e, t, n) => {
288
+ if (!n || t == null || n.type === "link" || n.type === "linkReference" || (q.lastIndex = 0, !q.test(e.value))) return;
289
+ q.lastIndex = 0;
290
+ let r = [], i = 0, a;
291
+ for (; (a = q.exec(e.value)) !== null;) {
292
+ a.index > i && r.push({
293
+ type: "text",
294
+ value: e.value.slice(i, a.index)
295
+ });
296
+ let t = a[2].split("|").map((e) => e.trim()).filter(Boolean);
297
+ r.push({
298
+ type: "emphasis",
299
+ data: {
300
+ hName: "span",
301
+ hProperties: { className: ["md-note-meta"] }
302
+ },
303
+ children: [Y("md-note-meta__book", a[1].trim()), ...t.map((e) => Y("md-note-meta__tag", e))]
304
+ }), i = a.index + a[0].length;
305
+ }
306
+ return i < e.value.length && r.push({
307
+ type: "text",
308
+ value: e.value.slice(i)
309
+ }), n.children.splice(t, 1, ...r), t + r.length;
310
+ });
311
+ };
312
+ }
313
+ function Ee(e, t) {
314
+ let n = M(t);
315
+ return {
316
+ type: "listItem",
317
+ spread: !1,
318
+ data: { hProperties: { className: [`md-doc-toc__item--${t.depth}`] } },
319
+ children: [{
320
+ type: "paragraph",
321
+ children: [{
322
+ type: "link",
323
+ url: `#${e.slug(n)}`,
324
+ children: [{
325
+ type: "text",
326
+ value: n
327
+ }]
328
+ }]
329
+ }]
330
+ };
331
+ }
332
+ function De() {
333
+ return (e) => {
334
+ let t = [];
335
+ if (e.children.forEach((e, n) => {
336
+ e.type === "paragraph" && J.test(M(e).trim()) && t.push(n);
337
+ }), t.length === 0) return;
338
+ let n = new g(), r = [];
339
+ N(e, "heading", (e) => {
340
+ r.push(e);
341
+ });
342
+ let i = r.filter((e) => e.depth >= 2 && e.depth <= 4).map((e) => Ee(n, e)), a = {
343
+ type: "paragraph",
344
+ data: {
345
+ hName: "span",
346
+ hProperties: { className: ["md-doc-toc__title"] }
347
+ },
348
+ children: [{
349
+ type: "text",
350
+ value: "目录"
351
+ }]
352
+ }, o = {
353
+ type: "blockquote",
354
+ data: {
355
+ hName: "nav",
356
+ hProperties: {
357
+ className: ["md-doc-toc"],
358
+ "aria-label": "文档目录"
359
+ }
360
+ },
361
+ children: i.length > 0 ? [a, {
362
+ type: "list",
363
+ ordered: !1,
364
+ spread: !1,
365
+ children: i
366
+ }] : [a]
367
+ };
368
+ for (let n of t.reverse()) e.children.splice(n, 1, o);
369
+ };
370
+ }
371
+ //#endregion
372
+ //#region src/components/MarkdownEditor/MarkdownPreview.tsx
373
+ function X(e) {
374
+ return `<!doctype html>
375
+ <html>
376
+ <head>
377
+ <meta charset="utf-8">
378
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data: https:">
379
+ <style>
380
+ html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; background: transparent; }
381
+ body { box-sizing: border-box; display: grid; padding: 10px; place-items: center; }
382
+ /* Mermaid 会写入内联 max-width,需要覆盖后图形才能填满容器 */
383
+ svg { display: block; width: 100% !important; height: 100% !important; max-width: none !important; }
384
+ </style>
385
+ </head>
386
+ <body>${e}</body>
387
+ </html>`;
388
+ }
389
+ function Z(e) {
390
+ let t = {
391
+ aspectRatio: 2,
392
+ naturalWidth: 640
393
+ }, n = /\bviewBox=["']([^"']+)["']/i.exec(e)?.[1];
394
+ if (!n) return t;
395
+ let r = n.trim().split(/[\s,]+/).map(Number), i = r[2], a = r[3];
396
+ return !Number.isFinite(i) || !Number.isFinite(a) || a <= 0 ? t : {
397
+ aspectRatio: Math.min(Math.max(i / a, .2), 8),
398
+ naturalWidth: Math.min(Math.max(i * 1.25, 200), 1200)
399
+ };
400
+ }
401
+ function Oe({ chart: e, label: r = "Mermaid 图表", cache: i, onError: o }) {
402
+ let s = n(), [c, l] = a(() => i.get(e) ?? null), [u, d] = a(""), [f, p] = a(!1);
403
+ return t(() => {
404
+ if (!f) return;
405
+ let e = (e) => {
406
+ e.key === "Escape" && p(!1);
407
+ };
408
+ return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
409
+ }, [f]), t(() => {
410
+ let t = !0;
411
+ return (async () => {
412
+ try {
413
+ let { default: n } = await import("mermaid");
414
+ n.initialize({
415
+ startOnLoad: !1,
416
+ securityLevel: "strict",
417
+ theme: "base",
418
+ fontFamily: "\"Helvetica Neue\", Helvetica, \"PingFang SC\", sans-serif",
419
+ themeVariables: {
420
+ fontSize: "16px",
421
+ primaryColor: "#ffffff",
422
+ primaryTextColor: "#2f3d4a",
423
+ primaryBorderColor: "#2f3d4a",
424
+ secondaryColor: "#ffffff",
425
+ tertiaryColor: "#ffffff",
426
+ lineColor: "#2f3d4a",
427
+ textColor: "#2f3d4a",
428
+ noteBkgColor: "#ffffff",
429
+ noteBorderColor: "#2f3d4a",
430
+ noteTextColor: "#2f3d4a",
431
+ actorBkg: "#ffffff",
432
+ actorBorder: "#2f3d4a",
433
+ actorTextColor: "#2f3d4a",
434
+ actorLineColor: "#2f3d4a",
435
+ signalColor: "#2f3d4a",
436
+ signalTextColor: "#2f3d4a"
437
+ },
438
+ flowchart: {
439
+ htmlLabels: !1,
440
+ useMaxWidth: !0,
441
+ curve: "linear",
442
+ padding: 14,
443
+ nodeSpacing: 46,
444
+ rankSpacing: 56
445
+ },
446
+ sequence: {
447
+ useMaxWidth: !0,
448
+ mirrorActors: !0,
449
+ actorMargin: 120,
450
+ boxMargin: 14,
451
+ noteMargin: 12,
452
+ messageMargin: 42
453
+ }
454
+ });
455
+ let r = `mermaid-${s.replace(/[^a-zA-Z0-9]/g, "")}-${Date.now()}`, a = i.get(e);
456
+ if (a) {
457
+ if (!t) return;
458
+ l(a), d("");
459
+ return;
460
+ }
461
+ let o = await n.render(r, e);
462
+ if (!t) return;
463
+ let c = {
464
+ source: X(o.svg),
465
+ ...Z(o.svg)
466
+ };
467
+ if (i.set(e, c), i.size > 32) {
468
+ let e = i.keys().next().value;
469
+ e && i.delete(e);
470
+ }
471
+ l(c), d("");
472
+ } catch (e) {
473
+ if (!t) return;
474
+ let n = e instanceof Error ? e : /* @__PURE__ */ Error("Mermaid 图表渲染失败");
475
+ d(n.message), l(null), o?.(n);
476
+ }
477
+ })(), () => {
478
+ t = !1;
479
+ };
480
+ }, [
481
+ i,
482
+ e,
483
+ o,
484
+ s
485
+ ]), u ? /* @__PURE__ */ F("div", {
486
+ className: "md-mermaid-error",
487
+ role: "alert",
488
+ children: [/* @__PURE__ */ P("strong", { children: "图表未能渲染" }), /* @__PURE__ */ P("span", { children: u })]
489
+ }) : c ? /* @__PURE__ */ F(Ce, { children: [/* @__PURE__ */ P("figure", {
490
+ className: "md-mermaid",
491
+ "aria-label": r,
492
+ children: /* @__PURE__ */ F("div", {
493
+ className: "md-mermaid__stage",
494
+ style: {
495
+ "--md-diagram-ratio": c.aspectRatio,
496
+ "--md-diagram-width": `${c.naturalWidth}px`
497
+ },
498
+ children: [/* @__PURE__ */ P("iframe", {
499
+ title: r,
500
+ sandbox: "",
501
+ srcDoc: c.source,
502
+ loading: "lazy"
503
+ }), /* @__PURE__ */ P("button", {
504
+ type: "button",
505
+ className: "md-mermaid__enlarge",
506
+ "aria-label": "放大查看图表",
507
+ onClick: () => p(!0),
508
+ children: /* @__PURE__ */ F("span", {
509
+ className: "md-mermaid__enlarge-chip",
510
+ children: [/* @__PURE__ */ P(w, {
511
+ size: 12,
512
+ strokeWidth: 2
513
+ }), "放大"]
514
+ })
515
+ })]
516
+ })
517
+ }), f && ve(/* @__PURE__ */ P("div", {
518
+ className: "md-diagram-viewer",
519
+ role: "presentation",
520
+ onMouseDown: () => p(!1),
521
+ children: /* @__PURE__ */ F("section", {
522
+ className: "md-diagram-viewer__card",
523
+ role: "dialog",
524
+ "aria-modal": "true",
525
+ "aria-label": `${r}放大视图`,
526
+ onMouseDown: (e) => e.stopPropagation(),
527
+ children: [
528
+ /* @__PURE__ */ F("header", { children: [/* @__PURE__ */ P("span", { children: r }), /* @__PURE__ */ P("button", {
529
+ type: "button",
530
+ "aria-label": "关闭放大视图",
531
+ onClick: () => p(!1),
532
+ children: /* @__PURE__ */ P(D, { size: 16 })
533
+ })] }),
534
+ /* @__PURE__ */ P("div", {
535
+ className: "md-diagram-viewer__stage",
536
+ style: { "--md-diagram-ratio": c.aspectRatio },
537
+ children: /* @__PURE__ */ P("iframe", {
538
+ title: `${r}放大视图`,
539
+ sandbox: "",
540
+ srcDoc: c.source
541
+ })
542
+ }),
543
+ /* @__PURE__ */ P("footer", { children: "点按空白处或按 Esc 关闭" })
544
+ ]
545
+ })
546
+ }), document.body)] }) : /* @__PURE__ */ P("div", {
547
+ className: "md-mermaid-loading",
548
+ children: "正在绘制图表…"
549
+ });
550
+ }
551
+ var Q = (e) => e?.position?.start?.line, ke = {
552
+ h1: ({ node: e, ...t }) => /* @__PURE__ */ P("h1", {
553
+ "data-source-line": Q(e),
554
+ ...t
555
+ }),
556
+ h2: ({ node: e, ...t }) => /* @__PURE__ */ P("h2", {
557
+ "data-source-line": Q(e),
558
+ ...t
559
+ }),
560
+ h3: ({ node: e, ...t }) => /* @__PURE__ */ P("h3", {
561
+ "data-source-line": Q(e),
562
+ ...t
563
+ }),
564
+ h4: ({ node: e, ...t }) => /* @__PURE__ */ P("h4", {
565
+ "data-source-line": Q(e),
566
+ ...t
567
+ }),
568
+ h5: ({ node: e, ...t }) => /* @__PURE__ */ P("h5", {
569
+ "data-source-line": Q(e),
570
+ ...t
571
+ }),
572
+ h6: ({ node: e, ...t }) => /* @__PURE__ */ P("h6", {
573
+ "data-source-line": Q(e),
574
+ ...t
575
+ }),
576
+ p: ({ node: e, ...t }) => /* @__PURE__ */ P("p", {
577
+ "data-source-line": Q(e),
578
+ ...t
579
+ }),
580
+ blockquote: ({ node: e, ...t }) => /* @__PURE__ */ P("blockquote", {
581
+ "data-source-line": Q(e),
582
+ ...t
583
+ }),
584
+ ul: ({ node: e, ...t }) => /* @__PURE__ */ P("ul", {
585
+ "data-source-line": Q(e),
586
+ ...t
587
+ }),
588
+ ol: ({ node: e, ...t }) => /* @__PURE__ */ P("ol", {
589
+ "data-source-line": Q(e),
590
+ ...t
591
+ }),
592
+ table: ({ node: e, ...t }) => /* @__PURE__ */ P("table", {
593
+ "data-source-line": Q(e),
594
+ ...t
595
+ })
596
+ };
597
+ function Ae(e, t) {
598
+ if (t === "src" && /^data:image\/(?:png|jpeg|gif|webp);base64,/i.test(e) || !/^[a-z][a-z0-9+.-]*:/i.test(e)) return e;
599
+ try {
600
+ let t = new URL(e);
601
+ if ([
602
+ "http:",
603
+ "https:",
604
+ "mailto:"
605
+ ].includes(t.protocol)) return e;
606
+ } catch {
607
+ return;
608
+ }
609
+ return O(e);
610
+ }
611
+ var $ = {
612
+ mermaid: {
613
+ label: "Mermaid 图表",
614
+ toMermaid: (e) => e
615
+ },
616
+ flow: {
617
+ label: "流程图",
618
+ toMermaid: G
619
+ },
620
+ flowchart: {
621
+ label: "流程图",
622
+ toMermaid: G
623
+ },
624
+ sequence: {
625
+ label: "时序图",
626
+ toMermaid: we
627
+ }
628
+ };
629
+ function je(e) {
630
+ let t = Array.isArray(e) ? e : [e];
631
+ for (let e of t) {
632
+ let t = /^language-(\w+)$/.exec(String(e ?? ""))?.[1];
633
+ if (t) return t;
634
+ }
635
+ }
636
+ function Me(e) {
637
+ let t = e?.children.find((e) => e.type === "element" && e.tagName === "code"), n = je(t?.properties.className);
638
+ return !!(n && $[n]);
639
+ }
640
+ function Ne({ source: e, onError: t }) {
641
+ let n = i(/* @__PURE__ */ new Map()), r = {
642
+ ...ke,
643
+ code: ({ className: e, children: r, node: i, ...a }) => {
644
+ let o = /language-(\w+)/.exec(e ?? "")?.[1], s = o ? $[o] : void 0;
645
+ if (s) {
646
+ let e = String(r).replace(/\n$/, "");
647
+ return /* @__PURE__ */ P(Oe, {
648
+ chart: s.toMermaid(e),
649
+ label: s.label,
650
+ cache: n.current,
651
+ onError: t
652
+ });
653
+ }
654
+ return /* @__PURE__ */ P("code", {
655
+ className: e,
656
+ ...a,
657
+ children: r
658
+ });
659
+ },
660
+ pre: ({ node: e, children: t, ...n }) => Me(e) ? /* @__PURE__ */ P("div", {
661
+ "data-source-line": Q(e),
662
+ className: "md-mermaid-block",
663
+ children: t
664
+ }) : /* @__PURE__ */ P("pre", {
665
+ "data-source-line": Q(e),
666
+ ...n,
667
+ children: t
668
+ }),
669
+ a: ({ children: e, node: t, ...n }) => /* @__PURE__ */ P("a", {
670
+ ...n,
671
+ rel: "noopener noreferrer",
672
+ children: e
673
+ })
674
+ };
675
+ return /* @__PURE__ */ P("article", {
676
+ className: "md-preview-document",
677
+ "aria-label": "Markdown 预览",
678
+ children: /* @__PURE__ */ P(ye, {
679
+ remarkPlugins: [
680
+ j,
681
+ Se,
682
+ xe,
683
+ Te,
684
+ De
685
+ ],
686
+ rehypePlugins: [
687
+ [A, {
688
+ trust: !1,
689
+ maxExpand: 1e3,
690
+ maxSize: 20
691
+ }],
692
+ [k, { detect: !1 }],
693
+ be
694
+ ],
695
+ remarkRehypeOptions: {
696
+ footnoteLabel: "脚注",
697
+ footnoteLabelProperties: { className: ["md-footnotes-title"] },
698
+ footnoteBackLabel: "返回正文"
699
+ },
700
+ components: r,
701
+ urlTransform: Ae,
702
+ children: e
703
+ })
704
+ });
705
+ }
706
+ //#endregion
707
+ //#region src/components/MarkdownEditor/Toolbar.tsx
708
+ var Pe = [
709
+ {
710
+ command: "heading1",
711
+ label: "一级标题",
712
+ icon: se
713
+ },
714
+ {
715
+ command: "heading2",
716
+ label: "二级标题",
717
+ icon: x
718
+ },
719
+ {
720
+ command: "bold",
721
+ label: "加粗(Ctrl/Cmd+B)",
722
+ icon: _
723
+ },
724
+ {
725
+ command: "italic",
726
+ label: "斜体",
727
+ icon: ce
728
+ },
729
+ {
730
+ command: "link",
731
+ label: "链接(Ctrl/Cmd+L)",
732
+ icon: C
733
+ },
734
+ {
735
+ command: "quote",
736
+ label: "引用",
737
+ icon: fe
738
+ },
739
+ {
740
+ command: "inlineCode",
741
+ label: "行内代码",
742
+ icon: y
743
+ },
744
+ {
745
+ command: "codeBlock",
746
+ label: "代码块",
747
+ icon: v
748
+ },
749
+ {
750
+ command: "bulletList",
751
+ label: "无序列表",
752
+ icon: le
753
+ },
754
+ {
755
+ command: "orderedList",
756
+ label: "有序列表",
757
+ icon: ue
758
+ },
759
+ {
760
+ command: "task",
761
+ label: "任务列表",
762
+ icon: me
763
+ },
764
+ {
765
+ command: "table",
766
+ label: "表格",
767
+ icon: E
768
+ },
769
+ {
770
+ command: "formula",
771
+ label: "数学公式",
772
+ icon: pe
773
+ },
774
+ {
775
+ command: "divider",
776
+ label: "分隔线",
777
+ icon: T
778
+ },
779
+ {
780
+ command: "image",
781
+ label: "图片(Ctrl/Cmd+G)",
782
+ icon: S
783
+ }
784
+ ];
785
+ function Fe({ mode: e, readOnly: t, onCommand: n, onModeChange: r, onDownload: i }) {
786
+ return /* @__PURE__ */ F("div", {
787
+ className: "md-toolbar",
788
+ role: "toolbar",
789
+ "aria-label": "Markdown 格式工具",
790
+ children: [
791
+ /* @__PURE__ */ F("div", {
792
+ className: "md-toolbar__brand",
793
+ "aria-label": "Markdown 编辑器",
794
+ children: [/* @__PURE__ */ P(ae, { size: 17 }), /* @__PURE__ */ P("span", { children: "Markdown" })]
795
+ }),
796
+ /* @__PURE__ */ P("div", {
797
+ className: "md-toolbar__scroll",
798
+ children: /* @__PURE__ */ P("div", {
799
+ className: "md-toolbar__group",
800
+ children: Pe.map(({ command: e, label: r, icon: i }) => /* @__PURE__ */ P("button", {
801
+ type: "button",
802
+ className: "md-icon-button",
803
+ "aria-label": r,
804
+ title: r,
805
+ disabled: t,
806
+ onClick: () => n(e),
807
+ children: /* @__PURE__ */ P(i, {
808
+ size: 15,
809
+ strokeWidth: 1.8
810
+ })
811
+ }, e))
812
+ })
813
+ }),
814
+ /* @__PURE__ */ F("div", {
815
+ className: "md-toolbar__group md-toolbar__modes",
816
+ "aria-label": "查看模式",
817
+ children: [
818
+ /* @__PURE__ */ P("button", {
819
+ type: "button",
820
+ className: `md-icon-button ${e === "edit" ? "is-active" : ""}`,
821
+ "aria-label": "最大化编辑器",
822
+ title: "最大化编辑器(Ctrl/Cmd+Alt+Enter)",
823
+ onClick: () => r("edit"),
824
+ children: /* @__PURE__ */ P(w, { size: 15 })
825
+ }),
826
+ /* @__PURE__ */ P("button", {
827
+ type: "button",
828
+ className: `md-icon-button ${e === "split" ? "is-active" : ""}`,
829
+ "aria-label": "分屏编辑",
830
+ title: "分屏编辑",
831
+ onClick: () => r("split"),
832
+ children: /* @__PURE__ */ P(b, { size: 15 })
833
+ }),
834
+ /* @__PURE__ */ P("button", {
835
+ type: "button",
836
+ className: `md-icon-button ${e === "preview" ? "is-active" : ""}`,
837
+ "aria-label": "预览文档",
838
+ title: "预览文档(Ctrl/Cmd+Enter)",
839
+ onClick: () => r("preview"),
840
+ children: /* @__PURE__ */ P(ie, { size: 15 })
841
+ }),
842
+ /* @__PURE__ */ P("button", {
843
+ type: "button",
844
+ className: "md-icon-button",
845
+ "aria-label": "下载 Markdown",
846
+ title: "下载 Markdown",
847
+ onClick: i,
848
+ children: /* @__PURE__ */ P(re, { size: 15 })
849
+ })
850
+ ]
851
+ })
852
+ ]
853
+ });
854
+ }
855
+ //#endregion
856
+ //#region src/components/MarkdownEditor/useScrollSync.ts
857
+ function Ie(e, t, n) {
858
+ if (e.length === 0) return 0;
859
+ let r = n === "line" ? "top" : "line";
860
+ if (t <= e[0][n]) return e[0][r];
861
+ for (let i = 1; i < e.length; i += 1) {
862
+ let a = e[i - 1], o = e[i];
863
+ if (t <= o[n]) {
864
+ let e = o[n] - a[n] || 1, i = (t - a[n]) / e;
865
+ return a[r] + i * (o[r] - a[r]);
866
+ }
867
+ }
868
+ return e.at(-1)?.[r] ?? 0;
869
+ }
870
+ function Le(n, r, a) {
871
+ let o = i(null), s = i(void 0), c = i(!1), l = i(void 0), u = e((e) => {
872
+ o.current = e, window.clearTimeout(s.current), s.current = window.setTimeout(() => {
873
+ o.current = null;
874
+ }, 180);
875
+ }, []), d = e(() => {
876
+ c.current = !0, window.clearTimeout(l.current), l.current = window.setTimeout(() => {
877
+ c.current = !1;
878
+ }, 180);
879
+ }, []), f = e(() => {
880
+ let e = r.current;
881
+ if (!e) return [];
882
+ let t = e.getBoundingClientRect();
883
+ return Array.from(e.querySelectorAll("[data-source-line]")).map((n) => ({
884
+ line: Number(n.dataset.sourceLine),
885
+ top: n.getBoundingClientRect().top - t.top + e.scrollTop
886
+ })).filter((e) => Number.isFinite(e.line)).sort((e, t) => e.line - t.line);
887
+ }, [r]);
888
+ return t(() => {
889
+ let e = r.current;
890
+ if (!n || !e || !a) return;
891
+ let t = 0, i = () => {
892
+ o.current !== "preview" && (cancelAnimationFrame(t), t = requestAnimationFrame(() => {
893
+ let t = f();
894
+ if (!t.length) return;
895
+ let r = n.lineBlockAtHeight(n.scrollDOM.scrollTop), i = n.state.doc.lineAt(r.from).number;
896
+ u("editor"), e.scrollTop = Ie(t, i, "line");
897
+ }));
898
+ }, p = () => {
899
+ o.current !== "editor" && c.current && (cancelAnimationFrame(t), t = requestAnimationFrame(() => {
900
+ let t = f();
901
+ if (!t.length) return;
902
+ let r = Math.round(Ie(t, e.scrollTop, "top")), i = Math.min(Math.max(r, 1), n.state.doc.lines);
903
+ u("preview");
904
+ let a = n.lineBlockAt(n.state.doc.line(i).from);
905
+ n.scrollDOM.scrollTop = a.top;
906
+ }));
907
+ }, m = { passive: !0 };
908
+ return n.scrollDOM.addEventListener("scroll", i, { passive: !0 }), e.addEventListener("scroll", p, { passive: !0 }), e.addEventListener("wheel", d, m), e.addEventListener("touchstart", d, m), e.addEventListener("pointerdown", d), () => {
909
+ cancelAnimationFrame(t), window.clearTimeout(s.current), window.clearTimeout(l.current), n.scrollDOM.removeEventListener("scroll", i), e.removeEventListener("scroll", p), e.removeEventListener("wheel", d), e.removeEventListener("touchstart", d), e.removeEventListener("pointerdown", d);
910
+ };
911
+ }, [
912
+ n,
913
+ a,
914
+ f,
915
+ d,
916
+ r,
917
+ u
918
+ ]), e((e) => {
919
+ let t = r.current;
920
+ if (!t) return;
921
+ let i = n ? Math.min(Math.max(e, 1), n.state.doc.lines) : Math.max(e, 1), a = f().find((e) => e.line >= i);
922
+ n?.dom.isConnected && (n.dispatch({
923
+ selection: { anchor: n.state.doc.line(i).from },
924
+ effects: m.scrollIntoView(n.state.doc.line(i).from, { y: "center" })
925
+ }), n.focus()), a && t.scrollTo({
926
+ top: a.top,
927
+ behavior: "smooth"
928
+ });
929
+ }, [
930
+ n,
931
+ f,
932
+ r
933
+ ]);
934
+ }
935
+ //#endregion
936
+ //#region src/components/MarkdownEditor/MarkdownEditor.tsx
937
+ var Re = m.theme({
938
+ "&": {
939
+ height: "100%",
940
+ backgroundColor: "#302c27",
941
+ color: "#e9ddcc",
942
+ fontSize: "15px"
943
+ },
944
+ ".cm-scroller": {
945
+ fontFamily: "\"SFMono-Regular\", \"Cascadia Code\", \"Liberation Mono\", Menlo, monospace",
946
+ lineHeight: "1.72",
947
+ padding: "25px 20px 80px"
948
+ },
949
+ ".cm-content": { caretColor: "#ffc94a" },
950
+ ".cm-cursor, .cm-dropCursor": { borderLeftColor: "#ffc94a" },
951
+ ".cm-activeLine": { backgroundColor: "rgba(15, 13, 11, .18)" },
952
+ ".cm-selectionBackground, &.cm-focused .cm-selectionBackground": { backgroundColor: "rgba(14, 12, 10, .5)" },
953
+ ".cm-gutters": {
954
+ backgroundColor: "#302c27",
955
+ color: "#66635e",
956
+ border: "none",
957
+ paddingRight: "7px"
958
+ },
959
+ ".cm-activeLineGutter": {
960
+ backgroundColor: "transparent",
961
+ color: "#9b958b"
962
+ },
963
+ ".cm-focused": { outline: "none" }
964
+ }, { dark: !0 }), ze = m.theme({
965
+ "&": {
966
+ height: "100%",
967
+ backgroundColor: "#f9fafb",
968
+ color: "#27303b"
969
+ },
970
+ ".cm-scroller": {
971
+ fontFamily: "\"SFMono-Regular\", \"Cascadia Code\", \"Liberation Mono\", Menlo, monospace",
972
+ lineHeight: "1.72",
973
+ padding: "25px 20px 80px"
974
+ },
975
+ ".cm-gutters": {
976
+ backgroundColor: "#f9fafb",
977
+ color: "#a0a6ad",
978
+ border: "none"
979
+ },
980
+ ".cm-activeLine": { backgroundColor: "rgba(29, 78, 216, .035)" },
981
+ ".cm-focused": { outline: "none" }
982
+ }), Be = f.define([
983
+ {
984
+ tag: h.heading,
985
+ color: "#ffc643",
986
+ fontWeight: "700"
987
+ },
988
+ {
989
+ tag: h.strong,
990
+ color: "#e38352",
991
+ fontWeight: "700"
992
+ },
993
+ {
994
+ tag: h.emphasis,
995
+ color: "#e8d9c5",
996
+ fontStyle: "italic"
997
+ },
998
+ {
999
+ tag: h.link,
1000
+ color: "#d7bd58",
1001
+ textDecoration: "underline"
1002
+ },
1003
+ {
1004
+ tag: h.url,
1005
+ color: "#718394"
1006
+ },
1007
+ {
1008
+ tag: h.monospace,
1009
+ color: "#98bd62"
1010
+ },
1011
+ {
1012
+ tag: h.quote,
1013
+ color: "#d47b53",
1014
+ fontStyle: "normal"
1015
+ },
1016
+ {
1017
+ tag: h.list,
1018
+ color: "#7b8793"
1019
+ },
1020
+ {
1021
+ tag: h.processingInstruction,
1022
+ color: "#606a74"
1023
+ },
1024
+ {
1025
+ tag: h.punctuation,
1026
+ color: "#6c747c"
1027
+ },
1028
+ {
1029
+ tag: h.contentSeparator,
1030
+ color: "#77716a"
1031
+ },
1032
+ {
1033
+ tag: h.comment,
1034
+ color: "#78846f",
1035
+ fontStyle: "italic"
1036
+ }
1037
+ ]), Ve = f.define([
1038
+ {
1039
+ tag: h.heading,
1040
+ color: "#9a5b22",
1041
+ fontWeight: "700"
1042
+ },
1043
+ {
1044
+ tag: h.strong,
1045
+ color: "#1f2937",
1046
+ fontWeight: "700"
1047
+ },
1048
+ {
1049
+ tag: h.emphasis,
1050
+ color: "#8a4b77",
1051
+ fontStyle: "italic"
1052
+ },
1053
+ {
1054
+ tag: h.link,
1055
+ color: "#2563a8",
1056
+ textDecoration: "underline"
1057
+ },
1058
+ {
1059
+ tag: h.url,
1060
+ color: "#397d89"
1061
+ },
1062
+ {
1063
+ tag: h.monospace,
1064
+ color: "#8d3f64"
1065
+ },
1066
+ {
1067
+ tag: h.quote,
1068
+ color: "#6b7280",
1069
+ fontStyle: "italic"
1070
+ },
1071
+ {
1072
+ tag: h.list,
1073
+ color: "#b45309"
1074
+ }
1075
+ ]), He = {
1076
+ bold: "Mod-b",
1077
+ link: "Mod-l",
1078
+ image: "Mod-g",
1079
+ preview: "Mod-Enter",
1080
+ maximize: "Mod-Alt-Enter",
1081
+ help: "Mod-/"
1082
+ }, Ue = {
1083
+ lineNumbers: !0,
1084
+ highlightActiveLine: !0,
1085
+ highlightActiveLineGutter: !0,
1086
+ foldGutter: !1,
1087
+ autocompletion: !1
1088
+ };
1089
+ function We(e) {
1090
+ let t = new g(), n = [], r = !1;
1091
+ return e.split("\n").forEach((e, i) => {
1092
+ if (/^\s*```/.test(e)) {
1093
+ r = !r;
1094
+ return;
1095
+ }
1096
+ if (r) return;
1097
+ let a = /^(#{1,6})\s+(.+?)\s*#*$/.exec(e);
1098
+ if (!a) return;
1099
+ let o = a[2].replace(/[*_`[\]]/g, "").trim();
1100
+ n.push({
1101
+ depth: a[1].length,
1102
+ text: o,
1103
+ slug: t.slug(o),
1104
+ line: i + 1
1105
+ });
1106
+ }), n;
1107
+ }
1108
+ function Ge(e) {
1109
+ return (e.match(/[\u3400-\u9fff]/g)?.length ?? 0) + (e.replace(/[\u3400-\u9fff]/g, " ").match(/[A-Za-z0-9]+(?:['’-][A-Za-z0-9]+)*/g)?.length ?? 0);
1110
+ }
1111
+ function Ke({ value: n, defaultValue: f = "", onChange: h, mode: g, onModeChange: _, readOnly: v = !1, height: y = "100vh", theme: b = "earthsong", className: re = "", ariaLabel: ae = "Markdown 源码编辑器", shortcuts: se, onImageUpload: x, onError: S, renderStatus: ce }) {
1112
+ let C = n !== void 0, [le, ue] = a(f), w = C ? n : le, [T, fe] = a(w), [pe, me] = a(g ?? "split"), E = g ?? pe, [ve, ye] = a(null), O = i(null), k = i(null), [A, be] = a({
1113
+ line: 1,
1114
+ column: 1
1115
+ }), [xe, j] = a(!1), [Se, M] = a(!1), [N, I] = a(!1), [L, R] = a({
1116
+ x: 0,
1117
+ y: 0
1118
+ }), B = i({
1119
+ x: 0,
1120
+ y: 0,
1121
+ offsetX: 0,
1122
+ offsetY: 0
1123
+ }), V = i(h), H = i(_), U = i(x), W = i(S), G = i(E);
1124
+ t(() => {
1125
+ V.current = h, H.current = _, U.current = x, W.current = S, G.current = E;
1126
+ }, [
1127
+ E,
1128
+ h,
1129
+ S,
1130
+ x,
1131
+ _
1132
+ ]), t(() => {
1133
+ let e = window.setTimeout(() => fe(w), 220);
1134
+ return () => window.clearTimeout(e);
1135
+ }, [w]);
1136
+ let K = e((e) => {
1137
+ g === void 0 && me(e), H.current?.(e);
1138
+ }, [g]), we = e((e) => {
1139
+ C || ue(e), V.current?.(e);
1140
+ }, [C]), q = e(async (e, t) => {
1141
+ if (!U.current) return;
1142
+ let n = typeof crypto < "u" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`, r = `![正在上传 ${e.name}…](uploading-${n})`, i = t.state.selection.main.from;
1143
+ t.dispatch({ changes: {
1144
+ from: i,
1145
+ insert: r
1146
+ } });
1147
+ let a = new AbortController();
1148
+ try {
1149
+ let n = await U.current(e, a.signal), i = typeof n == "string" ? {
1150
+ url: n,
1151
+ alt: e.name
1152
+ } : n, o = t.state.doc.toString().indexOf(r);
1153
+ if (o < 0) return;
1154
+ t.dispatch({ changes: {
1155
+ from: o,
1156
+ to: o + r.length,
1157
+ insert: `![${i.alt ?? e.name}](${i.url})`
1158
+ } });
1159
+ } catch (n) {
1160
+ let i = n instanceof Error ? n : /* @__PURE__ */ Error("图片上传失败");
1161
+ W.current?.(i);
1162
+ let a = t.state.doc.toString().indexOf(r);
1163
+ a >= 0 && t.dispatch({ changes: {
1164
+ from: a,
1165
+ to: a + r.length,
1166
+ insert: `<!-- ${e.name} 上传失败,请重试 -->`
1167
+ } });
1168
+ }
1169
+ }, []), J = r(() => ({
1170
+ ...He,
1171
+ ...se
1172
+ }), [se]), Y = r(() => {
1173
+ let e = (e) => (t) => !v && z(t, e), t = [
1174
+ {
1175
+ key: J.bold,
1176
+ run: e("bold")
1177
+ },
1178
+ {
1179
+ key: J.link,
1180
+ run: e("link")
1181
+ },
1182
+ {
1183
+ key: J.image,
1184
+ run: e("image")
1185
+ },
1186
+ {
1187
+ key: J.preview,
1188
+ run: () => (K(G.current === "preview" ? "split" : "preview"), !0)
1189
+ },
1190
+ {
1191
+ key: J.maximize,
1192
+ run: () => (K(G.current === "edit" ? "split" : "edit"), !0)
1193
+ },
1194
+ {
1195
+ key: J.help,
1196
+ run: () => (M((e) => !e), !0)
1197
+ },
1198
+ ...[
1199
+ 1,
1200
+ 2,
1201
+ 3,
1202
+ 4,
1203
+ 5
1204
+ ].map((t) => ({
1205
+ key: `Mod-${t}`,
1206
+ run: e(`heading${t}`)
1207
+ }))
1208
+ ];
1209
+ return [
1210
+ u(),
1211
+ ee.of([
1212
+ ...t,
1213
+ ...d,
1214
+ l,
1215
+ ...s,
1216
+ ...c
1217
+ ]),
1218
+ p(b === "earthsong" ? Be : Ve),
1219
+ m.lineWrapping,
1220
+ m.domEventHandlers({
1221
+ paste: (e, t) => {
1222
+ if (!U.current) return !1;
1223
+ let n = Array.from(e.clipboardData?.files ?? []).find((e) => e.type.startsWith("image/"));
1224
+ return n ? (e.preventDefault(), q(n, t), !0) : !1;
1225
+ },
1226
+ drop: (e, t) => {
1227
+ if (!U.current) return !1;
1228
+ let n = Array.from(e.dataTransfer?.files ?? []).find((e) => e.type.startsWith("image/"));
1229
+ if (!n) return !1;
1230
+ e.preventDefault();
1231
+ let r = t.posAtCoords({
1232
+ x: e.clientX,
1233
+ y: e.clientY
1234
+ });
1235
+ return r !== null && t.dispatch({ selection: { anchor: r } }), q(n, t), !0;
1236
+ }
1237
+ })
1238
+ ];
1239
+ }, [
1240
+ v,
1241
+ J,
1242
+ b,
1243
+ K,
1244
+ q
1245
+ ]), Te = e((e) => {
1246
+ if (!e.selectionSet && !e.docChanged) return;
1247
+ let t = e.state.selection.main.head, n = e.state.doc.lineAt(t);
1248
+ be({
1249
+ line: n.number,
1250
+ column: t - n.from + 1
1251
+ });
1252
+ }, []), Ee = e((e) => {
1253
+ O.current = e, ye(e);
1254
+ }, [ye]), De = Le(ve, k, E === "split"), X = r(() => We(T), [T]), Z = r(() => ({
1255
+ words: Ge(w),
1256
+ characters: w.length,
1257
+ line: A.line,
1258
+ column: A.column
1259
+ }), [A, w]), Oe = e(() => {
1260
+ let e = X[0]?.text.replace(/[^\p{L}\p{N}\-_]+/gu, "-") || "document", t = new Blob([w], { type: "text/markdown;charset=utf-8" }), n = URL.createObjectURL(t), r = document.createElement("a");
1261
+ r.href = n, r.download = `${e}.md`, r.click(), URL.revokeObjectURL(n);
1262
+ }, [w, X]), Q = e(async () => {
1263
+ let e = k.current?.querySelector(".md-preview-document")?.innerHTML ?? "";
1264
+ try {
1265
+ await navigator.clipboard.writeText(e), I(!0), window.setTimeout(() => I(!1), 1400);
1266
+ } catch (e) {
1267
+ S?.(e instanceof Error ? e : /* @__PURE__ */ Error("复制 HTML 失败"));
1268
+ }
1269
+ }, [S, I]), ke = /* @__PURE__ */ P("div", {
1270
+ className: "md-editor-pane",
1271
+ children: /* @__PURE__ */ P(o, {
1272
+ value: w,
1273
+ onChange: we,
1274
+ onUpdate: Te,
1275
+ onCreateEditor: Ee,
1276
+ extensions: Y,
1277
+ theme: b === "earthsong" ? Re : ze,
1278
+ editable: !v,
1279
+ basicSetup: Ue,
1280
+ "aria-label": ae,
1281
+ height: "100%"
1282
+ })
1283
+ }), Ae = /* @__PURE__ */ P("div", {
1284
+ className: "md-preview-pane",
1285
+ ref: k,
1286
+ children: /* @__PURE__ */ P(Ne, {
1287
+ source: T,
1288
+ onError: S
1289
+ })
1290
+ }), $ = (e) => {
1291
+ B.current = {
1292
+ x: e.clientX,
1293
+ y: e.clientY,
1294
+ offsetX: L.x,
1295
+ offsetY: L.y
1296
+ }, e.currentTarget.setPointerCapture(e.pointerId);
1297
+ }, je = (e) => {
1298
+ e.currentTarget.hasPointerCapture(e.pointerId) && R({
1299
+ x: B.current.offsetX + e.clientX - B.current.x,
1300
+ y: B.current.offsetY + e.clientY - B.current.y
1301
+ });
1302
+ }, Me = { "--md-editor-height": typeof y == "number" ? `${y}px` : y };
1303
+ return /* @__PURE__ */ F("section", {
1304
+ className: `markdown-editor markdown-editor--${b} ${re}`,
1305
+ style: Me,
1306
+ "data-mode": E,
1307
+ children: [
1308
+ /* @__PURE__ */ P(Fe, {
1309
+ mode: E,
1310
+ readOnly: v,
1311
+ onCommand: (e) => z(O.current, e),
1312
+ onModeChange: K,
1313
+ onDownload: Oe
1314
+ }),
1315
+ /* @__PURE__ */ P("div", {
1316
+ className: "md-workspace",
1317
+ children: E === "split" ? /* @__PURE__ */ F(he, {
1318
+ orientation: "horizontal",
1319
+ className: "md-panel-group",
1320
+ children: [
1321
+ /* @__PURE__ */ P(ge, {
1322
+ id: "editor",
1323
+ className: "md-editor-panel",
1324
+ defaultSize: "50%",
1325
+ minSize: "28%",
1326
+ children: ke
1327
+ }),
1328
+ /* @__PURE__ */ P(_e, { className: "md-resize-handle" }),
1329
+ /* @__PURE__ */ P(ge, {
1330
+ id: "preview",
1331
+ className: "md-preview-panel",
1332
+ defaultSize: "50%",
1333
+ minSize: "28%",
1334
+ children: Ae
1335
+ })
1336
+ ]
1337
+ }) : E === "edit" ? ke : Ae
1338
+ }),
1339
+ /* @__PURE__ */ F("div", {
1340
+ className: "md-mini-tools",
1341
+ style: { transform: `translate(${L.x}px, ${L.y}px)` },
1342
+ children: [
1343
+ xe && /* @__PURE__ */ F("nav", {
1344
+ className: "md-popover md-toc",
1345
+ "aria-label": "文档目录",
1346
+ children: [/* @__PURE__ */ F("div", {
1347
+ className: "md-popover__title",
1348
+ children: [/* @__PURE__ */ P("span", { children: "文档目录" }), /* @__PURE__ */ P("button", {
1349
+ type: "button",
1350
+ "aria-label": "关闭目录",
1351
+ onClick: () => j(!1),
1352
+ children: /* @__PURE__ */ P(D, { size: 14 })
1353
+ })]
1354
+ }), X.length ? X.map((e) => /* @__PURE__ */ P("button", {
1355
+ type: "button",
1356
+ style: { paddingLeft: `${12 + (e.depth - 1) * 12}px` },
1357
+ onClick: () => {
1358
+ De(e.line), j(!1);
1359
+ },
1360
+ children: e.text
1361
+ }, `${e.slug}-${e.line}`)) : /* @__PURE__ */ P("p", { children: "添加标题后会在这里生成目录。" })]
1362
+ }),
1363
+ /* @__PURE__ */ P("button", {
1364
+ type: "button",
1365
+ className: "md-mini-tools__drag",
1366
+ "aria-label": "拖动迷你工具条",
1367
+ title: "拖动工具条",
1368
+ onPointerDown: $,
1369
+ onPointerMove: je,
1370
+ children: /* @__PURE__ */ P(oe, { size: 13 })
1371
+ }),
1372
+ /* @__PURE__ */ P("button", {
1373
+ type: "button",
1374
+ "aria-label": "打开目录",
1375
+ title: "文档目录",
1376
+ onClick: () => j((e) => !e),
1377
+ children: /* @__PURE__ */ P(de, { size: 14 })
1378
+ }),
1379
+ /* @__PURE__ */ F("span", {
1380
+ className: "md-word-count",
1381
+ title: `${Z.characters} 个字符`,
1382
+ children: [Z.words, " 字"]
1383
+ }),
1384
+ /* @__PURE__ */ P("button", {
1385
+ type: "button",
1386
+ "aria-label": "预览文档",
1387
+ title: "切换预览",
1388
+ onClick: () => K(E === "preview" ? "split" : "preview"),
1389
+ children: /* @__PURE__ */ P(ie, { size: 14 })
1390
+ }),
1391
+ /* @__PURE__ */ P("button", {
1392
+ type: "button",
1393
+ "aria-label": "复制 HTML",
1394
+ title: N ? "已复制" : "复制 HTML",
1395
+ onClick: () => void Q(),
1396
+ children: /* @__PURE__ */ P(ne, { size: 14 })
1397
+ }),
1398
+ /* @__PURE__ */ P("button", {
1399
+ type: "button",
1400
+ "aria-label": "语法帮助",
1401
+ title: "语法帮助(Ctrl/Cmd+/)",
1402
+ onClick: () => M(!0),
1403
+ children: /* @__PURE__ */ P(te, { size: 14 })
1404
+ })
1405
+ ]
1406
+ }),
1407
+ /* @__PURE__ */ P("div", {
1408
+ className: "md-status",
1409
+ "aria-live": "polite",
1410
+ children: ce?.(Z) ?? /* @__PURE__ */ F(Ce, { children: [
1411
+ /* @__PURE__ */ F("span", { children: [
1412
+ "Ln ",
1413
+ Z.line,
1414
+ ", Col ",
1415
+ Z.column
1416
+ ] }),
1417
+ /* @__PURE__ */ F("span", { children: [Z.characters, " 字符"] }),
1418
+ N && /* @__PURE__ */ P("span", { children: "HTML 已复制" })
1419
+ ] })
1420
+ }),
1421
+ Se && /* @__PURE__ */ P("div", {
1422
+ className: "md-dialog-backdrop",
1423
+ role: "presentation",
1424
+ onMouseDown: () => M(!1),
1425
+ children: /* @__PURE__ */ F("section", {
1426
+ className: "md-help-dialog",
1427
+ role: "dialog",
1428
+ "aria-modal": "true",
1429
+ "aria-labelledby": "md-help-title",
1430
+ onMouseDown: (e) => e.stopPropagation(),
1431
+ children: [/* @__PURE__ */ F("header", { children: [/* @__PURE__ */ F("div", { children: [/* @__PURE__ */ P("span", {
1432
+ className: "md-help-dialog__eyebrow",
1433
+ children: "QUICK REFERENCE"
1434
+ }), /* @__PURE__ */ P("h2", {
1435
+ id: "md-help-title",
1436
+ children: "Markdown 语法帮助"
1437
+ })] }), /* @__PURE__ */ P("button", {
1438
+ type: "button",
1439
+ "aria-label": "关闭帮助",
1440
+ onClick: () => M(!1),
1441
+ children: /* @__PURE__ */ P(D, { size: 18 })
1442
+ })] }), /* @__PURE__ */ F("div", {
1443
+ className: "md-help-grid",
1444
+ children: [/* @__PURE__ */ F("dl", { children: [
1445
+ /* @__PURE__ */ P("dt", { children: "标题" }),
1446
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "# 一级标题" }) }),
1447
+ /* @__PURE__ */ P("dt", { children: "强调" }),
1448
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "**加粗** · *斜体*" }) }),
1449
+ /* @__PURE__ */ P("dt", { children: "链接" }),
1450
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "[文字](https://)" }) }),
1451
+ /* @__PURE__ */ P("dt", { children: "图片" }),
1452
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "![说明](图片地址)" }) }),
1453
+ /* @__PURE__ */ P("dt", { children: "引用" }),
1454
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "> 引用内容" }) }),
1455
+ /* @__PURE__ */ P("dt", { children: "分隔线" }),
1456
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "---" }) })
1457
+ ] }), /* @__PURE__ */ F("dl", { children: [
1458
+ /* @__PURE__ */ P("dt", { children: "任务" }),
1459
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "- [ ] 待办事项" }) }),
1460
+ /* @__PURE__ */ P("dt", { children: "公式" }),
1461
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "$E = mc^2$" }) }),
1462
+ /* @__PURE__ */ P("dt", { children: "图表" }),
1463
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "```mermaid ```flow ```sequence" }) }),
1464
+ /* @__PURE__ */ P("dt", { children: "目录" }),
1465
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "[TOC]" }) }),
1466
+ /* @__PURE__ */ P("dt", { children: "脚注" }),
1467
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "正文[^1] 与 [^1]: 注释" }) }),
1468
+ /* @__PURE__ */ P("dt", { children: "笔记本" }),
1469
+ /* @__PURE__ */ P("dd", { children: /* @__PURE__ */ P("code", { children: "@(笔记本)[标签A|标签B]" }) })
1470
+ ] })]
1471
+ })]
1472
+ })
1473
+ })
1474
+ ]
1475
+ });
1476
+ }
1477
+ //#endregion
1478
+ export { Ke as MarkdownEditor, Ne as MarkdownPreview, z as runEditorCommand, R as transformSelection };
1479
+
1480
+ //# sourceMappingURL=index.js.map