@extend-ai/react-docx 0.7.0-alpha.7 → 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/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
- canvas.width = Math.max(1, Math.round(resolution.pixelWidthPx));
4531
- canvas.height = Math.max(1, Math.round(resolution.pixelHeightPx));
4532
- canvas.style.width = `${Math.max(1, Math.round(resolution.widthPx))}px`;
4533
- canvas.style.height = `${Math.max(1, Math.round(resolution.heightPx))}px`;
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
- context.clearRect(0, 0, canvas.width, canvas.height);
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({ key, run, resolvers: [resolve] });
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
- this.pending.splice(index, 1);
4684
- return { entry: candidate };
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() {
@@ -23683,13 +24067,14 @@ function ensureDocxViewerPageSurfaceRegistry(editor) {
23683
24067
  pageElements: /* @__PURE__ */ new Map(),
23684
24068
  pageContentKeys: /* @__PURE__ */ new Map(),
23685
24069
  pageSizes: /* @__PURE__ */ new Map(),
24070
+ pageThumbnailSnapshots: /* @__PURE__ */ new Map(),
23686
24071
  listeners: /* @__PURE__ */ new Set()
23687
24072
  };
23688
24073
  docxViewerPageSurfaceRegistryByEditor.set(owner, registry);
23689
24074
  }
23690
24075
  return registry;
23691
24076
  }
