@extend-ai/react-docx 0.8.4 → 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 };
4979
4961
  }
4980
- function mergeCellParagraphTexts(paragraphTexts, boundaryParagraphIndex) {
4981
- if (boundaryParagraphIndex <= 0 || boundaryParagraphIndex >= paragraphTexts.length) {
4962
+ function normalizeHexColor(value) {
4963
+ if (!value) {
4982
4964
  return void 0;
4983
4965
  }
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;
4966
+ const normalized = value.trim();
4967
+ if (!normalized || normalized.toLowerCase() === "auto") {
4968
+ return void 0;
4993
4969
  }
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;
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;
4977
+ }
4978
+ function borderTypeToCssStyle(rawType) {
4979
+ const value = rawType?.trim().toLowerCase();
4980
+ if (!value || value === "none" || value === "nil") {
4981
+ return void 0;
4982
+ }
4983
+ if (value === "double") {
4984
+ return "double";
4985
+ }
4986
+ if (value === "dashed" || value === "dashsmallgap" || value === "dotdash" || value === "dotdotdash") {
4987
+ return "dashed";
4988
+ }
4989
+ if (value === "dotted") {
4990
+ return "dotted";
5001
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;
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);
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;
5230
+ }
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;
5247
+ }
5248
+ function resolveRenderableImageSource(image) {
5249
+ const src = normalizeImageSrc(image);
5250
+ if (!src) {
5251
+ return void 0;
5252
+ }
5253
+ if (imageHasMetafileContent(image)) {
5254
+ return void 0;
5255
+ }
5256
+ if (!imageHasTiffContent(image)) {
5257
+ return src;
5258
+ }
5259
+ const cached = convertedTiffSrcCache.get(src);
5260
+ if (cached !== void 0 || convertedTiffSrcCache.has(src)) {
5261
+ return cached;
5262
+ }
5263
+ let converted;
5264
+ try {
5265
+ const bytes = resolveTiffBytes(image);
5266
+ if (bytes) {
5267
+ converted = convertTiffToPngDataUri(bytes);
5156
5268
  }
5269
+ } catch {
5270
+ converted = void 0;
5157
5271
  }
5158
- return breaks;
5272
+ convertedTiffSrcCache.set(src, converted);
5273
+ return converted;
5274
+ }
5275
+ function subscribeRenderableImageSourceUpdates(listener) {
5276
+ void listener;
5277
+ return () => {
5278
+ };
5159
5279
  }
5160
5280
 
5161
- // src/page-count-reconciliation.ts
5281
+ // src/script-fonts.ts
5162
5282
  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;
5172
- }
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;
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;
5179
5300
  }
5180
- if (options.hasLastRenderedPageBreakHints !== true) {
5181
- return true;
5301
+ if (imported) {
5302
+ return current !== imported;
5182
5303
  }
5183
- return renderedBreakHintsSupportTarget;
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));
5184
5305
  }
5185
- function shouldLatchMeasuredBodyFooterOverlap(options) {
5186
- if (options.measuredBodyFooterOverlap !== true) {
5187
- return false;
5306
+ function normalizedFontHint(style) {
5307
+ return style?.fontHint?.trim().replace(/[-_\s]/g, "").toLowerCase() ?? "";
5308
+ }
5309
+ function neutralScript(style) {
5310
+ const hint = normalizedFontHint(style);
5311
+ if (hint === "eastasia") {
5312
+ return "eastAsia";
5188
5313
  }
5189
- const targetPageCount = Number.isFinite(options.targetPageCount) ? Math.max(1, Math.round(options.targetPageCount)) : void 0;
5190
- if (targetPageCount === void 0) {
5191
- return false;
5314
+ if (hint === "cs" || hint === "complexscript" || hint === "bidi") {
5315
+ return "complexScript";
5316
+ }
5317
+ if (style?.rightToLeft || COMPLEX_SCRIPT_LANGUAGE_RE.test(style?.languageBidi?.trim() ?? "")) {
5318
+ return "complexScript";
5319
+ }
5320
+ if (EAST_ASIA_LANGUAGE_RE.test(style?.languageEastAsia?.trim() ?? "")) {
5321
+ return "eastAsia";
5192
5322
  }
5193
- const pageCount = Math.max(1, Math.round(options.pageCount));
5194
- return pageCount <= targetPageCount;
5323
+ return "highAnsi";
5195
5324
  }
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
- };
5325
+ function classifyDocxFontScript(value, style) {
5326
+ const character = Array.from(value)[0];
5327
+ if (!character) {
5328
+ return void 0;
5208
5329
  }
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
5219
- };
5220
- }
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
- };
5243
- }
5244
- function resolveMeasuredSplitParagraphPageComparison(options) {
5245
- if (options.canUndo || options.canRedo || !options.hasMeasuredPageContentHeights) {
5246
- return {
5247
- pages: options.measuredEstimatedPages,
5248
- usedPureEstimatedPages: false
5249
- };
5330
+ if (style?.complexScript === true || style?.rightToLeft === true && style?.complexScript !== false) {
5331
+ return "complexScript";
5250
5332
  }
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
- };
5333
+ const codePoint = character.codePointAt(0) ?? 0;
5334
+ if (codePoint <= 127) {
5335
+ return "ascii";
5259
5336
  }
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 };
5337
+ if (EAST_ASIA_SCRIPT_RE.test(character) || codePoint >= 12288 && codePoint <= 12351 || codePoint >= 65280 && codePoint <= 65519) {
5338
+ return "eastAsia";
5264
5339
  }
