superdoc 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +12 -90
  2. package/dist/chunks/{create-super-doc-ui-CqGmoMMA.cjs → create-super-doc-ui-Bom7oDPv.cjs} +194 -29
  3. package/dist/chunks/{create-super-doc-ui-CmOSA_lN.es.js → create-super-doc-ui-DbzVC0rr.es.js} +194 -29
  4. package/dist/chunks/{eventemitter3-DEIiXiH2.es.js → eventemitter3-CMOjDs74.es.js} +1 -1
  5. package/dist/chunks/{eventemitter3-C_TAnXOl.cjs → eventemitter3-D38u8ta_.cjs} +1 -1
  6. package/dist/chunks/{jszip-D8mAFF-r.cjs → jszip-RC64TPzL.cjs} +1 -1
  7. package/dist/chunks/{jszip-BzJ3CyxR.es.js → jszip-VxCFV9YS.es.js} +1 -1
  8. package/dist/chunks/{rolldown-runtime-0pSA04fp.es.js → rolldown-runtime-B5TtN50X.es.js} +1 -1
  9. package/dist/chunks/{rolldown-runtime-74VwNCz7.cjs → rolldown-runtime-DtsSbkrh.cjs} +1 -1
  10. package/dist/collaboration-upgrade-engine.cjs +1 -1
  11. package/dist/collaboration-upgrade-engine.es.js +1 -1
  12. package/dist/document-api/src/types/track-changes.types.d.ts +17 -0
  13. package/dist/layout-engine/contracts/src/graphic-placement.d.ts +35 -6
  14. package/dist/layout-engine/contracts/src/index.d.ts +296 -13
  15. package/dist/layout-engine/contracts/src/resolved-layout.d.ts +5 -0
  16. package/dist/layout-engine/dom-contract/src/class-names.d.ts +2 -0
  17. package/dist/layout-engine/layout-bridge/src/footnote-scorer.d.ts +1 -1
  18. package/dist/layout-engine/layout-bridge/src/hydrateTableTextboxMeasures.d.ts +9 -0
  19. package/dist/layout-engine/layout-bridge/src/incrementalLayout.d.ts +40 -12
  20. package/dist/layout-engine/layout-bridge/src/index.d.ts +3 -2
  21. package/dist/layout-engine/layout-bridge/src/layoutHeaderFooter.d.ts +10 -7
  22. package/dist/layout-engine/layout-bridge/src/remeasure.d.ts +2 -2
  23. package/dist/layout-engine/layout-engine/src/anchors.d.ts +4 -0
  24. package/dist/layout-engine/layout-engine/src/execution.d.ts +21 -0
  25. package/dist/layout-engine/layout-engine/src/floating-objects.d.ts +15 -2
  26. package/dist/layout-engine/layout-engine/src/floating-table-anchor.d.ts +2 -0
  27. package/dist/layout-engine/layout-engine/src/footnote-anchor-index.d.ts +17 -0
  28. package/dist/layout-engine/layout-engine/src/index.d.ts +13 -10
  29. package/dist/layout-engine/layout-engine/src/inline-drawing-alignment.d.ts +9 -0
  30. package/dist/layout-engine/layout-engine/src/layout-drawing.d.ts +3 -3
  31. package/dist/layout-engine/layout-engine/src/layout-paragraph.d.ts +2 -2
  32. package/dist/layout-engine/layout-engine/src/layout-textbox.d.ts +3 -3
  33. package/dist/layout-engine/layout-engine/src/pageNumbering.d.ts +3 -41
  34. package/dist/layout-engine/layout-engine/src/paginator.d.ts +7 -2
  35. package/dist/layout-engine/layout-engine/src/resolvePageTokens.d.ts +2 -0
  36. package/dist/layout-engine/layout-engine/src/section-breaks.d.ts +1 -0
  37. package/dist/layout-engine/layout-engine/src/section-props.d.ts +5 -0
  38. package/dist/layout-engine/painters/dom/src/chart-renderer.d.ts +3 -3
  39. package/dist/layout-engine/painters/dom/src/images/image-outline.d.ts +7 -0
  40. package/dist/layout-engine/painters/dom/src/images/render-placeholder.d.ts +12 -0
  41. package/dist/layout-engine/painters/dom/src/renderer.d.ts +54 -0
  42. package/dist/layout-engine/painters/dom/src/runs/text-effects.d.ts +30 -0
  43. package/dist/layout-engine/painters/dom/src/runs/text-run.d.ts +6 -4
  44. package/dist/layout-engine/painters/dom/src/shapes/preset-text-warp-data.d.ts +32 -0
  45. package/dist/layout-engine/painters/dom/src/shapes/wordart-warp.d.ts +39 -0
  46. package/dist/layout-engine/painters/dom/src/table/border-utils.d.ts +20 -27
  47. package/dist/layout-engine/painters/dom/src/table/renderTableFragment.d.ts +1 -1
  48. package/dist/layout-engine/style-engine/src/ooxml/word-style-model/parse-theme.d.ts +7 -0
  49. package/dist/public/ui-react.cjs +1 -1
  50. package/dist/public/ui-react.es.js +1 -1
  51. package/dist/public/ui.cjs +1 -1
  52. package/dist/public/ui.es.js +1 -1
  53. package/dist/style.css +87 -87
  54. package/dist/style.layered.css +87 -87
  55. package/dist/superdoc/src/core/config/normalize-ui-config.d.ts +5 -0
  56. package/dist/superdoc/src/core/types/index.d.ts +24 -0
  57. package/dist/superdoc.cjs +88 -79
  58. package/dist/superdoc.es.js +88 -79
  59. package/dist-cdn/style.layered.css +1 -1
  60. package/dist-cdn/superdoc.min.css +1 -1
  61. package/dist-cdn/superdoc.min.js +37 -37
  62. package/package.json +2 -6
  63. package/AGENTS.md +0 -337