23692
- function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage, pageSizesByPage = []) {
24077
+ function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage, pageSizesByPage = [], thumbnailSnapshotsByPage = []) {
23693
24078
  const registry = ensureDocxViewerPageSurfaceRegistry(editor);
23694
24079
  let changed = false;
23695
24080
  contentKeysByPage.forEach((contentKey, pageIndex) => {
@@ -23707,6 +24092,20 @@ function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage, pageSiz
23707
24092
  changed = true;
23708
24093
  }
23709
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
+ });
23710
24109
  registry.pageContentKeys.forEach((_, pageIndex) => {
23711
24110
  if (pageIndex >= contentKeysByPage.length) {
23712
24111
  registry.pageContentKeys.delete(pageIndex);
@@ -23719,6 +24118,12 @@ function syncDocxViewerPageSurfaceContentKeys(editor, contentKeysByPage, pageSiz
23719
24118
  changed = true;
23720
24119
  }
23721
24120
  });
24121
+ registry.pageThumbnailSnapshots.forEach((_, pageIndex) => {
24122
+ if (pageIndex >= thumbnailSnapshotsByPage.length) {
24123
+ registry.pageThumbnailSnapshots.delete(pageIndex);
24124
+ changed = true;
24125
+ }
24126
+ });
23722
24127
  if (changed) {
23723
24128
  notifyDocxViewerPageSurfaceSubscribers(registry);
23724
24129
  }
@@ -23799,6 +24204,359 @@ function resolveDocxViewerPageSurfaceSize(element, fallbackWidthPx, fallbackHeig
23799
24204
  heightPx: Math.max(1, Math.round(fallbackHeightPx))
23800
24205
  };
23801
24206
  }
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;
24221
+ }
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
24290
+ );
24291
+ if (!paragraph) {
24292
+ return void 0;
24293
+ }
24294
+ const runs = docxThumbnailTextRunsFromParagraph(
24295
+ paragraph,
24296
+ documentTheme,
24297
+ DOCX_DIRECT_THUMBNAIL_MAX_CELL_TEXT_CHARS
24298
+ );
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
24318
+ );
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)
24395
+ );
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
+ }
23802
24560
  function DocxDetachedThumbnailPageSurface({
23803
24561
  editor,
23804
24562
  pageIndex
@@ -23824,17 +24582,19 @@ var DocxDetachedThumbnailSurfaceRenderer = class {
23824
24582
  host;
23825
24583
  root;
23826
24584
  activePageIndex;
24585
+ activeRenderKey;
23827
24586
  async renderPageSurface(params) {
23828
24587
  if (typeof document === "undefined" || typeof window === "undefined") {
23829
24588
  return void 0;
23830
24589
  }
23831
- const { editor, registry, pageIndex } = params;
24590
+ const { editor, registry, pageIndex, renderKey } = params;
23832
24591
  await this.ensureRoot();
23833
24592
  if (!this.root) {
23834
24593
  return void 0;
23835
24594
  }
23836
- if (this.activePageIndex !== pageIndex) {
24595
+ if (this.activePageIndex !== pageIndex || this.activeRenderKey !== renderKey) {
23837
24596
  this.activePageIndex = pageIndex;
24597
+ this.activeRenderKey = renderKey;
23838
24598
  this.root.render(
23839
24599
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
23840
24600
  DocxDetachedThumbnailPageSurface,
@@ -23857,6 +24617,7 @@ var DocxDetachedThumbnailSurfaceRenderer = class {
23857
24617
  }
23858
24618
  this.host = void 0;
23859
24619
  this.activePageIndex = void 0;
24620
+ this.activeRenderKey = void 0;
23860
24621
  }
23861
24622
  async ensureRoot() {
23862
24623
  if (this.root) {
@@ -23897,8 +24658,42 @@ var DocxDetachedThumbnailSurfaceRenderer = class {
23897
24658
  return pageElement?.isConnected ? pageElement : void 0;
23898
24659
  }
23899
24660
  };
23900
- var DOCX_THUMBNAIL_SURFACE_CACHE_MAX_ENTRIES = 32;
24661
+ var DOCX_THUMBNAIL_SURFACE_CACHE_MAX_ENTRIES = 64;
23901
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
+ }
23902
24697
  function resolveDocxPageThumbnailResolution(options) {
23903
24698
  const safeSourceWidthPx = Math.max(1, Math.round(options.sourceWidthPx));
23904
24699
  const safeSourceHeightPx = Math.max(1, Math.round(options.sourceHeightPx));
@@ -23978,6 +24773,12 @@ function useDocxPageThumbnails(editor, options = {}) {
23978
24773
  const lastPaintedThumbnailKeyByCanvasRef = React.useRef(
23979
24774
  /* @__PURE__ */ new WeakMap()
23980
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);
23981
24782
  const ensureThumbnailSurfaceCache = React.useCallback(() => {
23982
24783
  if (!thumbnailSurfaceCacheRef.current) {
23983
24784
  thumbnailSurfaceCacheRef.current = new DocxThumbnailSurfaceCache(
@@ -23989,18 +24790,50 @@ function useDocxPageThumbnails(editor, options = {}) {
23989
24790
  const ensureThumbnailRasterQueue = React.useCallback(() => {
23990
24791
  if (!thumbnailRasterQueueRef.current) {
23991
24792
  thumbnailRasterQueueRef.current = new SerialIdleTaskQueue({
23992
- minTaskIntervalMs: DOCX_THUMBNAIL_MIN_RASTER_INTERVAL_MS
24793
+ minTaskIntervalMs: thumbnailMinRasterIntervalMs
23993
24794
  });
23994
24795
  }
23995
24796
  return thumbnailRasterQueueRef.current;
23996
- }, []);
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]);
23997
24818
  React.useEffect(() => {
23998
24819
  thumbnailSurfaceCacheRef.current?.clear();
23999
24820
  thumbnailRasterQueueRef.current?.clear();
24000
24821
  detachedThumbnailSurfaceRendererRef.current?.clear();
24001
24822
  detachedThumbnailSurfaceRendererRef.current = void 0;
24002
24823
  lastPaintedThumbnailKeyByCanvasRef.current = /* @__PURE__ */ new WeakMap();
24824
+ thumbnailQueueKeyByCanvasRef.current = /* @__PURE__ */ new WeakMap();
24825
+ nextThumbnailCanvasQueueIdRef.current = 0;
24826
+ queuedPrefetchThumbnailKeysRef.current.clear();
24003
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
+ ]);
24004
24837
  React.useEffect(
24005
24838
  () => () => {
24006
24839
  detachedThumbnailSurfaceRendererRef.current?.clear();
@@ -24025,6 +24858,125 @@ function useDocxPageThumbnails(editor, options = {}) {
24025
24858
  },
24026
24859
  [editor.documentTheme, pageSurfaceRegistry, thumbnailResolutionOptionsKey]
24027
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
+ );
24028
24980
  const renderPageThumbnailToCanvas = React.useCallback(
24029
24981
  async (pageIndex, canvas, renderOptions) => {
24030
24982
  if (options.disabled) {
@@ -24041,74 +24993,19 @@ function useDocxPageThumbnails(editor, options = {}) {
24041
24993
  updatePageThumbnailState(pageIndex, "ready");
24042
24994
  return;
24043
24995
  }
24044
- updatePageThumbnailState(pageIndex, "rendering");
24045
- await ensureThumbnailRasterQueue().enqueue(targetCanvas, async () => {
24996
+ const paintIntoTarget = async () => {
24046
24997
  if (requiresAttachedTarget && attachedCanvasByPageRef.current.get(pageIndex) !== targetCanvas) {
24047
24998
  return;
24048
24999
  }
24049
- const runSkipKey = thumbnailSkipKeyForPage(pageIndex);
24050
- const fallbackSourceSize = resolveDocxViewerRegisteredPageSurfaceSize(
24051
- pageSurfaceRegistry,
24052
- pageIndex,
24053
- fallbackLayout.pageWidthPx,
24054
- fallbackLayout.pageHeightPx
24055
- );
24056
- const resolution = resolveDocxPageThumbnailResolution({
24057
- sourceWidthPx: fallbackSourceSize.widthPx,
24058
- sourceHeightPx: fallbackSourceSize.heightPx,
24059
- resolution: options.resolution,
24060
- maxWidthPx: options.maxWidthPx,
24061
- maxHeightPx: options.maxHeightPx,
24062
- pixelRatio: options.pixelRatio
24063
- });
24064
- const surfaceKey = runSkipKey === void 0 ? void 0 : `${runSkipKey}|${fallbackSourceSize.widthPx}x${fallbackSourceSize.heightPx}|${resolution.pixelWidthPx}x${resolution.pixelHeightPx}`;
24065
- const surfaceCache = ensureThumbnailSurfaceCache();
24066
25000
  try {
24067
- let surface = !force && surfaceKey !== void 0 ? surfaceCache.get(surfaceKey) : void 0;
24068
- if (!surface) {
24069
- let livePageElement = pageSurfaceRegistry.pageElements.get(pageIndex);
24070
- let renderedDetachedSurface = false;
24071
- try {
24072
- if (!livePageElement || !livePageElement.isConnected) {
24073
- if (!detachedThumbnailSurfaceRendererRef.current) {
24074
- detachedThumbnailSurfaceRendererRef.current = new DocxDetachedThumbnailSurfaceRenderer();
24075
- }
24076
- livePageElement = await detachedThumbnailSurfaceRendererRef.current.renderPageSurface(
24077
- {
24078
- editor,
24079
- registry: pageSurfaceRegistry,
24080
- pageIndex
24081
- }
24082
- );
24083
- renderedDetachedSurface = true;
24084
- }
24085
- if (!livePageElement || !livePageElement.isConnected) {
24086
- updatePageThumbnailState(pageIndex, "unavailable");
24087
- return;
24088
- }
24089
- const sourceSize = resolveDocxViewerPageSurfaceSize(
24090
- livePageElement,
24091
- fallbackSourceSize.widthPx,
24092
- fallbackSourceSize.heightPx
24093
- );
24094
- surface = await rasterizeDocxThumbnailSurface({
24095
- pageElement: livePageElement,
24096
- sourceWidthPx: sourceSize.widthPx,
24097
- sourceHeightPx: sourceSize.heightPx,
24098
- widthPx: resolution.widthPx,
24099
- heightPx: resolution.heightPx,
24100
- pixelWidthPx: resolution.pixelWidthPx,
24101
- pixelHeightPx: resolution.pixelHeightPx
24102
- });
24103
- if (surfaceKey !== void 0) {
24104
- surfaceCache.set(surfaceKey, surface);
24105
- }
24106
- } finally {
24107
- if (renderedDetachedSurface) {
24108
- detachedThumbnailSurfaceRendererRef.current?.clear();
24109
- }
24110
- }
25001
+ const rendered = await renderPageThumbnailSurface(pageIndex, {
25002
+ force
25003
+ });
25004
+ if (!rendered) {
25005
+ updatePageThumbnailState(pageIndex, "unavailable");
25006
+ return;
24111
25007
  }
25008
+ const { surface, resolution, runSkipKey } = rendered;
24112
25009
  blitDocxThumbnailSurface(surface, targetCanvas, resolution);
24113
25010
  if (runSkipKey !== void 0) {
24114
25011
  lastPaintedThumbnailKeyByCanvasRef.current.set(
@@ -24124,33 +25021,116 @@ function useDocxPageThumbnails(editor, options = {}) {
24124
25021
  error instanceof Error ? error : new Error("Failed to render DOCX page thumbnail.")
24125
25022
  );
24126
25023
  }
24127
- });
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
+ );
24128
25040
  },
24129
25041
  [
24130
25042
  ensureThumbnailRasterQueue,
24131
- ensureThumbnailSurfaceCache,
24132
- fallbackLayout.pageHeightPx,
24133
- fallbackLayout.pageWidthPx,
24134
25043
  options.disabled,
24135
- options.resolution,
24136
- options.maxHeightPx,
24137
- options.maxWidthPx,
24138
- options.pixelRatio,
24139
25044
  pageSurfaceRegistry,
25045
+ renderPageThumbnailSurface,
24140
25046
  thumbnailSkipKeyForPage,
24141
- updatePageThumbnailState,
24142
- editor
25047
+ thumbnailQueueKeyForCanvas,
25048
+ thumbnailRenderPriorityForPage,
25049
+ updatePageThumbnailState
24143
25050
  ]
24144
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
+ );
24145
25073
  const requestAttachedThumbnailRenders = React.useCallback(
24146
25074
  async (renderOptions) => {
24147
- const tasks = [...attachedCanvasByPageRef.current.keys()].map(
24148
- (pageIndex) => renderPageThumbnailToCanvas(pageIndex, void 0, renderOptions)
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
+ })
24149
25087
  );
24150
25088
  await Promise.all(tasks);
24151
25089
  },
24152
- [renderPageThumbnailToCanvas]
25090
+ [renderPageThumbnailToCanvas, thumbnailRenderPriorityForPage]
24153
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
+ ]);
24154
25134
  const rerenderAttachedThumbnails = React.useCallback(
24155
25135
  async () => requestAttachedThumbnailRenders({ force: true }),
24156
25136
  [requestAttachedThumbnailRenders]
@@ -24179,7 +25159,7 @@ function useDocxPageThumbnails(editor, options = {}) {
24179
25159
  options.pixelRatio,
24180
25160
  requestAttachedThumbnailRenders
24181
25161
  ]);
24182
- const thumbnails = React.useMemo(() => {
25162
+ const thumbnailGeometryItems = React.useMemo(() => {
24183
25163
  const totalPages = Math.max(1, editor.totalPages);
24184
25164
  return Array.from({ length: totalPages }, (_, pageIndex) => {
24185
25165
  const pageElement = mountedPageElements.get(pageIndex);
@@ -24201,15 +25181,14 @@ function useDocxPageThumbnails(editor, options = {}) {
24201
25181
  maxHeightPx: options.maxHeightPx,
24202
25182
  pixelRatio: options.pixelRatio
24203
25183
  });
24204
- const state = pageThumbnailStates.get(pageIndex);
24205
25184
  return {
25185
+ // Internal: drives the default status below; stripped before exposure.
25186
+ hasElement: Boolean(pageElement),
24206
25187
  pageIndex,
24207
25188
  pageNumber: pageIndex + 1,
24208
25189
  sourceWidthPx: sourceSize.widthPx,
24209
25190
  sourceHeightPx: sourceSize.heightPx,
24210
25191
  isMounted: Boolean(pageElement && pageElement.isConnected),
24211
- status: state?.status ?? (pageElement ? "idle" : "unavailable"),
24212
- error: state?.error,
24213
25192
  paint: (canvas) => {
24214
25193
  if (!canvas || options.disabled) {
24215
25194
  return false;
@@ -24226,7 +25205,9 @@ function useDocxPageThumbnails(editor, options = {}) {
24226
25205
  }
24227
25206
  const previousCanvas = attachedCanvasByPageRef.current.get(pageIndex);
24228
25207
  if (previousCanvas) {
24229
- thumbnailRasterQueueRef.current?.cancel(previousCanvas);
25208
+ thumbnailRasterQueueRef.current?.cancel(
25209
+ thumbnailQueueKeyForCanvas(previousCanvas)
25210
+ );
24230
25211
  }
24231
25212
  attachedCanvasByPageRef.current.delete(pageIndex);
24232
25213
  };
@@ -24262,8 +25243,20 @@ function useDocxPageThumbnails(editor, options = {}) {
24262
25243
  options.maxWidthPx,
24263
25244
  options.pixelRatio,
24264
25245
  pageSurfaceRegistry,
24265
- pageThumbnailStates
25246
+ thumbnailQueueKeyForCanvas
24266
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
+ );
24267
25260
  const paintThumbnail = React.useCallback(
24268
25261
  (pageIndex, canvas) => {
24269
25262
  if (!canvas || options.disabled) {
@@ -26647,15 +27640,39 @@ function DocxEditorViewer({
26647
27640
  }),
26648
27641
  [documentLayout, pageNodeSegmentsByPage, pageSectionInfoByIndex]
26649
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
+ );
26650
27665
  React.useEffect(() => {
26651
27666
  syncDocxViewerPageSurfaceContentKeys(
26652
27667
  editor,
26653
27668
  pageThumbnailContentKeysByPage,
26654
- pageThumbnailSurfaceSizesByPage
27669
+ pageThumbnailSurfaceSizesByPage,
27670
+ pageThumbnailSnapshotEntriesByPage
26655
27671
  );
26656
27672
  }, [
26657
27673
  pageSurfaceRegistryOwner,
26658
27674
  pageThumbnailContentKeysByPage,
27675
+ pageThumbnailSnapshotEntriesByPage,
26659
27676
  pageThumbnailSurfaceSizesByPage
26660
27677
  ]);
26661
27678
  const resolveStyleRefFieldValueForPage = React.useMemo(() => {