@ai-matrx/print 0.7.0 → 0.7.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 +14 -0
- package/dist/document.cjs +31 -13
- package/dist/document.cjs.map +1 -1
- package/dist/document.js +31 -13
- package/dist/document.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
- **Fixed (PDF):** a heading followed by a table taller than a page vanished
|
|
6
|
+
together with the whole table — keep-with-next glued them into one
|
|
7
|
+
unbreakable block and pdfmake drops a block that cannot fit a page. A
|
|
8
|
+
heading now travels only with blocks that always fit (a short paragraph,
|
|
9
|
+
a figure, a short list); tables are never unbreakable (rows never split,
|
|
10
|
+
the header row repeats, a caption above keeps with its table); code blocks
|
|
11
|
+
stay whole up to 30 lines. Found printing a real note.
|
|
12
|
+
- **Fixed (PDF):** emoji and pictographs printed as empty boxes (the embedded
|
|
13
|
+
fonts have no glyphs for them). They are left out of the PDF and announced
|
|
14
|
+
once with the `glyph-substituted` notice; Word, EPUB and HTML keep them.
|
|
15
|
+
- Consumer action: none — refresh to latest.
|
|
16
|
+
|
|
3
17
|
## 0.7.0
|
|
4
18
|
|
|
5
19
|
- **Added: `@ai-matrx/print/document` — print-grade documents from markdown.**
|
package/dist/document.cjs
CHANGED
|
@@ -1456,9 +1456,24 @@ var courierCanDraw = (s) => {
|
|
|
1456
1456
|
}
|
|
1457
1457
|
return true;
|
|
1458
1458
|
};
|
|
1459
|
+
var NO_GLYPH = /[\p{Extended_Pictographic}\u{1F1E6}-\u{1F1FF}\u200D\uFE0F\u20E3]/gu;
|
|
1460
|
+
function drawable(text, c) {
|
|
1461
|
+
if (!NO_GLYPH.test(text)) return text;
|
|
1462
|
+
NO_GLYPH.lastIndex = 0;
|
|
1463
|
+
if (!c.glyphs.announced) {
|
|
1464
|
+
c.glyphs.announced = true;
|
|
1465
|
+
c.tree.notices.push({
|
|
1466
|
+
code: "glyph-substituted",
|
|
1467
|
+
message: "Emoji and pictographs were left out of the PDF: its fonts cannot draw them (Word, EPUB and HTML keep them).",
|
|
1468
|
+
remedy: "Use words or plain symbols instead of emoji if they must appear in the PDF."
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
return text.replace(NO_GLYPH, "").replace(/ {2,}/g, " ");
|
|
1472
|
+
}
|
|
1459
1473
|
function runs2(nodes, c, st = {}) {
|
|
1460
1474
|
const out = [];
|
|
1461
|
-
const base = (
|
|
1475
|
+
const base = (raw) => {
|
|
1476
|
+
const text = drawable(raw, c);
|
|
1462
1477
|
const r = { text };
|
|
1463
1478
|
if (st.bold) r.bold = true;
|
|
1464
1479
|
if (st.italics) r.italics = true;
|
|
@@ -1535,6 +1550,8 @@ var capNode = (cap, c, where) => ({
|
|
|
1535
1550
|
text: [{ text: cap.label, bold: true, color: COLOR.heading }, ...cap.children.length ? [": ", ...runs2(cap.children, c)] : []],
|
|
1536
1551
|
style: "caption",
|
|
1537
1552
|
id: cap.id ? `${cap.kind}:${cap.id}` : void 0,
|
|
1553
|
+
// A caption above its table is never the last line on a page.
|
|
1554
|
+
...where === "above" ? { headlineLevel: 9 } : {},
|
|
1538
1555
|
margin: where === "above" ? [0, 0, 0, 4] : [0, 4, 0, 0]
|
|
1539
1556
|
});
|
|
1540
1557
|
function estimateLines(text, c) {
|
|
@@ -1557,13 +1574,12 @@ function taskItem(checked, content, c) {
|
|
|
1557
1574
|
columnGap: 2
|
|
1558
1575
|
};
|
|
1559
1576
|
}
|
|
1560
|
-
function gluable(b) {
|
|
1577
|
+
function gluable(b, c) {
|
|
1561
1578
|
if (!b) return false;
|
|
1562
|
-
if (b.type === "paragraph"
|
|
1563
|
-
if (b.type === "
|
|
1564
|
-
if (b.type === "
|
|
1565
|
-
|
|
1566
|
-
if (b.type === "blockquote") return b.children.length <= 4;
|
|
1579
|
+
if (b.type === "paragraph") return estimateLines(plain(b.children), c) <= 5;
|
|
1580
|
+
if (b.type === "figure" || b.type === "rule") return true;
|
|
1581
|
+
if (b.type === "list")
|
|
1582
|
+
return b.items.length <= 4 && b.items.every((i) => i.children.length === 1 && i.children[0]?.type === "paragraph");
|
|
1567
1583
|
return false;
|
|
1568
1584
|
}
|
|
1569
1585
|
function blocks2(list, c) {
|
|
@@ -1572,7 +1588,7 @@ function blocks2(list, c) {
|
|
|
1572
1588
|
for (let i = 0; i < list.length; i++) {
|
|
1573
1589
|
const b = list[i];
|
|
1574
1590
|
let node = block2(b, c);
|
|
1575
|
-
if (node && b.type === "heading" && gluable(list[i + 1])) {
|
|
1591
|
+
if (node && b.type === "heading" && gluable(list[i + 1], c)) {
|
|
1576
1592
|
const next = block2(list[i + 1], c);
|
|
1577
1593
|
if (next) {
|
|
1578
1594
|
node = { stack: [node, next], unbreakable: true };
|
|
@@ -1642,7 +1658,7 @@ function block2(b, c) {
|
|
|
1642
1658
|
const lines = b.value.replace(/\n$/, "").split("\n");
|
|
1643
1659
|
const size = c.s.fontSize * 0.8;
|
|
1644
1660
|
const stack = lines.map((l) => {
|
|
1645
|
-
const t2 = l.replace(/\t/g, " ") || " ";
|
|
1661
|
+
const t2 = drawable(l.replace(/\t/g, " "), c) || " ";
|
|
1646
1662
|
return courierCanDraw(t2) ? { text: t2, font: "Courier", fontSize: size, preserveLeadingSpaces: true } : { text: t2, fontSize: size, preserveLeadingSpaces: true };
|
|
1647
1663
|
});
|
|
1648
1664
|
return {
|
|
@@ -1658,8 +1674,9 @@ function block2(b, c) {
|
|
|
1658
1674
|
paddingBottom: () => 6
|
|
1659
1675
|
},
|
|
1660
1676
|
margin: [0, 0, 0, 8],
|
|
1661
|
-
// Keep a block that fits on one page together
|
|
1662
|
-
unbreakable
|
|
1677
|
+
// Keep a block that fits on one page together (30 lines fits even a
|
|
1678
|
+
// landscape page; a taller unbreakable block would be dropped).
|
|
1679
|
+
unbreakable: lines.length <= 30
|
|
1663
1680
|
};
|
|
1664
1681
|
}
|
|
1665
1682
|
case "table": {
|
|
@@ -1693,7 +1710,7 @@ function block2(b, c) {
|
|
|
1693
1710
|
const stack = [];
|
|
1694
1711
|
if (b.caption) stack.push(capNode(b.caption, c, "above"));
|
|
1695
1712
|
stack.push(table);
|
|
1696
|
-
return { stack, margin: [0, 2, 0, 10]
|
|
1713
|
+
return { stack, margin: [0, 2, 0, 10] };
|
|
1697
1714
|
}
|
|
1698
1715
|
case "figure": {
|
|
1699
1716
|
const img = c.images?.get(b.url);
|
|
@@ -1779,6 +1796,7 @@ function buildPdfDefinition(tree, images, pageCountSink) {
|
|
|
1779
1796
|
const headings = [];
|
|
1780
1797
|
for (const sec of tree.sections) for (const b of sec.blocks) if (b.type === "heading") headings.push(b.level);
|
|
1781
1798
|
const c = {
|
|
1799
|
+
glyphs: { announced: false },
|
|
1782
1800
|
tree,
|
|
1783
1801
|
images,
|
|
1784
1802
|
s,
|
|
@@ -1900,7 +1918,7 @@ async function documentToPdf(tree, images) {
|
|
|
1900
1918
|
}
|
|
1901
1919
|
async function headingPages(tree, images) {
|
|
1902
1920
|
const pdfMake = await loadPdfMake();
|
|
1903
|
-
const def = buildPdfDefinition(tree, images);
|
|
1921
|
+
const def = buildPdfDefinition({ ...tree, notices: [] }, images);
|
|
1904
1922
|
await pdfMake.createPdf(def).getBuffer();
|
|
1905
1923
|
const want = new Set(tree.toc.map((e) => e.id));
|
|
1906
1924
|
const pages = /* @__PURE__ */ new Map();
|