@@ -13,6 +13,8 @@ var DOM_CLASS_NAMES = {
13
13
  PAGE: "superdoc-page",
14
14
  /** Fragment container (paragraph, table, image block, etc.). */
15
15
  FRAGMENT: "superdoc-fragment",
16
+ /** Non-flowing fragment whose visual position must not define body flow geometry. */
17
+ FLOATING_FRAGMENT: "superdoc-floating-fragment",
16
18
  /** Line container within a fragment. */
17
19
  LINE: "superdoc-line",
18
20
  /**
@@ -614,7 +616,6 @@ var SUPERDOC_UI_REASONS = {
614
616
  * No descriptor imports a v1 editor internal or a private v2 runtime package,
615
617
  * and no routed command mutates while the document is read-only / viewing.
616
618
  *
617
- * See `docs/architecture/custom-ui-command-matrix.md` for the per-id matrix.
618
619
  */
619
620
  /**
620
621
  * The 14 canonical v2-native command ids. These are the historically stable
@@ -1873,6 +1874,23 @@ INLINE_PROPERTY_REGISTRY.filter((entry) => entry.storage === "mark").map((entry)
1873
1874
  * `false` when the surface is unavailable (view mode, a pre-ready editor, or a
1874
1875
  * host that has not exposed a Document API facade) rather than throwing.
1875
1876
  */
1877
+ function uiBenchNowMs() {
1878
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
1879
+ }
1880
+ function readUiBenchRuntime() {
1881
+ const benchGlobal = globalThis;
1882
+ return {
1883
+ sink: typeof benchGlobal.__superdocV2BenchPipelineTiming === "function" ? benchGlobal.__superdocV2BenchPipelineTiming : null,
1884
+ workerContext: benchGlobal.__superdocV2BenchWorkerMessageContext ?? null
1885
+ };
1886
+ }
1887
+ function emitUiBenchTiming(event) {
1888
+ const { sink } = readUiBenchRuntime();
1889
+ if (!sink) return;
1890
+ try {
1891
+ sink(event);
1892
+ } catch {}
1893
+ }
1876
1894
  var sharedUiTrackedChangesCatalogByHost = /* @__PURE__ */ new WeakMap();
1877
1895
  function acquireSharedUiTrackedChangesCatalog(host) {
1878
1896
  let state = sharedUiTrackedChangesCatalogByHost.get(host);
@@ -3702,6 +3720,7 @@ function createSuperDocUI(options) {
3702
3720
  if (options?.invalidateQueuedNavigation !== false) queuedTrackChangeNavigationInvalidation += 1;
3703
3721
  };
3704
3722
  const listeners = /* @__PURE__ */ new Set();
3723
+ let state;
3705
3724
  let disposed = false;
3706
3725
  let controllerRef = null;
3707
3726
  const asyncReads = /* @__PURE__ */ new Map();
@@ -3714,12 +3733,13 @@ function createSuperDocUI(options) {
3714
3733
  let foregroundAsyncRetryTimer = null;
3715
3734
  let pendingSelectionSeedValidationToken = null;
3716
3735
  let typingContentInvalidationTimer = null;
3736
+ const pendingAsyncReadSettlements = [];
3717
3737
  const scheduleAsyncRefresh = () => {
3718
3738
  if (asyncRefreshScheduled || disposed) return;
3719
3739
  asyncRefreshScheduled = true;
3720
3740
  const run = () => {
3721
3741
  asyncRefreshScheduled = false;
3722
- if (!disposed) recompute();
3742
+ if (!disposed) recompute("async-read-settled");
3723
3743
  };
3724
3744
  if (typeof queueMicrotask === "function") queueMicrotask(run);
3725
3745
  else Promise.resolve().then(run);
@@ -4273,6 +4293,24 @@ function createSuperDocUI(options) {
4273
4293
  failureCount: 0,
4274
4294
  retryAtMs: 0
4275
4295
  });
4296
+ const { sink, workerContext } = readUiBenchRuntime();
4297
+ if (sink) {
4298
+ const settledAtMs = uiBenchNowMs();
4299
+ pendingAsyncReadSettlements.push({
4300
+ key,
4301
+ settledAtMs,
4302
+ commandId: workerContext?.commandId ?? null,
4303
+ commandKind: workerContext?.commandKind ?? null
4304
+ });
4305
+ emitUiBenchTiming({
4306
+ stage: "superdoc-ui-async-read-settled",
4307
+ atMs: settledAtMs,
4308
+ key,
4309
+ settledAtMs,
4310
+ commandId: workerContext?.commandId ?? null,
4311
+ commandKind: workerContext?.commandKind ?? null
4312
+ });
4313
+ }
4276
4314
  scheduleAsyncRefresh();
4277
4315
  }, () => {
4278
4316
  const entry = asyncReads.get(key);
@@ -6533,31 +6571,57 @@ function createSuperDocUI(options) {
6533
6571
  diagnostics
6534
6572
  };
6535
6573
  };
6536
- const computeState = () => {
6537
- const documentMode = readDocumentMode();
6538
- const selection = computeSelection();
6574
+ const computeState = (reason = "direct") => {
6575
+ const { sink } = readUiBenchRuntime();
6576
+ const startedAtMs = sink ? uiBenchNowMs() : 0;
6577
+ const phaseMs = {};
6578
+ const measure = (phase, run) => {
6579
+ if (!sink) return run();
6580
+ const phaseStartedAtMs = uiBenchNowMs();
6581
+ try {
6582
+ return run();
6583
+ } finally {
6584
+ phaseMs[phase] = uiBenchNowMs() - phaseStartedAtMs;
6585
+ }
6586
+ };
6587
+ const documentMode = measure("documentMode", readDocumentMode);
6588
+ const selection = measure("selection", computeSelection);
6539
6589
  if (selection.status === "ready") pruneSelectionScopedAsyncReads(selection);
6540
6590
  reconcilePendingInlineFormat(selection);
6541
6591
  const selectionSignature = selectionInlineValueSignature(selection);
6542
6592
  for (const [commandId, optimistic] of optimisticInlineToggles) if (!selectionSignature || optimistic.selectionSignature !== selectionSignature) optimisticInlineToggles.delete(commandId);
6543
6593
  else if (optimistic.settled && selection.status === "ready") optimisticInlineToggles.delete(commandId);
6544
- return {
6594
+ const nextState = {
6545
6595
  ready: getEditor() != null,
6546
6596
  documentMode,
6547
- document: computeDocument(),
6597
+ document: measure("document", computeDocument),
6548
6598
  selection,
6549
6599
  toolbar: {
6550
6600
  context: documentMode,
6551
- commands: computeCommandStates(selection),
6601
+ commands: measure("toolbarCommands", () => computeCommandStates(selection)),
6552
6602
  copyFormatActive: painter.mode !== "idle"
6553
6603
  },
6554
- comments: computeComments(selection),
6555
- trackChanges: computeTrackChanges(selection),
6556
- contentControls: computeContentControls(selection),
6557
- zoom: computeZoom(),
6558
- fonts: computeFonts(),
6559
- styles: computeStyles(selection)
6560
- };
6604
+ comments: measure("comments", () => computeComments(selection)),
6605
+ trackChanges: measure("trackChanges", () => computeTrackChanges(selection)),
6606
+ contentControls: measure("contentControls", () => computeContentControls(selection)),
6607
+ zoom: measure("zoom", computeZoom),
6608
+ fonts: measure("fonts", computeFonts),
6609
+ styles: measure("styles", () => computeStyles(selection))
6610
+ };
6611
+ if (sink) {
6612
+ const completedAtMs = uiBenchNowMs();
6613
+ emitUiBenchTiming({
6614
+ stage: "superdoc-ui-compute-state",
6615
+ atMs: completedAtMs,
6616
+ reason,
6617
+ startedAtMs,
6618
+ completedAtMs,
6619
+ durationMs: completedAtMs - startedAtMs,
6620
+ phaseMs,
6621
+ asyncReadSettlements: pendingAsyncReadSettlements.splice(0)
6622
+ });
6623
+ }
6624
+ return nextState;
6561
6625
  };
6562
6626
  const syncOptimisticInlineSelection = (selection) => {
6563
6627
  const nextSignature = selectionInlineValueSignature(selection);
@@ -6642,7 +6706,7 @@ function createSuperDocUI(options) {
6642
6706
  const unsubscribe = next.subscribe((snapshot) => {
6643
6707
  selectionEpoch += 1;
6644
6708
  seedCaretSelectionFromHost(snapshot);
6645
- recompute();
6709
+ recompute("host-selection");
6646
6710
  });
6647
6711
  if (typeof unsubscribe === "function") detachHostSelection = unsubscribe;
6648
6712
  } catch {
@@ -6667,15 +6731,24 @@ function createSuperDocUI(options) {
6667
6731
  const target = rawTarget && typeof rawTarget === "object" ? rawTarget : null;
6668
6732
  let next = null;
6669
6733
  if (target?.entityType === "trackedChange" && typeof target.entityId === "string" && target.entityId.length > 0) {
6670
- const paintedEntityId = target.entityId;
6671
6734
  const targetStory = target.story && typeof target.story === "object" ? target.story : void 0;
6672
- const allStoryItems = readAllStoryTrackChanges();
6673
- const entityId = (allStoryItems ? targetStory ? buildStoryScopedTrackedChangeIdContext(allStoryItems, targetStory).toPublicId(paintedEntityId) : buildTrackedChangeIdContext(allStoryItems).toPublicId(paintedEntityId) : null) ?? paintedEntityId;
6674
6735
  const story = targetStory && storyLocatorSignature(targetStory) !== storyLocatorSignature(null) ? targetStory : void 0;
6736
+ const rawPaintedEntityId = typeof target.paintedEntityId === "string" && target.paintedEntityId.length > 0 ? target.paintedEntityId : null;
6737
+ const lookupEntityId = rawPaintedEntityId ?? target.entityId;
6738
+ const publicId = (() => {
6739
+ if (story) {
6740
+ const allStoryItems = readAllStoryTrackChanges();
6741
+ const storyContext = allStoryItems ? buildStoryScopedTrackedChangeIdContext(allStoryItems, story) : null;
6742
+ return storyContext?.toPublicId(lookupEntityId) ?? storyContext?.toPublicId(target.entityId) ?? target.entityId;
6743
+ }
6744
+ const bodyContext = buildTrackedChangeIdContext(Array.isArray(state?.trackChanges.items) ? state.trackChanges.items : []);
6745
+ return bodyContext.toPublicId(lookupEntityId) ?? bodyContext.toPublicId(target.entityId) ?? target.entityId;
6746
+ })();
6747
+ const paintedEntityId = rawPaintedEntityId ?? (lookupEntityId !== publicId ? lookupEntityId : null);
6675
6748
  next = {
6676
- id: entityId,
6749
+ id: publicId,
6677
6750
  ...story ? { story } : {},
6678
- ...typeof target.paintedEntityId === "string" && target.paintedEntityId.length > 0 ? { paintedEntityId: target.paintedEntityId } : entityId !== paintedEntityId ? { paintedEntityId } : {}
6751
+ ...paintedEntityId && paintedEntityId !== publicId ? { paintedEntityId } : {}
6679
6752
  };
6680
6753
  }
6681
6754
  if (rawTarget == null && next == null && explicitActiveChange != null && hasPendingTrackChangeRevealFocus(explicitActiveChange)) return false;
@@ -6741,7 +6814,7 @@ function createSuperDocUI(options) {
6741
6814
  };
6742
6815
  syncCoordinatorEditor();
6743
6816
  syncTrackedChangeFocusFromHostReviewTarget(readHostActiveReviewTarget(readHostReviewSource()));
6744
- let state = computeState();
6817
+ state = computeState("initial");
6745
6818
  lastOptimisticInlineSelectionSignature = selectionInlineValueSignature(state.selection);
6746
6819
  const syncHostEventsSubscription = () => {
6747
6820
  const events = (getEditor()?.host)?.events;
@@ -6809,8 +6882,10 @@ function createSuperDocUI(options) {
6809
6882
  currentHostEventsSource = null;
6810
6883
  }
6811
6884
  };
6812
- const recompute = () => {
6885
+ const recompute = (reason = "unspecified") => {
6813
6886
  if (disposed) return;
6887
+ const { sink } = readUiBenchRuntime();
6888
+ const startedAtMs = sink ? uiBenchNowMs() : 0;
6814
6889
  editCommandsRecomputeQueued = false;
6815
6890
  syncCoordinatorEditor();
6816
6891
  syncHostSelectionSubscription();
@@ -6819,10 +6894,36 @@ function createSuperDocUI(options) {
6819
6894
  syncHostReviewSubscription();
6820
6895
  syncDocumentSelectionFallbackSubscription();
6821
6896
  syncHostEventsSubscription();
6822
- const nextState = computeState();
6897
+ const nextState = computeState(reason);
6823
6898
  syncOptimisticInlineSelection(nextState.selection);
6824
6899
  state = nextState;
6825
- for (const listener of [...listeners]) listener(state);
6900
+ let listenerTotalMs = 0;
6901
+ let listenerMaxMs = 0;
6902
+ for (const listener of [...listeners]) {
6903
+ if (!sink) {
6904
+ listener(state);
6905
+ continue;
6906
+ }
6907
+ const listenerStartedAtMs = uiBenchNowMs();
6908
+ listener(state);
6909
+ const listenerMs = uiBenchNowMs() - listenerStartedAtMs;
6910
+ listenerTotalMs += listenerMs;
6911
+ listenerMaxMs = Math.max(listenerMaxMs, listenerMs);
6912
+ }
6913
+ if (sink) {
6914
+ const completedAtMs = uiBenchNowMs();
6915
+ emitUiBenchTiming({
6916
+ stage: "superdoc-ui-recompute",
6917
+ atMs: completedAtMs,
6918
+ reason,
6919
+ startedAtMs,
6920
+ completedAtMs,
6921
+ durationMs: completedAtMs - startedAtMs,
6922
+ listenerCount: listeners.size,
6923
+ listenerTotalMs,
6924
+ listenerMaxMs
6925
+ });
6926
+ }
6826
6927
  };
6827
6928
  /**
6828
6929
  * Work that is bound to one specific active editor and cannot survive a swap.
@@ -7412,7 +7513,7 @@ function createSuperDocUI(options) {
7412
7513
  if (options && options.success === false) return options;
7413
7514
  if (!selection.selectionTarget) return options ? op(input, options) : op(input);
7414
7515
  return op(input, {
7415
- ...options ?? {},
7516
+ ...options,
7416
7517
  offsetSpace: "selection"
7417
7518
  });
7418
7519
  };
@@ -8743,6 +8844,66 @@ function createSuperDocUI(options) {
8743
8844
  }
8744
8845
  };
8745
8846
  /**
8847
+ * Derive the browser-shell's `importedId` carrier-lookup alias from a
8848
+ * public list row's `wordRevisionIds` / `sourceIds` provenance fields,
8849
+ * mirroring `create-v2-tracked-changes-adapter.js`'s own derivation
8850
+ * (`wordRevisionIds.insert ?? .delete ?? .format ?? sourceIds.wordIdInsert
8851
+ * ?? .wordIdDelete ?? .wordIdOther[0]`). A carrier imported from a legacy
8852
+ * Word revision id is painted with THIS id, not the canonical public id —
8853
+ * `focusTrackedChange`'s carrier lookup only tries it when explicitly
8854
+ * passed as `importedId` on an object input (see `scrollTrackChangeIntoView`).
8855
+ */
8856
+ const deriveTrackedChangeImportedId = (row) => {
8857
+ if (!row || typeof row !== "object") return null;
8858
+ const record = row;
8859
+ const wordRevisionIds = record.wordRevisionIds && typeof record.wordRevisionIds === "object" ? record.wordRevisionIds : null;
8860
+ const sourceIds = record.sourceIds && typeof record.sourceIds === "object" ? record.sourceIds : null;
8861
+ const wordIdOther = Array.isArray(sourceIds?.wordIdOther) ? sourceIds.wordIdOther : void 0;
8862
+ const candidate = wordRevisionIds?.insert ?? wordRevisionIds?.delete ?? wordRevisionIds?.format ?? sourceIds?.wordIdInsert ?? sourceIds?.wordIdDelete ?? wordIdOther?.[0];
8863
+ return typeof candidate === "string" && candidate.length > 0 ? candidate : null;
8864
+ };
8865
+ /**
8866
+ * Scroll a tracked-change target into view, falling back to the v2
8867
+ * browser-shell's `focusTrackedChange` (the same mechanism the built-in
8868
+ * comments/tracked-changes sidebar uses via `CommentDialog.vue`'s
8869
+ * `setFocus`) when the shared host geometry path can't resolve the target.
8870
+ * The host's `normalizeGeometryTarget` only understands `text`/`replacement`
8871
+ * targets (enriched with painted `segments`) and never `structural`/
8872
+ * `formatting` targets, so those always fail the primary path and need this
8873
+ * fallback.
8874
+ *
8875
+ * `story`, when present, is threaded into the fallback input as
8876
+ * `trackedChangeStory` — a bare id always resolves to the body story in
8877
+ * `focusTrackedChange`'s target resolver, which would collapse a non-body
8878
+ * (footnote/header/footer) occurrence onto its body counterpart sharing the
8879
+ * same raw id. `importedId`, when present, is threaded in too: the carrier
8880
+ * lookup (`buildTrackChangeCarrierLookupIds`) tries it as an ADDITIONAL alias
8881
+ * alongside the canonical id, for rows whose painted carrier only matches
8882
+ * through a legacy-imported Word revision id, not the canonical public id
8883
+ * (`create-v2-tracked-changes-adapter.test.js` pins this alias path as
8884
+ * necessary for some rows).
8885
+ */
8886
+ const scrollTrackChangeIntoView = async (changeId, target, story, importedId, options) => {
8887
+ const primary = await scrollTargetIntoView(target, options);
8888
+ if (primary.ok) return primary;
8889
+ const trackedChanges = getV2TrackedChanges();
8890
+ const focusTrackedChange = trackedChanges?.focusTrackedChange;
8891
+ if (typeof focusTrackedChange !== "function") return primary;
8892
+ const fallbackInput = story || importedId ? {
8893
+ commentId: changeId,
8894
+ ...story ? { trackedChangeStory: story } : {},
8895
+ ...importedId ? { importedId } : {}
8896
+ } : changeId;
8897
+ try {
8898
+ const fallbackResult = await Promise.resolve(focusTrackedChange.call(trackedChanges, fallbackInput));
8899
+ if (fallbackResult && typeof fallbackResult === "object" && fallbackResult.ok === true) return {
8900
+ success: true,
8901
+ ok: true
8902
+ };
8903
+ } catch {}
8904
+ return primary;
8905
+ };
8906
+ /**
8746
8907
  * Resolve a document entity (comment / tracked change) to its anchor target.
8747
8908
  * Prefers the already-loaded list row, falling back to a live `get({ id })`
8748
8909
  * read when the list does not carry the row.
@@ -9004,9 +9165,11 @@ function createSuperDocUI(options) {
9004
9165
  rollback();
9005
9166
  return { success: false };
9006
9167
  }
9168
+ const activeRow = trackChangesSub.get().items.find((item) => entityRowMatchesRequest(item, activeId, optimisticActiveChange?.story)) ?? trackChangesSub.get().items.find((item) => readEntityId(item) === activeId);
9169
+ const importedId = deriveTrackedChangeImportedId(activeRow);
9007
9170
  trackedChangeNavigationInFlight += 1;
9008
9171
  try {
9009
- const result = await scrollTargetIntoView(target, {
9172
+ const result = await scrollTrackChangeIntoView(activeId, target, optimisticActiveChange?.story, importedId, {
9010
9173
  behavior: "auto",
9011
9174
  shouldContinue: isCurrent
9012
9175
  });
@@ -9130,7 +9293,9 @@ function createSuperDocUI(options) {
9130
9293
  const requestedAtInvalidation = trackChangeRevealInvalidation;
9131
9294
  const loadedItems = trackChangesSub.get().items;
9132
9295
  const publicId = buildTrackedChangeIdContext(loadedItems).toPublicId(changeId) ?? changeId;
9133
- const story = readEntityRequestStory(loadedItems.find((item) => readEntityId(item) === publicId));
9296
+ const matchingRow = loadedItems.find((item) => readEntityId(item) === publicId);
9297
+ const story = readEntityRequestStory(matchingRow);
9298
+ const importedId = deriveTrackedChangeImportedId(matchingRow);
9134
9299
  const previousActiveChange = explicitActiveChange;
9135
9300
  const requestedActiveChange = {
9136
9301
  id: publicId,
@@ -9162,7 +9327,7 @@ function createSuperDocUI(options) {
9162
9327
  recompute();
9163
9328
  trackedChangeNavigationInFlight += 1;
9164
9329
  try {
9165
- const result = await scrollTargetIntoView(target, {
9330
+ const result = await scrollTrackChangeIntoView(publicId, target, story, importedId, {
9166
9331
  behavior: "auto",
9167
9332
  shouldContinue: isCurrent
9168
9333
  });
@@ -1,4 +1,4 @@
1
- import { i as __toESM, t as __commonJSMin } from "./rolldown-runtime-0pSA04fp.es.js";
1
+ import { i as __toESM, t as __commonJSMin } from "./rolldown-runtime-B5TtN50X.es.js";
2
2
  //#endregion
3
3
  //#region ../../node_modules/.pnpm/eventemitter3@5.0.4/node_modules/eventemitter3/index.mjs
4
4
  var import_eventemitter3 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -1,4 +1,4 @@
1
- const require_rolldown_runtime = require("./rolldown-runtime-74VwNCz7.cjs");
1
+ const require_rolldown_runtime = require("./rolldown-runtime-DtsSbkrh.cjs");
2
2
  //#region ../../node_modules/.pnpm/eventemitter3@5.0.4/node_modules/eventemitter3/index.js
3
3
  var require_eventemitter3 = /* @__PURE__ */ require_rolldown_runtime.__commonJSMin(((exports, module) => {
4
4
  var has = Object.prototype.hasOwnProperty;
@@ -1,4 +1,4 @@
1
- const require_rolldown_runtime = require("./rolldown-runtime-74VwNCz7.cjs");
1
+ const require_rolldown_runtime = require("./rolldown-runtime-DtsSbkrh.cjs");
2
2
  //#region ../../node_modules/.pnpm/vite-plugin-node-polyfills@0.28.0_rollup@4.60.2_vite@7.3.1_@types+node@25.6.0_jiti@2.7._79de22fafa9a94a397e22a8c8322f563/node_modules/vite-plugin-node-polyfills/shims/buffer/dist/index.js
3
3
  function getLens(b64) {
4
4
  var len = b64.length;
@@ -1,4 +1,4 @@
1
- import { n as __esmMin, r as __require, t as __commonJSMin } from "./rolldown-runtime-0pSA04fp.es.js";
1
+ import { n as __esmMin, r as __require, t as __commonJSMin } from "./rolldown-runtime-B5TtN50X.es.js";
2
2
  //#region ../../node_modules/.pnpm/vite-plugin-node-polyfills@0.28.0_rollup@4.60.2_vite@7.3.1_@types+node@25.6.0_jiti@2.7._79de22fafa9a94a397e22a8c8322f563/node_modules/vite-plugin-node-polyfills/shims/buffer/dist/index.js
3
3
  function getLens(b64) {
4
4
  var len = b64.length;
@@ -24,7 +24,7 @@ var __copyProps = (to, from, except, desc) => {
24
24
  }
25
25
  return to;
26
26
  };
27
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
27
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
28
28
  value: mod,
29
29
  enumerable: true
30
30
  }) : target, mod));
@@ -24,7 +24,7 @@ var __copyProps = (to, from, except, desc) => {
24
24
  }
25
25
  return to;
26
26
  };
27
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
27
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
28
28
  value: mod,
29
29
  enumerable: true
30
30
  }) : target, mod));
@@ -19,7 +19,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
19
19
  var PRIVATE_ENGINE_INFO = (0, _superdoc_docx_engine_collaboration_upgrade_engine.getCollaborationUpgradeEngineInfo)();
20
20
  var ENGINE_INFO = Object.freeze({
21
21
  ...PRIVATE_ENGINE_INFO,
22
- superdocVersion: "2.4.0",
22
+ superdocVersion: "2.5.0",
23
23
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
24
24
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
25
25
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -18,7 +18,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
18
18
  var PRIVATE_ENGINE_INFO = getCollaborationUpgradeEngineInfo$1();
19
19
  var ENGINE_INFO = Object.freeze({
20
20
  ...PRIVATE_ENGINE_INFO,
21
- superdocVersion: "2.4.0",
21
+ superdocVersion: "2.5.0",
22
22
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
23
23
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
24
24
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -457,6 +457,16 @@ export interface TrackChangeNavigationTarget {
457
457
  blockId: string;
458
458
  role: 'primary' | 'move-source' | 'move-destination' | 'formatting-carrier' | 'structural-carrier';
459
459
  }
460
+ export interface TrackChangeCustomAttribute {
461
+ /** Source-qualified attribute name, preserving the prefix used by the carrier. */
462
+ name: string;
463
+ /** Resolved extension namespace URI. */
464
+ namespaceUri: string;
465
+ /** Attribute local name without its namespace prefix. */
466
+ localName: string;
467
+ /** Decoded XML attribute value. */
468
+ value: string;
469
+ }
460
470
  export interface TrackChangeInfo {
461
471
  address: TrackedChangeAddress;
462
472
  /** Stable SuperDoc logical tracked-change id (spec §3 / §4). */
@@ -569,6 +579,11 @@ export interface TrackChangeInfo {
569
579
  * tracked changes. Absent when the change is standalone.
570
580
  */
571
581
  overlap?: TrackChangeOverlapInfo;
582
+ /**
583
+ * Unknown extension attributes attached to contributing OOXML revision carriers.
584
+ * Exact duplicates are removed in document order; conflicting values are retained.
585
+ */
586
+ readonly customAttributes?: readonly TrackChangeCustomAttribute[];
572
587
  }
573
588
  export interface TrackChangesListQuery {
574
589
  limit?: number;
@@ -694,6 +709,8 @@ export interface TrackChangeDomain {
694
709
  * stack without an extra `trackChanges.get` round trip.
695
710
  */
696
711
  overlap?: TrackChangeOverlapInfo;
712
+ /** Unknown extension attributes attached to the contributing OOXML revision carriers. */
713
+ readonly customAttributes?: readonly TrackChangeCustomAttribute[];
697
714
  }
698
715
  /**
699
716
  * Standardized discovery output for `trackChanges.list`.
@@ -1,7 +1,19 @@
1
- type AnchorVRelative = 'paragraph' | 'page' | 'margin';
2
- type AnchorHRelative = 'column' | 'page' | 'margin';
3
- type AnchorAlignH = 'left' | 'center' | 'right';
4
- type AnchorAlignV = 'top' | 'center' | 'bottom';
1
+ /** ECMA-376 Part 1 §20.4.3.4 (`ST_RelFromH`). */
2
+ export declare const ANCHOR_H_RELATIVE_VALUES: readonly ["margin", "page", "column", "character", "leftMargin", "rightMargin", "insideMargin", "outsideMargin"];
3
+ /** ECMA-376 Part 1 §20.4.3.5 (`ST_RelFromV`). */
4
+ export declare const ANCHOR_V_RELATIVE_VALUES: readonly ["margin", "page", "paragraph", "line", "topMargin", "bottomMargin", "insideMargin", "outsideMargin"];
5
+ /** ECMA-376 Part 1 §20.4.3.1 (`ST_AlignH`). */
6
+ export declare const ANCHOR_H_ALIGN_VALUES: readonly ["left", "right", "center", "inside", "outside"];
7
+ /** ECMA-376 Part 1 §20.4.3.2 (`ST_AlignV`). */
8
+ export declare const ANCHOR_V_ALIGN_VALUES: readonly ["top", "bottom", "center", "inside", "outside"];
9
+ export type AnchorHRelative = (typeof ANCHOR_H_RELATIVE_VALUES)[number];
10
+ export type AnchorVRelative = (typeof ANCHOR_V_RELATIVE_VALUES)[number];
11
+ export type AnchorAlignH = (typeof ANCHOR_H_ALIGN_VALUES)[number];
12
+ export type AnchorAlignV = (typeof ANCHOR_V_ALIGN_VALUES)[number];
13
+ export declare function isAnchorHRelative(value: unknown): value is AnchorHRelative;
14
+ export declare function isAnchorVRelative(value: unknown): value is AnchorVRelative;
15
+ export declare function isAnchorAlignH(value: unknown): value is AnchorAlignH;
16
+ export declare function isAnchorAlignV(value: unknown): value is AnchorAlignV;
5
17
  export declare function isPositionedParagraphFrame<T extends {
6
18
  wrap?: string;
7
19
  }>(frame: T | undefined): frame is T & {
@@ -35,6 +47,10 @@ export type ColumnLayoutForAnchor = {
35
47
  */
36
48
  export type ResolveAnchoredGraphicYInput = {
37
49
  anchor?: {
50
+ simplePos?: {
51
+ x: number;
52
+ y: number;
53
+ };
38
54
  vRelativeFrom?: AnchorVRelative;
39
55
  alignV?: AnchorAlignV;
40
56
  offsetV?: number;
@@ -49,8 +65,12 @@ export type ResolveAnchoredGraphicYInput = {
49
65
  * Used for `paragraph` and legacy (undefined vRelativeFrom) positioning.
50
66
  */
51
67
  anchorParagraphY?: number;
68
+ /** Anchor line top Y. Falls back to the paragraph top when unavailable. */
69
+ anchorLineY?: number;
52
70
  /** First line height of the anchor paragraph (paragraph-relative alignV). */
53
71
  firstLineHeight?: number;
72
+ /** One-based physical page number, used by inside/outside placement. */
73
+ pageNumber?: number;
54
74
  /**
55
75
  * When true, anchor has no host paragraph (pre-registered / paragraphless layout).
56
76
  * For `vRelativeFrom: 'paragraph'`, use `contentTop + offsetV` instead of alignV on a
@@ -62,15 +82,24 @@ export type ResolveAnchoredGraphicYInput = {
62
82
  * Resolve the vertical paint position for an anchored graphic (image, drawing, or table).
63
83
  */
64
84
  export declare function resolveAnchoredGraphicY(input: ResolveAnchoredGraphicYInput): number;
85
+ export type ResolveAnchoredGraphicXContext = {
86
+ /** One-based physical page number, used by inside/outside placement. */
87
+ pageNumber?: number;
88
+ /** Page-space X of the anchor character. Falls back to the column origin. */
89
+ anchorCharacterX?: number;
90
+ };
65
91
  /**
66
92
  * Resolve horizontal paint position for an anchored graphic.
67
93
  */
68
94
  export declare function resolveAnchoredGraphicX(anchor: {
95
+ simplePos?: {
96
+ x: number;
97
+ y: number;
98
+ };
69
99
  hRelativeFrom?: AnchorHRelative;
70
100
  alignH?: AnchorAlignH;
71
101
  offsetH?: number;
72
102
  }, columnIndex: number, columns: ColumnLayoutForAnchor, objectWidth: number, margins?: {
73
103
  left?: number;
74
104
  right?: number;
75
- }, pageWidth?: number): number;
76
- export {};
105
+ }, pageWidth?: number, context?: ResolveAnchoredGraphicXContext): number;