dsh-md-plus 0.4.4 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,6 +1,21 @@
1
1
  # 更新日志
2
2
 
3
- ## 0.4.4 —— 未发布
3
+ ## 0.4.5 —— 2026-11-03
4
+
5
+ - 修复保存设置时无条件重绘所有 Mermaid 图、重置所有折叠状态的问题:只对真正变化的设置项执行重绘或重新测量,用户手动展开的长代码块和长表格不会被折叠回去。
6
+ - 优化长会话性能:流式输出期间跳过历史代码块的重复装饰;缓存设置读取,折叠扫描每轮只取一次阈值;同一轮扫描复用 Mermaid 图类型判断。
7
+ - 降低长会话内存:高亮去重键从 DOM 属性改为 WeakMap,避免完整源码复制进页面属性;定期清理已脱离文档的插件按钮。
8
+ - 工程化:`npm run check` 先构建再测试;补声明 `@shikijs/langs` 直接依赖;`publishConfig` 固定 npmjs registry;预览和展示脚本从 `package.json` 读取版本。
9
+ - 新增维护者发版脚本:自动修改 CHANGELOG 发布日期、提交、打 tag、推送代码和 tag,支持 `npm run release:dry` 预览。
10
+ - 修复 Mermaid「下载 PNG」不可用:Mermaid 改用 SVG 文本标签,避免 `foreignObject` 污染 canvas;导出失败时按钮会给出提示;新增 `npm run smoke` 真实浏览器验证。
11
+ - 修复折叠表格的 resize 监听泄漏和侧栏宽度变化时按钮偏位:表格卸载时自动清理监听,按钮位置改用 `ResizeObserver` 跟随。
12
+ - 修复合法 Mermaid 图的节点标签包含「Syntax error in text」时被误判为渲染失败。
13
+ - 修复表格复制按钮的反馈文案显示到另一颗按钮、剪贴板 API 被拒时没有 textarea 兜底;设置面板和图片预览打开时锁定背景滚动并约束键盘焦点;离开 Markdown 页面时移除设置齿轮。
14
+ - 修复 localStorage 读成功但写入失败时 Mermaid 配色只在存储里变化、当前会话不生效的问题。
15
+ - README 预览图改用 GitHub Pages 绝对地址,npm 包页面也能正常显示。
16
+ - 测试补到 85 条,补强设置保存不重置折叠、只改字号不重绘 Mermaid、流式输出不插按钮、源码不复制进属性、剪贴板降级、弹层滚动和主题存储等回归用例。
17
+
18
+ ## 0.4.4 —— 2026-11-01
4
19
 
5
20
  - 修复表格折叠按钮在低阈值和展开/收起后漂移、消失的问题:补齐表格折叠高度规则、重置滚动位置,并给按钮阴影留出空间。
6
21
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  给 DeepSeek Harness Web / Desktop 的 Markdown 阅读增强插件:重做代码块卡片、给 DSH 不认识的语言补语法高亮、自己渲染 mermaid 图形、重做表格样式并支持复制、图片点击放大,以及一个调整显示参数的设置面板。
4
4
 
