@ai-matrx/print 0.2.0 → 0.3.1
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 +107 -0
- package/README.md +44 -2
- package/dist/booklet.cjs +6 -5
- package/dist/booklet.cjs.map +1 -1
- package/dist/booklet.d.cts +4 -1
- package/dist/booklet.d.ts +4 -1
- package/dist/booklet.js +6 -5
- package/dist/booklet.js.map +1 -1
- package/dist/core.cjs +6 -5
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +25 -4
- package/dist/core.d.ts +25 -4
- package/dist/core.js +6 -5
- package/dist/core.js.map +1 -1
- package/dist/flashcards.cjs +18 -65
- package/dist/flashcards.cjs.map +1 -1
- package/dist/flashcards.js +18 -65
- package/dist/flashcards.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/labels.cjs +10 -11
- package/dist/labels.cjs.map +1 -1
- package/dist/labels.d.cts +3 -3
- package/dist/labels.d.ts +3 -3
- package/dist/labels.js +10 -11
- package/dist/labels.js.map +1 -1
- package/dist/markdown.cjs +1260 -0
- package/dist/markdown.cjs.map +1 -0
- package/dist/markdown.d.cts +177 -0
- package/dist/markdown.d.ts +177 -0
- package/dist/markdown.js +1237 -0
- package/dist/markdown.js.map +1 -0
- package/dist/pdf.cjs +77 -4
- package/dist/pdf.cjs.map +1 -1
- package/dist/pdf.d.cts +35 -9
- package/dist/pdf.d.ts +35 -9
- package/dist/pdf.js +77 -4
- package/dist/pdf.js.map +1 -1
- package/dist/react.cjs +23 -18
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +26 -3
- package/dist/react.d.ts +26 -3
- package/dist/react.js +23 -18
- package/dist/react.js.map +1 -1
- package/package.json +12 -2
package/dist/react.d.cts
CHANGED
|
@@ -109,9 +109,25 @@ interface BlockPrinter {
|
|
|
109
109
|
* data — the block's structured data (serverData or parsed content)
|
|
110
110
|
* variantId — which variant was chosen (undefined = default / no variants)
|
|
111
111
|
* settings — resolved setting values chosen by the user
|
|
112
|
+
*
|
|
113
|
+
* MAY resolve to a PrintOutcome ("opened" | "downloaded") so the host can
|
|
114
|
+
* tell the user when the popup-blocked download fallback fired; `void`
|
|
115
|
+
* stays legal for printers that don't go through a print window.
|
|
112
116
|
*/
|
|
113
|
-
print: (data: unknown, variantId?: string, settings?: PrintSettings) => void | Promise<void>;
|
|
117
|
+
print: (data: unknown, variantId?: string, settings?: PrintSettings) => void | PrintOutcome | Promise<void | PrintOutcome>;
|
|
114
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* How a print request actually reached the user.
|
|
121
|
+
*
|
|
122
|
+
* "opened" — a print window/tab was opened and the document written into it.
|
|
123
|
+
* "downloaded" — the popup was blocked, so the document was downloaded as an
|
|
124
|
+
* .html file instead (the contract's fallback). Hosts SHOULD
|
|
125
|
+
* surface this to the user (e.g. a toast saying the print file
|
|
126
|
+
* was downloaded) — a blocked popup plus a silent download is
|
|
127
|
+
* indistinguishable from "nothing happened", which is exactly
|
|
128
|
+
* how QA filed it (2026-08-30, F5/F6/F8).
|
|
129
|
+
*/
|
|
130
|
+
type PrintOutcome = "opened" | "downloaded";
|
|
115
131
|
|
|
116
132
|
/**
|
|
117
133
|
* @ai-matrx/print/labels — the label-sheet engine.
|
|
@@ -258,18 +274,25 @@ interface PrintOptionsDialogProps {
|
|
|
258
274
|
data: unknown;
|
|
259
275
|
open: boolean;
|
|
260
276
|
onOpenChange: (open: boolean) => void;
|
|
277
|
+
/**
|
|
278
|
+
* Fired after printer.print() settles, with the PrintOutcome when the
|
|
279
|
+
* printer reports one. "downloaded" means the popup was blocked and the
|
|
280
|
+
* print document was saved as an .html download instead — hosts should
|
|
281
|
+
* toast that, or the fallback is indistinguishable from nothing happening.
|
|
282
|
+
*/
|
|
283
|
+
onPrinted?: (outcome: void | PrintOutcome) => void;
|
|
261
284
|
}
|
|
262
285
|
/**
|
|
263
286
|
* Shared pre-print options UI — shown when a BlockPrinter has variants or settings.
|
|
264
287
|
* Desktop: Dialog. Mobile: Drawer (bottom sheet).
|
|
265
288
|
*/
|
|
266
|
-
declare function PrintOptionsDialog({ printer, data, open, onOpenChange, }: PrintOptionsDialogProps): React.JSX.Element;
|
|
289
|
+
declare function PrintOptionsDialog({ printer, data, open, onOpenChange, onPrinted, }: PrintOptionsDialogProps): React.JSX.Element;
|
|
267
290
|
/**
|
|
268
291
|
* Manages open state for PrintOptionsDialog.
|
|
269
292
|
* If the printer has variants or settings, shows the dialog.
|
|
270
293
|
* If it has neither, calls printer.print() immediately with no settings.
|
|
271
294
|
*/
|
|
272
|
-
declare function usePrintOptions(printer: BlockPrinter | null, data: unknown): {
|
|
295
|
+
declare function usePrintOptions(printer: BlockPrinter | null, data: unknown, onPrinted?: (outcome: void | PrintOutcome) => void): {
|
|
273
296
|
open: boolean;
|
|
274
297
|
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
|
275
298
|
triggerPrint: () => Promise<void>;
|
package/dist/react.d.ts
CHANGED
|
@@ -109,9 +109,25 @@ interface BlockPrinter {
|
|
|
109
109
|
* data — the block's structured data (serverData or parsed content)
|
|
110
110
|
* variantId — which variant was chosen (undefined = default / no variants)
|
|
111
111
|
* settings — resolved setting values chosen by the user
|
|
112
|
+
*
|
|
113
|
+
* MAY resolve to a PrintOutcome ("opened" | "downloaded") so the host can
|
|
114
|
+
* tell the user when the popup-blocked download fallback fired; `void`
|
|
115
|
+
* stays legal for printers that don't go through a print window.
|
|
112
116
|
*/
|
|
113
|
-
print: (data: unknown, variantId?: string, settings?: PrintSettings) => void | Promise<void>;
|
|
117
|
+
print: (data: unknown, variantId?: string, settings?: PrintSettings) => void | PrintOutcome | Promise<void | PrintOutcome>;
|
|
114
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* How a print request actually reached the user.
|
|
121
|
+
*
|
|
122
|
+
* "opened" — a print window/tab was opened and the document written into it.
|
|
123
|
+
* "downloaded" — the popup was blocked, so the document was downloaded as an
|
|
124
|
+
* .html file instead (the contract's fallback). Hosts SHOULD
|
|
125
|
+
* surface this to the user (e.g. a toast saying the print file
|
|
126
|
+
* was downloaded) — a blocked popup plus a silent download is
|
|
127
|
+
* indistinguishable from "nothing happened", which is exactly
|
|
128
|
+
* how QA filed it (2026-08-30, F5/F6/F8).
|
|
129
|
+
*/
|
|
130
|
+
type PrintOutcome = "opened" | "downloaded";
|
|
115
131
|
|
|
116
132
|
/**
|
|
117
133
|
* @ai-matrx/print/labels — the label-sheet engine.
|
|
@@ -258,18 +274,25 @@ interface PrintOptionsDialogProps {
|
|
|
258
274
|
data: unknown;
|
|
259
275
|
open: boolean;
|
|
260
276
|
onOpenChange: (open: boolean) => void;
|
|
277
|
+
/**
|
|
278
|
+
* Fired after printer.print() settles, with the PrintOutcome when the
|
|
279
|
+
* printer reports one. "downloaded" means the popup was blocked and the
|
|
280
|
+
* print document was saved as an .html download instead — hosts should
|
|
281
|
+
* toast that, or the fallback is indistinguishable from nothing happening.
|
|
282
|
+
*/
|
|
283
|
+
onPrinted?: (outcome: void | PrintOutcome) => void;
|
|
261
284
|
}
|
|
262
285
|
/**
|
|
263
286
|
* Shared pre-print options UI — shown when a BlockPrinter has variants or settings.
|
|
264
287
|
* Desktop: Dialog. Mobile: Drawer (bottom sheet).
|
|
265
288
|
*/
|
|
266
|
-
declare function PrintOptionsDialog({ printer, data, open, onOpenChange, }: PrintOptionsDialogProps): React.JSX.Element;
|
|
289
|
+
declare function PrintOptionsDialog({ printer, data, open, onOpenChange, onPrinted, }: PrintOptionsDialogProps): React.JSX.Element;
|
|
267
290
|
/**
|
|
268
291
|
* Manages open state for PrintOptionsDialog.
|
|
269
292
|
* If the printer has variants or settings, shows the dialog.
|
|
270
293
|
* If it has neither, calls printer.print() immediately with no settings.
|
|
271
294
|
*/
|
|
272
|
-
declare function usePrintOptions(printer: BlockPrinter | null, data: unknown): {
|
|
295
|
+
declare function usePrintOptions(printer: BlockPrinter | null, data: unknown, onPrinted?: (outcome: void | PrintOutcome) => void): {
|
|
273
296
|
open: boolean;
|
|
274
297
|
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
|
275
298
|
triggerPrint: () => Promise<void>;
|
package/dist/react.js
CHANGED
|
@@ -11,8 +11,8 @@ import { twMerge } from "tailwind-merge";
|
|
|
11
11
|
function escapeHtml(str) {
|
|
12
12
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
13
13
|
}
|
|
14
|
-
function openPrintWindow(htmlDocument, filename = "print") {
|
|
15
|
-
const win = window.open("", "_blank",
|
|
14
|
+
function openPrintWindow(htmlDocument, filename = "print", windowFeatures = "width=920,height=720,scrollbars=yes") {
|
|
15
|
+
const win = window.open("", "_blank", windowFeatures);
|
|
16
16
|
if (!win) {
|
|
17
17
|
const blob = new Blob([htmlDocument], { type: "text/html;charset=utf-8" });
|
|
18
18
|
const url = URL.createObjectURL(blob);
|
|
@@ -22,12 +22,13 @@ function openPrintWindow(htmlDocument, filename = "print") {
|
|
|
22
22
|
document.body.appendChild(a);
|
|
23
23
|
a.click();
|
|
24
24
|
document.body.removeChild(a);
|
|
25
|
-
URL.revokeObjectURL(url);
|
|
26
|
-
return;
|
|
25
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
26
|
+
return "downloaded";
|
|
27
27
|
}
|
|
28
28
|
win.document.open();
|
|
29
29
|
win.document.write(htmlDocument);
|
|
30
30
|
win.document.close();
|
|
31
|
+
return "opened";
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
// src/qr.ts
|
|
@@ -555,7 +556,7 @@ ${bodyHtml}
|
|
|
555
556
|
${withFitScript ? LP_FIT_SCRIPT : ""}
|
|
556
557
|
</body>
|
|
557
558
|
</html>`;
|
|
558
|
-
openPrintWindow(html, title);
|
|
559
|
+
return openPrintWindow(html, title);
|
|
559
560
|
}
|
|
560
561
|
function expandLabels(labels, s) {
|
|
561
562
|
const from = s.rangeFrom > 0 ? s.rangeFrom : 1;
|
|
@@ -593,7 +594,7 @@ function buildCalibrationBody(t) {
|
|
|
593
594
|
return `<div class="lp-page">${banner}${marks}${cells.join("\n")}</div>`;
|
|
594
595
|
}
|
|
595
596
|
function printCalibrationSheet(template) {
|
|
596
|
-
openSheetWindow(
|
|
597
|
+
return openSheetWindow(
|
|
597
598
|
template,
|
|
598
599
|
buildCalibrationBody(template),
|
|
599
600
|
"Label calibration",
|
|
@@ -660,18 +661,16 @@ async function printQrLabelSheet(data, variantId, rawSettings) {
|
|
|
660
661
|
const t = resolveTemplate(data, variantId);
|
|
661
662
|
const s = resolveSettings(rawSettings);
|
|
662
663
|
if (s.calibrationPage) {
|
|
663
|
-
printCalibrationSheet(t);
|
|
664
|
-
return;
|
|
664
|
+
return printCalibrationSheet(t);
|
|
665
665
|
}
|
|
666
666
|
const labels = expandLabels(data.labels ?? [], s);
|
|
667
667
|
if (!labels.length) {
|
|
668
|
-
openSheetWindow(
|
|
668
|
+
return openSheetWindow(
|
|
669
669
|
t,
|
|
670
670
|
`<div class="lp-page"><div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#94a3b8;font-size:11pt;">No labels to print.</div></div>`,
|
|
671
671
|
"QR labels",
|
|
672
672
|
false
|
|
673
673
|
);
|
|
674
|
-
return;
|
|
675
674
|
}
|
|
676
675
|
const hasBadge = labels.some((l) => (l.badge ?? "").trim() !== "");
|
|
677
676
|
const layout = computeCellLayout(t, s.showCaption, hasBadge);
|
|
@@ -701,7 +700,7 @@ async function printQrLabelSheet(data, variantId, rawSettings) {
|
|
|
701
700
|
const tail = cells.length % perPage;
|
|
702
701
|
if (tail > 0)
|
|
703
702
|
for (let i = 0; i < perPage - tail; i++) cells.push({ html: "" });
|
|
704
|
-
openSheetWindow(
|
|
703
|
+
return openSheetWindow(
|
|
705
704
|
t,
|
|
706
705
|
renderPages(t, cells),
|
|
707
706
|
"QR labels",
|
|
@@ -1101,7 +1100,8 @@ function visibleSettings(settings, variantId) {
|
|
|
1101
1100
|
function PrintOptionsContent({
|
|
1102
1101
|
printer,
|
|
1103
1102
|
data,
|
|
1104
|
-
onClose
|
|
1103
|
+
onClose,
|
|
1104
|
+
onPrinted
|
|
1105
1105
|
}) {
|
|
1106
1106
|
const [selectedVariant, setSelectedVariant] = useState(
|
|
1107
1107
|
printer.variants[0]?.id ?? ""
|
|
@@ -1125,7 +1125,8 @@ function PrintOptionsContent({
|
|
|
1125
1125
|
setIsPrinting(true);
|
|
1126
1126
|
try {
|
|
1127
1127
|
const settings = useDefaults ? buildDefaultSettings(allSettings) : settingValues;
|
|
1128
|
-
await printer.print(data, variantId, settings);
|
|
1128
|
+
const outcome = await printer.print(data, variantId, settings);
|
|
1129
|
+
onPrinted?.(outcome);
|
|
1129
1130
|
} finally {
|
|
1130
1131
|
setIsPrinting(false);
|
|
1131
1132
|
onClose();
|
|
@@ -1353,7 +1354,8 @@ function PrintOptionsDialog({
|
|
|
1353
1354
|
printer,
|
|
1354
1355
|
data,
|
|
1355
1356
|
open,
|
|
1356
|
-
onOpenChange
|
|
1357
|
+
onOpenChange,
|
|
1358
|
+
onPrinted
|
|
1357
1359
|
}) {
|
|
1358
1360
|
const isMobile = useIsMobile();
|
|
1359
1361
|
const handleClose = () => onOpenChange(false);
|
|
@@ -1380,7 +1382,8 @@ function PrintOptionsDialog({
|
|
|
1380
1382
|
{
|
|
1381
1383
|
printer,
|
|
1382
1384
|
data,
|
|
1383
|
-
onClose: handleClose
|
|
1385
|
+
onClose: handleClose,
|
|
1386
|
+
onPrinted
|
|
1384
1387
|
}
|
|
1385
1388
|
) })
|
|
1386
1389
|
] }) });
|
|
@@ -1398,18 +1401,20 @@ function PrintOptionsDialog({
|
|
|
1398
1401
|
{
|
|
1399
1402
|
printer,
|
|
1400
1403
|
data,
|
|
1401
|
-
onClose: handleClose
|
|
1404
|
+
onClose: handleClose,
|
|
1405
|
+
onPrinted
|
|
1402
1406
|
}
|
|
1403
1407
|
) })
|
|
1404
1408
|
] }) });
|
|
1405
1409
|
}
|
|
1406
|
-
function usePrintOptions(printer, data) {
|
|
1410
|
+
function usePrintOptions(printer, data, onPrinted) {
|
|
1407
1411
|
const [open, setOpen] = useState(false);
|
|
1408
1412
|
const triggerPrint = async () => {
|
|
1409
1413
|
if (!printer) return;
|
|
1410
1414
|
const hasOptions = printer.variants.length > 0 || (printer.settings?.length ?? 0) > 0;
|
|
1411
1415
|
if (!hasOptions) {
|
|
1412
|
-
await printer.print(data);
|
|
1416
|
+
const outcome = await printer.print(data);
|
|
1417
|
+
onPrinted?.(outcome);
|
|
1413
1418
|
} else {
|
|
1414
1419
|
setOpen(true);
|
|
1415
1420
|
}
|