@jvs-milkdown/crepe 1.2.25 → 1.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/lib/cjs/feature/block-edit/index.js +3 -3
  2. package/lib/cjs/feature/block-edit/index.js.map +1 -1
  3. package/lib/cjs/feature/toolbar/index.js +1 -1
  4. package/lib/cjs/feature/toolbar/index.js.map +1 -1
  5. package/lib/cjs/index.js +420 -6
  6. package/lib/cjs/index.js.map +1 -1
  7. package/lib/esm/feature/block-edit/index.js +3 -3
  8. package/lib/esm/feature/block-edit/index.js.map +1 -1
  9. package/lib/esm/feature/toolbar/index.js +1 -1
  10. package/lib/esm/feature/toolbar/index.js.map +1 -1
  11. package/lib/esm/index.js +421 -7
  12. package/lib/esm/index.js.map +1 -1
  13. package/lib/theme/common/block-edit.css +5 -3
  14. package/lib/theme/common/code-mirror.css +19 -0
  15. package/lib/theme/common/link-tooltip.css +2 -2
  16. package/lib/theme/common/toolbar.css +1 -1
  17. package/lib/tsconfig.tsbuildinfo +1 -1
  18. package/lib/types/default-config/index.d.ts.map +1 -1
  19. package/lib/types/feature/block-edit/handle/index.d.ts.map +1 -1
  20. package/lib/types/feature/block-edit/menu/component.d.ts.map +1 -1
  21. package/lib/types/feature/fixed-toolbar/config.d.ts.map +1 -1
  22. package/lib/types/feature/fixed-toolbar/index.d.ts +2 -0
  23. package/lib/types/feature/fixed-toolbar/index.d.ts.map +1 -1
  24. package/package.json +4 -4
  25. package/src/default-config/default-config.spec.ts +15 -0
  26. package/src/default-config/index.ts +17 -1
  27. package/src/feature/block-edit/handle/index.ts +8 -2
  28. package/src/feature/block-edit/menu/component.tsx +4 -1
  29. package/src/feature/fixed-toolbar/config.ts +482 -3
  30. package/src/feature/fixed-toolbar/index.ts +2 -0
  31. package/src/theme/common/block-edit.css +5 -3
  32. package/src/theme/common/code-mirror.css +19 -0
  33. package/src/theme/common/link-tooltip.css +2 -2
  34. package/src/theme/common/toolbar.css +1 -1
package/lib/esm/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { replaceAll, $prose as $prose$1, getHTML } from '@jvs-milkdown/utils';
2
2
  import { defaultsDeep } from 'lodash-es';
3
+ import { LanguageDescription } from '@codemirror/language';
3
4
  import { languages } from '@codemirror/language-data';
4
5
  import { oneDark } from '@codemirror/theme-one-dark';
5
6
  import { createSlice } from '@jvs-milkdown/kit/ctx';
