@ai-matrx/print 0.2.1 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,89 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1 — 2026-08-30
4
+
5
+ Release-only successor to 0.3.0. The 0.3.0 tagged workflow was rejected before
6
+ package verification because its monorepo lockfile did not match a concurrently
7
+ landed sibling manifest. No 0.3.0 artifact reached npm. This version carries the
8
+ same `/markdown` capability from a source graph whose frozen workspace install
9
+ passes, preserving the immutable-tag release boundary.
10
+
11
+ ## 0.3.0 — 2026-08-30
12
+
13
+ **The BYO-converter seam is gone.** `markdownToPdfBlob` used to declare its
14
+ markdown→HTML converter and its stylesheet as REQUIRED injected ports —
15
+ "bring your own converter + stylesheet". That is exactly the failure THE
16
+ ALL-INCLUSIVE LAW names: the package shipped the easy half and left the hard
17
+ half to every host. Both ports now ship a complete working default; the
18
+ injection seam survives as the OVERRIDE path.
19
+
20
+ - **NEW `/markdown` entry** — the shipped defaults:
21
+ - `markdownToHtml` — the full `.matrx-*` converter (headings, emphasis,
22
+ nested lists at any depth, markdown tables, images, links with underscores,
23
+ code fences, blockquotes, intro-paragraph and FAQ promotion,
24
+ `<flashcards>` blocks).
25
+ - `markdownToArticleHtml` — bare semantic tags for the print-window look;
26
+ code fences are HTML-escaped (a print window does not re-escape).
27
+ - `removeThinkingContent` / `hasThinkingContent` — strips `<thinking>`,
28
+ `<think>` AND `<reasoning>`.
29
+ - `MARKDOWN_DOCUMENT_CSS` / `MARKDOWN_ARTICLE_CSS` + their token sheets, and
30
+ `getMarkdownStylesheet({ skin, tokens, extraCss })`.
31
+ - `renderMarkdownDocument` — markdown → a complete standalone HTML page.
32
+ - `printMarkdown` — markdown → print window in one call, returning the
33
+ `PrintOutcome` so a popup-blocked download is still announced.
34
+ - **`markdownToPdfBlob(markdown)` now works with no second argument.**
35
+ `MarkdownPdfDeps` is all-optional and gains `skin`, `tokens`, `onNotice`,
36
+ `imageTimeoutMs`. Overriding one port leaves the other on its default.
37
+ - **C26 styling** — every colour in both shipped sheets is
38
+ `var(--matrx-print-<role>, <default>)` over one role vocabulary; the inline
39
+ fallbacks make the drop-in test pass unthemed and `tokens` is appended last
40
+ so a host's brand wins. A test proves zero hardcoded colours survive and that
41
+ the token sheet defines exactly the roles the CSS consumes.
42
+ - **Defect found in the ported original, fixed here** — the document
43
+ stylesheet had NO print rules at all: it was authored as a WordPress *screen*
44
+ sheet and then reused for PDF/print, so tables and code blocks split across
45
+ page boundaries, headings stranded at page bottoms, and coloured chrome
46
+ dropped out. It now carries `@media print` with page-break avoidance,
47
+ orphans/widows and `print-color-adjust: exact`.
48
+ - **Nothing fails silently (C22)** — a flashcard missing `Front:`/`Back:` was
49
+ dropped without a word; markdown that converts to an empty document produced
50
+ a blank PDF; an image that 404s or never loads is painted as a blank
51
+ rectangle by html2canvas with no error anywhere; a rasterization failure
52
+ surfaced as a raw html2canvas message. All four now report with a remedy —
53
+ through `onNotice`, or `console.warn` when no sink is supplied. Images are
54
+ awaited before capture (`imageTimeoutMs`, default 8000).
55
+ - **Bundle** — the defaults sit behind a lazy
56
+ `import("@ai-matrx/print/markdown")`, and tsup now treats the package's own
57
+ subpaths as `external` (with `splitting: false` a relative dynamic import is
58
+ inlined and the lazy edge silently disappears — measured: `dist/pdf.js` fell
59
+ from 54.7KB to 12.7KB once the edge was real). A DOM-capture-only consumer
60
+ pays nothing for the stylesheets.
61
+ - **tests** — new `markdown.test.ts` (converter fidelity, the C26 token
62
+ contract, skins/overrides, the announce-what-you-drop cases, the
63
+ popup-blocked print fallback) plus new `markdownToPdfBlob` cases for the
64
+ default path, partial overrides, image notices and capture-failure wording.
65
+ The tarball canary exercises `/markdown` through both `import` and
66
+ `require`, including the no-hardcoded-colour assertion.
67
+
68
+ ### Consumer action (C28)
69
+
70
+ - `markdownToPdfBlob(markdown, deps)` is **source-compatible** — existing
71
+ injecting call sites keep working unchanged.
72
+ - **Delete your markdown converter and print stylesheet.** If a host module
73
+ exists only to fill the old required ports, it is now redundant: call
74
+ `markdownToPdfBlob(markdown)` directly. matrx-frontend removed
75
+ `lib/print/markdown-pdf.ts`, `features/html-pages/css/wordpress-styles.ts`,
76
+ `features/html-pages/utils/markdown-wordpress-utils.ts`'s converter, the
77
+ `removeThinkingContent`/`hasThinkingContent` bodies in
78
+ `components/matrx/buttons/markdown-copy-utils.ts`, and the private converter
79
+ + print sheet inside `features/conversation/utils/markdown-print.ts` in the
80
+ 0.3.0 adoption.
81
+ - **Behaviour delta:** printed/exported document-skin output now obeys print
82
+ page-break rules it previously ignored. Pages break in better places; a
83
+ pixel-diff against a pre-0.3.0 PDF will differ.
84
+ - **Brand tokens:** a host that wants its own colours passes
85
+ `tokens: ":root{ --matrx-print-accent: …; }"` instead of forking the sheet.
86
+
3
87
  ## 0.2.1 — 2026-08-30
