@files-preview-app/preview-file 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { memo, forwardRef, useRef, useImperativeHandle, useEffect } from 'react';
2
- import DOMPurify5 from 'dompurify';
2
+ import DOMPurify6 from 'dompurify';
3
3
  import * as docx from 'docx-preview';
4
+ import { unzipSync, strFromU8, unzip } from 'fflate';
4
5
  import * as XLSX from 'xlsx';
5
6
  import hljs from 'highlight.js';
6
- import { unzipSync, strFromU8, unzip } from 'fflate';
7
7
  import { marked } from 'marked';
8
8
  import { PptxRenderer } from 'pptx-browser';
9
9
  import * as THREE from 'three';
@@ -341,7 +341,7 @@ async function sourceToArrayBuffer(source, signal) {
341
341
  return { buffer, metadata };
342
342
  }
343
343
  function sanitizeSVG(svg) {
344
- return DOMPurify5.sanitize(svg, {
344
+ return DOMPurify6.sanitize(svg, {
345
345
  USE_PROFILES: { svg: true, svgFilters: true }
346
346
  });
347
347
  }
@@ -417,7 +417,11 @@ var ICON_MAP = {
417
417
  "close": ICON_CLOSE,
418
418
  "copy": ICON_COPY,
419
419
  "prev": ICON_PAGE_PREV,
420
- "next": ICON_PAGE_NEXT
420
+ "next": ICON_PAGE_NEXT,
421
+ "page-prev": ICON_PAGE_PREV,
422
+ "page-next": ICON_PAGE_NEXT,
423
+ "chevron-left": ICON_PAGE_PREV,
424
+ "chevron-right": ICON_PAGE_NEXT
421
425
  };
422
426
  var ToolbarController = class {
423
427
  el;
@@ -449,7 +453,9 @@ var ToolbarController = class {
449
453
  view: [],
450
454
  actions: []
451
455
  };
452
- for (const action of this.actions) {
456
+ const hasPageNav = this.actions.some((a) => a.type === "page-nav");
457
+ const effectiveActions = hasPageNav ? this.actions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : this.actions;
458
+ for (const action of effectiveActions) {
453
459
  if (groups[action.group]) {
454
460
  groups[action.group].push(action);
455
461
  }
@@ -472,13 +478,26 @@ var ToolbarController = class {
472
478
  "prev",
473
479
  ICON_PAGE_PREV,
474
480
  "Previous Page",
475
- () => action.execute("prev")
481
+ () => {
482
+ const cur = parseInt(input.value, 10) || 1;
483
+ if (cur > 1) {
484
+ input.value = (cur - 1).toString();
485
+ action.execute("prev", cur - 1);
486
+ }
487
+ }
476
488
  );
477
489
  const nextBtn = this.createButton(
478
490
  "next",
479
491
  ICON_PAGE_NEXT,
480
492
  "Next Page",
481
- () => action.execute("next")
493
+ () => {
494
+ const cur = parseInt(input.value, 10) || 1;
495
+ const max = action.max ?? 1;
496
+ if (cur < max) {
497
+ input.value = (cur + 1).toString();
498
+ action.execute("next", cur + 1);
499
+ }
500
+ }
482
501
  );
483
502
  const input = createElement("input", {
484
503
  className: "fp-toolbar-input",
@@ -488,7 +507,10 @@ var ToolbarController = class {
488
507
  max: (action.max ?? 1).toString()
489
508
  });
490
509
  input.addEventListener("change", () => {
491
- action.execute("go", parseInt(input.value, 10));
510
+ const val = parseInt(input.value, 10);
511
+ if (!isNaN(val)) {
512
+ action.execute("go", val);
513
+ }
492
514
  });
493
515
  const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${action.max ?? 1}`);
494
516
  groupEl.appendChild(prevBtn);
@@ -529,11 +551,11 @@ var ToolbarController = class {
529
551
  type: "button",
530
552
  "data-action-id": id
531
553
  });
532
- const svg = ICON_MAP[iconHtml] || iconHtml;
533
- if (svg && svg.startsWith("<svg")) {
554
+ const svg = ICON_MAP[iconHtml] || ICON_MAP[id] || (iconHtml && iconHtml.startsWith("<svg") ? iconHtml : null);
555
+ if (svg) {
534
556
  btn.innerHTML = sanitizeSVG(svg);
535
557
  } else {
536
- btn.textContent = svg || title;
558
+ btn.textContent = title || id;
537
559
  }
538
560
  btn.addEventListener("click", onClick);
539
561
  return btn;
@@ -1276,12 +1298,12 @@ function pdfPlugin() {
1276
1298
  }
1277
1299
 
1278
1300
  // ../plugins/media/dist/index.js
1279
- var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"];
1280
- var VIDEO_EXTS = [".mp4", ".webm", ".ogg"];
1281
- var AUDIO_EXTS = [".mp3", ".wav", ".ogg"];
1301
+ var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp", ".ico", ".tiff", ".tif", ".avif"];
1302
+ var VIDEO_EXTS = [".mp4", ".m4v", ".webm", ".ogv", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".3gp", ".mpg", ".mpeg"];
1303
+ var AUDIO_EXTS = [".mp3", ".wav", ".ogg", ".flac", ".aac", ".m4a", ".wma", ".opus", ".weba"];
1282
1304
  var MediaPlugin = class {
1283
1305
  id = "media";
1284
- name = "Media Preview";
1306
+ name = "Media Preview (Image, Video, Audio)";
1285
1307
  extensions = [...IMAGE_EXTS, ...VIDEO_EXTS, ...AUDIO_EXTS];
1286
1308
  mimeTypes = [
1287
1309
  "image/jpeg",
@@ -1289,12 +1311,29 @@ var MediaPlugin = class {
1289
1311
  "image/gif",
1290
1312
  "image/webp",
1291
1313
  "image/svg+xml",
1314
+ "image/bmp",
1315
+ "image/x-icon",
1316
+ "image/tiff",
1317
+ "image/avif",
1292
1318
  "video/mp4",
1293
1319
  "video/webm",
1294
1320
  "video/ogg",
1321
+ "video/quicktime",
1322
+ "video/x-msvideo",
1323
+ "video/x-matroska",
1324
+ "video/x-flv",
1325
+ "video/x-ms-wmv",
1326
+ "video/3gpp",
1327
+ "video/mpeg",
1295
1328
  "audio/mpeg",
1296
1329
  "audio/wav",
1297
- "audio/ogg"
1330
+ "audio/ogg",
1331
+ "audio/flac",
1332
+ "audio/aac",
1333
+ "audio/mp4",
1334
+ "audio/x-ms-wma",
1335
+ "audio/opus",
1336
+ "audio/webm"
1298
1337
  ];
1299
1338
  weight = 90;
1300
1339
  supports(file) {
@@ -1427,8 +1466,12 @@ var MediaPlugin = class {
1427
1466
  const video = document.createElement("video");
1428
1467
  video.src = url;
1429
1468
  video.controls = true;
1430
- video.style.maxWidth = "100%";
1431
- video.style.maxHeight = "100%";
1469
+ video.playsInline = true;
1470
+ video.style.maxWidth = "90%";
1471
+ video.style.maxHeight = "90%";
1472
+ video.style.borderRadius = "8px";
1473
+ video.style.boxShadow = "0 8px 30px rgba(0,0,0,0.3)";
1474
+ video.style.backgroundColor = "#000000";
1432
1475
  element = video;
1433
1476
  mediaElement = video;
1434
1477
  } else if (isAudio) {
@@ -1504,7 +1547,7 @@ function mediaPlugin() {
1504
1547
  }
1505
1548
  var DocxPlugin = class {
1506
1549
  id = "docx";
1507
- name = "Word Document Preview";
1550
+ name = "Word Document Preview (.docx, .docm, .dotx, .dotm)";
1508
1551
  extensions = [".docx", ".docm", ".dotx", ".dotm"];
1509
1552
  mimeTypes = [
1510
1553
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@@ -1526,9 +1569,7 @@ var DocxPlugin = class {
1526
1569
  label: "Zoom Out",
1527
1570
  type: "button",
1528
1571
  group: "zoom",
1529
- execute: () => {
1530
- instance.zoomOut?.();
1531
- }
1572
+ execute: () => instance.zoomOut?.()
1532
1573
  },
1533
1574
  {
1534
1575
  id: "zoom-in",
@@ -1536,9 +1577,7 @@ var DocxPlugin = class {
1536
1577
  label: "Zoom In",
1537
1578
  type: "button",
1538
1579
  group: "zoom",
1539
- execute: () => {
1540
- instance.zoomIn?.();
1541
- }
1580
+ execute: () => instance.zoomIn?.()
1542
1581
  },
1543
1582
  {
1544
1583
  id: "fit-page",
@@ -1546,9 +1585,7 @@ var DocxPlugin = class {
1546
1585
  label: "Fit to Page",
1547
1586
  type: "button",
1548
1587
  group: "zoom",
1549
- execute: () => {
1550
- instance.fitToPage?.();
1551
- }
1588
+ execute: () => instance.fitToPage?.()
1552
1589
  },
1553
1590
  {
1554
1591
  id: "download",
@@ -1556,9 +1593,7 @@ var DocxPlugin = class {
1556
1593
  label: "Download",
1557
1594
  type: "button",
1558
1595
  group: "actions",
1559
- execute: () => {
1560
- instance.download?.();
1561
- }
1596
+ execute: () => instance.download?.()
1562
1597
  },
1563
1598
  {
1564
1599
  id: "print",
@@ -1566,9 +1601,7 @@ var DocxPlugin = class {
1566
1601
  label: "Print",
1567
1602
  type: "button",
1568
1603
  group: "actions",
1569
- execute: () => {
1570
- instance.print?.();
1571
- }
1604
+ execute: () => instance.print?.()
1572
1605
  }
1573
1606
  ];
1574
1607
  }
@@ -1577,24 +1610,46 @@ var DocxPlugin = class {
1577
1610
  wrapper.className = "fp-docx-wrapper";
1578
1611
  wrapper.style.transformOrigin = "top center";
1579
1612
  wrapper.style.transition = "transform 0.2s ease";
1580
- wrapper.style.padding = "16px";
1613
+ wrapper.style.padding = "24px 16px";
1614
+ wrapper.style.maxWidth = "900px";
1615
+ wrapper.style.margin = "0 auto";
1616
+ wrapper.style.boxSizing = "border-box";
1581
1617
  ctx.container.style.overflow = "auto";
1618
+ ctx.container.style.backgroundColor = "#f1f5f9";
1582
1619
  ctx.container.appendChild(wrapper);
1583
1620
  let scale = 1;
1621
+ let renderedSuccessfully = false;
1584
1622
  try {
1585
1623
  await docx.renderAsync(ctx.buffer, wrapper, ctx.container, {
1586
1624
  inWrapper: true,
1587
1625
  ignoreWidth: false,
1588
- ignoreHeight: false
1626
+ ignoreHeight: false,
1627
+ ignoreFonts: true,
1628
+ // Avoid crashes on embedded obfuscated fonts
1629
+ breakPages: true,
1630
+ experimental: true
1589
1631
  });
1590
- } catch {
1591
- wrapper.innerHTML = `
1592
- <div style="text-align:center; padding: 40px; color: #666;">
1593
- <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
1594
- <h3>${ctx.metadata.name || "Word Document"}</h3>
1595
- <p>DOCX render preview</p>
1596
- </div>
1597
- `;
1632
+ if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
1633
+ renderedSuccessfully = true;
1634
+ }
1635
+ } catch (err) {
1636
+ console.warn("[DocxPlugin] docx-preview failed, triggering native XML fallback:", err);
1637
+ }
1638
+ if (!renderedSuccessfully) {
1639
+ try {
1640
+ wrapper.innerHTML = "";
1641
+ this.renderXmlFallback(ctx, wrapper);
1642
+ renderedSuccessfully = true;
1643
+ } catch (fallbackErr) {
1644
+ console.error("[DocxPlugin] XML fallback failed:", fallbackErr);
1645
+ wrapper.innerHTML = `
1646
+ <div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
1647
+ <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
1648
+ <h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
1649
+ <p style="color: #64748b; margin: 0;">Could not parse document content</p>
1650
+ </div>
1651
+ `;
1652
+ }
1598
1653
  }
1599
1654
  const cleanup = () => {
1600
1655
  wrapper.remove();
@@ -1618,7 +1673,7 @@ var DocxPlugin = class {
1618
1673
  },
1619
1674
  fitToPage: () => {
1620
1675
  scale = 1;
1621
- wrapper.style.transform = `scale(1)`;
1676
+ wrapper.style.transform = "scale(1)";
1622
1677
  },
1623
1678
  download: () => {
1624
1679
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -1634,6 +1689,100 @@ var DocxPlugin = class {
1634
1689
  }
1635
1690
  };
1636
1691
  }
1692
+ renderXmlFallback(ctx, wrapper) {
1693
+ const unzipped = unzipSync(new Uint8Array(ctx.buffer));
1694
+ const docXmlEntry = unzipped["word/document.xml"];
1695
+ if (!docXmlEntry) throw new Error("Missing word/document.xml in DOCX package");
1696
+ const xmlStr = strFromU8(docXmlEntry);
1697
+ const parser = new DOMParser();
1698
+ const doc = parser.parseFromString(xmlStr, "application/xml");
1699
+ const card = document.createElement("div");
1700
+ card.className = "fp-docx-page-card";
1701
+ card.style.backgroundColor = "#ffffff";
1702
+ card.style.borderRadius = "6px";
1703
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
1704
+ card.style.padding = "48px 56px";
1705
+ card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1706
+ card.style.color = "#1e293b";
1707
+ card.style.lineHeight = "1.6";
1708
+ const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
1709
+ let html = "";
1710
+ for (const child of Array.from(body.children)) {
1711
+ const tag = child.localName || child.nodeName.split(":").pop();
1712
+ if (tag === "p") {
1713
+ const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
1714
+ const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
1715
+ const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
1716
+ const textContent = this.extractParagraphHtml(child);
1717
+ if (!textContent.trim()) {
1718
+ html += '<div style="height: 10px;"></div>';
1719
+ continue;
1720
+ }
1721
+ const lowerStyle = styleVal.toLowerCase();
1722
+ if (lowerStyle.includes("title")) {
1723
+ html += `<h1 style="font-size: 28px; font-weight: 700; color: #1e3a8a; margin: 24px 0 12px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px;">${textContent}</h1>`;
1724
+ } else if (lowerStyle.includes("heading1") || styleVal === "1") {
1725
+ html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
1726
+ } else if (lowerStyle.includes("heading2") || styleVal === "2") {
1727
+ html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
1728
+ } else if (lowerStyle.includes("heading3") || styleVal === "3") {
1729
+ html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
1730
+ } else if (numPr) {
1731
+ html += `<div style="display: flex; gap: 8px; margin: 4px 0 4px 20px;"><span style="color: #2563eb; font-weight: bold;">\u2022</span><span>${textContent}</span></div>`;
1732
+ } else {
1733
+ html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
1734
+ }
1735
+ } else if (tag === "tbl") {
1736
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
1737
+ const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
1738
+ rows.forEach((tr, rIdx) => {
1739
+ html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
1740
+ const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
1741
+ cells.forEach((tc) => {
1742
+ const cellText = this.extractParagraphHtml(tc);
1743
+ html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
1744
+ });
1745
+ html += "</tr>";
1746
+ });
1747
+ html += "</table>";
1748
+ }
1749
+ }
1750
+ card.innerHTML = DOMPurify6.sanitize(html, {
1751
+ ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "img", "div"],
1752
+ ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
1753
+ });
1754
+ wrapper.appendChild(card);
1755
+ }
1756
+ extractParagraphHtml(pElement) {
1757
+ let result = "";
1758
+ const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
1759
+ if (runs.length === 0) {
1760
+ return DOMPurify6.sanitize(pElement.textContent || "");
1761
+ }
1762
+ for (const r of runs) {
1763
+ const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
1764
+ const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
1765
+ const isItalic = !!rPr?.getElementsByTagNameNS("*", "i")[0];
1766
+ const isUnderline = !!rPr?.getElementsByTagNameNS("*", "u")[0];
1767
+ const colorNode = rPr?.getElementsByTagNameNS("*", "color")[0];
1768
+ const colorVal = colorNode?.getAttribute("w:val") || colorNode?.getAttribute("val");
1769
+ const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
1770
+ let text = texts.map((t) => t.textContent || "").join("");
1771
+ if (!text) continue;
1772
+ text = DOMPurify6.sanitize(text);
1773
+ let styles = "";
1774
+ if (isBold) styles += "font-weight: bold; ";
1775
+ if (isItalic) styles += "font-style: italic; ";
1776
+ if (isUnderline) styles += "text-decoration: underline; ";
1777
+ if (colorVal && colorVal !== "auto") styles += `color: #${colorVal}; `;
1778
+ if (styles) {
1779
+ result += `<span style="${styles}">${text}</span>`;
1780
+ } else {
1781
+ result += text;
1782
+ }
1783
+ }
1784
+ return result;
1785
+ }
1637
1786
  };
1638
1787
  function docxPlugin() {
1639
1788
  return new DocxPlugin();
@@ -2445,7 +2594,7 @@ var MarkdownPlugin = class {
2445
2594
  gfm: true,
2446
2595
  breaks: true
2447
2596
  });
2448
- const cleanHtml = DOMPurify5.sanitize(rawHtml, {
2597
+ const cleanHtml = DOMPurify6.sanitize(rawHtml, {
2449
2598
  USE_PROFILES: { html: true }
2450
2599
  });
2451
2600
  const wrapper = document.createElement("div");
@@ -2609,35 +2758,27 @@ var PptxPlugin = class {
2609
2758
  group: "navigation",
2610
2759
  execute: () => instance.toggleThumbnails?.()
2611
2760
  },
2612
- {
2613
- id: "page-prev",
2614
- icon: "page-prev",
2615
- label: "Previous Slide",
2616
- type: "button",
2617
- group: "navigation",
2618
- execute: () => {
2619
- const cur = instance.getCurrentPage?.() ?? 1;
2620
- if (cur > 1) instance.goToPage?.(cur - 1);
2621
- }
2622
- },
2623
2761
  {
2624
2762
  id: "page-nav",
2625
2763
  icon: "",
2626
- label: "Slide Number",
2764
+ label: "Slide Navigation",
2627
2765
  type: "page-nav",
2628
2766
  group: "navigation",
2629
- execute: (page) => instance.goToPage?.(Number(page))
2630
- },
2631
- {
2632
- id: "page-next",
2633
- icon: "page-next",
2634
- label: "Next Slide",
2635
- type: "button",
2636
- group: "navigation",
2637
- execute: () => {
2638
- const cur = instance.getCurrentPage?.() ?? 1;
2639
- const total = instance.getPageCount?.() ?? 1;
2640
- if (cur < total) instance.goToPage?.(cur + 1);
2767
+ value: instance.getCurrentPage?.() ?? 1,
2768
+ max: instance.getPageCount?.() ?? 1,
2769
+ execute: (action, page) => {
2770
+ if (action === "prev") {
2771
+ const cur = instance.getCurrentPage?.() ?? 1;
2772
+ if (cur > 1) instance.goToPage?.(cur - 1);
2773
+ } else if (action === "next") {
2774
+ const cur = instance.getCurrentPage?.() ?? 1;
2775
+ const total = instance.getPageCount?.() ?? 1;
2776
+ if (cur < total) instance.goToPage?.(cur + 1);
2777
+ } else if (typeof page === "number") {
2778
+ instance.goToPage?.(page);
2779
+ } else if (typeof action === "number") {
2780
+ instance.goToPage?.(action);
2781
+ }
2641
2782
  }
2642
2783
  },
2643
2784
  {
@@ -3168,7 +3309,7 @@ var HtmlPreviewPlugin = class {
3168
3309
  }
3169
3310
  async render(ctx) {
3170
3311
  const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
3171
- const sanitized = DOMPurify5.sanitize(rawHtml, {
3312
+ const sanitized = DOMPurify6.sanitize(rawHtml, {
3172
3313
  WHOLE_DOCUMENT: true,
3173
3314
  ADD_TAGS: ["style", "link"],
3174
3315
  ADD_ATTR: ["target", "rel"]
@@ -3263,35 +3404,27 @@ var OpenDocumentPlugin = class {
3263
3404
  group: "navigation",
3264
3405
  execute: () => instance.toggleThumbnails?.()
3265
3406
  },
3266
- {
3267
- id: "page-prev",
3268
- icon: "page-prev",
3269
- label: "Previous Slide",
3270
- type: "button",
3271
- group: "navigation",
3272
- execute: () => {
3273
- const cur = instance.getCurrentPage?.() ?? 1;
3274
- if (cur > 1) instance.goToPage?.(cur - 1);
3275
- }
3276
- },
3277
3407
  {
3278
3408
  id: "page-nav",
3279
3409
  icon: "",
3280
- label: "Slide Number",
3410
+ label: "Slide Navigation",
3281
3411
  type: "page-nav",
3282
3412
  group: "navigation",
3283
- execute: (p) => instance.goToPage?.(Number(p))
3284
- },
3285
- {
3286
- id: "page-next",
3287
- icon: "page-next",
3288
- label: "Next Slide",
3289
- type: "button",
3290
- group: "navigation",
3291
- execute: () => {
3292
- const cur = instance.getCurrentPage?.() ?? 1;
3293
- const total = instance.getPageCount?.() ?? 1;
3294
- if (cur < total) instance.goToPage?.(cur + 1);
3413
+ value: instance.getCurrentPage?.() ?? 1,
3414
+ max: instance.getPageCount?.() ?? 1,
3415
+ execute: (action, page) => {
3416
+ if (action === "prev") {
3417
+ const cur = instance.getCurrentPage?.() ?? 1;
3418
+ if (cur > 1) instance.goToPage?.(cur - 1);
3419
+ } else if (action === "next") {
3420
+ const cur = instance.getCurrentPage?.() ?? 1;
3421
+ const total = instance.getPageCount?.() ?? 1;
3422
+ if (cur < total) instance.goToPage?.(cur + 1);
3423
+ } else if (typeof page === "number") {
3424
+ instance.goToPage?.(page);
3425
+ } else if (typeof action === "number") {
3426
+ instance.goToPage?.(action);
3427
+ }
3295
3428
  }
3296
3429
  }
3297
3430
  );
@@ -3419,7 +3552,7 @@ var OpenDocumentPlugin = class {
3419
3552
  wrapper.style.padding = "48px";
3420
3553
  wrapper.style.minHeight = "100%";
3421
3554
  const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
3422
- wrapper.innerHTML = DOMPurify5.sanitize(bodyHtml, {
3555
+ wrapper.innerHTML = DOMPurify6.sanitize(bodyHtml, {
3423
3556
  ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
3424
3557
  ADD_ATTR: ["style", "colspan", "rowspan"]
3425
3558
  });
@@ -3939,24 +4072,24 @@ var DocPlugin = class {
3939
4072
  html += "</ul>";
3940
4073
  inList = false;
3941
4074
  }
3942
- html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify5.sanitize(line)}</h2>`;
4075
+ html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line)}</h2>`;
3943
4076
  } else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
3944
4077
  if (!inList) {
3945
4078
  html += '<ul style="margin: 8px 0; padding-left: 24px;">';
3946
4079
  inList = true;
3947
4080
  }
3948
4081
  const bulletText = line.replace(/^[•\-\*]\s*/, "");
3949
- html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify5.sanitize(bulletText)}</li>`;
4082
+ html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify6.sanitize(bulletText)}</li>`;
3950
4083
  } else {
3951
4084
  if (inList) {
3952
4085
  html += "</ul>";
3953
4086
  inList = false;
3954
4087
  }
3955
- html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify5.sanitize(line)}</p>`;
4088
+ html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
3956
4089
  }
3957
4090
  }
3958
4091
  if (inList) html += "</ul>";
3959
- return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify5.sanitize(filename)})</p>`;
4092
+ return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
3960
4093
  }
3961
4094
  };
3962
4095
  function docPlugin() {
@@ -3983,35 +4116,27 @@ var PptPlugin = class {
3983
4116
  group: "navigation",
3984
4117
  execute: () => instance.toggleThumbnails?.()
3985
4118
  },
3986
- {
3987
- id: "page-prev",
3988
- icon: "page-prev",
3989
- label: "Previous Slide",
3990
- type: "button",
3991
- group: "navigation",
3992
- execute: () => {
3993
- const cur = instance.getCurrentPage?.() ?? 1;
3994
- if (cur > 1) instance.goToPage?.(cur - 1);
3995
- }
3996
- },
3997
4119
  {
3998
4120
  id: "page-nav",
3999
4121
  icon: "",
4000
- label: "Slide Number",
4122
+ label: "Slide Navigation",
4001
4123
  type: "page-nav",
4002
4124
  group: "navigation",
4003
- execute: (p) => instance.goToPage?.(Number(p))
4004
- },
4005
- {
4006
- id: "page-next",
4007
- icon: "page-next",
4008
- label: "Next Slide",
4009
- type: "button",
4010
- group: "navigation",
4011
- execute: () => {
4012
- const cur = instance.getCurrentPage?.() ?? 1;
4013
- const total = instance.getPageCount?.() ?? 1;
4014
- if (cur < total) instance.goToPage?.(cur + 1);
4125
+ value: instance.getCurrentPage?.() ?? 1,
4126
+ max: instance.getPageCount?.() ?? 1,
4127
+ execute: (action, page) => {
4128
+ if (action === "prev") {
4129
+ const cur = instance.getCurrentPage?.() ?? 1;
4130
+ if (cur > 1) instance.goToPage?.(cur - 1);
4131
+ } else if (action === "next") {
4132
+ const cur = instance.getCurrentPage?.() ?? 1;
4133
+ const total = instance.getPageCount?.() ?? 1;
4134
+ if (cur < total) instance.goToPage?.(cur + 1);
4135
+ } else if (typeof page === "number") {
4136
+ instance.goToPage?.(page);
4137
+ } else if (typeof action === "number") {
4138
+ instance.goToPage?.(action);
4139
+ }
4015
4140
  }
4016
4141
  },
4017
4142
  {
@@ -4119,10 +4244,10 @@ var PptPlugin = class {
4119
4244
  </div>
4120
4245
  <div style="text-align: center; width: 100%;">
4121
4246
  <h1 style="font-size: ${idx === 1 ? "36px" : "28px"}; color: #1e3a8a; margin: 0 0 24px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-weight: 700;">
4122
- ${DOMPurify5.sanitize(s.title || `Slide ${idx}`)}
4247
+ ${DOMPurify6.sanitize(s.title || `Slide ${idx}`)}
4123
4248
  </h1>
4124
4249
  <div style="display: flex; flex-direction: column; gap: 12px; max-width: 80%; margin: 0 auto; text-align: ${idx === 1 ? "center" : "left"};">
4125
- ${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${DOMPurify5.sanitize(t)}</div>`).join("")}
4250
+ ${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${DOMPurify6.sanitize(t)}</div>`).join("")}
4126
4251
  </div>
4127
4252
  </div>
4128
4253
  `;