printdown 1.0.0 → 1.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/markdown/index.ts","../src/markdown/plugins/highlight.ts","../src/markdown/plugins/task-list.ts","../src/markdown/plugins/badge.ts","../src/markdown/plugins/kbd.ts","../src/markdown/plugins/center.ts","../src/markdown/plugins/heading.ts","../src/renderer/index.ts","../src/renderer/html.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createMarkdownRenderer } from \"./markdown/index.js\";\nimport { BrowserRenderer, renderHtmlToBuffer, renderHtmlToPageBuffers } from \"./renderer/index.js\";\nimport { buildHtmlDocument } from \"./renderer/html.js\";\nimport { defaultTheme, defaultThemeCss, defaultThemeCssParts } from \"./themes/default/index.js\";\nimport type { OutputFormat, RenderFileOptions, RenderOptions } from \"./types.js\";\n\nexport * from \"./types.js\";\nexport {\n BrowserRenderer,\n createMarkdownRenderer,\n defaultTheme,\n defaultThemeCss,\n defaultThemeCssParts,\n renderHtmlToPageBuffers,\n};\n\nfunction inferFormat(output?: string, explicitFormat?: OutputFormat): OutputFormat {\n if (explicitFormat) {\n return explicitFormat;\n }\n if (output) {\n const ext = path.extname(output).toLowerCase();\n if (ext === \".png\") return \"png\";\n if (ext === \".jpg\" || ext === \".jpeg\") return \"jpeg\";\n if (ext === \".webp\") return \"webp\";\n if (ext === \".pdf\") return \"pdf\";\n }\n return \"pdf\";\n}\n\nfunction resolvePageOutputFilePath(\n outputPath: string,\n pageIndex: number,\n totalPages: number,\n): string {\n const pageNumber = pageIndex + 1;\n if (outputPath.includes(\"%d\")) {\n return outputPath.replace(/%d/g, String(pageNumber));\n }\n if (totalPages === 1 && !outputPath.includes(\"-1\")) {\n // If only 1 page, we can still use -1 or keep name, but let's append -1 for consistency with multi-page requests\n const parsed = path.parse(outputPath);\n return path.join(parsed.dir, `${parsed.name}-${pageNumber}${parsed.ext}`);\n }\n const parsed = path.parse(outputPath);\n return path.join(parsed.dir, `${parsed.name}-${pageNumber}${parsed.ext}`);\n}\n\n/**\n * Compiles Markdown into an HTML document with theme and custom styles.\n */\nexport async function renderToHtml(markdown: string, options: RenderOptions = {}): Promise<string> {\n const md = await createMarkdownRenderer(options.markdown);\n const bodyHtml = md.render(markdown);\n return buildHtmlDocument(bodyHtml, options);\n}\n\n/**\n * Renders Markdown to multiple page image buffers (matching A4 / PDF page dimensions).\n * If `options.output` is provided, each page image will be saved to disk.\n */\nexport async function renderPages(\n markdown: string,\n options: RenderOptions = {},\n): Promise<Buffer[]> {\n const format = inferFormat(options.output, options.format);\n const html = await renderToHtml(markdown, options);\n const buffers = await renderHtmlToPageBuffers(html, format, options);\n\n if (options.output) {\n const resolvedPath = path.resolve(options.output);\n const outputDir = path.dirname(resolvedPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n if (format === \"pdf\" && buffers.length === 1) {\n fs.writeFileSync(resolvedPath, buffers[0]);\n } else {\n buffers.forEach((buf, idx) => {\n const filePath = resolvePageOutputFilePath(resolvedPath, idx, buffers.length);\n fs.writeFileSync(filePath, buf);\n });\n }\n }\n\n return buffers;\n}\n\n/**\n * Renders a Markdown file to multiple page image buffers.\n * If `options.output` is provided, each page image will be saved to disk.\n */\nexport async function renderFilePages(\n filePath: string,\n options: RenderFileOptions = {},\n): Promise<Buffer[]> {\n const absolutePath = path.resolve(filePath);\n const encoding = options.encoding ?? \"utf-8\";\n const markdown = fs.readFileSync(absolutePath, encoding);\n\n const fileDir = path.dirname(absolutePath);\n const baseUrl = options.baseUrl ?? fileDir;\n\n return renderPages(markdown, {\n baseUrl,\n ...options,\n });\n}\n\n/**\n * Renders Markdown to PDF, PNG, JPEG, or WebP buffer (or multiple buffers if `options.pages` is true).\n * If `options.output` is provided, the result is saved to disk.\n */\nexport async function render(\n markdown: string,\n options?: RenderOptions & { pages?: false },\n): Promise<Buffer>;\nexport async function render(\n markdown: string,\n options: RenderOptions & { pages: true },\n): Promise<Buffer[]>;\nexport async function render(markdown: string, options?: RenderOptions): Promise<Buffer | Buffer[]>;\nexport async function render(\n markdown: string,\n options: RenderOptions = {},\n): Promise<Buffer | Buffer[]> {\n if (options.pages) {\n return renderPages(markdown, options);\n }\n\n const format = inferFormat(options.output, options.format);\n const html = await renderToHtml(markdown, options);\n const buffer = await renderHtmlToBuffer(html, format, options);\n\n if (options.output) {\n const outputPath = path.resolve(options.output);\n const outputDir = path.dirname(outputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n fs.writeFileSync(outputPath, buffer);\n }\n\n return buffer;\n}\n\n/**\n * Renders a Markdown file to PDF, PNG, JPEG, or WebP buffer (or multiple buffers if `options.pages` is true).\n * If `options.output` is provided, the result is saved to disk.\n */\nexport async function renderFile(\n filePath: string,\n options?: RenderFileOptions & { pages?: false },\n): Promise<Buffer>;\nexport async function renderFile(\n filePath: string,\n options: RenderFileOptions & { pages: true },\n): Promise<Buffer[]>;\nexport async function renderFile(\n filePath: string,\n options?: RenderFileOptions,\n): Promise<Buffer | Buffer[]>;\nexport async function renderFile(\n filePath: string,\n options: RenderFileOptions = {},\n): Promise<Buffer | Buffer[]> {\n const absolutePath = path.resolve(filePath);\n const encoding = options.encoding ?? \"utf-8\";\n const markdown = fs.readFileSync(absolutePath, encoding);\n\n const fileDir = path.dirname(absolutePath);\n const baseUrl = options.baseUrl ?? fileDir;\n\n if (options.pages) {\n return renderPages(markdown, {\n baseUrl,\n ...options,\n });\n }\n\n return render(markdown, {\n baseUrl,\n ...options,\n });\n}\n","import MarkdownIt from \"markdown-it\";\nimport {\n createHighlighter,\n type BundledLanguage,\n type BundledTheme,\n type Highlighter,\n} from \"shiki\";\nimport { highlightPlugin } from \"./plugins/highlight.js\";\nimport { taskListPlugin } from \"./plugins/task-list.js\";\nimport { badgePlugin } from \"./plugins/badge.js\";\nimport { kbdPlugin } from \"./plugins/kbd.js\";\nimport { centerPlugin } from \"./plugins/center.js\";\nimport { headingPlugin } from \"./plugins/heading.js\";\n\nexport interface MarkdownOptions {\n html?: boolean;\n linkify?: boolean;\n typographer?: boolean;\n shiki?: {\n theme?: BundledTheme | string;\n langs?: (BundledLanguage | string)[];\n };\n}\n\nconst DEFAULT_LANGS: BundledLanguage[] = [\n \"javascript\",\n \"typescript\",\n \"jsx\",\n \"tsx\",\n \"html\",\n \"css\",\n \"json\",\n \"markdown\",\n \"mdx\",\n \"bash\",\n \"shell\",\n \"yaml\",\n \"toml\",\n \"sql\",\n \"python\",\n \"rust\",\n \"go\",\n \"c\",\n \"cpp\",\n \"diff\",\n \"dockerfile\",\n \"graphql\",\n \"ini\",\n \"java\",\n \"kotlin\",\n \"ruby\",\n \"php\",\n \"swift\",\n \"xml\",\n];\n\nconst DEFAULT_THEME: BundledTheme = \"github-dark\";\n\nlet cachedHighlighter: Highlighter | null = null;\nconst cachedLangs = new Set<string>();\nconst cachedThemes = new Set<string>();\n\nexport async function getHighlighter(options?: MarkdownOptions[\"shiki\"]): Promise<Highlighter> {\n const theme = (options?.theme as BundledTheme) || DEFAULT_THEME;\n const userLangs = (options?.langs as BundledLanguage[]) || [];\n const requiredLangs = Array.from(new Set([...DEFAULT_LANGS, ...userLangs]));\n\n if (!cachedHighlighter) {\n cachedHighlighter = await createHighlighter({\n themes: [theme],\n langs: requiredLangs,\n });\n for (const lang of requiredLangs) {\n cachedLangs.add(lang);\n }\n cachedThemes.add(theme);\n return cachedHighlighter;\n }\n\n // Load missing theme if necessary\n if (!cachedThemes.has(theme)) {\n await cachedHighlighter.loadTheme(theme);\n cachedThemes.add(theme);\n }\n\n // Load missing languages if necessary\n const missingLangs = requiredLangs.filter((l) => !cachedLangs.has(l));\n if (missingLangs.length > 0) {\n await cachedHighlighter.loadLanguage(...missingLangs);\n for (const lang of missingLangs) {\n cachedLangs.add(lang);\n }\n }\n\n return cachedHighlighter;\n}\n\nexport async function createMarkdownRenderer(\n options: MarkdownOptions = {},\n): Promise<InstanceType<typeof MarkdownIt>> {\n const md = new MarkdownIt({\n html: options.html ?? true,\n linkify: options.linkify ?? true,\n typographer: options.typographer ?? true,\n });\n\n // Apply plugins\n md.use(highlightPlugin);\n md.use(taskListPlugin);\n md.use(badgePlugin);\n md.use(kbdPlugin);\n md.use(centerPlugin);\n md.use(headingPlugin);\n\n // Initialize Shiki\n const highlighter = await getHighlighter(options.shiki);\n const theme = options.shiki?.theme || DEFAULT_THEME;\n\n // Custom fence renderer\n const defaultFence = md.renderer.rules.fence;\n md.renderer.rules.fence = (tokens, idx, fenceOptions, env, self) => {\n const token = tokens[idx];\n const info = token.info ? token.info.trim() : \"\";\n const lang = info ? info.split(/\\s+/)[0] : \"text\";\n const code = token.content;\n\n try {\n const loadedLangs = highlighter.getLoadedLanguages();\n const targetLang = loadedLangs.includes(lang) ? lang : \"text\";\n\n return highlighter.codeToHtml(code, {\n lang: targetLang,\n theme,\n transformers: [\n {\n pre(node) {\n const existingClass = (node.properties.class as string) || \"\";\n node.properties.class = `printdown-code ${existingClass}`.trim();\n },\n },\n ],\n });\n } catch {\n // Fallback to default fence rule or simple pre/code\n if (defaultFence) {\n return defaultFence(tokens, idx, fenceOptions, env, self);\n }\n return `<pre class=\"printdown-code\"><code>${md.utils.escapeHtml(code)}</code></pre>\\n`;\n }\n };\n\n return md;\n}\n","import type MarkdownIt from \"markdown-it\";\nimport type { StateInline } from \"markdown-it\";\n\nexport function highlightPlugin(md: InstanceType<typeof MarkdownIt>): void {\n function tokenize(state: StateInline, silent: boolean): boolean {\n const start = state.pos;\n const marker = state.src.charCodeAt(start);\n\n // 0x3d is '='\n if (marker !== 0x3d) {\n return false;\n }\n\n const scanned = state.scanDelims(state.pos, true);\n const len = scanned.length;\n const ch = String.fromCharCode(marker);\n\n if (len < 2) {\n return false;\n }\n\n let isColor = false;\n let color = \"blue\";\n\n // Check if opener has {color}\n if (scanned.can_open) {\n const match = state.src.slice(start + len).match(/^\\{([a-zA-Z0-9_-]+)\\}/);\n if (match) {\n isColor = true;\n color = match[1];\n state.pos += match[0].length;\n }\n }\n\n if (silent) {\n state.pos += len;\n return true;\n }\n\n for (let i = 0; i < Math.floor(len / 2); i++) {\n const token = state.push(\"text\", \"\", 0);\n token.content = ch + ch;\n\n state.delimiters.push({\n marker: 0x3d,\n length: 0,\n jump: i,\n token: state.tokens.length - 1,\n level: state.level,\n end: -1,\n open: scanned.can_open,\n close: scanned.can_close,\n color: isColor ? color : \"blue\",\n } as unknown as (typeof state.delimiters)[number]);\n }\n\n state.pos += len;\n return true;\n }\n\n function postProcess(state: StateInline): void {\n const delimiters = state.delimiters;\n if (!delimiters) return;\n\n for (let i = 0; i < delimiters.length; i++) {\n const startDelim = delimiters[i] as unknown as {\n marker: number;\n end: number;\n token: number;\n color?: string;\n };\n if (startDelim.marker !== 0x3d || startDelim.end === -1) continue;\n\n const endDelim = delimiters[startDelim.end] as unknown as {\n token: number;\n };\n\n const tokenStart = state.tokens[startDelim.token];\n tokenStart.type = \"mark_open\";\n tokenStart.tag = \"mark\";\n tokenStart.nesting = 1;\n tokenStart.markup = \"==\";\n tokenStart.content = \"\";\n tokenStart.attrs = [\n [\"class\", `printdown-highlight printdown-highlight--${startDelim.color || \"blue\"}`],\n ];\n\n const tokenEnd = state.tokens[endDelim.token];\n tokenEnd.type = \"mark_close\";\n tokenEnd.tag = \"mark\";\n tokenEnd.nesting = -1;\n tokenEnd.markup = \"==\";\n tokenEnd.content = \"\";\n }\n }\n\n md.inline.ruler.before(\"emphasis\", \"highlight\", tokenize);\n md.inline.ruler2.before(\"emphasis\", \"highlight\", (state: StateInline) => {\n const delimiters = state.delimiters;\n if (!delimiters) return;\n\n for (let i = 0; i < delimiters.length; i++) {\n const startDelim = delimiters[i];\n if (startDelim.marker !== 0x3d) continue;\n\n for (let j = i + 1; j < delimiters.length; j++) {\n const endDelim = delimiters[j];\n if (endDelim.marker !== 0x3d) continue;\n\n if (startDelim.open && endDelim.close && endDelim.end === -1 && startDelim.end === -1) {\n startDelim.end = j;\n endDelim.end = i;\n break;\n }\n }\n }\n\n postProcess(state);\n });\n}\n","import type MarkdownIt from \"markdown-it\";\nimport type { StateCore, Token } from \"markdown-it\";\n\nconst TASK_LIST_REGEX = /^\\[([ xX])\\][ \\t]+/;\n\nexport function taskListPlugin(md: InstanceType<typeof MarkdownIt>): void {\n md.core.ruler.after(\"inline\", \"task_list\", (state: StateCore) => {\n const tokens = state.tokens;\n\n for (let i = 0; i < tokens.length; i++) {\n if (tokens[i].type !== \"bullet_list_open\") {\n continue;\n }\n\n // Check if this list contains any task list items\n let listEnd = i + 1;\n let depth = 1;\n let hasTaskItems = false;\n\n while (listEnd < tokens.length && depth > 0) {\n if (tokens[listEnd].type === \"bullet_list_open\") {\n depth++;\n } else if (tokens[listEnd].type === \"bullet_list_close\") {\n depth--;\n }\n listEnd++;\n }\n\n // Scan items within this list level\n for (let j = i + 1; j < listEnd; j++) {\n if (tokens[j].type === \"list_item_open\") {\n // Look for paragraph -> inline\n const inlineTokenIndex = findFirstInlineToken(tokens, j);\n if (inlineTokenIndex !== -1) {\n const inlineToken = tokens[inlineTokenIndex];\n if (isTaskListItem(inlineToken)) {\n hasTaskItems = true;\n break;\n }\n }\n }\n }\n\n if (!hasTaskItems) {\n continue;\n }\n\n // Add class to bullet_list_open\n addClass(tokens[i], \"printdown-task-list\");\n\n // Now transform each task list item\n for (let j = i + 1; j < listEnd; j++) {\n if (tokens[j].type === \"list_item_open\") {\n const inlineTokenIndex = findFirstInlineToken(tokens, j);\n if (inlineTokenIndex !== -1) {\n const inlineToken = tokens[inlineTokenIndex];\n const match = getTaskListMatch(inlineToken);\n if (match) {\n addClass(tokens[j], \"printdown-task-list-item\");\n const isChecked = match[1].toLowerCase() === \"x\";\n removeTaskListPrefix(inlineToken);\n insertCheckboxToken(inlineToken, isChecked, state.Token);\n }\n }\n }\n }\n }\n });\n}\n\nfunction findFirstInlineToken(tokens: Token[], listItemIndex: number): number {\n for (let i = listItemIndex + 1; i < tokens.length; i++) {\n if (tokens[i].type === \"list_item_close\" || tokens[i].type === \"list_item_open\") {\n return -1;\n }\n if (tokens[i].type === \"inline\") {\n return i;\n }\n }\n return -1;\n}\n\nfunction isTaskListItem(inlineToken: Token): boolean {\n if (!inlineToken.children || inlineToken.children.length === 0) {\n return false;\n }\n const firstChild = inlineToken.children[0];\n return firstChild.type === \"text\" && TASK_LIST_REGEX.test(firstChild.content);\n}\n\nfunction getTaskListMatch(inlineToken: Token): RegExpMatchArray | null {\n if (!inlineToken.children || inlineToken.children.length === 0) {\n return null;\n }\n const firstChild = inlineToken.children[0];\n if (firstChild.type === \"text\") {\n return firstChild.content.match(TASK_LIST_REGEX);\n }\n return null;\n}\n\nfunction removeTaskListPrefix(inlineToken: Token): void {\n if (!inlineToken.children || inlineToken.children.length === 0) {\n return;\n }\n const firstChild = inlineToken.children[0];\n if (firstChild.type === \"text\") {\n firstChild.content = firstChild.content.replace(TASK_LIST_REGEX, \"\");\n }\n}\n\nfunction insertCheckboxToken(\n inlineToken: Token,\n checked: boolean,\n TokenConstructor: typeof Token,\n): void {\n const checkboxToken = new TokenConstructor(\"html_inline\", \"\", 0);\n checkboxToken.content = `<input class=\"printdown-task-list-checkbox\" type=\"checkbox\" disabled${\n checked ? ' checked=\"\"' : \"\"\n } /> `;\n if (!inlineToken.children) {\n inlineToken.children = [];\n }\n inlineToken.children.unshift(checkboxToken);\n}\n\nfunction addClass(token: Token, className: string): void {\n const classIndex = token.attrIndex(\"class\");\n if (classIndex < 0) {\n token.attrPush([\"class\", className]);\n } else if (token.attrs) {\n const existing = token.attrs[classIndex][1];\n if (typeof existing === \"string\" && !existing.split(\" \").includes(className)) {\n token.attrs[classIndex][1] = `${existing} ${className}`.trim();\n }\n }\n}\n","import type MarkdownIt from \"markdown-it\";\nimport type { StateCore, StateInline, Token } from \"markdown-it\";\n\nexport type BadgeVariant = \"solid\" | \"soft\" | \"outline\";\n\nconst BADGE_MARKDOWN_REGEX = /^\\[badge(?:\\(([^)]+)\\)|\\{([^}]+)\\})?:([\\s\\S]*?)\\]/i;\nconst BADGE_OPEN_TAG_REGEX = /^<badge(\\s+[^>]*)?>$/i;\nconst BADGE_CLOSE_TAG_REGEX = /^<\\/badge>$/i;\nconst BADGE_SELF_CLOSING_REGEX = /^<badge(\\s+[^>]*)?\\/>$/i;\n\nfunction parseBadgeOptions(optionsStr?: string): { variant: BadgeVariant; color: string } {\n let variant: BadgeVariant = \"solid\";\n let color = \"blue\";\n\n if (!optionsStr) {\n return { variant, color };\n }\n\n const parts = optionsStr\n .split(/[\\s,]+/)\n .map((p) => p.trim().toLowerCase())\n .filter(Boolean);\n\n for (const part of parts) {\n if (part === \"solid\" || part === \"soft\" || part === \"outline\") {\n variant = part;\n } else if (/^[a-z0-9_-]+$/.test(part)) {\n color = part;\n }\n }\n\n return { variant, color };\n}\n\nfunction parseBadgeAttrs(attrsStr?: string): { variant: BadgeVariant; color: string } {\n let variant: BadgeVariant = \"solid\";\n let color = \"blue\";\n\n if (!attrsStr) {\n return { variant, color };\n }\n\n const variantMatch = attrsStr.match(/variant=[\"']?([a-zA-Z0-9_-]+)[\"']?/i);\n if (variantMatch) {\n const v = variantMatch[1].toLowerCase();\n if (v === \"solid\" || v === \"soft\" || v === \"outline\") {\n variant = v;\n }\n }\n\n const colorMatch = attrsStr.match(/color=[\"']?([a-zA-Z0-9_-]+)[\"']?/i);\n if (colorMatch) {\n color = colorMatch[1].toLowerCase();\n }\n\n return { variant, color };\n}\n\nexport function badgePlugin(md: InstanceType<typeof MarkdownIt>): void {\n // 1. Inline ruler for markdown syntax: [badge:Text], [badge(soft):Text], [badge(outline,amber):Text], [badge{amber}:Text]\n function inlineBadgeRule(state: StateInline, silent: boolean): boolean {\n const max = state.posMax;\n const start = state.pos;\n\n if (state.src.charCodeAt(start) !== 0x5b /* '[' */) {\n return false;\n }\n\n const match = state.src.slice(start).match(BADGE_MARKDOWN_REGEX);\n if (!match) {\n return false;\n }\n\n const matchedLength = match[0].length;\n if (start + matchedLength > max) {\n return false;\n }\n\n if (silent) {\n state.pos += matchedLength;\n return true;\n }\n\n const rawOptions = match[1] || match[2] || \"\";\n const badgeText = match[3];\n const { variant, color } = parseBadgeOptions(rawOptions);\n\n const tokenOpen = state.push(\"badge_open\", \"span\", 1);\n tokenOpen.attrs = [\n [\"class\", `printdown-badge printdown-badge--${variant} printdown-badge--${color}`],\n ];\n\n // Parse nested inline markdown if any\n const nestedTokens: Token[] = [];\n state.md.inline.parse(badgeText, state.md, state.env, nestedTokens);\n for (const nested of nestedTokens) {\n state.tokens.push(nested);\n }\n\n state.push(\"badge_close\", \"span\", -1);\n\n state.pos += matchedLength;\n return true;\n }\n\n md.inline.ruler.before(\"link\", \"badge\", inlineBadgeRule);\n\n // 2. Core ruler to process <Badge ...> and <badge ...> HTML tags\n md.core.ruler.after(\"inline\", \"badge_tags\", (state: StateCore) => {\n const tokens = state.tokens;\n\n function processToken(token: Token) {\n if (token.type === \"html_inline\") {\n const trimmed = token.content.trim();\n\n if (BADGE_SELF_CLOSING_REGEX.test(trimmed)) {\n const match = trimmed.match(BADGE_SELF_CLOSING_REGEX);\n const { variant, color } = parseBadgeAttrs(match?.[1]);\n token.content = `<span class=\"printdown-badge printdown-badge--${variant} printdown-badge--${color}\"></span>`;\n } else if (BADGE_OPEN_TAG_REGEX.test(trimmed)) {\n const match = trimmed.match(BADGE_OPEN_TAG_REGEX);\n const { variant, color } = parseBadgeAttrs(match?.[1]);\n token.content = `<span class=\"printdown-badge printdown-badge--${variant} printdown-badge--${color}\">`;\n } else if (BADGE_CLOSE_TAG_REGEX.test(trimmed)) {\n token.content = `</span>`;\n }\n } else if (token.type === \"html_block\") {\n token.content = token.content.replace(\n /<badge(\\s+[^>]*)?>([\\s\\S]*?)<\\/badge>/gi,\n (_, attrs, body) => {\n const { variant, color } = parseBadgeAttrs(attrs);\n return `<span class=\"printdown-badge printdown-badge--${variant} printdown-badge--${color}\">${body}</span>`;\n },\n );\n }\n }\n\n for (let i = 0; i < tokens.length; i++) {\n processToken(tokens[i]);\n if (tokens[i].children) {\n for (let j = 0; j < tokens[i].children!.length; j++) {\n processToken(tokens[i].children![j]);\n }\n }\n }\n });\n}\n","import type MarkdownIt from \"markdown-it\";\nimport type { StateCore, StateInline, Token } from \"markdown-it\";\n\nconst KBD_MARKDOWN_REGEX = /^\\[kbd(?:\\(([^)]+)\\))?:([\\s\\S]*?)\\]/i;\nconst KBD_ICON_ONLY_REGEX = /^\\[kbd\\(([^)]+)\\)\\]/i;\nconst KBD_OPEN_TAG_REGEX = /^<kbd(\\s+[^>]*)?>$/i;\nconst KBD_CLOSE_TAG_REGEX = /^<\\/kbd>$/i;\nconst KBD_SELF_CLOSING_REGEX = /^<kbd(\\s+[^>]*)?\\/>$/i;\n\nfunction parseKbdAttrs(attrsStr?: string): { icon?: string } {\n if (!attrsStr) return {};\n\n const iconMatch = attrsStr.match(/icon=[\"']?([a-zA-Z0-9_-]+)[\"']?/i);\n if (iconMatch) {\n return { icon: iconMatch[1].toLowerCase() };\n }\n return {};\n}\n\nexport function kbdPlugin(md: InstanceType<typeof MarkdownIt>): void {\n // 1. Inline ruler for markdown syntax: [kbd:K], [kbd(command)], [kbd(command):K], [kbd:Ctrl]\n function inlineKbdRule(state: StateInline, silent: boolean): boolean {\n const max = state.posMax;\n const start = state.pos;\n\n if (state.src.charCodeAt(start) !== 0x5b /* '[' */) {\n return false;\n }\n\n const rest = state.src.slice(start);\n\n // Try [kbd(icon):Text] or [kbd:Text]\n const matchWithText = rest.match(KBD_MARKDOWN_REGEX);\n // Try [kbd(icon)]\n const matchIconOnly = !matchWithText ? rest.match(KBD_ICON_ONLY_REGEX) : null;\n\n const match = matchWithText || matchIconOnly;\n if (!match) {\n return false;\n }\n\n const matchedLength = match[0].length;\n if (start + matchedLength > max) {\n return false;\n }\n\n if (silent) {\n state.pos += matchedLength;\n return true;\n }\n\n const icon = matchWithText ? matchWithText[1] : matchIconOnly ? matchIconOnly[1] : undefined;\n const kbdText = matchWithText ? matchWithText[2] : \"\";\n\n const tokenOpen = state.push(\"kbd_open\", \"kbd\", 1);\n tokenOpen.attrs = [[\"class\", \"printdown-kbd\"]];\n\n if (icon) {\n const iconToken = state.push(\"html_inline\", \"\", 0);\n iconToken.content = `<span class=\"printdown-kbd-icon printdown-kbd-icon--${icon.toLowerCase()}\"></span>`;\n }\n\n if (kbdText) {\n const nestedTokens: Token[] = [];\n state.md.inline.parse(kbdText, state.md, state.env, nestedTokens);\n for (const nested of nestedTokens) {\n state.tokens.push(nested);\n }\n }\n\n state.push(\"kbd_close\", \"kbd\", -1);\n\n state.pos += matchedLength;\n return true;\n }\n\n md.inline.ruler.before(\"link\", \"kbd\", inlineKbdRule);\n\n // 2. Core ruler to process <Kbd ...> and <kbd ...> HTML tags\n md.core.ruler.after(\"inline\", \"kbd_tags\", (state: StateCore) => {\n const tokens = state.tokens;\n\n function processToken(token: Token) {\n if (token.type === \"html_inline\") {\n const trimmed = token.content.trim();\n\n if (KBD_SELF_CLOSING_REGEX.test(trimmed)) {\n const match = trimmed.match(KBD_SELF_CLOSING_REGEX);\n const { icon } = parseKbdAttrs(match?.[1]);\n const iconHtml = icon\n ? `<span class=\"printdown-kbd-icon printdown-kbd-icon--${icon}\"></span>`\n : \"\";\n token.content = `<kbd class=\"printdown-kbd\">${iconHtml}</kbd>`;\n } else if (KBD_OPEN_TAG_REGEX.test(trimmed)) {\n const match = trimmed.match(KBD_OPEN_TAG_REGEX);\n const { icon } = parseKbdAttrs(match?.[1]);\n const iconHtml = icon\n ? `<span class=\"printdown-kbd-icon printdown-kbd-icon--${icon}\"></span>`\n : \"\";\n token.content = `<kbd class=\"printdown-kbd\">${iconHtml}`;\n } else if (KBD_CLOSE_TAG_REGEX.test(trimmed)) {\n token.content = `</kbd>`;\n }\n } else if (token.type === \"html_block\") {\n token.content = token.content.replace(\n /<kbd(\\s+[^>]*)?>([\\s\\S]*?)<\\/kbd>/gi,\n (_, attrs, body) => {\n const { icon } = parseKbdAttrs(attrs);\n const iconHtml = icon\n ? `<span class=\"printdown-kbd-icon printdown-kbd-icon--${icon}\"></span>`\n : \"\";\n return `<kbd class=\"printdown-kbd\">${iconHtml}${body}</kbd>`;\n },\n );\n }\n }\n\n for (let i = 0; i < tokens.length; i++) {\n processToken(tokens[i]);\n if (tokens[i].children) {\n for (let j = 0; j < tokens[i].children!.length; j++) {\n processToken(tokens[i].children![j]);\n }\n }\n }\n });\n}\n","import type MarkdownIt from \"markdown-it\";\nimport type { StateBlock, StateCore, StateInline, Token } from \"markdown-it\";\n\nconst CENTER_INLINE_BRACKET_REGEX = /^\\[center:([\\s\\S]*?)\\]/i;\nconst CENTER_INLINE_ARROW_REGEX = /^->\\s*([\\s\\S]*?)\\s*<-/;\n\nconst CENTER_OPEN_TAG_REGEX = /^<center(\\s+[^>]*)?>$/i;\nconst CENTER_CLOSE_TAG_REGEX = /^<\\/center>$/i;\n\n/**\n * Center alignment plugin for MarkdownIt.\n *\n * Supports:\n * 1. Inline bracket syntax: `[center:Centered Text]`\n * 2. Inline arrow syntax: `->Centered Text<-`\n * 3. Container block syntax: `::: center` ... `:::`\n * 4. Arrow block syntax: `->` ... `<-` or `-> Centered Line <-`\n * 5. HTML tags: `<center>...</center>` and `<Center>...</Center>`\n */\nexport function centerPlugin(md: InstanceType<typeof MarkdownIt>): void {\n // 1. Inline ruler for [center:...] and ->...<-\n function inlineCenterRule(state: StateInline, silent: boolean): boolean {\n const start = state.pos;\n const max = state.posMax;\n const src = state.src;\n\n // Check [center:...]\n if (src.charCodeAt(start) === 0x5b /* '[' */) {\n const match = src.slice(start).match(CENTER_INLINE_BRACKET_REGEX);\n if (match) {\n const matchedLength = match[0].length;\n if (start + matchedLength > max) return false;\n\n if (silent) {\n state.pos += matchedLength;\n return true;\n }\n\n const centerText = match[1];\n const tokenOpen = state.push(\"center_open\", \"span\", 1);\n tokenOpen.attrs = [[\"class\", \"printdown-center\"]];\n\n const nestedTokens: Token[] = [];\n state.md.inline.parse(centerText, state.md, state.env, nestedTokens);\n for (const nested of nestedTokens) {\n state.tokens.push(nested);\n }\n\n state.push(\"center_close\", \"span\", -1);\n state.pos += matchedLength;\n return true;\n }\n }\n\n // Check ->...<- inline\n if (src.charCodeAt(start) === 0x2d /* '-' */ && src.charCodeAt(start + 1) === 0x3e /* '>' */) {\n // Must not be preceded by another '-' (e.g. '-->')\n if (start > 0 && src.charCodeAt(start - 1) === 0x2d) {\n return false;\n }\n\n const rest = src.slice(start);\n const match = rest.match(CENTER_INLINE_ARROW_REGEX);\n if (match && match[1].length > 0) {\n const matchedLength = match[0].length;\n if (start + matchedLength > max) return false;\n\n if (silent) {\n state.pos += matchedLength;\n return true;\n }\n\n const centerText = match[1];\n const tokenOpen = state.push(\"center_open\", \"span\", 1);\n tokenOpen.attrs = [[\"class\", \"printdown-center\"]];\n\n const nestedTokens: Token[] = [];\n state.md.inline.parse(centerText, state.md, state.env, nestedTokens);\n for (const nested of nestedTokens) {\n state.tokens.push(nested);\n }\n\n state.push(\"center_close\", \"span\", -1);\n state.pos += matchedLength;\n return true;\n }\n }\n\n return false;\n }\n\n md.inline.ruler.before(\"link\", \"center_inline\", inlineCenterRule);\n\n // 2. Block ruler for ::: center and -> ... <-\n function blockCenterRule(\n state: StateBlock,\n startLine: number,\n endLine: number,\n silent: boolean,\n ): boolean {\n const startPos = state.bMarks[startLine] + state.tShift[startLine];\n const maxPos = state.eMarks[startLine];\n const lineText = state.src.slice(startPos, maxPos).trim();\n\n // Check for ::: center\n if (/^:::\\s*center\\s*$/i.test(lineText)) {\n if (silent) return true;\n\n let nextLine = startLine + 1;\n let foundEnd = false;\n\n while (nextLine < endLine) {\n const pos = state.bMarks[nextLine] + state.tShift[nextLine];\n const max = state.eMarks[nextLine];\n const curLine = state.src.slice(pos, max).trim();\n\n if (/^:::\\s*$/.test(curLine) || /^:::\\s*center\\s*$/i.test(curLine)) {\n foundEnd = true;\n break;\n }\n nextLine++;\n }\n\n const tokenOpen = state.push(\"center_container_open\", \"div\", 1);\n tokenOpen.attrs = [[\"class\", \"printdown-center\"]];\n tokenOpen.block = true;\n\n const oldParentType = state.parentType;\n state.parentType = \"root\";\n\n // Parse nested markdown blocks within container\n state.md.block.tokenize(state, startLine + 1, nextLine);\n\n state.parentType = oldParentType;\n\n const tokenClose = state.push(\"center_container_close\", \"div\", -1);\n tokenClose.block = true;\n\n state.line = foundEnd ? nextLine + 1 : nextLine;\n return true;\n }\n\n // Check for -> ... <- single line or multi-line block\n if (lineText.startsWith(\"->\")) {\n // Single line: -> Centered Text <-\n if (lineText.endsWith(\"<-\") && lineText.length >= 4) {\n if (silent) return true;\n\n const content = lineText.slice(2, -2).trim();\n const tokenOpen = state.push(\"center_container_open\", \"div\", 1);\n tokenOpen.attrs = [[\"class\", \"printdown-center\"]];\n tokenOpen.block = true;\n\n const pOpen = state.push(\"paragraph_open\", \"p\", 1);\n pOpen.attrs = [[\"class\", \"printdown-center\"]];\n const inlineToken = state.push(\"inline\", \"\", 0);\n inlineToken.content = content;\n inlineToken.children = [];\n state.push(\"paragraph_close\", \"p\", -1);\n\n const tokenClose = state.push(\"center_container_close\", \"div\", -1);\n tokenClose.block = true;\n\n state.line = startLine + 1;\n return true;\n }\n\n // Multi-line block starting with standalone '->'\n if (lineText === \"->\") {\n if (silent) return true;\n\n let nextLine = startLine + 1;\n let foundEnd = false;\n\n while (nextLine < endLine) {\n const pos = state.bMarks[nextLine] + state.tShift[nextLine];\n const max = state.eMarks[nextLine];\n const curLine = state.src.slice(pos, max).trim();\n\n if (curLine === \"<-\") {\n foundEnd = true;\n break;\n }\n nextLine++;\n }\n\n const tokenOpen = state.push(\"center_container_open\", \"div\", 1);\n tokenOpen.attrs = [[\"class\", \"printdown-center\"]];\n tokenOpen.block = true;\n\n const oldParentType = state.parentType;\n state.parentType = \"root\";\n\n state.md.block.tokenize(state, startLine + 1, nextLine);\n\n state.parentType = oldParentType;\n\n const tokenClose = state.push(\"center_container_close\", \"div\", -1);\n tokenClose.block = true;\n\n state.line = foundEnd ? nextLine + 1 : nextLine;\n return true;\n }\n }\n\n return false;\n }\n\n md.block.ruler.before(\"fence\", \"center_block\", blockCenterRule);\n\n // 3. Core ruler to process <center> and <Center> tags and parse inner markdown\n md.core.ruler.after(\"inline\", \"center_tags\", (state: StateCore) => {\n const tokens = state.tokens;\n\n function processToken(token: Token) {\n if (token.type === \"html_inline\") {\n const trimmed = token.content.trim();\n\n if (CENTER_OPEN_TAG_REGEX.test(trimmed)) {\n token.content = '<span class=\"printdown-center\">';\n } else if (CENTER_CLOSE_TAG_REGEX.test(trimmed)) {\n token.content = \"</span>\";\n }\n } else if (token.type === \"html_block\") {\n // Match <center>...</center> across multiple lines\n token.content = token.content.replace(\n /<center(\\s+[^>]*)?>([\\s\\S]*?)<\\/center>/gi,\n (_, _attrs, body) => {\n const rendered = md.render(body.trim()).trim();\n return `<div class=\"printdown-center\">${rendered}</div>`;\n },\n );\n }\n }\n\n for (let i = 0; i < tokens.length; i++) {\n processToken(tokens[i]);\n if (tokens[i].children) {\n for (let j = 0; j < tokens[i].children!.length; j++) {\n processToken(tokens[i].children![j]);\n }\n }\n }\n });\n}\n","import type MarkdownIt from \"markdown-it\";\nimport type { StateCore, Token } from \"markdown-it\";\n\nconst NO_BORDER_ATTR_REGEX =\n /\\s*(?:\\{(?:\\.|\\s)*(?:no-border|no-underline|no-bottom-border|plain|-)\\s*\\}|\\[(?:no-border|no-underline)\\]|<!--\\s*(?:no-border|no-underline)\\s*-->)\\s*$/i;\n\nfunction addClass(token: Token, className: string): void {\n const classIndex = token.attrIndex(\"class\");\n if (classIndex < 0) {\n token.attrPush([\"class\", className]);\n } else if (token.attrs) {\n const existing = token.attrs[classIndex][1];\n if (typeof existing === \"string\") {\n const classes = existing.split(\" \");\n const newClasses = className.split(\" \");\n for (const cls of newClasses) {\n if (!classes.includes(cls)) {\n classes.push(cls);\n }\n }\n token.attrs[classIndex][1] = classes.join(\" \").trim();\n }\n }\n}\n\n/**\n * Heading plugin to support individually removing bottom border/underline from headings (H1, H2, H3, etc.).\n *\n * Supported syntaxes at the end of a heading:\n * - `# Heading {.no-border}` or `# Heading {.no-underline}`\n * - `# Heading {no-border}` or `# Heading {no-underline}`\n * - `# Heading {-}` or `# Heading {.plain}`\n * - `# Heading [no-border]` or `# Heading [no-underline]`\n * - `# Heading <!-- no-border -->`\n */\nexport function headingPlugin(md: InstanceType<typeof MarkdownIt>): void {\n md.core.ruler.after(\"inline\", \"heading_no_border\", (state: StateCore) => {\n const tokens = state.tokens;\n\n for (let i = 0; i < tokens.length; i++) {\n if (tokens[i].type === \"heading_open\") {\n const inlineToken = tokens[i + 1];\n if (inlineToken && inlineToken.type === \"inline\") {\n if (NO_BORDER_ATTR_REGEX.test(inlineToken.content)) {\n // Add no-border classes to heading_open\n addClass(tokens[i], \"printdown-no-border printdown-no-underline\");\n\n // Strip from raw content\n inlineToken.content = inlineToken.content.replace(NO_BORDER_ATTR_REGEX, \"\");\n\n // Strip from children tokens\n if (inlineToken.children && inlineToken.children.length > 0) {\n for (let j = inlineToken.children.length - 1; j >= 0; j--) {\n const child = inlineToken.children[j];\n if (child.type === \"text\") {\n if (NO_BORDER_ATTR_REGEX.test(child.content)) {\n child.content = child.content.replace(NO_BORDER_ATTR_REGEX, \"\");\n if (child.content === \"\") {\n inlineToken.children.splice(j, 1);\n }\n break;\n }\n } else if (child.type === \"html_inline\") {\n if (\n child.content.includes(\"no-border\") ||\n child.content.includes(\"no-underline\")\n ) {\n inlineToken.children.splice(j, 1);\n break;\n }\n }\n }\n }\n }\n }\n } else if (tokens[i].type === \"html_block\") {\n // Handle HTML headings like <h1 no-border> or <h1 no-underline>\n tokens[i].content = tokens[i].content.replace(\n /<(h[1-6])(\\s+[^>]*)?(?:\\s+(?:no-border|no-underline))\\s*([^>]*)>/gi,\n (match, tag, before, after) => {\n const combinedAttrs = `${before || \"\"} ${after || \"\"}`.trim();\n if (combinedAttrs.includes('class=\"') || combinedAttrs.includes(\"class='\")) {\n return `<${tag} ${combinedAttrs.replace(\n /class=([\"'])(.*?)\\1/,\n \"class=$1$2 printdown-no-border printdown-no-underline$1\",\n )}>`;\n }\n return `<${tag} class=\"printdown-no-border printdown-no-underline\" ${combinedAttrs}>`.replace(\n /\\s+>/,\n \">\",\n );\n },\n );\n }\n }\n });\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { chromium, type Browser, type BrowserContext, type Page } from \"playwright\";\nimport { getFontDir } from \"../themes/default/fonts.js\";\nimport type { RenderOptions, OutputFormat } from \"../types.js\";\n\nasync function setupFontRouting(context: BrowserContext): Promise<void> {\n const interDir = getFontDir(\"@fontsource-variable/inter/index.css\");\n const notoDir = getFontDir(\"@fontsource-variable/noto-sans-jp/index.css\");\n const jbDir = getFontDir(\"@fontsource-variable/jetbrains-mono/index.css\");\n const genDir = getFontDir(\"gen-interface-jp/500.css\");\n\n await context.route(\"https://printdown.local/fonts/**\", async (route) => {\n const reqUrl = route.request().url();\n let filePath = \"\";\n\n if (interDir && reqUrl.startsWith(\"https://printdown.local/fonts/inter/\")) {\n filePath = path.join(\n interDir,\n \"files\",\n reqUrl.replace(\"https://printdown.local/fonts/inter/\", \"\"),\n );\n } else if (notoDir && reqUrl.startsWith(\"https://printdown.local/fonts/noto-sans-jp/\")) {\n filePath = path.join(\n notoDir,\n \"files\",\n reqUrl.replace(\"https://printdown.local/fonts/noto-sans-jp/\", \"\"),\n );\n } else if (jbDir && reqUrl.startsWith(\"https://printdown.local/fonts/jetbrains-mono/\")) {\n filePath = path.join(\n jbDir,\n \"files\",\n reqUrl.replace(\"https://printdown.local/fonts/jetbrains-mono/\", \"\"),\n );\n } else if (genDir && reqUrl.startsWith(\"https://printdown.local/fonts/gen-interface-jp/w/\")) {\n filePath = path.join(\n genDir,\n \"w\",\n reqUrl.replace(\"https://printdown.local/fonts/gen-interface-jp/w/\", \"\"),\n );\n }\n\n if (filePath && fs.existsSync(filePath)) {\n try {\n const body = fs.readFileSync(filePath);\n await route.fulfill({\n status: 200,\n contentType: \"font/woff2\",\n body,\n });\n return;\n } catch {\n // Fallback to abort\n }\n }\n await route.abort();\n });\n}\n\nexport class BrowserRenderer {\n private browser: Browser | null = null;\n\n async init(): Promise<void> {\n if (!this.browser) {\n this.browser = await chromium.launch({\n headless: true,\n args: [\n \"--disable-gpu\",\n \"--no-sandbox\",\n \"--disable-setuid-sandbox\",\n \"--font-render-hinting=medium\",\n ],\n });\n }\n }\n\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close();\n this.browser = null;\n }\n }\n\n private async preparePage(\n html: string,\n width: number,\n height: number,\n deviceScaleFactor: number,\n ): Promise<{ browser: Browser; context: BrowserContext; page: Page; isLocalBrowser: boolean }> {\n let isLocalBrowser = false;\n let browser = this.browser;\n\n if (!browser) {\n browser = await chromium.launch({\n headless: true,\n args: [\n \"--disable-gpu\",\n \"--no-sandbox\",\n \"--disable-setuid-sandbox\",\n \"--font-render-hinting=medium\",\n ],\n });\n isLocalBrowser = true;\n }\n\n const context = await browser.newContext({\n viewport: { width, height },\n deviceScaleFactor,\n });\n\n // Intercept and serve font files directly from npm packages (Fontsource, Gen Interface JP)\n await setupFontRouting(context);\n\n const page = await context.newPage();\n\n // Load HTML content\n await page.setContent(html, {\n waitUntil: \"networkidle\",\n });\n\n // Wait for fonts to be loaded\n await page.evaluate(async () => {\n if (document.fonts) {\n await document.fonts.ready;\n }\n });\n\n // Wait for all images to complete loading\n await page.evaluate(async () => {\n const images = Array.from(document.images);\n const pendingImages = images.filter((img) => !img.complete);\n if (pendingImages.length > 0) {\n await Promise.all(\n pendingImages.map(\n (img) =>\n new Promise((resolve) => {\n img.onload = img.onerror = resolve;\n }),\n ),\n );\n }\n });\n\n return { browser, context, page, isLocalBrowser };\n }\n\n async renderToBuffer(\n html: string,\n format: OutputFormat,\n options: RenderOptions = {},\n ): Promise<Buffer> {\n const width = options.width ?? (format === \"pdf\" ? 820 : 1200);\n const height = options.height ?? 800;\n const deviceScaleFactor = options.scale ?? options.deviceScaleFactor ?? 2;\n\n const { browser, context, page, isLocalBrowser } = await this.preparePage(\n html,\n width,\n height,\n deviceScaleFactor,\n );\n\n try {\n if (format === \"pdf\") {\n const pdfBuffer = await page.pdf({\n printBackground: true,\n preferCSSPageSize: true,\n ...options.pdf,\n });\n return Buffer.from(pdfBuffer);\n } else if (format === \"png\") {\n const screenshotBuffer = await page.screenshot({\n type: \"png\",\n fullPage: options.image?.fullPage ?? true,\n ...options.image,\n });\n return Buffer.from(screenshotBuffer);\n } else if (format === \"jpeg\") {\n const screenshotBuffer = await page.screenshot({\n type: \"jpeg\",\n quality: options.quality ?? 90,\n fullPage: options.image?.fullPage ?? true,\n ...options.image,\n });\n return Buffer.from(screenshotBuffer);\n } else if (format === \"webp\") {\n const screenshotBuffer = await page.screenshot({\n type: \"webp\",\n quality: options.quality ?? 90,\n fullPage: options.image?.fullPage ?? true,\n ...options.image,\n });\n return Buffer.from(screenshotBuffer);\n } else {\n throw new Error(`Unsupported output format: ${format}`);\n }\n } finally {\n await page.close().catch(() => {});\n await context.close().catch(() => {});\n if (isLocalBrowser && browser) {\n await browser.close().catch(() => {});\n }\n }\n }\n\n async renderToPageBuffers(\n html: string,\n format: OutputFormat,\n options: RenderOptions = {},\n ): Promise<Buffer[]> {\n if (format === \"pdf\") {\n const singleBuffer = await this.renderToBuffer(html, format, options);\n return [singleBuffer];\n }\n\n const width = options.width ?? 820;\n const pageHeight = options.pageHeight ?? Math.round((width * 297) / 210);\n const marginTop = options.pageMarginTop ?? Math.round((20 / 297) * pageHeight);\n const marginBottom = options.pageMarginBottom ?? Math.round((20 / 297) * pageHeight);\n const contentHeightPerPage = Math.max(100, pageHeight - marginTop - marginBottom);\n const deviceScaleFactor = options.scale ?? options.deviceScaleFactor ?? 2;\n\n // In pages mode, remove vertical padding from .printdown container so the page margin provides clean top/bottom whitespace\n const pagesHtml = html.includes(\"</head>\")\n ? html.replace(\n \"</head>\",\n \"<style>.printdown { padding-top: 0 !important; padding-bottom: 0 !important; }</style></head>\",\n )\n : html +\n \"<style>.printdown { padding-top: 0 !important; padding-bottom: 0 !important; }</style>\";\n\n const { browser, context, page, isLocalBrowser } = await this.preparePage(\n pagesHtml,\n width,\n pageHeight,\n deviceScaleFactor,\n );\n\n let composePage: Page | null = null;\n\n try {\n const totalContentHeight = await page.evaluate(() =>\n Math.max(document.documentElement.scrollHeight, document.body.scrollHeight),\n );\n\n const pageCount = Math.max(1, Math.ceil(totalContentHeight / contentHeightPerPage));\n\n // Expand viewport height for the full document capture\n await page.setViewportSize({\n width,\n height: Math.max(totalContentHeight + 100, pageHeight),\n });\n\n const fullContentScreenshot = await page.screenshot({\n type: \"png\",\n fullPage: true,\n });\n\n // Create a page for compositing each page slice on an A4 canvas with top/bottom margins\n composePage = await context.newPage();\n await composePage.setContent(`\n <!DOCTYPE html>\n <html>\n <head>\n <style>\n html, body { margin: 0; padding: 0; background: #ffffff; overflow: hidden; }\n canvas { display: block; }\n </style>\n </head>\n <body>\n <canvas id=\"canvas\" width=\"${width * deviceScaleFactor}\" height=\"${pageHeight * deviceScaleFactor}\" style=\"width:${width}px; height:${pageHeight}px;\"></canvas>\n </body>\n </html>\n `);\n\n const base64Img = fullContentScreenshot.toString(\"base64\");\n const pageBuffers: Buffer[] = [];\n const imageType = format === \"jpeg\" ? \"jpeg\" : format === \"webp\" ? \"webp\" : \"png\";\n\n for (let i = 0; i < pageCount; i++) {\n const srcY = i * contentHeightPerPage;\n const srcH = Math.min(contentHeightPerPage, totalContentHeight - srcY);\n\n await composePage.evaluate(\n async ({ base64, width, marginTop, srcY, srcH, scale }) => {\n const canvas = document.getElementById(\"canvas\") as HTMLCanvasElement;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n ctx.fillStyle = \"#ffffff\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n const img = new Image();\n await new Promise((resolve) => {\n img.onload = resolve;\n img.src = \"data:image/png;base64,\" + base64;\n });\n\n ctx.drawImage(\n img,\n 0,\n srcY * scale,\n width * scale,\n srcH * scale,\n 0,\n marginTop * scale,\n width * scale,\n srcH * scale,\n );\n },\n {\n base64: base64Img,\n width,\n marginTop,\n srcY,\n srcH,\n scale: deviceScaleFactor,\n },\n );\n\n const screenshotBuffer = await composePage.screenshot({\n type: imageType,\n quality: imageType !== \"png\" ? (options.quality ?? 90) : undefined,\n ...options.image,\n });\n\n pageBuffers.push(Buffer.from(screenshotBuffer));\n }\n\n return pageBuffers;\n } finally {\n if (composePage) {\n await composePage.close().catch(() => {});\n }\n await page.close().catch(() => {});\n await context.close().catch(() => {});\n if (isLocalBrowser && browser) {\n await browser.close().catch(() => {});\n }\n }\n }\n}\n\nexport async function renderHtmlToBuffer(\n html: string,\n format: OutputFormat,\n options: RenderOptions = {},\n): Promise<Buffer> {\n const renderer = new BrowserRenderer();\n return renderer.renderToBuffer(html, format, options);\n}\n\nexport async function renderHtmlToPageBuffers(\n html: string,\n format: OutputFormat,\n options: RenderOptions = {},\n): Promise<Buffer[]> {\n const renderer = new BrowserRenderer();\n return renderer.renderToPageBuffers(html, format, options);\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { defaultThemeCss, type Theme } from \"../themes/default/index.js\";\nimport type { RenderOptions } from \"../types.js\";\n\nfunction resolveCss(cssInput: string | string[], baseUrl?: string): string {\n const inputs = Array.isArray(cssInput) ? cssInput : [cssInput];\n const resolvedCssParts: string[] = [];\n\n for (const input of inputs) {\n if (!input || typeof input !== \"string\") continue;\n\n // Check if input is a file path\n let isFile = false;\n let filePath = input;\n\n if (baseUrl && !path.isAbsolute(input)) {\n const candidate = path.resolve(baseUrl, input);\n if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {\n isFile = true;\n filePath = candidate;\n }\n }\n\n if (!isFile && (fs.existsSync(input) || input.endsWith(\".css\"))) {\n if (fs.existsSync(input) && fs.statSync(input).isFile()) {\n isFile = true;\n filePath = path.resolve(input);\n }\n }\n\n if (isFile) {\n try {\n const fileContent = fs.readFileSync(filePath, \"utf-8\");\n resolvedCssParts.push(fileContent);\n } catch (err) {\n console.warn(`[printdown] Failed to read CSS file \"${filePath}\":`, err);\n }\n } else {\n // Inline CSS string\n resolvedCssParts.push(input);\n }\n }\n\n return resolvedCssParts.join(\"\\n\\n\");\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\nexport function buildHtmlDocument(bodyHtml: string, options: RenderOptions = {}): string {\n const title = options.title || \"Printdown Document\";\n let themeCss = \"\";\n\n if (options.theme !== false) {\n if (typeof options.theme === \"object\" && options.theme !== null && \"css\" in options.theme) {\n themeCss = (options.theme as Theme).css;\n } else {\n // Default theme\n themeCss = defaultThemeCss;\n }\n }\n\n const userCss = options.css ? resolveCss(options.css, options.baseUrl) : \"\";\n\n const baseTag = options.baseUrl\n ? `<base href=\"${options.baseUrl.endsWith(\"/\") ? options.baseUrl : options.baseUrl + \"/\"}\">`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"ja\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>${escapeHtml(title)}</title>\n ${baseTag}\n ${themeCss ? `<style id=\"printdown-theme\">${themeCss}</style>` : \"\"}\n ${userCss ? `<style id=\"printdown-user-css\">${userCss}</style>` : \"\"}\n</head>\n<body>\n <article class=\"printdown\">\n${bodyHtml}\n </article>\n</body>\n</html>`;\n}\n"],"mappings":"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","names":["fs","path","addClass","width","marginTop","srcY","srcH","fs","path","path","fs","path","parsed","fs"]}
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  renderFile
4
- } from "./chunk-HX2CR2SJ.js";
5
- import "./chunk-INBZBWSZ.js";
4
+ } from "./chunk-ZB6NLLOD.js";
5
+ import "./chunk-GEQQR3U7.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import path from "path";
@@ -66,6 +66,6 @@ cli.command("<file>", "Render markdown file to PDF, PNG, JPEG, or WebP").option(
66
66
  }