@@ -7,7 +8,7 @@ import { $ctx, $nodeSchema, $view, $remark, $markAttr, $markSchema, $command, $p
7
8
  import { defineComponent, shallowRef, ref, computed, h, createApp, watchEffect, watch, onUnmounted, Fragment, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue';
8
9
  import { Icon } from '@jvs-milkdown/kit/component';
9
10
  import { blockConfig, block, BlockProvider } from '@jvs-milkdown/kit/plugin/block';
10
- import { commandsCtx, editorViewCtx, schemaCtx, editorCtx, EditorStatus, parserCtx, editorViewOptionsCtx, Editor, rootCtx, defaultValueCtx } from '@jvs-milkdown/kit/core';
11
+ import { commandsCtx, editorViewCtx, schemaCtx, editorCtx, EditorStatus, rootCtx, parserCtx, editorViewOptionsCtx, Editor, defaultValueCtx } from '@jvs-milkdown/kit/core';
11
12
  import { findNodeInSelection, findParent, nodeRule } from '@jvs-milkdown/kit/prose';
12
13
  import { NodeSelection, TextSelection, Plugin, PluginKey, EditorState, AllSelection } from '@jvs-milkdown/kit/prose/state';
13
14
  import { computePosition, flip, shift, offset } from '@floating-ui/dom';
@@ -675,10 +676,21 @@ const importIcon = `
675
676
  </svg>
676
677
  `;
677
678
 
679
+ const mermaidLanguage = LanguageDescription.of({
680
+ name: "Mermaid",
681
+ alias: ["mermaid"],
682
+ load: () => {
683
+ const fallback = languages.find((l) => l.name === "YAML") || languages.find((l) => l.name === "Markdown");
684
+ return fallback ? fallback.load() : Promise.resolve(null);
685
+ }
686
+ });
687
+ const allLanguages = [mermaidLanguage, ...languages].sort(
688
+ (a, b) => a.name.localeCompare(b.name)
689
+ );
678
690
  const defaultConfig = {
679
691
  [CrepeFeature.CodeMirror]: {
680
692
  theme: oneDark,
681
- languages,
693
+ languages: allLanguages,
682
694
  expandIcon: chevronDownIcon,
683
695
  searchIcon,
684
696
  clearSearchIcon: clearIcon,
@@ -3064,7 +3076,7 @@ const Menu = defineComponent({
3064
3076
  const isTableBlock = (node == null ? void 0 : node.type.name) === "table";
3065
3077
  const isMedia = ((_a = node == null ? void 0 : node.type.name) == null ? void 0 : _a.includes("image")) || isAttachmentBlock || isImageParagraph || (node == null ? void 0 : node.type.name) === "hr" || isTableBlock;
3066
3078
  const showAlign = !isMedia || isImageBlock;
3067
- const isEmpty = node ? node.textContent.length === 0 && node.content.size <= 2 && !isMedia : false;
3079
+ const isEmpty = node ? node.type.name === "paragraph" && node.textContent.length === 0 && node.content.size <= 2 && !isMedia : false;
3068
3080
  const currentAlign = ((_b = node == null ? void 0 : node.attrs) == null ? void 0 : _b.align) || "left";
3069
3081
  const currentIndent = ((_c = node == null ? void 0 : node.attrs) == null ? void 0 : _c.indent) || 0;
3070
3082
  const setAlign = (alignValue) => {
@@ -4020,7 +4032,7 @@ class BlockHandleView {
4020
4032
  });
4021
4033
  }
4022
4034
  const isMedia = node.type.name.includes("image") || node.type.name.includes("attachment") || node.type.name === "hr" || node.type.name.includes("math") || hasMediaChild;
4023
- const isEmpty = node.textContent.length === 0 && node.content.size <= 2 && !isMedia;
4035
+ const isEmpty = node.type.name === "paragraph" && node.textContent.length === 0 && node.content.size <= 2 && !isMedia;
4024
4036
  if (isEmpty) {
4025
4037
  __privateGet$5(this, _content$3).classList.add("empty-block");
4026
4038
  } else {
@@ -4171,7 +4183,7 @@ class BlockHandleView {
4171
4183
  });
4172
4184
  }
4173
4185
  const isMedia = node.type.name.includes("image") || node.type.name.includes("attachment") || node.type.name === "hr" || node.type.name.includes("math") || hasMediaChild;
4174
- const isEmpty = node.textContent.length === 0 && node.content.size <= 2 && !isMedia;
4186
+ const isEmpty = node.type.name === "paragraph" && node.textContent.length === 0 && node.content.size <= 2 && !isMedia;
4175
4187
  if (isEmpty) {
4176
4188
  __privateGet$5(this, _content$3).classList.add("empty-block");
4177
4189
  } else {
@@ -9096,7 +9108,17 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
9096
9108
  active: () => false,
9097
9109
  onRun: (ctx2) => {
9098
9110
  const markdown = getMarkdown()(ctx2);
9099
- if (_config == null ? void 0 : _config.onExport) {
9111
+ const view = ctx2.get(editorViewCtx);
9112
+ const root = ctx2.get(rootCtx);
9113
+ const rootNode = view.dom.getRootNode();
9114
+ if ((_config == null ? void 0 : _config.exportItems) && _config.exportItems.length > 0) {
9115
+ const exportItems = _config.exportItems;
9116
+ if (exportItems.length === 1) {
9117
+ handleDirectExport(exportItems[0], markdown, view, root);
9118
+ } else {
9119
+ showDownloadPopover(rootNode, root, view, markdown, exportItems);
9120
+ }
9121
+ } else if (_config == null ? void 0 : _config.onExport) {
9100
9122
  _config.onExport(markdown, ctx2);
9101
9123
  } else {
9102
9124
  const blob = new Blob([markdown], {
@@ -9118,7 +9140,17 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
9118
9140
  icon: importIcon,
9119
9141
  active: () => false,
9120
9142
  onRun: (ctx2) => {
9121
- if (_config == null ? void 0 : _config.onImport) {
9143
+ const view = ctx2.get(editorViewCtx);
9144
+ const root = ctx2.get(rootCtx);
9145
+ const rootNode = view.dom.getRootNode();
9146
+ if ((_config == null ? void 0 : _config.importItems) && _config.importItems.length > 0) {
9147
+ const importItems = _config.importItems;
9148
+ if (importItems.length === 1) {
9149
+ handleDirectImport(importItems[0], root, ctx2);
9150
+ } else {
9151
+ showImportPopover(rootNode, root, ctx2, importItems);
9152
+ }
9153
+ } else if (_config == null ? void 0 : _config.onImport) {
9122
9154
  _config.onImport((markdown) => replaceAll(markdown)(ctx2), ctx2);
9123
9155
  } else {
9124
9156
  const input = document.createElement("input");
@@ -9149,6 +9181,388 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
9149
9181
  });
9150
9182
  return builder.build();
9151
9183
  }
9184
+ const activeDownloadPopovers = /* @__PURE__ */ new WeakMap();
9185
+ const activeImportPopovers = /* @__PURE__ */ new WeakMap();
9186
+ const ensureStyles = (rootNode) => {
9187
+ const target = rootNode instanceof ShadowRoot ? rootNode : document.head;
9188
+ if (target.querySelector("#download-popover-styles")) return;
9189
+ const styleEl = document.createElement("style");
9190
+ styleEl.id = "download-popover-styles";
9191
+ styleEl.textContent = `
9192
+ .download-popover, .import-popover {
9193
+ position: fixed;
9194
+ z-index: 10000;
9195
+ width: 140px;
9196
+ padding: 6px 0;
9197
+ display: flex;
9198
+ flex-direction: column;
9199
+ background-color: var(--crepe-color-surface, #ffffff);
9200
+ border: 1px solid var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%));
9201
+ border-radius: 8px;
9202
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
9203
+ opacity: 0;
9204
+ transform: translateY(-8px);
9205
+ transition: opacity 0.15s ease, transform 0.15s ease;
9206
+ pointer-events: none;
9207
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
9208
+ }
9209
+ .download-popover.show, .import-popover.show {
9210
+ opacity: 1;
9211
+ transform: translateY(0);
9212
+ pointer-events: auto;
9213
+ }
9214
+ .download-popover-item, .import-popover-item {
9215
+ cursor: pointer;
9216
+ padding: 8px 14px;
9217
+ display: flex;
9218
+ align-items: center;
9219
+ gap: 8px;
9220
+ font-size: 13px;
9221
+ font-weight: 500;
9222
+ color: var(--crepe-color-primary, #363B4C);
9223
+ transition: background-color 0.2s;
9224
+ user-select: none;
9225
+ }
9226
+ .download-popover-item:hover, .import-popover-item:hover {
9227
+ background-color: var(--crepe-color-hover, #f5f5f5);
9228
+ }
9229
+ .download-popover-item-icon, .import-popover-item-icon {
9230
+ display: flex;
9231
+ align-items: center;
9232
+ justify-content: center;
9233
+ width: 14px;
9234
+ height: 14px;
9235
+ color: var(--crepe-color-primary, #363B4C);
9236
+ opacity: 0.8;
9237
+ }
9238
+ `;
9239
+ target.appendChild(styleEl);
9240
+ };
9241
+ function handleDirectExport(type, markdown, view, root) {
9242
+ if (type === "markdown") {
9243
+ const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8;" });
9244
+ const url = URL.createObjectURL(blob);
9245
+ const link = document.createElement("a");
9246
+ link.href = url;
9247
+ link.download = "document.md";
9248
+ link.click();
9249
+ URL.revokeObjectURL(url);
9250
+ }
9251
+ const event = new CustomEvent("download-click", {
9252
+ detail: {
9253
+ type,
9254
+ markdown,
9255
+ html: view.dom.innerHTML || ""
9256
+ },
9257
+ bubbles: true,
9258
+ composed: true
9259
+ });
9260
+ root.dispatchEvent(event);
9261
+ }
9262
+ function handleDirectImport(type, root, ctx) {
9263
+ if (type === "markdown") {
9264
+ const input = document.createElement("input");
9265
+ input.type = "file";
9266
+ input.accept = ".md";
9267
+ input.onchange = (evt) => {
9268
+ var _a;
9269
+ const file = (_a = evt.target.files) == null ? void 0 : _a[0];
9270
+ if (!file) return;
9271
+ file.text().then((text) => {
9272
+ replaceAll(text)(ctx);
9273
+ const event = new CustomEvent("import-click", {
9274
+ detail: { type: "markdown", file },
9275
+ bubbles: true,
9276
+ composed: true
9277
+ });
9278
+ root.dispatchEvent(event);
9279
+ }).catch((err) => {
9280
+ console.error("Failed to read file:", err);
9281
+ });
9282
+ };
9283
+ input.click();
9284
+ } else {
9285
+ const event = new CustomEvent("import-click", {
9286
+ detail: { type },
9287
+ bubbles: true,
9288
+ composed: true
9289
+ });
9290
+ root.dispatchEvent(event);
9291
+ }
9292
+ }
9293
+ function showDownloadPopover(rootNode, root, view, markdown, exportItems) {
9294
+ var _a, _b, _c;
9295
+ const button = root.querySelector('button[data-key="export"]');
9296
+ if (!button) return;
9297
+ const existing = activeDownloadPopovers.get(button);
9298
+ if (existing) {
9299
+ existing.closePopover();
9300
+ return;
9301
+ }
9302
+ ensureStyles(rootNode);
9303
+ const container = rootNode instanceof ShadowRoot ? rootNode : document.body;
9304
+ const popover = document.createElement("div");
9305
+ popover.className = "download-popover";
9306
+ let popoverHtml = "";
9307
+ if (exportItems.includes("markdown")) {
9308
+ popoverHtml += `
9309
+ <div class="download-popover-item" id="download-md-btn">
9310
+ <span class="download-popover-item-icon">
9311
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><line x1="10" y1="9" x2="8" y2="9"></line></svg>
9312
+ </span>
9313
+ <span>\u4E0B\u8F7D MD</span>
9314
+ </div>
9315
+ `;
9316
+ }
9317
+ if (exportItems.includes("word")) {
9318
+ popoverHtml += `
9319
+ <div class="download-popover-item" id="download-word-btn">
9320
+ <span class="download-popover-item-icon">
9321
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
9322
+ </span>
9323
+ <span>\u4E0B\u8F7D WORD</span>
9324
+ </div>
9325
+ `;
9326
+ }
9327
+ if (exportItems.includes("pdf")) {
9328
+ popoverHtml += `
9329
+ <div class="download-popover-item" id="download-pdf-btn">
9330
+ <span class="download-popover-item-icon">
9331
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg>
9332
+ </span>
9333
+ <span>\u4E0B\u8F7D PDF</span>
9334
+ </div>
9335
+ `;
9336
+ }
9337
+ popover.innerHTML = popoverHtml;
9338
+ container.appendChild(popover);
9339
+ activeDownloadPopovers.set(button, popover);
9340
+ const updatePosition = () => {
9341
+ const rect = button.getBoundingClientRect();
9342
+ popover.style.top = `${rect.bottom + 4}px`;
9343
+ popover.style.left = `${rect.left + (rect.width - 140) / 2}px`;
9344
+ };
9345
+ updatePosition();
9346
+ requestAnimationFrame(() => {
9347
+ popover.classList.add("show");
9348
+ });
9349
+ const closePopover = () => {
9350
+ popover.classList.remove("show");
9351
+ activeDownloadPopovers.delete(button);
9352
+ container.removeEventListener("pointerdown", handleContainerClick, true);
9353
+ document.removeEventListener("pointerdown", handleOuterClick, true);
9354
+ window.removeEventListener("resize", updatePosition);
9355
+ popover.addEventListener(
9356
+ "transitionend",
9357
+ () => {
9358
+ popover.remove();
9359
+ },
9360
+ { once: true }
9361
+ );
9362
+ };
9363
+ popover.closePopover = closePopover;
9364
+ const handleContainerClick = (e) => {
9365
+ const target = e.target;
9366
+ if (!popover.contains(target) && target !== button && !button.contains(target)) {
9367
+ closePopover();
9368
+ }
9369
+ };
9370
+ const handleOuterClick = (e) => {
9371
+ const target = e.target;
9372
+ if (target !== root && !root.contains(target)) {
9373
+ closePopover();
9374
+ }
9375
+ };
9376
+ popover.addEventListener("pointerdown", (e) => {
9377
+ e.stopPropagation();
9378
+ });
9379
+ container.addEventListener("pointerdown", handleContainerClick, true);
9380
+ document.addEventListener("pointerdown", handleOuterClick, true);
9381
+ window.addEventListener("resize", updatePosition);
9382
+ (_a = popover.querySelector("#download-md-btn")) == null ? void 0 : _a.addEventListener("click", (e) => {
9383
+ e.stopPropagation();
9384
+ const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8;" });
9385
+ const url = URL.createObjectURL(blob);
9386
+ const link = document.createElement("a");
9387
+ link.href = url;
9388
+ link.download = "document.md";
9389
+ link.click();
9390
+ URL.revokeObjectURL(url);
9391
+ closePopover();
9392
+ const event = new CustomEvent("download-click", {
9393
+ detail: {
9394
+ type: "markdown",
9395
+ markdown,
9396
+ html: view.dom.innerHTML || ""
9397
+ },
9398
+ bubbles: true,
9399
+ composed: true
9400
+ });
9401
+ root.dispatchEvent(event);
9402
+ });
9403
+ (_b = popover.querySelector("#download-word-btn")) == null ? void 0 : _b.addEventListener("click", (e) => {
9404
+ e.stopPropagation();
9405
+ closePopover();
9406
+ const event = new CustomEvent("download-click", {
9407
+ detail: {
9408
+ type: "word",
9409
+ markdown,
9410
+ html: view.dom.innerHTML || ""
9411
+ },
9412
+ bubbles: true,
9413
+ composed: true
9414
+ });
9415
+ root.dispatchEvent(event);
9416
+ });
9417
+ (_c = popover.querySelector("#download-pdf-btn")) == null ? void 0 : _c.addEventListener("click", (e) => {
9418
+ e.stopPropagation();
9419
+ closePopover();
9420
+ const event = new CustomEvent("download-click", {
9421
+ detail: {
9422
+ type: "pdf",
9423
+ markdown,
9424
+ html: view.dom.innerHTML || ""
9425
+ },
9426
+ bubbles: true,
9427
+ composed: true
9428
+ });
9429
+ root.dispatchEvent(event);
9430
+ });
9431
+ }
9432
+ function showImportPopover(rootNode, root, ctx, importItems) {
9433
+ var _a, _b, _c;
9434
+ const button = root.querySelector('button[data-key="import"]');
9435
+ if (!button) return;
9436
+ const existing = activeImportPopovers.get(button);
9437
+ if (existing) {
9438
+ existing.closePopover();
9439
+ return;
9440
+ }
9441
+ ensureStyles(rootNode);
9442
+ const container = rootNode instanceof ShadowRoot ? rootNode : document.body;
9443
+ const popover = document.createElement("div");
9444
+ popover.className = "import-popover";
9445
+ let popoverHtml = "";
9446
+ if (importItems.includes("markdown")) {
9447
+ popoverHtml += `
9448
+ <div class="import-popover-item" id="import-md-btn">
9449
+ <span class="import-popover-item-icon">
9450
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><line x1="10" y1="9" x2="8" y2="9"></line></svg>
9451
+ </span>
9452
+ <span>\u5BFC\u5165 MD</span>
9453
+ </div>
9454
+ `;
9455
+ }
9456
+ if (importItems.includes("word")) {
9457
+ popoverHtml += `
9458
+ <div class="import-popover-item" id="import-word-btn">
9459
+ <span class="import-popover-item-icon">
9460
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
9461
+ </span>
9462
+ <span>\u5BFC\u5165 WORD</span>
9463
+ </div>
9464
+ `;
9465
+ }
9466
+ if (importItems.includes("pdf")) {
9467
+ popoverHtml += `
9468
+ <div class="import-popover-item" id="import-pdf-btn">
9469
+ <span class="import-popover-item-icon">
9470
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg>
9471
+ </span>
9472
+ <span>\u5BFC\u5165 PDF</span>
9473
+ </div>
9474
+ `;
9475
+ }
9476
+ popover.innerHTML = popoverHtml;
9477
+ container.appendChild(popover);
9478
+ activeImportPopovers.set(button, popover);
9479
+ const updatePosition = () => {
9480
+ const rect = button.getBoundingClientRect();
9481
+ popover.style.top = `${rect.bottom + 4}px`;
9482
+ popover.style.left = `${rect.left + (rect.width - 140) / 2}px`;
9483
+ };
9484
+ updatePosition();
9485
+ requestAnimationFrame(() => {
9486
+ popover.classList.add("show");
9487
+ });
9488
+ const closePopover = () => {
9489
+ popover.classList.remove("show");
9490
+ activeImportPopovers.delete(button);
9491
+ container.removeEventListener("pointerdown", handleContainerClick, true);
9492
+ document.removeEventListener("pointerdown", handleOuterClick, true);
9493
+ window.removeEventListener("resize", updatePosition);
9494
+ popover.addEventListener(
9495
+ "transitionend",
9496
+ () => {
9497
+ popover.remove();
9498
+ },
9499
+ { once: true }
9500
+ );
9501
+ };
9502
+ popover.closePopover = closePopover;
9503
+ const handleContainerClick = (e) => {
9504
+ const target = e.target;
9505
+ if (!popover.contains(target) && target !== button && !button.contains(target)) {
9506
+ closePopover();
9507
+ }
9508
+ };
9509
+ const handleOuterClick = (e) => {
9510
+ const target = e.target;
9511
+ if (target !== root && !root.contains(target)) {
9512
+ closePopover();
9513
+ }
9514
+ };
9515
+ popover.addEventListener("pointerdown", (e) => {
9516
+ e.stopPropagation();
9517
+ });
9518
+ container.addEventListener("pointerdown", handleContainerClick, true);
9519
+ document.addEventListener("pointerdown", handleOuterClick, true);
9520
+ window.addEventListener("resize", updatePosition);
9521
+ (_a = popover.querySelector("#import-md-btn")) == null ? void 0 : _a.addEventListener("click", (e) => {
9522
+ e.stopPropagation();
9523
+ closePopover();
9524
+ const input = document.createElement("input");
9525
+ input.type = "file";
9526
+ input.accept = ".md";
9527
+ input.onchange = (evt) => {
9528
+ var _a2;
9529
+ const file = (_a2 = evt.target.files) == null ? void 0 : _a2[0];
9530
+ if (!file) return;
9531
+ file.text().then((text) => {
9532
+ replaceAll(text)(ctx);
9533
+ const event = new CustomEvent("import-click", {
9534
+ detail: { type: "markdown", file },
9535
+ bubbles: true,
9536
+ composed: true
9537
+ });
9538
+ root.dispatchEvent(event);
9539
+ }).catch((err) => {
9540
+ console.error("Failed to read file:", err);
9541
+ });
9542
+ };
9543
+ input.click();
9544
+ });
9545
+ (_b = popover.querySelector("#import-word-btn")) == null ? void 0 : _b.addEventListener("click", (e) => {
9546
+ e.stopPropagation();
9547
+ closePopover();
9548
+ const event = new CustomEvent("import-click", {
9549
+ detail: { type: "word" },
9550
+ bubbles: true,
9551
+ composed: true
9552
+ });
9553
+ root.dispatchEvent(event);
9554
+ });
9555
+ (_c = popover.querySelector("#import-pdf-btn")) == null ? void 0 : _c.addEventListener("click", (e) => {
9556
+ e.stopPropagation();
9557
+ closePopover();
9558
+ const event = new CustomEvent("import-click", {
9559
+ detail: { type: "pdf" },
9560
+ bubbles: true,
9561
+ composed: true
9562
+ });
9563
+ root.dispatchEvent(event);
9564
+ });
9565
+ }
9152
9566
 
9153
9567
  keepAlive(h);
9154
9568
  const DocumentHeader = defineComponent({