4
88
 
5
89
  QA pass F5/F6/F8 hardening — the popup-blocked lane is now observable and has
package/README.md CHANGED
@@ -3,7 +3,8 @@
3
3
  The AI Matrx print system — everything a browser app needs to turn structured
4
4
  content into paper: a tiny print contract, print-window composition, QR
5
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
6
+ roll stock with custom label formats, a full flashcard deck printer, a shipped
7
+ markdown converter with two default print stylesheets, and
7
8
  DOM-capture/markdown → PDF.
8
9
 
9
10
  Every entry is import-inert and safe to import during SSR — browser APIs are
@@ -109,15 +110,56 @@ ranges, cut tick marks / full cut lines, side labels, card numbers, and
109
110
  show-through countermeasures (gray back text, mirrored back text). Face
110
111
  images print from durable URLs only.
111
112
 
113
+ ### `@ai-matrx/print/markdown` — the shipped converter & print stylesheets
114
+
115
+ ```ts
116
+ import { markdownToHtml, getMarkdownStylesheet, renderMarkdownDocument, printMarkdown, removeThinkingContent } from "@ai-matrx/print/markdown";
117
+
118
+ printMarkdown(markdown, { title: "Report" }); // markdown → print window, one call
119
+ const html = markdownToHtml(markdown); // → .matrx-* classed body HTML
120
+ const css = getMarkdownStylesheet({ skin: "article" }); // → the matching stylesheet
121
+ const page = renderMarkdownDocument(markdown, { title: "Report" }); // → a complete <!DOCTYPE html> page
122
+ ```
123
+
124
+ Two skins off one vocabulary. **`"document"`** (default) emits `.matrx-*`
125
+ classed HTML — headings, nested lists, markdown tables, images, links, code,
126
+ FAQ promotion, `<flashcards>` blocks — inside `.matrx-content-container`, and
127
+ its stylesheet is what pastes into a WordPress theme. **`"article"`** emits
128
+ bare semantic tags with the serif AI-response look for print windows (code
129
+ fences are HTML-escaped there, because a print window does not re-escape).
130
+ `removeThinkingContent` strips `<thinking>` / `<think>` / `<reasoning>` — all
131
+ three, which is why a model switching tag names cannot leak reasoning into a
132
+ printed page.
133
+
134
+ Colours are `var(--matrx-print-<role>, <default>)` throughout (C26): the inline
135
+ fallbacks make a fresh app render correctly with zero setup, and a host brands
136
+ it by passing `tokens: ":root{--matrx-print-accent:#0f766e}"` — appended last,
137
+ so the host wins. Both sheets carry the print hard parts (`@media print`,
138
+ page-break avoidance, orphans/widows, `print-color-adjust`).
139
+
112
140
  ### `@ai-matrx/print/pdf` — DOM capture & markdown → PDF
113
141
 
