@forevka/wordcanvas 0.7.1 → 0.7.3
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-CqU4Popa.js} +10903 -10736
- package/dist-lib/assets/worker-Cw5cYW5z.js +2418 -0
- package/dist-lib/blockFactory-DDCRWDnA.js +91 -0
- package/dist-lib/browser-BUrsjziD.js +612 -0
- package/dist-lib/builder.js +13 -13
- package/dist-lib/editorApp-CB_ZArIF.js +9566 -0
- package/dist-lib/export.js +4507 -4456
- package/dist-lib/generate-toc.js +7 -7
- package/dist-lib/import.js +2 -2
- package/dist-lib/lists-DpmgbDyt.js +110 -0
- package/dist-lib/measure.js +2 -2
- package/dist-lib/{measureHost-CMiJKdlk.js → measureHost-BlukHGwx.js} +1 -1
- package/dist-lib/metrics-bvGO8KDK.js +96 -0
- package/dist-lib/paintStyle-vT6jtWbH.js +74 -0
- package/dist-lib/pipeline-UryP-u7Z.js +1850 -0
- package/dist-lib/recalc-docx.js +2 -2
- package/dist-lib/recalcToc-BfXlXZik.js +3985 -0
- package/dist-lib/styleProps-DhqDEfvc.js +149 -0
- package/dist-lib/stylesheet-LTBEGkvG.js +146 -0
- package/dist-lib/toc-D09f4PrI.js +939 -0
- package/dist-lib/{webmcp-6WxRNKCc.js → webmcp-K6UZgQJ0.js} +60 -68
- package/dist-lib/wordcanvas-DBx2ana_.js +734 -0
- package/dist-lib/wordcanvas.js +4 -2
- package/dist-node/{chunk-CDN6WU2P.js → chunk-373K2XRY.js} +40 -22
- package/dist-node/chunk-373K2XRY.js.map +7 -0
- package/dist-node/{chunk-22JHAERT.js → chunk-3PUV3BG6.js} +235 -39
- package/dist-node/chunk-3PUV3BG6.js.map +7 -0
- package/dist-node/{chunk-4ICCHZX4.js → chunk-5RX3IHWE.js} +39 -3
- package/dist-node/chunk-5RX3IHWE.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-BRAPV465.js → chunk-HWQKGDS2.js} +2 -2
- package/dist-node/{chunk-6AJJMHKY.js → chunk-KJV7GJ3H.js} +1 -1
- package/dist-node/chunk-KJV7GJ3H.js.map +7 -0
- package/dist-node/{chunk-RNB336F3.js → chunk-ZLLSXOO2.js} +92 -14
- package/dist-node/{chunk-RNB336F3.js.map → chunk-ZLLSXOO2.js.map} +2 -2
- package/dist-node/{engine-5FGDJD2H.js → engine-LLA6PCS5.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 +493 -1
- 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/lists-Sc5I40JO.js +0 -110
- 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-lib/toc-B6VpkJge.js +0 -213
- package/dist-lib/wordcanvas-CFqpDK0k.js +0 -125
- 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-HWQKGDS2.js.map} +0 -0
- /package/dist-node/{engine-5FGDJD2H.js.map → engine-LLA6PCS5.js.map} +0 -0
|
@@ -91,11 +91,11 @@ function verticalShift(vertical, fontSizePx) {
|
|
|
91
91
|
var decorationThickness = (fontSizePx) => Math.max(1, fontSizePx / 14);
|
|
92
92
|
var UNDERLINE_OFFSET_PX = 1.5;
|
|
93
93
|
var strikeOffset = (fontSizePx) => -0.28 * fontSizePx;
|
|
94
|
-
function runPaint(style) {
|
|
94
|
+
function runPaint(style, linkColor = EXTERNAL_LINK_COLOR) {
|
|
95
95
|
const anchor = style.link !== void 0 && style.link.startsWith("#");
|
|
96
96
|
const externalLink = style.link !== void 0 && !anchor;
|
|
97
97
|
let color = style.color;
|
|
98
|
-
if (externalLink) color =
|
|
98
|
+
if (externalLink) color = linkColor;
|
|
99
99
|
else if (anchor && HYPERLINK_BLUES.has(style.color.toLowerCase())) color = ANCHOR_TEXT_COLOR;
|
|
100
100
|
return {
|
|
101
101
|
color,
|
|
@@ -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-5RX3IHWE.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/** UI-accent blue for editor chrome affordances (e.g. the band-edit boundary). */\nexport const ACCENT_BLUE = \"#1a73e8\";\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, linkColor: string = EXTERNAL_LINK_COLOR): 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 = linkColor;\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
|
+
}
|
|
@@ -77,6 +77,7 @@ var hexColor = (c) => c.replace(/^#/, "").toLowerCase();
|
|
|
77
77
|
function runPropsXml(s) {
|
|
78
78
|
const family = (s.fontFamily.split(",")[0] ?? "").trim();
|
|
79
79
|
const children = [];
|
|
80
|
+
if (s.charStyleId) children.push(el("w:rStyle", { "w:val": s.charStyleId }));
|
|
80
81
|
if (family) children.push(el("w:rFonts", { "w:ascii": family, "w:hAnsi": family, "w:cs": family }));
|
|
81
82
|
children.push(el("w:b", { "w:val": s.bold ? "1" : "0" }));
|
|
82
83
|
children.push(el("w:i", { "w:val": s.italic ? "1" : "0" }));
|
|
@@ -177,6 +178,34 @@ function partialPPrXml(p) {
|
|
|
177
178
|
}
|
|
178
179
|
return out.length > 0 ? el("w:pPr", void 0, out.join("")) : "";
|
|
179
180
|
}
|
|
181
|
+
function condBordersXml(tag, b) {
|
|
182
|
+
const edge = (name, spec) => {
|
|
183
|
+
if (!spec) return "";
|
|
184
|
+
const val = spec.style === "double" ? "double" : spec.style === "dashed" ? "dashed" : spec.style === "dotted" ? "dotted" : "single";
|
|
185
|
+
return el("w:" + name, { "w:val": val, "w:sz": pxToEighthPoints(spec.widthPx), "w:space": 0, "w:color": hexColor(spec.color) });
|
|
186
|
+
};
|
|
187
|
+
return el(tag, void 0, edge("top", b.top) + edge("left", b.left) + edge("bottom", b.bottom) + edge("right", b.right));
|
|
188
|
+
}
|
|
189
|
+
var shdFillXml = (fill) => el("w:shd", { "w:val": "clear", "w:color": "auto", "w:fill": hexColor(fill) });
|
|
190
|
+
function tblStylePrXml(cond, props) {
|
|
191
|
+
const tc = [];
|
|
192
|
+
if (props.borders) tc.push(condBordersXml("w:tcBorders", props.borders));
|
|
193
|
+
if (props.shading) tc.push(shdFillXml(props.shading));
|
|
194
|
+
const tcPr = tc.length > 0 ? el("w:tcPr", void 0, tc.join("")) : "";
|
|
195
|
+
return el("w:tblStylePr", { "w:type": cond }, partialRPrXml(props.char ?? {}) + partialPPrXml(props.para ?? {}) + tcPr);
|
|
196
|
+
}
|
|
197
|
+
function tableStyleXml(style) {
|
|
198
|
+
const base = style.conds.wholeTable ?? {};
|
|
199
|
+
const tblPrKids = [];
|
|
200
|
+
if (style.rowBandSize !== void 0) tblPrKids.push(el("w:tblStyleRowBandSize", { "w:val": style.rowBandSize }));
|
|
201
|
+
if (style.colBandSize !== void 0) tblPrKids.push(el("w:tblStyleColBandSize", { "w:val": style.colBandSize }));
|
|
202
|
+
if (base.borders) tblPrKids.push(condBordersXml("w:tblBorders", base.borders));
|
|
203
|
+
if (base.shading) tblPrKids.push(shdFillXml(base.shading));
|
|
204
|
+
const tblPr = tblPrKids.length > 0 ? el("w:tblPr", void 0, tblPrKids.join("")) : "";
|
|
205
|
+
const conds = Object.entries(style.conds).filter(([c]) => c !== "wholeTable").map(([c, p]) => tblStylePrXml(c, p)).join("");
|
|
206
|
+
const body = el("w:name", { "w:val": style.name }) + (style.basedOn ? el("w:basedOn", { "w:val": style.basedOn }) : "") + partialRPrXml(base.char ?? {}) + partialPPrXml(base.para ?? {}) + tblPr + conds;
|
|
207
|
+
return el("w:style", { "w:type": "table", "w:styleId": style.id }, body);
|
|
208
|
+
}
|
|
180
209
|
|
|
181
210
|
export {
|
|
182
211
|
pxToTwips,
|
|
@@ -191,6 +220,7 @@ export {
|
|
|
191
220
|
runPropsXml,
|
|
192
221
|
paraCoreXml,
|
|
193
222
|
partialRPrXml,
|
|
194
|
-
partialPPrXml
|
|
223
|
+
partialPPrXml,
|
|
224
|
+
tableStyleXml
|
|
195
225
|
};
|
|
196
|
-
//# sourceMappingURL=chunk-
|
|
226
|
+
//# sourceMappingURL=chunk-EMY2P524.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/export/docx/xmlWrite.ts", "../src/export/units.ts", "../src/export/docx/mappings.ts", "../src/export/docx/styleProps.ts"],
|
|
4
|
+
"sourcesContent": ["// Minimal, dependency-free XML string emitter for OOXML parts. Attribute order is\n// insertion order (Word doesn't care); empty children collapse to self-closing.\n\nexport type Attrs = Record<string, string | number | boolean | undefined>;\n\nexport function escapeText(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\nfunction escapeAttr(s: string): string {\n return escapeText(s).replace(/\"/g, \""\");\n}\n\nfunction serializeAttrs(attrs: Attrs | undefined): string {\n if (!attrs) return \"\";\n let out = \"\";\n for (const [k, v] of Object.entries(attrs)) {\n if (v === undefined || v === false) continue;\n out += ` ${k}=\"${escapeAttr(String(v))}\"`;\n }\n return out;\n}\n\n/** An element. `children` is pre-serialized XML (caller joins arrays). Pass \"\"\n * or undefined for an empty element (self-closing). */\nexport function el(tag: string, attrs?: Attrs, children?: string): string {\n const a = serializeAttrs(attrs);\n if (children === undefined || children === \"\") return `<${tag}${a}/>`;\n return `<${tag}${a}>${children}</${tag}>`;\n}\n\n/** A w:t, preserving leading/trailing whitespace when present. */\nexport function textEl(text: string): string {\n const needsPreserve = /^\\s|\\s$|\\s\\s/.test(text) || text.includes(\"\\t\");\n return el(\"w:t\", needsPreserve ? { \"xml:space\": \"preserve\" } : undefined, escapeText(text));\n}\n\nexport const XML_DECL = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\\n';\n\n/** The w: + relationships + drawing namespaces Word expects on a document root. */\nexport const WML_NS = {\n \"xmlns:w\": \"http://schemas.openxmlformats.org/wordprocessingml/2006/main\",\n \"xmlns:r\": \"http://schemas.openxmlformats.org/officeDocument/2006/relationships\",\n \"xmlns:wp\": \"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\",\n \"xmlns:a\": \"http://schemas.openxmlformats.org/drawingml/2006/main\",\n \"xmlns:pic\": \"http://schemas.openxmlformats.org/drawingml/2006/picture\",\n \"xmlns:w14\": \"http://schemas.microsoft.com/office/word/2010/wordml\",\n \"xmlns:mc\": \"http://schemas.openxmlformats.org/markup-compatibility/2006\",\n} as const;\n", "// px (CSS, 96dpi) -> OOXML units. Exact inverses of src/import/docx/units.ts.\r\n\r\n// A non-finite value (NaN/Infinity from an undefined style field) would serialize\r\n// to an invalid w:val=\"NaN\" and corrupt the .docx. Coerce to 0 so output stays\r\n// well-formed \u2014 these are pure unit conversions, so NaN never legitimately occurs.\r\nconst finite = (n: number): number => (Number.isFinite(n) ? n : 0);\r\n\r\n/** px -> twips: px \u00D7 15 (twip = 1/20pt, px = tw/15). */\r\nexport const pxToTwips = (px: number): number => Math.round(finite(px) * 15);\r\n\r\n/** px -> half-points: px \u00D7 1.5 (w:sz; px = hp \u00D7 2/3). */\r\nexport const pxToHalfPoints = (px: number): number => Math.round(finite(px) * 1.5);\r\n\r\n/** px -> EMU: px \u00D7 9525 (image extents; 914400 EMU/in \u00F7 96). */\r\nexport const pxToEmu = (px: number): number => Math.round(finite(px) * 9525);\r\n\r\n/** px -> eighth-points: px \u00D7 6 (border w:sz; px = sz/6). */\r\nexport const pxToEighthPoints = (px: number): number => Math.max(2, Math.round(finite(px) * 6));\r\n\r\n/** line-height multiplier -> w:line 240ths (lineRule=\"auto\"). */\r\nexport const multiplierToLine = (m: number): number => Math.round(finite(m) * 240);\r\n", "// Single source for model \u2192 WordprocessingML value mappings shared across the\r\n// exporter (documentXml, styleProps) and the headless TOC generator. Keeping\r\n// these in one place prevents the maps from drifting apart (they already had).\r\n\r\nimport type { ParaStyle } from \"@cw/shared\";\r\n\r\n/** highlight hex \u2192 Word highlight color name (w:highlight w:val). */\r\nexport const HIGHLIGHT_NAME: Record<string, string> = {\r\n \"#ffff00\": \"yellow\", \"#00ff00\": \"green\", \"#00ffff\": \"cyan\", \"#ff00ff\": \"magenta\",\r\n \"#0000ff\": \"blue\", \"#ff0000\": \"red\", \"#000080\": \"darkBlue\", \"#008080\": \"darkCyan\",\r\n \"#008000\": \"darkGreen\", \"#800080\": \"darkMagenta\", \"#800000\": \"darkRed\", \"#808000\": \"darkYellow\",\r\n \"#808080\": \"darkGray\", \"#c0c0c0\": \"lightGray\", \"#000000\": \"black\", \"#ffffff\": \"white\",\r\n};\r\n\r\n/** paragraph align \u2192 w:jc w:val. */\r\nexport const JC: Record<ParaStyle[\"align\"], string> = { left: \"left\", center: \"center\", right: \"right\", justify: \"both\" };\r\n\r\n/** tab align \u2192 w:tab w:val. */\r\nexport const TAB_VAL: Record<string, string> = { left: \"left\", center: \"center\", right: \"right\", decimal: \"decimal\" };\r\n\r\n/** tab leader \u2192 w:tab w:leader. */\r\nexport const TAB_LEADER: Record<string, string> = { dot: \"dot\", dash: \"hyphen\", underscore: \"underscore\" };\r\n\r\n/** strip a leading \"#\" and lowercase a hex color for OOXML w:val attributes. */\r\nexport const hexColor = (c: string): string => c.replace(/^#/, \"\").toLowerCase();\r\n", "// Partial rPr/pPr emitters for style-gallery patches (NamedStyle.char/.para) and\r\n// list-marker run props. Only DEFINED fields are written \u2014 the importer reads\r\n// each w:* element into a patch field, so absent elements stay absent.\r\n\r\nimport type { CellBorders, CharStyle, ParaStyle, TableCond, TableCondProps, TableStyle } from \"@cw/shared\";\r\nimport { multiplierToLine, pxToEighthPoints, pxToHalfPoints, pxToTwips } from \"../units\";\r\nimport { HIGHLIGHT_NAME, hexColor as hex, JC, TAB_LEADER, TAB_VAL } from \"./mappings\";\r\nimport { el } from \"./xmlWrite\";\r\n\r\n// Full rPr serializer: every toggle written explicitly (on/off) so a run's\r\n// direct formatting fully overrides any inherited paragraph/named style on\r\n// re-import. Shared by the main exporter (documentXml) and the headless TOC\r\n// generator (recalc/generateTocDocx) so they can't drift.\r\nexport function runPropsXml(s: CharStyle): string {\r\n const family = (s.fontFamily.split(\",\")[0] ?? \"\").trim();\r\n const children: string[] = [];\r\n // w:rStyle (character-style reference) must be the first child of w:rPr; the\r\n // concrete props below still override it on re-import (Word semantics).\r\n if (s.charStyleId) children.push(el(\"w:rStyle\", { \"w:val\": s.charStyleId }));\r\n if (family) children.push(el(\"w:rFonts\", { \"w:ascii\": family, \"w:hAnsi\": family, \"w:cs\": family }));\r\n children.push(el(\"w:b\", { \"w:val\": s.bold ? \"1\" : \"0\" }));\r\n children.push(el(\"w:i\", { \"w:val\": s.italic ? \"1\" : \"0\" }));\r\n if (s.strikethrough) children.push(el(\"w:strike\", { \"w:val\": \"1\" }));\r\n if (s.hidden) children.push(el(\"w:vanish\", { \"w:val\": \"1\" })); // preserved hidden text\r\n children.push(el(\"w:color\", { \"w:val\": hex(s.color) }));\r\n children.push(el(\"w:sz\", { \"w:val\": pxToHalfPoints(s.fontSizePx) }));\r\n children.push(el(\"w:szCs\", { \"w:val\": pxToHalfPoints(s.fontSizePx) }));\r\n children.push(el(\"w:u\", { \"w:val\": s.underline ? \"single\" : \"none\" }));\r\n if (s.letterSpacingPx !== undefined) children.push(el(\"w:spacing\", { \"w:val\": pxToTwips(s.letterSpacingPx) }));\r\n if (s.highlightColor) {\r\n const name = HIGHLIGHT_NAME[s.highlightColor.toLowerCase()];\r\n if (name) children.push(el(\"w:highlight\", { \"w:val\": name }));\r\n }\r\n if (s.verticalAlign) children.push(el(\"w:vertAlign\", { \"w:val\": s.verticalAlign === \"super\" ? \"superscript\" : \"subscript\" }));\r\n return el(\"w:rPr\", undefined, children.join(\"\"));\r\n}\r\n\r\n// The spacing/indent/jc/tabs core shared by every full pPr: returned as\r\n// concatenated child elements (NOT wrapped in w:pPr) so the main exporter can\r\n// interleave it with pStyle/numPr/breaks/section props, while the TOC generator\r\n// wraps it directly. Emission order matches OOXML's tolerant exporter convention.\r\nexport function paraCoreXml(style: ParaStyle): string {\r\n const c: string[] = [];\r\n c.push(el(\"w:spacing\", {\r\n \"w:before\": pxToTwips(style.spaceBeforePx),\r\n \"w:after\": pxToTwips(style.spaceAfterPx),\r\n \"w:line\": multiplierToLine(style.lineHeight),\r\n \"w:lineRule\": \"auto\",\r\n }));\r\n const ind: Record<string, number> = {};\r\n if (style.indentLeftPx) ind[\"w:left\"] = pxToTwips(style.indentLeftPx);\r\n if (style.indentRightPx) ind[\"w:right\"] = pxToTwips(style.indentRightPx);\r\n if (style.indentFirstLinePx > 0) ind[\"w:firstLine\"] = pxToTwips(style.indentFirstLinePx);\r\n else if (style.indentFirstLinePx < 0) ind[\"w:hanging\"] = pxToTwips(-style.indentFirstLinePx);\r\n if (Object.keys(ind).length > 0) c.push(el(\"w:ind\", ind));\r\n c.push(el(\"w:jc\", { \"w:val\": JC[style.align] }));\r\n if (style.tabStops && style.tabStops.length > 0) {\r\n const tabs = style.tabStops\r\n .map((t) =>\r\n el(\"w:tab\", {\r\n \"w:val\": t.align ? (TAB_VAL[t.align] ?? \"left\") : \"left\",\r\n \"w:pos\": pxToTwips(t.posPx),\r\n \"w:leader\": t.leader && t.leader !== \"none\" ? TAB_LEADER[t.leader] : undefined,\r\n }),\r\n )\r\n .join(\"\");\r\n c.push(el(\"w:tabs\", undefined, tabs));\r\n }\r\n return c.join(\"\");\r\n}\r\n\r\nexport function partialRPrXml(c: Partial<CharStyle>): string {\r\n const out: string[] = [];\r\n if (c.fontFamily) {\r\n const fam = (c.fontFamily.split(\",\")[0] ?? \"\").trim();\r\n if (fam) out.push(el(\"w:rFonts\", { \"w:ascii\": fam, \"w:hAnsi\": fam, \"w:cs\": fam }));\r\n }\r\n if (c.bold !== undefined) out.push(el(\"w:b\", { \"w:val\": c.bold ? \"1\" : \"0\" }));\r\n if (c.italic !== undefined) out.push(el(\"w:i\", { \"w:val\": c.italic ? \"1\" : \"0\" }));\r\n if (c.strikethrough !== undefined) out.push(el(\"w:strike\", { \"w:val\": c.strikethrough ? \"1\" : \"0\" }));\r\n if (c.color) out.push(el(\"w:color\", { \"w:val\": hex(c.color) }));\r\n if (c.fontSizePx !== undefined) {\r\n const sz = Math.round(c.fontSizePx * 1.5);\r\n out.push(el(\"w:sz\", { \"w:val\": sz }));\r\n out.push(el(\"w:szCs\", { \"w:val\": sz }));\r\n }\r\n if (c.underline !== undefined) out.push(el(\"w:u\", { \"w:val\": c.underline ? \"single\" : \"none\" }));\r\n if (c.highlightColor) {\r\n const name = HIGHLIGHT_NAME[c.highlightColor.toLowerCase()];\r\n if (name) out.push(el(\"w:highlight\", { \"w:val\": name }));\r\n }\r\n if (c.verticalAlign) out.push(el(\"w:vertAlign\", { \"w:val\": c.verticalAlign === \"super\" ? \"superscript\" : \"subscript\" }));\r\n return out.length > 0 ? el(\"w:rPr\", undefined, out.join(\"\")) : \"\";\r\n}\r\n\r\nexport function partialPPrXml(p: Partial<ParaStyle>): string {\r\n const out: string[] = [];\r\n if (p.align) out.push(el(\"w:jc\", { \"w:val\": JC[p.align] ?? \"left\" }));\r\n const sp: Record<string, number | string> = {};\r\n if (p.spaceBeforePx !== undefined) sp[\"w:before\"] = pxToTwips(p.spaceBeforePx);\r\n if (p.spaceAfterPx !== undefined) sp[\"w:after\"] = pxToTwips(p.spaceAfterPx);\r\n if (p.lineHeight !== undefined) {\r\n sp[\"w:line\"] = multiplierToLine(p.lineHeight);\r\n sp[\"w:lineRule\"] = \"auto\";\r\n }\r\n if (Object.keys(sp).length > 0) out.push(el(\"w:spacing\", sp));\r\n const ind: Record<string, number> = {};\r\n if (p.indentLeftPx !== undefined) ind[\"w:left\"] = pxToTwips(p.indentLeftPx);\r\n if (p.indentRightPx !== undefined) ind[\"w:right\"] = pxToTwips(p.indentRightPx);\r\n if (p.indentFirstLinePx !== undefined) {\r\n if (p.indentFirstLinePx >= 0) ind[\"w:firstLine\"] = pxToTwips(p.indentFirstLinePx);\r\n else ind[\"w:hanging\"] = pxToTwips(-p.indentFirstLinePx);\r\n }\r\n if (Object.keys(ind).length > 0) out.push(el(\"w:ind\", ind));\r\n if (p.keepWithNext) out.push(el(\"w:keepNext\"));\r\n if (p.keepLinesTogether) out.push(el(\"w:keepLines\"));\r\n if (p.tabStops && p.tabStops.length > 0) {\r\n const tabs = p.tabStops\r\n .map((t) =>\r\n el(\"w:tab\", {\r\n \"w:val\": t.align ? (TAB_VAL[t.align] ?? \"left\") : \"left\",\r\n \"w:pos\": pxToTwips(t.posPx),\r\n \"w:leader\": t.leader && t.leader !== \"none\" ? TAB_LEADER[t.leader] : undefined,\r\n }),\r\n )\r\n .join(\"\");\r\n out.push(el(\"w:tabs\", undefined, tabs));\r\n }\r\n return out.length > 0 ? el(\"w:pPr\", undefined, out.join(\"\")) : \"\";\r\n}\r\n\n// ---------------------------------------------------------------------------\n// Table styles \u2192 w:style[@w:type=\"table\"] with conditional formatting.\n\nfunction condBordersXml(tag: string, b: CellBorders): string {\n const edge = (name: string, spec: CellBorders[\"top\"]): string => {\n if (!spec) return \"\";\n const val = spec.style === \"double\" ? \"double\" : spec.style === \"dashed\" ? \"dashed\" : spec.style === \"dotted\" ? \"dotted\" : \"single\";\n return el(\"w:\" + name, { \"w:val\": val, \"w:sz\": pxToEighthPoints(spec.widthPx), \"w:space\": 0, \"w:color\": hex(spec.color) });\n };\n return el(tag, undefined, edge(\"top\", b.top) + edge(\"left\", b.left) + edge(\"bottom\", b.bottom) + edge(\"right\", b.right));\n}\n\nconst shdFillXml = (fill: string): string => el(\"w:shd\", { \"w:val\": \"clear\", \"w:color\": \"auto\", \"w:fill\": hex(fill) });\n\nfunction tblStylePrXml(cond: TableCond, props: TableCondProps): string {\n const tc: string[] = [];\n if (props.borders) tc.push(condBordersXml(\"w:tcBorders\", props.borders));\n if (props.shading) tc.push(shdFillXml(props.shading));\n const tcPr = tc.length > 0 ? el(\"w:tcPr\", undefined, tc.join(\"\")) : \"\";\n return el(\"w:tblStylePr\", { \"w:type\": cond }, partialRPrXml(props.char ?? {}) + partialPPrXml(props.para ?? {}) + tcPr);\n}\n\n/** One table style. Base (wholeTable) \u2192 rPr/pPr + tblPr(borders/shd/band sizes);\n * each other condition \u2192 a w:tblStylePr. */\nexport function tableStyleXml(style: TableStyle): string {\n const base = style.conds.wholeTable ?? {};\n const tblPrKids: string[] = [];\n if (style.rowBandSize !== undefined) tblPrKids.push(el(\"w:tblStyleRowBandSize\", { \"w:val\": style.rowBandSize }));\n if (style.colBandSize !== undefined) tblPrKids.push(el(\"w:tblStyleColBandSize\", { \"w:val\": style.colBandSize }));\n if (base.borders) tblPrKids.push(condBordersXml(\"w:tblBorders\", base.borders));\n if (base.shading) tblPrKids.push(shdFillXml(base.shading));\n const tblPr = tblPrKids.length > 0 ? el(\"w:tblPr\", undefined, tblPrKids.join(\"\")) : \"\";\n const conds = (Object.entries(style.conds) as [TableCond, TableCondProps][])\n .filter(([c]) => c !== \"wholeTable\")\n .map(([c, p]) => tblStylePrXml(c, p))\n .join(\"\");\n const body =\n el(\"w:name\", { \"w:val\": style.name }) +\n (style.basedOn ? el(\"w:basedOn\", { \"w:val\": style.basedOn }) : \"\") +\n partialRPrXml(base.char ?? {}) +\n partialPPrXml(base.para ?? {}) +\n tblPr +\n conds;\n return el(\"w:style\", { \"w:type\": \"table\", \"w:styleId\": style.id }, body);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
FONT_FILES,
|
|
9
9
|
cloneFamilyFor,
|
|
10
10
|
setMeasureContext
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-5RX3IHWE.js";
|
|
12
12
|
import {
|
|
13
13
|
__commonJS,
|
|
14
14
|
__esm,
|
|
@@ -140911,4 +140911,4 @@ export {
|
|
|
140911
140911
|
resolveFont,
|
|
140912
140912
|
installMeasureHost
|
|
140913
140913
|
};
|
|
140914
|
-
//# sourceMappingURL=chunk-
|
|
140914
|
+
//# sourceMappingURL=chunk-HWQKGDS2.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/import/docx/types.ts", "../../node_modules/txml/dist/txml.mjs", "../src/import/docx/xml.ts", "../src/import/docx/contentTypes.ts"],
|
|
4
|
+
"sourcesContent": ["// .docx import \u2014 shared types.\r\n//\r\n// The pipeline is: zip \u2192 XML parts \u2192 IR (intermediate representation) \u2192 model.\r\n// The IR is a faithful-but-minimal decode of document.xml: the parser keeps\r\n// everything it understands (even what the model can't hold yet); mapToModel\r\n// decides what survives and emits an ImportWarning for every lossy decision.\r\n\r\nimport type { Document, FieldDef } from \"@cw/shared\";\r\n\r\nexport type ImportPhase = \"unzip\" | \"styles\" | \"parse\" | \"map\";\r\n\r\nexport type ImportErrorCode = \"NOT_ZIP\" | \"ENCRYPTED\" | \"NO_DOCUMENT_PART\" | \"MALFORMED_XML\";\r\n\r\nexport class ImportError extends Error {\r\n readonly code: ImportErrorCode;\r\n constructor(code: ImportErrorCode, message: string) {\r\n super(message);\r\n this.name = \"ImportError\";\r\n this.code = code;\r\n }\r\n}\r\n\r\nexport interface ImportWarning {\r\n code: string;\r\n message: string;\r\n}\r\n\r\n/** Deduplicating warning collector \u2014 a 70-page doc with 400 tabs should say\r\n * \"tabs converted\" once, not 400 times. */\r\nexport class WarningSink {\r\n readonly list: ImportWarning[] = [];\r\n private readonly seen = new Set<string>();\r\n add(code: string, message: string): void {\r\n if (this.seen.has(code)) return;\r\n this.seen.add(code);\r\n this.list.push({ code, message });\r\n }\r\n}\r\n\r\nexport interface ImportResult {\r\n doc: Document;\r\n /** Every lossy mapping decision \u2014 surfaced, not swallowed. */\r\n warnings: ImportWarning[];\r\n /** blob: URLs created for embedded media; caller revokes when the doc is discarded. */\r\n mediaUrls: string[];\r\n /** Raw embedded image bytes, populated only when runImport is called with\r\n * { collectMediaBytes: true } \u2014 the Node/backend path, which content-addresses\r\n * them into its own media store instead of minting blob: URLs. Each `src`\r\n * matches the ImageBlock.src the mapper assigned, so the caller can swap in a\r\n * mediaId. Empty (and mediaUrls carry blob: URLs) in the browser path. */\r\n media: ImportMedia[];\r\n}\r\n\r\n/** A collected embedded image (Node/backend path). */\r\nexport interface ImportMedia {\r\n /** The synthetic src the mapper put on the ImageBlock (e.g. \"cw-media:0\"). */\r\n src: string;\r\n bytes: Uint8Array;\r\n mime: string;\r\n}\r\n\r\n/** Sink the media store routes raw image bytes to instead of creating a blob:\r\n * URL. Returns the src string to stamp on the ImageBlock. */\r\nexport interface MediaCollector {\r\n add(bytes: Uint8Array, mime: string): string;\r\n}\r\n\r\nexport interface RunImportOpts {\r\n onProgress?: (phase: ImportPhase, pct: number) => void;\r\n /** Collect raw image bytes (and skip blob: URL creation) for Node/backend\r\n * callers that content-address media themselves. */\r\n collectMediaBytes?: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Worker protocol\r\n\r\nexport interface ToWorker {\r\n id: number;\r\n buf: ArrayBuffer; // transferred, not cloned\r\n}\r\n\r\nexport type FromWorker =\r\n | { id: number; type: \"progress\"; phase: ImportPhase; pct: number }\r\n | { id: number; type: \"done\"; result: ImportResult }\r\n | { id: number; type: \"error\"; code: ImportErrorCode; message: string };\r\n\r\n// ---------------------------------------------------------------------------\r\n// IR \u2014 what documentParser produces. Units stay as OOXML units (twips,\r\n// half-points); conversion to px happens in mapToModel via units.ts.\r\n\r\n/** Direct run formatting decoded from w:rPr. Absent field = \"inherit\" \u2014\r\n * resolved through the style cascade in milestone 2, from defaults today. */\r\nexport interface IRRunProps {\r\n /** w:rStyle reference \u2014 recorded now, resolved when StyleResolver lands. */\r\n styleId?: string;\r\n bold?: boolean;\r\n italic?: boolean;\r\n underline?: boolean;\r\n strikethrough?: boolean;\r\n /** Raw w:color value: hex without '#' (\"FF0000\") or \"auto\". */\r\n color?: string;\r\n /** w:sz \u2014 half-points. */\r\n sizeHalfPoints?: number;\r\n /** w:rFonts w:ascii. */\r\n fontAscii?: string;\r\n /** w:rFonts w:asciiTheme \u2014 theme font slot (\"minorHAnsi\", \"majorHAnsi\", \u2026). */\r\n fontThemeAscii?: string;\r\n /** w:color w:themeColor \u2014 theme color slot (\"accent1\", \"text1\", \u2026). */\r\n colorTheme?: string;\r\n /** w:highlight w:val \u2014 named highlight color (\"yellow\", \"green\", \u2026). */\r\n highlight?: string;\r\n /** w:vertAlign w:val \u2014 \"superscript\" | \"subscript\" | \"baseline\". */\r\n vertAlign?: string;\r\n /** w:vanish \u2014 hidden text (Word shows it only with \u00B6 marks on). */\r\n vanish?: boolean;\r\n /** Hyperlink membership (set on runs inside a w:hyperlink). Resolved to a URL\r\n * in mapToModel: relId via the part's rels (external target), or anchor for\r\n * an in-document bookmark (kept as \"#name\"). */\r\n linkRelId?: string;\r\n linkAnchor?: string;\r\n /** w:footnoteReference w:id \u2014 this run is a footnote marker. mapToModel sets\r\n * the run text to the sequential note number and CharStyle.footnoteRef. */\r\n footnoteId?: string;\r\n}\r\n\r\n/** w:sdtPr \u2014 content-control properties, decoded faithfully (mapToModel turns\r\n * these into the model's SdtProps; runs inside the control carry the sdtId). */\r\nexport interface IRSdtProps {\r\n type: \"richText\" | \"plainText\" | \"checkbox\" | \"dropDown\" | \"comboBox\" | \"date\";\r\n alias?: string;\r\n tag?: string;\r\n /** w:showingPlcHdr \u2014 the content is currently the gray placeholder. */\r\n placeholder?: boolean;\r\n listItems?: { display: string; value: string }[];\r\n dateFormat?: string;\r\n checked?: boolean;\r\n lockContent?: boolean;\r\n lockControl?: boolean;\r\n}\r\n\r\nexport type IRInline =\r\n | { kind: \"run\"; text: string; props: IRRunProps; sdtId?: string; fieldId?: string }\r\n /** w:br / w:cr \u2014 soft line break (model has none; mapToModel splits the\r\n * paragraph). page=true for w:br w:type=\"page\" (\u2192 pageBreakBefore on the\r\n * follower); column=true for w:br w:type=\"column\" (\u2192 columnBreakBefore). */\r\n | { kind: \"break\"; page?: boolean; column?: boolean }\r\n /** w:drawing / w:pict \u2014 becomes a block-level ImageBlock (model has no inline images). */\r\n | {\r\n kind: \"image\";\r\n relId: string;\r\n widthEmu?: number;\r\n heightEmu?: number;\r\n anchored: boolean;\r\n /** For wp:anchor: square = text wraps around (maps to ImageBlock.wrap);\r\n * block = wrap mode the model can't express (none/topAndBottom). */\r\n anchorWrap?: \"square\" | \"block\";\r\n /** wp:positionH/wp:align when present. */\r\n anchorAlign?: \"left\" | \"right\" | \"center\";\r\n /** Set for wrapNone anchors (image sits behind/in-front of text, not in\r\n * the flow). Maps to ImageBlock.anchor \u2014 positioned absolutely, no flow\r\n * height, no text reflow. */\r\n anchorFloat?: {\r\n behind: boolean;\r\n offsetXEmu: number;\r\n offsetYEmu: number;\r\n relFromH: \"page\" | \"margin\" | \"column\" | \"leftMargin\" | \"rightMargin\" | \"character\";\r\n relFromV: \"page\" | \"margin\" | \"paragraph\" | \"line\" | \"topMargin\" | \"bottomMargin\";\r\n decorative?: boolean;\r\n /** wp:anchor @relativeHeight \u2014 stacking order within the layer. */\r\n z?: number;\r\n };\r\n };\r\n\r\nexport interface IRParaProps {\r\n /** w:pStyle reference \u2014 recorded now, resolved when StyleResolver lands. */\r\n styleId?: string;\r\n align?: \"left\" | \"center\" | \"right\" | \"justify\";\r\n spaceBeforeTwips?: number;\r\n spaceAfterTwips?: number;\r\n /** Multiplier \u2014 only set when lineRule is \"auto\" (or absent). */\r\n lineHeight?: number;\r\n indentLeftTwips?: number;\r\n /** w:ind/@w:right|@w:end \u2014 right-edge indent. */\r\n indentRightTwips?: number;\r\n /** Negative = hanging indent (w:hanging). */\r\n indentFirstLineTwips?: number;\r\n /** w:keepNext \u2014 maps onto ParaStyle.keepWithNext. */\r\n keepWithNext?: boolean;\r\n /** w:keepLines \u2014 maps onto ParaStyle.keepLinesTogether. */\r\n keepLinesTogether?: boolean;\r\n /** w:pPr/w:tabs \u2014 raw tab stops (pos in twips; val/leader raw OOXML names). */\r\n tabStops?: { posTwips: number; val?: string; leader?: string }[];\r\n /** w:pageBreakBefore \u2014 this paragraph starts a new page. */\r\n pageBreakBefore?: boolean;\r\n /** w:outlineLvl \u2014 0-8. Heading styles set it; drives TOC `\\u`/heading detection. */\r\n outlineLevel?: number;\r\n /** w:numPr \u2014 list membership. numId \"0\" / null = explicitly NOT a list\r\n * (overrides an inherited list from the paragraph style). */\r\n list?: { numId: string; level: number } | null;\r\n /** w:pPr/w:sectPr \u2014 this paragraph ENDS a section. \"page\" (nextPage/odd/even)\r\n * implies the following content starts a new page; \"continuous\" doesn't. */\r\n sectionBreak?: \"page\" | \"continuous\";\r\n /** The ending section's page size (twips), when its w:sectPr declares pgSz.\r\n * A \"page\" break only forces a new page when this differs from the document's\r\n * page size \u2014 geometry-preserving breaks (footer/header switches, which these\r\n * generated reports emit by the dozen) flow instead of leaving half-empty\r\n * pages, matching Word. */\r\n sectionPgSize?: { w: number; h: number };\r\n /** The ending section's margins (twips) \u2014 for a SectionPatch when geometry differs. */\r\n sectionMarginTwips?: { top: number; right: number; bottom: number; left: number };\r\n /** The ending section's newspaper columns (count > 1). */\r\n sectionColumns?: { count: number; spaceTwips?: number; sep?: boolean; cols?: { wTwips: number; spaceTwips: number }[] };\r\n /** The ending section's w:pgNumType w:start (page-number restart). */\r\n sectionPageNumberStart?: number;\r\n /** The ending section's w:pgMar header/footer band distances (twips). */\r\n sectionHeaderDistTwips?: number;\r\n sectionFooterDistTwips?: number;\r\n /** The ending section's w:pgBorders (raw, mapped downstream). */\r\n sectionPgBorders?: IRPageBorders;\r\n /** The ending section's sectPr declares its own header/footer references \u2014\r\n * when such a section is flowed (not page-broken) its bands aren't applied. */\r\n sectionHasBands?: boolean;\r\n /** w:pPr/w:rPr \u2014 the paragraph MARK's run formatting. Word styles empty\r\n * paragraphs (and the \u00B6 itself) with this; we use it for empty-run style. */\r\n markRunProps?: IRRunProps;\r\n}\r\n\r\n/** A w:bookmarkStart / w:bookmarkEnd seen while walking a paragraph: its w:id\r\n * (pairs start\u2194end, possibly across paragraphs), w:name (start only), and the\r\n * UTF-16 offset within the paragraph text where it sits. */\r\nexport interface BookmarkMarker {\r\n id: string;\r\n name?: string;\r\n kind: \"start\" | \"end\";\r\n offset: number;\r\n}\r\n\r\nexport interface IRParagraph {\r\n kind: \"paragraph\";\r\n props: IRParaProps;\r\n inlines: IRInline[];\r\n /** w:bookmarkStart names anchored in this paragraph (TOC/cross-ref heuristics). */\r\n bookmarks?: string[];\r\n /** Start/end markers with offsets \u2014 resolved to model ranges in mapToModel. */\r\n bookmarkMarkers?: BookmarkMarker[];\r\n /** Custom-field result membership \u2014 mapped onto Block.fieldId. */\r\n fieldId?: string;\r\n /** Set when this paragraph holds a `TOC` field \u2014 its verbatim instrText. Lets a\r\n * headless render anchor a freshly-built TOC at this exact block (mapToModel\r\n * records the resulting block id), instead of fragile ordinal counting. */\r\n tocField?: string;\r\n}\r\n\r\n/** One raw border edge (w:top/w:left/\u2026 inside w:tblBorders or w:tcBorders).\r\n * Kept raw (OOXML units) until mapToModel collapses the cascade to px. */\r\nexport interface IRRawBorder {\r\n /** w:val \u2014 \"single\", \"double\", \"dashed\", \"nil\"/\"none\", \u2026 */\r\n val: string;\r\n /** w:sz \u2014 eighths of a point. */\r\n sizeEighthPt?: number;\r\n /** w:color \u2014 hex without '#', or \"auto\". */\r\n color?: string;\r\n}\r\n\r\nexport interface IRBorders {\r\n top?: IRRawBorder;\r\n left?: IRRawBorder;\r\n bottom?: IRRawBorder;\r\n right?: IRRawBorder;\r\n /** Interior horizontal/vertical edges (w:tblBorders only). */\r\n insideH?: IRRawBorder;\r\n insideV?: IRRawBorder;\r\n}\r\n\r\n/** Cell margins in twips, per side. Any side may be absent (inherits the next\r\n * level of the cascade: cell \u2192 table \u2192 Word default). w:tcMar / w:tblCellMar. */\r\nexport interface IRCellMargin {\r\n top?: number;\r\n right?: number;\r\n bottom?: number;\r\n left?: number;\r\n}\r\n\r\nexport interface IRTableCell {\r\n /** Full block content: paragraphs, images (inside paragraphs), nested tables. */\r\n blocks: IRBlock[];\r\n /** w:gridSpan \u2014 columns this cell covers (1 = normal). Maps to TableCell.colSpan. */\r\n gridSpan: number;\r\n /** w:vMerge continuation \u2014 this cell is swallowed by the cell above. */\r\n vMergeContinue: boolean;\r\n /** w:tcPr/w:tcBorders. */\r\n borders?: IRBorders;\r\n /** A w:tcBorders element is present \u2014 even if empty (all edges nil/absent), the\r\n * author explicitly chose this cell's borders, so it must NOT fall back to the\r\n * renderer's default grid. */\r\n bordersSpecified?: boolean;\r\n /** w:tcPr/w:shd \u2192 CSS fill. */\r\n shd?: string;\r\n /** w:tcPr/w:tcMar \u2014 per-side inner padding override (twips). */\r\n marginTwips?: IRCellMargin;\r\n}\r\n\r\nexport interface IRTableRow {\r\n cells: IRTableCell[];\r\n}\r\n\r\nexport interface IRTable {\r\n kind: \"table\";\r\n rows: IRTableRow[];\r\n /** w:tblGrid/w:gridCol widths \u2014 become TableBlock.colFractions. */\r\n colWidthsTwips?: number[];\r\n /** w:tblPr/w:tblStyle \u2014 table style id (its borders/shd are the cascade base). */\r\n styleId?: string;\r\n /** w:tblPr/w:tblLook \u2014 which conditional bands of the table style are active. */\r\n look?: { firstRow?: boolean; lastRow?: boolean; firstCol?: boolean; lastCol?: boolean; bandRows?: boolean; bandCols?: boolean };\r\n /** w:tblPr/w:tblBorders. */\r\n borders?: IRBorders;\r\n /** A w:tblBorders element is present \u2014 even if empty, the table explicitly\r\n * declares its borders (e.g. \"no borders\"), suppressing the default grid. */\r\n bordersSpecified?: boolean;\r\n /** w:tblPr/w:shd \u2192 CSS fill applied to every cell unless overridden. */\r\n shd?: string;\r\n /** w:tblPr/w:tblCellMar \u2014 table-wide cell-margin default (twips), the base each\r\n * cell's own w:tcMar overrides per side. */\r\n cellMarginTwips?: IRCellMargin;\r\n /** Custom-field result membership \u2014 mapped onto Block.fieldId. */\r\n fieldId?: string;\r\n}\r\n\r\nexport type IRBlock = IRParagraph | IRTable;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Numbering (numbering.xml) \u2014 raw decode; mapToModel converts to model lists.\r\n\r\nexport interface IRListLevel {\r\n /** Raw w:numFmt w:val (\"decimal\", \"bullet\", \"lowerRoman\", \"none\", \u2026). */\r\n format: string;\r\n /** Raw w:lvlText w:val \u2014 \"%1.\" pattern, or the bullet glyph for bullets. */\r\n lvlText: string;\r\n start: number;\r\n indentLeftTwips?: number;\r\n hangingTwips?: number;\r\n /** w:lvl/w:rPr \u2014 marker glyph styling (esp. the bullet font). */\r\n markerRunProps?: IRRunProps;\r\n}\r\n\r\nexport interface IRListDefinition {\r\n /** numId (the id space paragraphs reference via w:numPr/w:numId). */\r\n id: string;\r\n levels: IRListLevel[];\r\n}\r\n\r\nexport interface IRSection {\r\n pageWidthTwips?: number;\r\n pageHeightTwips?: number;\r\n marginTwips?: { top: number; right: number; bottom: number; left: number };\r\n /** w:pgMar/@w:header and @w:footer \u2014 band distances from the page edges (twips). */\r\n headerDistTwips?: number;\r\n footerDistTwips?: number;\r\n /** w:headerReference / w:footerReference by type \u2014 r:id into the document\r\n * part's rels; the referenced parts are parsed separately. Variants are\r\n * gated downstream (first by w:titlePg, even by settings evenAndOdd). */\r\n headerRefs?: BandRefs;\r\n footerRefs?: BandRefs;\r\n /** w:titlePg \u2014 this section has a distinct first-page header/footer. */\r\n titlePg?: boolean;\r\n /** w:cols \u2014 newspaper columns (only count > 1 is meaningful). `sep` = a\r\n * separator line; `cols` = explicit per-column widths (w:equalWidth=\"0\"). */\r\n columns?: {\r\n count: number;\r\n spaceTwips?: number;\r\n sep?: boolean;\r\n cols?: { wTwips: number; spaceTwips: number }[];\r\n };\r\n /** w:pgNumType w:start \u2014 restart page numbering at this value. */\r\n pageNumberStart?: number;\r\n /** w:pgBorders \u2014 page border box (raw twips/eighth-points, mapped downstream). */\r\n pageBorders?: IRPageBorders;\r\n}\r\n\r\n/** w:pgBorders edge as parsed (w:sz eighth-points, w:space points). */\r\nexport interface IRPageBorderEdge {\r\n style: string;\r\n sz?: number;\r\n space?: number;\r\n color?: string;\r\n}\r\nexport interface IRPageBorders {\r\n top?: IRPageBorderEdge;\r\n right?: IRPageBorderEdge;\r\n bottom?: IRPageBorderEdge;\r\n left?: IRPageBorderEdge;\r\n offsetFrom?: \"page\" | \"text\";\r\n}\r\n\r\n/** Header/footer relationship ids by Word variant. */\r\nexport interface BandRefs {\r\n default?: string;\r\n first?: string;\r\n even?: string;\r\n}\r\n\r\nexport interface IRDocument {\r\n blocks: IRBlock[];\r\n section: IRSection | null;\r\n /** Content controls found in the body (header/footer parsing extends it). */\r\n sdts: Record<string, IRSdtProps>;\r\n /** Custom (non-built-in) complex fields captured in the body, keyed by id. */\r\n fields?: Record<string, FieldDef>;\r\n /** w:document/w:background @w:color \u2014 document-global page fill (\"RRGGBB\"). */\r\n pageColorHex?: string;\r\n}\r\n", "function t(t){return t.replace(/&(#x[0-9a-fA-F]+|#\\d+|amp|lt|gt|quot|apos);/g,function(t,r){if(\"amp\"===r)return\"&\";if(\"lt\"===r)return\"<\";if(\"gt\"===r)return\">\";if(\"quot\"===r)return'\"';if(\"apos\"===r)return\"'\";if(\"#\"===r[0]){var e=\"x\"===r[1]||\"X\"===r[1],a=parseInt(r.slice(e?2:1),e?16:10);if(!Number.isNaN(a)&&a>=0&&a<=1114111)try{return String.fromCodePoint(a)}catch(r){return t}}return t})}function r(t){return t.replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\")}function e(t){return t.replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\").replace(/\"/g,\""\").replace(/'/g,\"'\")}function a(r,e){var a=(e=e||{}).pos||0,i=!!e.keepComments,c=!!e.keepWhitespace,f=!!e.decodeEntities,s=\"<\".charCodeAt(0),u=\">\".charCodeAt(0),h=\"-\".charCodeAt(0),l=\"/\".charCodeAt(0),d=\"!\".charCodeAt(0),g=\"?\".charCodeAt(0),A=\"'\".charCodeAt(0),p='\"'.charCodeAt(0),C=\"=\".charCodeAt(0),v=\"[\".charCodeAt(0),y=\"]\".charCodeAt(0),m=\"?\".charCodeAt(0);function b(t){for(var e=[];r[a];)if(r.charCodeAt(a)==s){if(r.charCodeAt(a+1)===l){var n=a+2;if(a=r.indexOf(\">\",a),-1==r.substring(n,a).indexOf(t)){var o=r.substring(0,a).split(\"\\n\");throw new Error(\"Unexpected close tag\\nLine: \"+(o.length-1)+\"\\nColumn: \"+(o[o.length-1].length+1)+\"\\nChar: \"+r[a])}return a+1&&(a+=1),e}if(r.charCodeAt(a+1)===d){if(r.charCodeAt(a+2)==h){const t=a;for(;-1!==a&&(r.charCodeAt(a)!==u||r.charCodeAt(a-1)!=h||r.charCodeAt(a-2)!=h||-1==a);)a=r.indexOf(\">\",a+1);-1===a&&(a=r.length),i&&e.push(r.substring(t,a+1))}else{if(r.charCodeAt(a+2)===v&&r.charCodeAt(a+8)===v&&\"cdata\"===r.substr(a+3,5).toLowerCase()){var f=r.indexOf(\"]]>\",a);-1==f?(e.push(r.substr(a+9)),a=r.length):(e.push(r.substring(a+9,f)),a=f+3);continue}{const t=a+1;a+=2;for(var g=!1;(r.charCodeAt(a)!==u||!0===g)&&r[a];)r.charCodeAt(a)===v?g=!0:!0===g&&r.charCodeAt(a)===y&&(g=!1),a++;e.push(r.substring(t,a))}}a++;continue}var A=k();e.push(A)}else{var p=N();if(c)p.length>0&&e.push(p);else{var C=p.trim();C.length>0&&e.push(C)}a++}return e}function N(){var e=a;-2===(a=r.indexOf(\"<\",a)-1)&&(a=r.length);var n=r.slice(e,a+1);return f?t(n):n}var x=\"\\r\\n\\t>/= \";function O(){for(var t=a;-1===x.indexOf(r[a])&&r[a];)a++;return r.slice(t,a)}var j,E=e.selfClosingTags||e.noChildNodes||[\"img\",\"br\",\"input\",\"meta\",\"link\",\"hr\"];function k(){a++;const e=O(),n=\"?\"===e[0],i=a,o={};let c=[];for(;r[a]&&r.charCodeAt(a)!==u&&(!n||r.charCodeAt(a)!==g||r.charCodeAt(a+1)!==u);){var s=r.charCodeAt(a);if(s>64&&s<91||s>96&&s<123){for(var h=O(),d=null;32===r.charCodeAt(a)||9===r.charCodeAt(a)||10===r.charCodeAt(a)||13===r.charCodeAt(a);)a++;if(r.charCodeAt(a)===C){for(a++;32===r.charCodeAt(a)||9===r.charCodeAt(a)||10===r.charCodeAt(a)||13===r.charCodeAt(a);)a++;var v=r.charCodeAt(a);if(v===A||v===p){if(d=w(),-1===a)return{tagName:e,attributes:o,children:c}}else if(v&&v!==u){for(var y=a;r[a]&&-1===x.indexOf(r[a]);)a++;d=r.slice(y,a),f&&(d=t(d))}}o[h]=d}else a++}if(n){var N=r.slice(i,a).trim();return N.length>0&&0===Object.keys(o).length&&(c=[N]),r.charCodeAt(a)===g&&r.charCodeAt(a+1)===u?a+=2:r.charCodeAt(a)===u&&(a+=1),{tagName:e,attributes:o,children:c}}if(r.charCodeAt(a-1)!==l&&r.charCodeAt(a-1)!==m)if(\"script\"==e){var j=a+1;a=r.indexOf(\"<\\/script>\",a),c=[r.slice(j,a)],a+=9}else if(\"style\"==e){j=a+1;a=r.indexOf(\"</style>\",a),c=[r.slice(j,a)],a+=8}else-1===E.indexOf(e)?(a++,c=b(e)):a++;else a++;return{tagName:e,attributes:o,children:c}}function w(){var e=r[a],n=a+1;a=r.indexOf(e,n);var i=r.slice(n,a);return f?t(i):i}function V(){if(!e||!e.attrName||!e.attrValue)return-1;var t=new RegExp(\"\\\\s\"+e.attrName+\"\\\\s*=['\\\"]\"+e.attrValue+\"['\\\"]\").exec(r);return t?t.index:-1}if(void 0!==e.attrValue)for(e.attrName=e.attrName||\"id\",j=[];-1!==(a=V());)-1!==(a=r.lastIndexOf(\"<\",a))&&j.push(k()),r=r.substr(a),a=0;else j=e.parseNode?k():b(\"\");if(e.filter&&Array.isArray(j)&&(j=o(j,e.filter)),e.simplify){return n(Array.isArray(j)?j:[j])}return e.setPos&&\"object\"==typeof j&&!Array.isArray(j)&&(j.pos=a),j}function n(t){if(\"string\"==typeof t)return n(a(t));if(!Array.isArray(t))throw new TypeError(\"simplify() expects parsed node array or XML string\");var r={};if(!t.length)return\"\";if(1===t.length&&\"string\"==typeof t[0])return t[0];for(var e in t.forEach(function(t){if(\"object\"==typeof t){r[t.tagName]||(r[t.tagName]=[]);var e=n(t.children);r[t.tagName].push(e),Object.keys(t.attributes).length&&\"object\"==typeof e&&!Array.isArray(e)&&(e._attributes=t.attributes)}}),r)1==r[e].length&&(r[e]=r[e][0]);return r}function i(t,r={}){var e={};return t.length?1===t.length&&\"string\"==typeof t[0]?Object.keys(r).length?{_attributes:r,value:t[0]}:t[0]:(t.forEach(function(t){if(\"object\"==typeof t){e[t.tagName]||(e[t.tagName]=[]);var r=i(t.children||[],t.attributes);e[t.tagName].push(r),Object.keys(t.attributes).length&&\"object\"==typeof r&&!Array.isArray(r)&&(r._attributes=t.attributes)}}),e):e}function o(t,r,e=0,a=\"\"){var n=[];return t.forEach(function(t,i){if(\"object\"==typeof t&&r(t,i,e,a)&&n.push(t),\"object\"==typeof t&&t.children){var c=o(t.children,r,e+1,(a?a+\".\":\"\")+i+\".\"+t.tagName);n=n.concat(c)}}),n}function c(t,a){if(!t)return\"\";var n=!!(a=a||{}).encodeEntities,i=\"\";function o(t){if(t)for(var e=0;e<t.length;e++){var a=t[e];if(\"string\"==typeof a){var o=a.trim();i+=n?r(o):o}else a&&c(a)}}function c(t){if(t){for(var r in i+=\"<\"+t.tagName,t.attributes){var a=t.attributes[r];null===a?i+=\" \"+r:n?i+=\" \"+r+'=\"'+e(a.trim())+'\"':-1===a.indexOf('\"')?i+=\" \"+r+'=\"'+a.trim()+'\"':i+=\" \"+r+\"='\"+a.trim()+\"'\"}if(\"?\"!==t.tagName[0])i+=\">\",o(t.children),i+=\"</\"+t.tagName+\">\";else{if(t.children&&t.children.length){var c=t.children.filter(function(t){return\"string\"==typeof t}).join(\" \").trim();c.length>0&&(i+=\" \"+c)}i+=\"?>\"}}}return o(Array.isArray(t)?t:[t]),i}function f(t){if(Array.isArray(t)){var r=\"\";return t.forEach(function(t){r=(r+=\" \"+f(t)).trim()}),r}return\"object\"==typeof t&&null!==t?f(t.children):\" \"+t}function s(t,r,e){var i=a(t,{attrValue:r});return e?n(i):i[0]}function u(t,r,e){const i=a(t,{attrName:\"class\",attrValue:\"[a-zA-Z0-9- ]*\"+r+\"[a-zA-Z0-9- ]*\"});return e?n(i):i}function h(t){return\"string\"==typeof t}function l(t){return\"object\"==typeof t&&null!==t&&\"tagName\"in t}export{o as filter,s as getElementById,u as getElementsByClassName,l as isElementNode,h as isTextNode,a as parse,n as simplify,i as simplifyLostLess,c as stringify,f as toContentString};\n", "// txml helpers. DOMParser is window-only (not available in workers), so we use\n// txml \u2014 a tiny pure-JS parser that returns an ORDERED node tree. Order matters:\n// in document.xml, run order IS the text.\n//\n// OOXML namespace handling: prefixes (w:, a:, wp:) are technically remappable,\n// but Word always emits the conventional ones, so we match qualified names\n// directly \u2014 the same pragmatic choice docx-preview and mammoth make.\n\nimport { isElementNode, parse, type TNode } from \"txml/txml\";\nimport { ImportError } from \"./types\";\n\nexport type XmlNode = TNode;\n\n/** Parse an XML part. keepWhitespace matters: a run whose text is a single\n * space (`<w:t xml:space=\"preserve\"> </w:t>`) must not be dropped. */\nexport function parseXml(text: string, partName: string): XmlNode[] {\n try {\n return parse(text, { keepWhitespace: true, decodeEntities: true }).filter(isElementNode);\n } catch (e) {\n throw new ImportError(\n \"MALFORMED_XML\",\n `Failed to parse ${partName}: ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n}\n\n/** Top-level element by qualified name (skips the XML declaration / PIs). */\nexport function rootEl(nodes: XmlNode[], tagName: string): XmlNode | undefined {\n return nodes.find((n) => n.tagName === tagName);\n}\n\n/** Element children only (text nodes filtered out). */\nexport function children(node: XmlNode): XmlNode[] {\n return node.children.filter(isElementNode);\n}\n\n/** First child element with the given qualified name. */\nexport function el(node: XmlNode, tagName: string): XmlNode | undefined {\n return node.children.find((c): c is XmlNode => isElementNode(c) && c.tagName === tagName);\n}\n\n/** All child elements with the given qualified name. */\nexport function els(node: XmlNode, tagName: string): XmlNode[] {\n return node.children.filter((c): c is XmlNode => isElementNode(c) && c.tagName === tagName);\n}\n\n/** Attribute value by qualified name; valueless attributes read as \"\". */\nexport function attr(node: XmlNode, name: string): string | undefined {\n const v = node.attributes[name];\n return v === undefined ? undefined : (v ?? \"\");\n}\n\n/** Depth-first search for a descendant element. Used where the exact nesting\n * is deep and producer-dependent (e.g. a:blip inside w:drawing). */\nexport function findDeep(node: XmlNode, tagName: string): XmlNode | undefined {\n for (const c of node.children) {\n if (!isElementNode(c)) continue;\n if (c.tagName === tagName) return c;\n const found = findDeep(c, tagName);\n if (found) return found;\n }\n return undefined;\n}\n\n/** Concatenated text content (direct string children \u2014 w:t never nests). */\nexport function textOf(node: XmlNode): string {\n let out = \"\";\n for (const c of node.children) if (typeof c === \"string\") out += c;\n return out;\n}\n\n/** Shorthand for the ubiquitous `<w:x w:val=\"\u2026\"/>` child-element pattern. */\nexport function val(node: XmlNode, tagName: string): string | undefined {\n const child = el(node, tagName);\n return child ? attr(child, \"w:val\") : undefined;\n}\n\n/** OOXML on/off property: `<w:b/>` is on; w:val of 0/false/none/off is off. */\nexport function onOff(node: XmlNode | undefined): boolean | undefined {\n if (!node) return undefined;\n const v = attr(node, \"w:val\");\n if (v === undefined) return true;\n return ![\"0\", \"false\", \"none\", \"off\"].includes(v);\n}\n\n/** Numeric attribute (OOXML writes plain decimal integers). */\nexport function numAttr(node: XmlNode | undefined, name: string): number | undefined {\n if (!node) return undefined;\n const v = attr(node, name);\n if (v === undefined) return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n}\n", "// [Content_Types].xml \u2192 locate the main document part. Usually\n// \"word/document.xml\", but the spec allows any part name (and macro-enabled\n// .docm uses a different content type), so don't hardcode.\n\nimport { attr, children, parseXml, rootEl } from \"./xml\";\n\nconst MAIN_CONTENT_TYPES = new Set([\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\",\n \"application/vnd.ms-word.document.macroEnabled.main+xml\",\n]);\n\nexport function findMainDocumentPart(contentTypesXml: string): string | undefined {\n const types = rootEl(parseXml(contentTypesXml, \"[Content_Types].xml\"), \"Types\");\n if (!types) return undefined;\n for (const child of children(types)) {\n if (child.tagName !== \"Override\") continue;\n const ct = attr(child, \"ContentType\");\n const partName = attr(child, \"PartName\");\n if (ct && partName && MAIN_CONTENT_TYPES.has(ct)) {\n return partName.replace(/^\\//, \"\"); // OPC part names are /-rooted; zip entries aren't\n }\n }\n return undefined;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["t", "a", "r", "a", "l", "t", "e", "n", "o", "f", "g", "A", "p", "C", "i", "c", "s", "h", "d", "v", "y", "N", "j", "t", "a", "n", "t", "n"]
|
|
7
|
+
}
|
|
@@ -9,12 +9,12 @@ import {
|
|
|
9
9
|
formatListNumber,
|
|
10
10
|
isHiddenParagraph,
|
|
11
11
|
markerText
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-373K2XRY.js";
|
|
13
13
|
import {
|
|
14
14
|
charStyleToFont,
|
|
15
15
|
fontMetrics,
|
|
16
16
|
measureTextWidth
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-5RX3IHWE.js";
|
|
18
18
|
|
|
19
19
|
// ../node_modules/@chenglou/pretext/dist/generated/bidi-data.js
|
|
20
20
|
var latin1BidiTypes = [
|
|
@@ -4068,6 +4068,7 @@ function layoutTabbedSegment(p, segRuns, segStart, contentWidth, firstIndent) {
|
|
|
4068
4068
|
const out = [];
|
|
4069
4069
|
let curFrags = [];
|
|
4070
4070
|
let curLeaders = [];
|
|
4071
|
+
let curArrows = [];
|
|
4071
4072
|
let curX = firstIndent;
|
|
4072
4073
|
let maxH = 0;
|
|
4073
4074
|
let maxA = 0;
|
|
@@ -4089,10 +4090,12 @@ function layoutTabbedSegment(p, segRuns, segStart, contentWidth, firstIndent) {
|
|
|
4089
4090
|
// A tab-positioned line stays ragged (its manual x must not be re-justified);
|
|
4090
4091
|
// pure wrapped continuation lines justify normally when the paragraph does.
|
|
4091
4092
|
lastOfSegment: isLast || hasTab,
|
|
4092
|
-
...curLeaders.length > 0 ? { leaders: curLeaders } : {}
|
|
4093
|
+
...curLeaders.length > 0 ? { leaders: curLeaders } : {},
|
|
4094
|
+
...curArrows.length > 0 ? { tabArrows: curArrows } : {}
|
|
4093
4095
|
});
|
|
4094
4096
|
curFrags = [];
|
|
4095
4097
|
curLeaders = [];
|
|
4098
|
+
curArrows = [];
|
|
4096
4099
|
curX = 0;
|
|
4097
4100
|
maxH = 0;
|
|
4098
4101
|
maxA = 0;
|
|
@@ -4112,6 +4115,7 @@ function layoutTabbedSegment(p, segRuns, segStart, contentWidth, firstIndent) {
|
|
|
4112
4115
|
if ((stop.leader ?? "none") !== "none" && targetX > curX + 1 && baseStyle) {
|
|
4113
4116
|
curLeaders.push({ x1: curX, x2: targetX, kind: stop.leader ?? "none", color: baseStyle.color, fontSizePx: baseStyle.fontSizePx });
|
|
4114
4117
|
}
|
|
4118
|
+
curArrows.push({ x1: curX, x2: Math.max(targetX, curX) });
|
|
4115
4119
|
curX = targetX;
|
|
4116
4120
|
hasTab = true;
|
|
4117
4121
|
}
|
|
@@ -4164,10 +4168,13 @@ function paragraphLines(p, contentWidth, cache) {
|
|
|
4164
4168
|
const lines = [];
|
|
4165
4169
|
const raw = [];
|
|
4166
4170
|
let first = true;
|
|
4167
|
-
|
|
4171
|
+
const segLastLine = [];
|
|
4172
|
+
for (let si = 0; si < segments.length; si++) {
|
|
4173
|
+
const seg = segments[si];
|
|
4168
4174
|
if (seg.runs.some((r) => r.text.includes(" "))) {
|
|
4169
4175
|
raw.push(...layoutTabbedSegment(p, seg.runs, seg.startOffset, contentWidth, first ? p.style.indentFirstLinePx : 0));
|
|
4170
4176
|
first = false;
|
|
4177
|
+
segLastLine[si] = raw.length - 1;
|
|
4171
4178
|
continue;
|
|
4172
4179
|
}
|
|
4173
4180
|
const runStarts = segRunOffsets(seg.runs, seg.startOffset);
|
|
@@ -4208,6 +4215,13 @@ function paragraphLines(p, contentWidth, cache) {
|
|
|
4208
4215
|
} else {
|
|
4209
4216
|
raw[raw.length - 1].lastOfSegment = true;
|
|
4210
4217
|
}
|
|
4218
|
+
segLastLine[si] = raw.length - 1;
|
|
4219
|
+
}
|
|
4220
|
+
for (let si = 0; si < segLastLine.length; si++) {
|
|
4221
|
+
const idx = segLastLine[si];
|
|
4222
|
+
if (idx === void 0) continue;
|
|
4223
|
+
if (si === segments.length - 1) raw[idx].paragraphEnd = true;
|
|
4224
|
+
else raw[idx].lineBreak = true;
|
|
4211
4225
|
}
|
|
4212
4226
|
let y = 0;
|
|
4213
4227
|
for (const rl of raw) {
|
|
@@ -4222,6 +4236,11 @@ function paragraphLines(p, contentWidth, cache) {
|
|
|
4222
4236
|
if (rl.leaders && rl.leaders.length > 0) {
|
|
4223
4237
|
box.leaders = rl.leaders.map((l) => ({ ...l, x1: l.x1 + startX, x2: l.x2 + startX }));
|
|
4224
4238
|
}
|
|
4239
|
+
if (rl.tabArrows && rl.tabArrows.length > 0) {
|
|
4240
|
+
box.tabArrows = rl.tabArrows.map((a) => ({ x1: a.x1 + startX, x2: a.x2 + startX }));
|
|
4241
|
+
}
|
|
4242
|
+
if (rl.paragraphEnd) box.paragraphEnd = true;
|
|
4243
|
+
if (rl.lineBreak) box.lineBreak = true;
|
|
4225
4244
|
lines.push(box);
|
|
4226
4245
|
y += rl.height;
|
|
4227
4246
|
}
|
|
@@ -4244,6 +4263,10 @@ function effectiveSection(base, patch) {
|
|
|
4244
4263
|
if (headerDist !== void 0) out.headerDistancePx = headerDist;
|
|
4245
4264
|
const footerDist = patch.footerDistancePx ?? base.footerDistancePx;
|
|
4246
4265
|
if (footerDist !== void 0) out.footerDistancePx = footerDist;
|
|
4266
|
+
const pageColorHex = patch.pageColorHex ?? base.pageColorHex;
|
|
4267
|
+
if (pageColorHex !== void 0) out.pageColorHex = pageColorHex;
|
|
4268
|
+
const pageBorders = patch.pageBorders ?? base.pageBorders;
|
|
4269
|
+
if (pageBorders !== void 0) out.pageBorders = pageBorders;
|
|
4247
4270
|
for (const key of BAND_KEYS) {
|
|
4248
4271
|
const blocks = patch[key] ?? base[key];
|
|
4249
4272
|
if (blocks) out[key] = blocks;
|
|
@@ -4321,8 +4344,9 @@ function layoutDocument(doc, getLines, getPrepared, rawBand) {
|
|
|
4321
4344
|
let contentBottom = 0;
|
|
4322
4345
|
let contentWidth = 0;
|
|
4323
4346
|
let colCount = 1;
|
|
4324
|
-
let colGap = 0;
|
|
4325
4347
|
let colWidth = 0;
|
|
4348
|
+
let colBoxes = [];
|
|
4349
|
+
let colSeparatorsX = [];
|
|
4326
4350
|
const applySection = (props) => {
|
|
4327
4351
|
sec = props;
|
|
4328
4352
|
const box = contentBoxOf(sec);
|
|
@@ -4331,8 +4355,27 @@ function layoutDocument(doc, getLines, getPrepared, rawBand) {
|
|
|
4331
4355
|
contentBottom = box.bottom;
|
|
4332
4356
|
contentWidth = sec.pageWidthPx - sec.marginPx.left - sec.marginPx.right;
|
|
4333
4357
|
colCount = Math.max(1, sec.columns?.count ?? 1);
|
|
4334
|
-
|
|
4335
|
-
|
|
4358
|
+
const gap = sec.columns?.gapPx ?? 24;
|
|
4359
|
+
const cols = sec.columns?.cols;
|
|
4360
|
+
if (colCount > 1 && cols && cols.length === colCount) {
|
|
4361
|
+
let x = contentX;
|
|
4362
|
+
colBoxes = cols.map((c, i) => {
|
|
4363
|
+
const b = { x, width: c.widthPx };
|
|
4364
|
+
x += c.widthPx + (i < colCount - 1 ? c.spaceAfterPx : 0);
|
|
4365
|
+
return b;
|
|
4366
|
+
});
|
|
4367
|
+
colWidth = Math.min(...cols.map((c) => c.widthPx));
|
|
4368
|
+
} else if (colCount > 1) {
|
|
4369
|
+
colWidth = (contentWidth - (colCount - 1) * gap) / colCount;
|
|
4370
|
+
colBoxes = Array.from({ length: colCount }, (_, i) => ({
|
|
4371
|
+
x: contentX + i * (colWidth + gap),
|
|
4372
|
+
width: colWidth
|
|
4373
|
+
}));
|
|
4374
|
+
} else {
|
|
4375
|
+
colWidth = contentWidth;
|
|
4376
|
+
colBoxes = [{ x: contentX, width: contentWidth }];
|
|
4377
|
+
}
|
|
4378
|
+
colSeparatorsX = sec.columns?.sep ? colBoxes.slice(0, -1).map((b, i) => (b.x + b.width + colBoxes[i + 1].x) / 2) : [];
|
|
4336
4379
|
};
|
|
4337
4380
|
applySection(sec);
|
|
4338
4381
|
const lists = doc.lists ?? {};
|
|
@@ -4400,7 +4443,7 @@ function layoutDocument(doc, getLines, getPrepared, rawBand) {
|
|
|
4400
4443
|
const pageSections = [];
|
|
4401
4444
|
const mkPage = () => {
|
|
4402
4445
|
pageSections.push(sec);
|
|
4403
|
-
|
|
4446
|
+
const p = {
|
|
4404
4447
|
index: pageSections.length - 1,
|
|
4405
4448
|
number: pageSections.length,
|
|
4406
4449
|
// provisional; the post-pass sets the real value
|
|
@@ -4411,6 +4454,10 @@ function layoutDocument(doc, getLines, getPrepared, rawBand) {
|
|
|
4411
4454
|
contentTopPx: contentTop,
|
|
4412
4455
|
contentBottomPx: contentBottom
|
|
4413
4456
|
};
|
|
4457
|
+
if (sec.pageColorHex !== void 0) p.pageColorHex = sec.pageColorHex;
|
|
4458
|
+
if (sec.pageBorders !== void 0) p.pageBorders = sec.pageBorders;
|
|
4459
|
+
if (colSeparatorsX.length) p.columnSeparatorsX = colSeparatorsX.slice();
|
|
4460
|
+
return p;
|
|
4414
4461
|
};
|
|
4415
4462
|
const pages = [mkPage()];
|
|
4416
4463
|
let page = pages[0];
|
|
@@ -4450,7 +4497,7 @@ function layoutDocument(doc, getLines, getPrepared, rawBand) {
|
|
|
4450
4497
|
};
|
|
4451
4498
|
let colIdx = 0;
|
|
4452
4499
|
let colStartCount = 0;
|
|
4453
|
-
const colX = () =>
|
|
4500
|
+
const colX = () => colBoxes[colIdx]?.x ?? contentX;
|
|
4454
4501
|
const colHasContent = () => page.blocks.length > colStartCount;
|
|
4455
4502
|
const hardPage = () => {
|
|
4456
4503
|
colIdx = 0;
|
|
@@ -4480,6 +4527,12 @@ function layoutDocument(doc, getLines, getPrepared, rawBand) {
|
|
|
4480
4527
|
page.marginPx = sec.marginPx;
|
|
4481
4528
|
page.contentTopPx = contentTop;
|
|
4482
4529
|
page.contentBottomPx = contentBottom;
|
|
4530
|
+
if (sec.pageColorHex !== void 0) page.pageColorHex = sec.pageColorHex;
|
|
4531
|
+
else delete page.pageColorHex;
|
|
4532
|
+
if (sec.pageBorders !== void 0) page.pageBorders = sec.pageBorders;
|
|
4533
|
+
else delete page.pageBorders;
|
|
4534
|
+
if (colSeparatorsX.length) page.columnSeparatorsX = colSeparatorsX.slice();
|
|
4535
|
+
else delete page.columnSeparatorsX;
|
|
4483
4536
|
pageSections[page.index] = sec;
|
|
4484
4537
|
colIdx = 0;
|
|
4485
4538
|
colStartCount = 0;
|
|
@@ -4929,10 +4982,13 @@ function layoutDocument(doc, getLines, getPrepared, rawBand) {
|
|
|
4929
4982
|
}
|
|
4930
4983
|
}
|
|
4931
4984
|
}
|
|
4932
|
-
|
|
4933
|
-
|
|
4985
|
+
const reorderAnchoredLayers = (blocks) => {
|
|
4986
|
+
for (const b of blocks) {
|
|
4987
|
+
if (b.table) for (const row of b.table.rows) for (const cell of row.cells) cell.blocks = reorderAnchoredLayers(cell.blocks);
|
|
4988
|
+
}
|
|
4989
|
+
if (!blocks.some((b) => b.image?.behind || b.image?.front)) return blocks;
|
|
4934
4990
|
const layer = (b) => b.image?.behind ? 0 : b.image?.front ? 2 : 1;
|
|
4935
|
-
|
|
4991
|
+
return blocks.map((b, i) => ({ b, i })).sort((p, q) => {
|
|
4936
4992
|
const dl = layer(p.b) - layer(q.b);
|
|
4937
4993
|
if (dl !== 0) return dl;
|
|
4938
4994
|
if (layer(p.b) !== 1) {
|
|
@@ -4941,7 +4997,8 @@ function layoutDocument(doc, getLines, getPrepared, rawBand) {
|
|
|
4941
4997
|
}
|
|
4942
4998
|
return p.i - q.i;
|
|
4943
4999
|
}).map((x) => x.b);
|
|
4944
|
-
}
|
|
5000
|
+
};
|
|
5001
|
+
for (const pg of pages) pg.blocks = reorderAnchoredLayers(pg.blocks);
|
|
4945
5002
|
const pageNumbers = [];
|
|
4946
5003
|
{
|
|
4947
5004
|
let n = 0;
|
|
@@ -5173,6 +5230,7 @@ function measureTable(t, contentWidth, getLines, listCtx) {
|
|
|
5173
5230
|
return { kind: "para", block: b, lines };
|
|
5174
5231
|
}
|
|
5175
5232
|
if (b.kind === "image") {
|
|
5233
|
+
if (b.anchor) return { kind: "image", block: b, width: b.widthPx, height: b.heightPx };
|
|
5176
5234
|
const scale = Math.min(1, innerWidth / Math.max(1, b.widthPx));
|
|
5177
5235
|
const w = b.widthPx * scale;
|
|
5178
5236
|
const ih = b.heightPx * scale;
|
|
@@ -5243,6 +5301,26 @@ function placeTable(t, rows, colWidths, x, y, width, firstRowIndex, listCtx) {
|
|
|
5243
5301
|
blocks.push(placedPara);
|
|
5244
5302
|
py += totalLinesHeight(it.lines) + it.block.style.spaceAfterPx;
|
|
5245
5303
|
} else if (it.kind === "image") {
|
|
5304
|
+
const anchor = it.block.anchor;
|
|
5305
|
+
if (anchor) {
|
|
5306
|
+
const placedImage = {
|
|
5307
|
+
src: it.block.src,
|
|
5308
|
+
width: it.block.widthPx,
|
|
5309
|
+
height: it.block.heightPx,
|
|
5310
|
+
z: anchor.z ?? 0
|
|
5311
|
+
};
|
|
5312
|
+
if (anchor.behind) placedImage.behind = true;
|
|
5313
|
+
else placedImage.front = true;
|
|
5314
|
+
blocks.push({
|
|
5315
|
+
blockId: it.block.id,
|
|
5316
|
+
x: cx + mgn.left + anchor.offsetXPx,
|
|
5317
|
+
y: ry + mgn.top + anchor.offsetYPx,
|
|
5318
|
+
firstLineIndex: 0,
|
|
5319
|
+
lines: [],
|
|
5320
|
+
image: placedImage
|
|
5321
|
+
});
|
|
5322
|
+
continue;
|
|
5323
|
+
}
|
|
5246
5324
|
const innerH = cellHeight - mgn.top - mgn.bottom;
|
|
5247
5325
|
if (mc.items.length === 1 && innerH > it.height + 8) {
|
|
5248
5326
|
const scale = Math.max(innerWidth / it.block.widthPx, innerH / it.block.heightPx);
|
|
@@ -5311,4 +5389,4 @@ export {
|
|
|
5311
5389
|
effectiveSection,
|
|
5312
5390
|
resolveSections
|
|
5313
5391
|
};
|
|
5314
|
-
//# sourceMappingURL=chunk-
|
|
5392
|
+
//# sourceMappingURL=chunk-ZLLSXOO2.js.map
|