@ai-matrx/print 0.1.0
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 +56 -0
- package/LICENSE +21 -0
- package/README.md +141 -0
- package/dist/core.cjs +184 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +139 -0
- package/dist/core.d.ts +139 -0
- package/dist/core.js +163 -0
- package/dist/core.js.map +1 -0
- package/dist/flashcards.cjs +1709 -0
- package/dist/flashcards.cjs.map +1 -0
- package/dist/flashcards.d.cts +35 -0
- package/dist/flashcards.d.ts +35 -0
- package/dist/flashcards.js +1686 -0
- package/dist/flashcards.js.map +1 -0
- package/dist/index.cjs +19 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/labels.cjs +1035 -0
- package/dist/labels.cjs.map +1 -0
- package/dist/labels.d.cts +270 -0
- package/dist/labels.d.ts +270 -0
- package/dist/labels.js +1002 -0
- package/dist/labels.js.map +1 -0
- package/dist/pdf.cjs +325 -0
- package/dist/pdf.cjs.map +1 -0
- package/dist/pdf.d.cts +151 -0
- package/dist/pdf.d.ts +151 -0
- package/dist/pdf.js +294 -0
- package/dist/pdf.js.map +1 -0
- package/dist/qr.cjs +328 -0
- package/dist/qr.cjs.map +1 -0
- package/dist/qr.d.cts +91 -0
- package/dist/qr.d.ts +91 -0
- package/dist/qr.js +297 -0
- package/dist/qr.js.map +1 -0
- package/dist/react.cjs +1569 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +301 -0
- package/dist/react.d.ts +301 -0
- package/dist/react.js +1539 -0
- package/dist/react.js.map +1 -0
- package/package.json +163 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — 2026-08-29
|
|
4
|
+
|
|
5
|
+
First release. Extracted from the AI Matrx frontend's print system with
|
|
6
|
+
behavior-verbatim ports; only coupling seams were inverted (structural types,
|
|
7
|
+
injected markdown converter, bundled dialog primitives).
|
|
8
|
+
|
|
9
|
+
- **/core** — the `BlockPrinter` contract (boolean/range/number/select
|
|
10
|
+
settings), `buildPrintDocument` / `openPrintWindow` (popup-blocked → .html
|
|
11
|
+
download fallback) / `printHtmlContent` / `escapeHtml`, and
|
|
12
|
+
`buildFitTextScript` (the shared in-window auto-shrink loop).
|
|
13
|
+
- **/qr** — QR generation: PNG data URL + SVG lanes (lazy `qrcode`), ECC
|
|
14
|
+
default **M**, quiet zone clamped to the ISO minimum of 4 modules, symbol
|
|
15
|
+
math (`minQrVersion`, `qrModuleCount`, `qrByteCapacity` — byte-mode
|
|
16
|
+
capacity table verified against the reference encoder), and payload
|
|
17
|
+
builders: `buildShortResolverUrl` (opaque server-minted codes) and
|
|
18
|
+
`buildGs1DigitalLink` (GTIN check-digit validation; AI 17 as a query
|
|
19
|
+
attribute).
|
|
20
|
+
- **/labels** — the label engine: template registry (Avery 5160/8160,
|
|
21
|
+
5163/8163, 5164/8164, 22806, 22807 + custom), NEW roll formats
|
|
22
|
+
(Brother DK-1202/DK-11201, DYMO 30252, 4×6″ thermal), `startAtLabel` /
|
|
23
|
+
`copiesPerCode` / ranges / EC select, 300 dpi inlined data-URI QRs with
|
|
24
|
+
spec quiet zones, `print-color-adjust: exact`, calibration sheets, jsPDF
|
|
25
|
+
download lane, NEW `LabelFormat` custom-format model (`qr`/`text` with
|
|
26
|
+
title/detail/badge roles/`image` elements; presets `qr-only`, `qr-caption`,
|
|
27
|
+
`garment`, `asset-spec`; `badge` renders large in all lanes), and NEW
|
|
28
|
+
`assertScannable` (module-density validator wired into the print/PDF lanes
|
|
29
|
+
as a non-blocking warning).
|
|
30
|
+
- **/flashcards** — the deck printer, all 10 variants (portrait 6-up +
|
|
31
|
+
landscape 4-up duplex-mirrored/stacked, Avery 5388, cut-cards, both-sides,
|
|
32
|
+
study-sheet, front-only, back-only) with card ranges, cut guides, and
|
|
33
|
+
show-through countermeasures. Face images print from durable URLs only.
|
|
34
|
+
- **/pdf** — DOM-capture → PDF (html2canvas + jsPDF, lazy), the oklch/lab
|
|
35
|
+
`getComputedStyle` compatibility patch, paginated and continuous lanes,
|
|
36
|
+
Blob variants, `markdownToPdfBlob(markdown, { convertToHtml, loadCss })`
|
|
37
|
+
with the converter injected.
|
|
38
|
+
- **/react** — `PrintOptionsDialog` (+ `usePrintOptions`) over bundled Radix
|
|
39
|
+
dialog / vaul drawer with inlined icons, and `LabelSheetPreview`.
|
|
40
|
+
|
|
41
|
+
Deliberate divergences from the originals (defects fixed in the port — the
|
|
42
|
+
originals die at the adoption swap):
|
|
43
|
+
|
|
44
|
+
- flashcards: the "all fronts, then all backs" stacked variants actually
|
|
45
|
+
interleaved front/back pages per batch on decks larger than one page;
|
|
46
|
+
they now match their documented behavior.
|
|
47
|
+
- pdf: `patchGetComputedStyle` permanently stacked a `.bind` wrapper per
|
|
48
|
+
capture instead of restoring the original function; `captureToPDF` ignored
|
|
49
|
+
`imageFormat`/`imageQuality`; `captureToClipboardImage` resolved before its
|
|
50
|
+
clipboard/download work finished.
|
|
51
|
+
- labels: the Avery 22806/22807 rows did not tile the sheet (labels drifted
|
|
52
|
+
0.375″ per column off the die-cut) — corrected to Avery's published 2.75″
|
|
53
|
+
pitch; `customLabelTemplate` let an explicit `undefined` clobber its
|
|
54
|
+
defaults; the template registry is now immutable; the dev-time geometry
|
|
55
|
+
check no longer reads `process.env` bare (which would throw in browser
|
|
56
|
+
consumers).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AI Matrix Engine
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# @ai-matrx/print
|
|
2
|
+
|
|
3
|
+
The AI Matrx print system — everything a browser app needs to turn structured
|
|
4
|
+
content into paper: a tiny print contract, print-window composition, QR
|
|
5
|
+
generation with e-commerce payload builders, label-sheet printing on Avery and
|
|
6
|
+
roll stock with custom label formats, a full flashcard deck printer, and
|
|
7
|
+
DOM-capture/markdown → PDF.
|
|
8
|
+
|
|
9
|
+
Every entry is import-inert and safe to import during SSR — browser APIs are
|
|
10
|
+
touched only when you call something. `/react` is the only React entry (a
|
|
11
|
+
client component entry); everything else is framework-free.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @ai-matrx/print
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
React ≥18 is an optional peer, needed only for `@ai-matrx/print/react`.
|
|
20
|
+
|
|
21
|
+
## Entries
|
|
22
|
+
|
|
23
|
+
### `@ai-matrx/print` — types only
|
|
24
|
+
|
|
25
|
+
`BlockPrinter`, `PrintVariant`, `PrintSetting`, `PrintSettings`,
|
|
26
|
+
`LabelTemplate`, `LabelFormat`, `QrEcLevel`, `Flashcard`, … — the shared
|
|
27
|
+
vocabulary, no runtime.
|
|
28
|
+
|
|
29
|
+
### `@ai-matrx/print/core` — the print contract & window composition
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { buildPrintDocument, openPrintWindow, printHtmlContent, escapeHtml, buildFitTextScript } from "@ai-matrx/print/core";
|
|
33
|
+
|
|
34
|
+
printHtmlContent("<h1>Report</h1><table>…</table>", "Q3 Report");
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`BlockPrinter` is the one interface a host needs: `label`, `variants`,
|
|
38
|
+
optional `settings` (boolean / range / number / select), and
|
|
39
|
+
`print(data, variantId, settings)`. `openPrintWindow` opens a styled window
|
|
40
|
+
with Print / Close actions and falls back to an `.html` download when the
|
|
41
|
+
popup is blocked. `buildFitTextScript(selectors)` returns the in-window
|
|
42
|
+
auto-shrink script (0.5pt steps, 6pt floor) used by the flashcards engine.
|
|
43
|
+
|
|
44
|
+
### `@ai-matrx/print/qr` — QR generation (not decoding)
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { generateQrDataUrl, generateQrSvg, minQrVersion, buildShortResolverUrl, buildGs1DigitalLink } from "@ai-matrx/print/qr";
|
|
48
|
+
|
|
49
|
+
const url = buildShortResolverUrl({ origin: "https://yourbrand.com", code: "a1B2c3" }); // https://yourbrand.com/l/a1B2c3
|
|
50
|
+
const png = await generateQrDataUrl(url); // ECC "M", ≥4-module quiet zone — both enforced defaults
|
|
51
|
+
const gs1 = buildGs1DigitalLink({ origin: "https://id.yourbrand.com", gtin: "4006381333931", lot: "L42", serial: "S1001", expiry: "271231" });
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Error correction defaults to **M** (never L — scuffed labels need margin) and
|
|
55
|
+
the quiet zone is clamped to the ISO minimum of 4 modules. The code value in
|
|
56
|
+
`buildShortResolverUrl` is an opaque input — mint identities server-side.
|
|
57
|
+
`minQrVersion(byteLen, ecc)` / `qrModuleCount(version)` /
|
|
58
|
+
`qrByteCapacity(version, ecc)` expose the symbol math (byte-mode capacities
|
|
59
|
+
verified against the reference encoder).
|
|
60
|
+
|
|
61
|
+
### `@ai-matrx/print/labels` — label sheets, roll stock, custom formats
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { qrLabelsPrinter, printQrLabelSheet, downloadLabelsPdf, printCalibrationSheet, applyLabelFormat, LABEL_FORMAT_PRESETS, assertScannable, getLabelTemplate } from "@ai-matrx/print/labels";
|
|
65
|
+
|
|
66
|
+
// One data shape, three lanes: print window, PDF download, calibration page.
|
|
67
|
+
const data = applyLabelFormat(
|
|
68
|
+
LABEL_FORMAT_PRESETS.find((f) => f.id === "garment")!,
|
|
69
|
+
[{ qrValue: "https://yourbrand.com/l/a1B2c3", size: "XL", sku: "TS-001", color: "Black", price: "$29" }],
|
|
70
|
+
);
|
|
71
|
+
await printQrLabelSheet({ ...data, templateId: "avery-5160" });
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Built-in templates: Avery 5160/8160, 5163/8163, 5164/8164, 22806 (2″ square),
|
|
75
|
+
22807 (2″ round), plus roll stock — Brother DK-1202 / DK-11201, DYMO 30252,
|
|
76
|
+
and generic 4×6″ thermal (`kind: "roll"`). Custom stock is just data via
|
|
77
|
+
`customLabelTemplate(geometry)`; a dev-time assertion proves every template
|
|
78
|
+
tiles its sheet. Settings include `startAtLabel` (reuse a partially-used
|
|
79
|
+
sheet), `copiesPerCode`, label ranges, and EC level (default M).
|
|
80
|
+
|
|
81
|
+
`LabelFormat` describes a label as ordered elements — `qr`, `text` with a
|
|
82
|
+
`title` / `detail` / `badge` role, `image` (durable http(s) URLs only) — so
|
|
83
|
+
clients can define their own layouts as data. Presets: `qr-only`,
|
|
84
|
+
`qr-caption`, `garment`, `asset-spec`.
|
|
85
|
+
|
|
86
|
+
`assertScannable(template, payloadByteLen, ecc)` warns before anyone prints a
|
|
87
|
+
payload too dense for the stock (module size below the ~0.4 mm thermal floor);
|
|
88
|
+
the print lane surfaces it as an on-screen banner automatically.
|
|
89
|
+
|
|
90
|
+
Print fidelity: QRs are inlined data URIs rasterized at 300 dpi (a print
|
|
91
|
+
window is a fresh, unauthenticated document — nothing is fetched),
|
|
92
|
+
`print-color-adjust: exact`, inch-exact `@page` geometry, and a
|
|
93
|
+
print-on-plain-paper calibration sheet per template. Print at 100% scale with
|
|
94
|
+
no margins.
|
|
95
|
+
|
|
96
|
+
### `@ai-matrx/print/flashcards` — the deck printer
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { flashcardsPrinter } from "@ai-matrx/print/flashcards";
|
|
100
|
+
|
|
101
|
+
flashcardsPrinter.print({ title: "Biology 101", cards }, "portrait-6up-duplex", { showCutLines: true });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Ten variants: portrait 6-up and landscape 4-up (each duplex-mirrored — backs
|
|
105
|
+
column-swapped so long-edge duplex aligns perfectly — or stacked
|
|
106
|
+
all-fronts-then-all-backs), Avery 5388 index cards, cut-out cards, both-sides,
|
|
107
|
+
study-sheet table, questions-only self-test, answers-only. Settings: card
|
|
108
|
+
ranges, cut tick marks / full cut lines, side labels, card numbers, and
|
|
109
|
+
show-through countermeasures (gray back text, mirrored back text). Face
|
|
110
|
+
images print from durable URLs only.
|
|
111
|
+
|
|
112
|
+
### `@ai-matrx/print/pdf` — DOM capture & markdown → PDF
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { captureToPDF, captureElementsToPDF, markdownToPdfBlob } from "@ai-matrx/print/pdf";
|
|
116
|
+
|
|
117
|
+
await captureToPDF(document.getElementById("report")!, { filename: "report", orientation: "landscape" });
|
|
118
|
+
const blob = await markdownToPdfBlob(markdown, { convertToHtml, loadCss }); // bring your own converter + stylesheet
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
html2canvas + jsPDF, lazy-loaded on use. Handles the Tailwind v4 problem
|
|
122
|
+
(oklch/lab colors html2canvas can't parse) via a scoped `getComputedStyle`
|
|
123
|
+
patch that is always restored. `captureElementsToPDF` renders deliberately
|
|
124
|
+
paginated report pages one-per-PDF-page; the single-element lane slices one
|
|
125
|
+
tall canvas across pages.
|
|
126
|
+
|
|
127
|
+
### `@ai-matrx/print/react` — the options dialog & sheet preview
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import { PrintOptionsDialog, usePrintOptions, LabelSheetPreview } from "@ai-matrx/print/react";
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`PrintOptionsDialog` renders any `BlockPrinter`'s variants + settings
|
|
134
|
+
(desktop dialog, mobile bottom drawer) and runs the print.
|
|
135
|
+
`LabelSheetPreview` shows a scaled, exact-proportion preview of a label sheet,
|
|
136
|
+
with a calibration outline mode. Tailwind CSS classes; Radix dialog + vaul
|
|
137
|
+
drawer are bundled dependencies.
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
package/dist/core.cjs
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/core.ts
|
|
21
|
+
var core_exports = {};
|
|
22
|
+
__export(core_exports, {
|
|
23
|
+
buildFitTextScript: () => buildFitTextScript,
|
|
24
|
+
buildPrintDocument: () => buildPrintDocument,
|
|
25
|
+
escapeHtml: () => escapeHtml,
|
|
26
|
+
openPrintWindow: () => openPrintWindow,
|
|
27
|
+
printHtmlContent: () => printHtmlContent
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(core_exports);
|
|
30
|
+
var PRINT_STYLES = `
|
|
31
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
32
|
+
|
|
33
|
+
body {
|
|
34
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
|
|
35
|
+
font-size: 11pt;
|
|
36
|
+
line-height: 1.6;
|
|
37
|
+
color: #1a1a1a;
|
|
38
|
+
background: #fff;
|
|
39
|
+
max-width: 860px;
|
|
40
|
+
margin: 0 auto;
|
|
41
|
+
padding: 28px 36px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.print-actions {
|
|
45
|
+
display: flex;
|
|
46
|
+
gap: 10px;
|
|
47
|
+
margin-bottom: 24px;
|
|
48
|
+
padding-bottom: 18px;
|
|
49
|
+
border-bottom: 2px solid #e5e7eb;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.print-btn {
|
|
53
|
+
display: inline-flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
gap: 6px;
|
|
56
|
+
padding: 8px 20px;
|
|
57
|
+
border-radius: 8px;
|
|
58
|
+
font-size: 13px;
|
|
59
|
+
font-family: inherit;
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
border: none;
|
|
62
|
+
font-weight: 600;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.print-btn-primary { background: #2563eb; color: #fff; }
|
|
66
|
+
.print-btn-secondary { background: #f3f4f6; color: #374151; border: 1px solid #d1d5db; }
|
|
67
|
+
|
|
68
|
+
h1 { font-size: 22pt; font-weight: 700; margin-bottom: 0.5em; }
|
|
69
|
+
h2 { font-size: 16pt; font-weight: 700; margin: 1.2em 0 0.4em; border-bottom: 1px solid #e5e7eb; padding-bottom: 0.2em; }
|
|
70
|
+
h3 { font-size: 13pt; font-weight: 600; margin: 1em 0 0.3em; }
|
|
71
|
+
p { margin-bottom: 0.7em; }
|
|
72
|
+
|
|
73
|
+
table {
|
|
74
|
+
width: 100%;
|
|
75
|
+
border-collapse: collapse;
|
|
76
|
+
margin: 1em 0;
|
|
77
|
+
font-size: 10pt;
|
|
78
|
+
}
|
|
79
|
+
th {
|
|
80
|
+
background: #1e293b;
|
|
81
|
+
color: #f8fafc;
|
|
82
|
+
font-weight: 600;
|
|
83
|
+
text-align: left;
|
|
84
|
+
padding: 7px 12px;
|
|
85
|
+
border: 1px solid #334155;
|
|
86
|
+
}
|
|
87
|
+
td {
|
|
88
|
+
padding: 6px 12px;
|
|
89
|
+
border: 1px solid #e2e8f0;
|
|
90
|
+
vertical-align: top;
|
|
91
|
+
}
|
|
92
|
+
tr:nth-child(even) td { background: #f8fafc; }
|
|
93
|
+
|
|
94
|
+
@media print {
|
|
95
|
+
body { max-width: 100%; padding: 0; }
|
|
96
|
+
.print-actions { display: none !important; }
|
|
97
|
+
th { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
function escapeHtml(str) {
|
|
101
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
102
|
+
}
|
|
103
|
+
function buildPrintDocument(bodyHtml, title = "AI Response", extraStyles = "") {
|
|
104
|
+
return `<!DOCTYPE html>
|
|
105
|
+
<html lang="en">
|
|
106
|
+
<head>
|
|
107
|
+
<meta charset="UTF-8">
|
|
108
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
109
|
+
<title>${escapeHtml(title)}</title>
|
|
110
|
+
<style>
|
|
111
|
+
${PRINT_STYLES}
|
|
112
|
+
${extraStyles}
|
|
113
|
+
</style>
|
|
114
|
+
</head>
|
|
115
|
+
<body>
|
|
116
|
+
<div class="print-actions">
|
|
117
|
+
<button class="print-btn print-btn-primary" onclick="window.print()">Print / Save as PDF</button>
|
|
118
|
+
<button class="print-btn print-btn-secondary" onclick="window.close()">Close</button>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="content">
|
|
121
|
+
${bodyHtml}
|
|
122
|
+
</div>
|
|
123
|
+
</body>
|
|
124
|
+
</html>`;
|
|
125
|
+
}
|
|
126
|
+
function openPrintWindow(htmlDocument, filename = "print") {
|
|
127
|
+
const win = window.open("", "_blank", "width=920,height=720,scrollbars=yes");
|
|
128
|
+
if (!win) {
|
|
129
|
+
const blob = new Blob([htmlDocument], { type: "text/html;charset=utf-8" });
|
|
130
|
+
const url = URL.createObjectURL(blob);
|
|
131
|
+
const a = document.createElement("a");
|
|
132
|
+
a.href = url;
|
|
133
|
+
a.download = `${filename.replace(/\s+/g, "-").toLowerCase()}.html`;
|
|
134
|
+
document.body.appendChild(a);
|
|
135
|
+
a.click();
|
|
136
|
+
document.body.removeChild(a);
|
|
137
|
+
URL.revokeObjectURL(url);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
win.document.open();
|
|
141
|
+
win.document.write(htmlDocument);
|
|
142
|
+
win.document.close();
|
|
143
|
+
}
|
|
144
|
+
function printHtmlContent(bodyHtml, title = "AI Response", extraStyles = "") {
|
|
145
|
+
const doc = buildPrintDocument(bodyHtml, title, extraStyles);
|
|
146
|
+
openPrintWindow(doc, title);
|
|
147
|
+
}
|
|
148
|
+
function buildFitTextScript(selectors) {
|
|
149
|
+
const selectorsJson = JSON.stringify([...selectors]);
|
|
150
|
+
return `
|
|
151
|
+
<script>
|
|
152
|
+
(function() {
|
|
153
|
+
function fitText(el, container) {
|
|
154
|
+
// container is the bounding box we must fit inside
|
|
155
|
+
var maxW = container.clientWidth;
|
|
156
|
+
var maxH = container.clientHeight;
|
|
157
|
+
var size = parseFloat(window.getComputedStyle(el).fontSize);
|
|
158
|
+
var minSize = 6;
|
|
159
|
+
// Give the element a chance to reflow at current size before measuring
|
|
160
|
+
el.style.fontSize = size + "pt";
|
|
161
|
+
while (size > minSize && (el.scrollWidth > maxW + 1 || el.scrollHeight > maxH + 1)) {
|
|
162
|
+
size -= 0.5;
|
|
163
|
+
el.style.fontSize = size + "pt";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function runAll() {
|
|
167
|
+
var selectors = ${selectorsJson};
|
|
168
|
+
for (var s = 0; s < selectors.length; s++) {
|
|
169
|
+
var els = document.querySelectorAll(selectors[s]);
|
|
170
|
+
for (var i = 0; i < els.length; i++) {
|
|
171
|
+
fitText(els[i], els[i].parentElement);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (document.readyState === "loading") {
|
|
176
|
+
document.addEventListener("DOMContentLoaded", runAll);
|
|
177
|
+
} else {
|
|
178
|
+
// document.write pages may already be loaded
|
|
179
|
+
setTimeout(runAll, 0);
|
|
180
|
+
}
|
|
181
|
+
})();
|
|
182
|
+
<\/script>`;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=core.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core.ts"],"sourcesContent":["/**\n * @ai-matrx/print/core — the Block Print contract & print-window composition.\n *\n * Ported VERBATIM from matrx-frontend `lib/block-print/block-print-utils.ts`\n * (2026-08-29 state, including the `number` and `select` PrintSetting types the\n * commerce label lane added). Zero dependencies; touches `window` only at call\n * time, so the module stays import-inert and RSC-safe.\n *\n * BlockPrinter is the only interface a host system needs to know about.\n * Each printable unit exports its own BlockPrinter alongside its render\n * component; host code only ever calls print(data, variantId, settings).\n *\n * `buildFitTextScript` is the ONE auto-shrink script (the flashcards\n * FIT_TEXT pattern, parameterized by selector so the label lane shares it).\n */\n\n// ─── Contract ────────────────────────────────────────────────────────────────\n\nexport interface PrintVariant {\n id: string;\n label: string;\n description?: string;\n}\n\n/**\n * A single user-configurable setting shown in the print dialog.\n * Extend the discriminated union for new control types\n * without breaking existing printers.\n */\nexport type PrintSetting =\n | {\n type: \"boolean\";\n id: string;\n label: string;\n description?: string;\n /** Default value shown when the dialog first opens */\n defaultValue: boolean;\n /** Which variant IDs this setting applies to. Omit = applies to all. */\n appliesTo?: string[];\n }\n | {\n /**\n * A numeric \"from → to\" range control, rendered as two small number inputs.\n * Writes two entries into the resolved PrintSettings map — one under fromId,\n * one under toId. Printers interpret 0 (or missing) as \"no bound\" by convention.\n */\n type: \"range\";\n /** Stable id used as React key — not written to the settings map */\n id: string;\n label: string;\n description?: string;\n /** Settings map key for the lower bound value */\n fromId: string;\n /** Settings map key for the upper bound value */\n toId: string;\n defaultFrom: number;\n defaultTo: number;\n /** Minimum accepted value for each input (inclusive). Default 0. */\n min?: number;\n /** Placeholder shown when the input is empty (0). Default \"start\" / \"end\". */\n fromPlaceholder?: string;\n toPlaceholder?: string;\n /** Which variant IDs this setting applies to. Omit = applies to all. */\n appliesTo?: string[];\n }\n | {\n /** A single numeric input (e.g. \"start at label #\", \"copies\"). */\n type: \"number\";\n id: string;\n label: string;\n description?: string;\n defaultValue: number;\n /** Minimum accepted value (inclusive). Default 0. */\n min?: number;\n /** Maximum accepted value (inclusive). Omit = unbounded. */\n max?: number;\n /** Which variant IDs this setting applies to. Omit = applies to all. */\n appliesTo?: string[];\n }\n | {\n /** A one-of-N choice rendered as a compact segmented row. */\n type: \"select\";\n id: string;\n label: string;\n description?: string;\n options: { value: string; label: string }[];\n defaultValue: string;\n /** Which variant IDs this setting applies to. Omit = applies to all. */\n appliesTo?: string[];\n };\n\n/** A resolved map of setting id → current value, passed to print(). */\nexport type PrintSettings = Record<string, boolean | string | number>;\n\n/**\n * The self-contained print capability that each block can export.\n * Host code only ever calls print(data, variantId, settings) — it never inspects internals.\n */\nexport interface BlockPrinter {\n /** Tooltip / aria-label for the print button in the block header */\n label: string;\n\n /**\n * Variants offered to the user before printing.\n * Empty array = no options dialog shown; prints immediately with defaults.\n */\n variants: PrintVariant[];\n\n /**\n * Optional user-configurable settings shown below the variant picker.\n * Omit entirely if the block has no configurable settings.\n */\n settings?: PrintSetting[];\n\n /**\n * Execute the print.\n * data — the block's structured data (serverData or parsed content)\n * variantId — which variant was chosen (undefined = default / no variants)\n * settings — resolved setting values chosen by the user\n */\n print: (\n data: unknown,\n variantId?: string,\n settings?: PrintSettings,\n ) => void | Promise<void>;\n}\n\n// ─── Shared Utilities ─────────────────────────────────────────────────────────\n\nconst PRINT_STYLES = `\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;\n font-size: 11pt;\n line-height: 1.6;\n color: #1a1a1a;\n background: #fff;\n max-width: 860px;\n margin: 0 auto;\n padding: 28px 36px;\n }\n\n .print-actions {\n display: flex;\n gap: 10px;\n margin-bottom: 24px;\n padding-bottom: 18px;\n border-bottom: 2px solid #e5e7eb;\n }\n\n .print-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 20px;\n border-radius: 8px;\n font-size: 13px;\n font-family: inherit;\n cursor: pointer;\n border: none;\n font-weight: 600;\n }\n\n .print-btn-primary { background: #2563eb; color: #fff; }\n .print-btn-secondary { background: #f3f4f6; color: #374151; border: 1px solid #d1d5db; }\n\n h1 { font-size: 22pt; font-weight: 700; margin-bottom: 0.5em; }\n h2 { font-size: 16pt; font-weight: 700; margin: 1.2em 0 0.4em; border-bottom: 1px solid #e5e7eb; padding-bottom: 0.2em; }\n h3 { font-size: 13pt; font-weight: 600; margin: 1em 0 0.3em; }\n p { margin-bottom: 0.7em; }\n\n table {\n width: 100%;\n border-collapse: collapse;\n margin: 1em 0;\n font-size: 10pt;\n }\n th {\n background: #1e293b;\n color: #f8fafc;\n font-weight: 600;\n text-align: left;\n padding: 7px 12px;\n border: 1px solid #334155;\n }\n td {\n padding: 6px 12px;\n border: 1px solid #e2e8f0;\n vertical-align: top;\n }\n tr:nth-child(even) td { background: #f8fafc; }\n\n @media print {\n body { max-width: 100%; padding: 0; }\n .print-actions { display: none !important; }\n th { -webkit-print-color-adjust: exact; print-color-adjust: exact; }\n }\n`;\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Wrap body HTML in a complete, styled print document.\n */\nexport function buildPrintDocument(\n bodyHtml: string,\n title = \"AI Response\",\n extraStyles = \"\",\n): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(title)}</title>\n <style>\n${PRINT_STYLES}\n${extraStyles}\n </style>\n</head>\n<body>\n <div class=\"print-actions\">\n <button class=\"print-btn print-btn-primary\" onclick=\"window.print()\">Print / Save as PDF</button>\n <button class=\"print-btn print-btn-secondary\" onclick=\"window.close()\">Close</button>\n </div>\n <div class=\"content\">\n${bodyHtml}\n </div>\n</body>\n</html>`;\n}\n\n/**\n * Open a new browser window and write a complete HTML document into it.\n * Falls back to downloading an .html file if the popup is blocked.\n */\nexport function openPrintWindow(\n htmlDocument: string,\n filename = \"print\",\n): void {\n const win = window.open(\"\", \"_blank\", \"width=920,height=720,scrollbars=yes\");\n if (!win) {\n // Popup blocked — fall back to file download\n const blob = new Blob([htmlDocument], { type: \"text/html;charset=utf-8\" });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${filename.replace(/\\s+/g, \"-\").toLowerCase()}.html`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n return;\n }\n win.document.open();\n win.document.write(htmlDocument);\n win.document.close();\n}\n\n/**\n * Shorthand: build the document and open it in one call.\n */\nexport function printHtmlContent(\n bodyHtml: string,\n title = \"AI Response\",\n extraStyles = \"\",\n): void {\n const doc = buildPrintDocument(bodyHtml, title, extraStyles);\n openPrintWindow(doc, title);\n}\n\n/**\n * Build the auto-shrink script that runs INSIDE a printed window: for every\n * element matching each selector, its font-size is reduced (0.5pt steps, 6pt\n * floor) until it fits its parent element's box. This is the flashcards\n * FIT_TEXT behavior verbatim, parameterized by selector so every lane\n * (flashcards card text, Avery text, label captions) shares the ONE loop.\n *\n * Pass the same selectors the original used to get byte-identical behavior:\n * flashcards passes `[\".card-text .card-text-inner\", \".avery-text-wrap .avery-text\"]`.\n */\nexport function buildFitTextScript(selectors: readonly string[]): string {\n const selectorsJson = JSON.stringify([...selectors]);\n return `\n<script>\n(function() {\n function fitText(el, container) {\n // container is the bounding box we must fit inside\n var maxW = container.clientWidth;\n var maxH = container.clientHeight;\n var size = parseFloat(window.getComputedStyle(el).fontSize);\n var minSize = 6;\n // Give the element a chance to reflow at current size before measuring\n el.style.fontSize = size + \"pt\";\n while (size > minSize && (el.scrollWidth > maxW + 1 || el.scrollHeight > maxH + 1)) {\n size -= 0.5;\n el.style.fontSize = size + \"pt\";\n }\n }\n function runAll() {\n var selectors = ${selectorsJson};\n for (var s = 0; s < selectors.length; s++) {\n var els = document.querySelectorAll(selectors[s]);\n for (var i = 0; i < els.length; i++) {\n fitText(els[i], els[i].parentElement);\n }\n }\n }\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", runAll);\n } else {\n // document.write pages may already be loaded\n setTimeout(runAll, 0);\n }\n})();\n</script>`;\n}\n\nexport { escapeHtml };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiIA,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuErB,SAAS,WAAW,KAAqB;AACvC,SAAO,IACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,OAAO;AAC1B;AAKO,SAAS,mBACd,UACA,QAAQ,eACR,cAAc,IACN;AACR,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,WAKE,WAAW,KAAK,CAAC;AAAA;AAAA,EAE1B,YAAY;AAAA,EACZ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASX,QAAQ;AAAA;AAAA;AAAA;AAIV;AAMO,SAAS,gBACd,cACA,WAAW,SACL;AACN,QAAM,MAAM,OAAO,KAAK,IAAI,UAAU,qCAAqC;AAC3E,MAAI,CAAC,KAAK;AAER,UAAM,OAAO,IAAI,KAAK,CAAC,YAAY,GAAG,EAAE,MAAM,0BAA0B,CAAC;AACzE,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,UAAM,IAAI,SAAS,cAAc,GAAG;AACpC,MAAE,OAAO;AACT,MAAE,WAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,EAAE,YAAY,CAAC;AAC3D,aAAS,KAAK,YAAY,CAAC;AAC3B,MAAE,MAAM;AACR,aAAS,KAAK,YAAY,CAAC;AAC3B,QAAI,gBAAgB,GAAG;AACvB;AAAA,EACF;AACA,MAAI,SAAS,KAAK;AAClB,MAAI,SAAS,MAAM,YAAY;AAC/B,MAAI,SAAS,MAAM;AACrB;AAKO,SAAS,iBACd,UACA,QAAQ,eACR,cAAc,IACR;AACN,QAAM,MAAM,mBAAmB,UAAU,OAAO,WAAW;AAC3D,kBAAgB,KAAK,KAAK;AAC5B;AAYO,SAAS,mBAAmB,WAAsC;AACvE,QAAM,gBAAgB,KAAK,UAAU,CAAC,GAAG,SAAS,CAAC;AACnD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAiBa,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBnC;","names":[]}
|
package/dist/core.d.cts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ai-matrx/print/core — the Block Print contract & print-window composition.
|
|
3
|
+
*
|
|
4
|
+
* Ported VERBATIM from matrx-frontend `lib/block-print/block-print-utils.ts`
|
|
5
|
+
* (2026-08-29 state, including the `number` and `select` PrintSetting types the
|
|
6
|
+
* commerce label lane added). Zero dependencies; touches `window` only at call
|
|
7
|
+
* time, so the module stays import-inert and RSC-safe.
|
|
8
|
+
*
|
|
9
|
+
* BlockPrinter is the only interface a host system needs to know about.
|
|
10
|
+
* Each printable unit exports its own BlockPrinter alongside its render
|
|
11
|
+
* component; host code only ever calls print(data, variantId, settings).
|
|
12
|
+
*
|
|
13
|
+
* `buildFitTextScript` is the ONE auto-shrink script (the flashcards
|
|
14
|
+
* FIT_TEXT pattern, parameterized by selector so the label lane shares it).
|
|
15
|
+
*/
|
|
16
|
+
interface PrintVariant {
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A single user-configurable setting shown in the print dialog.
|
|
23
|
+
* Extend the discriminated union for new control types
|
|
24
|
+
* without breaking existing printers.
|
|
25
|
+
*/
|
|
26
|
+
type PrintSetting = {
|
|
27
|
+
type: "boolean";
|
|
28
|
+
id: string;
|
|
29
|
+
label: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
/** Default value shown when the dialog first opens */
|
|
32
|
+
defaultValue: boolean;
|
|
33
|
+
/** Which variant IDs this setting applies to. Omit = applies to all. */
|
|
34
|
+
appliesTo?: string[];
|
|
35
|
+
} | {
|
|
36
|
+
/**
|
|
37
|
+
* A numeric "from → to" range control, rendered as two small number inputs.
|
|
38
|
+
* Writes two entries into the resolved PrintSettings map — one under fromId,
|
|
39
|
+
* one under toId. Printers interpret 0 (or missing) as "no bound" by convention.
|
|
40
|
+
*/
|
|
41
|
+
type: "range";
|
|
42
|
+
/** Stable id used as React key — not written to the settings map */
|
|
43
|
+
id: string;
|
|
44
|
+
label: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
/** Settings map key for the lower bound value */
|
|
47
|
+
fromId: string;
|
|
48
|
+
/** Settings map key for the upper bound value */
|
|
49
|
+
toId: string;
|
|
50
|
+
defaultFrom: number;
|
|
51
|
+
defaultTo: number;
|
|
52
|
+
/** Minimum accepted value for each input (inclusive). Default 0. */
|
|
53
|
+
min?: number;
|
|
54
|
+
/** Placeholder shown when the input is empty (0). Default "start" / "end". */
|
|
55
|
+
fromPlaceholder?: string;
|
|
56
|
+
toPlaceholder?: string;
|
|
57
|
+
/** Which variant IDs this setting applies to. Omit = applies to all. */
|
|
58
|
+
appliesTo?: string[];
|
|
59
|
+
} | {
|
|
60
|
+
/** A single numeric input (e.g. "start at label #", "copies"). */
|
|
61
|
+
type: "number";
|
|
62
|
+
id: string;
|
|
63
|
+
label: string;
|
|
64
|
+
description?: string;
|
|
65
|
+
defaultValue: number;
|
|
66
|
+
/** Minimum accepted value (inclusive). Default 0. */
|
|
67
|
+
min?: number;
|
|
68
|
+
/** Maximum accepted value (inclusive). Omit = unbounded. */
|
|
69
|
+
max?: number;
|
|
70
|
+
/** Which variant IDs this setting applies to. Omit = applies to all. */
|
|
71
|
+
appliesTo?: string[];
|
|
72
|
+
} | {
|
|
73
|
+
/** A one-of-N choice rendered as a compact segmented row. */
|
|
74
|
+
type: "select";
|
|
75
|
+
id: string;
|
|
76
|
+
label: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
options: {
|
|
79
|
+
value: string;
|
|
80
|
+
label: string;
|
|
81
|
+
}[];
|
|
82
|
+
defaultValue: string;
|
|
83
|
+
/** Which variant IDs this setting applies to. Omit = applies to all. */
|
|
84
|
+
appliesTo?: string[];
|
|
85
|
+
};
|
|
86
|
+
/** A resolved map of setting id → current value, passed to print(). */
|
|
87
|
+
type PrintSettings = Record<string, boolean | string | number>;
|
|
88
|
+
/**
|
|
89
|
+
* The self-contained print capability that each block can export.
|
|
90
|
+
* Host code only ever calls print(data, variantId, settings) — it never inspects internals.
|
|
91
|
+
*/
|
|
92
|
+
interface BlockPrinter {
|
|
93
|
+
/** Tooltip / aria-label for the print button in the block header */
|
|
94
|
+
label: string;
|
|
95
|
+
/**
|
|
96
|
+
* Variants offered to the user before printing.
|
|
97
|
+
* Empty array = no options dialog shown; prints immediately with defaults.
|
|
98
|
+
*/
|
|
99
|
+
variants: PrintVariant[];
|
|
100
|
+
/**
|
|
101
|
+
* Optional user-configurable settings shown below the variant picker.
|
|
102
|
+
* Omit entirely if the block has no configurable settings.
|
|
103
|
+
*/
|
|
104
|
+
settings?: PrintSetting[];
|
|
105
|
+
/**
|
|
106
|
+
* Execute the print.
|
|
107
|
+
* data — the block's structured data (serverData or parsed content)
|
|
108
|
+
* variantId — which variant was chosen (undefined = default / no variants)
|
|
109
|
+
* settings — resolved setting values chosen by the user
|
|
110
|
+
*/
|
|
111
|
+
print: (data: unknown, variantId?: string, settings?: PrintSettings) => void | Promise<void>;
|
|
112
|
+
}
|
|
113
|
+
declare function escapeHtml(str: string): string;
|
|
114
|
+
/**
|
|
115
|
+
* Wrap body HTML in a complete, styled print document.
|
|
116
|
+
*/
|
|
117
|
+
declare function buildPrintDocument(bodyHtml: string, title?: string, extraStyles?: string): string;
|
|
118
|
+
/**
|
|
119
|
+
* Open a new browser window and write a complete HTML document into it.
|
|
120
|
+
* Falls back to downloading an .html file if the popup is blocked.
|
|
121
|
+
*/
|
|
122
|
+
declare function openPrintWindow(htmlDocument: string, filename?: string): void;
|
|
123
|
+
/**
|
|
124
|
+
* Shorthand: build the document and open it in one call.
|
|
125
|
+
*/
|
|
126
|
+
declare function printHtmlContent(bodyHtml: string, title?: string, extraStyles?: string): void;
|
|
127
|
+
/**
|
|
128
|
+
* Build the auto-shrink script that runs INSIDE a printed window: for every
|
|
129
|
+
* element matching each selector, its font-size is reduced (0.5pt steps, 6pt
|
|
130
|
+
* floor) until it fits its parent element's box. This is the flashcards
|
|
131
|
+
* FIT_TEXT behavior verbatim, parameterized by selector so every lane
|
|
132
|
+
* (flashcards card text, Avery text, label captions) shares the ONE loop.
|
|
133
|
+
*
|
|
134
|
+
* Pass the same selectors the original used to get byte-identical behavior:
|
|
135
|
+
* flashcards passes `[".card-text .card-text-inner", ".avery-text-wrap .avery-text"]`.
|
|
136
|
+
*/
|
|
137
|
+
declare function buildFitTextScript(selectors: readonly string[]): string;
|
|
138
|
+
|
|
139
|
+
export { type BlockPrinter, type PrintSetting, type PrintSettings, type PrintVariant, buildFitTextScript, buildPrintDocument, escapeHtml, openPrintWindow, printHtmlContent };
|