5
- [![dsh-md-plus 显示效果预览](<docs/preview.png>)](https://josephhy.github.io/dsh-md-plus/docs/showcase/)
5
+ [![dsh-md-plus 显示效果预览](https://josephhy.github.io/dsh-md-plus/docs/preview.png)](https://josephhy.github.io/dsh-md-plus/docs/showcase/)
6
6
 
7
7
  ## 功能
8
8
 
@@ -27,9 +27,12 @@ dsh plugin --profile desktop remove dsh-md-plus
27
27
  ```powershell
28
28
  npm install # 顺带跑 prepare → build
29
29
  npm run build # 产出 lib/ 下四个文件
30
- npm run check # 语法检查 + 78 条测试(先 build 再跑,check 不含 build)
30
+ npm run check # 构建 + 语法检查 + 85 条测试(check 会先 build)
31
+ npm run release:dry # 维护者发版:先看 CHANGELOG 日期 + 提交 + tag + push 计划
32
+ npm run release # 维护者发版:改 CHANGELOG 日期 + 提交 + 打 tag + 推送(tag 会触发 GitHub Actions 自动发 npm)
31
33
  npm run preview # 生成 preview.html(含真渲出来的 mermaid 图)
32
34
  npm run shot # 用 headless Chrome 把 preview.html 截成 docs/preview.png
35
+ npm run smoke # 用本机 Chrome 验证 Mermaid 渲染和 PNG 导出(Chrome 路径可用 CHROME_PATH 覆盖)
33
36
  ```
34
37
 
35
38
  `npm run preview` / `scripts/showcase.mjs` 需要读取 DSH 安装目录里的主题和前端资源;如果本机 DSH 是 `app.asar` 包,请先解包到目录,并把 `DSH_APP_DIR` 指向该目录。
package/lib/client.js CHANGED
@@ -65,6 +65,7 @@ window.__ModuleLoader__.load({
65
65
  fit: "\u9002\u5E94\u6574\u56FE",
66
66
  downloadSvg: "\u4E0B\u8F7D SVG",
67
67
  downloadPng: "\u4E0B\u8F7D PNG",
68
+ exportFailed: "\u5BFC\u51FA\u5931\u8D25\uFF0C\u8BF7\u6539\u7528 SVG",
68
69
  close: "\u5173\u95ED",
69
70
  tableCsv: "CSV",
70
71
  tableMd: "Markdown",
@@ -118,6 +119,7 @@ window.__ModuleLoader__.load({
118
119
  fit: "Fit",
119
120
  downloadSvg: "Download SVG",
120
121
  downloadPng: "Download PNG",
122
+ exportFailed: "Export failed; try SVG instead",
121
123
  close: "Close",
122
124
  tableCsv: "CSV",
123
125
  tableMd: "Markdown",
@@ -154,7 +156,6 @@ window.__ModuleLoader__.load({
154
156
  }
155
157
  var MODAL_CLASS = "md-plus-mmd-modal";
156
158
  var DONE_ATTR = "data-md-plus";
157
- var KEY_ATTR = "data-md-plus-key";
158
159
  var WRAP_ATTR = "data-md-plus-wrap";
159
160
  var MMD_ATTR = "data-md-plus-mmd";
160
161
  var FOLD_ATTR = "data-md-plus-fold";
@@ -180,7 +181,10 @@ window.__ModuleLoader__.load({
180
181
  var DEBOUNCE_MS = 160;
181
182
  var memorySettings = null;
182
183
  var memoryTheme = null;
184
+ var settingsCache = null;
185
+ var themeCache = null;
183
186
  function readSettings() {
187
+ if (settingsCache !== null) return { ...settingsCache };
184
188
  var settings = { ...DEFAULT_SETTINGS };
185
189
  try {
186
190
  var raw = window.localStorage.getItem(SETTINGS_KEY);
@@ -198,12 +202,14 @@ window.__ModuleLoader__.load({
198
202
  }
199
203
  memorySettings = { ...settings };
200
204
  } catch {
201
- if (memorySettings !== null) return { ...DEFAULT_SETTINGS, ...memorySettings };
205
+ if (memorySettings !== null) settings = { ...DEFAULT_SETTINGS, ...memorySettings };
202
206
  }
203
- return settings;
207
+ settingsCache = { ...settings };
208
+ return { ...settingsCache };
204
209
  }
205
210
  function saveSettings(next) {
206
211
  memorySettings = { ...next };
212
+ settingsCache = { ...next };
207
213
  try {
208
214
  window.localStorage.setItem(SETTINGS_KEY, JSON.stringify(next));
209
215
  } catch {
@@ -536,6 +542,11 @@ window.__ModuleLoader__.load({
536
542
  var scripts = /* @__PURE__ */ new Map();
537
543
  var pending = /* @__PURE__ */ new Set();
538
544
  var foldSyncs = /* @__PURE__ */ new WeakMap();
545
+ var foldTargets = /* @__PURE__ */ new Set();
546
+ var foldResizeObserver = null;
547
+ var foldResizeHandler = null;
548
+ var diagramKindCache = /* @__PURE__ */ new WeakMap();
549
+ var cacheKeys = /* @__PURE__ */ new WeakMap();
539
550
  var timer = null;
540
551
  var rescanQueued = false;
541
552
  var injected = /* @__PURE__ */ new Set();
@@ -668,7 +679,7 @@ window.__ModuleLoader__.load({
668
679
  var single = MMD_SINGLE.exec(value);
669
680
  return single === null ? null : single[1];
670
681
  }
671
- function diagramKind(block) {
682
+ function computeDiagramKind(block) {
672
683
  var lang = readLang(block);
673
684
  if (MMD_LANGS.has(lang)) return "diagram";
674
685
  if (lang !== "") return null;
@@ -676,12 +687,22 @@ window.__ModuleLoader__.load({
676
687
  if (pre === null) return null;
677
688
  return sniffDiagramType(pre.textContent ?? "") === null ? null : "diagram";
678
689
  }
690
+ function diagramKind(block) {
691
+ if (diagramKindCache.has(block)) return diagramKindCache.get(block);
692
+ var kind = computeDiagramKind(block);
693
+ diagramKindCache.set(block, kind);
694
+ return kind;
695
+ }
679
696
  function isOurs(node) {
680
697
  var element = node?.nodeType === 1 ? node : node?.parentElement;
681
698
  return element?.closest?.(
682
- "." + HOST_CLASS + ", ." + BTN_CLASS + ", ." + MMD_CLASS + ", ." + FOLD_BTN_CLASS + ", ." + TABLE_TOOLS_CLASS + ", ." + IMG_MODAL_CLASS + ", ." + SETTINGS_BTN_CLASS + ", ." + SETTINGS_MODAL_CLASS
699
+ "." + HOST_CLASS + ", ." + BTN_CLASS + ", ." + MMD_CLASS + ", ." + FOLD_BTN_CLASS + ", ." + TABLE_TOOLS_CLASS + ", ." + IMG_MODAL_CLASS + ", ." + MODAL_CLASS + ", ." + SETTINGS_BTN_CLASS + ", ." + SETTINGS_MODAL_CLASS
683
700
  ) != null;
684
701
  }
702
+ function closestStreaming(node) {
703
+ var element = node?.nodeType === 1 ? node : node?.parentElement;
704
+ return element?.closest?.("[data-streaming]") ?? null;
705
+ }
685
706
  function schedule(block) {
686
707
  if (disposed) return;
687
708
  if (block !== void 0) pending.add(block);
@@ -692,6 +713,11 @@ window.__ModuleLoader__.load({
692
713
  function flush() {
693
714
  timer = null;
694
715
  if (disposed) return;
716
+ for (const node of injected) {
717
+ if (!node.isConnected) injected.delete(node);
718
+ }
719
+ cleanupFoldTargets();
720
+ diagramKindCache = /* @__PURE__ */ new WeakMap();
695
721
  if (rescanQueued) {
696
722
  rescanQueued = false;
697
723
  for (const block of document.querySelectorAll(BLOCK)) pending.add(block);
@@ -699,6 +725,7 @@ window.__ModuleLoader__.load({
699
725
  var batch = Array.from(pending);
700
726
  pending.clear();
701
727
  for (const block of batch) {
728
+ if (closestStreaming(block) !== null) continue;
702
729
  decorate(block);
703
730
  void enhance(block);
704
731
  }
@@ -711,6 +738,7 @@ window.__ModuleLoader__.load({
711
738
  redrawDiagrams();
712
739
  return;
713
740
  }
741
+ if (closestStreaming(record.target) !== null) continue;
714
742
  if (isOurs(record.target)) continue;
715
743
  var added = record.addedNodes;
716
744
  var oursOnly = added.length > 0;
@@ -727,7 +755,7 @@ window.__ModuleLoader__.load({
727
755
  function redrawDiagrams() {
728
756
  for (const block of document.querySelectorAll("[" + MMD_ATTR + "]")) {
729
757
  if (block.getAttribute(MMD_ATTR) === "failed") continue;
730
- block.removeAttribute(KEY_ATTR);
758
+ cacheKeys.delete(block);
731
759
  pending.add(block);
732
760
  }
733
761
  schedule();
@@ -779,7 +807,7 @@ window.__ModuleLoader__.load({
779
807
  titleKey: "retry",
780
808
  ariaKey: "retryAria",
781
809
  run: (block) => {
782
- block.removeAttribute(KEY_ATTR);
810
+ cacheKeys.delete(block);
783
811
  block.removeAttribute(MMD_ATTR);
784
812
  block.querySelector("." + MMD_CLASS + "-error")?.remove();
785
813
  void enhance(block);
@@ -832,13 +860,13 @@ window.__ModuleLoader__.load({
832
860
  if (host === null) return false;
833
861
  if (content.querySelector("pre.shiki:not(.md-plus-pre)") === null) return false;
834
862
  host.remove();
835
- block.removeAttribute(KEY_ATTR);
863
+ cacheKeys.delete(block);
836
864
  block.removeAttribute(DONE_ATTR);
837
865
  return true;
838
866
  }
839
867
  async function enhance(block) {
840
868
  if (!block.isConnected) return;
841
- if (block.closest("[data-streaming]") !== null) return;
869
+ if (closestStreaming(block) !== null) return;
842
870
  var content = block.querySelector(CONTENT);
843
871
  if (content === null) return;
844
872
  if (releaseTakenOver(block, content)) return;
@@ -858,7 +886,7 @@ window.__ModuleLoader__.load({
858
886
  var code = pre.textContent ?? "";
859
887
  if (code.trim() === "") return;
860
888
  var key = lang + "\0" + code;
861
- if (block.getAttribute(KEY_ATTR) === key) return;
889
+ if (cacheKeys.get(block) === key) return;
862
890
  var html;
863
891
  try {
864
892
  html = await api.highlight(code, lang);
@@ -883,21 +911,27 @@ window.__ModuleLoader__.load({
883
911
  content.querySelector("." + HOST_CLASS)?.remove();
884
912
  resetFold(content);
885
913
  pre.after(host);
886
- block.setAttribute(KEY_ATTR, key);
914
+ cacheKeys.set(block, key);
887
915
  block.setAttribute(DONE_ATTR, "done");
888
916
  scheduleFold(content, foldLimit("code"));
889
917
  }
890
918
  function getMermaidTheme() {
919
+ if (themeCache !== null) return themeCache;
891
920
  try {
892
921
  var saved = window.localStorage.getItem(THEME_KEY);
893
922
  if (saved !== null && THEME_ORDER.indexOf(saved) !== -1) {
894
923
  memoryTheme = saved;
924
+ themeCache = saved;
895
925
  return saved;
896
926
  }
897
927
  memoryTheme = null;
898
928
  } catch {
899
- if (memoryTheme !== null) return memoryTheme;
929
+ if (memoryTheme !== null) {
930
+ themeCache = memoryTheme;
931
+ return memoryTheme;
932
+ }
900
933
  }
934
+ themeCache = "blue";
901
935
  return "blue";
902
936
  }
903
937
  function themeLabel(name) {
@@ -915,6 +949,7 @@ window.__ModuleLoader__.load({
915
949
  var index = THEME_ORDER.indexOf(current);
916
950
  var next = THEME_ORDER[(index + 1) % THEME_ORDER.length];
917
951
  memoryTheme = next;
952
+ themeCache = next;
918
953
  try {
919
954
  window.localStorage.setItem(THEME_KEY, next);
920
955
  } catch {
@@ -926,7 +961,7 @@ window.__ModuleLoader__.load({
926
961
  var code = (pre.textContent ?? "").trim();
927
962
  if (code === "") return;
928
963
  var key = "mmd\0" + code;
929
- if (block.getAttribute(KEY_ATTR) === key) return;
964
+ if (cacheKeys.get(block) === key) return;
930
965
  var api = await loadScript(MMD_URL, MMD_GLOBAL);
931
966
  if (disposed || api === null) return;
932
967
  if (!pre.isConnected) return;
@@ -959,7 +994,7 @@ window.__ModuleLoader__.load({
959
994
  if (viewport !== null) bindViewport(block, viewport);
960
995
  pre.before(host);
961
996
  content.querySelector("." + MMD_CLASS + "-error")?.remove();
962
- block.setAttribute(KEY_ATTR, key);
997
+ cacheKeys.set(block, key);
963
998
  var view = block.getAttribute(MMD_ATTR);
964
999
  if (view !== "code" && view !== "diagram") block.setAttribute(MMD_ATTR, readSettings().diagramView);
965
1000
  zooms.delete(block);
@@ -1072,14 +1107,65 @@ window.__ModuleLoader__.load({
1072
1107
  var sync = foldSyncs.get(target);
1073
1108
  if (sync !== void 0) {
1074
1109
  target.removeEventListener("scroll", sync);
1075
- window.removeEventListener("resize", sync);
1076
1110
  foldSyncs.delete(target);
1077
1111
  }
1112
+ foldTargets.delete(target);
1113
+ if (foldTargets.size === 0) {
1114
+ if (foldResizeObserver !== null) {
1115
+ foldResizeObserver.disconnect();
1116
+ foldResizeObserver = null;
1117
+ }
1118
+ if (foldResizeHandler !== null) {
1119
+ window.removeEventListener("resize", foldResizeHandler);
1120
+ foldResizeHandler = null;
1121
+ }
1122
+ } else if (foldResizeObserver !== null) {
1123
+ foldResizeObserver.unobserve(target);
1124
+ }
1078
1125
  target.removeAttribute(FOLD_ATTR);
1079
1126
  target.classList.remove(FOLD_CLASS);
1080
1127
  target.style.removeProperty("--md-plus-fold-max-height");
1081
1128
  target.querySelector("." + FOLD_BTN_CLASS)?.remove();
1082
1129
  }
1130
+ function watchFoldTarget(target, sync) {
1131
+ foldSyncs.set(target, sync);
1132
+ foldTargets.add(target);
1133
+ if (typeof window.ResizeObserver === "function") {
1134
+ if (foldResizeObserver === null) {
1135
+ foldResizeObserver = new window.ResizeObserver((entries) => {
1136
+ for (const entry of entries) {
1137
+ var entryTarget = entry.target;
1138
+ var entrySync = foldSyncs.get(entryTarget);
1139
+ if (entrySync === void 0) continue;
1140
+ if (!entryTarget.isConnected) {
1141
+ resetFold(entryTarget);
1142
+ continue;
1143
+ }
1144
+ entrySync();
1145
+ }
1146
+ });
1147
+ }
1148
+ foldResizeObserver.observe(target);
1149
+ return;
1150
+ }
1151
+ if (foldResizeHandler === null) {
1152
+ foldResizeHandler = () => {
1153
+ for (const entryTarget of foldTargets) {
1154
+ if (!entryTarget.isConnected) {
1155
+ resetFold(entryTarget);
1156
+ continue;
1157
+ }
1158
+ foldSyncs.get(entryTarget)?.();
1159
+ }
1160
+ };
1161
+ window.addEventListener("resize", foldResizeHandler);
1162
+ }
1163
+ }
1164
+ function cleanupFoldTargets() {
1165
+ for (const target of foldTargets) {
1166
+ if (!target.isConnected) resetFold(target);
1167
+ }
1168
+ }
1083
1169
  function scheduleFold(target, limit) {
1084
1170
  if (target === null) return;
1085
1171
  if (!(limit > 0)) {
@@ -1094,7 +1180,7 @@ window.__ModuleLoader__.load({
1094
1180
  if (target.getAttribute(FOLD_ATTR) !== null) return;
1095
1181
  var schedule2 = window.requestAnimationFrame ?? ((cb) => window.setTimeout(cb, 0));
1096
1182
  schedule2(() => {
1097
- if (!target.isConnected || target.getAttribute(FOLD_ATTR) !== null) return;
1183
+ if (disposed || !target.isConnected || target.getAttribute(FOLD_ATTR) !== null) return;
1098
1184
  if (target.scrollHeight <= limit) {
1099
1185
  target.setAttribute(FOLD_ATTR, "none");
1100
1186
  return;
@@ -1112,9 +1198,8 @@ window.__ModuleLoader__.load({
1112
1198
  button.style.left = target.scrollLeft + target.clientWidth / 2 + "px";
1113
1199
  } : null;
1114
1200
  if (sync !== null) {
1115
- foldSyncs.set(target, sync);
1116
1201
  target.addEventListener("scroll", sync, { passive: true });
1117
- window.addEventListener("resize", sync);
1202
+ watchFoldTarget(target, sync);
1118
1203
  }
1119
1204
  button.addEventListener("click", () => {
1120
1205
  var folded = target.getAttribute(FOLD_ATTR) === "on";
@@ -1129,15 +1214,17 @@ window.__ModuleLoader__.load({
1129
1214
  });
1130
1215
  }
1131
1216
  function scanFolds() {
1217
+ var codeLimit = foldLimit("code");
1218
+ var tableLimit = foldLimit("table");
1132
1219
  for (const block of document.querySelectorAll(BLOCK)) {
1133
- if (block.closest("[data-streaming]") !== null) continue;
1220
+ if (closestStreaming(block) !== null) continue;
1134
1221
  if (diagramKind(block) !== null) continue;
1135
- scheduleFold(block.querySelector(CONTENT), foldLimit("code"));
1222
+ scheduleFold(block.querySelector(CONTENT), codeLimit);
1136
1223
  }
1137
1224
  for (const table of document.querySelectorAll(TABLE)) {
1138
- if (table.closest("[data-streaming]") !== null) continue;
1225
+ if (closestStreaming(table) !== null) continue;
1139
1226
  decorateTable(table);
1140
- scheduleFold(table, foldLimit("table"));
1227
+ scheduleFold(table, tableLimit);
1141
1228
  }
1142
1229
  }
1143
1230
  function cellText(cell) {
@@ -1161,8 +1248,11 @@ window.__ModuleLoader__.load({
1161
1248
  }
1162
1249
  async function copyText(text) {
1163
1250
  if (window.navigator.clipboard !== void 0 && typeof window.navigator.clipboard.writeText === "function") {
1164
- await window.navigator.clipboard.writeText(text);
1165
- return true;
1251
+ try {
1252
+ await window.navigator.clipboard.writeText(text);
1253
+ return true;
1254
+ } catch {
1255
+ }
1166
1256
  }
1167
1257
  var area = document.createElement("textarea");
1168
1258
  area.value = text;
@@ -1201,7 +1291,7 @@ window.__ModuleLoader__.load({
1201
1291
  ["csv", t("tableCsv"), "copyCsvTitle", tableToCsv],
1202
1292
  ["md", t("tableMd"), "copyMdTitle", tableToMarkdown]
1203
1293
  ]) {
1204
- var button = document.createElement("button");
1294
+ const button = document.createElement("button");
1205
1295
  button.type = "button";
1206
1296
  button.textContent = label;
1207
1297
  button.title = t(titleKey);
@@ -1220,6 +1310,48 @@ window.__ModuleLoader__.load({
1220
1310
  tools.appendChild(group);
1221
1311
  dataTable.insertBefore(tools, dataTable.firstChild);
1222
1312
  }
1313
+ var scrollLocks = 0;
1314
+ var previousRootOverflow = "";
1315
+ function lockPageScroll() {
1316
+ if (scrollLocks === 0) {
1317
+ previousRootOverflow = document.documentElement.style.overflow;
1318
+ document.documentElement.style.overflow = "hidden";
1319
+ }
1320
+ scrollLocks += 1;
1321
+ }
1322
+ function unlockPageScroll() {
1323
+ if (scrollLocks === 0) return;
1324
+ scrollLocks -= 1;
1325
+ if (scrollLocks === 0) {
1326
+ document.documentElement.style.overflow = previousRootOverflow;
1327
+ previousRootOverflow = "";
1328
+ }
1329
+ }
1330
+ function trapFocus(container) {
1331
+ function onKey(event) {
1332
+ if (event.key !== "Tab") return;
1333
+ var candidates = Array.from(
1334
+ container.querySelectorAll(
1335
+ 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
1336
+ )
1337
+ ).filter((node) => node.offsetParent !== null || node === document.activeElement);
1338
+ if (candidates.length === 0) {
1339
+ event.preventDefault();
1340
+ return;
1341
+ }
1342
+ var first = candidates[0];
1343
+ var last = candidates[candidates.length - 1];
1344
+ if (event.shiftKey && document.activeElement === first) {
1345
+ event.preventDefault();
1346
+ last.focus();
1347
+ } else if (!event.shiftKey && document.activeElement === last) {
1348
+ event.preventDefault();
1349
+ first.focus();
1350
+ }
1351
+ }
1352
+ container.addEventListener("keydown", onKey, true);
1353
+ return () => container.removeEventListener("keydown", onKey, true);
1354
+ }
1223
1355
  function openImage(source, alt) {
1224
1356
  if (document.querySelector("." + IMG_MODAL_CLASS) !== null) return;
1225
1357
  var overlay = document.createElement("div");
@@ -1236,12 +1368,15 @@ window.__ModuleLoader__.load({
1236
1368
  closeButton.textContent = "\xD7";
1237
1369
  closeButton.setAttribute("aria-label", t("imageClose"));
1238
1370
  var previousFocus = document.activeElement;
1371
+ var releaseFocus = null;
1239
1372
  var closed = false;
1240
1373
  function closeViewer() {
1241
1374
  if (closed) return;
1242
1375
  closed = true;
1376
+ releaseFocus?.();
1243
1377
  document.removeEventListener("keydown", onKey, true);
1244
1378
  overlay.remove();
1379
+ unlockPageScroll();
1245
1380
  if (previousFocus !== null && typeof previousFocus.focus === "function") previousFocus.focus();
1246
1381
  }
1247
1382
  function onKey(event) {
@@ -1257,7 +1392,9 @@ window.__ModuleLoader__.load({
1257
1392
  document.addEventListener("keydown", onKey, true);
1258
1393
  overlay.appendChild(image);
1259
1394
  overlay.appendChild(closeButton);
1395
+ lockPageScroll();
1260
1396
  document.body.appendChild(overlay);
1397
+ releaseFocus = trapFocus(overlay);
1261
1398
  closeButton.focus();
1262
1399
  }
1263
1400
  function onDocumentClick(event) {
@@ -1300,10 +1437,26 @@ window.__ModuleLoader__.load({
1300
1437
  return input;
1301
1438
  }
1302
1439
  function rescanFolds() {
1303
- for (const node of document.querySelectorAll("[" + FOLD_ATTR + "]")) resetFold(node);
1440
+ diagramKindCache = /* @__PURE__ */ new WeakMap();
1441
+ var codeLimit = foldLimit("code");
1442
+ var tableLimit = foldLimit("table");
1443
+ var diagramLimit = foldLimit("diagram");
1444
+ for (const node of document.querySelectorAll("[" + FOLD_ATTR + "]")) {
1445
+ if (node.classList.contains(MMD_CLASS + "-viewport")) continue;
1446
+ var limit = node.hasAttribute(TABLE_DONE_ATTR) ? tableLimit : codeLimit;
1447
+ if (node.getAttribute(FOLD_ATTR) === "off" && limit > 0) {
1448
+ node.style.setProperty("--md-plus-fold-max-height", limit + "px");
1449
+ continue;
1450
+ }
1451
+ resetFold(node);
1452
+ }
1304
1453
  for (const viewport of document.querySelectorAll("." + MMD_CLASS + "-viewport")) {
1454
+ if (viewport.getAttribute(FOLD_ATTR) === "off" && diagramLimit > 0) {
1455
+ viewport.style.setProperty("--md-plus-fold-max-height", diagramLimit + "px");
1456
+ continue;
1457
+ }
1305
1458
  resetFold(viewport);
1306
- scheduleFold(viewport, foldLimit("diagram"));
1459
+ scheduleFold(viewport, diagramLimit);
1307
1460
  }
1308
1461
  scanFolds();
1309
1462
  }
@@ -1376,12 +1529,15 @@ window.__ModuleLoader__.load({
1376
1529
  panel.appendChild(actions);
1377
1530
  overlay.appendChild(panel);
1378
1531
  var previousFocus = document.activeElement;
1532
+ var releaseFocus = null;
1379
1533
  var closed = false;
1380
1534
  function closeSettings() {
1381
1535
  if (closed) return;
1382
1536
  closed = true;
1537
+ releaseFocus?.();
1383
1538
  document.removeEventListener("keydown", onKey, true);
1384
1539
  overlay.remove();
1540
+ unlockPageScroll();
1385
1541
  if (previousFocus !== null && typeof previousFocus.focus === "function") previousFocus.focus();
1386
1542
  }
1387
1543
  function onKey(event) {
@@ -1408,22 +1564,29 @@ window.__ModuleLoader__.load({
1408
1564
  foldDiagram.value = String(DEFAULT_SETTINGS.foldDiagram);
1409
1565
  });
1410
1566
  saveButton.addEventListener("click", () => {
1411
- saveSettings({
1567
+ var previous = readSettings();
1568
+ var previousTheme = getMermaidTheme();
1569
+ var nextTheme = THEME_ORDER.indexOf(themeSelect.value) === -1 ? "blue" : themeSelect.value;
1570
+ var next = {
1412
1571
  codeFontSize: readFontSize(fontInput),
1413
1572
  diagramView: viewSelect.value === "code" ? "code" : "diagram",
1414
1573
  foldCode: readNumber(foldCode, DEFAULT_SETTINGS.foldCode),
1415
1574
  foldTable: readNumber(foldTable, DEFAULT_SETTINGS.foldTable),
1416
1575
  foldDiagram: readNumber(foldDiagram, DEFAULT_SETTINGS.foldDiagram)
1417
- });
1418
- memoryTheme = themeSelect.value;
1576
+ };
1577
+ saveSettings(next);
1578
+ memoryTheme = nextTheme;
1579
+ themeCache = nextTheme;
1419
1580
  try {
1420
- window.localStorage.setItem(THEME_KEY, themeSelect.value);
1581
+ window.localStorage.setItem(THEME_KEY, nextTheme);
1421
1582
  } catch {
1422
1583
  }
1423
1584
  applyCodeFontSize();
1424
1585
  refreshThemeButtons();
1425
- redrawDiagrams();
1426
- rescanFolds();
1586
+ if (previousTheme !== nextTheme) redrawDiagrams();
1587
+ if (previous.codeFontSize !== next.codeFontSize || previous.foldCode !== next.foldCode || previous.foldTable !== next.foldTable || previous.foldDiagram !== next.foldDiagram) {
1588
+ rescanFolds();
1589
+ }
1427
1590
  closeSettings();
1428
1591
  });
1429
1592
  closeButton.addEventListener("click", closeSettings);
@@ -1431,12 +1594,18 @@ window.__ModuleLoader__.load({
1431
1594
  if (event.target === overlay) closeSettings();
1432
1595
  });
1433
1596
  document.addEventListener("keydown", onKey, true);
1597
+ lockPageScroll();
1434
1598
  document.body.appendChild(overlay);
1599
+ releaseFocus = trapFocus(overlay);
1435
1600
  saveButton.focus();
1436
1601
  }
1437
1602
  function ensureSettingsButton() {
1438
- if (document.querySelector("." + SETTINGS_BTN_CLASS) !== null) return;
1439
- if (document.querySelector('[class*="_markdown_"], .md-code-block') === null) return;
1603
+ var existing = document.querySelector("." + SETTINGS_BTN_CLASS);
1604
+ if (document.querySelector('[class*="_markdown_"], .md-code-block') === null) {
1605
+ existing?.remove();
1606
+ return;
1607
+ }
1608
+ if (existing !== null) return;
1440
1609
  var button = document.createElement("button");
1441
1610
  button.type = "button";
1442
1611
  button.className = SETTINGS_BTN_CLASS;
@@ -1490,16 +1659,23 @@ window.__ModuleLoader__.load({
1490
1659
  link.remove();
1491
1660
  window.setTimeout(() => URL.revokeObjectURL(url), 1e3);
1492
1661
  }
1493
- function downloadSvg(svg) {
1662
+ function exportFailed(button, error) {
1663
+ console.warn("[dsh-md-plus] \u56FE\u8868\u5BFC\u51FA\u5931\u8D25", error);
1664
+ if (button !== void 0) flashButton(button, t("exportFailed"));
1665
+ }
1666
+ function downloadSvg(svg, button) {
1494
1667
  try {
1495
1668
  downloadBlob(new Blob([serializeSvg(svg)], { type: "image/svg+xml;charset=utf-8" }), "mermaid-diagram.svg");
1496
1669
  } catch (error) {
1497
- console.warn("[dsh-md-plus] SVG \u5BFC\u51FA\u5931\u8D25", error);
1670
+ exportFailed(button, error);
1498
1671
  }
1499
1672
  }
1500
- function downloadPng(svg) {
1673
+ function downloadPng(svg, button) {
1501
1674
  var size = svgSize(svg);
1502
- if (size.width <= 0 || size.height <= 0) return;
1675
+ if (size.width <= 0 || size.height <= 0) {
1676
+ exportFailed(button, new Error("\u56FE\u8868\u5C3A\u5BF8\u65E0\u6548"));
1677
+ return;
1678
+ }
1503
1679
  var image = new window.Image();
1504
1680
  var objectUrl = "";
1505
1681
  image.onload = function() {
@@ -1513,16 +1689,17 @@ window.__ModuleLoader__.load({
1513
1689
  context.drawImage(image, 0, 0, canvas.width, canvas.height);
1514
1690
  canvas.toBlob((blob) => {
1515
1691
  if (blob !== null) downloadBlob(blob, "mermaid-diagram.png");
1692
+ else exportFailed(button, new Error("canvas \u672A\u751F\u6210\u56FE\u7247"));
1516
1693
  }, "image/png");
1517
1694
  } catch (error) {
1518
- console.warn("[dsh-md-plus] PNG \u5BFC\u51FA\u5931\u8D25", error);
1695
+ exportFailed(button, error);
1519
1696
  } finally {
1520
1697
  if (objectUrl !== "") URL.revokeObjectURL(objectUrl);
1521
1698
  }
1522
1699
  };
1523
1700
  image.onerror = function() {
1524
1701
  if (objectUrl !== "") URL.revokeObjectURL(objectUrl);
1525
- console.warn("[dsh-md-plus] PNG \u5BFC\u51FA\u5931\u8D25\uFF1ASVG \u65E0\u6CD5\u8F7D\u5165");
1702
+ exportFailed(button, new Error("SVG \u65E0\u6CD5\u8F7D\u5165"));
1526
1703
  };
1527
1704
  objectUrl = URL.createObjectURL(new Blob([serializeSvg(svg)], { type: "image/svg+xml;charset=utf-8" }));
1528
1705
  image.src = objectUrl;
@@ -1595,15 +1772,16 @@ window.__ModuleLoader__.load({
1595
1772
  panel.appendChild(body);
1596
1773
  overlay.appendChild(panel);
1597
1774
  var previousFocus = document.activeElement;
1598
- var previousOverflow = document.documentElement.style.overflow;
1775
+ var releaseFocus = null;
1599
1776
  var closed = false;
1600
1777
  var reset = () => fitToView(overlay);
1601
1778
  function closeViewer() {
1602
1779
  if (closed) return;
1603
1780
  closed = true;
1781
+ releaseFocus?.();
1604
1782
  document.removeEventListener("keydown", onKey, true);
1605
1783
  overlay.remove();
1606
- document.documentElement.style.overflow = previousOverflow;
1784
+ unlockPageScroll();
1607
1785
  zooms.delete(overlay);
1608
1786
  if (previousFocus !== null && typeof previousFocus.focus === "function") {
1609
1787
  previousFocus.focus();
@@ -1619,16 +1797,17 @@ window.__ModuleLoader__.load({
1619
1797
  if (event.target === overlay) closeViewer();
1620
1798
  });
1621
1799
  fitButton.addEventListener("click", reset);
1622
- svgButton.addEventListener("click", () => downloadSvg(svg));
1623
- pngButton.addEventListener("click", () => downloadPng(svg));
1800
+ svgButton.addEventListener("click", () => downloadSvg(svg, svgButton));
1801
+ pngButton.addEventListener("click", () => downloadPng(svg, pngButton));
1624
1802
  zoomOut.addEventListener("click", () => zoomBy(overlay, 1 / ZOOM_STEP));
1625
1803
  zoomIn.addEventListener("click", () => zoomBy(overlay, ZOOM_STEP));
1626
1804
  closeButton.addEventListener("click", closeViewer);
1627
1805
  document.addEventListener("keydown", onKey, true);
1628
1806
  zooms.set(overlay, { scale: 1, x: 0, y: 0, min: ZOOM_MIN_MODAL });
1629
1807
  bindViewport(overlay, viewport, reset, true);
1630
- document.documentElement.style.overflow = "hidden";
1808
+ lockPageScroll();
1631
1809
  document.body.appendChild(overlay);
1810
+ releaseFocus = trapFocus(overlay);
1632
1811
  closeButton.focus();
1633
1812
  var schedule2 = window.requestAnimationFrame ?? ((cb) => window.setTimeout(cb, 0));
1634
1813
  schedule2(reset);
@@ -1640,7 +1819,7 @@ window.__ModuleLoader__.load({
1640
1819
  var reason = (error?.message ?? String(error)).split("\n")[0] ?? "";
1641
1820
  note.textContent = t("renderFailed") + reason;
1642
1821
  content.appendChild(note);
1643
- block.setAttribute(KEY_ATTR, key);
1822
+ cacheKeys.set(block, key);
1644
1823
  block.setAttribute(MMD_ATTR, "failed");
1645
1824
  decorate(block);
1646
1825
  console.warn("[dsh-md-plus] mermaid \u6E32\u67D3\u5931\u8D25", error);
@@ -1649,6 +1828,8 @@ window.__ModuleLoader__.load({
1649
1828
  if (typeof document === "undefined") return;
1650
1829
  ctx.effect(() => {
1651
1830
  disposed = false;
1831
+ settingsCache = null;
1832
+ themeCache = null;
1652
1833
  injectStyle();
1653
1834
  applyCodeFontSize();
1654
1835
  ensureSettingsButton();
@@ -1671,6 +1852,7 @@ window.__ModuleLoader__.load({
1671
1852
  }
1672
1853
  pending.clear();
1673
1854
  rescanQueued = false;
1855
+ for (const target of [...foldTargets]) resetFold(target);
1674
1856
  observer.disconnect();
1675
1857
  document.removeEventListener("click", onDocumentClick, true);
1676
1858
  for (const node of injected) node.remove();
@@ -1680,7 +1862,7 @@ window.__ModuleLoader__.load({
1680
1862
  for (const node of document.querySelectorAll("." + FOLD_BTN_CLASS)) node.remove();
1681
1863
  for (const node of document.querySelectorAll("[" + FOLD_ATTR + "]")) resetFold(node);
1682
1864
  for (const node of document.querySelectorAll("." + TABLE_TOOLS_CLASS)) node.remove();
1683
- for (const attr of [DONE_ATTR, KEY_ATTR, WRAP_ATTR, MMD_ATTR, TABLE_DONE_ATTR, "data-md-plus-lang", ZOOM_ATTR]) {
1865
+ for (const attr of [DONE_ATTR, WRAP_ATTR, MMD_ATTR, TABLE_DONE_ATTR, "data-md-plus-lang", ZOOM_ATTR]) {
1684
1866
  for (const node of document.querySelectorAll("[" + attr + "]")) node.removeAttribute(attr);
1685
1867
  }
1686
1868
  for (const node of document.querySelectorAll("[data-md-plus-original-label]")) {
@@ -1692,7 +1874,9 @@ window.__ModuleLoader__.load({
1692
1874
  )) {
1693
1875
  node.remove();
1694
1876
  }
1695
- document.documentElement.style.overflow = "";
1877
+ scrollLocks = 0;
1878
+ document.documentElement.style.overflow = previousRootOverflow;
1879
+ previousRootOverflow = "";
1696
1880
  document.documentElement.style.removeProperty("--md-plus-code-font-size");
1697
1881
  document.documentElement.style.removeProperty("--md-plus-code-line-height");
1698
1882
  document.querySelector("style[" + STYLE_ATTR + "]")?.remove();
@@ -1700,6 +1884,10 @@ window.__ModuleLoader__.load({
1700
1884
  script.remove();
1701
1885
  }
1702
1886
  scripts.clear();
1887
+ settingsCache = null;
1888
+ themeCache = null;
1889
+ diagramKindCache = /* @__PURE__ */ new WeakMap();
1890
+ cacheKeys = /* @__PURE__ */ new WeakMap();
1703
1891
  delete window[HL_GLOBAL];
1704
1892
  delete window[MMD_GLOBAL];
1705
1893
  };
@@ -4290,4 +4290,4 @@ ${i?"":`
4290
4290
  `}else s+=`${t.themeCSS}
4291
4291
  `;return s+Hme(i)},"createCssStyles"),H0i=_((t,r)=>cxe(qEr(`${t}{${r}}`),YEr([_(function(s,o,u,h){if(s.type==="rule"&&Array.isArray(s.props)){if(s.parent&&s.parent.type===kre)return;s.props=s.props.map(d=>d===t&&Array.isArray(s.children)&&s.children.every(y=>y.type!=="decl"?!1:new Set(["font-family","font-size","fill"]).has(y.props))||(d.startsWith(`${t} `)||d.startsWith(`${t}>`))&&!d.startsWith(`${t} ||`)?d:`${t} ${d}`)}else s.type.startsWith("@")&&([...[REr,IEr,txe,OEr,"@container","@starting-style"],kre].includes(s.type)||(We.warn(`Removing unsupported at-rule ${s.type} from CSS`),s.type=cU))},"addNamespace"),WEr])),"compileCSS"),q0i=_((t,r,i,s)=>{let o=V0i(t,i),u=Eir(r,o,{...t.themeVariables,theme:t.theme,look:t.look},s);return H0i(s,u)},"createUserStyles"),W0i=_((t="",r,i)=>{let s=t;return!i&&!r&&(s=s.replace(/marker-end="url\([\d+./:=?A-Za-z-]*?#/g,'marker-end="url(#')),s=Z3(s),s=s.replace(/<br>/g,"<br/>"),s},"cleanUpSvgCode"),Y0i=_((t="",r)=>{let i=r?.viewBox?.baseVal?.height?r.viewBox.baseVal.height+"px":B0i,s=FGr(`<body style="${$0i}">${t}</body>`);return`<iframe style="width:${P0i};height:${i};${F0i}" src="data:text/html;charset=UTF-8;base64,${s}" sandbox="${z0i}">
4292
4292
  ${j0i}
4293
- </iframe>`},"putIntoIFrame"),Kjr=_((t,r,i,s,o)=>{let u=t.append("div");u.attr("id",i),s&&u.attr("style",s);let h=u.append("svg").attr("id",r).attr("width","100%").attr("xmlns",O0i);return o&&h.attr("xmlns:xlink",o),h.append("g"),t},"appendDivSvgG");function Qct(t,r){return t.append("iframe").attr("id",r).attr("style","width: 100%; height: 100%;").attr("sandbox","")}_(Qct,"sandboxedIframe");var K0i=_((t,r,i,s)=>{t.getElementById(r)?.remove(),t.getElementById(i)?.remove(),t.getElementById(s)?.remove()},"removeExistingElements"),X0i=_(async function(t,r,i){Hke();let s=Zct(r),o=s.code;r=o.cleaned;let u=Di();We.debug(u),r.length>(u?.maxTextSize??R0i)&&(r=L0i,o={raw:r,cleaned:r});let h=`#${t}`,d="i"+t,g="#"+d,y="d"+t,v="#"+y,x=_(()=>{let Q=un(C?g:v).node();Q&&"remove"in Q&&Q.remove()},"removeTempElements"),k=un(document.body),C=u.securityLevel===I0i,E=u.securityLevel===M0i,A=u.fontFamily;if(i!==void 0){if(i&&(i.innerHTML=""),C){let Z=Qct(un(i),d);k=un(Z.nodes()[0].contentDocument.body),k.node().style.margin="0"}else k=un(i);Kjr(k,t,y,`font-family: ${A}`,N0i)}else{if(K0i(document,t,y,d),C){let Z=Qct(un(document.body),d);k=un(Z.nodes()[0].contentDocument.body),k.node().style.margin="0"}else k=un("body");Kjr(k,t,y)}let R,L;try{R=await Uke.fromText(o,{title:s.title})}catch(Z){if(u.suppressErrorRendering)throw x(),Z;R=await Uke.fromText("error"),L=Z,R.db.setErrorMessage?.(iYe(Z))}let O=k.select(v).node(),N=R.type,F=O.firstChild,D=F.firstChild,P=R.renderer.getClasses?.(r,R),z=q0i(u,N,P,h),V=document.createElement("style");V.innerHTML=z,F.insertBefore(V,D);try{await R.renderer.draw(r,t,"12.1.0",R)}catch(Z){throw u.suppressErrorRendering?x():Jdi.draw(r,t,"12.1.0"),Z}let Y=k.select(`${v} svg`),K=R.db.getAccTitle?.(),J=R.db.getAccDescription?.();jGr(N,Y,K,J);let q=_(()=>{k.select(`[id="${t}"]`).selectAll("foreignobject > *").attr("xmlns",D0i);let Z=k.select(v).node().innerHTML;if(We.debug("config.arrowMarkerAbsolute",u.arrowMarkerAbsolute),Z=W0i(Z,C,_w(u.arrowMarkerAbsolute)),C){let Q=k.select(v+" svg").node();Z=Y0i(Z,Q)}else E||(Z=qm.sanitize(Z,{ADD_TAGS:G0i,ADD_ATTR:U0i,HTML_INTEGRATION_POINTS:{foreignobject:!0}}));return C0i(),Z},"serializeSvg")();if(L)throw L;return x(),{diagramType:N,svg:q,bindFunctions:R.db.bindFunctions}},"renderDiagram"),Q0i=_(async function(t,r,i){try{return await X0i(t,r,i)}finally{Vme(void 0)}},"render");function zGr(t={}){let r=Vh({},t);r?.fontFamily&&!r.themeVariables?.fontFamily&&(r.themeVariables||(r.themeVariables={}),r.themeVariables.fontFamily=r.fontFamily),mir(r);let i=B6.theme;r?.theme&&Object.hasOwn(S5,r.theme)?r.themeVariables=S5[r.theme].getThemeVariables(r.themeVariables):r&&(r.theme!=null&&r.theme!=="null"&&(r.theme=i),r.themeVariables=S5[i].getThemeVariables(r.themeVariables));let s=typeof r=="object"?gir(r):zVe();lZ(s.logLevel),Hke()}_(zGr,"initialize");var J0i=_((t,r={})=>{let{code:i}=Jct(t);return Uke.fromText(i,r)},"getDiagramFromText");function jGr(t,r,i,s){NGr(r,t),DGr(r,i,s,r.attr("id"))}_(jGr,"addA11yInfo");var CP=Object.freeze({render:Q0i,parse:$Gr,getDiagramFromText:J0i,initialize:zGr,getConfig:Di,setConfig:jVe,getSiteConfig:zVe,updateSiteConfig:yir,reset:_(()=>{LZ()},"reset"),globalReset:_(()=>{LZ(B6)},"globalReset"),defaultConfig:B6});lZ(Di().logLevel);LZ(Di());var Z0i=_((t,r,i)=>{We.warn(t),Gve(t)?(i&&i(t.str,t.hash),r.push({...t,message:t.str,error:t})):(i&&i(t),t instanceof Error&&r.push({str:t.message,message:t.message,hash:t.name,error:t}))},"handleError"),GGr=_(async function(t={querySelector:".mermaid"}){try{await e1i(t)}catch(r){if(Gve(r)&&We.error(r.str),WA.parseError&&WA.parseError(r),!t.suppressErrors)throw We.error("Use the suppressErrors option to suppress these errors"),r}},"run"),e1i=_(async function({postRenderCallback:t,querySelector:r,nodes:i}={querySelector:".mermaid"}){let s=CP.getConfig();We.debug(`${t?"":"No "}Callback function found`);let o;if(i)o=i;else if(r)o=document.querySelectorAll(r);else throw new Error("Nodes and querySelector are both undefined");We.debug(`Found ${o.length} diagrams`),s?.startOnLoad!==void 0&&(We.debug("Start On Load: "+s?.startOnLoad),CP.updateSiteConfig({startOnLoad:s?.startOnLoad}));let u=new ss.InitIDGenerator(s.deterministicIds,s.deterministicIDSeed),h,d=[];for(let g of Array.from(o)){if(We.info("Rendering diagram: "+g.id),g.getAttribute("data-processed"))continue;g.setAttribute("data-processed","true");let y=`mermaid-${u.next()}`;h=g.innerHTML,h=Kve(ss.entityDecode(h)).trim().replace(/<br\s*\/?>/gi,"<br/>");let v=ss.detectInit(h);v&&We.debug("Detected early reinit: ",v);try{let{svg:x,bindFunctions:k}=await qGr(y,h,g);g.innerHTML=x,t&&await t(y),k&&k(g)}catch(x){Z0i(x,d,WA.parseError)}}if(d.length>0)throw d[0]},"runThrowsErrors"),UGr=_(function(t){CP.initialize(t)},"initialize"),t1i=_(async function(t,r,i){We.warn("mermaid.init is deprecated. Please use run instead."),t&&UGr(t);let s={postRenderCallback:i,querySelector:".mermaid"};typeof r=="string"?s.querySelector=r:r&&(r instanceof HTMLElement?s.nodes=[r]:s.nodes=r),await GGr(s)},"init"),r1i=_(async(t,{lazyLoad:r=!0}={})=>{Hke(),Ume(...t),r===!1&&await T0i()},"registerExternalDiagrams"),VGr=_(function(){if(WA.startOnLoad){let{startOnLoad:t}=CP.getConfig();t&&WA.run().catch(r=>We.error("Mermaid failed to initialize",r))}},"contentLoaded");typeof document<"u"&&window.addEventListener("load",VGr,!1);var n1i=_(function(t){WA.parseError=t},"setParseErrorHandler"),Vke=[],Xct=!1,HGr=_(async()=>{if(!Xct){for(Xct=!0;Vke.length>0;){let t=Vke.shift();if(t)try{await t()}catch(r){We.error("Error executing queue",r)}}Xct=!1}},"executeQueue"),i1i=_(async(t,r)=>new Promise((i,s)=>{let o=_(()=>new Promise((u,h)=>{CP.parse(t,r).then(d=>{u(d),i(d)},d=>{We.error("Error parsing",d),WA.parseError?.(d),h(d),s(d)})}),"performCall");Vke.push(o),HGr().catch(s)}),"parse"),qGr=_((t,r,i)=>new Promise((s,o)=>{let u=_(()=>new Promise((h,d)=>{CP.render(t,r,i).then(g=>{h(g),s(g)},g=>{We.error("Error parsing",g),WA.parseError?.(g),d(g),o(g)})}),"performCall");Vke.push(u),HGr().catch(o)}),"render"),a1i=_(()=>Object.keys(iR).map(t=>({id:t})),"getRegisteredDiagramsMetadata"),WA={startOnLoad:!0,mermaidAPI:CP,parse:i1i,render:qGr,init:t1i,run:GGr,registerExternalDiagrams:r1i,registerLayoutLoaders:Ket,initialize:UGr,parseError:void 0,contentLoaded:VGr,setParseErrorHandler:n1i,detectType:cj,registerIconPacks:jj,getRegisteredDiagramsMetadata:a1i},qke=WA;var WGr={fontSize:"16px",flowchart:{curve:"basis",nodeSpacing:40,rankSpacing:41,padding:18,useMaxWidth:!0}},s1i={background:"transparent",primaryColor:"#e5f2ff",primaryTextColor:"#339cff",primaryBorderColor:"#e5f2ff",secondaryColor:"#e5f2ff",tertiaryColor:"#e5f2ff",lineColor:"#339cff",edgeLabelBackground:"#ffffff",clusterBkg:"#f2f8ff",clusterBorder:"#cde7ff",titleColor:"#339cff",nodeTextColor:"#339cff"},o1i={background:"transparent",primaryColor:"#16283d",primaryTextColor:"#79bdff",primaryBorderColor:"#16283d",secondaryColor:"#16283d",tertiaryColor:"#16283d",lineColor:"#5aa9f0",edgeLabelBackground:"#0f1115",clusterBkg:"#132133",clusterBorder:"#2b4a6b",titleColor:"#79bdff",nodeTextColor:"#79bdff"},l1i={background:"transparent",primaryColor:"#f2f2f2",primaryTextColor:"#222222",primaryBorderColor:"#c9c9c9",secondaryColor:"#f2f2f2",tertiaryColor:"#f2f2f2",lineColor:"#666666",edgeLabelBackground:"#ffffff",clusterBkg:"#fafafa",clusterBorder:"#dddddd",titleColor:"#222222",nodeTextColor:"#222222"},c1i={background:"transparent",primaryColor:"#2a2a2a",primaryTextColor:"#eeeeee",primaryBorderColor:"#555555",secondaryColor:"#2a2a2a",tertiaryColor:"#2a2a2a",lineColor:"#aaaaaa",edgeLabelBackground:"#111111",clusterBkg:"#1f1f1f",clusterBorder:"#3a3a3a",titleColor:"#eeeeee",nodeTextColor:"#eeeeee"},u1i={background:"transparent",primaryColor:"#e8f5e9",primaryTextColor:"#1b5e20",primaryBorderColor:"#a5d6a7",secondaryColor:"#e8f5e9",tertiaryColor:"#e8f5e9",lineColor:"#43a047",edgeLabelBackground:"#ffffff",clusterBkg:"#f1f8e9",clusterBorder:"#c8e6c9",titleColor:"#1b5e20",nodeTextColor:"#1b5e20"},h1i={background:"transparent",primaryColor:"#1b3320",primaryTextColor:"#a5d6a7",primaryBorderColor:"#2e7d32",secondaryColor:"#1b3320",tertiaryColor:"#1b3320",lineColor:"#66bb6a",edgeLabelBackground:"#0f1115",clusterBkg:"#142418",clusterBorder:"#2e4a34",titleColor:"#a5d6a7",nodeTextColor:"#a5d6a7"},f1i={background:"transparent",primaryColor:"#ffffff",primaryTextColor:"#000000",primaryBorderColor:"#000000",secondaryColor:"#ffffff",tertiaryColor:"#ffffff",lineColor:"#000000",edgeLabelBackground:"#ffffff",clusterBkg:"#ffffff",clusterBorder:"#000000",titleColor:"#000000",nodeTextColor:"#000000"},d1i={background:"transparent",primaryColor:"#0b0b0b",primaryTextColor:"#ffffff",primaryBorderColor:"#ffffff",secondaryColor:"#0b0b0b",tertiaryColor:"#0b0b0b",lineColor:"#ffffff",edgeLabelBackground:"#0b0b0b",clusterBkg:"#0b0b0b",clusterBorder:"#ffffff",titleColor:"#ffffff",nodeTextColor:"#ffffff"},eut={blue:{light:s1i,dark:o1i},neutral:{light:l1i,dark:c1i},forest:{light:u1i,dark:h1i},contrast:{light:f1i,dark:d1i}},G9a=Object.keys(eut);function YGr(t,r,i="blue"){let s=eut[i]??eut.blue,o=t?s.dark:s.light;return{startOnLoad:!1,securityLevel:"strict",theme:"base",fontFamily:r,themeVariables:{...o,...WGr},flowchart:WGr.flowchart,themeCSS:[".nodeLabel,.edgeLabel,.label{font-weight:600}",".flowchart-link{stroke-width:1.6px}",`.marker,.arrowheadPath{fill:${o.lineColor};stroke:${o.lineColor}}`].join("")}}var tut=11;var KGr=null,XGr=Promise.resolve();function p1i(t){let r=XGr.then(t,t);return XGr=r.then(()=>{},()=>{}),r}function g1i(t,r){let i=(t?"dark":"light")+":"+r;if(KGr===i)return;KGr=i;let s=getComputedStyle(document.body).fontFamily||"system-ui, sans-serif";qke.initialize(YGr(t,s,r))}function m1i(t){for(let r of t.querySelectorAll(".node rect"))r.setAttribute("rx",String(tut)),r.setAttribute("ry",String(tut))}function y1i(t){return t.includes('aria-roledescription="error"')||t.includes("Syntax error in text")}function v1i(t){let r=typeof CSS<"u"&&CSS.escape!==void 0?CSS.escape(t):t;for(let i of document.querySelectorAll(`#d${r}, #d${r} svg`))i.remove()}window.__DSH_MD_PLUS_MMD__={render(t,r,i,s){return p1i(async()=>{g1i(i===!0,s??"blue");let o=null;qke.parseError=u=>{o??=u};try{let{svg:u}=await qke.render(t,r);if(o!==null)throw o;if(y1i(u))throw new Error("mermaid \u8FD4\u56DE\u7684\u662F\u9519\u8BEF\u5361\u7247\uFF08\u8BED\u6CD5\u65E0\u6CD5\u89E3\u6790\uFF09");let h=document.createElement("div");return h.innerHTML=u,m1i(h),await new Promise(d=>setTimeout(d,0)),h.innerHTML}finally{v1i(t)}})}};})();
4293
+ </iframe>`},"putIntoIFrame"),Kjr=_((t,r,i,s,o)=>{let u=t.append("div");u.attr("id",i),s&&u.attr("style",s);let h=u.append("svg").attr("id",r).attr("width","100%").attr("xmlns",O0i);return o&&h.attr("xmlns:xlink",o),h.append("g"),t},"appendDivSvgG");function Qct(t,r){return t.append("iframe").attr("id",r).attr("style","width: 100%; height: 100%;").attr("sandbox","")}_(Qct,"sandboxedIframe");var K0i=_((t,r,i,s)=>{t.getElementById(r)?.remove(),t.getElementById(i)?.remove(),t.getElementById(s)?.remove()},"removeExistingElements"),X0i=_(async function(t,r,i){Hke();let s=Zct(r),o=s.code;r=o.cleaned;let u=Di();We.debug(u),r.length>(u?.maxTextSize??R0i)&&(r=L0i,o={raw:r,cleaned:r});let h=`#${t}`,d="i"+t,g="#"+d,y="d"+t,v="#"+y,x=_(()=>{let Q=un(C?g:v).node();Q&&"remove"in Q&&Q.remove()},"removeTempElements"),k=un(document.body),C=u.securityLevel===I0i,E=u.securityLevel===M0i,A=u.fontFamily;if(i!==void 0){if(i&&(i.innerHTML=""),C){let Z=Qct(un(i),d);k=un(Z.nodes()[0].contentDocument.body),k.node().style.margin="0"}else k=un(i);Kjr(k,t,y,`font-family: ${A}`,N0i)}else{if(K0i(document,t,y,d),C){let Z=Qct(un(document.body),d);k=un(Z.nodes()[0].contentDocument.body),k.node().style.margin="0"}else k=un("body");Kjr(k,t,y)}let R,L;try{R=await Uke.fromText(o,{title:s.title})}catch(Z){if(u.suppressErrorRendering)throw x(),Z;R=await Uke.fromText("error"),L=Z,R.db.setErrorMessage?.(iYe(Z))}let O=k.select(v).node(),N=R.type,F=O.firstChild,D=F.firstChild,P=R.renderer.getClasses?.(r,R),z=q0i(u,N,P,h),V=document.createElement("style");V.innerHTML=z,F.insertBefore(V,D);try{await R.renderer.draw(r,t,"12.1.0",R)}catch(Z){throw u.suppressErrorRendering?x():Jdi.draw(r,t,"12.1.0"),Z}let Y=k.select(`${v} svg`),K=R.db.getAccTitle?.(),J=R.db.getAccDescription?.();jGr(N,Y,K,J);let q=_(()=>{k.select(`[id="${t}"]`).selectAll("foreignobject > *").attr("xmlns",D0i);let Z=k.select(v).node().innerHTML;if(We.debug("config.arrowMarkerAbsolute",u.arrowMarkerAbsolute),Z=W0i(Z,C,_w(u.arrowMarkerAbsolute)),C){let Q=k.select(v+" svg").node();Z=Y0i(Z,Q)}else E||(Z=qm.sanitize(Z,{ADD_TAGS:G0i,ADD_ATTR:U0i,HTML_INTEGRATION_POINTS:{foreignobject:!0}}));return C0i(),Z},"serializeSvg")();if(L)throw L;return x(),{diagramType:N,svg:q,bindFunctions:R.db.bindFunctions}},"renderDiagram"),Q0i=_(async function(t,r,i){try{return await X0i(t,r,i)}finally{Vme(void 0)}},"render");function zGr(t={}){let r=Vh({},t);r?.fontFamily&&!r.themeVariables?.fontFamily&&(r.themeVariables||(r.themeVariables={}),r.themeVariables.fontFamily=r.fontFamily),mir(r);let i=B6.theme;r?.theme&&Object.hasOwn(S5,r.theme)?r.themeVariables=S5[r.theme].getThemeVariables(r.themeVariables):r&&(r.theme!=null&&r.theme!=="null"&&(r.theme=i),r.themeVariables=S5[i].getThemeVariables(r.themeVariables));let s=typeof r=="object"?gir(r):zVe();lZ(s.logLevel),Hke()}_(zGr,"initialize");var J0i=_((t,r={})=>{let{code:i}=Jct(t);return Uke.fromText(i,r)},"getDiagramFromText");function jGr(t,r,i,s){NGr(r,t),DGr(r,i,s,r.attr("id"))}_(jGr,"addA11yInfo");var CP=Object.freeze({render:Q0i,parse:$Gr,getDiagramFromText:J0i,initialize:zGr,getConfig:Di,setConfig:jVe,getSiteConfig:zVe,updateSiteConfig:yir,reset:_(()=>{LZ()},"reset"),globalReset:_(()=>{LZ(B6)},"globalReset"),defaultConfig:B6});lZ(Di().logLevel);LZ(Di());var Z0i=_((t,r,i)=>{We.warn(t),Gve(t)?(i&&i(t.str,t.hash),r.push({...t,message:t.str,error:t})):(i&&i(t),t instanceof Error&&r.push({str:t.message,message:t.message,hash:t.name,error:t}))},"handleError"),GGr=_(async function(t={querySelector:".mermaid"}){try{await e1i(t)}catch(r){if(Gve(r)&&We.error(r.str),WA.parseError&&WA.parseError(r),!t.suppressErrors)throw We.error("Use the suppressErrors option to suppress these errors"),r}},"run"),e1i=_(async function({postRenderCallback:t,querySelector:r,nodes:i}={querySelector:".mermaid"}){let s=CP.getConfig();We.debug(`${t?"":"No "}Callback function found`);let o;if(i)o=i;else if(r)o=document.querySelectorAll(r);else throw new Error("Nodes and querySelector are both undefined");We.debug(`Found ${o.length} diagrams`),s?.startOnLoad!==void 0&&(We.debug("Start On Load: "+s?.startOnLoad),CP.updateSiteConfig({startOnLoad:s?.startOnLoad}));let u=new ss.InitIDGenerator(s.deterministicIds,s.deterministicIDSeed),h,d=[];for(let g of Array.from(o)){if(We.info("Rendering diagram: "+g.id),g.getAttribute("data-processed"))continue;g.setAttribute("data-processed","true");let y=`mermaid-${u.next()}`;h=g.innerHTML,h=Kve(ss.entityDecode(h)).trim().replace(/<br\s*\/?>/gi,"<br/>");let v=ss.detectInit(h);v&&We.debug("Detected early reinit: ",v);try{let{svg:x,bindFunctions:k}=await qGr(y,h,g);g.innerHTML=x,t&&await t(y),k&&k(g)}catch(x){Z0i(x,d,WA.parseError)}}if(d.length>0)throw d[0]},"runThrowsErrors"),UGr=_(function(t){CP.initialize(t)},"initialize"),t1i=_(async function(t,r,i){We.warn("mermaid.init is deprecated. Please use run instead."),t&&UGr(t);let s={postRenderCallback:i,querySelector:".mermaid"};typeof r=="string"?s.querySelector=r:r&&(r instanceof HTMLElement?s.nodes=[r]:s.nodes=r),await GGr(s)},"init"),r1i=_(async(t,{lazyLoad:r=!0}={})=>{Hke(),Ume(...t),r===!1&&await T0i()},"registerExternalDiagrams"),VGr=_(function(){if(WA.startOnLoad){let{startOnLoad:t}=CP.getConfig();t&&WA.run().catch(r=>We.error("Mermaid failed to initialize",r))}},"contentLoaded");typeof document<"u"&&window.addEventListener("load",VGr,!1);var n1i=_(function(t){WA.parseError=t},"setParseErrorHandler"),Vke=[],Xct=!1,HGr=_(async()=>{if(!Xct){for(Xct=!0;Vke.length>0;){let t=Vke.shift();if(t)try{await t()}catch(r){We.error("Error executing queue",r)}}Xct=!1}},"executeQueue"),i1i=_(async(t,r)=>new Promise((i,s)=>{let o=_(()=>new Promise((u,h)=>{CP.parse(t,r).then(d=>{u(d),i(d)},d=>{We.error("Error parsing",d),WA.parseError?.(d),h(d),s(d)})}),"performCall");Vke.push(o),HGr().catch(s)}),"parse"),qGr=_((t,r,i)=>new Promise((s,o)=>{let u=_(()=>new Promise((h,d)=>{CP.render(t,r,i).then(g=>{h(g),s(g)},g=>{We.error("Error parsing",g),WA.parseError?.(g),d(g),o(g)})}),"performCall");Vke.push(u),HGr().catch(o)}),"render"),a1i=_(()=>Object.keys(iR).map(t=>({id:t})),"getRegisteredDiagramsMetadata"),WA={startOnLoad:!0,mermaidAPI:CP,parse:i1i,render:qGr,init:t1i,run:GGr,registerExternalDiagrams:r1i,registerLayoutLoaders:Ket,initialize:UGr,parseError:void 0,contentLoaded:VGr,setParseErrorHandler:n1i,detectType:cj,registerIconPacks:jj,getRegisteredDiagramsMetadata:a1i},qke=WA;var WGr={fontSize:"16px",flowchart:{curve:"basis",nodeSpacing:40,rankSpacing:41,padding:18,useMaxWidth:!0}},s1i={background:"transparent",primaryColor:"#e5f2ff",primaryTextColor:"#339cff",primaryBorderColor:"#e5f2ff",secondaryColor:"#e5f2ff",tertiaryColor:"#e5f2ff",lineColor:"#339cff",edgeLabelBackground:"#ffffff",clusterBkg:"#f2f8ff",clusterBorder:"#cde7ff",titleColor:"#339cff",nodeTextColor:"#339cff"},o1i={background:"transparent",primaryColor:"#16283d",primaryTextColor:"#79bdff",primaryBorderColor:"#16283d",secondaryColor:"#16283d",tertiaryColor:"#16283d",lineColor:"#5aa9f0",edgeLabelBackground:"#0f1115",clusterBkg:"#132133",clusterBorder:"#2b4a6b",titleColor:"#79bdff",nodeTextColor:"#79bdff"},l1i={background:"transparent",primaryColor:"#f2f2f2",primaryTextColor:"#222222",primaryBorderColor:"#c9c9c9",secondaryColor:"#f2f2f2",tertiaryColor:"#f2f2f2",lineColor:"#666666",edgeLabelBackground:"#ffffff",clusterBkg:"#fafafa",clusterBorder:"#dddddd",titleColor:"#222222",nodeTextColor:"#222222"},c1i={background:"transparent",primaryColor:"#2a2a2a",primaryTextColor:"#eeeeee",primaryBorderColor:"#555555",secondaryColor:"#2a2a2a",tertiaryColor:"#2a2a2a",lineColor:"#aaaaaa",edgeLabelBackground:"#111111",clusterBkg:"#1f1f1f",clusterBorder:"#3a3a3a",titleColor:"#eeeeee",nodeTextColor:"#eeeeee"},u1i={background:"transparent",primaryColor:"#e8f5e9",primaryTextColor:"#1b5e20",primaryBorderColor:"#a5d6a7",secondaryColor:"#e8f5e9",tertiaryColor:"#e8f5e9",lineColor:"#43a047",edgeLabelBackground:"#ffffff",clusterBkg:"#f1f8e9",clusterBorder:"#c8e6c9",titleColor:"#1b5e20",nodeTextColor:"#1b5e20"},h1i={background:"transparent",primaryColor:"#1b3320",primaryTextColor:"#a5d6a7",primaryBorderColor:"#2e7d32",secondaryColor:"#1b3320",tertiaryColor:"#1b3320",lineColor:"#66bb6a",edgeLabelBackground:"#0f1115",clusterBkg:"#142418",clusterBorder:"#2e4a34",titleColor:"#a5d6a7",nodeTextColor:"#a5d6a7"},f1i={background:"transparent",primaryColor:"#ffffff",primaryTextColor:"#000000",primaryBorderColor:"#000000",secondaryColor:"#ffffff",tertiaryColor:"#ffffff",lineColor:"#000000",edgeLabelBackground:"#ffffff",clusterBkg:"#ffffff",clusterBorder:"#000000",titleColor:"#000000",nodeTextColor:"#000000"},d1i={background:"transparent",primaryColor:"#0b0b0b",primaryTextColor:"#ffffff",primaryBorderColor:"#ffffff",secondaryColor:"#0b0b0b",tertiaryColor:"#0b0b0b",lineColor:"#ffffff",edgeLabelBackground:"#0b0b0b",clusterBkg:"#0b0b0b",clusterBorder:"#ffffff",titleColor:"#ffffff",nodeTextColor:"#ffffff"},eut={blue:{light:s1i,dark:o1i},neutral:{light:l1i,dark:c1i},forest:{light:u1i,dark:h1i},contrast:{light:f1i,dark:d1i}},G9a=Object.keys(eut);function YGr(t,r,i="blue"){let s=eut[i]??eut.blue,o=t?s.dark:s.light;return{startOnLoad:!1,securityLevel:"strict",htmlLabels:!1,theme:"base",fontFamily:r,themeVariables:{...o,...WGr},flowchart:WGr.flowchart,themeCSS:[".nodeLabel,.edgeLabel,.label{font-weight:600}",".flowchart-link{stroke-width:1.6px}",`.marker,.arrowheadPath{fill:${o.lineColor};stroke:${o.lineColor}}`].join("")}}var tut=11;var KGr=null,XGr=Promise.resolve();function p1i(t){let r=XGr.then(t,t);return XGr=r.then(()=>{},()=>{}),r}function g1i(t,r){let i=(t?"dark":"light")+":"+r;if(KGr===i)return;KGr=i;let s=getComputedStyle(document.body).fontFamily||"system-ui, sans-serif";qke.initialize(YGr(t,s,r))}function m1i(t){for(let r of t.querySelectorAll(".node rect"))r.setAttribute("rx",String(tut)),r.setAttribute("ry",String(tut))}function y1i(t){return t.includes('aria-roledescription="error"')||t.includes('class="error-text"')}function v1i(t){let r=typeof CSS<"u"&&CSS.escape!==void 0?CSS.escape(t):t;for(let i of document.querySelectorAll(`#d${r}, #d${r} svg`))i.remove()}window.__DSH_MD_PLUS_MMD__={render(t,r,i,s){return p1i(async()=>{g1i(i===!0,s??"blue");let o=null;qke.parseError=u=>{o??=u};try{let{svg:u}=await qke.render(t,r);if(o!==null)throw o;if(y1i(u))throw new Error("mermaid \u8FD4\u56DE\u7684\u662F\u9519\u8BEF\u5361\u7247\uFF08\u8BED\u6CD5\u65E0\u6CD5\u89E3\u6790\uFF09");let h=document.createElement("div");return h.innerHTML=u,m1i(h),await new Promise(d=>setTimeout(d,0)),h.innerHTML}finally{v1i(t)}})}};})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-md-plus",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Markdown display enhancements for DeepSeek Harness Web: code block restyle, syntax highlighting for languages DSH does not ship, and built-in mermaid diagrams.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -21,8 +21,12 @@
21
21
  "prepare": "node scripts/build.mjs",
22
22
  "preview": "node scripts/build.mjs && node scripts/preview.mjs && node scripts/shot.mjs",
23
23
  "shot": "node scripts/shot.mjs",
24
+ "smoke": "npm run build && node scripts/smoke.mjs",
24
25
  "test": "node --test test/host.test.mjs test/client.test.mjs",
25
- "check": "node --check src/index.js && node --check src/client.js && node --check src/highlight-runtime.js && node --check src/mermaid-runtime.js && node --check src/mermaid-theme.js && node --check scripts/build.mjs && npm test"
26
+ "check": "npm run build && node --check src/index.js && node --check src/client.js && node --check src/highlight-runtime.js && node --check src/mermaid-runtime.js && node --check src/mermaid-theme.js && node --check scripts/build.mjs && node --check scripts/smoke.mjs && npm test",
27
+ "release": "node scripts/release.mjs",
28
+ "release:dry": "node scripts/release.mjs --dry-run",
29
+ "release:yes": "node scripts/release.mjs --yes"
26
30
  },
27
31
  "dsh": {
28
32
  "bundle": {
@@ -34,6 +38,7 @@
34
38
  }
35
39
  },
36
40
  "devDependencies": {
41
+ "@shikijs/langs": "4.4.3",
37
42
  "esbuild": "0.28.2",
38
43
  "happy-dom": "^20.14.5",
39
44
  "mermaid": "^12.1.0",
@@ -62,6 +67,7 @@
62
67
  "url": "https://github.com/JosephHy/dsh-md-plus/issues"
63
68
  },
64
69
  "publishConfig": {
65
- "access": "public"
70
+ "access": "public",
71
+ "registry": "https://registry.npmjs.org/"
66
72
  }
67
73
  }