@ai-matrx/print 0.8.65 → 0.8.67

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.d.cts CHANGED
@@ -366,6 +366,17 @@ interface DocumentPrintPreviewProps {
366
366
  * (e.g. `[@research:<id>]`, `[@file:<id>]`) to CSL-JSON references.
367
367
  */
368
368
  resolveReferences?: (keys: string[]) => Promise<CslItem[]>;
369
+ /**
370
+ * Draws the PDF pages when the browser cannot show a PDF inline (Chrome
371
+ * with "Download PDFs" on, Android, touch devices). Receives a same-origin
372
+ * `blob:` URL of the exact PDF. Without it, such browsers get the Web view.
373
+ */
374
+ renderPages?: (pdfUrl: string) => React.ReactNode;
375
+ /**
376
+ * Prints the PDF's pages when the browser has no inline PDF viewer to print
377
+ * from. Without it, Print prints the Web view.
378
+ */
379
+ printPages?: (pdfUrl: string) => Promise<void>;
369
380
  }
370
381
  /**
371
382
  * Print preview for a markdown document: the real PDF (the same file the PDF
@@ -374,6 +385,6 @@ interface DocumentPrintPreviewProps {
374
385
  * HTML and Markdown. Everything comes from one parsed tree, so what you see
375
386
  * is what every format contains. Engines load lazily on mount.
376
387
  */
377
- declare function DocumentPrintPreview({ markdown, title, className, onNotice, resolveReferences }: DocumentPrintPreviewProps): React.JSX.Element;
388
+ declare function DocumentPrintPreview({ markdown, title, className, onNotice, resolveReferences, renderPages, printPages, }: DocumentPrintPreviewProps): React.JSX.Element;
378
389
 
379
390
  export { DocumentPrintPreview, type DocumentPrintPreviewProps, LabelSheetPreview, type LabelSheetPreviewProps, PrintOptionsDialog, type PrintOptionsDialogProps, usePrintOptions };
package/dist/react.d.ts CHANGED
@@ -366,6 +366,17 @@ interface DocumentPrintPreviewProps {
366
366
  * (e.g. `[@research:<id>]`, `[@file:<id>]`) to CSL-JSON references.
367
367
  */
368
368
  resolveReferences?: (keys: string[]) => Promise<CslItem[]>;
369
+ /**
370
+ * Draws the PDF pages when the browser cannot show a PDF inline (Chrome
371
+ * with "Download PDFs" on, Android, touch devices). Receives a same-origin
372
+ * `blob:` URL of the exact PDF. Without it, such browsers get the Web view.
373
+ */
374
+ renderPages?: (pdfUrl: string) => React.ReactNode;
375
+ /**
376
+ * Prints the PDF's pages when the browser has no inline PDF viewer to print
377
+ * from. Without it, Print prints the Web view.
378
+ */
379
+ printPages?: (pdfUrl: string) => Promise<void>;
369
380
  }
370
381
  /**
371
382
  * Print preview for a markdown document: the real PDF (the same file the PDF
@@ -374,6 +385,6 @@ interface DocumentPrintPreviewProps {
374
385
  * HTML and Markdown. Everything comes from one parsed tree, so what you see
375
386
  * is what every format contains. Engines load lazily on mount.
376
387
  */
377
- declare function DocumentPrintPreview({ markdown, title, className, onNotice, resolveReferences }: DocumentPrintPreviewProps): React.JSX.Element;
388
+ declare function DocumentPrintPreview({ markdown, title, className, onNotice, resolveReferences, renderPages, printPages, }: DocumentPrintPreviewProps): React.JSX.Element;
378
389
 
379
390
  export { DocumentPrintPreview, type DocumentPrintPreviewProps, LabelSheetPreview, type LabelSheetPreviewProps, PrintOptionsDialog, type PrintOptionsDialogProps, usePrintOptions };
package/dist/react.js CHANGED
@@ -1553,6 +1553,32 @@ function LabelSheetPreview({
1553
1553
  }
1554
1554
  );
1555
1555
  }
