@extend-ai/react-docx 0.8.3 → 0.9.0

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/index.cjs CHANGED
@@ -1384,6 +1384,7 @@ __export(index_exports, {
1384
1384
  collectTableExplicitPageBreakInfo: () => collectTableExplicitPageBreakInfo2,
1385
1385
  collectTopLevelExplicitPageBreakStartNodeIndexes: () => collectTopLevelExplicitPageBreakStartNodeIndexes2,
1386
1386
  copyParagraphs: () => copyParagraphs,
1387
+ createDocxThumbnailRenderer: () => createDocxThumbnailRenderer,
1387
1388
  createMinimalDocxPackage: () => createMinimalDocxPackage,
1388
1389
  createParagraphComment: () => createParagraphComment,
1389
1390
  deepFreezeDocModel: () => deepFreezeDocModel,
@@ -1406,6 +1407,7 @@ __export(index_exports, {
1406
1407
  paragraphLetterheadFloatSideAtNodeIndex: () => paragraphLetterheadFloatSideAtNodeIndex,
1407
1408
  paragraphStartsWithLastRenderedPageBreak: () => paragraphStartsWithLastRenderedPageBreak2,
1408
1409
  parseDocx: () => parseDocx,
1410
+ parseDocxForViewer: () => parseDocxForViewer,
1409
1411
  parseParagraphsFromClipboard: () => parseParagraphsFromClipboard,
1410
1412
  parseSectionLayout: () => parseSectionLayout,
1411
1413
  pasteParagraphs: () => pasteParagraphs,
@@ -1461,6 +1463,7 @@ __export(index_exports, {
1461
1463
  module.exports = __toCommonJS(index_exports);
1462
1464
  init_cjs_shims();
1463
1465
  var React2 = __toESM(require("react"), 1);
1466
+ var import_react_dom2 = require("react-dom");
1464
1467
 
1465
1468
  // ../layout-engine/src/index.ts
1466
1469
  init_cjs_shims();
@@ -1885,532 +1888,6 @@ async function importDocxBuffer(buffer, options = {}) {
1885
1888
  return result;
1886
1889
  }
1887
1890
 
1888
- // src/section-layout.ts
1889
- init_cjs_shims();
1890
- var DEFAULT_DOC_PAGE_WIDTH = 900;
1891
- var DEFAULT_DOC_PAGE_HEIGHT = 1200;
1892
- var DEFAULT_DOC_PAGE_MARGIN = 56;
1893
- var TWIPS_PER_PIXEL = 15;
1894
- var DEFAULT_DOCUMENT_LAYOUT = {
1895
- pageWidthPx: DEFAULT_DOC_PAGE_WIDTH,
1896
- pageHeightPx: DEFAULT_DOC_PAGE_HEIGHT,
1897
- marginsPx: {
1898
- top: DEFAULT_DOC_PAGE_MARGIN,
1899
- right: DEFAULT_DOC_PAGE_MARGIN,
1900
- bottom: DEFAULT_DOC_PAGE_MARGIN,
1901
- left: DEFAULT_DOC_PAGE_MARGIN
1902
- },
1903
- headerDistancePx: DEFAULT_DOC_PAGE_MARGIN,
1904
- footerDistancePx: DEFAULT_DOC_PAGE_MARGIN,
1905
- docGridLinePitchPx: void 0
1906
- };
1907
- function pageMarginPaddingStyle(marginsPx) {
1908
- return {
1909
- paddingTop: marginsPx.top,
1910
- paddingRight: marginsPx.right,
1911
- paddingBottom: marginsPx.bottom,
1912
- paddingLeft: marginsPx.left
1913
- };
1914
- }
1915
- function twipsToPixels(twips) {
1916
- if (!Number.isFinite(twips)) {
1917
- return void 0;
1918
- }
1919
- return Math.max(0, Math.round(twips / TWIPS_PER_PIXEL));
1920
- }
1921
- function readTwipsAttribute(tagXml, attribute) {
1922
- if (!tagXml) {
1923
- return void 0;
1924
- }
1925
- const match = tagXml.match(new RegExp(`${attribute}="(\\d+)"`, "i"));
1926
- if (!match?.[1]) {
1927
- return void 0;
1928
- }
1929
- const parsed = Number(match[1]);
1930
- return Number.isFinite(parsed) ? parsed : void 0;
1931
- }
1932
- function readStringAttribute(tagXml, attribute) {
1933
- if (!tagXml) {
1934
- return void 0;
1935
- }
1936
- return tagXml.match(new RegExp(`${attribute}="([^"]+)"`, "i"))?.[1];
1937
- }
1938
- function resolvePageSizeForOrientation(params) {
1939
- const normalizedOrientation = params.orientation?.trim().toLowerCase();
1940
- const widthPx = Math.max(1, params.widthPx);
1941
- const heightPx = Math.max(1, params.heightPx);
1942
- if (normalizedOrientation === "landscape" && widthPx < heightPx) {
1943
- return { widthPx: heightPx, heightPx: widthPx };
1944
- }
1945
- if (normalizedOrientation === "portrait" && widthPx > heightPx) {
1946
- return { widthPx: heightPx, heightPx: widthPx };
1947
- }
1948
- return { widthPx, heightPx };
1949
- }
1950
- function normalizeHexColor(value) {
1951
- if (!value) {
1952
- return void 0;
1953
- }
1954
- const normalized = value.trim();
1955
- if (!normalized || normalized.toLowerCase() === "auto") {
1956
- return void 0;
1957
- }
1958
- if (/^[0-9a-fA-F]{6}$/.test(normalized)) {
1959
- return `#${normalized}`;
1960
- }
1961
- if (/^#[0-9a-fA-F]{6}$/.test(normalized)) {
1962
- return normalized;
1963
- }
1964
- return void 0;
1965
- }
1966
- function borderTypeToCssStyle(rawType) {
1967
- const value = rawType?.trim().toLowerCase();
1968
- if (!value || value === "none" || value === "nil") {
1969
- return void 0;
1970
- }
1971
- if (value === "double") {
1972
- return "double";
1973
- }
1974
- if (value === "dashed" || value === "dashsmallgap" || value === "dotdash" || value === "dotdotdash") {
1975
- return "dashed";
1976
- }
1977
- if (value === "dotted") {
1978
- return "dotted";
1979
- }
1980
- return "solid";
1981
- }
1982
- function pointsToPixels(points) {
1983
- if (!Number.isFinite(points)) {
1984
- return void 0;
1985
- }
1986
- return Math.max(0, Math.round(points * (96 / 72)));
1987
- }
1988
- function parseSectionPageBorderEdge(sectionPropertiesXml, edge) {
1989
- if (!sectionPropertiesXml) {
1990
- return void 0;
1991
- }
1992
- const bordersXml = sectionPropertiesXml.match(
1993
- /<w:pgBorders\b[\s\S]*?<\/w:pgBorders>/i
1994
- )?.[0];
1995
- if (!bordersXml) {
1996
- return void 0;
1997
- }
1998
- const edgeTag = bordersXml.match(new RegExp(`<w:${edge}\\b[^>]*/?>`, "i"))?.[0];
1999
- if (!edgeTag) {
2000
- return void 0;
2001
- }
2002
- const cssStyle = borderTypeToCssStyle(readStringAttribute(edgeTag, "w:val"));
2003
- if (!cssStyle) {
2004
- return void 0;
2005
- }
2006
- const sizeEighthPt = Number(readStringAttribute(edgeTag, "w:sz"));
2007
- const widthPx = Number.isFinite(sizeEighthPt) && sizeEighthPt > 0 ? Math.max(0.5, Number((sizeEighthPt / 6).toFixed(2))) : 1;
2008
- const color = normalizeHexColor(readStringAttribute(edgeTag, "w:color")) ?? "#000000";
2009
- const offsetPoints = Number(readStringAttribute(edgeTag, "w:space"));
2010
- return {
2011
- cssBorder: `${widthPx}px ${cssStyle} ${color}`,
2012
- offsetPx: pointsToPixels(offsetPoints) ?? 0,
2013
- shadow: readStringAttribute(edgeTag, "w:shadow")?.trim().toLowerCase() === "1" || readStringAttribute(edgeTag, "w:shadow")?.trim().toLowerCase() === "true"
2014
- };
2015
- }
2016
- function parseSectionPageBorders(sectionPropertiesXml) {
2017
- if (!sectionPropertiesXml || !/<w:pgBorders\b/i.test(sectionPropertiesXml)) {
2018
- return void 0;
2019
- }
2020
- const borders = {
2021
- top: parseSectionPageBorderEdge(sectionPropertiesXml, "top"),
2022
- right: parseSectionPageBorderEdge(sectionPropertiesXml, "right"),
2023
- bottom: parseSectionPageBorderEdge(sectionPropertiesXml, "bottom"),
2024
- left: parseSectionPageBorderEdge(sectionPropertiesXml, "left")
2025
- };
2026
- return borders.top || borders.right || borders.bottom || borders.left ? borders : void 0;
2027
- }
2028
- function parseSectionLayout(sectionPropertiesXml) {
2029
- if (!sectionPropertiesXml) {
2030
- return DEFAULT_DOCUMENT_LAYOUT;
2031
- }
2032
- const pageSizeTag = sectionPropertiesXml.match(/<w:pgSz\b[^>]*>/i)?.[0];
2033
- const pageMarginTag = sectionPropertiesXml.match(/<w:pgMar\b[^>]*>/i)?.[0];
2034
- const docGridTag = sectionPropertiesXml.match(/<w:docGrid\b[^>]*\/?>/i)?.[0];
2035
- const rawPageWidthPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:w")) ?? DEFAULT_DOCUMENT_LAYOUT.pageWidthPx;
2036
- const rawPageHeightPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:h")) ?? DEFAULT_DOCUMENT_LAYOUT.pageHeightPx;
2037
- const pageSize = resolvePageSizeForOrientation({
2038
- widthPx: rawPageWidthPx,
2039
- heightPx: rawPageHeightPx,
2040
- orientation: readStringAttribute(pageSizeTag, "w:orient")
2041
- });
2042
- const topMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:top")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.top;
2043
- const rightMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:right")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.right;
2044
- const bottomMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:bottom")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.bottom;
2045
- const leftMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:left")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.left;
2046
- const headerDistancePx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:header")) ?? DEFAULT_DOCUMENT_LAYOUT.headerDistancePx;
2047
- const footerDistancePx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:footer")) ?? DEFAULT_DOCUMENT_LAYOUT.footerDistancePx;
2048
- const docGridType = readStringAttribute(docGridTag, "w:type")?.toLowerCase();
2049
- const docGridLinePitchPx = docGridType === "lines" || docGridType === "linesandchars" || docGridType === "snaptochars" ? twipsToPixels(readTwipsAttribute(docGridTag, "w:linePitch")) ?? DEFAULT_DOCUMENT_LAYOUT.docGridLinePitchPx : DEFAULT_DOCUMENT_LAYOUT.docGridLinePitchPx;
2050
- return {
2051
- pageWidthPx: pageSize.widthPx,
2052
- pageHeightPx: pageSize.heightPx,
2053
- marginsPx: {
2054
- top: topMarginPx,
2055
- right: rightMarginPx,
2056
- bottom: bottomMarginPx,
2057
- left: leftMarginPx
2058
- },
2059
- headerDistancePx,
2060
- footerDistancePx,
2061
- docGridLinePitchPx
2062
- };
2063
- }
2064
- function resolveDocumentSectionPropertiesXml(model) {
2065
- return model.metadata.sections?.[0]?.sectionPropertiesXml ?? model.metadata.sectionPropertiesXml;
2066
- }
2067
- function resolveDocumentLayout(model) {
2068
- return parseSectionLayout(resolveDocumentSectionPropertiesXml(model));
2069
- }
2070
-
2071
- // src/image-render.ts
2072
- init_cjs_shims();
2073
- var import_fast_png = require("fast-png");
2074
- var import_utif = __toESM(require("utif"), 1);
2075
- var TIFF_CONTENT_TYPES = /* @__PURE__ */ new Set(["image/tiff", "image/tif"]);
2076
- var PLACEHOLDER_FALLBACK_CONTENT_TYPES = /* @__PURE__ */ new Set([
2077
- "image/x-emf",
2078
- "image/emf",
2079
- "image/x-wmf",
2080
- "image/wmf"
2081
- ]);
2082
- var TIFF_DATA_URI_PREFIXES = ["data:image/tiff", "data:image/tif"];
2083
- var EMF_DATA_URI_PREFIXES = ["data:image/emf", "data:image/x-emf"];
2084
- var WMF_DATA_URI_PREFIXES = ["data:image/wmf", "data:image/x-wmf"];
2085
- var UTIF = import_utif.default;
2086
- var convertedTiffSrcCache = /* @__PURE__ */ new Map();
2087
- function normalizeImageContentType(image) {
2088
- return image.contentType?.trim().toLowerCase();
2089
- }
2090
- function normalizeImageSrc(image) {
2091
- return image.src?.trim();
2092
- }
2093
- function imageHasTiffContent(image) {
2094
- const contentType = normalizeImageContentType(image);
2095
- if (contentType && TIFF_CONTENT_TYPES.has(contentType)) {
2096
- return true;
2097
- }
2098
- const src = normalizeImageSrc(image)?.toLowerCase();
2099
- return Boolean(src && TIFF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)));
2100
- }
2101
- function imageHasMetafileContent(image) {
2102
- const contentType = normalizeImageContentType(image);
2103
- if (contentType && PLACEHOLDER_FALLBACK_CONTENT_TYPES.has(contentType)) {
2104
- return true;
2105
- }
2106
- const src = normalizeImageSrc(image)?.toLowerCase();
2107
- return Boolean(
2108
- src && (EMF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)) || WMF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)))
2109
- );
2110
- }
2111
- function imageUsesEmfContent(image) {
2112
- const contentType = normalizeImageContentType(image);
2113
- if (contentType === "image/x-emf" || contentType === "image/emf") {
2114
- return true;
2115
- }
2116
- const src = normalizeImageSrc(image)?.toLowerCase();
2117
- return Boolean(src && EMF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)));
2118
- }
2119
- function imageUsesWmfContent(image) {
2120
- const contentType = normalizeImageContentType(image);
2121
- if (contentType === "image/x-wmf" || contentType === "image/wmf") {
2122
- return true;
2123
- }
2124
- const src = normalizeImageSrc(image)?.toLowerCase();
2125
- return Boolean(src && WMF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)));
2126
- }
2127
- function imageUsesPlaceholderFallback(image) {
2128
- return imageHasMetafileContent(image);
2129
- }
2130
- function unsupportedImageFallbackLabel(image, widthPx, heightPx) {
2131
- const isSmallIcon = (widthPx ?? 0) <= 56 && (heightPx ?? 0) <= 56;
2132
- if (imageUsesEmfContent(image)) {
2133
- return isSmallIcon ? "e" : "EMF";
2134
- }
2135
- if (imageUsesWmfContent(image)) {
2136
- return isSmallIcon ? "w" : "WMF";
2137
- }
2138
- return isSmallIcon ? "e" : "TIFF";
2139
- }
2140
- function dataUriToBytes(dataUri) {
2141
- const match = dataUri.match(/^data:([^;]+);base64,(.+)$/i);
2142
- if (!match) {
2143
- return void 0;
2144
- }
2145
- const [, , base64] = match;
2146
- if (typeof Buffer !== "undefined") {
2147
- return new Uint8Array(Buffer.from(base64, "base64"));
2148
- }
2149
- if (typeof atob !== "function") {
2150
- return void 0;
2151
- }
2152
- const binary = atob(base64);
2153
- const bytes = new Uint8Array(binary.length);
2154
- for (let index = 0; index < binary.length; index += 1) {
2155
- bytes[index] = binary.charCodeAt(index);
2156
- }
2157
- return bytes;
2158
- }
2159
- function bytesToBase64(bytes) {
2160
- if (typeof Buffer !== "undefined") {
2161
- return Buffer.from(bytes).toString("base64");
2162
- }
2163
- if (typeof btoa !== "function") {
2164
- return void 0;
2165
- }
2166
- let binary = "";
2167
- const chunkSize = 32768;
2168
- for (let index = 0; index < bytes.byteLength; index += chunkSize) {
2169
- const chunk = bytes.subarray(index, index + chunkSize);
2170
- binary += String.fromCharCode(...chunk);
2171
- }
2172
- return btoa(binary);
2173
- }
2174
- function toArrayBuffer(bytes) {
2175
- const { buffer, byteOffset, byteLength } = bytes;
2176
- if (byteOffset === 0 && byteLength === buffer.byteLength) {
2177
- return buffer;
2178
- }
2179
- return buffer.slice(byteOffset, byteOffset + byteLength);
2180
- }
2181
- function resolveTiffBytes(image) {
2182
- if (image.data?.byteLength) {
2183
- return image.data;
2184
- }
2185
- const src = normalizeImageSrc(image);
2186
- return src ? dataUriToBytes(src) : void 0;
2187
- }
2188
- function selectPrimaryTiffPage(ifds) {
2189
- if (ifds.length === 0) {
2190
- return void 0;
2191
- }
2192
- let candidates = ifds;
2193
- if (Array.isArray(ifds[0]?.subIFD) && ifds[0].subIFD.length > 0) {
2194
- candidates = candidates.concat(ifds[0].subIFD);
2195
- }
2196
- let best;
2197
- let maxArea = -1;
2198
- for (const candidate of candidates) {
2199
- const width = candidate.width ?? candidate.t256 ?? 0;
2200
- const height = candidate.height ?? candidate.t257 ?? 0;
2201
- if (!width || !height) {
2202
- continue;
2203
- }
2204
- const area = width * height;
2205
- if (best === void 0 || area > maxArea) {
2206
- best = candidate;
2207
- maxArea = area;
2208
- }
2209
- }
2210
- return best ?? ifds[0];
2211
- }
2212
- function convertTiffToPngDataUri(bytes) {
2213
- const tiffBuffer = toArrayBuffer(bytes);
2214
- const ifds = UTIF.decode(tiffBuffer);
2215
- const page = selectPrimaryTiffPage(ifds);
2216
- if (!page) {
2217
- return void 0;
2218
- }
2219
- UTIF.decodeImage(tiffBuffer, page, ifds);
2220
- const width = page.width ?? page.t256 ?? 0;
2221
- const height = page.height ?? page.t257 ?? 0;
2222
- const rgba = UTIF.toRGBA8(page);
2223
- if (!width || !height || rgba.byteLength !== width * height * 4) {
2224
- return void 0;
2225
- }
2226
- const pngBytes = (0, import_fast_png.encode)({
2227
- width,
2228
- height,
2229
- data: rgba,
2230
- channels: 4,
2231
- depth: 8
2232
- });
2233
- const base64 = bytesToBase64(pngBytes);
2234
- return base64 ? `data:image/png;base64,${base64}` : void 0;
2235
- }
2236
- function resolveRenderableImageSource(image) {
2237
- const src = normalizeImageSrc(image);
2238
- if (!src) {
2239
- return void 0;
2240
- }
2241
- if (imageHasMetafileContent(image)) {
2242
- return void 0;
2243
- }
2244
- if (!imageHasTiffContent(image)) {
2245
- return src;
2246
- }
2247
- const cached = convertedTiffSrcCache.get(src);
2248
- if (cached !== void 0 || convertedTiffSrcCache.has(src)) {
2249
- return cached;
2250
- }
2251
- let converted;
2252
- try {
2253
- const bytes = resolveTiffBytes(image);
2254
- if (bytes) {
2255
- converted = convertTiffToPngDataUri(bytes);
2256
- }
2257
- } catch {
2258
- converted = void 0;
2259
- }
2260
- convertedTiffSrcCache.set(src, converted);
2261
- return converted;
2262
- }
2263
- function subscribeRenderableImageSourceUpdates(listener) {
2264
- void listener;
2265
- return () => {
2266
- };
2267
- }
2268
-
2269
- // src/script-fonts.ts
2270
- init_cjs_shims();
2271
- var EAST_ASIA_SCRIPT_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Bopomofo}\p{Script=Yi}]/u;
2272
- var COMPLEX_SCRIPT_RE = /[\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Syriac}\p{Script=Thaana}\p{Script=Nko}\p{Script=Samaritan}\p{Script=Mandaic}\p{Script=Devanagari}\p{Script=Bengali}\p{Script=Gurmukhi}\p{Script=Gujarati}\p{Script=Oriya}\p{Script=Tamil}\p{Script=Telugu}\p{Script=Kannada}\p{Script=Malayalam}\p{Script=Sinhala}\p{Script=Thai}\p{Script=Lao}\p{Script=Tibetan}\p{Script=Myanmar}\p{Script=Khmer}]/u;
2273
- var NEUTRAL_OR_CONTINUATION_RE = /[\p{Mark}\p{Separator}\p{Punctuation}\u200c\u200d\ufe00-\ufe0f]/u;
2274
- var EAST_ASIA_LANGUAGE_RE = /^(?:ja|ko|zh)(?:-|$)/i;
2275
- var COMPLEX_SCRIPT_LANGUAGE_RE = /^(?:ar|ckb|dv|fa|he|hi|ks|ku|pa-arab|ps|sd|syr|ug|ur|yi)(?:-|$)/i;
2276
- function normalizeFamily(value) {
2277
- const normalized = value?.trim();
2278
- return normalized || void 0;
2279
- }
2280
- function normalizedFamilyKey(value) {
2281
- return normalizeFamily(value)?.replace(/^['"]+|['"]+$/g, "").toLowerCase();
2282
- }
2283
- function hasLegacyFontFamilyOverride(style) {
2284
- const current = normalizedFamilyKey(style?.fontFamily);
2285
- const imported = normalizedFamilyKey(style?.sourceFontFamily);
2286
- if (!current) {
2287
- return false;
2288
- }
2289
- if (imported) {
2290
- return current !== imported;
2291
- }
2292
- return !(normalizeFamily(style?.fontFamilyAscii) || normalizeFamily(style?.fontFamilyHAnsi) || normalizeFamily(style?.fontFamilyEastAsia) || normalizeFamily(style?.fontFamilyCs) || normalizeFamily(style?.fontThemeAscii) || normalizeFamily(style?.fontThemeHAnsi) || normalizeFamily(style?.fontThemeEastAsia) || normalizeFamily(style?.fontThemeCs));
2293
- }
2294
- function normalizedFontHint(style) {
2295
- return style?.fontHint?.trim().replace(/[-_\s]/g, "").toLowerCase() ?? "";
2296
- }
2297
- function neutralScript(style) {
2298
- const hint = normalizedFontHint(style);
2299
- if (hint === "eastasia") {
2300
- return "eastAsia";
2301
- }
2302
- if (hint === "cs" || hint === "complexscript" || hint === "bidi") {
2303
- return "complexScript";
2304
- }
2305
- if (style?.rightToLeft || COMPLEX_SCRIPT_LANGUAGE_RE.test(style?.languageBidi?.trim() ?? "")) {
2306
- return "complexScript";
2307
- }
2308
- if (EAST_ASIA_LANGUAGE_RE.test(style?.languageEastAsia?.trim() ?? "")) {
2309
- return "eastAsia";
2310
- }
2311
- return "highAnsi";
2312
- }
2313
- function classifyDocxFontScript(value, style) {
2314
- const character = Array.from(value)[0];
2315
- if (!character) {
2316
- return void 0;
2317
- }
2318
- if (style?.complexScript === true || style?.rightToLeft === true && style?.complexScript !== false) {
2319
- return "complexScript";
2320
- }
2321
- const codePoint = character.codePointAt(0) ?? 0;
2322
- if (codePoint <= 127) {
2323
- return "ascii";
2324
- }
2325
- if (EAST_ASIA_SCRIPT_RE.test(character) || codePoint >= 12288 && codePoint <= 12351 || codePoint >= 65280 && codePoint <= 65519) {
2326
- return "eastAsia";
2327
- }
2328
- if (COMPLEX_SCRIPT_RE.test(character)) {
2329
- return "complexScript";
2330
- }
2331
- if (NEUTRAL_OR_CONTINUATION_RE.test(character)) {
2332
- return void 0;
2333
- }
2334
- return "highAnsi";
2335
- }
2336
- function resolveDocxScriptFontFamily(style, script) {
2337
- const legacyFamily = normalizeFamily(style?.fontFamily);
2338
- if (hasLegacyFontFamilyOverride(style)) {
2339
- return legacyFamily;
2340
- }
2341
- switch (script) {
2342
- case "ascii":
2343
- return normalizeFamily(style?.resolvedFontFamilyAscii) ?? normalizeFamily(style?.fontFamilyAscii) ?? normalizeFamily(style?.resolvedFontFamilyHAnsi) ?? normalizeFamily(style?.fontFamilyHAnsi) ?? legacyFamily;
2344
- case "highAnsi":
2345
- return normalizeFamily(style?.resolvedFontFamilyHAnsi) ?? normalizeFamily(style?.fontFamilyHAnsi) ?? normalizeFamily(style?.resolvedFontFamilyAscii) ?? normalizeFamily(style?.fontFamilyAscii) ?? legacyFamily;
2346
- case "eastAsia":
2347
- return normalizeFamily(style?.resolvedFontFamilyEastAsia) ?? normalizeFamily(style?.fontFamilyEastAsia) ?? normalizeFamily(style?.resolvedFontFamilyHAnsi) ?? normalizeFamily(style?.fontFamilyHAnsi) ?? normalizeFamily(style?.resolvedFontFamilyAscii) ?? normalizeFamily(style?.fontFamilyAscii) ?? legacyFamily;
2348
- case "complexScript":
2349
- return normalizeFamily(style?.resolvedFontFamilyCs) ?? normalizeFamily(style?.fontFamilyCs) ?? normalizeFamily(style?.resolvedFontFamilyHAnsi) ?? normalizeFamily(style?.fontFamilyHAnsi) ?? normalizeFamily(style?.resolvedFontFamilyAscii) ?? normalizeFamily(style?.fontFamilyAscii) ?? legacyFamily;
2350
- }
2351
- }
2352
- function segmentTextByDocxScriptFont(text, style) {
2353
- if (!text) {
2354
- return [];
2355
- }
2356
- const tokens = [];
2357
- let offset = 0;
2358
- for (const character of text) {
2359
- const startOffset = offset;
2360
- offset += character.length;
2361
- tokens.push({
2362
- text: character,
2363
- startOffset,
2364
- endOffset: offset,
2365
- script: classifyDocxFontScript(character, style)
2366
- });
2367
- }
2368
- const fallbackScript = neutralScript(style);
2369
- const nextStrongScript = new Array(
2370
- tokens.length
2371
- );
2372
- let nextScript;
2373
- for (let index = tokens.length - 1; index >= 0; index -= 1) {
2374
- nextStrongScript[index] = nextScript;
2375
- if (tokens[index]?.script) {
2376
- nextScript = tokens[index]?.script;
2377
- }
2378
- }
2379
- let previousScript;
2380
- for (let index = 0; index < tokens.length; index += 1) {
2381
- const token = tokens[index];
2382
- if (!token) {
2383
- continue;
2384
- }
2385
- token.script = token.script ?? previousScript ?? nextStrongScript[index] ?? fallbackScript;
2386
- previousScript = token.script;
2387
- }
2388
- const segments = [];
2389
- for (const token of tokens) {
2390
- const script = token.script ?? fallbackScript;
2391
- const fontFamily = resolveDocxScriptFontFamily(style, script);
2392
- const previous = segments[segments.length - 1];
2393
- if (previous && normalizedFamilyKey(previous.fontFamily) === normalizedFamilyKey(fontFamily)) {
2394
- previous.text += token.text;
2395
- previous.endOffset = token.endOffset;
2396
- continue;
2397
- }
2398
- segments.push({
2399
- text: token.text,
2400
- startOffset: token.startOffset,
2401
- endOffset: token.endOffset,
2402
- script,
2403
- fontFamily
2404
- });
2405
- }
2406
- return segments;
2407
- }
2408
- function resolveDocxTextFontFamily(text, style) {
2409
- return segmentTextByDocxScriptFont(text, style).find(
2410
- (segment) => segment.fontFamily
2411
- )?.fontFamily ?? normalizeFamily(style?.fontFamily);
2412
- }
2413
-
2414
1891
  // src/editor.tsx
2415
1892
  init_cjs_shims();
2416
1893
  var React = __toESM(require("react"), 1);
@@ -4972,452 +4449,978 @@ function applyTextEditingIntent(text, selectionStart, selectionEnd, intent) {
4972
4449
  return void 0;
4973
4450
  }
4974
4451
  }
4975
- function shouldCoalesceTextCommit(previous, next, windowMs = 1e3) {
4976
- return Boolean(
4977
- previous && previous.key === next.key && next.at >= previous.at && next.at - previous.at <= windowMs && previous.caretAfter === next.caretBefore
4978
- );
4452
+ function shouldCoalesceTextCommit(previous, next, windowMs = 1e3) {
4453
+ return Boolean(
4454
+ previous && previous.key === next.key && next.at >= previous.at && next.at - previous.at <= windowMs && previous.caretAfter === next.caretBefore
4455
+ );
4456
+ }
4457
+ function mergeCellParagraphTexts(paragraphTexts, boundaryParagraphIndex) {
4458
+ if (boundaryParagraphIndex <= 0 || boundaryParagraphIndex >= paragraphTexts.length) {
4459
+ return void 0;
4460
+ }
4461
+ const mergedTexts = [
4462
+ ...paragraphTexts.slice(0, boundaryParagraphIndex - 1),
4463
+ `${paragraphTexts[boundaryParagraphIndex - 1]}${paragraphTexts[boundaryParagraphIndex]}`,
4464
+ ...paragraphTexts.slice(boundaryParagraphIndex + 1)
4465
+ ];
4466
+ const cellText = mergedTexts.join("\n");
4467
+ let caretGlobalOffset = 0;
4468
+ for (let index = 0; index < boundaryParagraphIndex - 1; index += 1) {
4469
+ caretGlobalOffset += paragraphTexts[index].length + 1;
4470
+ }
4471
+ caretGlobalOffset += paragraphTexts[boundaryParagraphIndex - 1].length;
4472
+ const parts = cellText.split("\n");
4473
+ let remaining = caretGlobalOffset;
4474
+ let caretParagraphIndex = 0;
4475
+ while (caretParagraphIndex < parts.length - 1 && remaining > parts[caretParagraphIndex].length) {
4476
+ remaining -= parts[caretParagraphIndex].length + 1;
4477
+ caretParagraphIndex += 1;
4478
+ }
4479
+ return {
4480
+ cellText,
4481
+ caretParagraphIndex,
4482
+ caretOffset: Math.max(0, Math.min(remaining, parts[caretParagraphIndex].length))
4483
+ };
4484
+ }
4485
+
4486
+ // src/pagination-breaks.ts
4487
+ init_cjs_shims();
4488
+ var PAGE_BREAK_XML_PATTERN = /<w:br\b[^>]*w:type="page"[^>]*\/?>/i;
4489
+ var PAGE_BREAK_BEFORE_XML_PATTERN = /<w:pageBreakBefore\b[^>]*\/?>/i;
4490
+ var tableExplicitPageBreakInfoBySourceXml = /* @__PURE__ */ new Map();
4491
+ function isOnOffTagEnabled(tagXml) {
4492
+ if (!tagXml) {
4493
+ return false;
4494
+ }
4495
+ const valueMatch = tagXml.match(/\bw:val="([^"]+)"/i)?.[1]?.trim().toLowerCase();
4496
+ if (!valueMatch) {
4497
+ return true;
4498
+ }
4499
+ return !["0", "false", "off", "no"].includes(valueMatch);
4500
+ }
4501
+ function paragraphHasExplicitPageBreak(paragraph) {
4502
+ const sourceXml = paragraph.sourceXml ?? "";
4503
+ return sourceXml.length > 0 && PAGE_BREAK_XML_PATTERN.test(sourceXml);
4504
+ }
4505
+ function paragraphHasPageBreakBefore(paragraph) {
4506
+ if (paragraph.style?.pageBreakBefore === true) {
4507
+ return true;
4508
+ }
4509
+ const sourceXml = paragraph.sourceXml ?? "";
4510
+ if (!sourceXml) {
4511
+ return false;
4512
+ }
4513
+ return isOnOffTagEnabled(sourceXml.match(PAGE_BREAK_BEFORE_XML_PATTERN)?.[0]);
4514
+ }
4515
+ function paragraphHasVisibleText(paragraph) {
4516
+ return paragraph.children.some(
4517
+ (child) => child.type === "text" && child.text.trim().length > 0 || child.type === "form-field" && (child.value ?? "").trim().length > 0
4518
+ );
4519
+ }
4520
+ function paragraphHasImage(paragraph) {
4521
+ return paragraph.children.some((child) => child.type === "image");
4522
+ }
4523
+ function paragraphHasFormField(paragraph) {
4524
+ return paragraph.children.some((child) => child.type === "form-field");
4525
+ }
4526
+ function paragraphIsOnlyExplicitPageBreak(paragraph) {
4527
+ return paragraphHasExplicitPageBreak(paragraph) && !paragraphHasVisibleText(paragraph) && !paragraphHasImage(paragraph) && !paragraphHasFormField(paragraph);
4528
+ }
4529
+ function tableCellDirectParagraphs(nodeContent) {
4530
+ return nodeContent.filter((entry) => entry.type === "paragraph");
4531
+ }
4532
+ function tableRowHasSubstantiveContentOutsideBreakOnlyParagraphs(row) {
4533
+ return row.cells.some(
4534
+ (cell) => tableCellDirectParagraphs(cell.nodes).some((paragraph) => {
4535
+ if (paragraphIsOnlyExplicitPageBreak(paragraph)) {
4536
+ return false;
4537
+ }
4538
+ return paragraphHasVisibleText(paragraph) || paragraphHasImage(paragraph) || paragraphHasFormField(paragraph) || paragraphHasExplicitPageBreak(paragraph);
4539
+ })
4540
+ );
4541
+ }
4542
+ function tableRowSubstantiveCellIndexes(row) {
4543
+ const indexes = [];
4544
+ row.cells.forEach((cell, cellIndex) => {
4545
+ const substantive = tableCellDirectParagraphs(cell.nodes).some((paragraph) => {
4546
+ if (paragraphIsOnlyExplicitPageBreak(paragraph)) {
4547
+ return false;
4548
+ }
4549
+ return paragraphHasVisibleText(paragraph) || paragraphHasImage(paragraph) || paragraphHasFormField(paragraph) || paragraphHasExplicitPageBreak(paragraph);
4550
+ });
4551
+ if (substantive) {
4552
+ indexes.push(cellIndex);
4553
+ }
4554
+ });
4555
+ return indexes;
4556
+ }
4557
+ function tableRowUsesTrailingSignatureCellBreakPattern(table, row) {
4558
+ if (table.rows.length !== 1 || row.cells.length < 4) {
4559
+ return false;
4560
+ }
4561
+ const substantiveIndexes = tableRowSubstantiveCellIndexes(row);
4562
+ return substantiveIndexes.length === 1 && substantiveIndexes[0] >= row.cells.length - 1;
4563
+ }
4564
+ function collectTableExplicitPageBreakInfo(table) {
4565
+ const sourceXml = table.sourceXml ?? "";
4566
+ if (sourceXml) {
4567
+ const cached = tableExplicitPageBreakInfoBySourceXml.get(sourceXml);
4568
+ if (cached) {
4569
+ return cached;
4570
+ }
4571
+ }
4572
+ const startRowIndexes = /* @__PURE__ */ new Set();
4573
+ let breakAfterTable = false;
4574
+ table.rows.forEach((row, rowIndex) => {
4575
+ let rowBreakTarget;
4576
+ row.cells.forEach((cell) => {
4577
+ tableCellDirectParagraphs(cell.nodes).forEach((paragraph) => {
4578
+ if (!paragraphHasExplicitPageBreak(paragraph)) {
4579
+ return;
4580
+ }
4581
+ if (paragraphIsOnlyExplicitPageBreak(paragraph) && rowIndex === 0 && tableRowHasSubstantiveContentOutsideBreakOnlyParagraphs(row) && !tableRowUsesTrailingSignatureCellBreakPattern(table, row)) {
4582
+ return;
4583
+ }
4584
+ const breakTarget = paragraphIsOnlyExplicitPageBreak(paragraph) ? rowIndex : rowIndex + 1;
4585
+ if (rowBreakTarget === void 0 || breakTarget < rowBreakTarget) {
4586
+ rowBreakTarget = breakTarget;
4587
+ }
4588
+ });
4589
+ });
4590
+ if (rowBreakTarget === void 0) {
4591
+ return;
4592
+ }
4593
+ if (rowBreakTarget >= table.rows.length) {
4594
+ breakAfterTable = true;
4595
+ return;
4596
+ }
4597
+ startRowIndexes.add(Math.max(0, rowBreakTarget));
4598
+ });
4599
+ const info = {
4600
+ startRowIndexes: [...startRowIndexes].sort((left, right) => left - right),
4601
+ breakAfterTable
4602
+ };
4603
+ if (sourceXml) {
4604
+ tableExplicitPageBreakInfoBySourceXml.set(sourceXml, info);
4605
+ }
4606
+ return info;
4607
+ }
4608
+ function collectTopLevelExplicitPageBreakStartNodeIndexes(nodes) {
4609
+ const breaks = /* @__PURE__ */ new Set();
4610
+ for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += 1) {
4611
+ const node = nodes[nodeIndex];
4612
+ const hasNextNode = nodeIndex + 1 < nodes.length;
4613
+ if (node.type === "paragraph") {
4614
+ if (paragraphHasPageBreakBefore(node)) {
4615
+ breaks.add(nodeIndex);
4616
+ }
4617
+ if (hasNextNode && paragraphHasExplicitPageBreak(node)) {
4618
+ breaks.add(nodeIndex + 1);
4619
+ }
4620
+ continue;
4621
+ }
4622
+ const tableBreakInfo = collectTableExplicitPageBreakInfo(node);
4623
+ if (tableBreakInfo.startRowIndexes.includes(0) && nodeIndex > 0) {
4624
+ breaks.add(nodeIndex);
4625
+ }
4626
+ if (hasNextNode && tableBreakInfo.breakAfterTable) {
4627
+ breaks.add(nodeIndex + 1);
4628
+ }
4629
+ }
4630
+ for (const breakIndex of [...breaks]) {
4631
+ if (breakIndex <= 0 || breakIndex >= nodes.length) {
4632
+ breaks.delete(breakIndex);
4633
+ }
4634
+ }
4635
+ return breaks;
4636
+ }
4637
+
4638
+ // src/page-count-reconciliation.ts
4639
+ init_cjs_shims();
4640
+ var PAGE_COUNT_RECONCILIATION_REFINEMENT_STEPS = 10;
4641
+ function shouldAllowStoredPageCountReduction(options) {
4642
+ const estimatedPageCount = Math.max(
4643
+ 1,
4644
+ Math.round(options.estimatedPageCount)
4645
+ );
4646
+ const targetPageCount = Math.max(1, Math.round(options.targetPageCount));
4647
+ if (targetPageCount >= estimatedPageCount) {
4648
+ return true;
4649
+ }
4650
+ const renderedBreakHintPageCount = Number.isFinite(
4651
+ options.renderedBreakHintPageCount
4652
+ ) ? Math.max(1, Math.round(options.renderedBreakHintPageCount)) : void 0;
4653
+ const renderedBreakHintsSupportTarget = options.hasLastRenderedPageBreakHints === true && renderedBreakHintPageCount !== void 0 && targetPageCount >= renderedBreakHintPageCount;
4654
+ if (options.hasMeasuredBodyFooterOverlap === true) {
4655
+ return renderedBreakHintsSupportTarget;
4656
+ }
4657
+ if (options.hasLastRenderedPageBreakHints !== true) {
4658
+ return true;
4659
+ }
4660
+ return renderedBreakHintsSupportTarget;
4661
+ }
4662
+ function shouldLatchMeasuredBodyFooterOverlap(options) {
4663
+ if (options.measuredBodyFooterOverlap !== true) {
4664
+ return false;
4665
+ }
4666
+ const targetPageCount = Number.isFinite(options.targetPageCount) ? Math.max(1, Math.round(options.targetPageCount)) : void 0;
4667
+ if (targetPageCount === void 0) {
4668
+ return false;
4669
+ }
4670
+ const pageCount = Math.max(1, Math.round(options.pageCount));
4671
+ return pageCount <= targetPageCount;
4672
+ }
4673
+ function resolveMeasuredBodyFooterOverlapLatchState(options) {
4674
+ const shouldConsiderMeasuredBodyFooterOverlap = shouldLatchMeasuredBodyFooterOverlap({
4675
+ pageCount: options.pageCount,
4676
+ targetPageCount: options.targetPageCount,
4677
+ measuredBodyFooterOverlap: options.overlappingPageIndexes.length > 0
4678
+ });
4679
+ if (!shouldConsiderMeasuredBodyFooterOverlap) {
4680
+ return {
4681
+ signature: void 0,
4682
+ consecutivePasses: 0,
4683
+ shouldLatch: false
4684
+ };
4685
+ }
4686
+ const signature = options.overlappingPageIndexes.map((pageIndex) => `${pageIndex}`).join("|");
4687
+ const consecutivePasses = signature === options.previousSignature ? Math.max(0, Math.round(options.previousConsecutivePasses ?? 0)) + 1 : 1;
4688
+ const stabilityThreshold = Math.max(
4689
+ 1,
4690
+ Math.round(options.stabilityThreshold ?? 1)
4691
+ );
4692
+ return {
4693
+ signature,
4694
+ consecutivePasses,
4695
+ shouldLatch: consecutivePasses >= stabilityThreshold
4696
+ };
4697
+ }
4698
+ function createEstimatedPagesBuildMemo(build) {
4699
+ const entries = [];
4700
+ return (measuredTableRowHeightsByNodeIndex, measuredPageContentHeightsPxByPageIndex, strictLastRenderedParagraphStartBreaks) => {
4701
+ const cached = entries.find(
4702
+ (entry) => entry.measuredTableRowHeightsByNodeIndex === measuredTableRowHeightsByNodeIndex && entry.measuredPageContentHeightsPxByPageIndex === measuredPageContentHeightsPxByPageIndex && entry.strictLastRenderedParagraphStartBreaks === strictLastRenderedParagraphStartBreaks
4703
+ );
4704
+ if (cached) {
4705
+ return cached.pages;
4706
+ }
4707
+ const pages = build(
4708
+ measuredTableRowHeightsByNodeIndex,
4709
+ measuredPageContentHeightsPxByPageIndex,
4710
+ strictLastRenderedParagraphStartBreaks
4711
+ );
4712
+ entries.push({
4713
+ measuredTableRowHeightsByNodeIndex,
4714
+ measuredPageContentHeightsPxByPageIndex,
4715
+ strictLastRenderedParagraphStartBreaks,
4716
+ pages
4717
+ });
4718
+ return pages;
4719
+ };
4720
+ }
4721
+ function resolveMeasuredSplitParagraphPageComparison(options) {
4722
+ if (options.canUndo || options.canRedo || !options.hasMeasuredPageContentHeights) {
4723
+ return {
4724
+ pages: options.measuredEstimatedPages,
4725
+ usedPureEstimatedPages: false
4726
+ };
4727
+ }
4728
+ const measuredPagesAreOnlySplitParagraphs = options.measuredEstimatedPages.length > 0 && options.measuredEstimatedPages.every(
4729
+ options.pageContainsOnlySplitParagraphSegments
4730
+ );
4731
+ if (!measuredPagesAreOnlySplitParagraphs) {
4732
+ return {
4733
+ pages: options.measuredEstimatedPages,
4734
+ usedPureEstimatedPages: false
4735
+ };
4736
+ }
4737
+ const pureEstimatedPages = options.buildPureEstimatedPages();
4738
+ const purePagesAreOnlySplitParagraphs = pureEstimatedPages.length > 0 && pureEstimatedPages.every(options.pageContainsOnlySplitParagraphSegments);
4739
+ if (purePagesAreOnlySplitParagraphs && pureEstimatedPages.length < options.measuredEstimatedPages.length) {
4740
+ return { pages: pureEstimatedPages, usedPureEstimatedPages: true };
4741
+ }
4742
+ return {
4743
+ pages: options.measuredEstimatedPages,
4744
+ usedPureEstimatedPages: false
4745
+ };
4746
+ }
4747
+ function isBetterCandidate(candidate, incumbent, targetPageCount) {
4748
+ const candidateDifference = Math.abs(candidate.pageCount - targetPageCount);
4749
+ const incumbentDifference = Math.abs(incumbent.pageCount - targetPageCount);
4750
+ if (candidateDifference !== incumbentDifference) {
4751
+ return candidateDifference < incumbentDifference;
4752
+ }
4753
+ const candidateScaleDelta = Math.abs(candidate.scale - 1);
4754
+ const incumbentScaleDelta = Math.abs(incumbent.scale - 1);
4755
+ if (candidateScaleDelta !== incumbentScaleDelta) {
4756
+ return candidateScaleDelta < incumbentScaleDelta;
4757
+ }
4758
+ return candidate.pageCount === targetPageCount && incumbent.pageCount !== targetPageCount;
4759
+ }
4760
+ function reconcilePageCountCandidateToTargetCountByScalingHeight(options) {
4761
+ const {
4762
+ initialPages,
4763
+ targetPageCount,
4764
+ buildPagesAtScale,
4765
+ maxDifference = 3,
4766
+ scales: customScales
4767
+ } = options;
4768
+ const safeTargetPageCount = Math.max(1, Math.round(targetPageCount));
4769
+ const initialPageCount = initialPages.length;
4770
+ const initialDifference = Math.abs(initialPageCount - safeTargetPageCount);
4771
+ if (initialDifference === 0 || initialDifference > maxDifference) {
4772
+ return {
4773
+ pageCount: initialPageCount,
4774
+ pages: initialPages,
4775
+ scale: 1
4776
+ };
4777
+ }
4778
+ const bestCandidate = {
4779
+ pageCount: initialPageCount,
4780
+ pages: initialPages,
4781
+ scale: 1
4782
+ };
4783
+ let selectedCandidate = bestCandidate;
4784
+ const needMorePages = initialPageCount < safeTargetPageCount;
4785
+ const scales = customScales && customScales.length > 0 ? customScales : needMorePages ? [
4786
+ 0.98,
4787
+ 0.96,
4788
+ 0.94,
4789
+ 0.92,
4790
+ 0.9,
4791
+ 0.88,
4792
+ 0.86,
4793
+ 0.84,
4794
+ 0.82,
4795
+ 0.8,
4796
+ 0.78,
4797
+ 0.76,
4798
+ 0.74,
4799
+ 0.72,
4800
+ 0.7,
4801
+ 0.68,
4802
+ 0.66,
4803
+ 0.64,
4804
+ 0.62,
4805
+ 0.6,
4806
+ 0.58,
4807
+ 0.56,
4808
+ 0.54,
4809
+ 0.52,
4810
+ 0.5,
4811
+ 0.48,
4812
+ 0.46,
4813
+ 0.44,
4814
+ 0.42,
4815
+ 0.4,
4816
+ 0.38,
4817
+ 0.36,
4818
+ 0.34,
4819
+ 0.32,
4820
+ 0.3,
4821
+ 0.28,
4822
+ 0.26,
4823
+ 0.24,
4824
+ 0.22,
4825
+ 0.2
4826
+ ] : [
4827
+ 1.02,
4828
+ 1.04,
4829
+ 1.06,
4830
+ 1.08,
4831
+ 1.1,
4832
+ 1.12,
4833
+ 1.14,
4834
+ 1.16,
4835
+ 1.18,
4836
+ 1.2,
4837
+ 1.22,
4838
+ 1.24,
4839
+ 1.26,
4840
+ 1.28,
4841
+ 1.3
4842
+ ];
4843
+ const buildCandidateAtScale = (scale) => {
4844
+ const pages = buildPagesAtScale(scale);
4845
+ return {
4846
+ pageCount: pages.length,
4847
+ pages,
4848
+ scale
4849
+ };
4850
+ };
4851
+ const refineExactTargetCandidate = (lowerScale, upperScale) => {
4852
+ let bestExactCandidate;
4853
+ const interval = upperScale - lowerScale;
4854
+ if (!Number.isFinite(interval) || Math.abs(interval) < 1e-4) {
4855
+ return selectedCandidate;
4856
+ }
4857
+ for (let step = 1; step <= PAGE_COUNT_RECONCILIATION_REFINEMENT_STEPS; step += 1) {
4858
+ const scale = lowerScale + interval * step / PAGE_COUNT_RECONCILIATION_REFINEMENT_STEPS;
4859
+ const candidate = buildCandidateAtScale(scale);
4860
+ if (isBetterCandidate(candidate, selectedCandidate, safeTargetPageCount)) {
4861
+ selectedCandidate = candidate;
4862
+ }
4863
+ if (candidate.pageCount === safeTargetPageCount && (bestExactCandidate === void 0 || isBetterCandidate(
4864
+ candidate,
4865
+ bestExactCandidate,
4866
+ safeTargetPageCount
4867
+ ))) {
4868
+ bestExactCandidate = candidate;
4869
+ }
4870
+ }
4871
+ return bestExactCandidate ?? selectedCandidate;
4872
+ };
4873
+ let previousScale = 1;
4874
+ let previousPageCount = initialPageCount;
4875
+ for (const scale of scales) {
4876
+ const candidate = buildCandidateAtScale(scale);
4877
+ if (isBetterCandidate(candidate, selectedCandidate, safeTargetPageCount)) {
4878
+ selectedCandidate = candidate;
4879
+ }
4880
+ if (candidate.pageCount === safeTargetPageCount) {
4881
+ const crossedIntoExactTarget = needMorePages ? previousPageCount < safeTargetPageCount : previousPageCount > safeTargetPageCount;
4882
+ if (crossedIntoExactTarget) {
4883
+ return refineExactTargetCandidate(previousScale, scale);
4884
+ }
4885
+ return candidate;
4886
+ }
4887
+ previousScale = scale;
4888
+ previousPageCount = candidate.pageCount;
4889
+ }
4890
+ if (!needMorePages && selectedCandidate.pageCount !== safeTargetPageCount) {
4891
+ return {
4892
+ pageCount: initialPageCount,
4893
+ pages: initialPages,
4894
+ scale: 1
4895
+ };
4896
+ }
4897
+ return selectedCandidate;
4898
+ }
4899
+
4900
+ // src/section-layout.ts
4901
+ init_cjs_shims();
4902
+ var DEFAULT_DOC_PAGE_WIDTH = 900;
4903
+ var DEFAULT_DOC_PAGE_HEIGHT = 1200;
4904
+ var DEFAULT_DOC_PAGE_MARGIN = 56;
4905
+ var TWIPS_PER_PIXEL = 15;
4906
+ var DEFAULT_DOCUMENT_LAYOUT = {
4907
+ pageWidthPx: DEFAULT_DOC_PAGE_WIDTH,
4908
+ pageHeightPx: DEFAULT_DOC_PAGE_HEIGHT,
4909
+ marginsPx: {
4910
+ top: DEFAULT_DOC_PAGE_MARGIN,
4911
+ right: DEFAULT_DOC_PAGE_MARGIN,
4912
+ bottom: DEFAULT_DOC_PAGE_MARGIN,
4913
+ left: DEFAULT_DOC_PAGE_MARGIN
4914
+ },
4915
+ headerDistancePx: DEFAULT_DOC_PAGE_MARGIN,
4916
+ footerDistancePx: DEFAULT_DOC_PAGE_MARGIN,
4917
+ docGridLinePitchPx: void 0
4918
+ };
4919
+ function pageMarginPaddingStyle(marginsPx) {
4920
+ return {
4921
+ paddingTop: marginsPx.top,
4922
+ paddingRight: marginsPx.right,
4923
+ paddingBottom: marginsPx.bottom,
4924
+ paddingLeft: marginsPx.left
4925
+ };
4926
+ }
4927
+ function twipsToPixels(twips) {
4928
+ if (!Number.isFinite(twips)) {
4929
+ return void 0;
4930
+ }
4931
+ return Math.max(0, Math.round(twips / TWIPS_PER_PIXEL));
4932
+ }
4933
+ function readTwipsAttribute(tagXml, attribute) {
4934
+ if (!tagXml) {
4935
+ return void 0;
4936
+ }
4937
+ const match = tagXml.match(new RegExp(`${attribute}="(\\d+)"`, "i"));
4938
+ if (!match?.[1]) {
4939
+ return void 0;
4940
+ }
4941
+ const parsed = Number(match[1]);
4942
+ return Number.isFinite(parsed) ? parsed : void 0;
4943
+ }
4944
+ function readStringAttribute(tagXml, attribute) {
4945
+ if (!tagXml) {
4946
+ return void 0;
4947
+ }
4948
+ return tagXml.match(new RegExp(`${attribute}="([^"]+)"`, "i"))?.[1];
4949
+ }
4950
+ function resolvePageSizeForOrientation(params) {
4951
+ const normalizedOrientation = params.orientation?.trim().toLowerCase();
4952
+ const widthPx = Math.max(1, params.widthPx);
4953
+ const heightPx = Math.max(1, params.heightPx);
4954
+ if (normalizedOrientation === "landscape" && widthPx < heightPx) {
4955
+ return { widthPx: heightPx, heightPx: widthPx };
4956
+ }
4957
+ if (normalizedOrientation === "portrait" && widthPx > heightPx) {
4958
+ return { widthPx: heightPx, heightPx: widthPx };
4959
+ }
4960
+ return { widthPx, heightPx };
4961
+ }
4962
+ function normalizeHexColor(value) {
4963
+ if (!value) {
4964
+ return void 0;
4965
+ }
4966
+ const normalized = value.trim();
4967
+ if (!normalized || normalized.toLowerCase() === "auto") {
4968
+ return void 0;
4969
+ }
4970
+ if (/^[0-9a-fA-F]{6}$/.test(normalized)) {
4971
+ return `#${normalized}`;
4972
+ }
4973
+ if (/^#[0-9a-fA-F]{6}$/.test(normalized)) {
4974
+ return normalized;
4975
+ }
4976
+ return void 0;
4979
4977
  }
