@extend-ai/react-docx 0.7.0-alpha.6 → 0.7.0-alpha.8
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/README.md +11 -8
- package/dist/index.cjs +1330 -123
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +1330 -123
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4403,6 +4403,14 @@ var THUMBNAIL_EXCLUDED_CLONE_SELECTOR = [
|
|
|
4403
4403
|
var THUMBNAIL_IMAGE_DOWNSCALE_MIN_DATA_URI_LENGTH = 32768;
|
|
4404
4404
|
var THUMBNAIL_IMAGE_DOWNSCALE_MAX_DIMENSION_PX = 512;
|
|
4405
4405
|
var THUMBNAIL_IMAGE_JPEG_QUALITY = 0.78;
|
|
4406
|
+
var THUMBNAIL_DIRECT_DEFAULT_FONT_FAMILY = "Calibri, Arial, sans-serif";
|
|
4407
|
+
var THUMBNAIL_DIRECT_DEFAULT_TEXT_COLOR = "#111827";
|
|
4408
|
+
var THUMBNAIL_DIRECT_TABLE_BORDER_COLOR = "#d1d5db";
|
|
4409
|
+
var THUMBNAIL_DIRECT_IMAGE_BACKGROUND = "#f3f4f6";
|
|
4410
|
+
var THUMBNAIL_DIRECT_MAX_ELEMENTS = 320;
|
|
4411
|
+
var THUMBNAIL_DIRECT_MAX_TEXT_CHARS = 640;
|
|
4412
|
+
var THUMBNAIL_DIRECT_MAX_LINES = 14;
|
|
4413
|
+
var THUMBNAIL_DIRECT_MAX_LAYOUT_LINES = 80;
|
|
4406
4414
|
function thumbnailSvgDataUri(svg) {
|
|
4407
4415
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
4408
4416
|
}
|
|
@@ -4466,6 +4474,346 @@ function getDownscaledThumbnailImageDataUri(src) {
|
|
|
4466
4474
|
downscaledThumbnailImageCache.set(src, pending);
|
|
4467
4475
|
return pending;
|
|
4468
4476
|
}
|
|
4477
|
+
function directThumbnailPositivePx(value, fallback = 1) {
|
|
4478
|
+
return Number.isFinite(value) && value > 0 ? Math.max(1, Number(value)) : fallback;
|
|
4479
|
+
}
|
|
4480
|
+
function setCanvasFillStyle(context, color, fallback) {
|
|
4481
|
+
try {
|
|
4482
|
+
context.fillStyle = color || fallback;
|
|
4483
|
+
} catch {
|
|
4484
|
+
context.fillStyle = fallback;
|
|
4485
|
+
}
|
|
4486
|
+
}
|
|
4487
|
+
function setCanvasStrokeStyle(context, color, fallback) {
|
|
4488
|
+
try {
|
|
4489
|
+
context.strokeStyle = color || fallback;
|
|
4490
|
+
} catch {
|
|
4491
|
+
context.strokeStyle = fallback;
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
function directThumbnailFont(run, fallbackFontSizePx) {
|
|
4495
|
+
const fontSizePx = Math.max(
|
|
4496
|
+
6,
|
|
4497
|
+
Math.min(
|
|
4498
|
+
36,
|
|
4499
|
+
Math.round(
|
|
4500
|
+
directThumbnailPositivePx(run?.fontSizePx, fallbackFontSizePx)
|
|
4501
|
+
)
|
|
4502
|
+
)
|
|
4503
|
+
);
|
|
4504
|
+
const fontStyle = run?.italic ? "italic " : "";
|
|
4505
|
+
const fontWeight = run?.bold ? "700 " : "";
|
|
4506
|
+
return `${fontStyle}${fontWeight}${fontSizePx}px ${run?.fontFamily || THUMBNAIL_DIRECT_DEFAULT_FONT_FAMILY}`;
|
|
4507
|
+
}
|
|
4508
|
+
var THUMBNAIL_DIRECT_TOKEN_REGEX = /(\r\n|\n|\t|[^\S\r\n\t]+|[^\s\r\n\t]+)/g;
|
|
4509
|
+
var THUMBNAIL_DIRECT_LEADING_WHITESPACE_REGEX = /^\s/;
|
|
4510
|
+
var THUMBNAIL_DIRECT_TEXT_MEASURE_CACHE_MAX_ENTRIES = 4096;
|
|
4511
|
+
var directThumbnailTextMeasureCache = /* @__PURE__ */ new Map();
|
|
4512
|
+
function measureDirectThumbnailToken(context, font, text) {
|
|
4513
|
+
if (!text) {
|
|
4514
|
+
return 0;
|
|
4515
|
+
}
|
|
4516
|
+
const cacheKey = `${font}\0${text}`;
|
|
4517
|
+
const cached = directThumbnailTextMeasureCache.get(cacheKey);
|
|
4518
|
+
if (cached !== void 0) {
|
|
4519
|
+
return cached;
|
|
4520
|
+
}
|
|
4521
|
+
const width = context.measureText(text).width;
|
|
4522
|
+
if (directThumbnailTextMeasureCache.size >= THUMBNAIL_DIRECT_TEXT_MEASURE_CACHE_MAX_ENTRIES) {
|
|
4523
|
+
const oldestKey = directThumbnailTextMeasureCache.keys().next().value;
|
|
4524
|
+
if (oldestKey !== void 0) {
|
|
4525
|
+
directThumbnailTextMeasureCache.delete(oldestKey);
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
directThumbnailTextMeasureCache.set(cacheKey, width);
|
|
4529
|
+
return width;
|
|
4530
|
+
}
|
|
4531
|
+
function appendDirectThumbnailTextLine(lines, currentSegments, currentWidthPx) {
|
|
4532
|
+
const line = {
|
|
4533
|
+
segments: currentSegments,
|
|
4534
|
+
widthPx: currentWidthPx
|
|
4535
|
+
};
|
|
4536
|
+
lines.push(line);
|
|
4537
|
+
return line;
|
|
4538
|
+
}
|
|
4539
|
+
function layoutDirectThumbnailTextRuns(params) {
|
|
4540
|
+
const { context, runs, fallbackFontSizePx } = params;
|
|
4541
|
+
const widthPx = Math.max(1, params.widthPx);
|
|
4542
|
+
const maxLineCount = Math.max(
|
|
4543
|
+
1,
|
|
4544
|
+
Math.min(THUMBNAIL_DIRECT_MAX_LAYOUT_LINES, params.maxLineCount)
|
|
4545
|
+
);
|
|
4546
|
+
const lines = [];
|
|
4547
|
+
let currentSegments = [];
|
|
4548
|
+
let currentWidthPx = 0;
|
|
4549
|
+
let remainingChars = THUMBNAIL_DIRECT_MAX_TEXT_CHARS;
|
|
4550
|
+
const flushLine = () => {
|
|
4551
|
+
appendDirectThumbnailTextLine(lines, currentSegments, currentWidthPx);
|
|
4552
|
+
currentSegments = [];
|
|
4553
|
+
currentWidthPx = 0;
|
|
4554
|
+
};
|
|
4555
|
+
for (const run of runs) {
|
|
4556
|
+
if (lines.length >= maxLineCount || remainingChars <= 0) {
|
|
4557
|
+
break;
|
|
4558
|
+
}
|
|
4559
|
+
const text = run.text.slice(0, remainingChars);
|
|
4560
|
+
remainingChars -= text.length;
|
|
4561
|
+
const runFont = directThumbnailFont(run, fallbackFontSizePx);
|
|
4562
|
+
context.font = runFont;
|
|
4563
|
+
const tokens = text.match(THUMBNAIL_DIRECT_TOKEN_REGEX) ?? [];
|
|
4564
|
+
for (const token of tokens) {
|
|
4565
|
+
if (lines.length >= maxLineCount) {
|
|
4566
|
+
break;
|
|
4567
|
+
}
|
|
4568
|
+
if (token === "\n" || token === "\r\n") {
|
|
4569
|
+
flushLine();
|
|
4570
|
+
continue;
|
|
4571
|
+
}
|
|
4572
|
+
const drawableToken = token === " " ? " " : token;
|
|
4573
|
+
const tokenWidthPx = measureDirectThumbnailToken(
|
|
4574
|
+
context,
|
|
4575
|
+
runFont,
|
|
4576
|
+
drawableToken
|
|
4577
|
+
);
|
|
4578
|
+
const tokenIsWhitespace = THUMBNAIL_DIRECT_LEADING_WHITESPACE_REGEX.test(drawableToken);
|
|
4579
|
+
if (currentSegments.length > 0 && currentWidthPx + tokenWidthPx > widthPx && !tokenIsWhitespace) {
|
|
4580
|
+
flushLine();
|
|
4581
|
+
}
|
|
4582
|
+
if (currentSegments.length === 0 && tokenIsWhitespace) {
|
|
4583
|
+
continue;
|
|
4584
|
+
}
|
|
4585
|
+
currentSegments.push({
|
|
4586
|
+
run,
|
|
4587
|
+
text: drawableToken,
|
|
4588
|
+
widthPx: tokenWidthPx,
|
|
4589
|
+
font: runFont
|
|
4590
|
+
});
|
|
4591
|
+
currentWidthPx += tokenWidthPx;
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4594
|
+
if (currentSegments.length > 0 || lines.length === 0) {
|
|
4595
|
+
flushLine();
|
|
4596
|
+
}
|
|
4597
|
+
return lines;
|
|
4598
|
+
}
|
|
4599
|
+
function directThumbnailAlignedX(params) {
|
|
4600
|
+
const { xPx, widthPx, lineWidthPx, align } = params;
|
|
4601
|
+
if (align === "center") {
|
|
4602
|
+
return xPx + Math.max(0, (widthPx - lineWidthPx) / 2);
|
|
4603
|
+
}
|
|
4604
|
+
if (align === "right") {
|
|
4605
|
+
return xPx + Math.max(0, widthPx - lineWidthPx);
|
|
4606
|
+
}
|
|
4607
|
+
return xPx;
|
|
4608
|
+
}
|
|
4609
|
+
function drawDirectThumbnailTextRuns(params) {
|
|
4610
|
+
const {
|
|
4611
|
+
context,
|
|
4612
|
+
runs,
|
|
4613
|
+
xPx,
|
|
4614
|
+
yPx,
|
|
4615
|
+
widthPx,
|
|
4616
|
+
heightPx,
|
|
4617
|
+
align,
|
|
4618
|
+
startLineIndex
|
|
4619
|
+
} = params;
|
|
4620
|
+
const safeWidthPx = Math.max(1, widthPx);
|
|
4621
|
+
const safeHeightPx = Math.max(1, heightPx);
|
|
4622
|
+
const fallbackFontSizePx = Math.max(
|
|
4623
|
+
7,
|
|
4624
|
+
Math.min(
|
|
4625
|
+
20,
|
|
4626
|
+
Math.round(
|
|
4627
|
+
runs.find((run) => Number.isFinite(run.fontSizePx))?.fontSizePx ?? 12
|
|
4628
|
+
)
|
|
4629
|
+
)
|
|
4630
|
+
);
|
|
4631
|
+
const lineHeightPx = Math.max(
|
|
4632
|
+
fallbackFontSizePx + 1,
|
|
4633
|
+
Math.round(params.lineHeightPx ?? fallbackFontSizePx * 1.25)
|
|
4634
|
+
);
|
|
4635
|
+
const skippedLineCount = Math.max(
|
|
4636
|
+
0,
|
|
4637
|
+
Math.min(THUMBNAIL_DIRECT_MAX_LAYOUT_LINES - 1, Math.trunc(startLineIndex ?? 0))
|
|
4638
|
+
);
|
|
4639
|
+
const visibleLineCount = Math.max(
|
|
4640
|
+
1,
|
|
4641
|
+
Math.min(
|
|
4642
|
+
THUMBNAIL_DIRECT_MAX_LINES,
|
|
4643
|
+
Math.ceil(safeHeightPx / Math.max(1, lineHeightPx)) + 1
|
|
4644
|
+
)
|
|
4645
|
+
);
|
|
4646
|
+
const lines = layoutDirectThumbnailTextRuns({
|
|
4647
|
+
context,
|
|
4648
|
+
runs,
|
|
4649
|
+
widthPx: safeWidthPx,
|
|
4650
|
+
fallbackFontSizePx,
|
|
4651
|
+
maxLineCount: skippedLineCount + visibleLineCount
|
|
4652
|
+
}).slice(skippedLineCount, skippedLineCount + visibleLineCount);
|
|
4653
|
+
context.save();
|
|
4654
|
+
context.beginPath();
|
|
4655
|
+
context.rect(xPx, yPx, safeWidthPx, safeHeightPx);
|
|
4656
|
+
context.clip();
|
|
4657
|
+
context.textBaseline = "alphabetic";
|
|
4658
|
+
let lastAppliedFont;
|
|
4659
|
+
lines.forEach((line, lineIndex) => {
|
|
4660
|
+
const lineTopPx = yPx + lineIndex * lineHeightPx;
|
|
4661
|
+
if (lineTopPx > yPx + safeHeightPx) {
|
|
4662
|
+
return;
|
|
4663
|
+
}
|
|
4664
|
+
let cursorXPx = directThumbnailAlignedX({
|
|
4665
|
+
xPx,
|
|
4666
|
+
widthPx: safeWidthPx,
|
|
4667
|
+
lineWidthPx: line.widthPx,
|
|
4668
|
+
align
|
|
4669
|
+
});
|
|
4670
|
+
const baselineYPx = lineTopPx + Math.max(1, Math.round(lineHeightPx * 0.78));
|
|
4671
|
+
line.segments.forEach((segment) => {
|
|
4672
|
+
const segmentWidthPx = segment.widthPx;
|
|
4673
|
+
if (segment.run.backgroundColor) {
|
|
4674
|
+
setCanvasFillStyle(context, segment.run.backgroundColor, "transparent");
|
|
4675
|
+
context.fillRect(cursorXPx, lineTopPx + 1, segmentWidthPx, lineHeightPx);
|
|
4676
|
+
}
|
|
4677
|
+
if (segment.font !== lastAppliedFont) {
|
|
4678
|
+
context.font = segment.font;
|
|
4679
|
+
lastAppliedFont = segment.font;
|
|
4680
|
+
}
|
|
4681
|
+
setCanvasFillStyle(
|
|
4682
|
+
context,
|
|
4683
|
+
segment.run.color,
|
|
4684
|
+
THUMBNAIL_DIRECT_DEFAULT_TEXT_COLOR
|
|
4685
|
+
);
|
|
4686
|
+
context.fillText(segment.text, cursorXPx, baselineYPx);
|
|
4687
|
+
cursorXPx += segmentWidthPx;
|
|
4688
|
+
});
|
|
4689
|
+
});
|
|
4690
|
+
context.restore();
|
|
4691
|
+
}
|
|
4692
|
+
function drawDirectThumbnailParagraph(context, paragraph) {
|
|
4693
|
+
const xPx = Math.round(paragraph.xPx);
|
|
4694
|
+
const yPx = Math.round(paragraph.yPx);
|
|
4695
|
+
const widthPx = Math.max(1, Math.round(paragraph.widthPx));
|
|
4696
|
+
const heightPx = Math.max(1, Math.round(paragraph.heightPx));
|
|
4697
|
+
if (paragraph.backgroundColor) {
|
|
4698
|
+
setCanvasFillStyle(context, paragraph.backgroundColor, "transparent");
|
|
4699
|
+
context.fillRect(xPx, yPx, widthPx, heightPx);
|
|
4700
|
+
}
|
|
4701
|
+
drawDirectThumbnailTextRuns({
|
|
4702
|
+
context,
|
|
4703
|
+
runs: paragraph.runs,
|
|
4704
|
+
xPx: xPx + 1,
|
|
4705
|
+
yPx,
|
|
4706
|
+
widthPx: Math.max(1, widthPx - 2),
|
|
4707
|
+
heightPx,
|
|
4708
|
+
align: paragraph.align,
|
|
4709
|
+
lineHeightPx: paragraph.lineHeightPx,
|
|
4710
|
+
startLineIndex: paragraph.startLineIndex
|
|
4711
|
+
});
|
|
4712
|
+
}
|
|
4713
|
+
function drawDirectThumbnailImagePlaceholder(context, image, hairlineSourcePx) {
|
|
4714
|
+
const xPx = Math.round(image.xPx);
|
|
4715
|
+
const yPx = Math.round(image.yPx);
|
|
4716
|
+
const widthPx = Math.max(1, Math.round(image.widthPx));
|
|
4717
|
+
const heightPx = Math.max(1, Math.round(image.heightPx));
|
|
4718
|
+
setCanvasFillStyle(
|
|
4719
|
+
context,
|
|
4720
|
+
image.backgroundColor,
|
|
4721
|
+
THUMBNAIL_DIRECT_IMAGE_BACKGROUND
|
|
4722
|
+
);
|
|
4723
|
+
context.fillRect(xPx, yPx, widthPx, heightPx);
|
|
4724
|
+
setCanvasStrokeStyle(
|
|
4725
|
+
context,
|
|
4726
|
+
image.borderColor,
|
|
4727
|
+
THUMBNAIL_DIRECT_TABLE_BORDER_COLOR
|
|
4728
|
+
);
|
|
4729
|
+
context.lineWidth = hairlineSourcePx;
|
|
4730
|
+
context.strokeRect(xPx, yPx, widthPx, heightPx);
|
|
4731
|
+
}
|
|
4732
|
+
function drawDirectThumbnailTable(context, table, hairlineSourcePx) {
|
|
4733
|
+
const tableXPx = Math.round(table.xPx);
|
|
4734
|
+
const tableYPx = Math.round(table.yPx);
|
|
4735
|
+
const tableWidthPx = Math.max(1, Math.round(table.widthPx));
|
|
4736
|
+
const tableHeightPx = Math.max(1, Math.round(table.heightPx));
|
|
4737
|
+
context.save();
|
|
4738
|
+
context.beginPath();
|
|
4739
|
+
context.rect(tableXPx, tableYPx, tableWidthPx, tableHeightPx);
|
|
4740
|
+
context.clip();
|
|
4741
|
+
setCanvasStrokeStyle(
|
|
4742
|
+
context,
|
|
4743
|
+
table.borderColor,
|
|
4744
|
+
THUMBNAIL_DIRECT_TABLE_BORDER_COLOR
|
|
4745
|
+
);
|
|
4746
|
+
context.lineWidth = hairlineSourcePx;
|
|
4747
|
+
table.cells.forEach((cell) => {
|
|
4748
|
+
const xPx = tableXPx + Math.round(cell.xPx);
|
|
4749
|
+
const yPx = tableYPx + Math.round(cell.yPx);
|
|
4750
|
+
const widthPx = Math.max(1, Math.round(cell.widthPx));
|
|
4751
|
+
const heightPx = Math.max(1, Math.round(cell.heightPx));
|
|
4752
|
+
if (cell.backgroundColor) {
|
|
4753
|
+
setCanvasFillStyle(context, cell.backgroundColor, "transparent");
|
|
4754
|
+
context.fillRect(xPx, yPx, widthPx, heightPx);
|
|
4755
|
+
}
|
|
4756
|
+
context.strokeRect(xPx, yPx, widthPx, heightPx);
|
|
4757
|
+
if (cell.runs?.length) {
|
|
4758
|
+
drawDirectThumbnailTextRuns({
|
|
4759
|
+
context,
|
|
4760
|
+
runs: cell.runs,
|
|
4761
|
+
xPx: xPx + 3,
|
|
4762
|
+
yPx: yPx + 2,
|
|
4763
|
+
widthPx: Math.max(1, widthPx - 6),
|
|
4764
|
+
heightPx: Math.max(1, heightPx - 4),
|
|
4765
|
+
lineHeightPx: 13
|
|
4766
|
+
});
|
|
4767
|
+
}
|
|
4768
|
+
});
|
|
4769
|
+
context.restore();
|
|
4770
|
+
}
|
|
4771
|
+
function renderDocxThumbnailSnapshotSurface(params) {
|
|
4772
|
+
if (typeof document === "undefined") {
|
|
4773
|
+
throw new Error("DOCX thumbnails require a browser environment.");
|
|
4774
|
+
}
|
|
4775
|
+
const sourceWidthPx = directThumbnailPositivePx(params.snapshot.sourceWidthPx);
|
|
4776
|
+
const sourceHeightPx = directThumbnailPositivePx(params.snapshot.sourceHeightPx);
|
|
4777
|
+
const pixelWidthPx = Math.max(1, Math.round(params.pixelWidthPx));
|
|
4778
|
+
const pixelHeightPx = Math.max(1, Math.round(params.pixelHeightPx));
|
|
4779
|
+
const surface = document.createElement("canvas");
|
|
4780
|
+
surface.width = pixelWidthPx;
|
|
4781
|
+
surface.height = pixelHeightPx;
|
|
4782
|
+
const context = surface.getContext("2d");
|
|
4783
|
+
if (!context) {
|
|
4784
|
+
throw new Error("2D canvas context is unavailable for DOCX thumbnails.");
|
|
4785
|
+
}
|
|
4786
|
+
const scaleX = pixelWidthPx / sourceWidthPx;
|
|
4787
|
+
const scaleY = pixelHeightPx / sourceHeightPx;
|
|
4788
|
+
const hairlineSourcePx = Math.max(0.75, 1 / Math.max(scaleX, scaleY));
|
|
4789
|
+
context.setTransform(scaleX, 0, 0, scaleY, 0, 0);
|
|
4790
|
+
context.imageSmoothingEnabled = true;
|
|
4791
|
+
context.imageSmoothingQuality = "high";
|
|
4792
|
+
setCanvasFillStyle(
|
|
4793
|
+
context,
|
|
4794
|
+
params.snapshot.pageBackgroundColor,
|
|
4795
|
+
"#ffffff"
|
|
4796
|
+
);
|
|
4797
|
+
context.fillRect(0, 0, sourceWidthPx, sourceHeightPx);
|
|
4798
|
+
params.snapshot.elements.slice(0, THUMBNAIL_DIRECT_MAX_ELEMENTS).forEach((element) => {
|
|
4799
|
+
switch (element.kind) {
|
|
4800
|
+
case "paragraph":
|
|
4801
|
+
drawDirectThumbnailParagraph(context, element);
|
|
4802
|
+
break;
|
|
4803
|
+
case "image-placeholder":
|
|
4804
|
+
drawDirectThumbnailImagePlaceholder(
|
|
4805
|
+
context,
|
|
4806
|
+
element,
|
|
4807
|
+
hairlineSourcePx
|
|
4808
|
+
);
|
|
4809
|
+
break;
|
|
4810
|
+
case "table":
|
|
4811
|
+
drawDirectThumbnailTable(context, element, hairlineSourcePx);
|
|
4812
|
+
break;
|
|
4813
|
+
}
|
|
4814
|
+
});
|
|
4815
|
+
return surface;
|
|
4816
|
+
}
|
|
4469
4817
|
async function buildDocxThumbnailSvgMarkup(params) {
|
|
4470
4818
|
const { pageElement, sourceWidthPx, sourceHeightPx, widthPx, heightPx } = params;
|
|
4471
4819
|
const clone = pageElement.cloneNode(true);
|
|
@@ -4527,16 +4875,33 @@ async function rasterizeDocxThumbnailSurface(params) {
|
|
|
4527
4875
|
return surface;
|
|
4528
4876
|
}
|
|
4529
4877
|
function blitDocxThumbnailSurface(surface, canvas, resolution) {
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4878
|
+
const pixelWidth = Math.max(1, Math.round(resolution.pixelWidthPx));
|
|
4879
|
+
const pixelHeight = Math.max(1, Math.round(resolution.pixelHeightPx));
|
|
4880
|
+
const cssWidth = `${Math.max(1, Math.round(resolution.widthPx))}px`;
|
|
4881
|
+
const cssHeight = `${Math.max(1, Math.round(resolution.heightPx))}px`;
|
|
4882
|
+
let bufferResized = false;
|
|
4883
|
+
if (canvas.width !== pixelWidth) {
|
|
4884
|
+
canvas.width = pixelWidth;
|
|
4885
|
+
bufferResized = true;
|
|
4886
|
+
}
|
|
4887
|
+
if (canvas.height !== pixelHeight) {
|
|
4888
|
+
canvas.height = pixelHeight;
|
|
4889
|
+
bufferResized = true;
|
|
4890
|
+
}
|
|
4891
|
+
if (canvas.style.width !== cssWidth) {
|
|
4892
|
+
canvas.style.width = cssWidth;
|
|
4893
|
+
}
|
|
4894
|
+
if (canvas.style.height !== cssHeight) {
|
|
4895
|
+
canvas.style.height = cssHeight;
|
|
4896
|
+
}
|
|
4534
4897
|
const context = canvas.getContext("2d");
|
|
4535
4898
|
if (!context) {
|
|
4536
4899
|
throw new Error("2D canvas context is unavailable for DOCX thumbnails.");
|
|
4537
4900
|
}
|
|
4538
4901
|
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
4539
|
-
|
|
4902
|
+
if (!bufferResized) {
|
|
4903
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
4904
|
+
}
|
|
4540
4905
|
context.drawImage(surface, 0, 0, canvas.width, canvas.height);
|
|
4541
4906
|
}
|
|
4542
4907
|
var DocxThumbnailSurfaceCache = class {
|
|
@@ -4611,6 +4976,7 @@ var SerialIdleTaskQueue = class {
|
|
|
4611
4976
|
now;
|
|
4612
4977
|
pumpScheduled = false;
|
|
4613
4978
|
running = false;
|
|
4979
|
+
nextSequence = 0;
|
|
4614
4980
|
constructor(options) {
|
|
4615
4981
|
this.scheduleTask = options?.scheduleTask ?? defaultScheduleTask;
|
|
4616
4982
|
this.scheduleDelayed = options?.scheduleDelayed ?? defaultScheduleDelayed;
|
|
@@ -4620,14 +4986,23 @@ var SerialIdleTaskQueue = class {
|
|
|
4620
4986
|
get pendingCount() {
|
|
4621
4987
|
return this.pending.length;
|
|
4622
4988
|
}
|
|
4623
|
-
enqueue(key, run) {
|
|
4989
|
+
enqueue(key, run, options) {
|
|
4990
|
+
const priority = Number.isFinite(options?.priority) ? Number(options?.priority) : 0;
|
|
4624
4991
|
return new Promise((resolve) => {
|
|
4625
4992
|
const existing = this.pending.find((entry) => entry.key === key);
|
|
4626
4993
|
if (existing) {
|
|
4627
4994
|
existing.run = run;
|
|
4628
4995
|
existing.resolvers.push(resolve);
|
|
4996
|
+
existing.priority = Math.min(existing.priority, priority);
|
|
4629
4997
|
} else {
|
|
4630
|
-
this.pending.push({
|
|
4998
|
+
this.pending.push({
|
|
4999
|
+
key,
|
|
5000
|
+
run,
|
|
5001
|
+
resolvers: [resolve],
|
|
5002
|
+
priority,
|
|
5003
|
+
sequence: this.nextSequence
|
|
5004
|
+
});
|
|
5005
|
+
this.nextSequence += 1;
|
|
4631
5006
|
}
|
|
4632
5007
|
this.schedulePump();
|
|
4633
5008
|
});
|
|
@@ -4672,6 +5047,8 @@ var SerialIdleTaskQueue = class {
|
|
|
4672
5047
|
}
|
|
4673
5048
|
const now = this.now();
|
|
4674
5049
|
let earliestWaitMs;
|
|
5050
|
+
let bestIndex = -1;
|
|
5051
|
+
let bestEntry;
|
|
4675
5052
|
for (let index = 0; index < this.pending.length; index += 1) {
|
|
4676
5053
|
const candidate = this.pending[index];
|
|
4677
5054
|
if (!candidate) {
|
|
@@ -4680,11 +5057,18 @@ var SerialIdleTaskQueue = class {
|
|
|
4680
5057
|
const lastRunAt = this.lastRunAtByKey.get(candidate.key);
|
|
4681
5058
|
const waitMs = lastRunAt === void 0 ? 0 : lastRunAt + this.minTaskIntervalMs - now;
|
|
4682
5059
|
if (waitMs <= 0) {
|
|
4683
|
-
|
|
4684
|
-
|
|
5060
|
+
if (!bestEntry || candidate.priority < bestEntry.priority || candidate.priority === bestEntry.priority && candidate.sequence < bestEntry.sequence) {
|
|
5061
|
+
bestEntry = candidate;
|
|
5062
|
+
bestIndex = index;
|
|
5063
|
+
}
|
|
5064
|
+
continue;
|
|
4685
5065
|
}
|
|
4686
5066
|
earliestWaitMs = earliestWaitMs === void 0 ? waitMs : Math.min(earliestWaitMs, waitMs);
|
|
4687
5067
|
}
|
|
5068
|
+
if (bestEntry && bestIndex >= 0) {
|
|
5069
|
+
this.pending.splice(bestIndex, 1);
|
|
5070
|
+
return { entry: bestEntry };
|
|
5071
|
+
}
|
|
4688
5072
|
return earliestWaitMs === void 0 ? void 0 : { retryDelayMs: earliestWaitMs };
|
|
4689
5073
|
}
|
|
4690
5074
|
async runNext() {
|
|
@@ -23682,13 +24066,15 @@ function ensureDocxViewerPageSurfaceRegistry(editor) {
|
|
|
23682
24066
|
registry = {
|
|
23683
24067
|
pageElements: /* @__PURE__ */ new Map(),
|
|
23684
24068
|
pageContentKeys: /* @__PURE__ */ new Map(),
|
|
24069
|
+
pageSizes: /* @__PURE__ */ new Map(),
|
|
24070
|
+
pageThumbnailSnapshots: /* @__PURE__ */ new Map(),
|
|
23685
24071
|
listeners: /* @__PURE__ */ new Set()
|
|
23686
24072
|
};
|
|
23687
24073
|
docxViewerPageSurfaceRegistryByEditor.set(owner, registry);
|
|
23688
24074
|
}
|
|
23689
24075
|
return registry;
|
|
23690
24076
|
}
|
|
23691
|
-
function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage) {
|
|
24077
|
+
function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage, pageSizesByPage = [], thumbnailSnapshotsByPage = []) {
|
|
23692
24078
|
const registry = ensureDocxViewerPageSurfaceRegistry(editor);
|
|
23693
24079
|
let changed = false;
|
|
23694
24080
|
contentKeysByPage.forEach((contentKey, pageIndex) => {
|
|
@@ -23697,12 +24083,47 @@ function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage) {
|
|
|
23697
24083
|
changed = true;
|
|
23698
24084
|
}
|
|
23699
24085
|
});
|
|
24086
|
+
pageSizesByPage.forEach((pageSize, pageIndex) => {
|
|
24087
|
+
const widthPx = Math.max(1, Math.round(pageSize.widthPx));
|
|
24088
|
+
const heightPx = Math.max(1, Math.round(pageSize.heightPx));
|
|
24089
|
+
const previous = registry.pageSizes.get(pageIndex);
|
|
24090
|
+
if (previous?.widthPx !== widthPx || previous?.heightPx !== heightPx) {
|
|
24091
|
+
registry.pageSizes.set(pageIndex, { widthPx, heightPx });
|
|
24092
|
+
changed = true;
|
|
24093
|
+
}
|
|
24094
|
+
});
|
|
24095
|
+
thumbnailSnapshotsByPage.forEach((snapshot, pageIndex) => {
|
|
24096
|
+
const previous = registry.pageThumbnailSnapshots.get(pageIndex);
|
|
24097
|
+
if (!snapshot) {
|
|
24098
|
+
if (previous) {
|
|
24099
|
+
registry.pageThumbnailSnapshots.delete(pageIndex);
|
|
24100
|
+
changed = true;
|
|
24101
|
+
}
|
|
24102
|
+
return;
|
|
24103
|
+
}
|
|
24104
|
+
if (previous?.key !== snapshot.key) {
|
|
24105
|
+
registry.pageThumbnailSnapshots.set(pageIndex, snapshot);
|
|
24106
|
+
changed = true;
|
|
24107
|
+
}
|
|
24108
|
+
});
|
|
23700
24109
|
registry.pageContentKeys.forEach((_, pageIndex) => {
|
|
23701
24110
|
if (pageIndex >= contentKeysByPage.length) {
|
|
23702
24111
|
registry.pageContentKeys.delete(pageIndex);
|
|
23703
24112
|
changed = true;
|
|
23704
24113
|
}
|
|
23705
24114
|
});
|
|
24115
|
+
registry.pageSizes.forEach((_, pageIndex) => {
|
|
24116
|
+
if (pageIndex >= pageSizesByPage.length) {
|
|
24117
|
+
registry.pageSizes.delete(pageIndex);
|
|
24118
|
+
changed = true;
|
|
24119
|
+
}
|
|
24120
|
+
});
|
|
24121
|
+
registry.pageThumbnailSnapshots.forEach((_, pageIndex) => {
|
|
24122
|
+
if (pageIndex >= thumbnailSnapshotsByPage.length) {
|
|
24123
|
+
registry.pageThumbnailSnapshots.delete(pageIndex);
|
|
24124
|
+
changed = true;
|
|
24125
|
+
}
|
|
24126
|
+
});
|
|
23706
24127
|
if (changed) {
|
|
23707
24128
|
notifyDocxViewerPageSurfaceSubscribers(registry);
|
|
23708
24129
|
}
|
|
@@ -23719,7 +24140,7 @@ function notifyDocxViewerPageSurfaceSubscribers(registry) {
|
|
|
23719
24140
|
listener();
|
|
23720
24141
|
});
|
|
23721
24142
|
}
|
|
23722
|
-
function registerDocxViewerPageSurface(editor, pageIndex, element) {
|
|
24143
|
+
function registerDocxViewerPageSurface(editor, pageIndex, element, previousElement) {
|
|
23723
24144
|
const registry = ensureDocxViewerPageSurfaceRegistry(editor);
|
|
23724
24145
|
const normalizedPageIndex = Math.max(0, Math.round(pageIndex));
|
|
23725
24146
|
const currentElement = registry.pageElements.get(normalizedPageIndex);
|
|
@@ -23734,9 +24155,22 @@ function registerDocxViewerPageSurface(editor, pageIndex, element) {
|
|
|
23734
24155
|
if (!currentElement) {
|
|
23735
24156
|
return;
|
|
23736
24157
|
}
|
|
24158
|
+
if (previousElement && currentElement !== previousElement) {
|
|
24159
|
+
return;
|
|
24160
|
+
}
|
|
23737
24161
|
registry.pageElements.delete(normalizedPageIndex);
|
|
23738
24162
|
notifyDocxViewerPageSurfaceSubscribers(registry);
|
|
23739
24163
|
}
|
|
24164
|
+
function resolveDocxViewerRegisteredPageSurfaceSize(registry, pageIndex, fallbackWidthPx, fallbackHeightPx) {
|
|
24165
|
+
const registeredSize = registry.pageSizes.get(pageIndex);
|
|
24166
|
+
if (registeredSize) {
|
|
24167
|
+
return registeredSize;
|
|
24168
|
+
}
|
|
24169
|
+
return {
|
|
24170
|
+
widthPx: Math.max(1, Math.round(fallbackWidthPx)),
|
|
24171
|
+
heightPx: Math.max(1, Math.round(fallbackHeightPx))
|
|
24172
|
+
};
|
|
24173
|
+
}
|
|
23740
24174
|
function resolveDocxViewerPageSurfaceSize(element, fallbackWidthPx, fallbackHeightPx) {
|
|
23741
24175
|
if (element) {
|
|
23742
24176
|
const rect = element.getBoundingClientRect();
|
|
@@ -23770,58 +24204,546 @@ function resolveDocxViewerPageSurfaceSize(element, fallbackWidthPx, fallbackHeig
|
|
|
23770
24204
|
heightPx: Math.max(1, Math.round(fallbackHeightPx))
|
|
23771
24205
|
};
|
|
23772
24206
|
}
|
|
23773
|
-
var
|
|
23774
|
-
var
|
|
23775
|
-
|
|
23776
|
-
|
|
23777
|
-
|
|
23778
|
-
|
|
23779
|
-
|
|
23780
|
-
|
|
23781
|
-
}
|
|
23782
|
-
|
|
23783
|
-
|
|
23784
|
-
|
|
23785
|
-
|
|
23786
|
-
|
|
23787
|
-
const scale = Math.min(
|
|
23788
|
-
1,
|
|
23789
|
-
widthBoundPx / safeSourceWidthPx,
|
|
23790
|
-
heightBoundPx / safeSourceHeightPx
|
|
23791
|
-
);
|
|
23792
|
-
const pixelRatio = Number.isFinite(options.pixelRatio) ? Math.max(1, Number(options.pixelRatio)) : 1;
|
|
23793
|
-
const widthPx = Math.max(1, Math.round(safeSourceWidthPx * scale));
|
|
23794
|
-
const heightPx = Math.max(1, Math.round(safeSourceHeightPx * scale));
|
|
23795
|
-
return {
|
|
23796
|
-
widthPx,
|
|
23797
|
-
heightPx,
|
|
23798
|
-
pixelWidthPx: Math.max(1, Math.round(widthPx * pixelRatio)),
|
|
23799
|
-
pixelHeightPx: Math.max(1, Math.round(heightPx * pixelRatio)),
|
|
23800
|
-
scale
|
|
23801
|
-
};
|
|
24207
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_ELEMENTS_PER_PAGE = 260;
|
|
24208
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_TEXT_RUNS = 28;
|
|
24209
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_TEXT_CHARS = 900;
|
|
24210
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_TABLE_CELLS = 220;
|
|
24211
|
+
var DOCX_DIRECT_THUMBNAIL_MAX_CELL_TEXT_CHARS = 120;
|
|
24212
|
+
function docxThumbnailCssNumber(value) {
|
|
24213
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
24214
|
+
return value;
|
|
24215
|
+
}
|
|
24216
|
+
if (typeof value === "string") {
|
|
24217
|
+
const parsed = Number.parseFloat(value);
|
|
24218
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
24219
|
+
}
|
|
24220
|
+
return 0;
|
|
23802
24221
|
}
|
|
23803
|
-
function
|
|
23804
|
-
const
|
|
23805
|
-
|
|
23806
|
-
|
|
23807
|
-
|
|
24222
|
+
function normalizeDocxThumbnailColor(value) {
|
|
24223
|
+
const normalized = value?.trim();
|
|
24224
|
+
if (!normalized || normalized.toLowerCase() === "auto") {
|
|
24225
|
+
return void 0;
|
|
24226
|
+
}
|
|
24227
|
+
if (/^[0-9a-fA-F]{6}$/.test(normalized)) {
|
|
24228
|
+
return `#${normalized}`;
|
|
24229
|
+
}
|
|
24230
|
+
return normalized;
|
|
24231
|
+
}
|
|
24232
|
+
function docxThumbnailTextRunStylesMatch(left, right) {
|
|
24233
|
+
return left.bold === right.bold && left.italic === right.italic && left.color === right.color && left.backgroundColor === right.backgroundColor && left.fontSizePx === right.fontSizePx && left.fontFamily === right.fontFamily;
|
|
24234
|
+
}
|
|
24235
|
+
function appendDocxThumbnailTextRun(runs, run, remaining) {
|
|
24236
|
+
if (remaining.chars <= 0 || runs.length >= DOCX_DIRECT_THUMBNAIL_MAX_TEXT_RUNS) {
|
|
24237
|
+
return;
|
|
24238
|
+
}
|
|
24239
|
+
const text = run.text.slice(0, remaining.chars);
|
|
24240
|
+
if (!text) {
|
|
24241
|
+
return;
|
|
24242
|
+
}
|
|
24243
|
+
remaining.chars -= text.length;
|
|
24244
|
+
const nextRun = { ...run, text };
|
|
24245
|
+
const previous = runs[runs.length - 1];
|
|
24246
|
+
if (previous && docxThumbnailTextRunStylesMatch(previous, nextRun)) {
|
|
24247
|
+
previous.text += nextRun.text;
|
|
24248
|
+
return;
|
|
24249
|
+
}
|
|
24250
|
+
runs.push(nextRun);
|
|
24251
|
+
}
|
|
24252
|
+
function docxThumbnailFallbackHeadingRunStyle(paragraph) {
|
|
24253
|
+
const headingLevel = paragraph.style?.headingLevel;
|
|
24254
|
+
return headingLevel && headingLevel >= 1 && headingLevel <= 6 ? DEFAULT_WORD_HEADING_RUN_STYLES[headingLevel] : void 0;
|
|
24255
|
+
}
|
|
24256
|
+
function docxThumbnailTextRunsFromParagraph(paragraph, documentTheme, maxChars = DOCX_DIRECT_THUMBNAIL_MAX_TEXT_CHARS) {
|
|
24257
|
+
const runs = [];
|
|
24258
|
+
const remaining = { chars: maxChars };
|
|
24259
|
+
const fallbackHeadingStyle = docxThumbnailFallbackHeadingRunStyle(paragraph);
|
|
24260
|
+
const fallbackFontFamily = cssFontFamily(fallbackHeadingStyle?.fontFamily) ?? cssFontFamily(paragraphDominantFontFamily(paragraph));
|
|
24261
|
+
paragraph.children.forEach((child) => {
|
|
24262
|
+
if (remaining.chars <= 0) {
|
|
24263
|
+
return;
|
|
24264
|
+
}
|
|
24265
|
+
const style = child.type === "text" || child.type === "form-field" ? child.style : void 0;
|
|
24266
|
+
const text = child.type === "text" ? child.text : child.type === "form-field" ? formFieldDisplayValue2(child) : child.type === "image" ? child.alt || "[image]" : "";
|
|
24267
|
+
appendDocxThumbnailTextRun(
|
|
24268
|
+
runs,
|
|
24269
|
+
{
|
|
24270
|
+
text,
|
|
24271
|
+
bold: style?.bold ?? fallbackHeadingStyle?.bold,
|
|
24272
|
+
italic: style?.italic ?? fallbackHeadingStyle?.italic,
|
|
24273
|
+
color: normalizeDocxThumbnailColor(
|
|
24274
|
+
themedRunColor(style?.color ?? fallbackHeadingStyle?.color, documentTheme)
|
|
24275
|
+
),
|
|
24276
|
+
backgroundColor: normalizeDocxThumbnailColor(
|
|
24277
|
+
style?.backgroundColor ?? resolveHighlightColor(style?.highlight)
|
|
24278
|
+
),
|
|
24279
|
+
fontSizePx: style?.fontSizePt && style.fontSizePt > 0 ? Math.max(6, style.fontSizePt * 96 / 72) : fallbackHeadingStyle?.fontSizePt ? Math.max(6, fallbackHeadingStyle.fontSizePt * 96 / 72) : paragraphBaseFontSizePx(paragraph),
|
|
24280
|
+
fontFamily: cssFontFamily(style?.fontFamily) ?? fallbackFontFamily
|
|
24281
|
+
},
|
|
24282
|
+
remaining
|
|
24283
|
+
);
|
|
24284
|
+
});
|
|
24285
|
+
return runs;
|
|
24286
|
+
}
|
|
24287
|
+
function docxThumbnailCellTextRuns(cell, documentTheme) {
|
|
24288
|
+
const paragraph = tableCellParagraphsRecursively(cell.nodes).find(
|
|
24289
|
+
(candidate) => paragraphText(candidate).trim().length > 0
|
|
23808
24290
|
);
|
|
23809
|
-
|
|
23810
|
-
|
|
23811
|
-
|
|
23812
|
-
|
|
24291
|
+
if (!paragraph) {
|
|
24292
|
+
return void 0;
|
|
24293
|
+
}
|
|
24294
|
+
const runs = docxThumbnailTextRunsFromParagraph(
|
|
24295
|
+
paragraph,
|
|
24296
|
+
documentTheme,
|
|
24297
|
+
DOCX_DIRECT_THUMBNAIL_MAX_CELL_TEXT_CHARS
|
|
23813
24298
|
);
|
|
23814
|
-
|
|
23815
|
-
|
|
23816
|
-
|
|
23817
|
-
|
|
23818
|
-
|
|
24299
|
+
return runs.length > 0 ? runs : void 0;
|
|
24300
|
+
}
|
|
24301
|
+
function buildDocxThumbnailParagraphElements(params) {
|
|
24302
|
+
const {
|
|
24303
|
+
paragraph,
|
|
24304
|
+
segment,
|
|
24305
|
+
contentLeftPx,
|
|
24306
|
+
contentWidthPx,
|
|
24307
|
+
yPx,
|
|
24308
|
+
heightPx,
|
|
24309
|
+
numberingDefinitions,
|
|
24310
|
+
docGridLinePitchPx,
|
|
24311
|
+
documentTheme
|
|
24312
|
+
} = params;
|
|
24313
|
+
const blockStyle = paragraphBlockStyle(
|
|
24314
|
+
paragraph,
|
|
24315
|
+
numberingDefinitions,
|
|
24316
|
+
void 0,
|
|
24317
|
+
docGridLinePitchPx
|
|
23819
24318
|
);
|
|
23820
|
-
const
|
|
23821
|
-
|
|
23822
|
-
|
|
24319
|
+
const paragraphLineRange = segment.paragraphLineRange;
|
|
24320
|
+
const marginTopPx = paragraphLineRange && paragraphLineRange.startLineIndex > 0 ? 0 : Math.max(0, docxThumbnailCssNumber(blockStyle.marginTop));
|
|
24321
|
+
const marginBottomPx = paragraphLineRange && paragraphLineRange.endLineIndex < paragraphLineRange.totalLineCount ? 0 : Math.max(0, docxThumbnailCssNumber(blockStyle.marginBottom));
|
|
24322
|
+
const marginLeftPx = docxThumbnailCssNumber(blockStyle.marginLeft);
|
|
24323
|
+
const marginRightPx = Math.max(0, docxThumbnailCssNumber(blockStyle.marginRight));
|
|
24324
|
+
const xPx = contentLeftPx + marginLeftPx;
|
|
24325
|
+
const widthPx = Math.max(8, contentWidthPx - marginLeftPx - marginRightPx);
|
|
24326
|
+
const bodyYPx = yPx + marginTopPx;
|
|
24327
|
+
const bodyHeightPx = Math.max(1, heightPx - marginTopPx - marginBottomPx);
|
|
24328
|
+
const runs = docxThumbnailTextRunsFromParagraph(paragraph, documentTheme);
|
|
24329
|
+
const elements = [];
|
|
24330
|
+
elements.push({
|
|
24331
|
+
kind: "paragraph",
|
|
24332
|
+
xPx,
|
|
24333
|
+
yPx: bodyYPx,
|
|
24334
|
+
widthPx,
|
|
24335
|
+
heightPx: bodyHeightPx,
|
|
24336
|
+
align: paragraph.style?.align,
|
|
24337
|
+
backgroundColor: normalizeDocxThumbnailColor(
|
|
24338
|
+
paragraph.style?.backgroundColor
|
|
24339
|
+
),
|
|
24340
|
+
lineHeightPx: paragraphLineRange?.lineHeightPx ?? estimateParagraphLineHeightPx(paragraph, docGridLinePitchPx),
|
|
24341
|
+
startLineIndex: paragraphLineRange?.startLineIndex,
|
|
24342
|
+
runs
|
|
24343
|
+
});
|
|
24344
|
+
const hasVisibleText = runs.some((run) => run.text.trim().length > 0);
|
|
24345
|
+
if (!hasVisibleText) {
|
|
24346
|
+
const imageRuns = paragraph.children.filter(
|
|
24347
|
+
(child) => child.type === "image"
|
|
24348
|
+
);
|
|
24349
|
+
imageRuns.slice(0, 4).forEach((imageRun) => {
|
|
24350
|
+
const imageWidthPx = Math.max(18, imageRun.widthPx ?? widthPx * 0.5);
|
|
24351
|
+
const imageHeightPx = Math.max(18, imageRun.heightPx ?? bodyHeightPx * 0.5);
|
|
24352
|
+
const scale = Math.min(
|
|
24353
|
+
1,
|
|
24354
|
+
(widthPx - 4) / imageWidthPx,
|
|
24355
|
+
(bodyHeightPx - 4) / imageHeightPx
|
|
24356
|
+
);
|
|
24357
|
+
elements.push({
|
|
24358
|
+
kind: "image-placeholder",
|
|
24359
|
+
xPx: xPx + 2,
|
|
24360
|
+
yPx: bodyYPx + 2,
|
|
24361
|
+
widthPx: Math.max(12, imageWidthPx * scale),
|
|
24362
|
+
heightPx: Math.max(12, imageHeightPx * scale)
|
|
24363
|
+
});
|
|
24364
|
+
});
|
|
24365
|
+
}
|
|
24366
|
+
return elements;
|
|
24367
|
+
}
|
|
24368
|
+
function buildDocxThumbnailTableElement(params) {
|
|
24369
|
+
const {
|
|
24370
|
+
table,
|
|
24371
|
+
segment,
|
|
24372
|
+
contentLeftPx,
|
|
24373
|
+
contentWidthPx,
|
|
24374
|
+
contentHeightPx,
|
|
24375
|
+
yPx,
|
|
24376
|
+
heightPx,
|
|
24377
|
+
numberingDefinitions,
|
|
24378
|
+
docGridLinePitchPx,
|
|
24379
|
+
documentTheme
|
|
24380
|
+
} = params;
|
|
24381
|
+
const columnCount = tableColumnCount(table);
|
|
24382
|
+
const tableIndentPx = twipsToSignedPixels(table.style?.indentTwips) ?? 0;
|
|
24383
|
+
const tableWidthPx = twipsToPixels(table.style?.widthTwips);
|
|
24384
|
+
const definedWidthsTwips = columnWidthsFromTableDefinition(table, columnCount);
|
|
24385
|
+
const rawTableColumnWidthsPx = definedWidthsTwips && definedWidthsTwips.length > 0 ? normalizeColumnWidthsPx(
|
|
24386
|
+
definedWidthsTwips.map((widthTwips) => twipsToPixels(widthTwips) ?? 0),
|
|
24387
|
+
columnCount,
|
|
24388
|
+
tableWidthPx,
|
|
24389
|
+
1
|
|
24390
|
+
) : defaultColumnWidthsPx(columnCount, tableWidthPx);
|
|
24391
|
+
const rawResolvedTableWidthPx = tableWidthPx ?? rawTableColumnWidthsPx.reduce((sum, widthPx) => sum + widthPx, 0);
|
|
24392
|
+
const maxTableWidthPx = Math.max(
|
|
24393
|
+
24,
|
|
24394
|
+
contentWidthPx - tableIndentPx - resolveCollapsedTableHorizontalOuterBleedPx(table, columnCount)
|
|
23823
24395
|
);
|
|
23824
|
-
|
|
24396
|
+
const resolvedTableWidthPx = clampTableWidthPx(
|
|
24397
|
+
rawResolvedTableWidthPx,
|
|
24398
|
+
maxTableWidthPx
|
|
24399
|
+
);
|
|
24400
|
+
const { columnWidthsPx } = resolveFittedTableColumnWidths(
|
|
24401
|
+
table,
|
|
24402
|
+
rawTableColumnWidthsPx,
|
|
24403
|
+
resolvedTableWidthPx
|
|
24404
|
+
);
|
|
24405
|
+
const rowHeightsPx = estimateTableRowHeightsPx(
|
|
24406
|
+
table,
|
|
24407
|
+
contentWidthPx,
|
|
24408
|
+
numberingDefinitions,
|
|
24409
|
+
docGridLinePitchPx,
|
|
24410
|
+
contentHeightPx
|
|
24411
|
+
);
|
|
24412
|
+
const startRowIndex = Math.max(
|
|
24413
|
+
0,
|
|
24414
|
+
segment.tableRowSlice?.rowIndex ?? segment.tableRowRange?.startRowIndex ?? 0
|
|
24415
|
+
);
|
|
24416
|
+
const endRowIndex = Math.min(
|
|
24417
|
+
table.rows.length,
|
|
24418
|
+
segment.tableRowSlice ? startRowIndex + 1 : segment.tableRowRange?.endRowIndex ?? table.rows.length
|
|
24419
|
+
);
|
|
24420
|
+
const cells = [];
|
|
24421
|
+
let rowYPx = segment.tableRowSlice ? -Math.max(0, segment.tableRowSlice.startOffsetPx) : 0;
|
|
24422
|
+
for (let rowIndex = startRowIndex; rowIndex < endRowIndex && cells.length < DOCX_DIRECT_THUMBNAIL_MAX_TABLE_CELLS; rowIndex += 1) {
|
|
24423
|
+
const row = table.rows[rowIndex];
|
|
24424
|
+
if (!row) {
|
|
24425
|
+
continue;
|
|
24426
|
+
}
|
|
24427
|
+
const rowHeightPx = segment.tableRowSlice && rowIndex === segment.tableRowSlice.rowIndex ? Math.max(1, segment.tableRowSlice.totalRowHeightPx) : Math.max(1, rowHeightsPx[rowIndex] ?? MIN_PARAGRAPH_LINE_HEIGHT_PX);
|
|
24428
|
+
let columnCursor = 0;
|
|
24429
|
+
row.cells.forEach((cell) => {
|
|
24430
|
+
if (cells.length >= DOCX_DIRECT_THUMBNAIL_MAX_TABLE_CELLS) {
|
|
24431
|
+
return;
|
|
24432
|
+
}
|
|
24433
|
+
const span = cell.style?.gridSpan && cell.style.gridSpan > 1 ? cell.style.gridSpan : 1;
|
|
24434
|
+
const xPx = columnWidthsPx.slice(0, columnCursor).reduce((sum, widthPx2) => sum + widthPx2, 0);
|
|
24435
|
+
const widthPx = columnWidthsPx.slice(columnCursor, columnCursor + span).reduce((sum, widthPx2) => sum + widthPx2, 0);
|
|
24436
|
+
columnCursor += span;
|
|
24437
|
+
cells.push({
|
|
24438
|
+
xPx,
|
|
24439
|
+
yPx: rowYPx,
|
|
24440
|
+
widthPx: Math.max(1, widthPx),
|
|
24441
|
+
heightPx: rowHeightPx,
|
|
24442
|
+
backgroundColor: normalizeDocxThumbnailColor(
|
|
24443
|
+
cell.style?.backgroundColor ?? row.style?.backgroundColor
|
|
24444
|
+
),
|
|
24445
|
+
runs: docxThumbnailCellTextRuns(cell, documentTheme)
|
|
24446
|
+
});
|
|
24447
|
+
});
|
|
24448
|
+
rowYPx += rowHeightPx;
|
|
24449
|
+
}
|
|
24450
|
+
if (cells.length === 0) {
|
|
24451
|
+
return void 0;
|
|
24452
|
+
}
|
|
24453
|
+
return {
|
|
24454
|
+
kind: "table",
|
|
24455
|
+
xPx: contentLeftPx + tableIndentPx,
|
|
24456
|
+
yPx,
|
|
24457
|
+
widthPx: Math.max(1, resolvedTableWidthPx),
|
|
24458
|
+
heightPx: Math.max(1, heightPx),
|
|
24459
|
+
cells
|
|
24460
|
+
};
|
|
24461
|
+
}
|
|
24462
|
+
function buildDocxPageThumbnailRenderSnapshotEntries(params) {
|
|
24463
|
+
const {
|
|
24464
|
+
model,
|
|
24465
|
+
pageNodeSegmentsByPage,
|
|
24466
|
+
pageSectionInfoByIndex,
|
|
24467
|
+
contentKeysByPage,
|
|
24468
|
+
fallbackLayout,
|
|
24469
|
+
documentTheme,
|
|
24470
|
+
docGridLinePitchPxByNodeIndex,
|
|
24471
|
+
numberingDefinitions
|
|
24472
|
+
} = params;
|
|
24473
|
+
return pageNodeSegmentsByPage.map((pageSegments, pageIndex) => {
|
|
24474
|
+
const key = `${contentKeysByPage[pageIndex] ?? ""}|theme:${documentTheme}`;
|
|
24475
|
+
let cachedSnapshot;
|
|
24476
|
+
return {
|
|
24477
|
+
key,
|
|
24478
|
+
getSnapshot: () => {
|
|
24479
|
+
if (cachedSnapshot) {
|
|
24480
|
+
return cachedSnapshot;
|
|
24481
|
+
}
|
|
24482
|
+
const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? fallbackLayout;
|
|
24483
|
+
const contentLeftPx = pageLayout.marginsPx.left;
|
|
24484
|
+
const contentTopPx = pageLayout.marginsPx.top;
|
|
24485
|
+
const contentWidthPx = Math.max(
|
|
24486
|
+
1,
|
|
24487
|
+
pageLayout.pageWidthPx - pageLayout.marginsPx.left - pageLayout.marginsPx.right
|
|
24488
|
+
);
|
|
24489
|
+
const contentHeightPx = Math.max(
|
|
24490
|
+
1,
|
|
24491
|
+
pageLayout.pageHeightPx - pageLayout.marginsPx.top - pageLayout.marginsPx.bottom
|
|
24492
|
+
);
|
|
24493
|
+
const elements = [];
|
|
24494
|
+
let yPx = contentTopPx;
|
|
24495
|
+
for (const segment of pageSegments) {
|
|
24496
|
+
if (elements.length >= DOCX_DIRECT_THUMBNAIL_MAX_ELEMENTS_PER_PAGE) {
|
|
24497
|
+
break;
|
|
24498
|
+
}
|
|
24499
|
+
const node = model.nodes[segment.nodeIndex];
|
|
24500
|
+
if (!node) {
|
|
24501
|
+
continue;
|
|
24502
|
+
}
|
|
24503
|
+
const docGridLinePitchPx = docGridLinePitchPxByNodeIndex.get(
|
|
24504
|
+
segment.nodeIndex
|
|
24505
|
+
);
|
|
24506
|
+
const segmentHeightPx = estimateRenderedPageSegmentHeightPx(
|
|
24507
|
+
node,
|
|
24508
|
+
segment,
|
|
24509
|
+
model,
|
|
24510
|
+
contentWidthPx,
|
|
24511
|
+
numberingDefinitions,
|
|
24512
|
+
docGridLinePitchPx
|
|
24513
|
+
);
|
|
24514
|
+
if (node.type === "paragraph" && !segment.tableRowRange) {
|
|
24515
|
+
elements.push(
|
|
24516
|
+
...buildDocxThumbnailParagraphElements({
|
|
24517
|
+
paragraph: node,
|
|
24518
|
+
segment,
|
|
24519
|
+
contentLeftPx,
|
|
24520
|
+
contentTopPx,
|
|
24521
|
+
contentWidthPx,
|
|
24522
|
+
yPx,
|
|
24523
|
+
heightPx: segmentHeightPx,
|
|
24524
|
+
numberingDefinitions,
|
|
24525
|
+
docGridLinePitchPx,
|
|
24526
|
+
documentTheme
|
|
24527
|
+
})
|
|
24528
|
+
);
|
|
24529
|
+
} else if (node.type === "table") {
|
|
24530
|
+
const tableElement = buildDocxThumbnailTableElement({
|
|
24531
|
+
table: node,
|
|
24532
|
+
segment,
|
|
24533
|
+
contentLeftPx,
|
|
24534
|
+
contentWidthPx,
|
|
24535
|
+
contentHeightPx,
|
|
24536
|
+
yPx,
|
|
24537
|
+
heightPx: segmentHeightPx,
|
|
24538
|
+
numberingDefinitions,
|
|
24539
|
+
docGridLinePitchPx,
|
|
24540
|
+
documentTheme
|
|
24541
|
+
});
|
|
24542
|
+
if (tableElement) {
|
|
24543
|
+
elements.push(tableElement);
|
|
24544
|
+
}
|
|
24545
|
+
}
|
|
24546
|
+
yPx += Math.max(1, segmentHeightPx);
|
|
24547
|
+
}
|
|
24548
|
+
cachedSnapshot = {
|
|
24549
|
+
key,
|
|
24550
|
+
sourceWidthPx: pageLayout.pageWidthPx,
|
|
24551
|
+
sourceHeightPx: pageLayout.pageHeightPx,
|
|
24552
|
+
pageBackgroundColor: documentTheme === "dark" ? "#111827" : "#ffffff",
|
|
24553
|
+
elements
|
|
24554
|
+
};
|
|
24555
|
+
return cachedSnapshot;
|
|
24556
|
+
}
|
|
24557
|
+
};
|
|
24558
|
+
});
|
|
24559
|
+
}
|
|
24560
|
+
function DocxDetachedThumbnailPageSurface({
|
|
24561
|
+
editor,
|
|
24562
|
+
pageIndex
|
|
24563
|
+
}) {
|
|
24564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
24565
|
+
DocxEditorViewer,
|
|
24566
|
+
{
|
|
24567
|
+
editor,
|
|
24568
|
+
mode: "read-only",
|
|
24569
|
+
visiblePageRange: { startPageIndex: pageIndex, endPageIndex: pageIndex },
|
|
24570
|
+
pageVirtualization: { enabled: false },
|
|
24571
|
+
showTrackedChanges: editor.showTrackedChanges,
|
|
24572
|
+
showComments: editor.showComments,
|
|
24573
|
+
style: {
|
|
24574
|
+
background: "transparent",
|
|
24575
|
+
padding: 0,
|
|
24576
|
+
margin: 0
|
|
24577
|
+
}
|
|
24578
|
+
}
|
|
24579
|
+
);
|
|
24580
|
+
}
|
|
24581
|
+
var DocxDetachedThumbnailSurfaceRenderer = class {
|
|
24582
|
+
host;
|
|
24583
|
+
root;
|
|
24584
|
+
activePageIndex;
|
|
24585
|
+
activeRenderKey;
|
|
24586
|
+
async renderPageSurface(params) {
|
|
24587
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
24588
|
+
return void 0;
|
|
24589
|
+
}
|
|
24590
|
+
const { editor, registry, pageIndex, renderKey } = params;
|
|
24591
|
+
await this.ensureRoot();
|
|
24592
|
+
if (!this.root) {
|
|
24593
|
+
return void 0;
|
|
24594
|
+
}
|
|
24595
|
+
if (this.activePageIndex !== pageIndex || this.activeRenderKey !== renderKey) {
|
|
24596
|
+
this.activePageIndex = pageIndex;
|
|
24597
|
+
this.activeRenderKey = renderKey;
|
|
24598
|
+
this.root.render(
|
|
24599
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
24600
|
+
DocxDetachedThumbnailPageSurface,
|
|
24601
|
+
{
|
|
24602
|
+
editor,
|
|
24603
|
+
pageIndex
|
|
24604
|
+
}
|
|
24605
|
+
)
|
|
24606
|
+
);
|
|
24607
|
+
}
|
|
24608
|
+
return this.waitForPageSurface(registry, pageIndex);
|
|
24609
|
+
}
|
|
24610
|
+
clear() {
|
|
24611
|
+
if (this.root) {
|
|
24612
|
+
this.root.unmount();
|
|
24613
|
+
this.root = void 0;
|
|
24614
|
+
}
|
|
24615
|
+
if (this.host?.parentNode) {
|
|
24616
|
+
this.host.parentNode.removeChild(this.host);
|
|
24617
|
+
}
|
|
24618
|
+
this.host = void 0;
|
|
24619
|
+
this.activePageIndex = void 0;
|
|
24620
|
+
this.activeRenderKey = void 0;
|
|
24621
|
+
}
|
|
24622
|
+
async ensureRoot() {
|
|
24623
|
+
if (this.root) {
|
|
24624
|
+
return;
|
|
24625
|
+
}
|
|
24626
|
+
if (typeof document === "undefined") {
|
|
24627
|
+
return;
|
|
24628
|
+
}
|
|
24629
|
+
const host = document.createElement("div");
|
|
24630
|
+
host.setAttribute("data-docx-thumbnail-detached-renderer", "true");
|
|
24631
|
+
Object.assign(host.style, {
|
|
24632
|
+
position: "fixed",
|
|
24633
|
+
left: "-100000px",
|
|
24634
|
+
top: "0",
|
|
24635
|
+
width: "1px",
|
|
24636
|
+
height: "1px",
|
|
24637
|
+
overflow: "visible",
|
|
24638
|
+
opacity: "0",
|
|
24639
|
+
pointerEvents: "none",
|
|
24640
|
+
zIndex: "-1"
|
|
24641
|
+
});
|
|
24642
|
+
document.body.appendChild(host);
|
|
24643
|
+
this.host = host;
|
|
24644
|
+
const { createRoot } = await import("react-dom/client");
|
|
24645
|
+
this.root = createRoot(host);
|
|
24646
|
+
}
|
|
24647
|
+
async waitForPageSurface(registry, pageIndex) {
|
|
24648
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
24649
|
+
const pageElement2 = registry.pageElements.get(pageIndex);
|
|
24650
|
+
if (pageElement2?.isConnected) {
|
|
24651
|
+
return pageElement2;
|
|
24652
|
+
}
|
|
24653
|
+
await new Promise((resolve) => {
|
|
24654
|
+
window.requestAnimationFrame(() => resolve());
|
|
24655
|
+
});
|
|
24656
|
+
}
|
|
24657
|
+
const pageElement = registry.pageElements.get(pageIndex);
|
|
24658
|
+
return pageElement?.isConnected ? pageElement : void 0;
|
|
24659
|
+
}
|
|
24660
|
+
};
|
|
24661
|
+
var DOCX_THUMBNAIL_SURFACE_CACHE_MAX_ENTRIES = 64;
|
|
24662
|
+
var DOCX_THUMBNAIL_MIN_RASTER_INTERVAL_MS = 200;
|
|
24663
|
+
var DOCX_THUMBNAIL_RENDER_PRIORITY_VISIBLE = 0;
|
|
24664
|
+
var DOCX_THUMBNAIL_RENDER_PRIORITY_ATTACHED = 1;
|
|
24665
|
+
var DOCX_THUMBNAIL_RENDER_PRIORITY_PREFETCH = 2;
|
|
24666
|
+
function normalizeDocxThumbnailMinRasterIntervalMs(value) {
|
|
24667
|
+
return Number.isFinite(value) && Number(value) >= 0 ? Number(value) : DOCX_THUMBNAIL_MIN_RASTER_INTERVAL_MS;
|
|
24668
|
+
}
|
|
24669
|
+
function normalizeDocxThumbnailPageIndexes(indexes, totalPages) {
|
|
24670
|
+
if (!indexes?.length || totalPages <= 0) {
|
|
24671
|
+
return [];
|
|
24672
|
+
}
|
|
24673
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24674
|
+
const normalized = [];
|
|
24675
|
+
indexes.forEach((pageIndex) => {
|
|
24676
|
+
if (!Number.isFinite(pageIndex)) {
|
|
24677
|
+
return;
|
|
24678
|
+
}
|
|
24679
|
+
const roundedPageIndex = Math.trunc(pageIndex);
|
|
24680
|
+
if (roundedPageIndex < 0 || roundedPageIndex >= totalPages || seen.has(roundedPageIndex)) {
|
|
24681
|
+
return;
|
|
24682
|
+
}
|
|
24683
|
+
seen.add(roundedPageIndex);
|
|
24684
|
+
normalized.push(roundedPageIndex);
|
|
24685
|
+
});
|
|
24686
|
+
return normalized;
|
|
24687
|
+
}
|
|
24688
|
+
function docxThumbnailPageIndexesKey(pageIndexes) {
|
|
24689
|
+
return pageIndexes.join(",");
|
|
24690
|
+
}
|
|
24691
|
+
function docxThumbnailCanvasQueueKey(canvasId) {
|
|
24692
|
+
return `canvas:${canvasId}`;
|
|
24693
|
+
}
|
|
24694
|
+
function docxThumbnailPrefetchQueueKey(pageIndex) {
|
|
24695
|
+
return `prefetch:${pageIndex}`;
|
|
24696
|
+
}
|
|
24697
|
+
function resolveDocxPageThumbnailResolution(options) {
|
|
24698
|
+
const safeSourceWidthPx = Math.max(1, Math.round(options.sourceWidthPx));
|
|
24699
|
+
const safeSourceHeightPx = Math.max(1, Math.round(options.sourceHeightPx));
|
|
24700
|
+
const resolutionBounds = typeof options.resolution === "number" && Number.isFinite(options.resolution) && options.resolution > 0 ? {
|
|
24701
|
+
maxWidthPx: Number(options.resolution),
|
|
24702
|
+
maxHeightPx: Number(options.resolution)
|
|
24703
|
+
} : typeof options.resolution === "object" && options.resolution ? {
|
|
24704
|
+
maxWidthPx: Number.isFinite(options.resolution.maxWidth) && Number(options.resolution.maxWidth) > 0 ? Number(options.resolution.maxWidth) : void 0,
|
|
24705
|
+
maxHeightPx: Number.isFinite(options.resolution.maxHeight) && Number(options.resolution.maxHeight) > 0 ? Number(options.resolution.maxHeight) : void 0
|
|
24706
|
+
} : void 0;
|
|
24707
|
+
const widthBoundPx = Number.isFinite(options.maxWidthPx) ? Math.max(1, Math.round(options.maxWidthPx)) : Number.isFinite(resolutionBounds?.maxWidthPx) ? Math.max(1, Math.round(resolutionBounds?.maxWidthPx)) : 180;
|
|
24708
|
+
const heightBoundPx = Number.isFinite(options.maxHeightPx) ? Math.max(1, Math.round(options.maxHeightPx)) : Number.isFinite(resolutionBounds?.maxHeightPx) ? Math.max(1, Math.round(resolutionBounds?.maxHeightPx)) : Number.POSITIVE_INFINITY;
|
|
24709
|
+
const scale = Math.min(
|
|
24710
|
+
1,
|
|
24711
|
+
widthBoundPx / safeSourceWidthPx,
|
|
24712
|
+
heightBoundPx / safeSourceHeightPx
|
|
24713
|
+
);
|
|
24714
|
+
const pixelRatio = Number.isFinite(options.pixelRatio) ? Math.max(1, Number(options.pixelRatio)) : 1;
|
|
24715
|
+
const widthPx = Math.max(1, Math.round(safeSourceWidthPx * scale));
|
|
24716
|
+
const heightPx = Math.max(1, Math.round(safeSourceHeightPx * scale));
|
|
24717
|
+
return {
|
|
24718
|
+
widthPx,
|
|
24719
|
+
heightPx,
|
|
24720
|
+
pixelWidthPx: Math.max(1, Math.round(widthPx * pixelRatio)),
|
|
24721
|
+
pixelHeightPx: Math.max(1, Math.round(heightPx * pixelRatio)),
|
|
24722
|
+
scale
|
|
24723
|
+
};
|
|
24724
|
+
}
|
|
24725
|
+
function useDocxPageThumbnails(editor, options = {}) {
|
|
24726
|
+
const pageSurfaceRegistryOwner = docxViewerPageSurfaceRegistryOwner(editor);
|
|
24727
|
+
const pageSurfaceRegistryEditor = React.useMemo(
|
|
24728
|
+
() => ({ syncPaginationInfo: editor.syncPaginationInfo }),
|
|
24729
|
+
[pageSurfaceRegistryOwner]
|
|
24730
|
+
);
|
|
24731
|
+
const [pageSurfaceEpoch, setPageSurfaceEpoch] = React.useState(0);
|
|
24732
|
+
const [pageThumbnailStates, setPageThumbnailStates] = React.useState(() => /* @__PURE__ */ new Map());
|
|
24733
|
+
const attachedCanvasByPageRef = React.useRef(
|
|
24734
|
+
/* @__PURE__ */ new Map()
|
|
24735
|
+
);
|
|
24736
|
+
const canvasRefCallbacksRef = React.useRef(/* @__PURE__ */ new Map());
|
|
24737
|
+
const renderToCanvasCallbacksRef = React.useRef(/* @__PURE__ */ new Map());
|
|
24738
|
+
const fallbackLayout = React.useMemo(
|
|
24739
|
+
() => resolveDocumentLayout(editor.model),
|
|
24740
|
+
[editor.model]
|
|
24741
|
+
);
|
|
24742
|
+
const pageSurfaceRegistry = React.useMemo(
|
|
24743
|
+
() => ensureDocxViewerPageSurfaceRegistry(pageSurfaceRegistryEditor),
|
|
24744
|
+
[pageSurfaceRegistryEditor]
|
|
24745
|
+
);
|
|
24746
|
+
React.useEffect(
|
|
23825
24747
|
() => subscribeDocxViewerPageSurfaces(pageSurfaceRegistryEditor, () => {
|
|
23826
24748
|
setPageSurfaceEpoch((current) => current + 1);
|
|
23827
24749
|
}),
|
|
@@ -23847,9 +24769,16 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
23847
24769
|
);
|
|
23848
24770
|
const thumbnailSurfaceCacheRef = React.useRef(void 0);
|
|
23849
24771
|
const thumbnailRasterQueueRef = React.useRef(void 0);
|
|
24772
|
+
const detachedThumbnailSurfaceRendererRef = React.useRef(void 0);
|
|
23850
24773
|
const lastPaintedThumbnailKeyByCanvasRef = React.useRef(
|
|
23851
24774
|
/* @__PURE__ */ new WeakMap()
|
|
23852
24775
|
);
|
|
24776
|
+
const thumbnailQueueKeyByCanvasRef = React.useRef(
|
|
24777
|
+
/* @__PURE__ */ new WeakMap()
|
|
24778
|
+
);
|
|
24779
|
+
const nextThumbnailCanvasQueueIdRef = React.useRef(0);
|
|
24780
|
+
const queuedPrefetchThumbnailKeysRef = React.useRef(/* @__PURE__ */ new Set());
|
|
24781
|
+
const thumbnailMinRasterIntervalMs = normalizeDocxThumbnailMinRasterIntervalMs(options.minRasterIntervalMs);
|
|
23853
24782
|
const ensureThumbnailSurfaceCache = React.useCallback(() => {
|
|
23854
24783
|
if (!thumbnailSurfaceCacheRef.current) {
|
|
23855
24784
|
thumbnailSurfaceCacheRef.current = new DocxThumbnailSurfaceCache(
|
|
@@ -23861,16 +24790,57 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
23861
24790
|
const ensureThumbnailRasterQueue = React.useCallback(() => {
|
|
23862
24791
|
if (!thumbnailRasterQueueRef.current) {
|
|
23863
24792
|
thumbnailRasterQueueRef.current = new SerialIdleTaskQueue({
|
|
23864
|
-
minTaskIntervalMs:
|
|
24793
|
+
minTaskIntervalMs: thumbnailMinRasterIntervalMs
|
|
23865
24794
|
});
|
|
23866
24795
|
}
|
|
23867
24796
|
return thumbnailRasterQueueRef.current;
|
|
23868
|
-
}, []);
|
|
24797
|
+
}, [thumbnailMinRasterIntervalMs]);
|
|
24798
|
+
const thumbnailQueueKeyForCanvas = React.useCallback(
|
|
24799
|
+
(canvas) => {
|
|
24800
|
+
const existing = thumbnailQueueKeyByCanvasRef.current.get(canvas);
|
|
24801
|
+
if (existing) {
|
|
24802
|
+
return existing;
|
|
24803
|
+
}
|
|
24804
|
+
const nextKey = docxThumbnailCanvasQueueKey(
|
|
24805
|
+
nextThumbnailCanvasQueueIdRef.current
|
|
24806
|
+
);
|
|
24807
|
+
nextThumbnailCanvasQueueIdRef.current += 1;
|
|
24808
|
+
thumbnailQueueKeyByCanvasRef.current.set(canvas, nextKey);
|
|
24809
|
+
return nextKey;
|
|
24810
|
+
},
|
|
24811
|
+
[]
|
|
24812
|
+
);
|
|
24813
|
+
React.useEffect(() => {
|
|
24814
|
+
thumbnailRasterQueueRef.current?.clear();
|
|
24815
|
+
thumbnailRasterQueueRef.current = void 0;
|
|
24816
|
+
queuedPrefetchThumbnailKeysRef.current.clear();
|
|
24817
|
+
}, [thumbnailMinRasterIntervalMs]);
|
|
23869
24818
|
React.useEffect(() => {
|
|
23870
24819
|
thumbnailSurfaceCacheRef.current?.clear();
|
|
23871
24820
|
thumbnailRasterQueueRef.current?.clear();
|
|
24821
|
+
detachedThumbnailSurfaceRendererRef.current?.clear();
|
|
24822
|
+
detachedThumbnailSurfaceRendererRef.current = void 0;
|
|
23872
24823
|
lastPaintedThumbnailKeyByCanvasRef.current = /* @__PURE__ */ new WeakMap();
|
|
24824
|
+
thumbnailQueueKeyByCanvasRef.current = /* @__PURE__ */ new WeakMap();
|
|
24825
|
+
nextThumbnailCanvasQueueIdRef.current = 0;
|
|
24826
|
+
queuedPrefetchThumbnailKeysRef.current.clear();
|
|
23873
24827
|
}, [editor.documentLoadNonce, pageSurfaceRegistryOwner]);
|
|
24828
|
+
React.useEffect(() => {
|
|
24829
|
+
detachedThumbnailSurfaceRendererRef.current?.clear();
|
|
24830
|
+
detachedThumbnailSurfaceRendererRef.current = void 0;
|
|
24831
|
+
}, [
|
|
24832
|
+
editor.documentTheme,
|
|
24833
|
+
editor.model,
|
|
24834
|
+
editor.showComments,
|
|
24835
|
+
editor.showTrackedChanges
|
|
24836
|
+
]);
|
|
24837
|
+
React.useEffect(
|
|
24838
|
+
() => () => {
|
|
24839
|
+
detachedThumbnailSurfaceRendererRef.current?.clear();
|
|
24840
|
+
detachedThumbnailSurfaceRendererRef.current = void 0;
|
|
24841
|
+
},
|
|
24842
|
+
[]
|
|
24843
|
+
);
|
|
23874
24844
|
const thumbnailResolutionOptionsKey = React.useMemo(() => {
|
|
23875
24845
|
const bounds = options.resolution;
|
|
23876
24846
|
const boundsKey = typeof bounds === "number" ? `n${bounds}` : bounds ? `b${bounds.maxWidth ?? ""}x${bounds.maxHeight ?? ""}` : "";
|
|
@@ -23888,6 +24858,125 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
23888
24858
|
},
|
|
23889
24859
|
[editor.documentTheme, pageSurfaceRegistry, thumbnailResolutionOptionsKey]
|
|
23890
24860
|
);
|
|
24861
|
+
const totalThumbnailPages = Math.max(1, editor.totalPages);
|
|
24862
|
+
const visibleThumbnailPageIndexes = React.useMemo(
|
|
24863
|
+
() => normalizeDocxThumbnailPageIndexes(
|
|
24864
|
+
options.renderWindow?.visiblePageIndexes,
|
|
24865
|
+
totalThumbnailPages
|
|
24866
|
+
),
|
|
24867
|
+
[options.renderWindow?.visiblePageIndexes, totalThumbnailPages]
|
|
24868
|
+
);
|
|
24869
|
+
const prefetchThumbnailPageIndexes = React.useMemo(
|
|
24870
|
+
() => normalizeDocxThumbnailPageIndexes(
|
|
24871
|
+
options.renderWindow?.prefetchPageIndexes,
|
|
24872
|
+
totalThumbnailPages
|
|
24873
|
+
),
|
|
24874
|
+
[options.renderWindow?.prefetchPageIndexes, totalThumbnailPages]
|
|
24875
|
+
);
|
|
24876
|
+
const visibleThumbnailPageIndexesKey = docxThumbnailPageIndexesKey(
|
|
24877
|
+
visibleThumbnailPageIndexes
|
|
24878
|
+
);
|
|
24879
|
+
const prefetchThumbnailPageIndexesKey = docxThumbnailPageIndexesKey(
|
|
24880
|
+
prefetchThumbnailPageIndexes
|
|
24881
|
+
);
|
|
24882
|
+
const visibleThumbnailPageIndexSet = React.useMemo(
|
|
24883
|
+
() => new Set(visibleThumbnailPageIndexes),
|
|
24884
|
+
[visibleThumbnailPageIndexesKey]
|
|
24885
|
+
);
|
|
24886
|
+
const thumbnailRenderPriorityForPage = React.useCallback(
|
|
24887
|
+
(pageIndex, fallbackPriority = DOCX_THUMBNAIL_RENDER_PRIORITY_ATTACHED) => visibleThumbnailPageIndexSet.has(pageIndex) ? DOCX_THUMBNAIL_RENDER_PRIORITY_VISIBLE : fallbackPriority,
|
|
24888
|
+
[visibleThumbnailPageIndexSet]
|
|
24889
|
+
);
|
|
24890
|
+
const renderPageThumbnailSurface = React.useCallback(
|
|
24891
|
+
async (pageIndex, renderOptions) => {
|
|
24892
|
+
const force = renderOptions?.force === true;
|
|
24893
|
+
const runSkipKey = thumbnailSkipKeyForPage(pageIndex);
|
|
24894
|
+
const detachedRenderKey = [
|
|
24895
|
+
runSkipKey ?? `load:${editor.documentLoadNonce}`,
|
|
24896
|
+
editor.showComments ? "comments:1" : "comments:0",
|
|
24897
|
+
editor.showTrackedChanges ? "tracked:1" : "tracked:0"
|
|
24898
|
+
].join("|");
|
|
24899
|
+
const thumbnailSnapshotEntry = pageSurfaceRegistry.pageThumbnailSnapshots.get(pageIndex);
|
|
24900
|
+
const fallbackSourceSize = resolveDocxViewerRegisteredPageSurfaceSize(
|
|
24901
|
+
pageSurfaceRegistry,
|
|
24902
|
+
pageIndex,
|
|
24903
|
+
fallbackLayout.pageWidthPx,
|
|
24904
|
+
fallbackLayout.pageHeightPx
|
|
24905
|
+
);
|
|
24906
|
+
const resolution = resolveDocxPageThumbnailResolution({
|
|
24907
|
+
sourceWidthPx: fallbackSourceSize.widthPx,
|
|
24908
|
+
sourceHeightPx: fallbackSourceSize.heightPx,
|
|
24909
|
+
resolution: options.resolution,
|
|
24910
|
+
maxWidthPx: options.maxWidthPx,
|
|
24911
|
+
maxHeightPx: options.maxHeightPx,
|
|
24912
|
+
pixelRatio: options.pixelRatio
|
|
24913
|
+
});
|
|
24914
|
+
const surfaceKey = runSkipKey === void 0 ? void 0 : `${runSkipKey}|${fallbackSourceSize.widthPx}x${fallbackSourceSize.heightPx}|${resolution.pixelWidthPx}x${resolution.pixelHeightPx}`;
|
|
24915
|
+
const surfaceCache = ensureThumbnailSurfaceCache();
|
|
24916
|
+
let surface = !force && surfaceKey !== void 0 ? surfaceCache.get(surfaceKey) : void 0;
|
|
24917
|
+
if (!surface) {
|
|
24918
|
+
const thumbnailSnapshot = thumbnailSnapshotEntry?.getSnapshot();
|
|
24919
|
+
if (thumbnailSnapshot) {
|
|
24920
|
+
surface = renderDocxThumbnailSnapshotSurface({
|
|
24921
|
+
snapshot: thumbnailSnapshot,
|
|
24922
|
+
widthPx: resolution.widthPx,
|
|
24923
|
+
heightPx: resolution.heightPx,
|
|
24924
|
+
pixelWidthPx: resolution.pixelWidthPx,
|
|
24925
|
+
pixelHeightPx: resolution.pixelHeightPx
|
|
24926
|
+
});
|
|
24927
|
+
if (surfaceKey !== void 0) {
|
|
24928
|
+
surfaceCache.set(surfaceKey, surface);
|
|
24929
|
+
}
|
|
24930
|
+
return { surface, resolution, runSkipKey };
|
|
24931
|
+
}
|
|
24932
|
+
let livePageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
|
|
24933
|
+
if (!livePageElement || !livePageElement.isConnected) {
|
|
24934
|
+
if (!detachedThumbnailSurfaceRendererRef.current) {
|
|
24935
|
+
detachedThumbnailSurfaceRendererRef.current = new DocxDetachedThumbnailSurfaceRenderer();
|
|
24936
|
+
}
|
|
24937
|
+
livePageElement = await detachedThumbnailSurfaceRendererRef.current.renderPageSurface({
|
|
24938
|
+
editor,
|
|
24939
|
+
registry: pageSurfaceRegistry,
|
|
24940
|
+
pageIndex,
|
|
24941
|
+
renderKey: detachedRenderKey
|
|
24942
|
+
});
|
|
24943
|
+
}
|
|
24944
|
+
if (!livePageElement || !livePageElement.isConnected) {
|
|
24945
|
+
return void 0;
|
|
24946
|
+
}
|
|
24947
|
+
const sourceSize = resolveDocxViewerPageSurfaceSize(
|
|
24948
|
+
livePageElement,
|
|
24949
|
+
fallbackSourceSize.widthPx,
|
|
24950
|
+
fallbackSourceSize.heightPx
|
|
24951
|
+
);
|
|
24952
|
+
surface = await rasterizeDocxThumbnailSurface({
|
|
24953
|
+
pageElement: livePageElement,
|
|
24954
|
+
sourceWidthPx: sourceSize.widthPx,
|
|
24955
|
+
sourceHeightPx: sourceSize.heightPx,
|
|
24956
|
+
widthPx: resolution.widthPx,
|
|
24957
|
+
heightPx: resolution.heightPx,
|
|
24958
|
+
pixelWidthPx: resolution.pixelWidthPx,
|
|
24959
|
+
pixelHeightPx: resolution.pixelHeightPx
|
|
24960
|
+
});
|
|
24961
|
+
if (surfaceKey !== void 0) {
|
|
24962
|
+
surfaceCache.set(surfaceKey, surface);
|
|
24963
|
+
}
|
|
24964
|
+
}
|
|
24965
|
+
return { surface, resolution, runSkipKey };
|
|
24966
|
+
},
|
|
24967
|
+
[
|
|
24968
|
+
ensureThumbnailSurfaceCache,
|
|
24969
|
+
fallbackLayout.pageHeightPx,
|
|
24970
|
+
fallbackLayout.pageWidthPx,
|
|
24971
|
+
options.resolution,
|
|
24972
|
+
options.maxHeightPx,
|
|
24973
|
+
options.maxWidthPx,
|
|
24974
|
+
options.pixelRatio,
|
|
24975
|
+
pageSurfaceRegistry,
|
|
24976
|
+
thumbnailSkipKeyForPage,
|
|
24977
|
+
editor
|
|
24978
|
+
]
|
|
24979
|
+
);
|
|
23891
24980
|
const renderPageThumbnailToCanvas = React.useCallback(
|
|
23892
24981
|
async (pageIndex, canvas, renderOptions) => {
|
|
23893
24982
|
if (options.disabled) {
|
|
@@ -23898,59 +24987,25 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
23898
24987
|
return;
|
|
23899
24988
|
}
|
|
23900
24989
|
const requiresAttachedTarget = canvas === void 0;
|
|
23901
|
-
const pageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
|
|
23902
|
-
if (!pageElement || !pageElement.isConnected) {
|
|
23903
|
-
updatePageThumbnailState(pageIndex, "unavailable");
|
|
23904
|
-
return;
|
|
23905
|
-
}
|
|
23906
24990
|
const force = renderOptions?.force === true;
|
|
23907
24991
|
const lastPaintedKey = lastPaintedThumbnailKeyByCanvasRef.current.get(targetCanvas);
|
|
23908
24992
|
if (!force && lastPaintedKey !== void 0 && lastPaintedKey === thumbnailSkipKeyForPage(pageIndex)) {
|
|
23909
24993
|
updatePageThumbnailState(pageIndex, "ready");
|
|
23910
24994
|
return;
|
|
23911
24995
|
}
|
|
23912
|
-
|
|
23913
|
-
await ensureThumbnailRasterQueue().enqueue(targetCanvas, async () => {
|
|
24996
|
+
const paintIntoTarget = async () => {
|
|
23914
24997
|
if (requiresAttachedTarget && attachedCanvasByPageRef.current.get(pageIndex) !== targetCanvas) {
|
|
23915
24998
|
return;
|
|
23916
24999
|
}
|
|
23917
|
-
const livePageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
|
|
23918
|
-
if (!livePageElement || !livePageElement.isConnected) {
|
|
23919
|
-
updatePageThumbnailState(pageIndex, "unavailable");
|
|
23920
|
-
return;
|
|
23921
|
-
}
|
|
23922
|
-
const runSkipKey = thumbnailSkipKeyForPage(pageIndex);
|
|
23923
|
-
const sourceSize = resolveDocxViewerPageSurfaceSize(
|
|
23924
|
-
livePageElement,
|
|
23925
|
-
fallbackLayout.pageWidthPx,
|
|
23926
|
-
fallbackLayout.pageHeightPx
|
|
23927
|
-
);
|
|
23928
|
-
const resolution = resolveDocxPageThumbnailResolution({
|
|
23929
|
-
sourceWidthPx: sourceSize.widthPx,
|
|
23930
|
-
sourceHeightPx: sourceSize.heightPx,
|
|
23931
|
-
resolution: options.resolution,
|
|
23932
|
-
maxWidthPx: options.maxWidthPx,
|
|
23933
|
-
maxHeightPx: options.maxHeightPx,
|
|
23934
|
-
pixelRatio: options.pixelRatio
|
|
23935
|
-
});
|
|
23936
|
-
const surfaceKey = runSkipKey === void 0 ? void 0 : `${runSkipKey}|${sourceSize.widthPx}x${sourceSize.heightPx}|${resolution.pixelWidthPx}x${resolution.pixelHeightPx}`;
|
|
23937
|
-
const surfaceCache = ensureThumbnailSurfaceCache();
|
|
23938
25000
|
try {
|
|
23939
|
-
|
|
23940
|
-
|
|
23941
|
-
|
|
23942
|
-
|
|
23943
|
-
|
|
23944
|
-
|
|
23945
|
-
widthPx: resolution.widthPx,
|
|
23946
|
-
heightPx: resolution.heightPx,
|
|
23947
|
-
pixelWidthPx: resolution.pixelWidthPx,
|
|
23948
|
-
pixelHeightPx: resolution.pixelHeightPx
|
|
23949
|
-
});
|
|
23950
|
-
if (surfaceKey !== void 0) {
|
|
23951
|
-
surfaceCache.set(surfaceKey, surface);
|
|
23952
|
-
}
|
|
25001
|
+
const rendered = await renderPageThumbnailSurface(pageIndex, {
|
|
25002
|
+
force
|
|
25003
|
+
});
|
|
25004
|
+
if (!rendered) {
|
|
25005
|
+
updatePageThumbnailState(pageIndex, "unavailable");
|
|
25006
|
+
return;
|
|
23953
25007
|
}
|
|
25008
|
+
const { surface, resolution, runSkipKey } = rendered;
|
|
23954
25009
|
blitDocxThumbnailSurface(surface, targetCanvas, resolution);
|
|
23955
25010
|
if (runSkipKey !== void 0) {
|
|
23956
25011
|
lastPaintedThumbnailKeyByCanvasRef.current.set(
|
|
@@ -23966,32 +25021,116 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
23966
25021
|
error instanceof Error ? error : new Error("Failed to render DOCX page thumbnail.")
|
|
23967
25022
|
);
|
|
23968
25023
|
}
|
|
23969
|
-
}
|
|
25024
|
+
};
|
|
25025
|
+
updatePageThumbnailState(pageIndex, "rendering");
|
|
25026
|
+
if (pageSurfaceRegistry.pageThumbnailSnapshots.has(pageIndex)) {
|
|
25027
|
+
await paintIntoTarget();
|
|
25028
|
+
return;
|
|
25029
|
+
}
|
|
25030
|
+
await ensureThumbnailRasterQueue().enqueue(
|
|
25031
|
+
thumbnailQueueKeyForCanvas(targetCanvas),
|
|
25032
|
+
paintIntoTarget,
|
|
25033
|
+
{
|
|
25034
|
+
priority: renderOptions?.priority ?? thumbnailRenderPriorityForPage(
|
|
25035
|
+
pageIndex,
|
|
25036
|
+
DOCX_THUMBNAIL_RENDER_PRIORITY_ATTACHED
|
|
25037
|
+
)
|
|
25038
|
+
}
|
|
25039
|
+
);
|
|
23970
25040
|
},
|
|
23971
25041
|
[
|
|
23972
25042
|
ensureThumbnailRasterQueue,
|
|
23973
|
-
ensureThumbnailSurfaceCache,
|
|
23974
|
-
fallbackLayout.pageHeightPx,
|
|
23975
|
-
fallbackLayout.pageWidthPx,
|
|
23976
25043
|
options.disabled,
|
|
23977
|
-
options.resolution,
|
|
23978
|
-
options.maxHeightPx,
|
|
23979
|
-
options.maxWidthPx,
|
|
23980
|
-
options.pixelRatio,
|
|
23981
25044
|
pageSurfaceRegistry,
|
|
25045
|
+
renderPageThumbnailSurface,
|
|
23982
25046
|
thumbnailSkipKeyForPage,
|
|
25047
|
+
thumbnailQueueKeyForCanvas,
|
|
25048
|
+
thumbnailRenderPriorityForPage,
|
|
23983
25049
|
updatePageThumbnailState
|
|
23984
25050
|
]
|
|
23985
25051
|
);
|
|
25052
|
+
const prefetchPageThumbnailSurface = React.useCallback(
|
|
25053
|
+
async (pageIndex) => {
|
|
25054
|
+
if (options.disabled) {
|
|
25055
|
+
return;
|
|
25056
|
+
}
|
|
25057
|
+
const queueKey = docxThumbnailPrefetchQueueKey(pageIndex);
|
|
25058
|
+
queuedPrefetchThumbnailKeysRef.current.add(queueKey);
|
|
25059
|
+
await ensureThumbnailRasterQueue().enqueue(
|
|
25060
|
+
queueKey,
|
|
25061
|
+
async () => {
|
|
25062
|
+
try {
|
|
25063
|
+
await renderPageThumbnailSurface(pageIndex);
|
|
25064
|
+
} catch {
|
|
25065
|
+
}
|
|
25066
|
+
},
|
|
25067
|
+
{ priority: DOCX_THUMBNAIL_RENDER_PRIORITY_PREFETCH }
|
|
25068
|
+
);
|
|
25069
|
+
queuedPrefetchThumbnailKeysRef.current.delete(queueKey);
|
|
25070
|
+
},
|
|
25071
|
+
[ensureThumbnailRasterQueue, options.disabled, renderPageThumbnailSurface]
|
|
25072
|
+
);
|
|
23986
25073
|
const requestAttachedThumbnailRenders = React.useCallback(
|
|
23987
25074
|
async (renderOptions) => {
|
|
23988
|
-
const
|
|
23989
|
-
(
|
|
25075
|
+
const attachedPageIndexes = [
|
|
25076
|
+
...attachedCanvasByPageRef.current.keys()
|
|
25077
|
+
].sort((leftPageIndex, rightPageIndex) => {
|
|
25078
|
+
const leftPriority = thumbnailRenderPriorityForPage(leftPageIndex);
|
|
25079
|
+
const rightPriority = thumbnailRenderPriorityForPage(rightPageIndex);
|
|
25080
|
+
return leftPriority - rightPriority || leftPageIndex - rightPageIndex;
|
|
25081
|
+
});
|
|
25082
|
+
const tasks = attachedPageIndexes.map(
|
|
25083
|
+
(pageIndex) => renderPageThumbnailToCanvas(pageIndex, void 0, {
|
|
25084
|
+
...renderOptions,
|
|
25085
|
+
priority: thumbnailRenderPriorityForPage(pageIndex)
|
|
25086
|
+
})
|
|
23990
25087
|
);
|
|
23991
25088
|
await Promise.all(tasks);
|
|
23992
25089
|
},
|
|
23993
|
-
[renderPageThumbnailToCanvas]
|
|
25090
|
+
[renderPageThumbnailToCanvas, thumbnailRenderPriorityForPage]
|
|
23994
25091
|
);
|
|
25092
|
+
const requestPrefetchThumbnailRenders = React.useCallback(async () => {
|
|
25093
|
+
if (options.disabled) {
|
|
25094
|
+
queuedPrefetchThumbnailKeysRef.current.forEach((queueKey) => {
|
|
25095
|
+
thumbnailRasterQueueRef.current?.cancel(queueKey);
|
|
25096
|
+
});
|
|
25097
|
+
queuedPrefetchThumbnailKeysRef.current.clear();
|
|
25098
|
+
return;
|
|
25099
|
+
}
|
|
25100
|
+
const requestedPrefetchKeys = new Set(
|
|
25101
|
+
prefetchThumbnailPageIndexes.map(
|
|
25102
|
+
(pageIndex) => docxThumbnailPrefetchQueueKey(pageIndex)
|
|
25103
|
+
)
|
|
25104
|
+
);
|
|
25105
|
+
queuedPrefetchThumbnailKeysRef.current.forEach((queueKey) => {
|
|
25106
|
+
if (!requestedPrefetchKeys.has(queueKey)) {
|
|
25107
|
+
thumbnailRasterQueueRef.current?.cancel(queueKey);
|
|
25108
|
+
queuedPrefetchThumbnailKeysRef.current.delete(queueKey);
|
|
25109
|
+
}
|
|
25110
|
+
});
|
|
25111
|
+
const tasks = prefetchThumbnailPageIndexes.map(
|
|
25112
|
+
(pageIndex) => prefetchPageThumbnailSurface(pageIndex)
|
|
25113
|
+
);
|
|
25114
|
+
await Promise.all(tasks);
|
|
25115
|
+
}, [
|
|
25116
|
+
options.disabled,
|
|
25117
|
+
prefetchPageThumbnailSurface,
|
|
25118
|
+
prefetchThumbnailPageIndexes
|
|
25119
|
+
]);
|
|
25120
|
+
React.useEffect(() => {
|
|
25121
|
+
void requestPrefetchThumbnailRenders();
|
|
25122
|
+
}, [
|
|
25123
|
+
editor.documentLoadNonce,
|
|
25124
|
+
editor.documentTheme,
|
|
25125
|
+
editor.model,
|
|
25126
|
+
mountedPageElements,
|
|
25127
|
+
options.maxHeightPx,
|
|
25128
|
+
options.maxWidthPx,
|
|
25129
|
+
options.pixelRatio,
|
|
25130
|
+
options.resolution,
|
|
25131
|
+
prefetchThumbnailPageIndexesKey,
|
|
25132
|
+
requestPrefetchThumbnailRenders
|
|
25133
|
+
]);
|
|
23995
25134
|
const rerenderAttachedThumbnails = React.useCallback(
|
|
23996
25135
|
async () => requestAttachedThumbnailRenders({ force: true }),
|
|
23997
25136
|
[requestAttachedThumbnailRenders]
|
|
@@ -24020,14 +25159,19 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
24020
25159
|
options.pixelRatio,
|
|
24021
25160
|
requestAttachedThumbnailRenders
|
|
24022
25161
|
]);
|
|
24023
|
-
const
|
|
25162
|
+
const thumbnailGeometryItems = React.useMemo(() => {
|
|
24024
25163
|
const totalPages = Math.max(1, editor.totalPages);
|
|
24025
25164
|
return Array.from({ length: totalPages }, (_, pageIndex) => {
|
|
24026
25165
|
const pageElement = mountedPageElements.get(pageIndex);
|
|
24027
|
-
const sourceSize = resolveDocxViewerPageSurfaceSize(
|
|
25166
|
+
const sourceSize = pageElement && pageElement.isConnected ? resolveDocxViewerPageSurfaceSize(
|
|
24028
25167
|
pageElement,
|
|
24029
25168
|
fallbackLayout.pageWidthPx,
|
|
24030
25169
|
fallbackLayout.pageHeightPx
|
|
25170
|
+
) : resolveDocxViewerRegisteredPageSurfaceSize(
|
|
25171
|
+
pageSurfaceRegistry,
|
|
25172
|
+
pageIndex,
|
|
25173
|
+
fallbackLayout.pageWidthPx,
|
|
25174
|
+
fallbackLayout.pageHeightPx
|
|
24031
25175
|
);
|
|
24032
25176
|
const resolution = resolveDocxPageThumbnailResolution({
|
|
24033
25177
|
sourceWidthPx: sourceSize.widthPx,
|
|
@@ -24037,15 +25181,14 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
24037
25181
|
maxHeightPx: options.maxHeightPx,
|
|
24038
25182
|
pixelRatio: options.pixelRatio
|
|
24039
25183
|
});
|
|
24040
|
-
const state = pageThumbnailStates.get(pageIndex);
|
|
24041
25184
|
return {
|
|
25185
|
+
// Internal: drives the default status below; stripped before exposure.
|
|
25186
|
+
hasElement: Boolean(pageElement),
|
|
24042
25187
|
pageIndex,
|
|
24043
25188
|
pageNumber: pageIndex + 1,
|
|
24044
25189
|
sourceWidthPx: sourceSize.widthPx,
|
|
24045
25190
|
sourceHeightPx: sourceSize.heightPx,
|
|
24046
25191
|
isMounted: Boolean(pageElement && pageElement.isConnected),
|
|
24047
|
-
status: state?.status ?? (pageElement ? "idle" : "unavailable"),
|
|
24048
|
-
error: state?.error,
|
|
24049
25192
|
paint: (canvas) => {
|
|
24050
25193
|
if (!canvas || options.disabled) {
|
|
24051
25194
|
return false;
|
|
@@ -24062,7 +25205,9 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
24062
25205
|
}
|
|
24063
25206
|
const previousCanvas = attachedCanvasByPageRef.current.get(pageIndex);
|
|
24064
25207
|
if (previousCanvas) {
|
|
24065
|
-
thumbnailRasterQueueRef.current?.cancel(
|
|
25208
|
+
thumbnailRasterQueueRef.current?.cancel(
|
|
25209
|
+
thumbnailQueueKeyForCanvas(previousCanvas)
|
|
25210
|
+
);
|
|
24066
25211
|
}
|
|
24067
25212
|
attachedCanvasByPageRef.current.delete(pageIndex);
|
|
24068
25213
|
};
|
|
@@ -24097,8 +25242,21 @@ function useDocxPageThumbnails(editor, options = {}) {
|
|
|
24097
25242
|
options.maxHeightPx,
|
|
24098
25243
|
options.maxWidthPx,
|
|
24099
25244
|
options.pixelRatio,
|
|
24100
|
-
|
|
25245
|
+
pageSurfaceRegistry,
|
|
25246
|
+
thumbnailQueueKeyForCanvas
|
|
24101
25247
|
]);
|
|
25248
|
+
const thumbnails = React.useMemo(
|
|
25249
|
+
() => thumbnailGeometryItems.map((geometryItem) => {
|
|
25250
|
+
const { hasElement, ...item } = geometryItem;
|
|
25251
|
+
const state = pageThumbnailStates.get(item.pageIndex);
|
|
25252
|
+
return {
|
|
25253
|
+
...item,
|
|
25254
|
+
status: state?.status ?? (hasElement ? "idle" : "unavailable"),
|
|
25255
|
+
error: state?.error
|
|
25256
|
+
};
|
|
25257
|
+
}),
|
|
25258
|
+
[thumbnailGeometryItems, pageThumbnailStates]
|
|
25259
|
+
);
|
|
24102
25260
|
const paintThumbnail = React.useCallback(
|
|
24103
25261
|
(pageIndex, canvas) => {
|
|
24104
25262
|
if (!canvas || options.disabled) {
|
|
@@ -25393,13 +26551,23 @@ function DocxEditorViewer({
|
|
|
25393
26551
|
if (cached) {
|
|
25394
26552
|
return cached;
|
|
25395
26553
|
}
|
|
26554
|
+
let registeredElement = null;
|
|
25396
26555
|
const nextRef = (element) => {
|
|
25397
26556
|
if (element) {
|
|
26557
|
+
registeredElement = element;
|
|
25398
26558
|
pageElementsRef.current.set(normalizedPageIndex, element);
|
|
25399
26559
|
} else {
|
|
25400
26560
|
pageElementsRef.current.delete(normalizedPageIndex);
|
|
25401
26561
|
}
|
|
25402
|
-
registerDocxViewerPageSurface(
|
|
26562
|
+
registerDocxViewerPageSurface(
|
|
26563
|
+
editor,
|
|
26564
|
+
normalizedPageIndex,
|
|
26565
|
+
element,
|
|
26566
|
+
registeredElement
|
|
26567
|
+
);
|
|
26568
|
+
if (!element) {
|
|
26569
|
+
registeredElement = null;
|
|
26570
|
+
}
|
|
25403
26571
|
};
|
|
25404
26572
|
pageSurfaceRefCallbacksRef.current.set(normalizedPageIndex, nextRef);
|
|
25405
26573
|
return nextRef;
|
|
@@ -26462,12 +27630,51 @@ function DocxEditorViewer({
|
|
|
26462
27630
|
pageSectionInfoByIndex,
|
|
26463
27631
|
trackedChangesEnabled
|
|
26464
27632
|
]);
|
|
27633
|
+
const pageThumbnailSurfaceSizesByPage = React.useMemo(
|
|
27634
|
+
() => pageNodeSegmentsByPage.map((_, pageIndex) => {
|
|
27635
|
+
const pageLayout = pageSectionInfoByIndex[pageIndex]?.layout ?? documentLayout;
|
|
27636
|
+
return {
|
|
27637
|
+
widthPx: pageLayout.pageWidthPx,
|
|
27638
|
+
heightPx: pageLayout.pageHeightPx
|
|
27639
|
+
};
|
|
27640
|
+
}),
|
|
27641
|
+
[documentLayout, pageNodeSegmentsByPage, pageSectionInfoByIndex]
|
|
27642
|
+
);
|
|
27643
|
+
const pageThumbnailSnapshotEntriesByPage = React.useMemo(
|
|
27644
|
+
() => buildDocxPageThumbnailRenderSnapshotEntries({
|
|
27645
|
+
model: editor.model,
|
|
27646
|
+
pageNodeSegmentsByPage,
|
|
27647
|
+
pageSectionInfoByIndex,
|
|
27648
|
+
contentKeysByPage: pageThumbnailContentKeysByPage,
|
|
27649
|
+
fallbackLayout: documentLayout,
|
|
27650
|
+
documentTheme: editor.documentTheme,
|
|
27651
|
+
docGridLinePitchPxByNodeIndex,
|
|
27652
|
+
numberingDefinitions: editor.model.metadata.numberingDefinitions
|
|
27653
|
+
}),
|
|
27654
|
+
[
|
|
27655
|
+
docGridLinePitchPxByNodeIndex,
|
|
27656
|
+
documentLayout,
|
|
27657
|
+
editor.documentTheme,
|
|
27658
|
+
editor.model,
|
|
27659
|
+
editor.model.metadata.numberingDefinitions,
|
|
27660
|
+
pageNodeSegmentsByPage,
|
|
27661
|
+
pageSectionInfoByIndex,
|
|
27662
|
+
pageThumbnailContentKeysByPage
|
|
27663
|
+
]
|
|
27664
|
+
);
|
|
26465
27665
|
React.useEffect(() => {
|
|
26466
27666
|
syncDocxViewerPageSurfaceContentKeys(
|
|
26467
27667
|
editor,
|
|
26468
|
-
pageThumbnailContentKeysByPage
|
|
27668
|
+
pageThumbnailContentKeysByPage,
|
|
27669
|
+
pageThumbnailSurfaceSizesByPage,
|
|
27670
|
+
pageThumbnailSnapshotEntriesByPage
|
|
26469
27671
|
);
|
|
26470
|
-
}, [
|
|
27672
|
+
}, [
|
|
27673
|
+
pageSurfaceRegistryOwner,
|
|
27674
|
+
pageThumbnailContentKeysByPage,
|
|
27675
|
+
pageThumbnailSnapshotEntriesByPage,
|
|
27676
|
+
pageThumbnailSurfaceSizesByPage
|
|
27677
|
+
]);
|
|
26471
27678
|
const resolveStyleRefFieldValueForPage = React.useMemo(() => {
|
|
26472
27679
|
const valueCache = /* @__PURE__ */ new Map();
|
|
26473
27680
|
const nodes = editor.model.nodes;
|