1556
+ function hasInlinePdfViewer() {
1557
+ if (typeof navigator === "undefined") return true;
1558
+ if (navigator.pdfViewerEnabled === false) return false;
1559
+ return !(typeof window !== "undefined" && window.matchMedia?.("(pointer: coarse)").matches);
1560
+ }
1561
+ function printHtml(html) {
1562
+ const frame = document.createElement("iframe");
1563
+ frame.setAttribute("aria-hidden", "true");
1564
+ frame.style.cssText = "position:fixed;right:0;bottom:0;width:0;height:0;border:0;";
1565
+ document.body.appendChild(frame);
1566
+ const win = frame.contentWindow;
1567
+ if (!win) {
1568
+ frame.remove();
1569
+ throw new Error("Printing is blocked in this browser.");
1570
+ }
1571
+ win.document.open();
1572
+ win.document.write(html);
1573
+ win.document.close();
1574
+ const run = () => {
1575
+ win.focus();
1576
+ win.print();
1577
+ setTimeout(() => frame.remove(), 1e3);
1578
+ };
1579
+ if (win.document.readyState === "complete") setTimeout(run, 50);
1580
+ else win.addEventListener("load", run, { once: true });
1581
+ }
1556
1582
  var EXPORT_BUTTONS = [
1557
1583
  { format: "pdf", label: "PDF" },
1558
1584
  { format: "docx", label: "Word" },
@@ -1560,8 +1586,18 @@ var EXPORT_BUTTONS = [
1560
1586
  { format: "html", label: "HTML" },
1561
1587
  { format: "markdown", label: "Markdown" }
1562
1588
  ];
1563
- function DocumentPrintPreview({ markdown, title, className, onNotice, resolveReferences }) {
1564
- const [view, setView] = useState("pages");
1589
+ function DocumentPrintPreview({
1590
+ markdown,
1591
+ title,
1592
+ className,
1593
+ onNotice,
1594
+ resolveReferences,
1595
+ renderPages: renderPages2,
1596
+ printPages
1597
+ }) {
1598
+ const [inlineViewer] = useState(hasInlinePdfViewer);
1599
+ const canShowPages = inlineViewer || Boolean(renderPages2);
1600
+ const [view, setView] = useState(canShowPages ? "pages" : "web");
1565
1601
  const [pdf, setPdf] = useState(null);
1566
1602
  const [html, setHtml] = useState("");
1567
1603
  const [notices, setNotices] = useState([]);
@@ -1623,18 +1659,23 @@ function DocumentPrintPreview({ markdown, title, className, onNotice, resolveRef
1623
1659
  setBusy(null);
1624
1660
  }
1625
1661
  };
1626
- const print = () => {
1662
+ const print = async () => {
1627
1663
  if (!pdf) return;
1628
1664
  try {
1629
- frameRef.current?.contentWindow?.print();
1630
- } catch {
1631
- window.open(pdf.url, "_blank", "noopener");
1665
+ if (inlineViewer && frameRef.current?.contentWindow) {
1666
+ frameRef.current.contentWindow.print();
1667
+ return;
1668
+ }
1669
+ if (printPages) await printPages(pdf.url);
1670
+ else printHtml(html);
1671
+ } catch (err) {
1672
+ setError(`Print failed: ${err instanceof Error ? err.message : String(err)}`);
1632
1673
  }
1633
1674
  };
1634
1675
  const btn = "inline-flex h-7 items-center gap-1 rounded-md border border-border bg-background px-2.5 text-xs font-medium text-foreground hover:bg-accent disabled:opacity-50";
1635
1676
  return /* @__PURE__ */ jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col", className), "data-testid": "document-print-preview", children: [
1636
1677
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-border px-3 py-1.5 text-xs", children: [
1637
- /* @__PURE__ */ jsx("div", { className: "inline-flex overflow-hidden rounded-md border border-border", role: "tablist", children: ["pages", "web"].map((v) => /* @__PURE__ */ jsx(
1678
+ /* @__PURE__ */ jsx("div", { className: "inline-flex overflow-hidden rounded-md border border-border", role: "tablist", children: (canShowPages ? ["pages", "web"] : ["web"]).map((v) => /* @__PURE__ */ jsx(
1638
1679
  "button",
1639
1680
  {
1640
1681
  type: "button",
@@ -1648,7 +1689,7 @@ function DocumentPrintPreview({ markdown, title, className, onNotice, resolveRef
1648
1689
  )) }),
1649
1690
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "data-testid": "document-print-summary", children: busy === "render" && !pdf ? "Laying out pages\u2026" : `${pdf?.pages ?? 0} page${pdf?.pages === 1 ? "" : "s"}${summary ? ` \xB7 ${summary}` : ""}` }),
1650
1691
  /* @__PURE__ */ jsxs("div", { className: "ml-auto flex flex-wrap items-center gap-1.5", children: [
1651
- /* @__PURE__ */ jsx("button", { type: "button", className: btn, onClick: print, disabled: !pdf, children: "Print" }),
1692
+ /* @__PURE__ */ jsx("button", { type: "button", className: btn, onClick: () => void print(), disabled: !pdf, children: "Print" }),
1652
1693
  EXPORT_BUTTONS.map((b) => /* @__PURE__ */ jsx("button", { type: "button", className: btn, onClick: () => void download(b.format), disabled: busy === b.format, children: busy === b.format ? "Saving\u2026" : b.label }, b.format))
1653
1694
  ] })
1654
1695
  ] }),
@@ -1666,7 +1707,7 @@ function DocumentPrintPreview({ markdown, title, className, onNotice, resolveRef
1666
1707
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: n.remedy })
1667
1708
  ] }, i)) })
1668
1709
  ] }),
1669
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-muted/40", children: view === "pages" ? pdf ? /* @__PURE__ */ jsx("iframe", { ref: frameRef, title: "Print preview", src: pdf.url, className: "h-full min-h-[480px] w-full border-0" }) : /* @__PURE__ */ jsx("p", { className: "p-8 text-center text-xs text-muted-foreground", children: error ? "No preview." : "Laying out pages\u2026" }) : /* @__PURE__ */ jsx("iframe", { title: "Web preview", srcDoc: html, sandbox: "allow-same-origin", className: "h-full min-h-[480px] w-full border-0 bg-white" }) })
1710
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-muted/40", children: view === "pages" ? pdf ? inlineViewer ? /* @__PURE__ */ jsx("iframe", { ref: frameRef, title: "Print preview", src: pdf.url, className: "h-full min-h-[480px] w-full border-0" }) : /* @__PURE__ */ jsx("div", { className: "h-full min-h-[480px] w-full", children: renderPages2?.(pdf.url) }) : /* @__PURE__ */ jsx("p", { className: "p-8 text-center text-xs text-muted-foreground", children: error ? "No preview." : "Laying out pages\u2026" }) : /* @__PURE__ */ jsx("iframe", { title: "Web preview", srcDoc: html, sandbox: "allow-same-origin", className: "h-full min-h-[480px] w-full border-0 bg-white" }) })
1670
1711
  ] });
1671
1712
  }
1672
1713
  export {