114
142
  ```ts
115
143
  import { captureToPDF, captureElementsToPDF, markdownToPdfBlob } from "@ai-matrx/print/pdf";
116
144
 
117
145
  await captureToPDF(document.getElementById("report")!, { filename: "report", orientation: "landscape" });
118
- const blob = await markdownToPdfBlob(markdown, { convertToHtml, loadCss }); // bring your own converter + stylesheet
146
+ const blob = await markdownToPdfBlob(markdown); // converter + stylesheet included
147
+ const branded = await markdownToPdfBlob(markdown, { skin: "article", tokens }); // tune without replacing
148
+ const custom = await markdownToPdfBlob(markdown, { convertToHtml, loadCss }); // override either port
119
149
  ```
120
150
 
151
+ `markdownToPdfBlob` needs nothing from you. Both ports ship a working default
152
+ (they were REQUIRED injections until 0.3.0); supplying one replaces that
153
+ default and leaves the other alone. The defaults load through a lazy
154
+ `import("@ai-matrx/print/markdown")`, so a consumer that only does DOM capture
155
+ never pulls in the stylesheets.
156
+
157
+ Nothing degrades silently: a flashcard missing its `Front:`/`Back:`, markdown
158
+ that converts to an empty document, an image that 404s or never finishes
159
+ loading (html2canvas would paint a blank rectangle and say nothing), and a
160
+ failed rasterization all report through `onNotice` — or `console.warn` with the
161
+ remedy when no sink is given. `imageTimeoutMs` (default 8000) bounds the wait.
162
+
121
163
  html2canvas + jsPDF, lazy-loaded on use. Handles the Tailwind v4 problem
