@speajus/markdown-to-pdf 1.0.12 → 1.0.13

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/browser.d.ts CHANGED
@@ -1,6 +1,9 @@
1
+ /**
2
+ * Browser-specific entry point that excludes Node.js dependencies
3
+ */
1
4
  export { createBrowserImageRenderer } from "./browser-image-renderer.js";
2
5
  export { createBrowserColorEmojiRenderer } from './color-emoji.js';
3
- export type { TextStyle, PageLayout, CodeStyle, CodeBlockStyle, BlockquoteStyle, TableStyles, TokenColors, SyntaxHighlightTheme, ThemeConfig, PdfOptions, ColorEmojiRenderer, } from './types.js';
6
+ export type { TextStyle, PageLayout, CodeStyle, CodeBlockStyle, BlockquoteStyle, TableStyles, TokenColors, SyntaxHighlightTheme, ThemeConfig, PdfOptions, ColorEmojiRenderer, CustomFontDefinition, } from './types.js';
4
7
  export { defaultTheme, defaultPageLayout, defaultSyntaxHighlightTheme } from './styles.js';
5
8
  export { themes, modernTheme, academicTheme, minimalTheme, oceanTheme } from './themes/index.js';
6
9
  export { renderMarkdownToPdf } from "./renderer.js";
package/dist/browser.js CHANGED
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.renderMarkdownToPdf = exports.oceanTheme = exports.minimalTheme = exports.academicTheme = exports.modernTheme = exports.themes = exports.defaultSyntaxHighlightTheme = exports.defaultPageLayout = exports.defaultTheme = exports.createBrowserColorEmojiRenderer = exports.createBrowserImageRenderer = void 0;
4
+ /**
5
+ * Browser-specific entry point that excludes Node.js dependencies
6
+ */
4
7
  var browser_image_renderer_js_1 = require("./browser-image-renderer.js");
5
8
  Object.defineProperty(exports, "createBrowserImageRenderer", { enumerable: true, get: function () { return browser_image_renderer_js_1.createBrowserImageRenderer; } });
6
9
  var color_emoji_js_1 = require("./color-emoji.js");
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { TextStyle, PageLayout, CodeStyle, CodeBlockStyle, BlockquoteStyle, TableStyles, TokenColors, SyntaxHighlightTheme, ThemeConfig, PdfOptions, ColorEmojiRenderer, } from './types.js';
1
+ export type { TextStyle, PageLayout, CodeStyle, CodeBlockStyle, BlockquoteStyle, TableStyles, TokenColors, SyntaxHighlightTheme, ThemeConfig, PdfOptions, ColorEmojiRenderer, CustomFontDefinition, } from './types.js';
2
2
  export { defaultTheme, defaultPageLayout, defaultSyntaxHighlightTheme } from './styles.js';
3
3
  export { renderMarkdownToPdf as generatePdf, renderMarkdownToPdf, } from "./renderer.js";
4
4
  export { createBrowserImageRenderer } from './browser-image-renderer.js';
package/dist/renderer.js CHANGED
@@ -67,6 +67,26 @@ async function renderMarkdownToPdf(markdown, options) {
67
67
  // fall through without emoji support.
68
68
  }
69
69
  }
70
+ // ── Custom font registration ─────────────────────────────────────────────
71
+ // Register user-supplied font families so they can be referenced by name
72
+ // in ThemeConfig font fields. Each variant is registered with a suffix:
73
+ // name (regular), name-Bold, name-Italic, name-BoldItalic
74
+ // Missing variants fall back: boldItalic → bold → regular, italic → regular.
75
+ const customFontNames = new Set();
76
+ if (options?.customFonts) {
77
+ for (const cf of options.customFonts) {
78
+ try {
79
+ doc.registerFont(cf.name, cf.regular);
80
+ doc.registerFont(`${cf.name}-Bold`, cf.bold ?? cf.regular);
81
+ doc.registerFont(`${cf.name}-Italic`, cf.italic ?? cf.regular);
82
+ doc.registerFont(`${cf.name}-BoldItalic`, cf.boldItalic ?? cf.bold ?? cf.regular);
83
+ customFontNames.add(cf.name);
84
+ }
85
+ catch {
86
+ // Font registration failed — skip this font gracefully.
87
+ }
88
+ }
89
+ }
70
90
  // ── Color emoji pre-render ─────────────────────────────────────────────
71
91
  // When a colorEmoji renderer is provided, pre-scan the entire markdown for
72
92
  // every unique emoji and convert them all to PNG buffers up-front. This
@@ -92,8 +112,38 @@ async function renderMarkdownToPdf(markdown, options) {
92
112
  doc.addPage();
93
113
  }
94
114
  }