67
67
  });
68
68
  cli.help();
69
- cli.version("1.0.0");
69
+ cli.version("1.1.1");
70
70
  cli.parse();
71
71
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport path from \"node:path\";\nimport { cac } from \"cac\";\nimport { renderFile } from \"./index.js\";\nimport type { OutputFormat } from \"./types.js\";\n\nconst cli = cac(\"printdown\");\n\ncli\n .command(\"<file>\", \"Render markdown file to PDF, PNG, JPEG, or WebP\")\n .option(\"-o, --output <path>\", \"Output file path (e.g., output.pdf, output.png, output.webp)\")\n .option(\"-f, --format <format>\", \"Output format (pdf, png, jpeg, webp)\")\n .option(\"-c, --css <path>\", \"Path to custom CSS file or inline CSS string\")\n .option(\"-t, --theme <theme>\", \"Theme to use (default: 'default', 'false' to disable)\")\n .option(\"-p, --pages\", \"Export multiple page images matching PDF/A4 page size\", {\n default: false,\n })\n .option(\"-s, --scale <scale>\", \"Image resolution scale multiplier (e.g., 1, 2, 3)\", {\n default: undefined,\n })\n .option(\"--device-scale-factor <factor>\", \"Device scale factor for screenshots\", {\n default: undefined,\n })\n .option(\"--width <width>\", \"Viewport width in pixels\", { default: undefined })\n .option(\"--page-height <height>\", \"Page height in pixels for pages mode\", { default: undefined })\n .option(\"--margin-top <margin>\", \"Top margin in pixels for pages mode\", { default: undefined })\n .option(\"--margin-bottom <margin>\", \"Bottom margin in pixels for pages mode\", {\n default: undefined,\n })\n .option(\"--quality <quality>\", \"JPEG / WebP image quality (0-100)\", { default: 90 })\n .action(async (file: string, options) => {\n try {\n const inputPath = path.resolve(file);\n const ext = path.extname(inputPath);\n const baseName = path.basename(inputPath, ext);\n\n let format: OutputFormat | undefined = undefined;\n if (options.format) {\n const fmt = options.format.toLowerCase();\n if (fmt === \"pdf\" || fmt === \"png\" || fmt === \"jpeg\" || fmt === \"jpg\" || fmt === \"webp\") {\n format = fmt === \"jpg\" ? \"jpeg\" : (fmt as OutputFormat);\n } else {\n console.error(\n `Error: Unsupported format \"${options.format}\". Use pdf, png, jpeg, or webp.`,\n );\n process.exit(1);\n }\n }\n\n let outputPath = options.output;\n if (!outputPath) {\n const targetFormat = format || \"pdf\";\n outputPath = path.join(path.dirname(inputPath), `${baseName}.${targetFormat}`);\n }\n\n const themeOption =\n options.theme === \"false\" || options.theme === false ? false : options.theme || \"default\";\n\n const width = options.width ? Number(options.width) : undefined;\n const pageHeight = options.pageHeight ? Number(options.pageHeight) : undefined;\n const pageMarginTop = options.marginTop ? Number(options.marginTop) : undefined;\n const pageMarginBottom = options.marginBottom ? Number(options.marginBottom) : undefined;\n const quality = options.quality ? Number(options.quality) : 90;\n const scale = options.scale\n ? Number(options.scale)\n : options.deviceScaleFactor\n ? Number(options.deviceScaleFactor)\n : undefined;\n const pages = Boolean(options.pages);\n\n await renderFile(inputPath, {\n output: outputPath,\n format,\n theme: themeOption,\n css: options.css,\n width,\n pageHeight,\n pageMarginTop,\n pageMarginBottom,\n quality,\n scale,\n pages,\n });\n\n console.log(`Successfully generated: ${outputPath}`);\n } catch (err: unknown) {\n console.error(\"Error generating document:\", err instanceof Error ? err.message : err);\n process.exit(1);\n }\n });\n\ncli.help();\ncli.version(\"1.0.0\");\n\ncli.parse();\n"],"mappings":";;;;;;;AACA,OAAO,UAAU;AACjB,SAAS,WAAW;AAIpB,IAAM,MAAM,IAAI,WAAW;AAE3B,IACG,QAAQ,UAAU,iDAAiD,EACnE,OAAO,uBAAuB,8DAA8D,EAC5F,OAAO,yBAAyB,sCAAsC,EACtE,OAAO,oBAAoB,8CAA8C,EACzE,OAAO,uBAAuB,uDAAuD,EACrF,OAAO,eAAe,yDAAyD;AAAA,EAC9E,SAAS;AACX,CAAC,EACA,OAAO,uBAAuB,qDAAqD;AAAA,EAClF,SAAS;AACX,CAAC,EACA,OAAO,kCAAkC,uCAAuC;AAAA,EAC/E,SAAS;AACX,CAAC,EACA,OAAO,mBAAmB,4BAA4B,EAAE,SAAS,OAAU,CAAC,EAC5E,OAAO,0BAA0B,wCAAwC,EAAE,SAAS,OAAU,CAAC,EAC/F,OAAO,yBAAyB,uCAAuC,EAAE,SAAS,OAAU,CAAC,EAC7F,OAAO,4BAA4B,0CAA0C;AAAA,EAC5E,SAAS;AACX,CAAC,EACA,OAAO,uBAAuB,qCAAqC,EAAE,SAAS,GAAG,CAAC,EAClF,OAAO,OAAO,MAAc,YAAY;AACvC,MAAI;AACF,UAAM,YAAY,KAAK,QAAQ,IAAI;AACnC,UAAM,MAAM,KAAK,QAAQ,SAAS;AAClC,UAAM,WAAW,KAAK,SAAS,WAAW,GAAG;AAE7C,QAAI,SAAmC;AACvC,QAAI,QAAQ,QAAQ;AAClB,YAAM,MAAM,QAAQ,OAAO,YAAY;AACvC,UAAI,QAAQ,SAAS,QAAQ,SAAS,QAAQ,UAAU,QAAQ,SAAS,QAAQ,QAAQ;AACvF,iBAAS,QAAQ,QAAQ,SAAU;AAAA,MACrC,OAAO;AACL,gBAAQ;AAAA,UACN,8BAA8B,QAAQ,MAAM;AAAA,QAC9C;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,aAAa,QAAQ;AACzB,QAAI,CAAC,YAAY;AACf,YAAM,eAAe,UAAU;AAC/B,mBAAa,KAAK,KAAK,KAAK,QAAQ,SAAS,GAAG,GAAG,QAAQ,IAAI,YAAY,EAAE;AAAA,IAC/E;AAEA,UAAM,cACJ,QAAQ,UAAU,WAAW,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,SAAS;AAElF,UAAM,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,KAAK,IAAI;AACtD,UAAM,aAAa,QAAQ,aAAa,OAAO,QAAQ,UAAU,IAAI;AACrE,UAAM,gBAAgB,QAAQ,YAAY,OAAO,QAAQ,SAAS,IAAI;AACtE,UAAM,mBAAmB,QAAQ,eAAe,OAAO,QAAQ,YAAY,IAAI;AAC/E,UAAM,UAAU,QAAQ,UAAU,OAAO,QAAQ,OAAO,IAAI;AAC5D,UAAM,QAAQ,QAAQ,QAClB,OAAO,QAAQ,KAAK,IACpB,QAAQ,oBACN,OAAO,QAAQ,iBAAiB,IAChC;AACN,UAAM,QAAQ,QAAQ,QAAQ,KAAK;AAEnC,UAAM,WAAW,WAAW;AAAA,MAC1B,QAAQ;AAAA,MACR;AAAA,MACA,OAAO;AAAA,MACP,KAAK,QAAQ;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,YAAQ,IAAI,2BAA2B,UAAU,EAAE;AAAA,EACrD,SAAS,KAAc;AACrB,YAAQ,MAAM,8BAA8B,eAAe,QAAQ,IAAI,UAAU,GAAG;AACpF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,IAAI,KAAK;AACT,IAAI,QAAQ,OAAO;AAEnB,IAAI,MAAM;","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport path from \"node:path\";\nimport { cac } from \"cac\";\nimport { renderFile } from \"./index.js\";\nimport type { OutputFormat } from \"./types.js\";\n\nconst cli = cac(\"printdown\");\n\ncli\n .command(\"<file>\", \"Render markdown file to PDF, PNG, JPEG, or WebP\")\n .option(\"-o, --output <path>\", \"Output file path (e.g., output.pdf, output.png, output.webp)\")\n .option(\"-f, --format <format>\", \"Output format (pdf, png, jpeg, webp)\")\n .option(\"-c, --css <path>\", \"Path to custom CSS file or inline CSS string\")\n .option(\"-t, --theme <theme>\", \"Theme to use (default: 'default', 'false' to disable)\")\n .option(\"-p, --pages\", \"Export multiple page images matching PDF/A4 page size\", {\n default: false,\n })\n .option(\"-s, --scale <scale>\", \"Image resolution scale multiplier (e.g., 1, 2, 3)\", {\n default: undefined,\n })\n .option(\"--device-scale-factor <factor>\", \"Device scale factor for screenshots\", {\n default: undefined,\n })\n .option(\"--width <width>\", \"Viewport width in pixels\", { default: undefined })\n .option(\"--page-height <height>\", \"Page height in pixels for pages mode\", { default: undefined })\n .option(\"--margin-top <margin>\", \"Top margin in pixels for pages mode\", { default: undefined })\n .option(\"--margin-bottom <margin>\", \"Bottom margin in pixels for pages mode\", {\n default: undefined,\n })\n .option(\"--quality <quality>\", \"JPEG / WebP image quality (0-100)\", { default: 90 })\n .action(async (file: string, options) => {\n try {\n const inputPath = path.resolve(file);\n const ext = path.extname(inputPath);\n const baseName = path.basename(inputPath, ext);\n\n let format: OutputFormat | undefined = undefined;\n if (options.format) {\n const fmt = options.format.toLowerCase();\n if (fmt === \"pdf\" || fmt === \"png\" || fmt === \"jpeg\" || fmt === \"jpg\" || fmt === \"webp\") {\n format = fmt === \"jpg\" ? \"jpeg\" : (fmt as OutputFormat);\n } else {\n console.error(\n `Error: Unsupported format \"${options.format}\". Use pdf, png, jpeg, or webp.`,\n );\n process.exit(1);\n }\n }\n\n let outputPath = options.output;\n if (!outputPath) {\n const targetFormat = format || \"pdf\";\n outputPath = path.join(path.dirname(inputPath), `${baseName}.${targetFormat}`);\n }\n\n const themeOption =\n options.theme === \"false\" || options.theme === false ? false : options.theme || \"default\";\n\n const width = options.width ? Number(options.width) : undefined;\n const pageHeight = options.pageHeight ? Number(options.pageHeight) : undefined;\n const pageMarginTop = options.marginTop ? Number(options.marginTop) : undefined;\n const pageMarginBottom = options.marginBottom ? Number(options.marginBottom) : undefined;\n const quality = options.quality ? Number(options.quality) : 90;\n const scale = options.scale\n ? Number(options.scale)\n : options.deviceScaleFactor\n ? Number(options.deviceScaleFactor)\n : undefined;\n const pages = Boolean(options.pages);\n\n await renderFile(inputPath, {\n output: outputPath,\n format,\n theme: themeOption,\n css: options.css,\n width,\n pageHeight,\n pageMarginTop,\n pageMarginBottom,\n quality,\n scale,\n pages,\n });\n\n console.log(`Successfully generated: ${outputPath}`);\n } catch (err: unknown) {\n console.error(\"Error generating document:\", err instanceof Error ? err.message : err);\n process.exit(1);\n }\n });\n\ncli.help();\ncli.version(\"1.1.1\");\n\ncli.parse();\n"],"mappings":";;;;;;;AACA,OAAO,UAAU;AACjB,SAAS,WAAW;AAIpB,IAAM,MAAM,IAAI,WAAW;AAE3B,IACG,QAAQ,UAAU,iDAAiD,EACnE,OAAO,uBAAuB,8DAA8D,EAC5F,OAAO,yBAAyB,sCAAsC,EACtE,OAAO,oBAAoB,8CAA8C,EACzE,OAAO,uBAAuB,uDAAuD,EACrF,OAAO,eAAe,yDAAyD;AAAA,EAC9E,SAAS;AACX,CAAC,EACA,OAAO,uBAAuB,qDAAqD;AAAA,EAClF,SAAS;AACX,CAAC,EACA,OAAO,kCAAkC,uCAAuC;AAAA,EAC/E,SAAS;AACX,CAAC,EACA,OAAO,mBAAmB,4BAA4B,EAAE,SAAS,OAAU,CAAC,EAC5E,OAAO,0BAA0B,wCAAwC,EAAE,SAAS,OAAU,CAAC,EAC/F,OAAO,yBAAyB,uCAAuC,EAAE,SAAS,OAAU,CAAC,EAC7F,OAAO,4BAA4B,0CAA0C;AAAA,EAC5E,SAAS;AACX,CAAC,EACA,OAAO,uBAAuB,qCAAqC,EAAE,SAAS,GAAG,CAAC,EAClF,OAAO,OAAO,MAAc,YAAY;AACvC,MAAI;AACF,UAAM,YAAY,KAAK,QAAQ,IAAI;AACnC,UAAM,MAAM,KAAK,QAAQ,SAAS;AAClC,UAAM,WAAW,KAAK,SAAS,WAAW,GAAG;AAE7C,QAAI,SAAmC;AACvC,QAAI,QAAQ,QAAQ;AAClB,YAAM,MAAM,QAAQ,OAAO,YAAY;AACvC,UAAI,QAAQ,SAAS,QAAQ,SAAS,QAAQ,UAAU,QAAQ,SAAS,QAAQ,QAAQ;AACvF,iBAAS,QAAQ,QAAQ,SAAU;AAAA,MACrC,OAAO;AACL,gBAAQ;AAAA,UACN,8BAA8B,QAAQ,MAAM;AAAA,QAC9C;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,aAAa,QAAQ;AACzB,QAAI,CAAC,YAAY;AACf,YAAM,eAAe,UAAU;AAC/B,mBAAa,KAAK,KAAK,KAAK,QAAQ,SAAS,GAAG,GAAG,QAAQ,IAAI,YAAY,EAAE;AAAA,IAC/E;AAEA,UAAM,cACJ,QAAQ,UAAU,WAAW,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,SAAS;AAElF,UAAM,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,KAAK,IAAI;AACtD,UAAM,aAAa,QAAQ,aAAa,OAAO,QAAQ,UAAU,IAAI;AACrE,UAAM,gBAAgB,QAAQ,YAAY,OAAO,QAAQ,SAAS,IAAI;AACtE,UAAM,mBAAmB,QAAQ,eAAe,OAAO,QAAQ,YAAY,IAAI;AAC/E,UAAM,UAAU,QAAQ,UAAU,OAAO,QAAQ,OAAO,IAAI;AAC5D,UAAM,QAAQ,QAAQ,QAClB,OAAO,QAAQ,KAAK,IACpB,QAAQ,oBACN,OAAO,QAAQ,iBAAiB,IAChC;AACN,UAAM,QAAQ,QAAQ,QAAQ,KAAK;AAEnC,UAAM,WAAW,WAAW;AAAA,MAC1B,QAAQ;AAAA,MACR;AAAA,MACA,OAAO;AAAA,MACP,KAAK,QAAQ;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,YAAQ,IAAI,2BAA2B,UAAU,EAAE;AAAA,EACrD,SAAS,KAAc;AACrB,YAAQ,MAAM,8BAA8B,eAAe,QAAQ,IAAI,UAAU,GAAG;AACpF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,IAAI,KAAK;AACT,IAAI,QAAQ,OAAO;AAEnB,IAAI,MAAM;","names":[]}
package/dist/index.js CHANGED
@@ -7,12 +7,12 @@ import {
7
7
  renderHtmlToPageBuffers,
8
8
  renderPages,
9
9
  renderToHtml
10
- } from "./chunk-HX2CR2SJ.js";
10
+ } from "./chunk-ZB6NLLOD.js";
11
11
  import {
12
12
  defaultTheme,
13
13
  defaultThemeCss,
14
14
  defaultThemeCssParts
15
- } from "./chunk-INBZBWSZ.js";
15
+ } from "./chunk-GEQQR3U7.js";
16
16
  export {
17
17
  BrowserRenderer,
18
18
  createMarkdownRenderer,
@@ -4,11 +4,11 @@ declare const variablesCss = ":root {\n /* Primary brand color - Deep Blue */\n
4
4
 
5
5
  declare const baseCss = "*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\nhtml {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n font-size: 16px;\n}\n\nbody {\n margin: 0;\n padding: 0;\n background-color: var(--printdown-bg);\n color: var(--printdown-text);\n font-family: var(--printdown-font-sans);\n font-size: var(--printdown-text-base);\n font-weight: var(--printdown-font-weight-normal);\n line-height: var(--printdown-leading-relaxed);\n}\n\n.printdown {\n font-family: var(--printdown-font-sans);\n color: var(--printdown-text);\n font-size: var(--printdown-text-base);\n font-weight: var(--printdown-font-weight-normal);\n line-height: var(--printdown-leading-relaxed);\n max-width: 820px;\n margin: 0 auto;\n padding: 2.5rem 2rem;\n background-color: var(--printdown-bg);\n}\n";
6
6
 
7
- declare const typographyCss = ".printdown h1,\n.printdown h2,\n.printdown h3,\n.printdown h4,\n.printdown h5,\n.printdown h6 {\n color: var(--printdown-text-strong);\n margin-top: 2rem;\n margin-bottom: 0.75rem;\n font-weight: var(--printdown-font-weight-bold);\n line-height: var(--printdown-leading-tight);\n}\n\n.printdown h1:first-child,\n.printdown h2:first-child,\n.printdown h3:first-child {\n margin-top: 0;\n}\n\n.printdown h1 {\n font-size: var(--printdown-text-3xl);\n font-weight: var(--printdown-font-weight-bold);\n letter-spacing: -0.025em;\n margin-top: 2.25rem;\n margin-bottom: 1rem;\n padding-bottom: 0.5rem;\n border-bottom: 1px solid var(--printdown-border-light);\n}\n\n.printdown h2 {\n font-size: var(--printdown-text-2xl);\n font-weight: var(--printdown-font-weight-bold);\n letter-spacing: -0.015em;\n margin-top: 2rem;\n margin-bottom: 0.75rem;\n}\n\n.printdown h3 {\n font-size: var(--printdown-text-xl);\n font-weight: var(--printdown-font-weight-semibold);\n letter-spacing: -0.01em;\n margin-top: 1.5rem;\n margin-bottom: 0.5rem;\n}\n\n.printdown h4 {\n font-size: var(--printdown-text-lg);\n font-weight: var(--printdown-font-weight-semibold);\n margin-top: 1.25rem;\n margin-bottom: 0.5rem;\n}\n\n.printdown h5 {\n font-size: var(--printdown-text-base);\n font-weight: var(--printdown-font-weight-semibold);\n margin-top: 1rem;\n margin-bottom: 0.5rem;\n}\n\n.printdown h6 {\n font-size: var(--printdown-text-sm);\n font-weight: var(--printdown-font-weight-semibold);\n color: var(--printdown-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 1rem;\n margin-bottom: 0.5rem;\n}\n\n.printdown p {\n margin-top: 0;\n margin-bottom: 1rem;\n line-height: var(--printdown-leading-relaxed);\n}\n\n.printdown p:last-child {\n margin-bottom: 0;\n}\n\n.printdown strong,\n.printdown b {\n font-weight: var(--printdown-font-weight-bold);\n color: var(--printdown-text-strong);\n}\n\n.printdown em,\n.printdown i {\n font-style: italic;\n}\n\n.printdown del,\n.printdown s {\n text-decoration: line-through;\n color: var(--printdown-text-muted);\n}\n\n.printdown small {\n font-size: var(--printdown-text-sm);\n color: var(--printdown-text-muted);\n}\n\n.printdown a {\n color: var(--printdown-primary);\n text-decoration: underline;\n text-decoration-thickness: 1px;\n text-underline-offset: 2.5px;\n}\n\n.printdown hr {\n border: 0;\n border-top: 1px solid var(--printdown-border);\n margin: 2rem 0;\n}\n";
7
+ declare const typographyCss = ".printdown h1,\n.printdown h2,\n.printdown h3,\n.printdown h4,\n.printdown h5,\n.printdown h6 {\n color: var(--printdown-text-strong);\n margin-top: 2rem;\n margin-bottom: 0.75rem;\n font-weight: var(--printdown-font-weight-bold);\n line-height: var(--printdown-leading-tight);\n}\n\n.printdown h1:first-child,\n.printdown h2:first-child,\n.printdown h3:first-child {\n margin-top: 0;\n}\n\n.printdown h1 {\n font-size: var(--printdown-text-3xl);\n font-weight: var(--printdown-font-weight-bold);\n letter-spacing: -0.025em;\n margin-top: 2.25rem;\n margin-bottom: 1rem;\n padding-bottom: 0.5rem;\n border-bottom: 1px solid var(--printdown-border-light);\n}\n\n.printdown h1.printdown-no-border,\n.printdown h1.printdown-no-underline,\n.printdown h1.no-border,\n.printdown h1.no-underline,\n.printdown h1.plain,\n.printdown h1[no-border],\n.printdown h1[no-underline],\n.printdown h2.printdown-no-border,\n.printdown h2.printdown-no-underline,\n.printdown h2.no-border,\n.printdown h2.no-underline,\n.printdown h2.plain,\n.printdown h2[no-border],\n.printdown h2[no-underline],\n.printdown h3.printdown-no-border,\n.printdown h3.printdown-no-underline,\n.printdown h3.no-border,\n.printdown h3.no-underline,\n.printdown h3.plain,\n.printdown h3[no-border],\n.printdown h3[no-underline],\n.printdown h4.printdown-no-border,\n.printdown h4.printdown-no-underline,\n.printdown h4.no-border,\n.printdown h4.no-underline,\n.printdown h4.plain,\n.printdown h4[no-border],\n.printdown h4[no-underline],\n.printdown h5.printdown-no-border,\n.printdown h5.printdown-no-underline,\n.printdown h5.no-border,\n.printdown h5.no-underline,\n.printdown h5.plain,\n.printdown h5[no-border],\n.printdown h5[no-underline],\n.printdown h6.printdown-no-border,\n.printdown h6.printdown-no-underline,\n.printdown h6.no-border,\n.printdown h6.no-underline,\n.printdown h6.plain,\n.printdown h6[no-border],\n.printdown h6[no-underline],\n.printdown .printdown-no-border,\n.printdown .printdown-no-underline,\n.printdown .no-border,\n.printdown .no-underline {\n border-bottom: none !important;\n padding-bottom: 0 !important;\n}\n\n.printdown h2 {\n font-size: var(--printdown-text-2xl);\n font-weight: var(--printdown-font-weight-bold);\n letter-spacing: -0.015em;\n margin-top: 2rem;\n margin-bottom: 0.75rem;\n}\n\n.printdown h3 {\n font-size: var(--printdown-text-xl);\n font-weight: var(--printdown-font-weight-semibold);\n letter-spacing: -0.01em;\n margin-top: 1.5rem;\n margin-bottom: 0.5rem;\n}\n\n.printdown h4 {\n font-size: var(--printdown-text-lg);\n font-weight: var(--printdown-font-weight-semibold);\n margin-top: 1.25rem;\n margin-bottom: 0.5rem;\n}\n\n.printdown h5 {\n font-size: var(--printdown-text-base);\n font-weight: var(--printdown-font-weight-semibold);\n margin-top: 1rem;\n margin-bottom: 0.5rem;\n}\n\n.printdown h6 {\n font-size: var(--printdown-text-sm);\n font-weight: var(--printdown-font-weight-semibold);\n color: var(--printdown-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 1rem;\n margin-bottom: 0.5rem;\n}\n\n.printdown p {\n margin-top: 0;\n margin-bottom: 1rem;\n line-height: var(--printdown-leading-relaxed);\n}\n\n.printdown p:last-child {\n margin-bottom: 0;\n}\n\n.printdown strong,\n.printdown b {\n font-weight: var(--printdown-font-weight-bold);\n color: var(--printdown-text-strong);\n}\n\n.printdown em,\n.printdown i {\n font-style: italic;\n}\n\n.printdown del,\n.printdown s {\n text-decoration: line-through;\n color: var(--printdown-text-muted);\n}\n\n.printdown small {\n font-size: var(--printdown-text-sm);\n color: var(--printdown-text-muted);\n}\n\n.printdown a {\n color: var(--printdown-primary);\n text-decoration: underline;\n text-decoration-thickness: 1px;\n text-underline-offset: 2.5px;\n}\n\n.printdown hr {\n border: 0;\n border-top: 1px solid var(--printdown-border);\n margin: 2rem 0;\n}\n";
8
8
 
9
9
  declare const markdownCss = "/* Lists */\n.printdown ul,\n.printdown ol {\n padding-left: 1.5rem;\n margin-top: 0.5rem;\n margin-bottom: 1rem;\n}\n\n.printdown ul {\n list-style-type: disc;\n}\n\n.printdown ol {\n list-style-type: decimal;\n}\n\n.printdown li {\n margin-top: 0.25rem;\n margin-bottom: 0.25rem;\n line-height: var(--printdown-leading-relaxed);\n}\n\n.printdown li > ul,\n.printdown li > ol {\n margin-top: 0.25rem;\n margin-bottom: 0.25rem;\n}\n\n/* Task Lists */\n.printdown ul.printdown-task-list {\n list-style: none;\n padding-left: 0;\n}\n\n.printdown .printdown-task-list-item {\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n margin-top: 0.35rem;\n margin-bottom: 0.35rem;\n}\n\n.printdown .printdown-task-list-checkbox {\n appearance: none;\n -webkit-appearance: none;\n width: 1.05em;\n height: 1.05em;\n margin-top: 0.3em;\n flex-shrink: 0;\n border-radius: 2px;\n border: 1.5px solid var(--printdown-neutral-400);\n background-color: transparent;\n position: relative;\n cursor: default;\n}\n\n.printdown .printdown-task-list-checkbox:checked {\n background-color: var(--printdown-blue-900);\n border-color: var(--printdown-blue-900);\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n background-size: 80% 80%;\n background-position: center;\n background-repeat: no-repeat;\n}\n\n/* Blockquote */\n.printdown blockquote {\n position: relative;\n margin: 1.25rem 0;\n padding: 0.25rem 0 0.25rem 1rem;\n border-left: 3px solid var(--printdown-primary);\n background: transparent;\n color: var(--printdown-neutral-700);\n font-size: var(--printdown-text-base);\n line-height: var(--printdown-leading-relaxed);\n}\n\n.printdown blockquote > *:first-child {\n margin-top: 0;\n}\n\n.printdown blockquote > *:last-child {\n margin-bottom: 0;\n}\n\n/* Tables */\n.printdown table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 1.25rem;\n margin-bottom: 1.25rem;\n font-size: var(--printdown-text-sm);\n line-height: var(--printdown-leading-normal);\n}\n\n.printdown th,\n.printdown td {\n padding: 0.625rem 0.75rem;\n text-align: left;\n vertical-align: top;\n}\n\n.printdown th {\n font-weight: var(--printdown-font-weight-semibold);\n color: var(--printdown-text-strong);\n border-bottom: 2px solid var(--printdown-gray-300);\n}\n\n.printdown td {\n border-bottom: 1px solid var(--printdown-gray-200);\n color: var(--printdown-text);\n}\n\n.printdown tr:last-child td {\n border-bottom: 1px solid var(--printdown-gray-200);\n}\n\n/* Images */\n.printdown img {\n max-width: 100%;\n height: auto;\n display: block;\n margin: 1.25rem auto;\n border-radius: 4px;\n}\n";
10
10
 
11
- declare const codeCss = "/* Inline Code */\n.printdown :not(pre) > code {\n font-family: var(--printdown-font-mono);\n background-color: var(--printdown-neutral-200);\n color: var(--printdown-neutral-900);\n padding: 0.15em 0.35em;\n border-radius: 4px;\n font-size: 0.875em;\n font-weight: 400;\n vertical-align: baseline;\n}\n\n/* Code Blocks */\n.printdown pre.printdown-code,\n.printdown pre.shiki {\n font-family: var(--printdown-font-mono);\n font-size: 0.85rem;\n line-height: 1.55;\n padding: 1rem 1.25rem;\n border-radius: 6px;\n margin: 1.25rem 0;\n overflow-x: auto;\n tab-size: 2;\n background-color: #1a1b26;\n color: #c0caf5;\n}\n\n.printdown pre.printdown-code code,\n.printdown pre.shiki code {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n background: transparent;\n padding: 0;\n border-radius: 0;\n color: inherit;\n}\n";
11
+ declare const codeCss = "/* Inline Code */\n.printdown :not(pre) > code {\n font-family: var(--printdown-font-mono);\n background-color: var(--printdown-neutral-200);\n color: var(--printdown-neutral-900);\n padding: 0.15em 0.35em;\n margin: 0 0.25em;\n border-radius: 4px;\n font-size: 0.875em;\n font-weight: 400;\n vertical-align: baseline;\n}\n\n/* Code Blocks */\n.printdown pre.printdown-code,\n.printdown pre.shiki {\n font-family: var(--printdown-font-mono);\n font-size: 0.85rem;\n line-height: 1.55;\n padding: 1rem 1.25rem;\n border-radius: 6px;\n margin: 1.25rem 0;\n overflow-x: auto;\n tab-size: 2;\n background-color: #1a1b26;\n color: #c0caf5;\n}\n\n.printdown pre.printdown-code code,\n.printdown pre.shiki code {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n background: transparent;\n padding: 0;\n border-radius: 0;\n color: inherit;\n}\n";
12
12
 
13
13
  declare const highlightCss = "/* Marker Pen / Highlight */\n.printdown mark,\n.printdown .printdown-highlight {\n --highlight-ink: color-mix(in oklch, var(--printdown-blue-300) 42%, transparent);\n\n display: inline;\n padding: 0 0.15em;\n margin: 0;\n border-radius: 0;\n font-size: inherit;\n font-weight: inherit;\n font-family: inherit;\n line-height: inherit;\n color: inherit;\n vertical-align: baseline;\n background-color: transparent;\n background-image: linear-gradient(\n to top,\n var(--highlight-ink) 0%,\n var(--highlight-ink) 58%,\n transparent 58%\n );\n box-decoration-break: clone;\n -webkit-box-decoration-break: clone;\n}\n\n.printdown .printdown-highlight--blue {\n --highlight-ink: color-mix(in oklch, var(--printdown-blue-300) 42%, transparent);\n}\n\n.printdown .printdown-highlight--amber {\n --highlight-ink: color-mix(in oklch, var(--printdown-amber-400) 48%, transparent);\n}\n\n/* Inline code inside highlight \u2014 transparent wrapper, marker stroke on code */\n.printdown mark:has(> code),\n.printdown .printdown-highlight:has(> code) {\n display: contents;\n padding: 0;\n background-image: none;\n background-color: transparent;\n}\n\n.printdown mark > code,\n.printdown .printdown-highlight > code {\n --highlight-ink: color-mix(in oklch, var(--printdown-blue-300) 42%, transparent);\n\n display: inline;\n padding: 0 0.25em;\n border-radius: 0;\n font-size: inherit;\n font-weight: inherit;\n font-family: inherit;\n line-height: inherit;\n vertical-align: baseline;\n background-color: transparent;\n background-image: linear-gradient(\n to top,\n var(--highlight-ink) 0%,\n var(--highlight-ink) 58%,\n transparent 58%\n );\n box-decoration-break: clone;\n -webkit-box-decoration-break: clone;\n}\n\n.printdown .printdown-highlight--amber > code {\n --highlight-ink: color-mix(in oklch, var(--printdown-amber-400) 48%, transparent);\n}\n";
14
14
 
@@ -16,6 +16,8 @@ declare const badgeCss = "/* Badges */\n.printdown .printdown-badge,\n.printdown
16
16
 
17
17
  declare const kbdCss = "/* Keyboard Key (Kbd) */\n.printdown kbd,\n.printdown .printdown-kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.5em;\n height: 1.6em;\n padding: 0 0.45em 2px; /* Compensate for 2px bottom shadow to center on key surface */\n margin: 0 0.25em;\n border-radius: 4px;\n background-color: var(--printdown-neutral-50);\n color: var(--printdown-blue-900);\n font-family: var(--printdown-font-sans);\n font-size: 0.8em;\n font-weight: var(--printdown-font-weight-semibold);\n line-height: 1;\n text-align: center;\n vertical-align: middle;\n white-space: nowrap;\n box-sizing: border-box;\n border: 1px solid var(--printdown-gray-300);\n box-shadow: inset 0 -2px 0 0 var(--printdown-gray-200), 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n/* Headings adjustment */\n.printdown h1 kbd,\n.printdown h1 .printdown-kbd,\n.printdown h2 kbd,\n.printdown h2 .printdown-kbd,\n.printdown h3 kbd,\n.printdown h3 .printdown-kbd {\n font-size: 0.6em;\n height: 1.6em;\n vertical-align: middle;\n}\n\n/* Kbd Icons */\n.printdown .printdown-kbd-icon {\n display: inline-block;\n width: 1.1em;\n height: 1.1em;\n background-color: currentColor;\n -webkit-mask-size: contain;\n mask-size: contain;\n -webkit-mask-position: center;\n mask-position: center;\n -webkit-mask-repeat: no-repeat;\n mask-repeat: no-repeat;\n}\n\n.printdown .printdown-kbd-icon + span,\n.printdown .printdown-kbd-icon + text {\n margin-left: 0.25em;\n}\n\n/* Command Icon */\n.printdown .printdown-kbd-icon--command,\n.printdown .printdown-kbd-icon--cmd {\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3z'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3z'/%3E%3C/svg%3E\");\n}\n\n/* Arrow Icons */\n.printdown .printdown-kbd-icon--arrow-up,\n.printdown .printdown-kbd-icon--up {\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 7-7 7 7'/%3E%3Cpath d='M12 19V5'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 7-7 7 7'/%3E%3Cpath d='M12 19V5'/%3E%3C/svg%3E\");\n}\n\n.printdown .printdown-kbd-icon--arrow-down,\n.printdown .printdown-kbd-icon--down {\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14'/%3E%3Cpath d='m19 12-7 7-7-7'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14'/%3E%3Cpath d='m19 12-7 7-7-7'/%3E%3C/svg%3E\");\n}\n\n.printdown .printdown-kbd-icon--arrow-left,\n.printdown .printdown-kbd-icon--left {\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 19-7-7 7-7'/%3E%3Cpath d='M19 12H5'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 19-7-7 7-7'/%3E%3Cpath d='M19 12H5'/%3E%3C/svg%3E\");\n}\n\n.printdown .printdown-kbd-icon--arrow-right,\n.printdown .printdown-kbd-icon--right {\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E\");\n}\n\n/* Option / Alt Icon */\n.printdown .printdown-kbd-icon--option,\n.printdown .printdown-kbd-icon--alt {\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 3h6l6 18h6'/%3E%3Cpath d='M14 3h7'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 3h6l6 18h6'/%3E%3Cpath d='M14 3h7'/%3E%3C/svg%3E\");\n}\n\n/* Shift Icon */\n.printdown .printdown-kbd-icon--shift {\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 3-8 8h5v10h6V11h5z'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 3-8 8h5v10h6V11h5z'/%3E%3C/svg%3E\");\n}\n\n/* Enter Icon */\n.printdown .printdown-kbd-icon--enter,\n.printdown .printdown-kbd-icon--return {\n -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 10 4 15 9 20'/%3E%3Cpath d='M20 4v7a4 4 0 0 1-4 4H4'/%3E%3C/svg%3E\");\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 10 4 15 9 20'/%3E%3Cpath d='M20 4v7a4 4 0 0 1-4 4H4'/%3E%3C/svg%3E\");\n}\n";
18
18
 
19
+ declare const centerCss = "/* Center Alignment */\n.printdown center,\n.printdown .printdown-center,\n.printdown .text-center,\n.printdown [align=\"center\"] {\n text-align: center;\n}\n\n.printdown div.printdown-center,\n.printdown center {\n display: block;\n text-align: center;\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\n.printdown div.printdown-center > *:first-child,\n.printdown center > *:first-child {\n margin-top: 0;\n}\n\n.printdown div.printdown-center > *:last-child,\n.printdown center > *:last-child {\n margin-bottom: 0;\n}\n\n.printdown span.printdown-center {\n display: inline-block;\n text-align: center;\n}\n\n.printdown .printdown-center img,\n.printdown center img {\n display: inline-block;\n margin-left: auto;\n margin-right: auto;\n}\n\n.printdown .printdown-center table,\n.printdown center table {\n margin-left: auto;\n margin-right: auto;\n}\n";
20
+
19
21
  declare const printCss = "/* Print and PDF Layout */\n@page {\n size: A4;\n margin: 20mm 18mm;\n}\n\n@media print {\n html,\n body {\n background-color: #ffffff;\n font-size: 15px;\n }\n\n .printdown {\n max-width: 100%;\n margin: 0;\n padding: 0;\n }\n\n /* Prevent awkward page breaks */\n .printdown h1,\n .printdown h2,\n .printdown h3,\n .printdown h4,\n .printdown h5,\n .printdown h6 {\n break-after: avoid;\n page-break-after: avoid;\n }\n\n .printdown pre.printdown-code,\n .printdown pre.shiki,\n .printdown blockquote,\n .printdown table,\n .printdown tr,\n .printdown img,\n .printdown .printdown-task-list-item {\n break-inside: avoid;\n page-break-inside: avoid;\n }\n\n .printdown p {\n orphans: 3;\n widows: 3;\n }\n\n .printdown .printdown-page-break {\n break-before: page;\n page-break-before: always;\n }\n}\n";
20
22
 
21
23
  declare const defaultThemeCssParts: {
@@ -28,6 +30,7 @@ declare const defaultThemeCssParts: {
28
30
  highlight: string;
29
31
  badge: string;
30
32
  kbd: string;
33
+ center: string;
31
34
  print: string;
32
35
  };
33
36
  declare const defaultThemeCss: string;
@@ -37,4 +40,4 @@ interface Theme {
37
40
  }
38
41
  declare const defaultTheme: Theme;
39
42
 
40
- export { type Theme, badgeCss, baseCss, codeCss, defaultTheme, defaultThemeCss, defaultThemeCssParts, fontsCss, highlightCss, kbdCss, markdownCss, printCss, typographyCss, variablesCss };
43
+ export { type Theme, badgeCss, baseCss, centerCss, codeCss, defaultTheme, defaultThemeCss, defaultThemeCssParts, fontsCss, highlightCss, kbdCss, markdownCss, printCss, typographyCss, variablesCss };
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  badgeCss,
3
3
  baseCss,
4
+ centerCss,
4
5
  codeCss,
5
6
  defaultTheme,
6
7
  defaultThemeCss,
@@ -12,10 +13,11 @@ import {
12
13
  printCss,
13
14
  typographyCss,
14
15
  variablesCss
15
- } from "../../chunk-INBZBWSZ.js";
16
+ } from "../../chunk-GEQQR3U7.js";
16
17
  export {
17
18
  badgeCss,
18
19
  baseCss,
20
+ centerCss,
19
21
  codeCss,
20
22
  defaultTheme,
21
23
  defaultThemeCss,
@@ -1561,6 +1561,56 @@ body {
1561
1561
  border-bottom: 1px solid var(--printdown-border-light);
1562
1562
  }
1563
1563
 
1564
+ .printdown h1.printdown-no-border,
1565
+ .printdown h1.printdown-no-underline,
1566
+ .printdown h1.no-border,
1567
+ .printdown h1.no-underline,
1568
+ .printdown h1.plain,
1569
+ .printdown h1[no-border],
1570
+ .printdown h1[no-underline],
1571
+ .printdown h2.printdown-no-border,
1572
+ .printdown h2.printdown-no-underline,
1573
+ .printdown h2.no-border,
1574
+ .printdown h2.no-underline,
1575
+ .printdown h2.plain,
1576
+ .printdown h2[no-border],
1577
+ .printdown h2[no-underline],
1578
+ .printdown h3.printdown-no-border,
1579
+ .printdown h3.printdown-no-underline,
1580
+ .printdown h3.no-border,
1581
+ .printdown h3.no-underline,
1582
+ .printdown h3.plain,
1583
+ .printdown h3[no-border],
1584
+ .printdown h3[no-underline],
1585
+ .printdown h4.printdown-no-border,
1586
+ .printdown h4.printdown-no-underline,
1587
+ .printdown h4.no-border,
1588
+ .printdown h4.no-underline,
1589
+ .printdown h4.plain,
1590
+ .printdown h4[no-border],
1591
+ .printdown h4[no-underline],
1592
+ .printdown h5.printdown-no-border,
1593
+ .printdown h5.printdown-no-underline,
1594
+ .printdown h5.no-border,
1595
+ .printdown h5.no-underline,
1596
+ .printdown h5.plain,
1597
+ .printdown h5[no-border],
1598
+ .printdown h5[no-underline],
1599
+ .printdown h6.printdown-no-border,
1600
+ .printdown h6.printdown-no-underline,
1601
+ .printdown h6.no-border,
1602
+ .printdown h6.no-underline,
1603
+ .printdown h6.plain,
1604
+ .printdown h6[no-border],
1605
+ .printdown h6[no-underline],
1606
+ .printdown .printdown-no-border,
1607
+ .printdown .printdown-no-underline,
1608
+ .printdown .no-border,
1609
+ .printdown .no-underline {
1610
+ border-bottom: none !important;
1611
+ padding-bottom: 0 !important;
1612
+ }
1613
+
1564
1614
  .printdown h2 {
1565
1615
  font-size: var(--printdown-text-2xl);
1566
1616
  font-weight: var(--printdown-font-weight-bold);
@@ -1780,6 +1830,7 @@ body {
1780
1830
  background-color: var(--printdown-neutral-200);
1781
1831
  color: var(--printdown-neutral-900);
1782
1832
  padding: 0.15em 0.35em;
1833
+ margin: 0 0.25em;
1783
1834
  border-radius: 4px;
1784
1835
  font-size: 0.875em;
1785
1836
  font-weight: 400;
@@ -2080,6 +2131,51 @@ body {
2080
2131
  }
2081
2132
 
2082
2133
 
2134
+ /* Center Alignment */
2135
+ .printdown center,
2136
+ .printdown .printdown-center,
2137
+ .printdown .text-center,
2138
+ .printdown [align="center"] {
2139
+ text-align: center;
2140
+ }
2141
+
2142
+ .printdown div.printdown-center,
2143
+ .printdown center {
2144
+ display: block;
2145
+ text-align: center;
2146
+ margin-top: 0;
2147
+ margin-bottom: 1rem;
2148
+ }
2149
+
2150
+ .printdown div.printdown-center > *:first-child,
2151
+ .printdown center > *:first-child {
2152
+ margin-top: 0;
2153
+ }
2154
+
2155
+ .printdown div.printdown-center > *:last-child,
2156
+ .printdown center > *:last-child {
2157
+ margin-bottom: 0;
2158
+ }
2159
+
2160
+ .printdown span.printdown-center {
2161
+ display: inline-block;
2162
+ text-align: center;
2163
+ }
2164
+
2165
+ .printdown .printdown-center img,
2166
+ .printdown center img {
2167
+ display: inline-block;
2168
+ margin-left: auto;
2169
+ margin-right: auto;
2170
+ }
2171
+
2172
+ .printdown .printdown-center table,
2173
+ .printdown center table {
2174
+ margin-left: auto;
2175
+ margin-right: auto;
2176
+ }
2177
+
2178
+
2083
2179
  /* Print and PDF Layout */
2084
2180
  @page {
2085
2181
  size: A4;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "printdown",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "A customizable Markdown renderer for generating beautifully styled PDFs and images with CSS.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",