@jvs-milkdown/crepe 1.2.25 → 1.2.26

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/lib/cjs/index.js CHANGED
@@ -9117,7 +9117,17 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
9117
9117
  active: () => false,
9118
9118
  onRun: (ctx2) => {
9119
9119
  const markdown = utils.getMarkdown()(ctx2);
9120
- if (_config == null ? void 0 : _config.onExport) {
9120
+ const view = ctx2.get(core.editorViewCtx);
9121
+ const root = ctx2.get(core.rootCtx);
9122
+ const rootNode = view.dom.getRootNode();
9123
+ if ((_config == null ? void 0 : _config.exportItems) && _config.exportItems.length > 0) {
9124
+ const exportItems = _config.exportItems;
9125
+ if (exportItems.length === 1) {
9126
+ handleDirectExport(exportItems[0], markdown, view, root);
9127
+ } else {
9128
+ showDownloadPopover(rootNode, root, view, markdown, exportItems);
9129
+ }
9130
+ } else if (_config == null ? void 0 : _config.onExport) {
9121
9131
  _config.onExport(markdown, ctx2);
9122
9132
  } else {
9123
9133
  const blob = new Blob([markdown], {
@@ -9139,7 +9149,17 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
9139
9149
  icon: importIcon,
9140
9150
  active: () => false,
9141
9151
  onRun: (ctx2) => {
9142
- if (_config == null ? void 0 : _config.onImport) {
9152
+ const view = ctx2.get(core.editorViewCtx);
9153
+ const root = ctx2.get(core.rootCtx);
9154
+ const rootNode = view.dom.getRootNode();
9155
+ if ((_config == null ? void 0 : _config.importItems) && _config.importItems.length > 0) {
9156
+ const importItems = _config.importItems;
9157
+ if (importItems.length === 1) {
9158
+ handleDirectImport(importItems[0], root, ctx2);
9159
+ } else {
9160
+ showImportPopover(rootNode, root, ctx2, importItems);
9161
+ }
9162
+ } else if (_config == null ? void 0 : _config.onImport) {
9143
9163
  _config.onImport((markdown) => utils$1.replaceAll(markdown)(ctx2), ctx2);
9144
9164
  } else {
9145
9165
  const input = document.createElement("input");
@@ -9170,6 +9190,388 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
9170
9190
  });
9171
9191
  return builder.build();
9172
9192
  }
9193
+ const activeDownloadPopovers = /* @__PURE__ */ new WeakMap();
9194
+ const activeImportPopovers = /* @__PURE__ */ new WeakMap();
9195
+ const ensureStyles = (rootNode) => {
9196
+ const target = rootNode instanceof ShadowRoot ? rootNode : document.head;
9197
+ if (target.querySelector("#download-popover-styles")) return;
9198
+ const styleEl = document.createElement("style");
9199
+ styleEl.id = "download-popover-styles";
9200
+ styleEl.textContent = `
9201
+ .download-popover, .import-popover {
9202
+ position: fixed;
9203
+ z-index: 10000;
9204
+ width: 140px;
9205
+ padding: 6px 0;
9206
+ display: flex;
9207
+ flex-direction: column;
9208
+ background-color: var(--crepe-color-surface, #ffffff);
9209
+ border: 1px solid var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%));
9210
+ border-radius: 8px;
9211
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
9212
+ opacity: 0;
9213
+ transform: translateY(-8px);
9214
+ transition: opacity 0.15s ease, transform 0.15s ease;
9215
+ pointer-events: none;
9216
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
9217
+ }
9218
+ .download-popover.show, .import-popover.show {
9219
+ opacity: 1;
9220
+ transform: translateY(0);
9221
+ pointer-events: auto;
9222
+ }
9223
+ .download-popover-item, .import-popover-item {
9224
+ cursor: pointer;
9225
+ padding: 8px 14px;
9226
+ display: flex;
9227
+ align-items: center;
9228
+ gap: 8px;
9229
+ font-size: 13px;
9230
+ font-weight: 500;
9231
+ color: var(--crepe-color-primary, #363B4C);
9232
+ transition: background-color 0.2s;
9233
+ user-select: none;
9234
+ }
9235
+ .download-popover-item:hover, .import-popover-item:hover {
9236
+ background-color: var(--crepe-color-hover, #f5f5f5);
9237
+ }
9238
+ .download-popover-item-icon, .import-popover-item-icon {
9239
+ display: flex;
9240
+ align-items: center;
9241
+ justify-content: center;
9242
+ width: 14px;
9243
+ height: 14px;
9244
+ color: var(--crepe-color-primary, #363B4C);
9245
+ opacity: 0.8;
9246
+ }
9247
+ `;
9248
+ target.appendChild(styleEl);
9249
+ };
9250
+ function handleDirectExport(type, markdown, view, root) {
9251
+ if (type === "markdown") {
9252
+ const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8;" });
9253
+ const url = URL.createObjectURL(blob);
9254
+ const link = document.createElement("a");
9255
+ link.href = url;
9256
+ link.download = "document.md";
9257
+ link.click();
9258
+ URL.revokeObjectURL(url);
9259
+ }
9260
+ const event = new CustomEvent("download-click", {
9261
+ detail: {
9262
+ type,
9263
+ markdown,
9264
+ html: view.dom.innerHTML || ""
9265
+ },
9266
+ bubbles: true,
9267
+ composed: true
9268
+ });
9269
+ root.dispatchEvent(event);
9270
+ }
9271
+ function handleDirectImport(type, root, ctx) {
9272
+ if (type === "markdown") {
9273
+ const input = document.createElement("input");
9274
+ input.type = "file";
9275
+ input.accept = ".md";
9276
+ input.onchange = (evt) => {
9277
+ var _a;
9278
+ const file = (_a = evt.target.files) == null ? void 0 : _a[0];
9279
+ if (!file) return;
9280
+ file.text().then((text) => {
9281
+ utils$1.replaceAll(text)(ctx);
9282
+ const event = new CustomEvent("import-click", {
9283
+ detail: { type: "markdown", file },
9284
+ bubbles: true,
9285
+ composed: true
9286
+ });
9287
+ root.dispatchEvent(event);
9288
+ }).catch((err) => {
9289
+ console.error("Failed to read file:", err);
9290
+ });
9291
+ };
9292
+ input.click();
9293
+ } else {
9294
+ const event = new CustomEvent("import-click", {
9295
+ detail: { type },
9296
+ bubbles: true,
9297
+ composed: true
9298
+ });
9299
+ root.dispatchEvent(event);
9300
+ }
9301
+ }
9302
+ function showDownloadPopover(rootNode, root, view, markdown, exportItems) {
9303
+ var _a, _b, _c;
9304
+ const button = root.querySelector('button[data-key="export"]');
9305
+ if (!button) return;
9306
+ const existing = activeDownloadPopovers.get(button);
9307
+ if (existing) {
9308
+ existing.closePopover();
9309
+ return;
9310
+ }
9311
+ ensureStyles(rootNode);
9312
+ const container = rootNode instanceof ShadowRoot ? rootNode : document.body;
9313
+ const popover = document.createElement("div");
9314
+ popover.className = "download-popover";
9315
+ let popoverHtml = "";
9316
+ if (exportItems.includes("markdown")) {
9317
+ popoverHtml += `
9318
+ <div class="download-popover-item" id="download-md-btn">
9319
+ <span class="download-popover-item-icon">
9320
+ <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>
9321
+ </span>
9322
+ <span>\u4E0B\u8F7D MD</span>
9323
+ </div>
9324
+ `;
9325
+ }
9326
+ if (exportItems.includes("word")) {
9327
+ popoverHtml += `
9328
+ <div class="download-popover-item" id="download-word-btn">
9329
+ <span class="download-popover-item-icon">
9330
+ <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>
9331
+ </span>
9332
+ <span>\u4E0B\u8F7D WORD</span>
9333
+ </div>
9334
+ `;
9335
+ }
9336
+ if (exportItems.includes("pdf")) {
9337
+ popoverHtml += `
9338
+ <div class="download-popover-item" id="download-pdf-btn">
9339
+ <span class="download-popover-item-icon">
9340
+ <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>
9341
+ </span>
9342
+ <span>\u4E0B\u8F7D PDF</span>
9343
+ </div>
9344
+ `;
9345
+ }
9346
+ popover.innerHTML = popoverHtml;
9347
+ container.appendChild(popover);
9348
+ activeDownloadPopovers.set(button, popover);
9349
+ const updatePosition = () => {
9350
+ const rect = button.getBoundingClientRect();
9351
+ popover.style.top = `${rect.bottom + 4}px`;
9352
+ popover.style.left = `${rect.left + (rect.width - 140) / 2}px`;
9353
+ };
9354
+ updatePosition();
9355
+ requestAnimationFrame(() => {
9356
+ popover.classList.add("show");
9357
+ });
9358
+ const closePopover = () => {
9359
+ popover.classList.remove("show");
9360
+ activeDownloadPopovers.delete(button);
9361
+ container.removeEventListener("pointerdown", handleContainerClick, true);
9362
+ document.removeEventListener("pointerdown", handleOuterClick, true);
9363
+ window.removeEventListener("resize", updatePosition);
9364
+ popover.addEventListener(
9365
+ "transitionend",
9366
+ () => {
9367
+ popover.remove();
9368
+ },
9369
+ { once: true }
9370
+ );
9371
+ };
9372
+ popover.closePopover = closePopover;
9373
+ const handleContainerClick = (e) => {
9374
+ const target = e.target;
9375
+ if (!popover.contains(target) && target !== button && !button.contains(target)) {
9376
+ closePopover();
9377
+ }
9378
+ };
9379
+ const handleOuterClick = (e) => {
9380
+ const target = e.target;
9381
+ if (target !== root && !root.contains(target)) {
9382
+ closePopover();
9383
+ }
9384
+ };
9385
+ popover.addEventListener("pointerdown", (e) => {
9386
+ e.stopPropagation();
9387
+ });
9388
+ container.addEventListener("pointerdown", handleContainerClick, true);
9389
+ document.addEventListener("pointerdown", handleOuterClick, true);
9390
+ window.addEventListener("resize", updatePosition);
9391
+ (_a = popover.querySelector("#download-md-btn")) == null ? void 0 : _a.addEventListener("click", (e) => {
9392
+ e.stopPropagation();
9393
+ const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8;" });
9394
+ const url = URL.createObjectURL(blob);
9395
+ const link = document.createElement("a");
9396
+ link.href = url;
9397
+ link.download = "document.md";
9398
+ link.click();
9399
+ URL.revokeObjectURL(url);
9400
+ closePopover();
9401
+ const event = new CustomEvent("download-click", {
9402
+ detail: {
9403
+ type: "markdown",
9404
+ markdown,
9405
+ html: view.dom.innerHTML || ""
9406
+ },
9407
+ bubbles: true,
9408
+ composed: true
9409
+ });
9410
+ root.dispatchEvent(event);
9411
+ });
9412
+ (_b = popover.querySelector("#download-word-btn")) == null ? void 0 : _b.addEventListener("click", (e) => {
9413
+ e.stopPropagation();
9414
+ closePopover();
9415
+ const event = new CustomEvent("download-click", {
9416
+ detail: {
9417
+ type: "word",
9418
+ markdown,
9419
+ html: view.dom.innerHTML || ""
9420
+ },
9421
+ bubbles: true,
9422
+ composed: true
9423
+ });
9424
+ root.dispatchEvent(event);
9425
+ });
9426
+ (_c = popover.querySelector("#download-pdf-btn")) == null ? void 0 : _c.addEventListener("click", (e) => {
9427
+ e.stopPropagation();
9428
+ closePopover();
9429
+ const event = new CustomEvent("download-click", {
9430
+ detail: {
9431
+ type: "pdf",
9432
+ markdown,
9433
+ html: view.dom.innerHTML || ""
9434
+ },
9435
+ bubbles: true,
9436
+ composed: true
9437
+ });
9438
+ root.dispatchEvent(event);
9439
+ });
9440
+ }
9441
+ function showImportPopover(rootNode, root, ctx, importItems) {
9442
+ var _a, _b, _c;
9443
+ const button = root.querySelector('button[data-key="import"]');
9444
+ if (!button) return;
9445
+ const existing = activeImportPopovers.get(button);
9446
+ if (existing) {
9447
+ existing.closePopover();
9448
+ return;
9449
+ }
9450
+ ensureStyles(rootNode);
9451
+ const container = rootNode instanceof ShadowRoot ? rootNode : document.body;
9452
+ const popover = document.createElement("div");
9453
+ popover.className = "import-popover";
9454
+ let popoverHtml = "";
9455
+ if (importItems.includes("markdown")) {
9456
+ popoverHtml += `
9457
+ <div class="import-popover-item" id="import-md-btn">
9458
+ <span class="import-popover-item-icon">
9459
+ <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>
9460
+ </span>
9461
+ <span>\u5BFC\u5165 MD</span>
9462
+ </div>
9463
+ `;
9464
+ }
9465
+ if (importItems.includes("word")) {
9466
+ popoverHtml += `
9467
+ <div class="import-popover-item" id="import-word-btn">
9468
+ <span class="import-popover-item-icon">
9469
+ <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>
9470
+ </span>
9471
+ <span>\u5BFC\u5165 WORD</span>
9472
+ </div>
9473
+ `;
9474
+ }
9475
+ if (importItems.includes("pdf")) {
9476
+ popoverHtml += `
9477
+ <div class="import-popover-item" id="import-pdf-btn">
9478
+ <span class="import-popover-item-icon">
9479
+ <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>
9480
+ </span>
9481
+ <span>\u5BFC\u5165 PDF</span>
9482
+ </div>
9483
+ `;
9484
+ }
9485
+ popover.innerHTML = popoverHtml;
9486
+ container.appendChild(popover);
9487
+ activeImportPopovers.set(button, popover);
9488
+ const updatePosition = () => {
9489
+ const rect = button.getBoundingClientRect();
9490
+ popover.style.top = `${rect.bottom + 4}px`;
9491
+ popover.style.left = `${rect.left + (rect.width - 140) / 2}px`;
9492
+ };
9493
+ updatePosition();
9494
+ requestAnimationFrame(() => {
9495
+ popover.classList.add("show");
9496
+ });
9497
+ const closePopover = () => {
9498
+ popover.classList.remove("show");
9499
+ activeImportPopovers.delete(button);
9500
+ container.removeEventListener("pointerdown", handleContainerClick, true);
9501
+ document.removeEventListener("pointerdown", handleOuterClick, true);
9502
+ window.removeEventListener("resize", updatePosition);
9503
+ popover.addEventListener(
9504
+ "transitionend",
9505
+ () => {
9506
+ popover.remove();
9507
+ },
9508
+ { once: true }
9509
+ );
9510
+ };
9511
+ popover.closePopover = closePopover;
9512
+ const handleContainerClick = (e) => {
9513
+ const target = e.target;
9514
+ if (!popover.contains(target) && target !== button && !button.contains(target)) {
9515
+ closePopover();
9516
+ }
9517
+ };
9518
+ const handleOuterClick = (e) => {
9519
+ const target = e.target;
9520
+ if (target !== root && !root.contains(target)) {
9521
+ closePopover();
9522
+ }
9523
+ };
9524
+ popover.addEventListener("pointerdown", (e) => {
9525
+ e.stopPropagation();
9526
+ });
9527
+ container.addEventListener("pointerdown", handleContainerClick, true);
9528
+ document.addEventListener("pointerdown", handleOuterClick, true);
9529
+ window.addEventListener("resize", updatePosition);
9530
+ (_a = popover.querySelector("#import-md-btn")) == null ? void 0 : _a.addEventListener("click", (e) => {
9531
+ e.stopPropagation();
9532
+ closePopover();
9533
+ const input = document.createElement("input");
9534
+ input.type = "file";
9535
+ input.accept = ".md";
9536
+ input.onchange = (evt) => {
9537
+ var _a2;
9538
+ const file = (_a2 = evt.target.files) == null ? void 0 : _a2[0];
9539
+ if (!file) return;
9540
+ file.text().then((text) => {
9541
+ utils$1.replaceAll(text)(ctx);
9542
+ const event = new CustomEvent("import-click", {
9543
+ detail: { type: "markdown", file },
9544
+ bubbles: true,
9545
+ composed: true
9546
+ });
9547
+ root.dispatchEvent(event);
9548
+ }).catch((err) => {
9549
+ console.error("Failed to read file:", err);
9550
+ });
9551
+ };
9552
+ input.click();
9553
+ });
9554
+ (_b = popover.querySelector("#import-word-btn")) == null ? void 0 : _b.addEventListener("click", (e) => {
9555
+ e.stopPropagation();
9556
+ closePopover();
9557
+ const event = new CustomEvent("import-click", {
9558
+ detail: { type: "word" },
9559
+ bubbles: true,
9560
+ composed: true
9561
+ });
9562
+ root.dispatchEvent(event);
9563
+ });
9564
+ (_c = popover.querySelector("#import-pdf-btn")) == null ? void 0 : _c.addEventListener("click", (e) => {
9565
+ e.stopPropagation();
9566
+ closePopover();
9567
+ const event = new CustomEvent("import-click", {
9568
+ detail: { type: "pdf" },
9569
+ bubbles: true,
9570
+ composed: true
9571
+ });
9572
+ root.dispatchEvent(event);
9573
+ });
9574
+ }
9173
9575
 
9174
9576
  keepAlive(vue.h);
9175
9577
  const DocumentHeader = vue.defineComponent({