122
164
  (oklch/lab colors html2canvas can't parse) via a scoped `getComputedStyle`
123
165
  patch that is always restored. `captureElementsToPDF` renders deliberately
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @ai-matrx/print — root entry: TYPES ONLY.\n *\n * The runtime lives in the subpaths (each import-inert, RSC-safe except\n * /react which is a client entry):\n * @ai-matrx/print/core BlockPrinter contract + print-window composition\n * @ai-matrx/print/qr QR generation + e-commerce payload builders\n * @ai-matrx/print/labels label-sheet engine (templates, formats, print/PDF)\n * @ai-matrx/print/flashcards the deck printer (10 variants)\n * @ai-matrx/print/pdf DOM-capture / markdown → PDF\n * @ai-matrx/print/barcode 1-D barcodes (Code128 / EAN-13 / UPC-A)\n * @ai-matrx/print/booklet saddle-stitch imposition + 2-up print lane\n * @ai-matrx/print/qr-styled branded/logo QR (browser-only at call time)\n * @ai-matrx/print/react PrintOptionsDialog + LabelSheetPreview\n */\n\nexport type {\n BlockPrinter,\n PrintVariant,\n PrintSetting,\n PrintSettings,\n PrintOutcome,\n} from \"./core\";\n\nexport type { QrEcLevel, QrOptions } from \"./qr\";\n\nexport type {\n LabelTemplate,\n QrLabel,\n QrLabelPrintData,\n QrLabelSettings,\n ScannabilityReport,\n LabelField,\n LabelElement,\n LabelFormat,\n} from \"./labels\";\n\nexport type { Flashcard, FlashcardsVariant } from \"./flashcards\";\n\nexport type { DomCaptureOptions, MarkdownPdfDeps } from \"./pdf\";\n\nexport type { BarcodeSymbology, BarcodeOptions } from \"./barcode\";\n\nexport type {\n BookletSheet,\n BookletImposition,\n BookletPrintOptions,\n} from \"./booklet\";\n\nexport type {\n StyledQrOptions,\n StyledQrEcLevel,\n StyledQrDotStyle,\n StyledQrCornerStyle,\n} from \"./qr-styled\";\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @ai-matrx/print — root entry: TYPES ONLY.\n *\n * The runtime lives in the subpaths (each import-inert, RSC-safe except\n * /react which is a client entry):\n * @ai-matrx/print/core BlockPrinter contract + print-window composition\n * @ai-matrx/print/qr QR generation + e-commerce payload builders\n * @ai-matrx/print/labels label-sheet engine (templates, formats, print/PDF)\n * @ai-matrx/print/flashcards the deck printer (10 variants)\n * @ai-matrx/print/pdf DOM-capture / markdown → PDF\n * @ai-matrx/print/markdown the shipped markdown converter + print stylesheets\n * @ai-matrx/print/barcode 1-D barcodes (Code128 / EAN-13 / UPC-A)\n * @ai-matrx/print/booklet saddle-stitch imposition + 2-up print lane\n * @ai-matrx/print/qr-styled branded/logo QR (browser-only at call time)\n * @ai-matrx/print/react PrintOptionsDialog + LabelSheetPreview\n */\n\nexport type {\n BlockPrinter,\n PrintVariant,\n PrintSetting,\n PrintSettings,\n PrintOutcome,\n} from \"./core\";\n\nexport type { QrEcLevel, QrOptions } from \"./qr\";\n\nexport type {\n LabelTemplate,\n QrLabel,\n QrLabelPrintData,\n QrLabelSettings,\n ScannabilityReport,\n LabelField,\n LabelElement,\n LabelFormat,\n} from \"./labels\";\n\nexport type { Flashcard, FlashcardsVariant } from \"./flashcards\";\n\nexport type {\n DomCaptureOptions,\n MarkdownPdfDeps,\n MarkdownPdfNotice,\n} from \"./pdf\";\n\nexport type {\n MarkdownSkin,\n MarkdownNotice,\n MarkdownToHtmlOptions,\n MarkdownStylesheetOptions,\n RenderMarkdownDocumentOptions,\n PrintMarkdownOptions,\n} from \"./markdown\";\n\nexport type { BarcodeSymbology, BarcodeOptions } from \"./barcode\";\n\nexport type {\n BookletSheet,\n BookletImposition,\n BookletPrintOptions,\n} from \"./booklet\";\n\nexport type {\n StyledQrOptions,\n StyledQrEcLevel,\n StyledQrDotStyle,\n StyledQrCornerStyle,\n} from \"./qr-styled\";\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
package/dist/index.d.cts CHANGED
@@ -2,7 +2,8 @@ export { BlockPrinter, PrintOutcome, PrintSetting, PrintSettings, PrintVariant }
2
2
  export { QrEcLevel, QrOptions } from './qr.cjs';
3
3
  export { LabelElement, LabelField, LabelFormat, LabelTemplate, QrLabel, QrLabelPrintData, QrLabelSettings, ScannabilityReport } from './labels.cjs';
4
4
  export { Flashcard, FlashcardsVariant } from './flashcards.cjs';
5
- export { DomCaptureOptions, MarkdownPdfDeps } from './pdf.cjs';
5
+ export { DomCaptureOptions, MarkdownPdfDeps, MarkdownPdfNotice } from './pdf.cjs';
6
+ export { MarkdownNotice, MarkdownSkin, MarkdownStylesheetOptions, MarkdownToHtmlOptions, PrintMarkdownOptions, RenderMarkdownDocumentOptions } from './markdown.cjs';
6
7
  export { BarcodeOptions, BarcodeSymbology } from './barcode.cjs';
7
8
  export { BookletImposition, BookletPrintOptions, BookletSheet } from './booklet.cjs';
8
9
  export { StyledQrCornerStyle, StyledQrDotStyle, StyledQrEcLevel, StyledQrOptions } from './qr-styled.cjs';
package/dist/index.d.ts CHANGED
@@ -2,7 +2,8 @@ export { BlockPrinter, PrintOutcome, PrintSetting, PrintSettings, PrintVariant }
2
2
  export { QrEcLevel, QrOptions } from './qr.js';
3
3
  export { LabelElement, LabelField, LabelFormat, LabelTemplate, QrLabel, QrLabelPrintData, QrLabelSettings, ScannabilityReport } from './labels.js';
4
4
  export { Flashcard, FlashcardsVariant } from './flashcards.js';
5
- export { DomCaptureOptions, MarkdownPdfDeps } from './pdf.js';
5
+ export { DomCaptureOptions, MarkdownPdfDeps, MarkdownPdfNotice } from './pdf.js';
6
+ export { MarkdownNotice, MarkdownSkin, MarkdownStylesheetOptions, MarkdownToHtmlOptions, PrintMarkdownOptions, RenderMarkdownDocumentOptions } from './markdown.js';
6
7
  export { BarcodeOptions, BarcodeSymbology } from './barcode.js';
7
8
  export { BookletImposition, BookletPrintOptions, BookletSheet } from './booklet.js';
8
9
  export { StyledQrCornerStyle, StyledQrDotStyle, StyledQrEcLevel, StyledQrOptions } from './qr-styled.js';