4980
- function mergeCellParagraphTexts(paragraphTexts, boundaryParagraphIndex) {
4981
- if (boundaryParagraphIndex <= 0 || boundaryParagraphIndex >= paragraphTexts.length) {
4978
+ function borderTypeToCssStyle(rawType) {
4979
+ const value = rawType?.trim().toLowerCase();
4980
+ if (!value || value === "none" || value === "nil") {
4982
4981
  return void 0;
4983
4982
  }
4984
- const mergedTexts = [
4985
- ...paragraphTexts.slice(0, boundaryParagraphIndex - 1),
4986
- `${paragraphTexts[boundaryParagraphIndex - 1]}${paragraphTexts[boundaryParagraphIndex]}`,
4987
- ...paragraphTexts.slice(boundaryParagraphIndex + 1)
4988
- ];
4989
- const cellText = mergedTexts.join("\n");
4990
- let caretGlobalOffset = 0;
4991
- for (let index = 0; index < boundaryParagraphIndex - 1; index += 1) {
4992
- caretGlobalOffset += paragraphTexts[index].length + 1;
4983
+ if (value === "double") {
4984
+ return "double";
4993
4985
  }
4994
- caretGlobalOffset += paragraphTexts[boundaryParagraphIndex - 1].length;
4995
- const parts = cellText.split("\n");
4996
- let remaining = caretGlobalOffset;
4997
- let caretParagraphIndex = 0;
4998
- while (caretParagraphIndex < parts.length - 1 && remaining > parts[caretParagraphIndex].length) {
4999
- remaining -= parts[caretParagraphIndex].length + 1;
5000
- caretParagraphIndex += 1;
4986
+ if (value === "dashed" || value === "dashsmallgap" || value === "dotdash" || value === "dotdotdash") {
4987
+ return "dashed";
4988
+ }
4989
+ if (value === "dotted") {
4990
+ return "dotted";
4991
+ }
4992
+ return "solid";
4993
+ }
4994
+ function pointsToPixels(points) {
4995
+ if (!Number.isFinite(points)) {
4996
+ return void 0;
4997
+ }
4998
+ return Math.max(0, Math.round(points * (96 / 72)));
4999
+ }
5000
+ function parseSectionPageBorderEdge(sectionPropertiesXml, edge) {
5001
+ if (!sectionPropertiesXml) {
5002
+ return void 0;
5003
+ }
5004
+ const bordersXml = sectionPropertiesXml.match(
5005
+ /<w:pgBorders\b[\s\S]*?<\/w:pgBorders>/i
5006
+ )?.[0];
5007
+ if (!bordersXml) {
5008
+ return void 0;
5009
+ }
5010
+ const edgeTag = bordersXml.match(new RegExp(`<w:${edge}\\b[^>]*/?>`, "i"))?.[0];
5011
+ if (!edgeTag) {
5012
+ return void 0;
5013
+ }
5014
+ const cssStyle = borderTypeToCssStyle(readStringAttribute(edgeTag, "w:val"));
5015
+ if (!cssStyle) {
5016
+ return void 0;
5001
5017
  }
5018
+ const sizeEighthPt = Number(readStringAttribute(edgeTag, "w:sz"));
5019
+ const widthPx = Number.isFinite(sizeEighthPt) && sizeEighthPt > 0 ? Math.max(0.5, Number((sizeEighthPt / 6).toFixed(2))) : 1;
5020
+ const color = normalizeHexColor(readStringAttribute(edgeTag, "w:color")) ?? "#000000";
5021
+ const offsetPoints = Number(readStringAttribute(edgeTag, "w:space"));
5002
5022
  return {
5003
- cellText,
5004
- caretParagraphIndex,
5005
- caretOffset: Math.max(0, Math.min(remaining, parts[caretParagraphIndex].length))
5023
+ cssBorder: `${widthPx}px ${cssStyle} ${color}`,
5024
+ offsetPx: pointsToPixels(offsetPoints) ?? 0,
5025
+ shadow: readStringAttribute(edgeTag, "w:shadow")?.trim().toLowerCase() === "1" || readStringAttribute(edgeTag, "w:shadow")?.trim().toLowerCase() === "true"
5006
5026
  };
5007
5027
  }
5008
-
5009
- // src/pagination-breaks.ts
5010
- init_cjs_shims();
5011
- var PAGE_BREAK_XML_PATTERN = /<w:br\b[^>]*w:type="page"[^>]*\/?>/i;
5012
- var PAGE_BREAK_BEFORE_XML_PATTERN = /<w:pageBreakBefore\b[^>]*\/?>/i;
5013
- var tableExplicitPageBreakInfoBySourceXml = /* @__PURE__ */ new Map();
5014
- function isOnOffTagEnabled(tagXml) {
5015
- if (!tagXml) {
5016
- return false;
5028
+ function parseSectionPageBorders(sectionPropertiesXml) {
5029
+ if (!sectionPropertiesXml || !/<w:pgBorders\b/i.test(sectionPropertiesXml)) {
5030
+ return void 0;
5017
5031
  }
5018
- const valueMatch = tagXml.match(/\bw:val="([^"]+)"/i)?.[1]?.trim().toLowerCase();
5019
- if (!valueMatch) {
5020
- return true;
5032
+ const borders = {
5033
+ top: parseSectionPageBorderEdge(sectionPropertiesXml, "top"),
5034
+ right: parseSectionPageBorderEdge(sectionPropertiesXml, "right"),
5035
+ bottom: parseSectionPageBorderEdge(sectionPropertiesXml, "bottom"),
5036
+ left: parseSectionPageBorderEdge(sectionPropertiesXml, "left")
5037
+ };
5038
+ return borders.top || borders.right || borders.bottom || borders.left ? borders : void 0;
5039
+ }
5040
+ function parseSectionLayout(sectionPropertiesXml) {
5041
+ if (!sectionPropertiesXml) {
5042
+ return DEFAULT_DOCUMENT_LAYOUT;
5021
5043
  }
5022
- return !["0", "false", "off", "no"].includes(valueMatch);
5044
+ const pageSizeTag = sectionPropertiesXml.match(/<w:pgSz\b[^>]*>/i)?.[0];
5045
+ const pageMarginTag = sectionPropertiesXml.match(/<w:pgMar\b[^>]*>/i)?.[0];
5046
+ const docGridTag = sectionPropertiesXml.match(/<w:docGrid\b[^>]*\/?>/i)?.[0];
5047
+ const rawPageWidthPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:w")) ?? DEFAULT_DOCUMENT_LAYOUT.pageWidthPx;
5048
+ const rawPageHeightPx = twipsToPixels(readTwipsAttribute(pageSizeTag, "w:h")) ?? DEFAULT_DOCUMENT_LAYOUT.pageHeightPx;
5049
+ const pageSize = resolvePageSizeForOrientation({
5050
+ widthPx: rawPageWidthPx,
5051
+ heightPx: rawPageHeightPx,
5052
+ orientation: readStringAttribute(pageSizeTag, "w:orient")
5053
+ });
5054
+ const topMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:top")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.top;
5055
+ const rightMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:right")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.right;
5056
+ const bottomMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:bottom")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.bottom;
5057
+ const leftMarginPx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:left")) ?? DEFAULT_DOCUMENT_LAYOUT.marginsPx.left;
5058
+ const headerDistancePx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:header")) ?? DEFAULT_DOCUMENT_LAYOUT.headerDistancePx;
5059
+ const footerDistancePx = twipsToPixels(readTwipsAttribute(pageMarginTag, "w:footer")) ?? DEFAULT_DOCUMENT_LAYOUT.footerDistancePx;
5060
+ const docGridType = readStringAttribute(docGridTag, "w:type")?.toLowerCase();
5061
+ const docGridLinePitchPx = docGridType === "lines" || docGridType === "linesandchars" || docGridType === "snaptochars" ? twipsToPixels(readTwipsAttribute(docGridTag, "w:linePitch")) ?? DEFAULT_DOCUMENT_LAYOUT.docGridLinePitchPx : DEFAULT_DOCUMENT_LAYOUT.docGridLinePitchPx;
5062
+ return {
5063
+ pageWidthPx: pageSize.widthPx,
5064
+ pageHeightPx: pageSize.heightPx,
5065
+ marginsPx: {
5066
+ top: topMarginPx,
5067
+ right: rightMarginPx,
5068
+ bottom: bottomMarginPx,
5069
+ left: leftMarginPx
5070
+ },
5071
+ headerDistancePx,
5072
+ footerDistancePx,
5073
+ docGridLinePitchPx
5074
+ };
5023
5075
  }
5024
- function paragraphHasExplicitPageBreak(paragraph) {
5025
- const sourceXml = paragraph.sourceXml ?? "";
5026
- return sourceXml.length > 0 && PAGE_BREAK_XML_PATTERN.test(sourceXml);
5076
+ function resolveDocumentSectionPropertiesXml(model) {
5077
+ return model.metadata.sections?.[0]?.sectionPropertiesXml ?? model.metadata.sectionPropertiesXml;
5027
5078
  }
5028
- function paragraphHasPageBreakBefore(paragraph) {
5029
- if (paragraph.style?.pageBreakBefore === true) {
5079
+ function resolveDocumentLayout(model) {
5080
+ return parseSectionLayout(resolveDocumentSectionPropertiesXml(model));
5081
+ }
5082
+
5083
+ // src/image-render.ts
5084
+ init_cjs_shims();
5085
+ var import_fast_png = require("fast-png");
5086
+ var import_utif = __toESM(require("utif"), 1);
5087
+ var TIFF_CONTENT_TYPES = /* @__PURE__ */ new Set(["image/tiff", "image/tif"]);
5088
+ var PLACEHOLDER_FALLBACK_CONTENT_TYPES = /* @__PURE__ */ new Set([
5089
+ "image/x-emf",
5090
+ "image/emf",
5091
+ "image/x-wmf",
5092
+ "image/wmf"
5093
+ ]);
5094
+ var TIFF_DATA_URI_PREFIXES = ["data:image/tiff", "data:image/tif"];
5095
+ var EMF_DATA_URI_PREFIXES = ["data:image/emf", "data:image/x-emf"];
5096
+ var WMF_DATA_URI_PREFIXES = ["data:image/wmf", "data:image/x-wmf"];
5097
+ var UTIF = import_utif.default;
5098
+ var convertedTiffSrcCache = /* @__PURE__ */ new Map();
5099
+ function normalizeImageContentType(image) {
5100
+ return image.contentType?.trim().toLowerCase();
5101
+ }
5102
+ function normalizeImageSrc(image) {
5103
+ return image.src?.trim();
5104
+ }
5105
+ function imageHasTiffContent(image) {
5106
+ const contentType = normalizeImageContentType(image);
5107
+ if (contentType && TIFF_CONTENT_TYPES.has(contentType)) {
5030
5108
  return true;
5031
5109
  }
5032
- const sourceXml = paragraph.sourceXml ?? "";
5033
- if (!sourceXml) {
5034
- return false;
5035
- }
5036
- return isOnOffTagEnabled(sourceXml.match(PAGE_BREAK_BEFORE_XML_PATTERN)?.[0]);
5110
+ const src = normalizeImageSrc(image)?.toLowerCase();
5111
+ return Boolean(src && TIFF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)));
5037
5112
  }
5038
- function paragraphHasVisibleText(paragraph) {
5039
- return paragraph.children.some(
5040
- (child) => child.type === "text" && child.text.trim().length > 0 || child.type === "form-field" && (child.value ?? "").trim().length > 0
5113
+ function imageHasMetafileContent(image) {
5114
+ const contentType = normalizeImageContentType(image);
5115
+ if (contentType && PLACEHOLDER_FALLBACK_CONTENT_TYPES.has(contentType)) {
5116
+ return true;
5117
+ }
5118
+ const src = normalizeImageSrc(image)?.toLowerCase();
5119
+ return Boolean(
5120
+ src && (EMF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)) || WMF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)))
5041
5121
  );
5042
5122
  }
5043
- function paragraphHasImage(paragraph) {
5044
- return paragraph.children.some((child) => child.type === "image");
5045
- }
5046
- function paragraphHasFormField(paragraph) {
5047
- return paragraph.children.some((child) => child.type === "form-field");
5123
+ function imageUsesEmfContent(image) {
5124
+ const contentType = normalizeImageContentType(image);
5125
+ if (contentType === "image/x-emf" || contentType === "image/emf") {
5126
+ return true;
5127
+ }
5128
+ const src = normalizeImageSrc(image)?.toLowerCase();
5129
+ return Boolean(src && EMF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)));
5048
5130
  }
5049
- function paragraphIsOnlyExplicitPageBreak(paragraph) {
5050
- return paragraphHasExplicitPageBreak(paragraph) && !paragraphHasVisibleText(paragraph) && !paragraphHasImage(paragraph) && !paragraphHasFormField(paragraph);
5131
+ function imageUsesWmfContent(image) {
5132
+ const contentType = normalizeImageContentType(image);
5133
+ if (contentType === "image/x-wmf" || contentType === "image/wmf") {
5134
+ return true;
5135
+ }
5136
+ const src = normalizeImageSrc(image)?.toLowerCase();
5137
+ return Boolean(src && WMF_DATA_URI_PREFIXES.some((prefix) => src.startsWith(prefix)));
5051
5138
  }
5052
- function tableCellDirectParagraphs(nodeContent) {
5053
- return nodeContent.filter((entry) => entry.type === "paragraph");
5139
+ function imageUsesPlaceholderFallback(image) {
5140
+ return imageHasMetafileContent(image);
5054
5141
  }
5055
- function tableRowHasSubstantiveContentOutsideBreakOnlyParagraphs(row) {
5056
- return row.cells.some(
5057
- (cell) => tableCellDirectParagraphs(cell.nodes).some((paragraph) => {
5058
- if (paragraphIsOnlyExplicitPageBreak(paragraph)) {
5059
- return false;
5060
- }
5061
- return paragraphHasVisibleText(paragraph) || paragraphHasImage(paragraph) || paragraphHasFormField(paragraph) || paragraphHasExplicitPageBreak(paragraph);
5062
- })
5063
- );
5142
+ function unsupportedImageFallbackLabel(image, widthPx, heightPx) {
5143
+ const isSmallIcon = (widthPx ?? 0) <= 56 && (heightPx ?? 0) <= 56;
5144
+ if (imageUsesEmfContent(image)) {
5145
+ return isSmallIcon ? "e" : "EMF";
5146
+ }
5147
+ if (imageUsesWmfContent(image)) {
5148
+ return isSmallIcon ? "w" : "WMF";
5149
+ }
5150
+ return isSmallIcon ? "e" : "TIFF";
5064
5151
  }
5065
- function tableRowSubstantiveCellIndexes(row) {
5066
- const indexes = [];
5067
- row.cells.forEach((cell, cellIndex) => {
5068
- const substantive = tableCellDirectParagraphs(cell.nodes).some((paragraph) => {
5069
- if (paragraphIsOnlyExplicitPageBreak(paragraph)) {
5070
- return false;
5071
- }
5072
- return paragraphHasVisibleText(paragraph) || paragraphHasImage(paragraph) || paragraphHasFormField(paragraph) || paragraphHasExplicitPageBreak(paragraph);
5073
- });
5074
- if (substantive) {
5075
- indexes.push(cellIndex);
5076
- }
5077
- });
5078
- return indexes;
5152
+ function dataUriToBytes(dataUri) {
5153
+ const match = dataUri.match(/^data:([^;]+);base64,(.+)$/i);
5154
+ if (!match) {
5155
+ return void 0;
5156
+ }
5157
+ const [, , base64] = match;
5158
+ if (typeof Buffer !== "undefined") {
5159
+ return new Uint8Array(Buffer.from(base64, "base64"));
5160
+ }
5161
+ if (typeof atob !== "function") {
5162
+ return void 0;
5163
+ }
5164
+ const binary = atob(base64);
5165
+ const bytes = new Uint8Array(binary.length);
5166
+ for (let index = 0; index < binary.length; index += 1) {
5167
+ bytes[index] = binary.charCodeAt(index);
5168
+ }
5169
+ return bytes;
5079
5170
  }
5080
- function tableRowUsesTrailingSignatureCellBreakPattern(table, row) {
5081
- if (table.rows.length !== 1 || row.cells.length < 4) {
5082
- return false;
5171
+ function bytesToBase64(bytes) {
5172
+ if (typeof Buffer !== "undefined") {
5173
+ return Buffer.from(bytes).toString("base64");
5083
5174
  }
5084
- const substantiveIndexes = tableRowSubstantiveCellIndexes(row);
5085
- return substantiveIndexes.length === 1 && substantiveIndexes[0] >= row.cells.length - 1;
5175
+ if (typeof btoa !== "function") {
5176
+ return void 0;
5177
+ }
5178
+ let binary = "";
5179
+ const chunkSize = 32768;
5180
+ for (let index = 0; index < bytes.byteLength; index += chunkSize) {
5181
+ const chunk = bytes.subarray(index, index + chunkSize);
5182
+ binary += String.fromCharCode(...chunk);
5183
+ }
5184
+ return btoa(binary);
5086
5185
  }
5087
- function collectTableExplicitPageBreakInfo(table) {
5088
- const sourceXml = table.sourceXml ?? "";
5089
- if (sourceXml) {
5090
- const cached = tableExplicitPageBreakInfoBySourceXml.get(sourceXml);
5091
- if (cached) {
5092
- return cached;
5093
- }
5186
+ function toArrayBuffer(bytes) {
5187
+ const { buffer, byteOffset, byteLength } = bytes;
5188
+ if (byteOffset === 0 && byteLength === buffer.byteLength) {
5189
+ return buffer;
5094
5190
  }
5095
- const startRowIndexes = /* @__PURE__ */ new Set();
5096
- let breakAfterTable = false;
5097
- table.rows.forEach((row, rowIndex) => {
5098
- let rowBreakTarget;
5099
- row.cells.forEach((cell) => {
5100
- tableCellDirectParagraphs(cell.nodes).forEach((paragraph) => {
5101
- if (!paragraphHasExplicitPageBreak(paragraph)) {
5102
- return;
5103
- }
5104
- if (paragraphIsOnlyExplicitPageBreak(paragraph) && rowIndex === 0 && tableRowHasSubstantiveContentOutsideBreakOnlyParagraphs(row) && !tableRowUsesTrailingSignatureCellBreakPattern(table, row)) {
5105
- return;
5106
- }
5107
- const breakTarget = paragraphIsOnlyExplicitPageBreak(paragraph) ? rowIndex : rowIndex + 1;
5108
- if (rowBreakTarget === void 0 || breakTarget < rowBreakTarget) {
5109
- rowBreakTarget = breakTarget;
5110
- }
5111
- });
5112
- });
5113
- if (rowBreakTarget === void 0) {
5114
- return;
5115
- }
5116
- if (rowBreakTarget >= table.rows.length) {
5117
- breakAfterTable = true;
5118
- return;
5119
- }
5120
- startRowIndexes.add(Math.max(0, rowBreakTarget));
5121
- });
5122
- const info = {
5123
- startRowIndexes: [...startRowIndexes].sort((left, right) => left - right),
5124
- breakAfterTable
5125
- };
5126
- if (sourceXml) {
5127
- tableExplicitPageBreakInfoBySourceXml.set(sourceXml, info);
5191
+ return buffer.slice(byteOffset, byteOffset + byteLength);
5192
+ }
5193
+ function resolveTiffBytes(image) {
5194
+ if (image.data?.byteLength) {
5195
+ return image.data;
5128
5196
  }
5129
- return info;
5197
+ const src = normalizeImageSrc(image);
5198
+ return src ? dataUriToBytes(src) : void 0;
5130
5199
  }
5131
- function collectTopLevelExplicitPageBreakStartNodeIndexes(nodes) {
5132
- const breaks = /* @__PURE__ */ new Set();
5133
- for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += 1) {
5134
- const node = nodes[nodeIndex];
5135
- const hasNextNode = nodeIndex + 1 < nodes.length;
5136
- if (node.type === "paragraph") {
5137
- if (paragraphHasPageBreakBefore(node)) {
5138
- breaks.add(nodeIndex);
5139
- }
5140
- if (hasNextNode && paragraphHasExplicitPageBreak(node)) {
5141
- breaks.add(nodeIndex + 1);
5142
- }
5200
+ function selectPrimaryTiffPage(ifds) {
5201
+ if (ifds.length === 0) {
5202
+ return void 0;
5203
+ }
5204
+ let candidates = ifds;
5205
+ if (Array.isArray(ifds[0]?.subIFD) && ifds[0].subIFD.length > 0) {
5206
+ candidates = candidates.concat(ifds[0].subIFD);
5207
+ }
5208
+ let best;
5209
+ let maxArea = -1;
5210
+ for (const candidate of candidates) {
5211
+ const width = candidate.width ?? candidate.t256 ?? 0;
5212
+ const height = candidate.height ?? candidate.t257 ?? 0;
5213
+ if (!width || !height) {
5143
5214
  continue;
5144
5215
  }
5145
- const tableBreakInfo = collectTableExplicitPageBreakInfo(node);
5146
- if (tableBreakInfo.startRowIndexes.includes(0) && nodeIndex > 0) {
5147
- breaks.add(nodeIndex);
5148
- }
5149
- if (hasNextNode && tableBreakInfo.breakAfterTable) {
5150
- breaks.add(nodeIndex + 1);
5216
+ const area = width * height;
5217
+ if (best === void 0 || area > maxArea) {
5218
+ best = candidate;
5219
+ maxArea = area;
5151
5220
  }
5152
5221
  }
5153
- for (const breakIndex of [...breaks]) {
5154
- if (breakIndex <= 0 || breakIndex >= nodes.length) {
5155
- breaks.delete(breakIndex);
5156
- }
5222
+ return best ?? ifds[0];
5223
+ }
5224
+ function convertTiffToPngDataUri(bytes) {
5225
+ const tiffBuffer = toArrayBuffer(bytes);
5226
+ const ifds = UTIF.decode(tiffBuffer);
5227
+ const page = selectPrimaryTiffPage(ifds);
5228
+ if (!page) {
5229
+ return void 0;
5157
5230
  }
5158
- return breaks;
5231
+ UTIF.decodeImage(tiffBuffer, page, ifds);
5232
+ const width = page.width ?? page.t256 ?? 0;
5233
+ const height = page.height ?? page.t257 ?? 0;
5234
+ const rgba = UTIF.toRGBA8(page);
5235
+ if (!width || !height || rgba.byteLength !== width * height * 4) {
5236
+ return void 0;
5237
+ }
5238
+ const pngBytes = (0, import_fast_png.encode)({
5239
+ width,
5240
+ height,
5241
+ data: rgba,
5242
+ channels: 4,
5243
+ depth: 8
5244
+ });
5245
+ const base64 = bytesToBase64(pngBytes);
5246
+ return base64 ? `data:image/png;base64,${base64}` : void 0;
5159
5247
  }
5160
-
5161
- // src/page-count-reconciliation.ts
5162
- init_cjs_shims();
5163
- var PAGE_COUNT_RECONCILIATION_REFINEMENT_STEPS = 10;
5164
- function shouldAllowStoredPageCountReduction(options) {
5165
- const estimatedPageCount = Math.max(
5166
- 1,
5167
- Math.round(options.estimatedPageCount)
5168
- );
5169
- const targetPageCount = Math.max(1, Math.round(options.targetPageCount));
5170
- if (targetPageCount >= estimatedPageCount) {
5171
- return true;
5248
+ function resolveRenderableImageSource(image) {
5249
+ const src = normalizeImageSrc(image);
5250
+ if (!src) {
5251
+ return void 0;
5172
5252
  }
5173
- const renderedBreakHintPageCount = Number.isFinite(
5174
- options.renderedBreakHintPageCount
5175
- ) ? Math.max(1, Math.round(options.renderedBreakHintPageCount)) : void 0;
5176
- const renderedBreakHintsSupportTarget = options.hasLastRenderedPageBreakHints === true && renderedBreakHintPageCount !== void 0 && targetPageCount >= renderedBreakHintPageCount;
5177
- if (options.hasMeasuredBodyFooterOverlap === true) {
5178
- return renderedBreakHintsSupportTarget;
5253
+ if (imageHasMetafileContent(image)) {
5254
+ return void 0;
5179
5255
  }
5180
- if (options.hasLastRenderedPageBreakHints !== true) {
5181
- return true;
5256
+ if (!imageHasTiffContent(image)) {
5257
+ return src;
5182
5258
  }
5183
- return renderedBreakHintsSupportTarget;
5184
- }
5185
- function shouldLatchMeasuredBodyFooterOverlap(options) {
5186
- if (options.measuredBodyFooterOverlap !== true) {
5187
- return false;
5259
+ const cached = convertedTiffSrcCache.get(src);
5260
+ if (cached !== void 0 || convertedTiffSrcCache.has(src)) {
5261
+ return cached;
5188
5262
  }
5189
- const targetPageCount = Number.isFinite(options.targetPageCount) ? Math.max(1, Math.round(options.targetPageCount)) : void 0;
5190
- if (targetPageCount === void 0) {
5191
- return false;
5263
+ let converted;
5264
+ try {
5265
+ const bytes = resolveTiffBytes(image);
5266
+ if (bytes) {
5267
+ converted = convertTiffToPngDataUri(bytes);
5268
+ }
5269
+ } catch {
5270
+ converted = void 0;
5192
5271
  }
5193
- const pageCount = Math.max(1, Math.round(options.pageCount));
5194
- return pageCount <= targetPageCount;
5272
+ convertedTiffSrcCache.set(src, converted);
5273
+ return converted;
5195
5274
  }
5196
- function resolveMeasuredBodyFooterOverlapLatchState(options) {
5197
- const shouldConsiderMeasuredBodyFooterOverlap = shouldLatchMeasuredBodyFooterOverlap({
5198
- pageCount: options.pageCount,
5199
- targetPageCount: options.targetPageCount,
5200
- measuredBodyFooterOverlap: options.overlappingPageIndexes.length > 0
5201
- });
5202
- if (!shouldConsiderMeasuredBodyFooterOverlap) {
5203
- return {
5204
- signature: void 0,
5205
- consecutivePasses: 0,
5206
- shouldLatch: false
5207
- };
5208
- }
5209
- const signature = options.overlappingPageIndexes.map((pageIndex) => `${pageIndex}`).join("|");
5210
- const consecutivePasses = signature === options.previousSignature ? Math.max(0, Math.round(options.previousConsecutivePasses ?? 0)) + 1 : 1;
5211
- const stabilityThreshold = Math.max(
5212
- 1,
5213
- Math.round(options.stabilityThreshold ?? 1)
5214
- );
5215
- return {
5216
- signature,
5217
- consecutivePasses,
5218
- shouldLatch: consecutivePasses >= stabilityThreshold
5275
+ function subscribeRenderableImageSourceUpdates(listener) {
5276
+ void listener;
5277
+ return () => {
5219
5278
  };
5220
5279
  }
5221
- function createEstimatedPagesBuildMemo(build) {
5222
- const entries = [];
5223
- return (measuredTableRowHeightsByNodeIndex, measuredPageContentHeightsPxByPageIndex, strictLastRenderedParagraphStartBreaks) => {
5224
- const cached = entries.find(
5225
- (entry) => entry.measuredTableRowHeightsByNodeIndex === measuredTableRowHeightsByNodeIndex && entry.measuredPageContentHeightsPxByPageIndex === measuredPageContentHeightsPxByPageIndex && entry.strictLastRenderedParagraphStartBreaks === strictLastRenderedParagraphStartBreaks
5226
- );
5227
- if (cached) {
5228
- return cached.pages;
5229
- }
5230
- const pages = build(
5231
- measuredTableRowHeightsByNodeIndex,
5232
- measuredPageContentHeightsPxByPageIndex,
5233
- strictLastRenderedParagraphStartBreaks
5234
- );
5235
- entries.push({
5236
- measuredTableRowHeightsByNodeIndex,
5237
- measuredPageContentHeightsPxByPageIndex,
5238
- strictLastRenderedParagraphStartBreaks,
5239
- pages
5240
- });
5241
- return pages;
5242
- };
5280
+
5281
+ // src/script-fonts.ts
5282
+ init_cjs_shims();
5283
+ var EAST_ASIA_SCRIPT_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Bopomofo}\p{Script=Yi}]/u;
5284
+ var COMPLEX_SCRIPT_RE = /[\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Syriac}\p{Script=Thaana}\p{Script=Nko}\p{Script=Samaritan}\p{Script=Mandaic}\p{Script=Devanagari}\p{Script=Bengali}\p{Script=Gurmukhi}\p{Script=Gujarati}\p{Script=Oriya}\p{Script=Tamil}\p{Script=Telugu}\p{Script=Kannada}\p{Script=Malayalam}\p{Script=Sinhala}\p{Script=Thai}\p{Script=Lao}\p{Script=Tibetan}\p{Script=Myanmar}\p{Script=Khmer}]/u;
5285
+ var NEUTRAL_OR_CONTINUATION_RE = /[\p{Mark}\p{Separator}\p{Punctuation}\u200c\u200d\ufe00-\ufe0f]/u;
5286
+ var EAST_ASIA_LANGUAGE_RE = /^(?:ja|ko|zh)(?:-|$)/i;
5287
+ var COMPLEX_SCRIPT_LANGUAGE_RE = /^(?:ar|ckb|dv|fa|he|hi|ks|ku|pa-arab|ps|sd|syr|ug|ur|yi)(?:-|$)/i;
5288
+ function normalizeFamily(value) {
5289
+ const normalized = value?.trim();
5290
+ return normalized || void 0;
5291
+ }
5292
+ function normalizedFamilyKey(value) {
5293
+ return normalizeFamily(value)?.replace(/^['"]+|['"]+$/g, "").toLowerCase();
5294
+ }
5295
+ function hasLegacyFontFamilyOverride(style) {
5296
+ const current = normalizedFamilyKey(style?.fontFamily);
5297
+ const imported = normalizedFamilyKey(style?.sourceFontFamily);
5298
+ if (!current) {
5299
+ return false;
5300
+ }
5301
+ if (imported) {
5302
+ return current !== imported;
5303
+ }
5304
+ return !(normalizeFamily(style?.fontFamilyAscii) || normalizeFamily(style?.fontFamilyHAnsi) || normalizeFamily(style?.fontFamilyEastAsia) || normalizeFamily(style?.fontFamilyCs) || normalizeFamily(style?.fontThemeAscii) || normalizeFamily(style?.fontThemeHAnsi) || normalizeFamily(style?.fontThemeEastAsia) || normalizeFamily(style?.fontThemeCs));
5305
+ }
5306
+ function normalizedFontHint(style) {
5307
+ return style?.fontHint?.trim().replace(/[-_\s]/g, "").toLowerCase() ?? "";
5243
5308
  }
5244
- function resolveMeasuredSplitParagraphPageComparison(options) {
5245
- if (options.canUndo || options.canRedo || !options.hasMeasuredPageContentHeights) {
5246
- return {
5247
- pages: options.measuredEstimatedPages,
5248
- usedPureEstimatedPages: false
5249
- };
5309
+ function neutralScript(style) {
5310
+ const hint = normalizedFontHint(style);
5311
+ if (hint === "eastasia") {
5312
+ return "eastAsia";
5250
5313
  }
5251
- const measuredPagesAreOnlySplitParagraphs = options.measuredEstimatedPages.length > 0 && options.measuredEstimatedPages.every(
5252
- options.pageContainsOnlySplitParagraphSegments
5253
- );
5254
- if (!measuredPagesAreOnlySplitParagraphs) {
5255
- return {
5256
- pages: options.measuredEstimatedPages,
5257
- usedPureEstimatedPages: false
5258
- };
5314
+ if (hint === "cs" || hint === "complexscript" || hint === "bidi") {
5315
+ return "complexScript";
5259
5316
  }
5260
- const pureEstimatedPages = options.buildPureEstimatedPages();
5261
- const purePagesAreOnlySplitParagraphs = pureEstimatedPages.length > 0 && pureEstimatedPages.every(options.pageContainsOnlySplitParagraphSegments);
5262
- if (purePagesAreOnlySplitParagraphs && pureEstimatedPages.length < options.measuredEstimatedPages.length) {
5263
- return { pages: pureEstimatedPages, usedPureEstimatedPages: true };
5317
+ if (style?.rightToLeft || COMPLEX_SCRIPT_LANGUAGE_RE.test(style?.languageBidi?.trim() ?? "")) {
5318
+ return "complexScript";
5264
5319
  }
5265
- return {
5266
- pages: options.measuredEstimatedPages,
5267
- usedPureEstimatedPages: false
5268
- };
5320
+ if (EAST_ASIA_LANGUAGE_RE.test(style?.languageEastAsia?.trim() ?? "")) {
5321
+ return "eastAsia";
5322
+ }
5323
+ return "highAnsi";
5269
5324
  }
5270
- function isBetterCandidate(candidate, incumbent, targetPageCount) {
5271
- const candidateDifference = Math.abs(candidate.pageCount - targetPageCount);
5272
- const incumbentDifference = Math.abs(incumbent.pageCount - targetPageCount);
5273
- if (candidateDifference !== incumbentDifference) {
5274
- return candidateDifference < incumbentDifference;
5325
+ function classifyDocxFontScript(value, style) {
5326
+ const character = Array.from(value)[0];
5327
+ if (!character) {
5328
+ return void 0;
5275
5329
  }
5276
- const candidateScaleDelta = Math.abs(candidate.scale - 1);
5277
- const incumbentScaleDelta = Math.abs(incumbent.scale - 1);
5278
- if (candidateScaleDelta !== incumbentScaleDelta) {
5279
- return candidateScaleDelta < incumbentScaleDelta;
5330
+ if (style?.complexScript === true || style?.rightToLeft === true && style?.complexScript !== false) {
5331
+ return "complexScript";
5280
5332
  }
5281
- return candidate.pageCount === targetPageCount && incumbent.pageCount !== targetPageCount;
5333
+ const codePoint = character.codePointAt(0) ?? 0;
5334
+ if (codePoint <= 127) {
5335
+ return "ascii";
5336
+ }
5337
+ if (EAST_ASIA_SCRIPT_RE.test(character) || codePoint >= 12288 && codePoint <= 12351 || codePoint >= 65280 && codePoint <= 65519) {
5338
+ return "eastAsia";
5339
+ }
5340
+ if (COMPLEX_SCRIPT_RE.test(character)) {
5341
+ return "complexScript";
5342
+ }
5343
+ if (NEUTRAL_OR_CONTINUATION_RE.test(character)) {
5344
+ return void 0;
5345
+ }
5346
+ return "highAnsi";
5282
5347
  }
5283
- function reconcilePageCountCandidateToTargetCountByScalingHeight(options) {
5284
- const {
5285
- initialPages,
5286
- targetPageCount,
5287
- buildPagesAtScale,
5288
- maxDifference = 3,
5289
- scales: customScales
5290
- } = options;
5291
- const safeTargetPageCount = Math.max(1, Math.round(targetPageCount));
5292
- const initialPageCount = initialPages.length;
5293
- const initialDifference = Math.abs(initialPageCount - safeTargetPageCount);
5294
- if (initialDifference === 0 || initialDifference > maxDifference) {
5295
- return {
5296
- pageCount: initialPageCount,
5297
- pages: initialPages,
5298
- scale: 1
5299
- };
5348
+ function resolveDocxScriptFontFamily(style, script) {
5349
+ const legacyFamily = normalizeFamily(style?.fontFamily);
5350
+ if (hasLegacyFontFamilyOverride(style)) {
5351
+ return legacyFamily;
5300
5352
  }
5301
- const bestCandidate = {
5302
- pageCount: initialPageCount,
5303
- pages: initialPages,
5304
- scale: 1
5305
- };
5306
- let selectedCandidate = bestCandidate;
5307
- const needMorePages = initialPageCount < safeTargetPageCount;
5308
- const scales = customScales && customScales.length > 0 ? customScales : needMorePages ? [
5309
- 0.98,
5310
- 0.96,
5311
- 0.94,
5312
- 0.92,
5313
- 0.9,
5314
- 0.88,
5315
- 0.86,
5316
- 0.84,
5317
- 0.82,
5318
- 0.8,
5319
- 0.78,
5320
- 0.76,
5321
- 0.74,
5322
- 0.72,
5323
- 0.7,
5324
- 0.68,
5325
- 0.66,
5326
- 0.64,
5327
- 0.62,
5328
- 0.6,
5329
- 0.58,
5330
- 0.56,
5331
- 0.54,
5332
- 0.52,
5333
- 0.5,
5334
- 0.48,
5335
- 0.46,
5336
- 0.44,
5337
- 0.42,
5338
- 0.4,
5339
- 0.38,
5340
- 0.36,
5341
- 0.34,
5342
- 0.32,
5343
- 0.3,
5344
- 0.28,
5345
- 0.26,
5346
- 0.24,
5347
- 0.22,
5348
- 0.2
5349
- ] : [
5350
- 1.02,
5351
- 1.04,
5352
- 1.06,
5353
- 1.08,
5354
- 1.1,
5355
- 1.12,
5356
- 1.14,
5357
- 1.16,
5358
- 1.18,
5359
- 1.2,
5360
- 1.22,
5361
- 1.24,
5362
- 1.26,
5363
- 1.28,
5364
- 1.3
5365
- ];
5366
- const buildCandidateAtScale = (scale) => {
5367
- const pages = buildPagesAtScale(scale);
5368
- return {
5369
- pageCount: pages.length,
5370
- pages,
5371
- scale
5372
- };
5373
- };
5374
- const refineExactTargetCandidate = (lowerScale, upperScale) => {
5375
- let bestExactCandidate;
5376
- const interval = upperScale - lowerScale;
5377
- if (!Number.isFinite(interval) || Math.abs(interval) < 1e-4) {
5378
- return selectedCandidate;
5379
- }
5380
- for (let step = 1; step <= PAGE_COUNT_RECONCILIATION_REFINEMENT_STEPS; step += 1) {
5381
- const scale = lowerScale + interval * step / PAGE_COUNT_RECONCILIATION_REFINEMENT_STEPS;
5382
- const candidate = buildCandidateAtScale(scale);
5383
- if (isBetterCandidate(candidate, selectedCandidate, safeTargetPageCount)) {
5384
- selectedCandidate = candidate;
5385
- }
5386
- if (candidate.pageCount === safeTargetPageCount && (bestExactCandidate === void 0 || isBetterCandidate(
5387
- candidate,
5388
- bestExactCandidate,
5389
- safeTargetPageCount
5390
- ))) {
5391
- bestExactCandidate = candidate;
5392
- }
5393
- }
5394
- return bestExactCandidate ?? selectedCandidate;
5395
- };
5396
- let previousScale = 1;
5397
- let previousPageCount = initialPageCount;
5398
- for (const scale of scales) {
5399
- const candidate = buildCandidateAtScale(scale);
5400
- if (isBetterCandidate(candidate, selectedCandidate, safeTargetPageCount)) {
5401
- selectedCandidate = candidate;
5353
+ switch (script) {
5354
+ case "ascii":
5355
+ return normalizeFamily(style?.resolvedFontFamilyAscii) ?? normalizeFamily(style?.fontFamilyAscii) ?? normalizeFamily(style?.resolvedFontFamilyHAnsi) ?? normalizeFamily(style?.fontFamilyHAnsi) ?? legacyFamily;
5356
+ case "highAnsi":
5357
+ return normalizeFamily(style?.resolvedFontFamilyHAnsi) ?? normalizeFamily(style?.fontFamilyHAnsi) ?? normalizeFamily(style?.resolvedFontFamilyAscii) ?? normalizeFamily(style?.fontFamilyAscii) ?? legacyFamily;
5358
+ case "eastAsia":
5359
+ return normalizeFamily(style?.resolvedFontFamilyEastAsia) ?? normalizeFamily(style?.fontFamilyEastAsia) ?? normalizeFamily(style?.resolvedFontFamilyHAnsi) ?? normalizeFamily(style?.fontFamilyHAnsi) ?? normalizeFamily(style?.resolvedFontFamilyAscii) ?? normalizeFamily(style?.fontFamilyAscii) ?? legacyFamily;
5360
+ case "complexScript":
5361
+ return normalizeFamily(style?.resolvedFontFamilyCs) ?? normalizeFamily(style?.fontFamilyCs) ?? normalizeFamily(style?.resolvedFontFamilyHAnsi) ?? normalizeFamily(style?.fontFamilyHAnsi) ?? normalizeFamily(style?.resolvedFontFamilyAscii) ?? normalizeFamily(style?.fontFamilyAscii) ?? legacyFamily;
5362
+ }
5363
+ }
5364
+ function segmentTextByDocxScriptFont(text, style) {
5365
+ if (!text) {
5366
+ return [];
5367
+ }
5368
+ const tokens = [];
5369
+ let offset = 0;
5370
+ for (const character of text) {
5371
+ const startOffset = offset;
5372
+ offset += character.length;
5373
+ tokens.push({
5374
+ text: character,
5375
+ startOffset,
5376
+ endOffset: offset,
5377
+ script: classifyDocxFontScript(character, style)
5378
+ });
5379
+ }
5380
+ const fallbackScript = neutralScript(style);
5381
+ const nextStrongScript = new Array(
5382
+ tokens.length
5383
+ );
5384
+ let nextScript;
5385
+ for (let index = tokens.length - 1; index >= 0; index -= 1) {
5386
+ nextStrongScript[index] = nextScript;
5387
+ if (tokens[index]?.script) {
5388
+ nextScript = tokens[index]?.script;
5402
5389
  }
5403
- if (candidate.pageCount === safeTargetPageCount) {
5404
- const crossedIntoExactTarget = needMorePages ? previousPageCount < safeTargetPageCount : previousPageCount > safeTargetPageCount;
5405
- if (crossedIntoExactTarget) {
5406
- return refineExactTargetCandidate(previousScale, scale);
5407
- }
5408
- return candidate;
5390
+ }
5391
+ let previousScript;
5392
+ for (let index = 0; index < tokens.length; index += 1) {
5393
+ const token = tokens[index];
5394
+ if (!token) {
5395
+ continue;
5409
5396
  }
5410
- previousScale = scale;
5411
- previousPageCount = candidate.pageCount;
5397
+ token.script = token.script ?? previousScript ?? nextStrongScript[index] ?? fallbackScript;
5398
+ previousScript = token.script;
5412
5399
  }
5413
- if (!needMorePages && selectedCandidate.pageCount !== safeTargetPageCount) {
5414
- return {
5415
- pageCount: initialPageCount,
5416
- pages: initialPages,
5417
- scale: 1
5418
- };
5400
+ const segments = [];
5401
+ for (const token of tokens) {
5402
+ const script = token.script ?? fallbackScript;
5403
+ const fontFamily = resolveDocxScriptFontFamily(style, script);
5404
+ const previous = segments[segments.length - 1];
5405
+ if (previous && normalizedFamilyKey(previous.fontFamily) === normalizedFamilyKey(fontFamily)) {
5406
+ previous.text += token.text;
5407
+ previous.endOffset = token.endOffset;
5408
+ continue;
5409
+ }
5410
+ segments.push({
5411
+ text: token.text,
5412
+ startOffset: token.startOffset,
5413
+ endOffset: token.endOffset,
5414
+ script,
5415
+ fontFamily
5416
+ });
5419
5417
  }
5420
- return selectedCandidate;
5418
+ return segments;
5419
+ }
5420
+ function resolveDocxTextFontFamily(text, style) {
5421
+ return segmentTextByDocxScriptFont(text, style).find(
5422
+ (segment) => segment.fontFamily
5423
+ )?.fontFamily ?? normalizeFamily(style?.fontFamily);
5421
5424
  }
5422
5425
 
5423
5426
  // src/editor-transaction-state.ts
@@ -7285,7 +7288,7 @@ var SerialIdleTaskQueue = class {
7285
7288
  if (this.pending.length === 0) {
7286
7289
  return void 0;
7287
7290
  }
7288
- const now = this.now();
7291
+ const now2 = this.now();
7289
7292
  let earliestWaitMs;
7290
7293
  let bestIndex = -1;
7291
7294
  let bestEntry;
@@ -7295,7 +7298,7 @@ var SerialIdleTaskQueue = class {
7295
7298
  continue;
7296
7299
  }
7297
7300
  const lastRunAt = this.lastRunAtByKey.get(candidate.key);
7298
- const waitMs = lastRunAt === void 0 ? 0 : lastRunAt + this.minTaskIntervalMs - now;
7301
+ const waitMs = lastRunAt === void 0 ? 0 : lastRunAt + this.minTaskIntervalMs - now2;
7299
7302
  if (waitMs <= 0) {
7300
7303
  if (!bestEntry || candidate.priority < bestEntry.priority || candidate.priority === bestEntry.priority && candidate.sequence < bestEntry.sequence) {
7301
7304
  bestEntry = candidate;
@@ -23736,11 +23739,16 @@ function useDocxEditor(options = {}) {
23736
23739
  const starterTemplateRef = React.useRef(
23737
23740
  cloneDocModelWithBlockIds(options.starterModel ?? defaultStarterModel)
23738
23741
  );
23742
+ const initialModelRef = React.useRef(
23743
+ cloneDocModelWithBlockIds(
23744
+ options.document?.model ?? starterTemplateRef.current
23745
+ )
23746
+ );
23739
23747
  const [editorState, dispatchCanonicalEditorState] = React.useReducer(
23740
23748
  reduceDocxEditorState,
23741
- starterTemplateRef.current,
23742
- (starterModel) => ({
23743
- model: cloneDocModelWithBlockIds(starterModel),
23749
+ initialModelRef.current,
23750
+ (initialModel) => ({
23751
+ model: cloneDocModelWithBlockIds(initialModel),
23744
23752
  selection: {
23745
23753
  kind: "paragraph",
23746
23754
  nodeIndex: 0
@@ -23826,7 +23834,7 @@ function useDocxEditor(options = {}) {
23826
23834
  },
23827
23835
  [applyCanonicalEditorStateAction]
23828
23836
  );
23829
- const [basePackage, setBasePackage] = React.useState();
23837
+ const [basePackage, setBasePackage] = React.useState(options.document?.package);
23830
23838
  const [documentLoadNonce, setDocumentLoadNonce] = React.useState(0);
23831
23839
  const documentLoadNonceRef = React.useRef(0);
23832
23840
  const advanceDocumentLoadNonce = React.useCallback(() => {
@@ -23834,11 +23842,11 @@ function useDocxEditor(options = {}) {
23834
23842
  setDocumentLoadNonce(documentLoadNonceRef.current);
23835
23843
  }, []);
23836
23844
  const [fileName, setFileName] = React.useState(
23837
- options.initialFileName ?? "(new document)"
23845
+ options.initialFileName ?? options.document?.fileName ?? "(new document)"
23838
23846
  );
23839
23847
  const [selectedFormFieldLocation, setSelectedFormFieldLocation] = React.useState();
23840
23848
  const [status, setStatus] = React.useState(
23841
- options.initialStatus ?? "Ready"
23849
+ options.initialStatus ?? (options.document?.fileName ? `Loaded ${options.document.fileName}` : "Ready")
23842
23850
  );
23843
23851
  const [importError, setImportError] = React.useState();
23844
23852
  const [isImporting, setIsImporting] = React.useState(false);
@@ -24255,6 +24263,16 @@ function useDocxEditor(options = {}) {
24255
24263
  unloadEmbeddedFonts();
24256
24264
  };
24257
24265
  }, [unloadEmbeddedFonts]);
24266
+ React.useEffect(() => {
24267
+ if (!options.document || options.loadEmbeddedFonts === false || options.document.embeddedFontsLoaded) {
24268
+ return;
24269
+ }
24270
+ void loadEmbeddedFontsFromPackage(options.document.package);
24271
+ }, [
24272
+ loadEmbeddedFontsFromPackage,
24273
+ options.document,
24274
+ options.loadEmbeddedFonts
24275
+ ]);
24258
24276
  const dispatchEditorTransaction = React.useCallback(
24259
24277
  (resolver) => {
24260
24278
  const currentState = canonicalEditorStateRef.current;
@@ -27641,7 +27659,7 @@ function useDocxEditor(options = {}) {
27641
27659
  );
27642
27660
  const commitParagraphTextAtRange = React.useCallback(
27643
27661
  (location, text, caret, options2) => {
27644
- const now = Date.now();
27662
+ const now2 = Date.now();
27645
27663
  return dispatchEditorTransaction((current) => {
27646
27664
  const paragraph = getParagraphAtLocation(
27647
27665
  current.model,
@@ -27658,9 +27676,9 @@ function useDocxEditor(options = {}) {
27658
27676
  const coalesce = options2?.coalesceKey !== void 0 && shouldCoalesceTextCommit(textCommitBurstRef.current, {
27659
27677
  key: options2.coalesceKey,
27660
27678
  caretBefore: insertionOffset,
27661
- at: now
27679
+ at: now2
27662
27680
  });
27663
- textCommitBurstRef.current = options2?.coalesceKey !== void 0 ? { key: options2.coalesceKey, caretAfter: caret.end, at: now } : void 0;
27681
+ textCommitBurstRef.current = options2?.coalesceKey !== void 0 ? { key: options2.coalesceKey, caretAfter: caret.end, at: now2 } : void 0;
27664
27682
  return {
27665
27683
  model: nextModel,
27666
27684
  selection: selectionFromTextRangeLocation(location),
@@ -28441,7 +28459,7 @@ function DocxDetachedThumbnailPageSurface({
28441
28459
  {
28442
28460
  editor,
28443
28461
  mode: "read-only",
28444
- visiblePageRange: { startPageIndex: pageIndex, endPageIndex: pageIndex },
28462
+ pageIndexes: [pageIndex],
28445
28463
  pageVirtualization: { enabled: false },
28446
28464
  showTrackedChanges: editor.showTrackedChanges,
28447
28465
  showComments: editor.showComments,
@@ -28458,6 +28476,7 @@ var DocxDetachedThumbnailSurfaceRenderer = class {
28458
28476
  root;
28459
28477
  activePageIndex;
28460
28478
  activeRenderKey;
28479
+ rootGeneration = 0;
28461
28480
  async renderPageSurface(params) {
28462
28481
  if (typeof document === "undefined" || typeof window === "undefined") {
28463
28482
  return void 0;
@@ -28483,16 +28502,24 @@ var DocxDetachedThumbnailSurfaceRenderer = class {
28483
28502
  return this.waitForPageSurface(registry, pageIndex);
28484
28503
  }
28485
28504
  clear() {
28486
- if (this.root) {
28487
- this.root.unmount();
28488
- this.root = void 0;
28489
- }
28490
- if (this.host?.parentNode) {
28491
- this.host.parentNode.removeChild(this.host);
28492
- }
28505
+ const root = this.root;
28506
+ const host = this.host;
28507
+ this.rootGeneration += 1;
28508
+ this.root = void 0;
28493
28509
  this.host = void 0;
28494
28510
  this.activePageIndex = void 0;
28495
28511
  this.activeRenderKey = void 0;
28512
+ const dispose = () => {
28513
+ root?.unmount();
28514
+ if (host?.parentNode) {
28515
+ host.parentNode.removeChild(host);
28516
+ }
28517
+ };
28518
+ if (root && typeof window !== "undefined") {
28519
+ window.setTimeout(dispose, 0);
28520
+ } else {
28521
+ dispose();
28522
+ }
28496
28523
  }
28497
28524
  async ensureRoot() {
28498
28525
  if (this.root) {
@@ -28501,6 +28528,7 @@ var DocxDetachedThumbnailSurfaceRenderer = class {
28501
28528
  if (typeof document === "undefined") {
28502
28529
  return;
28503
28530
  }
28531
+ const generation = this.rootGeneration;
28504
28532
  const host = document.createElement("div");
28505
28533
  host.setAttribute("data-docx-thumbnail-detached-renderer", "true");
28506
28534
  Object.assign(host.style, {
@@ -28517,6 +28545,12 @@ var DocxDetachedThumbnailSurfaceRenderer = class {
28517
28545
  document.body.appendChild(host);
28518
28546
  this.host = host;
28519
28547
  const { createRoot } = await import("react-dom/client");
28548
+ if (generation !== this.rootGeneration) {
28549
+ if (host.parentNode) {
28550
+ host.parentNode.removeChild(host);
28551
+ }
28552
+ return;
28553
+ }
28520
28554
  this.root = createRoot(host);
28521
28555
  }
28522
28556
  async waitForPageSurface(registry, pageIndex) {
@@ -28654,6 +28688,7 @@ function useDocxPageThumbnails(editor, options = {}) {
28654
28688
  const nextThumbnailCanvasQueueIdRef = React.useRef(0);
28655
28689
  const queuedPrefetchThumbnailKeysRef = React.useRef(/* @__PURE__ */ new Set());
28656
28690
  const thumbnailMinRasterIntervalMs = normalizeDocxThumbnailMinRasterIntervalMs(options.minRasterIntervalMs);
28691
+ const defaultThumbnailScheduling = options.scheduling ?? "idle";
28657
28692
  const ensureThumbnailSurfaceCache = React.useCallback(() => {
28658
28693
  if (!thumbnailSurfaceCacheRef.current) {
28659
28694
  thumbnailSurfaceCacheRef.current = new DocxThumbnailSurfaceCache(
@@ -28734,20 +28769,43 @@ function useDocxPageThumbnails(editor, options = {}) {
28734
28769
  [editor.documentTheme, pageSurfaceRegistry, thumbnailResolutionOptionsKey]
28735
28770
  );
28736
28771
  const totalThumbnailPages = Math.max(1, editor.totalPages);
28737
- const visibleThumbnailPageIndexes = React.useMemo(
28738
- () => normalizeDocxThumbnailPageIndexes(
28739
- options.renderWindow?.visiblePageIndexes,
28772
+ const hardThumbnailPageIndexes = React.useMemo(
28773
+ () => options.pageIndexes === void 0 ? void 0 : normalizeDocxThumbnailPageIndexes(
28774
+ options.pageIndexes,
28740
28775
  totalThumbnailPages
28741
28776
  ),
28742
- [options.renderWindow?.visiblePageIndexes, totalThumbnailPages]
28777
+ [options.pageIndexes, totalThumbnailPages]
28743
28778
  );
28744
- const prefetchThumbnailPageIndexes = React.useMemo(
28745
- () => normalizeDocxThumbnailPageIndexes(
28779
+ const hardThumbnailPageIndexSet = React.useMemo(
28780
+ () => hardThumbnailPageIndexes ? new Set(hardThumbnailPageIndexes) : void 0,
28781
+ [hardThumbnailPageIndexes]
28782
+ );
28783
+ const visibleThumbnailPageIndexes = React.useMemo(() => {
28784
+ const normalized = normalizeDocxThumbnailPageIndexes(
28785
+ options.renderWindow?.visiblePageIndexes,
28786
+ totalThumbnailPages
28787
+ );
28788
+ return hardThumbnailPageIndexSet ? normalized.filter(
28789
+ (pageIndex) => hardThumbnailPageIndexSet.has(pageIndex)
28790
+ ) : normalized;
28791
+ }, [
28792
+ hardThumbnailPageIndexSet,
28793
+ options.renderWindow?.visiblePageIndexes,
28794
+ totalThumbnailPages
28795
+ ]);
28796
+ const prefetchThumbnailPageIndexes = React.useMemo(() => {
28797
+ const normalized = normalizeDocxThumbnailPageIndexes(
28746
28798
  options.renderWindow?.prefetchPageIndexes,
28747
28799
  totalThumbnailPages
28748
- ),
28749
- [options.renderWindow?.prefetchPageIndexes, totalThumbnailPages]
28750
- );
28800
+ );
28801
+ return hardThumbnailPageIndexSet ? normalized.filter(
28802
+ (pageIndex) => hardThumbnailPageIndexSet.has(pageIndex)
28803
+ ) : normalized;
28804
+ }, [
28805
+ hardThumbnailPageIndexSet,
28806
+ options.renderWindow?.prefetchPageIndexes,
28807
+ totalThumbnailPages
28808
+ ]);
28751
28809
  const visibleThumbnailPageIndexesKey = docxThumbnailPageIndexesKey(
28752
28810
  visibleThumbnailPageIndexes
28753
28811
  );
@@ -28904,6 +28962,10 @@ function useDocxPageThumbnails(editor, options = {}) {
28904
28962
  await paintIntoTarget();
28905
28963
  return;
28906
28964
  }
28965
+ if ((renderOptions?.scheduling ?? defaultThumbnailScheduling) === "immediate") {
28966
+ await paintIntoTarget();
28967
+ return;
28968
+ }
28907
28969
  await ensureThumbnailRasterQueue().enqueue(
28908
28970
  thumbnailQueueKeyForCanvas(targetCanvas),
28909
28971
  paintIntoTarget,
@@ -28917,6 +28979,7 @@ function useDocxPageThumbnails(editor, options = {}) {
28917
28979
  },
28918
28980
  [
28919
28981
  ensureThumbnailRasterQueue,
28982
+ defaultThumbnailScheduling,
28920
28983
  options.disabled,
28921
28984
  pageSurfaceRegistry,
28922
28985
  renderPageThumbnailSurface,
@@ -29038,7 +29101,8 @@ function useDocxPageThumbnails(editor, options = {}) {
29038
29101
  ]);
29039
29102
  const thumbnailGeometryItems = React.useMemo(() => {
29040
29103
  const totalPages = Math.max(1, editor.totalPages);
29041
- return Array.from({ length: totalPages }, (_, pageIndex) => {
29104
+ const geometryPageIndexes = hardThumbnailPageIndexes ?? Array.from({ length: totalPages }, (_, pageIndex) => pageIndex);
29105
+ return geometryPageIndexes.map((pageIndex) => {
29042
29106
  const pageElement = mountedPageElements.get(pageIndex);
29043
29107
  const sourceSize = pageElement && pageElement.isConnected ? resolveDocxViewerPageSurfaceSize(
29044
29108
  pageElement,
@@ -29092,8 +29156,11 @@ function useDocxPageThumbnails(editor, options = {}) {
29092
29156
  return nextCanvasRef;
29093
29157
  })(),
29094
29158
  renderToCanvas: renderToCanvasCallbacksRef.current.get(pageIndex) ?? (() => {
29095
- const nextRenderToCanvas = async (canvas) => {
29096
- await renderPageThumbnailToCanvasRef.current(pageIndex, canvas);
29159
+ const nextRenderToCanvas = async (canvas, renderOptions) => {
29160
+ await renderPageThumbnailToCanvasRef.current(pageIndex, canvas, {
29161
+ force: renderOptions?.force,
29162
+ scheduling: renderOptions?.scheduling
29163
+ });
29097
29164
  };
29098
29165
  renderToCanvasCallbacksRef.current.set(
29099
29166
  pageIndex,
@@ -29119,6 +29186,7 @@ function useDocxPageThumbnails(editor, options = {}) {
29119
29186
  options.maxHeightPx,
29120
29187
  options.maxWidthPx,
29121
29188
  options.pixelRatio,
29189
+ hardThumbnailPageIndexes,
29122
29190
  pageSurfaceRegistry,
29123
29191
  thumbnailQueueKeyForCanvas
29124
29192
  ]);
@@ -29139,7 +29207,9 @@ function useDocxPageThumbnails(editor, options = {}) {
29139
29207
  if (!canvas || options.disabled) {
29140
29208
  return false;
29141
29209
  }
29142
- const thumbnail = thumbnails[pageIndex];
29210
+ const thumbnail = thumbnails.find(
29211
+ (candidate) => candidate.pageIndex === pageIndex
29212
+ );
29143
29213
  if (!thumbnail) {
29144
29214
  return false;
29145
29215
  }
@@ -30277,6 +30347,7 @@ function DocxEditorViewer({
30277
30347
  loadingState,
30278
30348
  pageVirtualization,
30279
30349
  visiblePageRange,
30350
+ pageIndexes,
30280
30351
  onPageCountChange,
30281
30352
  onRequestPageReveal,
30282
30353
  headingStyles,
@@ -30428,16 +30499,16 @@ function DocxEditorViewer({
30428
30499
  const [embeddedTableColumnWidths, setEmbeddedTableColumnWidths] = React.useState({});
30429
30500
  const handleRepeatedFormFieldClick = React.useCallback(
30430
30501
  (location) => {
30431
- const now = typeof performance !== "undefined" ? performance.now() : Date.now();
30502
+ const now2 = typeof performance !== "undefined" ? performance.now() : Date.now();
30432
30503
  const key = formFieldLocationKey(location);
30433
30504
  const previousClick = lastFormFieldClickRef.current;
30434
- if (previousClick && previousClick.key === key && now - previousClick.time <= 350) {
30505
+ if (previousClick && previousClick.key === key && now2 - previousClick.time <= 350) {
30435
30506
  lastFormFieldClickRef.current = void 0;
30436
30507
  editor.selectFormField(location);
30437
30508
  onFormFieldDoubleClick?.(location);
30438
30509
  return true;
30439
30510
  }
30440
- lastFormFieldClickRef.current = { key, time: now };
30511
+ lastFormFieldClickRef.current = { key, time: now2 };
30441
30512
  return false;
30442
30513
  },
30443
30514
  [editor.selectFormField, formFieldLocationKey, onFormFieldDoubleClick]
@@ -31709,6 +31780,13 @@ function DocxEditorViewer({
31709
31780
  };
31710
31781
  }, [editor.model.nodes, pageNodeSegmentsByPage]);
31711
31782
  const pageCount = pageNodeSegmentsByPage.length;
31783
+ const requestedPageIndexes = React.useMemo(
31784
+ () => normalizeDocxThumbnailPageIndexes(pageIndexes, pageCount).sort(
31785
+ (left, right) => left - right
31786
+ ),
31787
+ [pageCount, pageIndexes]
31788
+ );
31789
+ const hasRequestedPageIndexes = pageIndexes !== void 0;
31712
31790
  const hasLargeTableLayoutSurface = React.useMemo(() => {
31713
31791
  let tableParagraphCount = 0;
31714
31792
  let tableCellCount = 0;
@@ -31803,7 +31881,7 @@ function DocxEditorViewer({
31803
31881
  )
31804
31882
  )
31805
31883
  ) : 0;
31806
- const hasExternalVisiblePageRange = Number.isFinite(Number(visiblePageRange?.startPageIndex)) || Number.isFinite(Number(visiblePageRange?.endPageIndex));
31884
+ const hasExternalVisiblePageRange = hasRequestedPageIndexes || Number.isFinite(Number(visiblePageRange?.startPageIndex)) || Number.isFinite(Number(visiblePageRange?.endPageIndex));
31807
31885
  const [deferInternalPageVirtualization, setDeferInternalPageVirtualization] = React.useState(false);
31808
31886
  const [internalVirtualScrollElement, setInternalVirtualScrollElement] = React.useState(null);
31809
31887
  const [virtualizerMeasurementScale, setVirtualizerMeasurementScale] = React.useState(1);
@@ -32386,9 +32464,12 @@ function DocxEditorViewer({
32386
32464
  const initialPremeasurePageLimit = hasLargeTableLayoutSurface ? Math.min(2, INITIAL_PAGINATION_PREMEASURE_PAGE_LIMIT) : INITIAL_PAGINATION_PREMEASURE_PAGE_LIMIT;
32387
32465
  const initialPremeasureEndPageIndex = hasExternalVisiblePageRange ? normalizedVisiblePageRange.endPageIndex : Math.min(pageCount - 1, initialPremeasurePageLimit - 1);
32388
32466
  const measureAllPagesBeforeInitialReveal = hideDocumentUntilPaginationSettled && pageCount > 0 && initialPremeasureStartPageIndex === 0 && initialPremeasureEndPageIndex >= pageCount - 1;
32389
- const visiblePageStartIndex = measureAllPagesBeforeInitialReveal ? 0 : hideDocumentUntilPaginationSettled ? initialPremeasureStartPageIndex : normalizedVisiblePageRange.startPageIndex;
32390
- const visiblePageEndIndex = measureAllPagesBeforeInitialReveal ? pageCount - 1 : hideDocumentUntilPaginationSettled ? initialPremeasureEndPageIndex : normalizedVisiblePageRange.endPageIndex;
32467
+ const visiblePageStartIndex = hasRequestedPageIndexes ? requestedPageIndexes[0] ?? 0 : measureAllPagesBeforeInitialReveal ? 0 : hideDocumentUntilPaginationSettled ? initialPremeasureStartPageIndex : normalizedVisiblePageRange.startPageIndex;
32468
+ const visiblePageEndIndex = hasRequestedPageIndexes ? requestedPageIndexes[requestedPageIndexes.length - 1] ?? -1 : measureAllPagesBeforeInitialReveal ? pageCount - 1 : hideDocumentUntilPaginationSettled ? initialPremeasureEndPageIndex : normalizedVisiblePageRange.endPageIndex;
32391
32469
  const visiblePageIndexes = React.useMemo(() => {
32470
+ if (hasRequestedPageIndexes) {
32471
+ return requestedPageIndexes;
32472
+ }
32392
32473
  if (pageCount <= 0 || visiblePageEndIndex < visiblePageStartIndex) {
32393
32474
  return [];
32394
32475
  }
@@ -32397,7 +32478,13 @@ function DocxEditorViewer({
32397
32478
  indexes.push(pageIndex);
32398
32479
  }
32399
32480
  return indexes;
32400
- }, [pageCount, visiblePageEndIndex, visiblePageStartIndex]);
32481
+ }, [
32482
+ hasRequestedPageIndexes,
32483
+ pageCount,
32484
+ requestedPageIndexes,
32485
+ visiblePageEndIndex,
32486
+ visiblePageStartIndex
32487
+ ]);
32401
32488
  const pageStackVirtualSpacers = React.useMemo(() => {
32402
32489
  const pageWrapperWidthPxForIndex = (pageIndex) => {
32403
32490
  const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
@@ -32827,9 +32914,14 @@ function DocxEditorViewer({
32827
32914
  ]);
32828
32915
  const isPageVisible = React.useCallback(
32829
32916
  (pageIndex) => {
32830
- return pageIndex >= visiblePageStartIndex && pageIndex <= visiblePageEndIndex;
32917
+ return hasRequestedPageIndexes ? requestedPageIndexes.includes(pageIndex) : pageIndex >= visiblePageStartIndex && pageIndex <= visiblePageEndIndex;
32831
32918
  },
32832
- [visiblePageEndIndex, visiblePageStartIndex]
32919
+ [
32920
+ hasRequestedPageIndexes,
32921
+ requestedPageIndexes,
32922
+ visiblePageEndIndex,
32923
+ visiblePageStartIndex
32924
+ ]
32833
32925
  );
32834
32926
  const requestPageReveal = React.useCallback(
32835
32927
  (targetPageIndex) => {
@@ -49380,6 +49472,224 @@ ${currentText.slice(end)}`;
49380
49472
  );
49381
49473
  }
49382
49474
 
49475
+ // src/parsed-docx.ts
49476
+ init_cjs_shims();
49477
+ function now() {
49478
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
49479
+ }
49480
+ function xmlAttribute3(xml, name) {
49481
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
49482
+ return xml.match(new RegExp(`${escapedName}="([^"]*)"`, "i"))?.[1];
49483
+ }
49484
+ function relationshipPartName(partName) {
49485
+ const segments = partName.split("/");
49486
+ const name = segments.pop() ?? partName;
49487
+ const directory = segments.join("/");
49488
+ return directory ? `${directory}/_rels/${name}.rels` : `_rels/${name}.rels`;
49489
+ }
49490
+ function resolveRelativePartName(basePartName, target) {
49491
+ if (/^[a-z]+:/i.test(target)) {
49492
+ return target;
49493
+ }
49494
+ if (target.startsWith("/")) {
49495
+ return target.replace(/^\/+/, "");
49496
+ }
49497
+ const segments = basePartName.replace(/^\/+/, "").split("/");
49498
+ segments.pop();
49499
+ target.split("/").forEach((segment) => {
49500
+ if (!segment || segment === ".") {
49501
+ return;
49502
+ }
49503
+ if (segment === "..") {
49504
+ segments.pop();
49505
+ return;
49506
+ }
49507
+ segments.push(segment);
49508
+ });
49509
+ return segments.join("/");
49510
+ }
49511
+ function parseRelationships(pkg, partName) {
49512
+ const relationships = /* @__PURE__ */ new Map();
49513
+ const xml = pkg.parts.get(relationshipPartName(partName))?.content;
49514
+ if (!xml) {
49515
+ return relationships;
49516
+ }
49517
+ const pattern = /<Relationship\b[^>]*Id="([^"]+)"[^>]*Target="([^"]+)"[^>]*\/?>/gi;
49518
+ let match;
49519
+ while (match = pattern.exec(xml)) {
49520
+ const id = match[1]?.trim();
49521
+ const target = match[2]?.trim();
49522
+ if (id && target) {
49523
+ relationships.set(id, resolveRelativePartName(partName, target));
49524
+ }
49525
+ }
49526
+ return relationships;
49527
+ }
49528
+ function deobfuscateFontData(data, key) {
49529
+ const output = Uint8Array.from(data);
49530
+ const normalizedKey = (key ?? "").replace(/[{}-]/g, "");
49531
+ if (/^[0-9a-f]{32}$/i.test(normalizedKey)) {
49532
+ const keyBytes = Uint8Array.from(
49533
+ normalizedKey.match(/../g)?.map((pair) => Number.parseInt(pair, 16)) ?? []
49534
+ ).reverse();
49535
+ const length = Math.min(32, output.length);
49536
+ for (let index = 0; index < length; index += 1) {
49537
+ output[index] ^= keyBytes[index % keyBytes.length] ?? 0;
49538
+ }
49539
+ }
49540
+ return output.buffer.slice(
49541
+ output.byteOffset,
49542
+ output.byteOffset + output.byteLength
49543
+ );
49544
+ }
49545
+ function embeddedFontDescriptors(pkg) {
49546
+ const partName = "word/fontTable.xml";
49547
+ const xml = pkg.parts.get(partName)?.content;
49548
+ if (!xml) {
49549
+ return [];
49550
+ }
49551
+ const relationships = parseRelationships(pkg, partName);
49552
+ const descriptors = [];
49553
+ const fontPattern = /<w:font\b[^>]*w:name="([^"]+)"[^>]*>([\s\S]*?)<\/w:font>/gi;
49554
+ const variants = [
49555
+ { tag: "embedRegular", style: "normal", weight: "400" },
49556
+ { tag: "embedBold", style: "normal", weight: "700" },
49557
+ { tag: "embedItalic", style: "italic", weight: "400" },
49558
+ { tag: "embedBoldItalic", style: "italic", weight: "700" }
49559
+ ];
49560
+ let fontMatch;
49561
+ while (fontMatch = fontPattern.exec(xml)) {
49562
+ const family = fontMatch[1]?.trim();
49563
+ const fontXml = fontMatch[2] ?? "";
49564
+ if (!family) {
49565
+ continue;
49566
+ }
49567
+ variants.forEach((variant) => {
49568
+ const tagXml = fontXml.match(new RegExp(`<w:${variant.tag}\\b[^>]*\\/?>`, "i"))?.[0] ?? "";
49569
+ const relationshipId = xmlAttribute3(tagXml, "r:id");
49570
+ const resolvedPartName = relationshipId ? relationships.get(relationshipId) : void 0;
49571
+ const data = resolvedPartName ? pkg.binaryAssets.get(resolvedPartName) : void 0;
49572
+ if (!data) {
49573
+ return;
49574
+ }
49575
+ descriptors.push({
49576
+ family,
49577
+ style: variant.style,
49578
+ weight: variant.weight,
49579
+ source: deobfuscateFontData(data, xmlAttribute3(tagXml, "w:fontKey"))
49580
+ });
49581
+ });
49582
+ }
49583
+ return descriptors;
49584
+ }
49585
+ async function sourceToArrayBuffer(source) {
49586
+ if (source instanceof ArrayBuffer) {
49587
+ return source;
49588
+ }
49589
+ if (ArrayBuffer.isView(source)) {
49590
+ return source.buffer.slice(
49591
+ source.byteOffset,
49592
+ source.byteOffset + source.byteLength
49593
+ );
49594
+ }
49595
+ return source.arrayBuffer();
49596
+ }
49597
+ async function parseDocxForViewer(source, options = {}) {
49598
+ const startedAt = now();
49599
+ const readStartedAt = now();
49600
+ const buffer = await sourceToArrayBuffer(source);
49601
+ const readFinishedAt = now();
49602
+ const importResult = await importDocxBuffer(buffer, {
49603
+ signal: options.signal,
49604
+ transferBuffer: options.transferBuffer,
49605
+ useWorker: options.useWorker
49606
+ });
49607
+ const importFinishedAt = now();
49608
+ let faces = [];
49609
+ let fontLoadingMs = 0;
49610
+ let fontLoadingComplete = false;
49611
+ let fontLoadPromise;
49612
+ const dispose = () => {
49613
+ if (typeof document !== "undefined" && "fonts" in document) {
49614
+ faces.forEach((face) => {
49615
+ try {
49616
+ document.fonts.delete(face);
49617
+ } catch {
49618
+ }
49619
+ });
49620
+ }
49621
+ faces = [];
49622
+ };
49623
+ const loadEmbeddedFonts = () => {
49624
+ if (fontLoadPromise) {
49625
+ return fontLoadPromise;
49626
+ }
49627
+ fontLoadPromise = (async () => {
49628
+ if (typeof document === "undefined" || !("fonts" in document) || typeof FontFace === "undefined") {
49629
+ fontLoadingComplete = true;
49630
+ return;
49631
+ }
49632
+ const fontStartedAt = now();
49633
+ const loaded = (await Promise.all(
49634
+ embeddedFontDescriptors(importResult.package).map(
49635
+ async (descriptor) => {
49636
+ try {
49637
+ const face = new FontFace(
49638
+ descriptor.family,
49639
+ descriptor.source,
49640
+ {
49641
+ style: descriptor.style,
49642
+ weight: descriptor.weight
49643
+ }
49644
+ );
49645
+ await face.load();
49646
+ return face;
49647
+ } catch {
49648
+ return void 0;
49649
+ }
49650
+ }
49651
+ )
49652
+ )).filter((face) => Boolean(face));
49653
+ loaded.forEach((face) => document.fonts.add(face));
49654
+ faces = loaded;
49655
+ try {
49656
+ await document.fonts.ready;
49657
+ } catch {
49658
+ }
49659
+ fontLoadingMs += now() - fontStartedAt;
49660
+ fontLoadingComplete = true;
49661
+ })();
49662
+ return fontLoadPromise;
49663
+ };
49664
+ if (options.loadEmbeddedFonts !== false && options.loadEmbeddedFonts !== "defer") {
49665
+ await loadEmbeddedFonts();
49666
+ }
49667
+ const nonFontTotalMs = importFinishedAt - startedAt;
49668
+ const timings = {
49669
+ fileReadMs: readFinishedAt - readStartedAt,
49670
+ parseMs: importResult.timings?.parseMs ?? importFinishedAt - readFinishedAt,
49671
+ modelConstructionMs: importResult.timings?.buildModelMs ?? 0,
49672
+ get fontLoadingMs() {
49673
+ return fontLoadingMs;
49674
+ },
49675
+ get totalMs() {
49676
+ return nonFontTotalMs + fontLoadingMs;
49677
+ }
49678
+ };
49679
+ return {
49680
+ model: importResult.model,
49681
+ package: importResult.package,
49682
+ source: importResult.source,
49683
+ fileName: options.fileName ?? (typeof File !== "undefined" && source instanceof File ? source.name : void 0),
49684
+ timings,
49685
+ get embeddedFontsLoaded() {
49686
+ return fontLoadingComplete;
49687
+ },
49688
+ loadEmbeddedFonts,
49689
+ dispose
49690
+ };
49691
+ }
49692
+
49383
49693
  // src/index.tsx
49384
49694
  init_src2();
49385
49695
  init_src3();
@@ -51169,6 +51479,9 @@ function renderBlock(block) {
51169
51479
  function ReactDocxViewer({
51170
51480
  file,
51171
51481
  model,
51482
+ document: document2,
51483
+ loadEmbeddedFonts = true,
51484
+ pageIndexes,
51172
51485
  className,
51173
51486
  layoutOptions,
51174
51487
  emptyState
@@ -51177,8 +51490,13 @@ function ReactDocxViewer({
51177
51490
  model: parsedModel,
51178
51491
  isLoading,
51179
51492
  error
51180
- } = useDocxModel(model ? void 0 : file);
51181
- const resolvedModel = model ?? parsedModel;
51493
+ } = useDocxModel(model || document2 ? void 0 : file);
51494
+ const resolvedModel = model ?? document2?.model ?? parsedModel;
51495
+ React2.useEffect(() => {
51496
+ if (document2 && loadEmbeddedFonts && !document2.embeddedFontsLoaded) {
51497
+ void document2.loadEmbeddedFonts();
51498
+ }
51499
+ }, [document2, loadEmbeddedFonts]);
51182
51500
  const modelWithSections = React2.useMemo(() => {
51183
51501
  if (!resolvedModel) {
51184
51502
  return void 0;
@@ -51210,6 +51528,12 @@ function ReactDocxViewer({
51210
51528
  }
51211
51529
  return layoutDocument(modelWithSections, resolvedLayoutOptions);
51212
51530
  }, [modelWithSections, resolvedLayoutOptions]);
51531
+ const requestedPageIndexSet = React2.useMemo(
51532
+ () => pageIndexes === void 0 ? void 0 : new Set(
51533
+ pageIndexes.filter((pageIndex) => Number.isFinite(pageIndex)).map((pageIndex) => Math.trunc(pageIndex))
51534
+ ),
51535
+ [pageIndexes]
51536
+ );
51213
51537
  if (isLoading) {
51214
51538
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className, children: "Loading DOCX..." });
51215
51539
  }
@@ -51231,29 +51555,288 @@ function ReactDocxViewer({
51231
51555
  className,
51232
51556
  "data-testid": "react-docx-viewer",
51233
51557
  style: containerStyle,
51234
- children: pages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
51235
- "section",
51236
- {
51237
- "data-page": page.number,
51238
- style: {
51239
- width: pageWidth,
51240
- minHeight: pageHeight,
51241
- boxSizing: "border-box",
51242
- padding: pagePadding,
51243
- background: "#fff",
51244
- border: "1px solid #d4d4d4",
51245
- boxShadow: "0 8px 24px rgba(0, 0, 0, 0.08)",
51246
- display: "grid",
51247
- gap: 8,
51248
- alignContent: "start"
51558
+ children: pages.map(
51559
+ (page, pageIndex) => requestedPageIndexSet && !requestedPageIndexSet.has(pageIndex) ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
51560
+ "section",
51561
+ {
51562
+ "data-page": page.number,
51563
+ "data-page-index": pageIndex,
51564
+ style: {
51565
+ width: pageWidth,
51566
+ minHeight: pageHeight,
51567
+ boxSizing: "border-box",
51568
+ padding: pagePadding,
51569
+ background: "#fff",
51570
+ border: "1px solid #d4d4d4",
51571
+ boxShadow: "0 8px 24px rgba(0, 0, 0, 0.08)",
51572
+ display: "grid",
51573
+ gap: 8,
51574
+ alignContent: "start"
51575
+ },
51576
+ children: page.blocks.map(renderBlock)
51249
51577
  },
51250
- children: page.blocks.map(renderBlock)
51251
- },
51252
- page.number
51253
- ))
51578
+ page.number
51579
+ )
51580
+ )
51254
51581
  }
51255
51582
  );
51256
51583
  }
51584
+ function thumbnailNow() {
51585
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
51586
+ }
51587
+ function canvasToBlob(canvas, mimeType, quality) {
51588
+ return new Promise((resolve, reject) => {
51589
+ canvas.toBlob(
51590
+ (blob) => {
51591
+ if (blob) {
51592
+ resolve(blob);
51593
+ } else {
51594
+ reject(new Error("Failed to encode DOCX thumbnail."));
51595
+ }
51596
+ },
51597
+ mimeType,
51598
+ quality
51599
+ );
51600
+ });
51601
+ }
51602
+ function createDocxThumbnailRenderer(documentModel, options = {}) {
51603
+ const model = "model" in documentModel ? documentModel.model : documentModel;
51604
+ const layout = resolveDocumentLayout(model);
51605
+ const layoutOptions = {
51606
+ pageWidth: layout.pageWidthPx,
51607
+ pageHeight: layout.pageHeightPx
51608
+ };
51609
+ const headerNodes = model.metadata.headerSections[0]?.nodes ?? [];
51610
+ const footerNodes = model.metadata.footerSections[0]?.nodes ?? [];
51611
+ const paginationStartedAt = thumbnailNow();
51612
+ const builtPageSegments = buildDocumentPageNodeSegments(
51613
+ model,
51614
+ Math.max(
51615
+ 120,
51616
+ layout.pageHeightPx - layout.marginsPx.top - layout.marginsPx.bottom
51617
+ ),
51618
+ Math.max(
51619
+ 120,
51620
+ layout.pageWidthPx - layout.marginsPx.left - layout.marginsPx.right
51621
+ ),
51622
+ model.metadata.numberingDefinitions
51623
+ );
51624
+ const pageSegments = builtPageSegments.length > 0 ? builtPageSegments : [[]];
51625
+ const paginationMs = thumbnailNow() - paginationStartedAt;
51626
+ const pageLayoutCache = /* @__PURE__ */ new Map();
51627
+ const layoutPage = (pageIndex) => {
51628
+ const cached = pageLayoutCache.get(pageIndex);
51629
+ if (cached) {
51630
+ return { page: cached, paginationMs: 0 };
51631
+ }
51632
+ const startedAt = thumbnailNow();
51633
+ const nodeIndexes = new Set(
51634
+ (pageSegments[pageIndex] ?? []).map((segment) => segment.nodeIndex)
51635
+ );
51636
+ const pageModel = {
51637
+ ...model,
51638
+ nodes: [
51639
+ ...headerNodes,
51640
+ ...model.nodes.filter(
51641
+ (_, nodeIndex) => nodeIndexes.has(nodeIndex)
51642
+ ),
51643
+ ...footerNodes
51644
+ ]
51645
+ };
51646
+ const page = layoutDocument(pageModel, layoutOptions)[0];
51647
+ if (!page) {
51648
+ throw new RangeError(`DOCX page index ${pageIndex} is unavailable.`);
51649
+ }
51650
+ pageLayoutCache.set(pageIndex, page);
51651
+ return { page, paginationMs: thumbnailNow() - startedAt };
51652
+ };
51653
+ const allowedPageIndexes = options.pageIndexes === void 0 ? void 0 : new Set(
51654
+ options.pageIndexes.filter((pageIndex) => Number.isFinite(pageIndex)).map((pageIndex) => Math.trunc(pageIndex))
51655
+ );
51656
+ const queue = new SerialIdleTaskQueue({ minTaskIntervalMs: 0 });
51657
+ let host;
51658
+ let root;
51659
+ let rootPromise;
51660
+ let requestId = 0;
51661
+ let disposed = false;
51662
+ const ensureRoot = async () => {
51663
+ if (disposed) {
51664
+ throw new Error("DOCX thumbnail renderer has been disposed.");
51665
+ }
51666
+ if (root) {
51667
+ return root;
51668
+ }
51669
+ if (!rootPromise) {
51670
+ rootPromise = (async () => {
51671
+ if (typeof document === "undefined") {
51672
+ throw new Error("DOCX thumbnail rendering requires a browser DOM.");
51673
+ }
51674
+ const nextHost = document.createElement("div");
51675
+ nextHost.setAttribute("data-docx-thumbnail-renderer", "true");
51676
+ Object.assign(nextHost.style, {
51677
+ position: "fixed",
51678
+ left: "-100000px",
51679
+ top: "0",
51680
+ overflow: "visible",
51681
+ pointerEvents: "none"
51682
+ });
51683
+ document.body.appendChild(nextHost);
51684
+ host = nextHost;
51685
+ const { createRoot } = await import("react-dom/client");
51686
+ const nextRoot = createRoot(nextHost);
51687
+ if (disposed) {
51688
+ nextRoot.unmount();
51689
+ nextHost.remove();
51690
+ throw new Error("DOCX thumbnail renderer has been disposed.");
51691
+ }
51692
+ root = nextRoot;
51693
+ return root;
51694
+ })();
51695
+ }
51696
+ return rootPromise;
51697
+ };
51698
+ const renderImmediately = async (pageIndex, renderOptions) => {
51699
+ const startedAt = thumbnailNow();
51700
+ if (!Number.isInteger(pageIndex) || pageIndex < 0 || pageIndex >= pageSegments.length) {
51701
+ throw new RangeError(`DOCX page index ${pageIndex} is out of range.`);
51702
+ }
51703
+ if (allowedPageIndexes && !allowedPageIndexes.has(pageIndex)) {
51704
+ throw new RangeError(`DOCX page index ${pageIndex} was not requested.`);
51705
+ }
51706
+ const resolvedPage = layoutPage(pageIndex);
51707
+ const renderPaginationMs = paginationMs + resolvedPage.paginationMs;
51708
+ const pageMountStartedAt = thumbnailNow();
51709
+ const activeRoot = await ensureRoot();
51710
+ (0, import_react_dom2.flushSync)(() => {
51711
+ activeRoot.render(
51712
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
51713
+ "section",
51714
+ {
51715
+ "data-docx-thumbnail-page-index": pageIndex,
51716
+ style: {
51717
+ width: layout.pageWidthPx,
51718
+ minHeight: layout.pageHeightPx,
51719
+ boxSizing: "border-box",
51720
+ padding: `${layout.marginsPx.top}px ${layout.marginsPx.right}px ${layout.marginsPx.bottom}px ${layout.marginsPx.left}px`,
51721
+ background: "#fff",
51722
+ display: "grid",
51723
+ gap: 8,
51724
+ alignContent: "start"
51725
+ },
51726
+ children: resolvedPage.page.blocks.map(renderBlock)
51727
+ }
51728
+ )
51729
+ );
51730
+ });
51731
+ const pageElement = host?.querySelector(
51732
+ `[data-docx-thumbnail-page-index="${pageIndex}"]`
51733
+ );
51734
+ if (!pageElement) {
51735
+ throw new Error("Failed to mount the requested DOCX page.");
51736
+ }
51737
+ const pageMountMs = thumbnailNow() - pageMountStartedAt;
51738
+ const resolution = resolveDocxPageThumbnailResolution({
51739
+ sourceWidthPx: layout.pageWidthPx,
51740
+ sourceHeightPx: layout.pageHeightPx,
51741
+ resolution: renderOptions.resolution ?? options.resolution,
51742
+ maxWidthPx: renderOptions.maxWidth,
51743
+ maxHeightPx: renderOptions.maxHeight,
51744
+ pixelRatio: renderOptions.pixelRatio ?? options.pixelRatio
51745
+ });
51746
+ const rasterStartedAt = thumbnailNow();
51747
+ const surface = await rasterizeDocxThumbnailSurface({
51748
+ pageElement,
51749
+ sourceWidthPx: layout.pageWidthPx,
51750
+ sourceHeightPx: layout.pageHeightPx,
51751
+ widthPx: resolution.widthPx,
51752
+ heightPx: resolution.heightPx,
51753
+ pixelWidthPx: resolution.pixelWidthPx,
51754
+ pixelHeightPx: resolution.pixelHeightPx
51755
+ });
51756
+ const rasterizationMs = thumbnailNow() - rasterStartedAt;
51757
+ const output = renderOptions.output ?? "canvas";
51758
+ const outputCanvas = renderOptions.canvas ?? surface;
51759
+ if (outputCanvas !== surface) {
51760
+ blitDocxThumbnailSurface(surface, outputCanvas, resolution);
51761
+ }
51762
+ const encodingStartedAt = thumbnailNow();
51763
+ let blob;
51764
+ let imageBitmap;
51765
+ if (output === "blob") {
51766
+ blob = await canvasToBlob(
51767
+ outputCanvas,
51768
+ renderOptions.mimeType ?? "image/png",
51769
+ renderOptions.quality
51770
+ );
51771
+ } else if (output === "imageBitmap") {
51772
+ if (typeof createImageBitmap !== "function") {
51773
+ throw new Error("ImageBitmap output is not supported in this browser.");
51774
+ }
51775
+ imageBitmap = await createImageBitmap(outputCanvas);
51776
+ }
51777
+ const encodingMs = thumbnailNow() - encodingStartedAt;
51778
+ return {
51779
+ pageIndex,
51780
+ pageCount: pageSegments.length,
51781
+ width: resolution.widthPx,
51782
+ height: resolution.heightPx,
51783
+ pixelWidth: resolution.pixelWidthPx,
51784
+ pixelHeight: resolution.pixelHeightPx,
51785
+ output,
51786
+ canvas: output === "canvas" ? outputCanvas : void 0,
51787
+ blob,
51788
+ imageBitmap,
51789
+ timings: {
51790
+ paginationMs: renderPaginationMs,
51791
+ pageMountMs,
51792
+ rasterizationMs,
51793
+ encodingMs,
51794
+ totalMs: paginationMs + thumbnailNow() - startedAt
51795
+ }
51796
+ };
51797
+ };
51798
+ return {
51799
+ document: documentModel,
51800
+ pageCount: pageSegments.length,
51801
+ renderPage(pageIndex, renderOptions = {}) {
51802
+ const scheduling = renderOptions.scheduling ?? options.scheduling ?? "idle";
51803
+ if (scheduling === "immediate") {
51804
+ return renderImmediately(pageIndex, renderOptions);
51805
+ }
51806
+ requestId += 1;
51807
+ let result;
51808
+ let failure;
51809
+ return queue.enqueue(
51810
+ `page:${pageIndex}:${requestId}`,
51811
+ async () => {
51812
+ try {
51813
+ result = await renderImmediately(pageIndex, renderOptions);
51814
+ } catch (error) {
51815
+ failure = error;
51816
+ }
51817
+ },
51818
+ { priority: 0 }
51819
+ ).then(() => {
51820
+ if (failure) {
51821
+ throw failure;
51822
+ }
51823
+ if (!result) {
51824
+ throw new Error("DOCX thumbnail request was cancelled.");
51825
+ }
51826
+ return result;
51827
+ });
51828
+ },
51829
+ dispose() {
51830
+ disposed = true;
51831
+ queue.clear();
51832
+ root?.unmount();
51833
+ root = void 0;
51834
+ rootPromise = void 0;
51835
+ host?.remove();
51836
+ host = void 0;
51837
+ }
51838
+ };
51839
+ }
51257
51840
  // Annotate the CommonJS export names for ESM import in node:
51258
51841
  0 && (module.exports = {
51259
51842
  DEFAULT_MIN_PARAGRAPH_LINE_HEIGHT_PX,
@@ -51278,6 +51861,7 @@ function ReactDocxViewer({
51278
51861
  collectTableExplicitPageBreakInfo,
51279
51862
  collectTopLevelExplicitPageBreakStartNodeIndexes,
51280
51863
  copyParagraphs,
51864
+ createDocxThumbnailRenderer,
51281
51865
  createMinimalDocxPackage,
51282
51866
  createParagraphComment,
51283
51867
  deepFreezeDocModel,
@@ -51300,6 +51884,7 @@ function ReactDocxViewer({
51300
51884
  paragraphLetterheadFloatSideAtNodeIndex,
51301
51885
  paragraphStartsWithLastRenderedPageBreak,
51302
51886
  parseDocx,
51887
+ parseDocxForViewer,
51303
51888
  parseParagraphsFromClipboard,
51304
51889
  parseSectionLayout,
51305
51890
  pasteParagraphs,