@forevka/wordcanvas 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/assets/{worker-D8rUOKfg.js → worker-4HYrkNrG.js} +10873 -10730
- package/dist-lib/assets/worker-CJpwUzKh.js +2403 -0
- package/dist-lib/blockFactory-B_CLnkUh.js +106 -0
- package/dist-lib/browser-p_rkUcqE.js +1339 -0
- package/dist-lib/builder.js +14 -13
- package/dist-lib/editorApp-mTD0YNv-.js +9863 -0
- package/dist-lib/export.js +4507 -4456
- package/dist-lib/generate-toc.js +5 -5
- package/dist-lib/import.js +2 -2
- package/dist-lib/measure.js +2 -2
- package/dist-lib/{measureHost-CMiJKdlk.js → measureHost-B2aKX7lF.js} +1 -1
- package/dist-lib/metrics-BUMIC9Mv.js +164 -0
- package/dist-lib/pipeline-DD0nxAYM.js +1850 -0
- package/dist-lib/recalc-docx.js +2 -2
- package/dist-lib/recalcToc-CFCGCgij.js +3985 -0
- package/dist-lib/styleProps-DhqDEfvc.js +149 -0
- package/dist-lib/stylesheet-B6oczA-L.js +141 -0
- package/dist-lib/{toc-B6VpkJge.js → toc-Dj57zdz-.js} +5 -5
- package/dist-lib/{webmcp-6WxRNKCc.js → webmcp-CXghUon_.js} +2 -2
- package/dist-lib/{wordcanvas-CFqpDK0k.js → wordcanvas-D5DI9ZR1.js} +49 -23
- package/dist-lib/wordcanvas.js +1 -1
- package/dist-node/{chunk-22JHAERT.js → chunk-57L5XMCL.js} +235 -39
- package/dist-node/chunk-57L5XMCL.js.map +7 -0
- package/dist-node/{chunk-4PDVRJF6.js → chunk-EMY2P524.js} +32 -2
- package/dist-node/chunk-EMY2P524.js.map +7 -0
- package/dist-node/{chunk-6AJJMHKY.js → chunk-KJV7GJ3H.js} +1 -1
- package/dist-node/chunk-KJV7GJ3H.js.map +7 -0
- package/dist-node/{chunk-CDN6WU2P.js → chunk-PIMVQULL.js} +7 -1
- package/dist-node/chunk-PIMVQULL.js.map +7 -0
- package/dist-node/{chunk-BRAPV465.js → chunk-SA26UVIJ.js} +2 -2
- package/dist-node/{chunk-RNB336F3.js → chunk-T3253N22.js} +92 -14
- package/dist-node/{chunk-RNB336F3.js.map → chunk-T3253N22.js.map} +2 -2
- package/dist-node/{chunk-4ICCHZX4.js → chunk-U27EBKBG.js} +37 -1
- package/dist-node/chunk-U27EBKBG.js.map +7 -0
- package/dist-node/{engine-5FGDJD2H.js → engine-5F7DUU4W.js} +4 -4
- package/dist-node/export.js +89 -24
- package/dist-node/export.js.map +2 -2
- package/dist-node/generate-toc.js +6 -6
- package/dist-node/import.js +3 -3
- package/dist-node/measure.js +2 -2
- package/dist-node/recalc-docx.js +4 -4
- package/package.json +1 -1
- package/types/model.d.ts +46 -0
- package/types/wordcanvas.d.ts +212 -157
- package/dist-lib/assets/worker-wXuuyshQ.js +0 -2258
- package/dist-lib/blockFactory-CUI4Rqiq.js +0 -186
- package/dist-lib/browser-DkKxreJM.js +0 -1305
- package/dist-lib/editorApp-DLXMmtu5.js +0 -8023
- package/dist-lib/metrics-CkAo4zh8.js +0 -143
- package/dist-lib/pipeline-CbxmCE84.js +0 -1705
- package/dist-lib/recalcToc-g1hFKSNs.js +0 -3935
- package/dist-lib/styleProps-Db5pEkG8.js +0 -127
- package/dist-node/chunk-22JHAERT.js.map +0 -7
- package/dist-node/chunk-4ICCHZX4.js.map +0 -7
- package/dist-node/chunk-4PDVRJF6.js.map +0 -7
- package/dist-node/chunk-6AJJMHKY.js.map +0 -7
- package/dist-node/chunk-CDN6WU2P.js.map +0 -7
- /package/dist-node/{chunk-BRAPV465.js.map → chunk-SA26UVIJ.js.map} +0 -0
- /package/dist-node/{engine-5FGDJD2H.js.map → engine-5F7DUU4W.js.map} +0 -0
|
@@ -111,6 +111,40 @@ var leaderWidth = (fontSizePx) => Math.max(1, fontSizePx / 14);
|
|
|
111
111
|
var TOC_LEADER_DASH = [1, 4];
|
|
112
112
|
var TOC_LEADER_GAP_PX = 8;
|
|
113
113
|
var FOOTNOTE_RULE_WIDTH_FRACTION = 1 / 3;
|
|
114
|
+
var COLUMN_SEPARATOR_COLOR = "#c0c4c9";
|
|
115
|
+
var PAGE_BORDER_DEFAULT_SPACE = 24;
|
|
116
|
+
function pageBorderSegments(borders, pageW, pageH, margin) {
|
|
117
|
+
const fromText = borders.offsetFrom === "text";
|
|
118
|
+
const sp = (e) => e?.spacePx ?? PAGE_BORDER_DEFAULT_SPACE;
|
|
119
|
+
const xL = fromText ? margin.left - sp(borders.left) : sp(borders.left);
|
|
120
|
+
const xR = fromText ? pageW - margin.right + sp(borders.right) : pageW - sp(borders.right);
|
|
121
|
+
const yT = fromText ? margin.top - sp(borders.top) : sp(borders.top);
|
|
122
|
+
const yB = fromText ? pageH - margin.bottom + sp(borders.bottom) : pageH - sp(borders.bottom);
|
|
123
|
+
const out = [];
|
|
124
|
+
const push = (e, x1, y1, x2, y2) => {
|
|
125
|
+
if (!e || e.style === "none") return;
|
|
126
|
+
const w = e.style === "thick" ? Math.max(2, e.widthPx) : Math.max(0.5, e.widthPx);
|
|
127
|
+
const color = e.color === "auto" ? "#000000" : e.color;
|
|
128
|
+
const dash = e.style === "dashed" ? [w * 3, w * 2] : e.style === "dotted" ? [w, w * 1.5] : [];
|
|
129
|
+
out.push({ x1, y1, x2, y2, widthPx: w, color, dash });
|
|
130
|
+
if (e.style === "double") {
|
|
131
|
+
const g = w + 1;
|
|
132
|
+
const horizontal = y1 === y2;
|
|
133
|
+
if (horizontal) {
|
|
134
|
+
const dy = y1 < pageH / 2 ? g : -g;
|
|
135
|
+
out.push({ x1, y1: y1 + dy, x2, y2: y2 + dy, widthPx: w, color, dash: [] });
|
|
136
|
+
} else {
|
|
137
|
+
const dx = x1 < pageW / 2 ? g : -g;
|
|
138
|
+
out.push({ x1: x1 + dx, y1, x2: x2 + dx, y2, widthPx: w, color, dash: [] });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
push(borders.top, xL, yT, xR, yT);
|
|
143
|
+
push(borders.bottom, xL, yB, xR, yB);
|
|
144
|
+
push(borders.left, xL, yT, xL, yB);
|
|
145
|
+
push(borders.right, xR, yT, xR, yB);
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
114
148
|
var cellBorderWidth = (widthPx) => Math.max(0.5, widthPx);
|
|
115
149
|
function cellBorderDash(style, w) {
|
|
116
150
|
return style === "dashed" ? [w * 3, w * 2] : style === "dotted" ? [w, w * 1.5] : [];
|
|
@@ -175,6 +209,8 @@ export {
|
|
|
175
209
|
TOC_LEADER_DASH,
|
|
176
210
|
TOC_LEADER_GAP_PX,
|
|
177
211
|
FOOTNOTE_RULE_WIDTH_FRACTION,
|
|
212
|
+
COLUMN_SEPARATOR_COLOR,
|
|
213
|
+
pageBorderSegments,
|
|
178
214
|
cellBorderWidth,
|
|
179
215
|
cellBorderDash,
|
|
180
216
|
doubleBorderGap,
|
|
@@ -183,4 +219,4 @@ export {
|
|
|
183
219
|
measureTextWidth,
|
|
184
220
|
fontMetrics
|
|
185
221
|
};
|
|
186
|
-
//# sourceMappingURL=chunk-
|
|
222
|
+
//# sourceMappingURL=chunk-U27EBKBG.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/fonts/clones.ts", "../src/paint/paintStyle.ts", "../src/layout/metrics.ts"],
|
|
4
|
+
"sourcesContent": ["// Single source of truth for font substitution. The editor and both exporters\n// render & measure with these freely-redistributable metric clones instead of\n// the (Windows-only) originals, so layout is identical across the editor, the\n// browser export, and the Node backend \u2014 no system fonts anywhere. The model\n// keeps the original family names; only rendering/measuring/embedding map to a\n// clone. See src/export/shared/fonts/LICENSES.md.\n\n// \"TimesNewRoman\" is the genuine Microsoft Times New Roman (bundled at the user's\n// request), not a clone \u2014 see FONTS.md / fonts/LICENSES.md for the licensing note.\nexport const CLONE_FAMILIES = [\"Carlito\", \"Caladea\", \"Gelasio\", \"Arimo\", \"TimesNewRoman\", \"Cousine\"] as const;\nexport const FALLBACK_CLONE = \"Arimo\";\n\n// Requested family (lowercased, first CSS-stack token) -> bundled clone family.\n// Includes identity entries for the clone names themselves (so already-mapped\n// strings resolve to themselves) and the generic CSS families.\nexport const CLONE_OF: Record<string, string> = {\n // metric clones of common Office/Windows fonts\n calibri: \"Carlito\",\n cambria: \"Caladea\",\n georgia: \"Gelasio\",\n arial: \"Arimo\",\n helvetica: \"Arimo\",\n \"helvetica neue\": \"Arimo\",\n \"times new roman\": \"TimesNewRoman\",\n times: \"TimesNewRoman\",\n \"courier new\": \"Cousine\",\n courier: \"Cousine\",\n // reasonable substitutes for fonts we don't ship\n verdana: \"Arimo\",\n tahoma: \"Arimo\",\n \"segoe ui\": \"Arimo\",\n \"trebuchet ms\": \"Arimo\",\n consolas: \"Cousine\",\n monaco: \"Cousine\",\n \"lucida console\": \"Cousine\",\n garamond: \"TimesNewRoman\",\n \"book antiqua\": \"Caladea\",\n palatino: \"Caladea\",\n // generic CSS families\n serif: \"TimesNewRoman\",\n \"sans-serif\": \"Arimo\",\n sans: \"Arimo\",\n monospace: \"Cousine\",\n mono: \"Cousine\",\n // identity (already a clone)\n carlito: \"Carlito\",\n caladea: \"Caladea\",\n gelasio: \"Gelasio\",\n arimo: \"Arimo\",\n timesnewroman: \"TimesNewRoman\",\n cousine: \"Cousine\",\n};\n\n// Per-clone vertical metrics as a fraction of font size (ascent, descent above/\n// below the baseline). Used by fontMetrics so line heights are computed the SAME\n// way in the editor and both exporters \u2014 otherwise the browser's canvas\n// fontBoundingBox (editor) and fontkit's tables (export) disagree by a hair and\n// pagination drifts by a page. Values measured from the browser's canvas\n// fontBoundingBox at 16px (an exact multiple here), so the editor's appearance is\n// unchanged while the export now matches it on every platform.\nexport const CLONE_METRICS: Record<string, { ascent: number; descent: number }> = {\n Carlito: { ascent: 0.9375, descent: 0.25 },\n Caladea: { ascent: 0.9375, descent: 0.25 },\n Gelasio: { ascent: 0.9375, descent: 0.3125 },\n Arimo: { ascent: 0.875, descent: 0.1875 },\n TimesNewRoman: { ascent: 0.875, descent: 0.1875 },\n Cousine: { ascent: 0.625, descent: 0.1875 },\n};\n\n/** Resolve one CSS-stack family token to its bundled clone family. */\nexport function cloneFamilyFor(family: string): { clone: string; substituted: boolean } {\n const key = family.trim().toLowerCase().replace(/^[\"']|[\"']$/g, \"\");\n const clone = CLONE_OF[key];\n return clone ? { clone, substituted: false } : { clone: FALLBACK_CLONE, substituted: true };\n}\n\n/** First token of a CSS font-family stack (\"Calibri, serif\" -> \"Calibri\"). */\nexport const firstFamilyToken = (stack: string): string => (stack.split(\",\")[0] ?? \"\").trim();\n\nexport const FONT_STYLES = [\"Regular\", \"Bold\", \"Italic\", \"BoldItalic\"] as const;\n\n/** Every bundled face filename. */\nexport const FONT_FILES: string[] = CLONE_FAMILIES.flatMap((fam) =>\n FONT_STYLES.map((style) => `${fam}-${style}.ttf`),\n);\n\n/** Toolbar font list: value is the original family (stored in the model), label\n * shows the clone we actually render \u2014 e.g. \"Calibri (Carlito)\". */\nexport const TOOLBAR_FONTS: { value: string; label: string }[] = [\n { value: \"Calibri, sans-serif\", label: \"Calibri (Carlito)\" },\n { value: \"Cambria, serif\", label: \"Cambria (Caladea)\" },\n { value: \"Georgia, serif\", label: \"Georgia (Gelasio)\" },\n { value: \"Arial, sans-serif\", label: \"Arial (Arimo)\" },\n { value: \"Times New Roman, serif\", label: \"Times New Roman\" },\n { value: \"Verdana, sans-serif\", label: \"Verdana (Arimo)\" },\n { value: \"Consolas, monospace\", label: \"Consolas (Cousine)\" },\n { value: \"Courier New, monospace\", label: \"Courier New (Cousine)\" },\n];\n", "// Shared paint styling \u2014 the constants and per-run styling DECISIONS that the\n// canvas renderer (src/paint/renderer.ts) and the PDF painter\n// (src/export/pdf/paintBlock.ts) must keep in lockstep. Centralising the magic\n// numbers and the link/colour rules stops the two painters from silently\n// drifting; the actual draw calls stay separate (canvas vs pdfkit are different\n// APIs). Pure data + math \u2014 no DOM, no rendering backend.\n\nimport type { CharStyle, PageBorderEdge, PageBorders, TabLeader } from \"@cw/shared\";\n\n// --- colours ---------------------------------------------------------------\n/** Unstyled/native table grid (when a cell carries no explicit borders). */\nexport const DEFAULT_GRID_COLOR = \"#c0c4c9\";\n/** External hyperlinks paint in this blue (Word's affordance). */\nexport const EXTERNAL_LINK_COLOR = \"#0b57d0\";\n/** In-document anchors that inherited a Hyperlink blue read as plain text. */\nexport const ANCHOR_TEXT_COLOR = \"#202124\";\nexport const FOOTNOTE_RULE_COLOR = \"#80868b\";\n/** Non-printing formatting marks (space dots, tab arrows, pilcrows, line breaks)\n * drawn only when \"show formatting marks\" is on. A muted gray-blue, like Word. */\nexport const FORMATTING_MARK_COLOR = \"#7a8aa0\";\nexport const TOC_LEADER_COLOR = \"#9aa0a6\";\nexport const IMAGE_PLACEHOLDER_COLOR = \"#f1f3f4\";\n\n/** Office \"Hyperlink\" character-style blues, normalised to text colour when they\n * arrive on an in-document anchor (TOC/cross-ref) so those read as plain text. */\nexport const HYPERLINK_BLUES = new Set([\n \"#0563c1\", \"#0000ff\", \"#0000ee\", \"#0b57d0\", \"#0066cc\", \"#1155cc\",\n]);\n\n/** A leader/TOC colour that inherited a Hyperlink blue \u2192 text colour. */\nexport const normalizeLinkBlue = (color: string): string =>\n HYPERLINK_BLUES.has(color.toLowerCase()) ? ANCHOR_TEXT_COLOR : color;\n\n// --- sub/superscript -------------------------------------------------------\n/** Sub/superscript is MEASURED and PAINTED at this fraction of the run size\n * (metrics.charStyleToFont scales the font; the painters scale to match). */\nexport const SUB_SUPER_SCALE = 0.65;\nconst SUPER_SHIFT = -0.38;\nconst SUB_SHIFT = 0.16;\n\n/** Baseline shift (px) for a sub/superscript run \u2014 fraction of the ORIGINAL size. */\nexport function verticalShift(vertical: CharStyle[\"verticalAlign\"], fontSizePx: number): number {\n if (vertical === \"super\") return SUPER_SHIFT * fontSizePx;\n if (vertical === \"sub\") return SUB_SHIFT * fontSizePx;\n return 0;\n}\n\n// --- text decorations ------------------------------------------------------\n/** Underline / strikethrough thickness (px). */\nexport const decorationThickness = (fontSizePx: number): number => Math.max(1, fontSizePx / 14);\n/** Underline distance below the baseline (the run's vShift is added by the caller). */\nexport const UNDERLINE_OFFSET_PX = 1.5;\n/** Strikethrough offset relative to the baseline (above it). */\nexport const strikeOffset = (fontSizePx: number): number => -0.28 * fontSizePx;\n\n/** The colour + decoration decision for a run, with link normalisation applied. */\nexport interface RunPaint {\n color: string;\n underline: boolean;\n strike: boolean;\n /** External (non-anchor) link \u2014 paints blue+underlined; the PDF also annotates it. */\n externalLink: boolean;\n}\nexport function runPaint(style: CharStyle): RunPaint {\n const anchor = style.link !== undefined && style.link.startsWith(\"#\");\n const externalLink = style.link !== undefined && !anchor;\n let color = style.color;\n if (externalLink) color = EXTERNAL_LINK_COLOR;\n else if (anchor && HYPERLINK_BLUES.has(style.color.toLowerCase())) color = ANCHOR_TEXT_COLOR;\n return {\n color,\n underline: externalLink || (!!style.underline && !anchor),\n strike: !!style.strikethrough,\n externalLink,\n };\n}\n\n// --- leaders (tab + TOC) ---------------------------------------------------\n/** Tab-leader dash pattern; [] = solid (underscore/none). */\nexport function leaderDash(kind: TabLeader): number[] {\n return kind === \"dot\" ? [1, 3] : kind === \"dash\" ? [4, 3] : [];\n}\nexport const leaderWidth = (fontSizePx: number): number => Math.max(1, fontSizePx / 14);\nexport const TOC_LEADER_DASH: number[] = [1, 4];\n/** Gap (px) between an entry's text/number and its dot leader. */\nexport const TOC_LEADER_GAP_PX = 8;\n\n// --- footnote rule ---------------------------------------------------------\n/** The separator rule spans this fraction of the content width (Word style). */\nexport const FOOTNOTE_RULE_WIDTH_FRACTION = 1 / 3;\n\n// --- column separators -----------------------------------------------------\n/** Thin gray rule drawn between newspaper columns (w:cols/@w:sep). */\nexport const COLUMN_SEPARATOR_COLOR = \"#c0c4c9\";\n\n// --- page borders (w:pgBorders) --------------------------------------------\n/** Default offset (px) of a page border from the page edge / text when an edge\n * omits w:space. ~24pt is Word's typical page-border offset. */\nconst PAGE_BORDER_DEFAULT_SPACE = 24;\n\n/** One stroked line segment of a page border, in page (px) coords. */\nexport interface PageBorderSegment {\n x1: number;\n y1: number;\n x2: number;\n y2: number;\n widthPx: number;\n color: string;\n /** [] = solid. */\n dash: number[];\n}\n\n/** Geometry of a page border box \u2192 the line segments to stroke. Shared so the\n * canvas renderer and the PDF painter draw identical borders. \"double\" yields\n * two parallel segments; \"none\"/absent edges are skipped. */\nexport function pageBorderSegments(\n borders: PageBorders,\n pageW: number,\n pageH: number,\n margin: { top: number; right: number; bottom: number; left: number },\n): PageBorderSegment[] {\n const fromText = borders.offsetFrom === \"text\";\n const sp = (e?: PageBorderEdge): number => e?.spacePx ?? PAGE_BORDER_DEFAULT_SPACE;\n // Each edge's distance, then the box bounds (per-edge space; usually uniform).\n const xL = fromText ? margin.left - sp(borders.left) : sp(borders.left);\n const xR = fromText ? pageW - margin.right + sp(borders.right) : pageW - sp(borders.right);\n const yT = fromText ? margin.top - sp(borders.top) : sp(borders.top);\n const yB = fromText ? pageH - margin.bottom + sp(borders.bottom) : pageH - sp(borders.bottom);\n const out: PageBorderSegment[] = [];\n const push = (e: PageBorderEdge | undefined, x1: number, y1: number, x2: number, y2: number): void => {\n if (!e || e.style === \"none\") return;\n const w = e.style === \"thick\" ? Math.max(2, e.widthPx) : Math.max(0.5, e.widthPx);\n const color = e.color === \"auto\" ? \"#000000\" : e.color;\n const dash = e.style === \"dashed\" ? [w * 3, w * 2] : e.style === \"dotted\" ? [w, w * 1.5] : [];\n out.push({ x1, y1, x2, y2, widthPx: w, color, dash });\n if (e.style === \"double\") {\n const g = w + 1; // inset the second line toward the box interior\n const horizontal = y1 === y2;\n if (horizontal) {\n const dy = y1 < pageH / 2 ? g : -g;\n out.push({ x1, y1: y1 + dy, x2, y2: y2 + dy, widthPx: w, color, dash: [] });\n } else {\n const dx = x1 < pageW / 2 ? g : -g;\n out.push({ x1: x1 + dx, y1, x2: x2 + dx, y2, widthPx: w, color, dash: [] });\n }\n }\n };\n push(borders.top, xL, yT, xR, yT);\n push(borders.bottom, xL, yB, xR, yB);\n push(borders.left, xL, yT, xL, yB);\n push(borders.right, xR, yT, xR, yB);\n return out;\n}\n\n// --- cell borders ----------------------------------------------------------\n/** Hairlines clamp up so a thin rule stays visible. */\nexport const cellBorderWidth = (widthPx: number): number => Math.max(0.5, widthPx);\n/** Dash pattern for a cell edge of stroke width w; [] = solid. */\nexport function cellBorderDash(style: string | undefined, w: number): number[] {\n return style === \"dashed\" ? [w * 3, w * 2] : style === \"dotted\" ? [w, w * 1.5] : [];\n}\n/** Offset of the inner stroke of a \"double\" border. */\nexport const doubleBorderGap = (w: number): number => w + 1;\n", "// Vertical font metrics (pretext measures widths; ascent/descent are ours).\n// One hidden canvas, results cached per font string.\n\nimport type { CharStyle } from \"@cw/shared\";\nimport { CLONE_METRICS, cloneFamilyFor, firstFamilyToken } from \"../fonts/clones\";\nimport { SUB_SUPER_SCALE } from \"../paint/paintStyle\";\n\nexport interface FontMetrics {\n ascent: number;\n descent: number;\n}\n\n/** The slice of CanvasRenderingContext2D the layout actually measures through.\n * DOM-free hosts (the export worker, Node backends) inject their own via\n * {@link setMeasureContext}; the browser falls back to a real canvas. */\nexport interface MeasureContext {\n font: string;\n measureText(text: string): {\n width: number;\n fontBoundingBoxAscent: number;\n fontBoundingBoxDescent: number;\n };\n}\n\nlet injectedCtx: MeasureContext | null = null;\nlet browserCtx: MeasureContext | null = null;\n\n/** Install a measurement context (export/Node hosts). Must be called before the\n * engine measures any text. No-op for the browser, which uses a real canvas. */\nexport function setMeasureContext(ctx: MeasureContext): void {\n injectedCtx = ctx;\n}\n\n// Lazily created so importing this module never touches the DOM \u2014 the engine can\n// run under Node once a context is injected (browser path stays byte-identical).\nfunction measureContext(): MeasureContext {\n if (injectedCtx) return injectedCtx;\n if (!browserCtx) {\n browserCtx = document.createElement(\"canvas\").getContext(\"2d\")! as unknown as MeasureContext;\n }\n return browserCtx;\n}\n\nconst metricsCache = new Map<string, FontMetrics>();\n\nexport function charStyleToFont(s: CharStyle): string {\n const italic = s.italic ? \"italic \" : \"\";\n const weight = s.bold ? \"700\" : \"400\";\n // Sub/superscript runs are MEASURED at the scaled size (paint shifts the\n // baseline) \u2014 pretext must measure exactly what paint draws.\n const size = s.verticalAlign ? Math.round(s.fontSizePx * SUB_SUPER_SCALE) : s.fontSizePx;\n // Render & measure with the bundled metric clone (e.g. Calibri -> Carlito), so\n // the editor, the browser export, and the Node backend all lay out identically\n // \u2014 no dependency on system fonts. The model keeps the original family.\n const family = cloneFamilyFor(firstFamilyToken(s.fontFamily)).clone;\n return `${italic}${weight} ${size}px ${family}`;\n}\n\n/** One-off text width at a font \u2014 LAYOUT-time only (paint never measures).\n * Used for paint-only decorations the engine positions (TOC page numbers). */\nexport function measureTextWidth(text: string, font: string): number {\n const ctx = measureContext();\n ctx.font = font;\n return ctx.measureText(text).width;\n}\n\n// Vertical metrics come from baked per-clone ratios (NOT the canvas/fontkit\n// context), so the editor and the exporters compute identical line heights and\n// therefore identical pagination on every platform. charStyleToFont already\n// emits the clone family, so the last token of the font string is it.\nexport function fontMetrics(font: string): FontMetrics {\n let m = metricsCache.get(font);\n if (!m) {\n const sizeMatch = /(\\d+(?:\\.\\d+)?)px/.exec(font);\n const size = sizeMatch ? parseFloat(sizeMatch[1]!) : 16;\n const family = font.slice(font.indexOf(\"px \") + 3).trim();\n const r = CLONE_METRICS[cloneFamilyFor(family).clone] ?? { ascent: 0.9, descent: 0.25 };\n m = { ascent: Math.round(r.ascent * size), descent: Math.round(r.descent * size) };\n metricsCache.set(font, m);\n }\n return m;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
createLayoutEngine,
|
|
9
9
|
effectiveSection,
|
|
10
10
|
resolveSections
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-T3253N22.js";
|
|
12
|
+
import "./chunk-PIMVQULL.js";
|
|
13
|
+
import "./chunk-U27EBKBG.js";
|
|
14
14
|
import "./chunk-XSRSBST2.js";
|
|
15
15
|
export {
|
|
16
16
|
createLayoutEngine,
|
|
17
17
|
effectiveSection,
|
|
18
18
|
resolveSections
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=engine-
|
|
20
|
+
//# sourceMappingURL=engine-5F7DUU4W.js.map
|
package/dist-node/export.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
require_unicode_trie,
|
|
17
17
|
resolveFont,
|
|
18
18
|
tslib_es6_exports
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-SA26UVIJ.js";
|
|
20
20
|
import {
|
|
21
21
|
WML_NS,
|
|
22
22
|
XML_DECL,
|
|
@@ -30,8 +30,9 @@ import {
|
|
|
30
30
|
pxToEmu,
|
|
31
31
|
pxToTwips,
|
|
32
32
|
runPropsXml,
|
|
33
|
+
tableStyleXml,
|
|
33
34
|
textEl
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-EMY2P524.js";
|
|
35
36
|
import {
|
|
36
37
|
pageOfBlockMap
|
|
37
38
|
} from "./chunk-EGSAVPCC.js";
|
|
@@ -41,14 +42,16 @@ import {
|
|
|
41
42
|
} from "./chunk-5PUCGN47.js";
|
|
42
43
|
import {
|
|
43
44
|
createLayoutEngine
|
|
44
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-T3253N22.js";
|
|
45
46
|
import {
|
|
46
47
|
detectTocHeadings,
|
|
47
48
|
inRange,
|
|
48
49
|
parseTocInstruction,
|
|
50
|
+
styleType,
|
|
49
51
|
textOfRuns
|
|
50
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-PIMVQULL.js";
|
|
51
53
|
import {
|
|
54
|
+
COLUMN_SEPARATOR_COLOR,
|
|
52
55
|
DEFAULT_GRID_COLOR,
|
|
53
56
|
FOOTNOTE_RULE_COLOR,
|
|
54
57
|
FOOTNOTE_RULE_WIDTH_FRACTION,
|
|
@@ -65,10 +68,11 @@ import {
|
|
|
65
68
|
leaderDash,
|
|
66
69
|
leaderWidth,
|
|
67
70
|
normalizeLinkBlue,
|
|
71
|
+
pageBorderSegments,
|
|
68
72
|
runPaint,
|
|
69
73
|
strikeOffset,
|
|
70
74
|
verticalShift
|
|
71
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-U27EBKBG.js";
|
|
72
76
|
import {
|
|
73
77
|
__commonJS,
|
|
74
78
|
__require,
|
|
@@ -24545,7 +24549,7 @@ function toBuffer(bytes) {
|
|
|
24545
24549
|
var PT = 72 / 96;
|
|
24546
24550
|
async function renderPdf(doc, opts = {}) {
|
|
24547
24551
|
await installMeasureHost();
|
|
24548
|
-
const { createLayoutEngine: createLayoutEngine2 } = await import("./engine-
|
|
24552
|
+
const { createLayoutEngine: createLayoutEngine2 } = await import("./engine-5F7DUU4W.js");
|
|
24549
24553
|
const tree = createLayoutEngine2().layout(doc);
|
|
24550
24554
|
const warnings = new WarningSink();
|
|
24551
24555
|
const images = opts.images ?? {};
|
|
@@ -24600,8 +24604,23 @@ async function renderPdf(doc, opts = {}) {
|
|
|
24600
24604
|
}
|
|
24601
24605
|
pdf.save();
|
|
24602
24606
|
pdf.scale(PT);
|
|
24603
|
-
pdf.rect(0, 0, page.widthPx, page.heightPx).fill("#ffffff");
|
|
24607
|
+
pdf.rect(0, 0, page.widthPx, page.heightPx).fill(page.pageColorHex ?? "#ffffff");
|
|
24608
|
+
if (page.pageBorders) {
|
|
24609
|
+
for (const s of pageBorderSegments(page.pageBorders, page.widthPx, page.heightPx, page.marginPx)) {
|
|
24610
|
+
pdf.lineWidth(s.widthPx).strokeColor(s.color);
|
|
24611
|
+
if (s.dash.length) pdf.dash(s.dash[0], { space: s.dash[1] ?? s.dash[0] });
|
|
24612
|
+
else pdf.undash();
|
|
24613
|
+
pdf.moveTo(s.x1, s.y1).lineTo(s.x2, s.y2).stroke();
|
|
24614
|
+
}
|
|
24615
|
+
pdf.undash();
|
|
24616
|
+
}
|
|
24604
24617
|
for (const block of page.blocks) paintBlock(ctx, block);
|
|
24618
|
+
if (page.columnSeparatorsX) {
|
|
24619
|
+
pdf.undash().lineWidth(1).strokeColor(COLUMN_SEPARATOR_COLOR);
|
|
24620
|
+
for (const x of page.columnSeparatorsX) {
|
|
24621
|
+
pdf.moveTo(x + 0.5, page.contentTopPx).lineTo(x + 0.5, page.contentBottomPx).stroke();
|
|
24622
|
+
}
|
|
24623
|
+
}
|
|
24605
24624
|
if (page.footnoteRuleY !== void 0) {
|
|
24606
24625
|
const cw = page.widthPx - page.marginPx.left - page.marginPx.right;
|
|
24607
24626
|
pdf.undash().lineWidth(1).strokeColor(FOOTNOTE_RULE_COLOR);
|
|
@@ -24944,13 +24963,25 @@ function tableXml(table, ctx) {
|
|
|
24944
24963
|
col = emitContinues(col, out);
|
|
24945
24964
|
rowsXml.push(el("w:tr", void 0, out.join("")));
|
|
24946
24965
|
}
|
|
24966
|
+
const styleRef = table.styleId ? el("w:tblStyle", { "w:val": table.styleId }) : "";
|
|
24967
|
+
const look = table.styleId && table.condOverrides ? tblLookXml(table.condOverrides) : "";
|
|
24947
24968
|
const tblPr = el(
|
|
24948
24969
|
"w:tblPr",
|
|
24949
24970
|
void 0,
|
|
24950
|
-
el("w:tblW", { "w:w": 0, "w:type": "auto" }) + el("w:tblLayout", { "w:type": "fixed" })
|
|
24971
|
+
styleRef + el("w:tblW", { "w:w": 0, "w:type": "auto" }) + el("w:tblLayout", { "w:type": "fixed" }) + look
|
|
24951
24972
|
);
|
|
24952
24973
|
return el("w:tbl", void 0, tblPr + el("w:tblGrid", void 0, grid) + rowsXml.join(""));
|
|
24953
24974
|
}
|
|
24975
|
+
function tblLookXml(o) {
|
|
24976
|
+
return el("w:tblLook", {
|
|
24977
|
+
"w:firstRow": o.firstRow ? "1" : "0",
|
|
24978
|
+
"w:lastRow": o.lastRow ? "1" : "0",
|
|
24979
|
+
"w:firstColumn": o.firstCol ? "1" : "0",
|
|
24980
|
+
"w:lastColumn": o.lastCol ? "1" : "0",
|
|
24981
|
+
"w:noHBand": o.bandRows ? "0" : "1",
|
|
24982
|
+
"w:noVBand": o.bandCols ? "0" : "1"
|
|
24983
|
+
});
|
|
24984
|
+
}
|
|
24954
24985
|
function blockXml(block, ctx) {
|
|
24955
24986
|
if (block.kind === "paragraph") return paragraphXml(block, ctx);
|
|
24956
24987
|
if (block.kind === "table") return tableXml(block, ctx);
|
|
@@ -25077,6 +25108,20 @@ function imageParagraphXml(img, ctx) {
|
|
|
25077
25108
|
const align = img.align === "center" ? "center" : img.align === "right" ? "right" : "left";
|
|
25078
25109
|
return el("w:p", void 0, el("w:pPr", void 0, el("w:jc", { "w:val": align })) + el("w:r", void 0, drawing));
|
|
25079
25110
|
}
|
|
25111
|
+
function pgBordersXml(b) {
|
|
25112
|
+
const edge = (name, e) => {
|
|
25113
|
+
if (!e || e.style === "none") return "";
|
|
25114
|
+
const spacePt = Math.min(31, Math.max(0, Math.round((e.spacePx ?? 0) * (72 / 96))));
|
|
25115
|
+
return el("w:" + name, {
|
|
25116
|
+
"w:val": e.style,
|
|
25117
|
+
"w:sz": pxToEighthPoints(e.widthPx),
|
|
25118
|
+
"w:space": spacePt,
|
|
25119
|
+
"w:color": e.color === "auto" ? "auto" : hexColor(e.color)
|
|
25120
|
+
});
|
|
25121
|
+
};
|
|
25122
|
+
const inner = edge("top", b.top) + edge("left", b.left) + edge("bottom", b.bottom) + edge("right", b.right);
|
|
25123
|
+
return el("w:pgBorders", { "w:offsetFrom": b.offsetFrom ?? "page" }, inner);
|
|
25124
|
+
}
|
|
25080
25125
|
function sectPrXml(s, ctx, addBand, isBody) {
|
|
25081
25126
|
const c = [];
|
|
25082
25127
|
const band = (blocks, kind, type) => {
|
|
@@ -25092,7 +25137,12 @@ function sectPrXml(s, ctx, addBand, isBody) {
|
|
|
25092
25137
|
band(s.footerEven, "footer", "even");
|
|
25093
25138
|
if (s.headerFirst || s.footerFirst) c.push(el("w:titlePg"));
|
|
25094
25139
|
if (s.pageWidthPx !== void 0 && s.pageHeightPx !== void 0) {
|
|
25095
|
-
|
|
25140
|
+
const pgSz = {
|
|
25141
|
+
"w:w": pxToTwips(s.pageWidthPx),
|
|
25142
|
+
"w:h": pxToTwips(s.pageHeightPx)
|
|
25143
|
+
};
|
|
25144
|
+
if (s.pageWidthPx > s.pageHeightPx) pgSz["w:orient"] = "landscape";
|
|
25145
|
+
c.push(el("w:pgSz", pgSz));
|
|
25096
25146
|
}
|
|
25097
25147
|
if (s.marginPx) {
|
|
25098
25148
|
const m = s.marginPx;
|
|
@@ -25101,13 +25151,23 @@ function sectPrXml(s, ctx, addBand, isBody) {
|
|
|
25101
25151
|
"w:right": pxToTwips(m.right),
|
|
25102
25152
|
"w:bottom": pxToTwips(m.bottom),
|
|
25103
25153
|
"w:left": pxToTwips(m.left),
|
|
25104
|
-
"w:header": 720,
|
|
25105
|
-
"w:footer": 720
|
|
25154
|
+
"w:header": s.headerDistancePx !== void 0 ? pxToTwips(s.headerDistancePx) : 720,
|
|
25155
|
+
"w:footer": s.footerDistancePx !== void 0 ? pxToTwips(s.footerDistancePx) : 720
|
|
25106
25156
|
}));
|
|
25107
25157
|
}
|
|
25108
25158
|
if (s.columns && s.columns.count > 1) {
|
|
25109
|
-
|
|
25159
|
+
const cols = s.columns;
|
|
25160
|
+
const attrs = { "w:num": cols.count, "w:space": pxToTwips(cols.gapPx) };
|
|
25161
|
+
if (cols.sep) attrs["w:sep"] = "1";
|
|
25162
|
+
if (cols.cols && cols.cols.length === cols.count) {
|
|
25163
|
+
attrs["w:equalWidth"] = "0";
|
|
25164
|
+
const inner = cols.cols.map((col) => el("w:col", { "w:w": pxToTwips(col.widthPx), "w:space": pxToTwips(col.spaceAfterPx) })).join("");
|
|
25165
|
+
c.push(el("w:cols", attrs, inner));
|
|
25166
|
+
} else {
|
|
25167
|
+
c.push(el("w:cols", attrs));
|
|
25168
|
+
}
|
|
25110
25169
|
}
|
|
25170
|
+
if (s.pageBorders) c.push(pgBordersXml(s.pageBorders));
|
|
25111
25171
|
if (s.pageNumberStart !== void 0) c.push(el("w:pgNumType", { "w:start": s.pageNumberStart }));
|
|
25112
25172
|
if (!isBody) c.push(el("w:type", { "w:val": "nextPage" }));
|
|
25113
25173
|
return el("w:sectPr", void 0, c.join(""));
|
|
@@ -25132,7 +25192,8 @@ function buildDocumentXml(blocks, section, ctx, addBand) {
|
|
|
25132
25192
|
}
|
|
25133
25193
|
}
|
|
25134
25194
|
const body = parts.join("") + sectPrXml(section, ctx, addBand, true);
|
|
25135
|
-
|
|
25195
|
+
const background = section.pageColorHex !== void 0 ? el("w:background", { "w:color": hexColor(section.pageColorHex) }) : "";
|
|
25196
|
+
return XML_DECL + el("w:document", WML_NS, background + el("w:body", void 0, body));
|
|
25136
25197
|
}
|
|
25137
25198
|
|
|
25138
25199
|
// src/export/docx/contentTypes.ts
|
|
@@ -25240,20 +25301,22 @@ function numberingXml(lists, listIdMap) {
|
|
|
25240
25301
|
}
|
|
25241
25302
|
|
|
25242
25303
|
// src/export/docx/settingsXml.ts
|
|
25243
|
-
function settingsXml(evenAndOdd) {
|
|
25244
|
-
const body = evenAndOdd ? el("w:evenAndOddHeadersAndFooters") : "";
|
|
25304
|
+
function settingsXml(evenAndOdd, displayBackgroundShape = false) {
|
|
25305
|
+
const body = (displayBackgroundShape ? el("w:displayBackgroundShape") : "") + (evenAndOdd ? el("w:evenAndOddHeadersAndFooters") : "");
|
|
25245
25306
|
return XML_DECL + el("w:settings", WML_NS, body);
|
|
25246
25307
|
}
|
|
25247
25308
|
|
|
25248
25309
|
// src/export/docx/stylesXml.ts
|
|
25249
|
-
function stylesXml(sheet) {
|
|
25250
|
-
const
|
|
25251
|
-
const
|
|
25252
|
-
|
|
25253
|
-
|
|
25310
|
+
function stylesXml(sheet, tableStyles) {
|
|
25311
|
+
const named = (sheet?.styles ?? []).map((s) => {
|
|
25312
|
+
const isChar = styleType(s) === "character";
|
|
25313
|
+
const attrs = { "w:type": isChar ? "character" : "paragraph", "w:styleId": s.id };
|
|
25314
|
+
if (!isChar && sheet && s.id === sheet.defaultStyleId) attrs["w:default"] = "1";
|
|
25315
|
+
const body = el("w:name", { "w:val": s.name }) + (s.basedOn ? el("w:basedOn", { "w:val": s.basedOn }) : "") + (isChar ? "" : partialPPrXml(s.para)) + partialRPrXml(s.char);
|
|
25254
25316
|
return el("w:style", attrs, body);
|
|
25255
25317
|
}).join("");
|
|
25256
|
-
|
|
25318
|
+
const tables = Object.values(tableStyles ?? {}).map(tableStyleXml).join("");
|
|
25319
|
+
return XML_DECL + el("w:styles", WML_NS, named + tables);
|
|
25257
25320
|
}
|
|
25258
25321
|
|
|
25259
25322
|
// src/export/docx/writeDocx.ts
|
|
@@ -25343,8 +25406,10 @@ function writeDocx(doc, images = {}, tocPages) {
|
|
|
25343
25406
|
return bodyRels.add(kind === "header" ? REL.header : REL.footer, file);
|
|
25344
25407
|
};
|
|
25345
25408
|
parts["word/document.xml"] = buildDocumentXml(doc.blocks, doc.section, bodyCtx, addBand);
|
|
25346
|
-
|
|
25347
|
-
|
|
25409
|
+
const hasNamed = !!doc.stylesheet && doc.stylesheet.styles.length > 0;
|
|
25410
|
+
const hasTableStyles = !!doc.tableStyles && Object.keys(doc.tableStyles).length > 0;
|
|
25411
|
+
if (hasNamed || hasTableStyles) {
|
|
25412
|
+
parts["word/styles.xml"] = stylesXml(doc.stylesheet, doc.tableStyles);
|
|
25348
25413
|
overrides.push(["/word/styles.xml", CT.styles]);
|
|
25349
25414
|
bodyRels.add(REL.styles, "styles.xml");
|
|
25350
25415
|
}
|
|
@@ -25359,7 +25424,7 @@ function writeDocx(doc, images = {}, tocPages) {
|
|
|
25359
25424
|
bodyRels.add(REL.footnotes, "footnotes.xml");
|
|
25360
25425
|
}
|
|
25361
25426
|
const evenAndOdd = sectionsHaveEvenBands(doc);
|
|
25362
|
-
parts["word/settings.xml"] = settingsXml(evenAndOdd);
|
|
25427
|
+
parts["word/settings.xml"] = settingsXml(evenAndOdd, doc.section.pageColorHex !== void 0);
|
|
25363
25428
|
overrides.push(["/word/settings.xml", CT.settings]);
|
|
25364
25429
|
bodyRels.add(REL.settings, "settings.xml");
|
|
25365
25430
|
for (const [path, bytes2] of bodyMedia.parts()) parts[`word/${path}`] = bytes2;
|