5265
- return {
5266
- pages: options.measuredEstimatedPages,
5267
- usedPureEstimatedPages: false
5268
- };
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";
5269
5347
  }
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;
5348
+ function resolveDocxScriptFontFamily(style, script) {
5349
+ const legacyFamily = normalizeFamily(style?.fontFamily);
5350
+ if (hasLegacyFontFamilyOverride(style)) {
5351
+ return legacyFamily;
5275
5352
  }
5276
- const candidateScaleDelta = Math.abs(candidate.scale - 1);
5277
- const incumbentScaleDelta = Math.abs(incumbent.scale - 1);
5278
- if (candidateScaleDelta !== incumbentScaleDelta) {
5279
- return candidateScaleDelta < incumbentScaleDelta;
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;
5280
5362
  }
5281
- return candidate.pageCount === targetPageCount && incumbent.pageCount !== targetPageCount;
5282
5363
  }
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
- };
5364
+ function segmentTextByDocxScriptFont(text, style) {
5365
+ if (!text) {
5366
+ return [];
5300
5367
  }
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;
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,
@@ -28670,6 +28688,7 @@ function useDocxPageThumbnails(editor, options = {}) {
28670
28688
  const nextThumbnailCanvasQueueIdRef = React.useRef(0);
28671
28689
  const queuedPrefetchThumbnailKeysRef = React.useRef(/* @__PURE__ */ new Set());
28672
28690
  const thumbnailMinRasterIntervalMs = normalizeDocxThumbnailMinRasterIntervalMs(options.minRasterIntervalMs);
28691
+ const defaultThumbnailScheduling = options.scheduling ?? "idle";
28673
28692
  const ensureThumbnailSurfaceCache = React.useCallback(() => {
28674
28693
  if (!thumbnailSurfaceCacheRef.current) {
28675
28694
  thumbnailSurfaceCacheRef.current = new DocxThumbnailSurfaceCache(
@@ -28750,20 +28769,43 @@ function useDocxPageThumbnails(editor, options = {}) {
28750
28769
  [editor.documentTheme, pageSurfaceRegistry, thumbnailResolutionOptionsKey]
28751
28770
  );
28752
28771
  const totalThumbnailPages = Math.max(1, editor.totalPages);
28753
- const visibleThumbnailPageIndexes = React.useMemo(
28754
- () => normalizeDocxThumbnailPageIndexes(
28755
- options.renderWindow?.visiblePageIndexes,
28772
+ const hardThumbnailPageIndexes = React.useMemo(
28773
+ () => options.pageIndexes === void 0 ? void 0 : normalizeDocxThumbnailPageIndexes(
28774
+ options.pageIndexes,
28756
28775
  totalThumbnailPages
28757
28776
  ),
28758
- [options.renderWindow?.visiblePageIndexes, totalThumbnailPages]
28777
+ [options.pageIndexes, totalThumbnailPages]
28778
+ );
28779
+ const hardThumbnailPageIndexSet = React.useMemo(
28780
+ () => hardThumbnailPageIndexes ? new Set(hardThumbnailPageIndexes) : void 0,
28781
+ [hardThumbnailPageIndexes]
28759
28782
  );
28760
- const prefetchThumbnailPageIndexes = React.useMemo(
28761
- () => normalizeDocxThumbnailPageIndexes(
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(
28762
28798
  options.renderWindow?.prefetchPageIndexes,
28763
28799
  totalThumbnailPages
28764
- ),
28765
- [options.renderWindow?.prefetchPageIndexes, totalThumbnailPages]
28766
- );
28800
+ );
28801
+ return hardThumbnailPageIndexSet ? normalized.filter(
28802
+ (pageIndex) => hardThumbnailPageIndexSet.has(pageIndex)
28803
+ ) : normalized;
28804
+ }, [
28805
+ hardThumbnailPageIndexSet,
28806
+ options.renderWindow?.prefetchPageIndexes,
28807
+ totalThumbnailPages
28808
+ ]);
28767
28809
  const visibleThumbnailPageIndexesKey = docxThumbnailPageIndexesKey(
28768
28810
  visibleThumbnailPageIndexes
28769
28811
  );
@@ -28920,6 +28962,10 @@ function useDocxPageThumbnails(editor, options = {}) {
28920
28962
  await paintIntoTarget();
28921
28963
  return;
28922
28964
  }
28965
+ if ((renderOptions?.scheduling ?? defaultThumbnailScheduling) === "immediate") {
28966
+ await paintIntoTarget();
28967
+ return;
28968
+ }
28923
28969
  await ensureThumbnailRasterQueue().enqueue(
28924
28970
  thumbnailQueueKeyForCanvas(targetCanvas),
28925
28971
  paintIntoTarget,
@@ -28933,6 +28979,7 @@ function useDocxPageThumbnails(editor, options = {}) {
28933
28979
  },
28934
28980
  [
28935
28981
  ensureThumbnailRasterQueue,
28982
+ defaultThumbnailScheduling,
28936
28983
  options.disabled,
28937
28984
  pageSurfaceRegistry,
28938
28985
  renderPageThumbnailSurface,
@@ -29054,7 +29101,8 @@ function useDocxPageThumbnails(editor, options = {}) {
29054
29101
  ]);
29055
29102
  const thumbnailGeometryItems = React.useMemo(() => {
29056
29103
  const totalPages = Math.max(1, editor.totalPages);
29057
- return Array.from({ length: totalPages }, (_, pageIndex) => {
29104
+ const geometryPageIndexes = hardThumbnailPageIndexes ?? Array.from({ length: totalPages }, (_, pageIndex) => pageIndex);
29105
+ return geometryPageIndexes.map((pageIndex) => {
29058
29106
  const pageElement = mountedPageElements.get(pageIndex);
29059
29107
  const sourceSize = pageElement && pageElement.isConnected ? resolveDocxViewerPageSurfaceSize(
29060
29108
  pageElement,
@@ -29108,8 +29156,11 @@ function useDocxPageThumbnails(editor, options = {}) {
29108
29156
  return nextCanvasRef;
29109
29157
  })(),
29110
29158
  renderToCanvas: renderToCanvasCallbacksRef.current.get(pageIndex) ?? (() => {
29111
- const nextRenderToCanvas = async (canvas) => {
29112
- 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
+ });
29113
29164
  };
29114
29165
  renderToCanvasCallbacksRef.current.set(
29115
29166
  pageIndex,
@@ -29135,6 +29186,7 @@ function useDocxPageThumbnails(editor, options = {}) {
29135
29186
  options.maxHeightPx,
29136
29187
  options.maxWidthPx,
29137
29188
  options.pixelRatio,
29189
+ hardThumbnailPageIndexes,
29138
29190
  pageSurfaceRegistry,
29139
29191
  thumbnailQueueKeyForCanvas
29140
29192
  ]);
@@ -29155,7 +29207,9 @@ function useDocxPageThumbnails(editor, options = {}) {
29155
29207
  if (!canvas || options.disabled) {
29156
29208
  return false;
29157
29209
  }
29158
- const thumbnail = thumbnails[pageIndex];
29210
+ const thumbnail = thumbnails.find(
29211
+ (candidate) => candidate.pageIndex === pageIndex
29212
+ );
29159
29213
  if (!thumbnail) {
29160
29214
  return false;
29161
29215
  }
@@ -30293,6 +30347,7 @@ function DocxEditorViewer({
30293
30347
  loadingState,
30294
30348
  pageVirtualization,
30295
30349
  visiblePageRange,
30350
+ pageIndexes,
30296
30351
  onPageCountChange,
30297
30352
  onRequestPageReveal,
30298
30353
  headingStyles,
@@ -30444,16 +30499,16 @@ function DocxEditorViewer({
30444
30499
  const [embeddedTableColumnWidths, setEmbeddedTableColumnWidths] = React.useState({});
30445
30500
  const handleRepeatedFormFieldClick = React.useCallback(
30446
30501
  (location) => {
30447
- const now = typeof performance !== "undefined" ? performance.now() : Date.now();
30502
+ const now2 = typeof performance !== "undefined" ? performance.now() : Date.now();
30448
30503
  const key = formFieldLocationKey(location);
30449
30504
  const previousClick = lastFormFieldClickRef.current;
30450
- if (previousClick && previousClick.key === key && now - previousClick.time <= 350) {
30505
+ if (previousClick && previousClick.key === key && now2 - previousClick.time <= 350) {
30451
30506
  lastFormFieldClickRef.current = void 0;
30452
30507
  editor.selectFormField(location);
30453
30508
  onFormFieldDoubleClick?.(location);
30454
30509
  return true;
30455
30510
  }
30456
- lastFormFieldClickRef.current = { key, time: now };
30511
+ lastFormFieldClickRef.current = { key, time: now2 };
30457
30512
  return false;
30458
30513
  },
30459
30514
  [editor.selectFormField, formFieldLocationKey, onFormFieldDoubleClick]
@@ -31725,6 +31780,13 @@ function DocxEditorViewer({
31725
31780
  };
31726
31781
  }, [editor.model.nodes, pageNodeSegmentsByPage]);
31727
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;
31728
31790
  const hasLargeTableLayoutSurface = React.useMemo(() => {
31729
31791
  let tableParagraphCount = 0;
31730
31792
  let tableCellCount = 0;
@@ -31819,7 +31881,7 @@ function DocxEditorViewer({
31819
31881
  )
31820
31882
  )
31821
31883
  ) : 0;
31822
- 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));
31823
31885
  const [deferInternalPageVirtualization, setDeferInternalPageVirtualization] = React.useState(false);
31824
31886
  const [internalVirtualScrollElement, setInternalVirtualScrollElement] = React.useState(null);
31825
31887
  const [virtualizerMeasurementScale, setVirtualizerMeasurementScale] = React.useState(1);
@@ -32402,9 +32464,12 @@ function DocxEditorViewer({
32402
32464
  const initialPremeasurePageLimit = hasLargeTableLayoutSurface ? Math.min(2, INITIAL_PAGINATION_PREMEASURE_PAGE_LIMIT) : INITIAL_PAGINATION_PREMEASURE_PAGE_LIMIT;
32403
32465
  const initialPremeasureEndPageIndex = hasExternalVisiblePageRange ? normalizedVisiblePageRange.endPageIndex : Math.min(pageCount - 1, initialPremeasurePageLimit - 1);
32404
32466
  const measureAllPagesBeforeInitialReveal = hideDocumentUntilPaginationSettled && pageCount > 0 && initialPremeasureStartPageIndex === 0 && initialPremeasureEndPageIndex >= pageCount - 1;
32405
- const visiblePageStartIndex = measureAllPagesBeforeInitialReveal ? 0 : hideDocumentUntilPaginationSettled ? initialPremeasureStartPageIndex : normalizedVisiblePageRange.startPageIndex;
32406
- 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;
32407
32469
  const visiblePageIndexes = React.useMemo(() => {
32470
+ if (hasRequestedPageIndexes) {
32471
+ return requestedPageIndexes;
32472
+ }
32408
32473
  if (pageCount <= 0 || visiblePageEndIndex < visiblePageStartIndex) {
32409
32474
  return [];
32410
32475
  }
@@ -32413,7 +32478,13 @@ function DocxEditorViewer({
32413
32478
  indexes.push(pageIndex);
32414
32479
  }
32415
32480
  return indexes;
32416
- }, [pageCount, visiblePageEndIndex, visiblePageStartIndex]);
32481
+ }, [
32482
+ hasRequestedPageIndexes,
32483
+ pageCount,
32484
+ requestedPageIndexes,
32485
+ visiblePageEndIndex,
32486
+ visiblePageStartIndex
32487
+ ]);
32417
32488
  const pageStackVirtualSpacers = React.useMemo(() => {
32418
32489
  const pageWrapperWidthPxForIndex = (pageIndex) => {
32419
32490
  const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
@@ -32843,9 +32914,14 @@ function DocxEditorViewer({
32843
32914
  ]);
32844
32915
  const isPageVisible = React.useCallback(
32845
32916
  (pageIndex) => {
32846
- return pageIndex >= visiblePageStartIndex && pageIndex <= visiblePageEndIndex;
32917
+ return hasRequestedPageIndexes ? requestedPageIndexes.includes(pageIndex) : pageIndex >= visiblePageStartIndex && pageIndex <= visiblePageEndIndex;
32847
32918
  },
32848
- [visiblePageEndIndex, visiblePageStartIndex]
32919
+ [
32920
+ hasRequestedPageIndexes,
32921
+ requestedPageIndexes,
32922
+ visiblePageEndIndex,
32923
+ visiblePageStartIndex
32924
+ ]
32849
32925
  );
32850
32926
  const requestPageReveal = React.useCallback(
32851
32927
  (targetPageIndex) => {
@@ -49396,6 +49472,224 @@ ${currentText.slice(end)}`;
49396
49472
  );
49397
49473
  }
49398
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
+
49399
49693
  // src/index.tsx
49400
49694
  init_src2();
49401
49695
  init_src3();
@@ -51185,6 +51479,9 @@ function renderBlock(block) {
51185
51479
  function ReactDocxViewer({
51186
51480
  file,
51187
51481
  model,
51482
+ document: document2,
51483
+ loadEmbeddedFonts = true,
51484
+ pageIndexes,
51188
51485
  className,
51189
51486
  layoutOptions,
51190
51487
  emptyState
@@ -51193,8 +51490,13 @@ function ReactDocxViewer({
51193
51490
  model: parsedModel,
51194
51491
  isLoading,
51195
51492
  error
51196
- } = useDocxModel(model ? void 0 : file);
51197
- 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]);
51198
51500
  const modelWithSections = React2.useMemo(() => {
51199
51501
  if (!resolvedModel) {
51200
51502
  return void 0;
@@ -51226,6 +51528,12 @@ function ReactDocxViewer({
51226
51528
  }
51227
51529
  return layoutDocument(modelWithSections, resolvedLayoutOptions);
51228
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
+ );
51229
51537
  if (isLoading) {
51230
51538
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className, children: "Loading DOCX..." });
51231
51539
  }
@@ -51247,29 +51555,288 @@ function ReactDocxViewer({
51247
51555
  className,
51248
51556
  "data-testid": "react-docx-viewer",
51249
51557
  style: containerStyle,
51250
- children: pages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
51251
- "section",
51252
- {
51253
- "data-page": page.number,
51254
- style: {
51255
- width: pageWidth,
51256
- minHeight: pageHeight,
51257
- boxSizing: "border-box",
51258
- padding: pagePadding,
51259
- background: "#fff",
51260
- border: "1px solid #d4d4d4",
51261
- boxShadow: "0 8px 24px rgba(0, 0, 0, 0.08)",
51262
- display: "grid",
51263
- gap: 8,
51264
- 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)
51265
51577
  },
51266
- children: page.blocks.map(renderBlock)
51267
- },
51268
- page.number
51269
- ))
51578
+ page.number
51579
+ )
51580
+ )
51270
51581
  }
51271
51582
  );
51272
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
+ }
51273
51840
  // Annotate the CommonJS export names for ESM import in node:
51274
51841
  0 && (module.exports = {
51275
51842
  DEFAULT_MIN_PARAGRAPH_LINE_HEIGHT_PX,
@@ -51294,6 +51861,7 @@ function ReactDocxViewer({
51294
51861
  collectTableExplicitPageBreakInfo,
51295
51862
  collectTopLevelExplicitPageBreakStartNodeIndexes,
51296
51863
  copyParagraphs,
51864
+ createDocxThumbnailRenderer,
51297
51865
  createMinimalDocxPackage,
51298
51866
  createParagraphComment,
51299
51867
  deepFreezeDocModel,
@@ -51316,6 +51884,7 @@ function ReactDocxViewer({
51316
51884
  paragraphLetterheadFloatSideAtNodeIndex,
51317
51885
  paragraphStartsWithLastRenderedPageBreak,
51318
51886
  parseDocx,
51887
+ parseDocxForViewer,
51319
51888
  parseParagraphsFromClipboard,
51320
51889
  parseSectionLayout,
51321
51890
  pasteParagraphs,