95
- /** Derive the italic variant of a PDFKit built-in font name. */
115
+ /** Check whether `font` (or its base name) is a registered custom font. */
116
+ function isCustomFont(font) {
117
+ if (customFontNames.has(font))
118
+ return true;
119
+ // Also match variant names like "Roboto-Bold"
120
+ const dash = font.lastIndexOf('-');
121
+ if (dash > 0)
122
+ return customFontNames.has(font.substring(0, dash));
123
+ return false;
124
+ }
125
+ /** Return the base (registered) name of a custom font, stripping any variant suffix. */
126
+ function customFontBase(font) {
127
+ if (customFontNames.has(font))
128
+ return font;
129
+ const dash = font.lastIndexOf('-');
130
+ if (dash > 0) {
131
+ const base = font.substring(0, dash);
132
+ if (customFontNames.has(base))
133
+ return base;
134
+ }
135
+ return font;
136
+ }
137
+ /** Derive the italic variant of a font name. */
96
138
  function italicVariant(font) {
139
+ // Custom fonts use Name-Italic / Name-BoldItalic
140
+ if (isCustomFont(font)) {
141
+ const base = customFontBase(font);
142
+ if (font.endsWith('-Bold'))
143
+ return `${base}-BoldItalic`;
144
+ return `${base}-Italic`;
145
+ }
146
+ // Built-in Times family
97
147
  if (font.startsWith('Times'))
98
148
  return font.replace(/-Bold$/, '-BoldItalic').replace(/^Times-Roman$/, 'Times-Italic');
99
149
  // Helvetica / Courier families use "Oblique"
@@ -101,22 +151,49 @@ async function renderMarkdownToPdf(markdown, options) {
101
151
  return font + 'Oblique';
102
152
  return font + '-Oblique';
103
153
  }
154
+ /** Resolve the correct font variant (regular / bold / italic / bold-italic). */
155
+ function resolveFont(baseFont, bold, italic) {
156
+ if (isCustomFont(baseFont)) {
157
+ const base = customFontBase(baseFont);
158
+ if (bold && italic)
159
+ return `${base}-BoldItalic`;
160
+ if (bold)
161
+ return `${base}-Bold`;
162
+ if (italic)
163
+ return `${base}-Italic`;
164
+ return base;
165
+ }
166
+ // Built-in PDFKit fonts — strip existing variant suffix before applying,
167
+ // so that e.g. 'Helvetica-Bold' + bold doesn't produce 'Helvetica-Bold-Bold'.
168
+ if (baseFont.startsWith('Times')) {
169
+ if (bold && italic)
170
+ return 'Times-BoldItalic';
171
+ if (bold)
172
+ return 'Times-Bold';
173
+ if (italic)
174
+ return 'Times-Italic';
175
+ return baseFont;
176
+ }
177
+ // Helvetica / Courier families: strip any existing variant suffix first
178
+ const family = baseFont.replace(/-(Bold|Oblique|BoldOblique)$/, '');
179
+ if (bold && italic)
180
+ return `${family}-BoldOblique`;
181
+ if (bold)
182
+ return `${family}-Bold`;
183
+ if (italic)
184
+ return `${family}-Oblique`;
185
+ return family;
186
+ }
104
187
  function applyBodyFont(bold, italic) {
105
188
  if (headingCtx) {
106
189
  // Inside a heading — use heading style as the base.
107
190
  let font = headingCtx.font;
108
- if (italic)
109
- font = italicVariant(font);
191
+ if (bold || italic)
192
+ font = resolveFont(font, bold, italic);
110
193
  doc.font(font).fontSize(headingCtx.fontSize).fillColor(headingCtx.color);
111
194
  return;
112
195
  }
113
- let font = theme.body.font;
114
- if (bold && italic)
115
- font = 'Helvetica-BoldOblique';
116
- else if (bold)
117
- font = 'Helvetica-Bold';
118
- else if (italic)
119
- font = 'Helvetica-Oblique';
196
+ const font = resolveFont(theme.body.font, bold, italic);
120
197
  doc.font(font).fontSize(theme.body.fontSize).fillColor(theme.body.color);
121
198
  }
122
199
  function resetBodyFont() {
@@ -684,7 +761,7 @@ async function renderMarkdownToPdf(markdown, options) {
684
761
  for (const child of t.tokens) {
685
762
  if (child.type === 'paragraph') {
686
763
  const p = child;
687
- const font = bq.italic ? 'Helvetica-Oblique' : theme.body.font;
764
+ const font = bq.italic ? italicVariant(theme.body.font) : theme.body.font;
688
765
  doc.font(font).fontSize(theme.body.fontSize).fillColor(theme.body.color);
689
766
  doc.text('', textX, doc.y, { width: textWidth });
690
767
  await renderInlineTokens(p.tokens, false, false, bq.italic);
package/dist/types.d.ts CHANGED
@@ -73,6 +73,25 @@ export interface ThemeConfig {
73
73
  */
74
74
  syntaxHighlight?: SyntaxHighlightTheme;
75
75
  }
76
+ /**
77
+ * A custom font definition providing font data for registration with PDFKit.
78
+ *
79
+ * Supply at minimum a `name` and `regular` buffer. Missing bold / italic /
80
+ * bold-italic variants fall back: boldItalic → bold → regular,
81
+ * italic → regular, bold → regular.
82
+ */
83
+ export interface CustomFontDefinition {
84
+ /** The name to use in ThemeConfig font fields (e.g. 'Roboto'). */
85
+ name: string;
86
+ /** Regular weight font data. */
87
+ regular: Buffer;
88
+ /** Bold variant (falls back to regular). */
89
+ bold?: Buffer;
90
+ /** Italic variant (falls back to regular). */
91
+ italic?: Buffer;
92
+ /** Bold-italic variant (falls back to bold or regular). */
93
+ boldItalic?: Buffer;
94
+ }
76
95
  /** Converts a single emoji string to a PNG `Buffer`. */
77
96
  export type ColorEmojiRenderer = (emoji: string) => Promise<Buffer>;
78
97
  export interface PdfOptions {
@@ -146,4 +165,12 @@ export interface PdfOptions {
146
165
  * monochrome font or the body font.
147
166
  */
148
167
  colorEmoji?: ColorEmojiRenderer;
168
+ /**
169
+ * Custom font definitions to register with PDFKit.
170
+ *
171
+ * Each entry provides font data (as `Buffer`s) for a named font family
172
+ * with optional bold, italic, and bold-italic variants. The `name` can
173
+ * then be used in any `ThemeConfig` font field (e.g. `body.font`).
174
+ */
175
+ customFonts?: CustomFontDefinition[];
149
176
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@speajus/markdown-to-pdf",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "A new project created with Intent by Augment.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",